aboutsummaryrefslogtreecommitdiff
path: root/contrib/compiler-rt
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/compiler-rt')
-rw-r--r--contrib/compiler-rt/CREDITS.TXT12
-rw-r--r--contrib/compiler-rt/LICENSE.TXT10
-rw-r--r--contrib/compiler-rt/README.txt332
-rw-r--r--contrib/compiler-rt/include/sanitizer/allocator_interface.h66
-rw-r--r--contrib/compiler-rt/include/sanitizer/asan_interface.h155
-rw-r--r--contrib/compiler-rt/include/sanitizer/common_interface_defs.h118
-rw-r--r--contrib/compiler-rt/include/sanitizer/coverage_interface.h46
-rw-r--r--contrib/compiler-rt/include/sanitizer/dfsan_interface.h104
-rw-r--r--contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h3070
-rw-r--r--contrib/compiler-rt/include/sanitizer/lsan_interface.h73
-rw-r--r--contrib/compiler-rt/include/sanitizer/msan_interface.h102
-rw-r--r--contrib/compiler-rt/include/sanitizer/tsan_interface_atomic.h222
-rw-r--r--contrib/compiler-rt/lib/BlocksRuntime/Block.h (renamed from contrib/compiler-rt/BlocksRuntime/Block.h)0
-rw-r--r--contrib/compiler-rt/lib/BlocksRuntime/Block_private.h (renamed from contrib/compiler-rt/BlocksRuntime/Block_private.h)0
-rw-r--r--contrib/compiler-rt/lib/BlocksRuntime/data.c (renamed from contrib/compiler-rt/BlocksRuntime/data.c)0
-rw-r--r--contrib/compiler-rt/lib/BlocksRuntime/runtime.c (renamed from contrib/compiler-rt/BlocksRuntime/runtime.c)0
-rw-r--r--contrib/compiler-rt/lib/adddf3.c152
-rw-r--r--contrib/compiler-rt/lib/arm/udivmodsi4.S80
-rw-r--r--contrib/compiler-rt/lib/arm/udivsi3.S90
-rw-r--r--contrib/compiler-rt/lib/arm/umodsi3.S58
-rw-r--r--contrib/compiler-rt/lib/asan/README.txt26
-rw-r--r--contrib/compiler-rt/lib/asan/asan.syms.extra3
-rw-r--r--contrib/compiler-rt/lib/asan/asan_activation.cc142
-rw-r--r--contrib/compiler-rt/lib/asan/asan_activation.h23
-rw-r--r--contrib/compiler-rt/lib/asan/asan_activation_flags.inc35
-rw-r--r--contrib/compiler-rt/lib/asan/asan_allocator.cc909
-rw-r--r--contrib/compiler-rt/lib/asan/asan_allocator.h179
-rw-r--r--contrib/compiler-rt/lib/asan/asan_blacklist.txt13
-rw-r--r--contrib/compiler-rt/lib/asan/asan_debugging.cc141
-rw-r--r--contrib/compiler-rt/lib/asan/asan_fake_stack.cc256
-rw-r--r--contrib/compiler-rt/lib/asan/asan_fake_stack.h175
-rw-r--r--contrib/compiler-rt/lib/asan/asan_flags.cc160
-rw-r--r--contrib/compiler-rt/lib/asan/asan_flags.h49
-rw-r--r--contrib/compiler-rt/lib/asan/asan_flags.inc145
-rw-r--r--contrib/compiler-rt/lib/asan/asan_globals.cc309
-rw-r--r--contrib/compiler-rt/lib/asan/asan_init_version.h34
-rw-r--r--contrib/compiler-rt/lib/asan/asan_interceptors.cc930
-rw-r--r--contrib/compiler-rt/lib/asan/asan_interceptors.h108
-rw-r--r--contrib/compiler-rt/lib/asan/asan_interface_internal.h185
-rw-r--r--contrib/compiler-rt/lib/asan/asan_internal.h162
-rw-r--r--contrib/compiler-rt/lib/asan/asan_linux.cc249
-rw-r--r--contrib/compiler-rt/lib/asan/asan_lock.h0
-rw-r--r--contrib/compiler-rt/lib/asan/asan_mac.cc436
-rw-r--r--contrib/compiler-rt/lib/asan/asan_malloc_linux.cc186
-rw-r--r--contrib/compiler-rt/lib/asan/asan_malloc_mac.cc362
-rw-r--r--contrib/compiler-rt/lib/asan/asan_malloc_win.cc178
-rw-r--r--contrib/compiler-rt/lib/asan/asan_mapping.h288
-rw-r--r--contrib/compiler-rt/lib/asan/asan_new_delete.cc132
-rw-r--r--contrib/compiler-rt/lib/asan/asan_poisoning.cc427
-rw-r--r--contrib/compiler-rt/lib/asan/asan_poisoning.h93
-rw-r--r--contrib/compiler-rt/lib/asan/asan_posix.cc119
-rw-r--r--contrib/compiler-rt/lib/asan/asan_preinit.cc25
-rw-r--r--contrib/compiler-rt/lib/asan/asan_report.cc1090
-rw-r--r--contrib/compiler-rt/lib/asan/asan_report.h95
-rw-r--r--contrib/compiler-rt/lib/asan/asan_rtl.cc523
-rw-r--r--contrib/compiler-rt/lib/asan/asan_stack.cc40
-rw-r--r--contrib/compiler-rt/lib/asan/asan_stack.h118
-rw-r--r--contrib/compiler-rt/lib/asan/asan_stats.cc179
-rw-r--r--contrib/compiler-rt/lib/asan/asan_stats.h78
-rw-r--r--contrib/compiler-rt/lib/asan/asan_suppressions.cc93
-rw-r--r--contrib/compiler-rt/lib/asan/asan_suppressions.h29
-rw-r--r--contrib/compiler-rt/lib/asan/asan_thread.cc358
-rw-r--r--contrib/compiler-rt/lib/asan/asan_thread.h187
-rw-r--r--contrib/compiler-rt/lib/asan/asan_win.cc168
-rw-r--r--contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc412
-rw-r--r--contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc119
-rwxr-xr-xcontrib/compiler-rt/lib/asan/scripts/asan_device_setup344
-rwxr-xr-xcontrib/compiler-rt/lib/asan/scripts/asan_symbolize.py479
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc267
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc85
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc27
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc152
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc45
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc433
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc236
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mac_test.h19
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm240
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc241
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc263
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc128
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc32
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_str_test.cc602
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test.cc1317
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test.ignore3
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test_config.h54
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test_main.cc19
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test_utils.h107
-rw-r--r--contrib/compiler-rt/lib/assembly.h73
-rw-r--r--contrib/compiler-rt/lib/builtins/README.txt343
-rw-r--r--contrib/compiler-rt/lib/builtins/absvdi2.c (renamed from contrib/compiler-rt/lib/absvdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/absvsi2.c (renamed from contrib/compiler-rt/lib/absvsi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/absvti2.c (renamed from contrib/compiler-rt/lib/absvti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/adddf3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/addsf3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/addtf3.c25
-rw-r--r--contrib/compiler-rt/lib/builtins/addvdi3.c (renamed from contrib/compiler-rt/lib/addvdi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/addvsi3.c (renamed from contrib/compiler-rt/lib/addvsi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/addvti3.c (renamed from contrib/compiler-rt/lib/addvti3.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/apple_versioning.c350
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S (renamed from contrib/compiler-rt/lib/arm/adddf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S (renamed from contrib/compiler-rt/lib/arm/addsf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S40
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_div0.c43
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S40
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S (renamed from contrib/compiler-rt/lib/arm/aeabi_idivmod.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S (renamed from contrib/compiler-rt/lib/arm/aeabi_ldivmod.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S (renamed from contrib/compiler-rt/lib/arm/aeabi_memcmp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S (renamed from contrib/compiler-rt/lib/arm/aeabi_memcpy.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S (renamed from contrib/compiler-rt/lib/arm/aeabi_memmove.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S (renamed from contrib/compiler-rt/lib/arm/aeabi_memset.S)6
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S (renamed from contrib/compiler-rt/lib/arm/aeabi_uidivmod.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S (renamed from contrib/compiler-rt/lib/arm/aeabi_uldivmod.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/bswapdi2.S (renamed from contrib/compiler-rt/lib/arm/bswapdi2.S)17
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/bswapsi2.S (renamed from contrib/compiler-rt/lib/arm/bswapsi2.S)17
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/clzdi2.S97
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/clzsi2.S76
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/comparesf2.S (renamed from contrib/compiler-rt/lib/arm/comparesf2.S)60
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S (renamed from contrib/compiler-rt/lib/arm/divdf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/divmodsi4.S (renamed from contrib/compiler-rt/lib/arm/divmodsi4.S)31
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S (renamed from contrib/compiler-rt/lib/arm/divsf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/divsi3.S (renamed from contrib/compiler-rt/lib/arm/divsi3.S)20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S (renamed from contrib/compiler-rt/lib/arm/eqdf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S (renamed from contrib/compiler-rt/lib/arm/eqsf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S (renamed from contrib/compiler-rt/lib/arm/extendsfdf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S (renamed from contrib/compiler-rt/lib/arm/fixdfsivfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S (renamed from contrib/compiler-rt/lib/arm/fixsfsivfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S (renamed from contrib/compiler-rt/lib/arm/fixunsdfsivfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S (renamed from contrib/compiler-rt/lib/arm/fixunssfsivfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S (renamed from contrib/compiler-rt/lib/arm/floatsidfvfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S (renamed from contrib/compiler-rt/lib/arm/floatsisfvfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S (renamed from contrib/compiler-rt/lib/arm/floatunssidfvfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S (renamed from contrib/compiler-rt/lib/arm/floatunssisfvfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S (renamed from contrib/compiler-rt/lib/arm/gedf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S (renamed from contrib/compiler-rt/lib/arm/gesf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S (renamed from contrib/compiler-rt/lib/arm/gtdf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S (renamed from contrib/compiler-rt/lib/arm/gtsf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S (renamed from contrib/compiler-rt/lib/arm/ledf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S (renamed from contrib/compiler-rt/lib/arm/lesf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S (renamed from contrib/compiler-rt/lib/arm/ltdf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S (renamed from contrib/compiler-rt/lib/arm/ltsf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/modsi3.S (renamed from contrib/compiler-rt/lib/arm/modsi3.S)28
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S (renamed from contrib/compiler-rt/lib/arm/muldf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S (renamed from contrib/compiler-rt/lib/arm/mulsf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S (renamed from contrib/compiler-rt/lib/arm/nedf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S (renamed from contrib/compiler-rt/lib/arm/negdf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S (renamed from contrib/compiler-rt/lib/arm/negsf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S (renamed from contrib/compiler-rt/lib/arm/nesf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S (renamed from contrib/compiler-rt/lib/arm/restore_vfp_d8_d15_regs.S)8
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S (renamed from contrib/compiler-rt/lib/arm/save_vfp_d8_d15_regs.S)6
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/softfloat-alias.list (renamed from contrib/compiler-rt/lib/arm/softfloat-alias.list)0
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S (renamed from contrib/compiler-rt/lib/arm/subdf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S (renamed from contrib/compiler-rt/lib/arm/subsf3vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/switch16.S (renamed from contrib/compiler-rt/lib/arm/switch16.S)8
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/switch32.S (renamed from contrib/compiler-rt/lib/arm/switch32.S)12
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/switch8.S (renamed from contrib/compiler-rt/lib/arm/switch8.S)9
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/switchu8.S (renamed from contrib/compiler-rt/lib/arm/switchu8.S)9
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync-ops.h64
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S21
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S24
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S19
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S23
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S21
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S21
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S24
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S24
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S21
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S24
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S21
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S21
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S20
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S24
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S (renamed from contrib/compiler-rt/lib/arm/sync_synchronize.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S (renamed from contrib/compiler-rt/lib/arm/truncdfsf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S184
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/udivsi3.S170
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/umodsi3.S161
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S (renamed from contrib/compiler-rt/lib/arm/unorddf2vfp.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S (renamed from contrib/compiler-rt/lib/arm/unordsf2vfp.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/ashldi3.c (renamed from contrib/compiler-rt/lib/ashldi3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ashlti3.c (renamed from contrib/compiler-rt/lib/ashlti3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/ashrdi3.c (renamed from contrib/compiler-rt/lib/ashrdi3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ashrti3.c (renamed from contrib/compiler-rt/lib/ashrti3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/assembly.h149
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic.c (renamed from contrib/compiler-rt/lib/atomic.c)24
-rw-r--r--contrib/compiler-rt/lib/builtins/clear_cache.c157
-rw-r--r--contrib/compiler-rt/lib/builtins/clzdi2.c (renamed from contrib/compiler-rt/lib/clzdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/clzsi2.c (renamed from contrib/compiler-rt/lib/clzsi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/clzti2.c (renamed from contrib/compiler-rt/lib/clzti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/cmpdi2.c (renamed from contrib/compiler-rt/lib/cmpdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/cmpti2.c (renamed from contrib/compiler-rt/lib/cmpti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/comparedf2.c (renamed from contrib/compiler-rt/lib/comparedf2.c)25
-rw-r--r--contrib/compiler-rt/lib/builtins/comparesf2.c (renamed from contrib/compiler-rt/lib/comparesf2.c)25
-rw-r--r--contrib/compiler-rt/lib/builtins/comparetf2.c133
-rw-r--r--contrib/compiler-rt/lib/builtins/ctzdi2.c (renamed from contrib/compiler-rt/lib/ctzdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ctzsi2.c (renamed from contrib/compiler-rt/lib/ctzsi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ctzti2.c (renamed from contrib/compiler-rt/lib/ctzti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/divdc3.c (renamed from contrib/compiler-rt/lib/divdc3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/divdf3.c (renamed from contrib/compiler-rt/lib/divdf3.c)5
-rw-r--r--contrib/compiler-rt/lib/builtins/divdi3.c (renamed from contrib/compiler-rt/lib/divdi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/divmoddi4.c (renamed from contrib/compiler-rt/lib/divmoddi4.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/divmodsi4.c (renamed from contrib/compiler-rt/lib/divmodsi4.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/divsc3.c (renamed from contrib/compiler-rt/lib/divsc3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/divsf3.c (renamed from contrib/compiler-rt/lib/divsf3.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/divsi3.c (renamed from contrib/compiler-rt/lib/divsi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/divtf3.c203
-rw-r--r--contrib/compiler-rt/lib/builtins/divti3.c (renamed from contrib/compiler-rt/lib/divti3.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/divxc3.c (renamed from contrib/compiler-rt/lib/divxc3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/enable_execute_stack.c (renamed from contrib/compiler-rt/lib/enable_execute_stack.c)5
-rw-r--r--contrib/compiler-rt/lib/builtins/eprintf.c (renamed from contrib/compiler-rt/lib/eprintf.c)7
-rw-r--r--contrib/compiler-rt/lib/builtins/extenddftf2.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/extendsfdf2.c19
-rw-r--r--contrib/compiler-rt/lib/builtins/extendsftf2.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/ffsdi2.c (renamed from contrib/compiler-rt/lib/ffsdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ffsti2.c (renamed from contrib/compiler-rt/lib/ffsti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/fixdfdi.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/fixdfsi.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/fixdfti.c26
-rw-r--r--contrib/compiler-rt/lib/builtins/fixsfdi.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/fixsfsi.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/fixsfti.c26
-rw-r--r--contrib/compiler-rt/lib/builtins/fixtfdi.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/fixtfsi.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/fixtfti.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsdfdi.c21
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsdfsi.c21
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsdfti.c23
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunssfdi.c21
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunssfsi.c25
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunssfti.c26
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunstfdi.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunstfsi.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunstfti.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsxfdi.c (renamed from contrib/compiler-rt/lib/fixunsxfdi.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsxfsi.c (renamed from contrib/compiler-rt/lib/fixunsxfsi.c)5
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsxfti.c (renamed from contrib/compiler-rt/lib/fixunsxfti.c)7
-rw-r--r--contrib/compiler-rt/lib/builtins/fixxfdi.c (renamed from contrib/compiler-rt/lib/fixxfdi.c)8
-rw-r--r--contrib/compiler-rt/lib/builtins/fixxfti.c (renamed from contrib/compiler-rt/lib/fixxfti.c)10
-rw-r--r--contrib/compiler-rt/lib/builtins/floatdidf.c (renamed from contrib/compiler-rt/lib/floatdidf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/floatdisf.c (renamed from contrib/compiler-rt/lib/floatdisf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/floatditf.c52
-rw-r--r--contrib/compiler-rt/lib/builtins/floatdixf.c (renamed from contrib/compiler-rt/lib/floatdixf.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/floatsidf.c (renamed from contrib/compiler-rt/lib/floatsidf.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/floatsisf.c (renamed from contrib/compiler-rt/lib/floatsisf.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/floatsitf.c52
-rw-r--r--contrib/compiler-rt/lib/builtins/floattidf.c (renamed from contrib/compiler-rt/lib/floattidf.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/floattisf.c (renamed from contrib/compiler-rt/lib/floattisf.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/floattixf.c (renamed from contrib/compiler-rt/lib/floattixf.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/floatundidf.c (renamed from contrib/compiler-rt/lib/floatundidf.c)1
-rw-r--r--contrib/compiler-rt/lib/builtins/floatundisf.c (renamed from contrib/compiler-rt/lib/floatundisf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/floatunditf.c40
-rw-r--r--contrib/compiler-rt/lib/builtins/floatundixf.c (renamed from contrib/compiler-rt/lib/floatundixf.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/floatunsidf.c (renamed from contrib/compiler-rt/lib/floatunsidf.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/floatunsisf.c (renamed from contrib/compiler-rt/lib/floatunsisf.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/floatunsitf.c40
-rw-r--r--contrib/compiler-rt/lib/builtins/floatuntidf.c (renamed from contrib/compiler-rt/lib/floatuntidf.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/floatuntisf.c (renamed from contrib/compiler-rt/lib/floatuntisf.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/floatuntixf.c (renamed from contrib/compiler-rt/lib/floatuntixf.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_add_impl.inc (renamed from contrib/compiler-rt/lib/addsf3.c)57
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_extend.h76
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_extend_impl.inc (renamed from contrib/compiler-rt/lib/extendsfdf2.c)61
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc41
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc39
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_lib.h270
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_mul_impl.inc (renamed from contrib/compiler-rt/lib/muldf3.c)52
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_trunc.h64
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc (renamed from contrib/compiler-rt/lib/truncdfsf2.c)69
-rw-r--r--contrib/compiler-rt/lib/builtins/gcc_personality_v0.c (renamed from contrib/compiler-rt/lib/gcc_personality_v0.c)72
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/ashldi3.S (renamed from contrib/compiler-rt/lib/i386/ashldi3.S)8
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/ashrdi3.S (renamed from contrib/compiler-rt/lib/i386/ashrdi3.S)8
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/divdi3.S (renamed from contrib/compiler-rt/lib/i386/divdi3.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/floatdidf.S (renamed from contrib/compiler-rt/lib/i386/floatdidf.S)20
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/floatdisf.S (renamed from contrib/compiler-rt/lib/i386/floatdisf.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/floatdixf.S (renamed from contrib/compiler-rt/lib/i386/floatdixf.S)3
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/floatundidf.S (renamed from contrib/compiler-rt/lib/i386/floatundidf.S)24
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/floatundisf.S (renamed from contrib/compiler-rt/lib/i386/floatundisf.S)40
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/floatundixf.S (renamed from contrib/compiler-rt/lib/i386/floatundixf.S)24
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/lshrdi3.S (renamed from contrib/compiler-rt/lib/i386/lshrdi3.S)8
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/moddi3.S (renamed from contrib/compiler-rt/lib/i386/moddi3.S)4
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/muldi3.S (renamed from contrib/compiler-rt/lib/i386/muldi3.S)5
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/udivdi3.S (renamed from contrib/compiler-rt/lib/i386/udivdi3.S)5
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/umoddi3.S (renamed from contrib/compiler-rt/lib/i386/umoddi3.S)5
-rw-r--r--contrib/compiler-rt/lib/builtins/int_endianness.h (renamed from contrib/compiler-rt/lib/int_endianness.h)23
-rw-r--r--contrib/compiler-rt/lib/builtins/int_lib.h (renamed from contrib/compiler-rt/lib/int_lib.h)36
-rw-r--r--contrib/compiler-rt/lib/builtins/int_math.h (renamed from contrib/compiler-rt/lib/int_math.h)0
-rw-r--r--contrib/compiler-rt/lib/builtins/int_types.h (renamed from contrib/compiler-rt/lib/int_types.h)3
-rw-r--r--contrib/compiler-rt/lib/builtins/int_util.c (renamed from contrib/compiler-rt/lib/int_util.c)9
-rw-r--r--contrib/compiler-rt/lib/builtins/int_util.h (renamed from contrib/compiler-rt/lib/int_util.h)2
-rw-r--r--contrib/compiler-rt/lib/builtins/lshrdi3.c (renamed from contrib/compiler-rt/lib/lshrdi3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/lshrti3.c (renamed from contrib/compiler-rt/lib/lshrti3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/moddi3.c (renamed from contrib/compiler-rt/lib/moddi3.c)8
-rw-r--r--contrib/compiler-rt/lib/builtins/modsi3.c (renamed from contrib/compiler-rt/lib/modsi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/modti3.c (renamed from contrib/compiler-rt/lib/modti3.c)10
-rw-r--r--contrib/compiler-rt/lib/builtins/muldc3.c (renamed from contrib/compiler-rt/lib/muldc3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/muldf3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/muldi3.c (renamed from contrib/compiler-rt/lib/muldi3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/mulodi4.c (renamed from contrib/compiler-rt/lib/mulodi4.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulosi4.c (renamed from contrib/compiler-rt/lib/mulosi4.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/muloti4.c (renamed from contrib/compiler-rt/lib/muloti4.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulsc3.c (renamed from contrib/compiler-rt/lib/mulsc3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulsf3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/multc3.c73
-rw-r--r--contrib/compiler-rt/lib/builtins/multf3.c25
-rw-r--r--contrib/compiler-rt/lib/builtins/multi3.c (renamed from contrib/compiler-rt/lib/multi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulvdi3.c (renamed from contrib/compiler-rt/lib/mulvdi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulvsi3.c (renamed from contrib/compiler-rt/lib/mulvsi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulvti3.c (renamed from contrib/compiler-rt/lib/mulvti3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/mulxc3.c (renamed from contrib/compiler-rt/lib/mulxc3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/negdf2.c (renamed from contrib/compiler-rt/lib/negdf2.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/negdi2.c (renamed from contrib/compiler-rt/lib/negdi2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/negsf2.c (renamed from contrib/compiler-rt/lib/negsf2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/negti2.c (renamed from contrib/compiler-rt/lib/negti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/negvdi2.c (renamed from contrib/compiler-rt/lib/negvdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/negvsi2.c (renamed from contrib/compiler-rt/lib/negvsi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/negvti2.c (renamed from contrib/compiler-rt/lib/negvti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/paritydi2.c (renamed from contrib/compiler-rt/lib/paritydi2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/paritysi2.c (renamed from contrib/compiler-rt/lib/paritysi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/parityti2.c (renamed from contrib/compiler-rt/lib/parityti2.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/popcountdi2.c (renamed from contrib/compiler-rt/lib/popcountdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/popcountsi2.c (renamed from contrib/compiler-rt/lib/popcountsi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/popcountti2.c (renamed from contrib/compiler-rt/lib/popcountti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/powidf2.c (renamed from contrib/compiler-rt/lib/powidf2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/powisf2.c (renamed from contrib/compiler-rt/lib/powisf2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/powitf2.c (renamed from contrib/compiler-rt/lib/powitf2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/powixf2.c (renamed from contrib/compiler-rt/lib/powixf2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/DD.h (renamed from contrib/compiler-rt/lib/ppc/DD.h)2
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/divtc3.c (renamed from contrib/compiler-rt/lib/ppc/divtc3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/fixtfdi.c (renamed from contrib/compiler-rt/lib/ppc/fixtfdi.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/fixunstfdi.c (renamed from contrib/compiler-rt/lib/ppc/fixunstfdi.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/floatditf.c (renamed from contrib/compiler-rt/lib/ppc/floatditf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/floatunditf.c (renamed from contrib/compiler-rt/lib/ppc/floatunditf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/gcc_qadd.c (renamed from contrib/compiler-rt/lib/ppc/gcc_qadd.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/gcc_qdiv.c (renamed from contrib/compiler-rt/lib/ppc/gcc_qdiv.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/gcc_qmul.c (renamed from contrib/compiler-rt/lib/ppc/gcc_qmul.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/gcc_qsub.c (renamed from contrib/compiler-rt/lib/ppc/gcc_qsub.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/multc3.c (renamed from contrib/compiler-rt/lib/ppc/multc3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/restFP.S (renamed from contrib/compiler-rt/lib/ppc/restFP.S)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/saveFP.S (renamed from contrib/compiler-rt/lib/ppc/saveFP.S)0
-rw-r--r--contrib/compiler-rt/lib/builtins/sparc64/divmod.m4 (renamed from contrib/compiler-rt/lib/sparc64/divmod.m4)0
-rw-r--r--contrib/compiler-rt/lib/builtins/sparc64/divsi3.S (renamed from contrib/compiler-rt/lib/sparc64/divsi3.S)0
-rw-r--r--contrib/compiler-rt/lib/builtins/sparc64/generate.sh (renamed from contrib/compiler-rt/lib/sparc64/generate.sh)0
-rw-r--r--contrib/compiler-rt/lib/builtins/sparc64/modsi3.S (renamed from contrib/compiler-rt/lib/sparc64/modsi3.S)0
-rw-r--r--contrib/compiler-rt/lib/builtins/sparc64/udivsi3.S (renamed from contrib/compiler-rt/lib/sparc64/udivsi3.S)0
-rw-r--r--contrib/compiler-rt/lib/builtins/sparc64/umodsi3.S (renamed from contrib/compiler-rt/lib/sparc64/umodsi3.S)0
-rw-r--r--contrib/compiler-rt/lib/builtins/subdf3.c (renamed from contrib/compiler-rt/lib/subdf3.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/subsf3.c (renamed from contrib/compiler-rt/lib/subsf3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/subtf3.c27
-rw-r--r--contrib/compiler-rt/lib/builtins/subvdi3.c (renamed from contrib/compiler-rt/lib/subvdi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/subvsi3.c (renamed from contrib/compiler-rt/lib/subvsi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/subvti3.c (renamed from contrib/compiler-rt/lib/subvti3.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/trampoline_setup.c (renamed from contrib/compiler-rt/lib/trampoline_setup.c)5
-rw-r--r--contrib/compiler-rt/lib/builtins/truncdfsf2.c18
-rw-r--r--contrib/compiler-rt/lib/builtins/trunctfdf2.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/trunctfsf2.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/ucmpdi2.c (renamed from contrib/compiler-rt/lib/ucmpdi2.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/ucmpti2.c (renamed from contrib/compiler-rt/lib/ucmpti2.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/udivdi3.c (renamed from contrib/compiler-rt/lib/udivdi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/udivmoddi4.c (renamed from contrib/compiler-rt/lib/udivmoddi4.c)92
-rw-r--r--contrib/compiler-rt/lib/builtins/udivmodsi4.c (renamed from contrib/compiler-rt/lib/udivmodsi4.c)3
-rw-r--r--contrib/compiler-rt/lib/builtins/udivmodti4.c (renamed from contrib/compiler-rt/lib/udivmodti4.c)96
-rw-r--r--contrib/compiler-rt/lib/builtins/udivsi3.c (renamed from contrib/compiler-rt/lib/udivsi3.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/udivti3.c (renamed from contrib/compiler-rt/lib/udivti3.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/umoddi3.c (renamed from contrib/compiler-rt/lib/umoddi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/umodsi3.c (renamed from contrib/compiler-rt/lib/umodsi3.c)2
-rw-r--r--contrib/compiler-rt/lib/builtins/umodti3.c (renamed from contrib/compiler-rt/lib/umodti3.c)4
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/floatdidf.c (renamed from contrib/compiler-rt/lib/x86_64/floatdidf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/floatdisf.c (renamed from contrib/compiler-rt/lib/x86_64/floatdisf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/floatdixf.c (renamed from contrib/compiler-rt/lib/x86_64/floatdixf.c)0
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S (renamed from contrib/compiler-rt/lib/x86_64/floatundidf.S)24
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S (renamed from contrib/compiler-rt/lib/x86_64/floatundisf.S)14
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S (renamed from contrib/compiler-rt/lib/x86_64/floatundixf.S)32
-rw-r--r--contrib/compiler-rt/lib/clear_cache.c40
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan.cc380
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan.h73
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan.syms.extra3
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan_custom.cc1125
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan_flags.inc32
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc44
-rw-r--r--contrib/compiler-rt/lib/dfsan/done_abilist.txt260
-rw-r--r--contrib/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt3433
-rwxr-xr-xcontrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py96
-rwxr-xr-xcontrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh50
-rw-r--r--contrib/compiler-rt/lib/fixdfdi.c45
-rw-r--r--contrib/compiler-rt/lib/fixdfsi.c49
-rw-r--r--contrib/compiler-rt/lib/fixdfti.c45
-rw-r--r--contrib/compiler-rt/lib/fixsfdi.c43
-rw-r--r--contrib/compiler-rt/lib/fixsfsi.c47
-rw-r--r--contrib/compiler-rt/lib/fixsfti.c45
-rw-r--r--contrib/compiler-rt/lib/fixunsdfdi.c47
-rw-r--r--contrib/compiler-rt/lib/fixunsdfsi.c44
-rw-r--r--contrib/compiler-rt/lib/fixunsdfti.c47
-rw-r--r--contrib/compiler-rt/lib/fixunssfdi.c44
-rw-r--r--contrib/compiler-rt/lib/fixunssfsi.c45
-rw-r--r--contrib/compiler-rt/lib/fixunssfti.c47
-rw-r--r--contrib/compiler-rt/lib/fp_lib.h144
-rw-r--r--contrib/compiler-rt/lib/interception/interception.h262
-rw-r--r--contrib/compiler-rt/lib/interception/interception_linux.cc36
-rw-r--r--contrib/compiler-rt/lib/interception/interception_linux.h47
-rw-r--r--contrib/compiler-rt/lib/interception/interception_mac.cc20
-rw-r--r--contrib/compiler-rt/lib/interception/interception_mac.h28
-rw-r--r--contrib/compiler-rt/lib/interception/interception_type_test.cc39
-rw-r--r--contrib/compiler-rt/lib/interception/interception_win.cc216
-rw-r--r--contrib/compiler-rt/lib/interception/interception_win.h50
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan.cc96
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan.h47
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_allocator.cc250
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_allocator.h39
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_common.cc688
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_common.h183
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_common_linux.cc157
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_flags.inc45
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_interceptors.cc287
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_preinit.cc22
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_thread.cc160
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_thread.h53
-rw-r--r--contrib/compiler-rt/lib/msan/msan.cc610
-rw-r--r--contrib/compiler-rt/lib/msan/msan.h218
-rw-r--r--contrib/compiler-rt/lib/msan/msan.syms.extra1
-rw-r--r--contrib/compiler-rt/lib/msan/msan_allocator.cc227
-rw-r--r--contrib/compiler-rt/lib/msan/msan_allocator.h33
-rw-r--r--contrib/compiler-rt/lib/msan/msan_blacklist.txt7
-rw-r--r--contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc126
-rw-r--r--contrib/compiler-rt/lib/msan/msan_chained_origin_depot.h29
-rw-r--r--contrib/compiler-rt/lib/msan/msan_flags.h30
-rw-r--r--contrib/compiler-rt/lib/msan/msan_flags.inc33
-rw-r--r--contrib/compiler-rt/lib/msan/msan_interceptors.cc1575
-rw-r--r--contrib/compiler-rt/lib/msan/msan_interface_internal.h158
-rw-r--r--contrib/compiler-rt/lib/msan/msan_linux.cc195
-rw-r--r--contrib/compiler-rt/lib/msan/msan_new_delete.cc65
-rw-r--r--contrib/compiler-rt/lib/msan/msan_origin.h169
-rw-r--r--contrib/compiler-rt/lib/msan/msan_poisoning.cc174
-rw-r--r--contrib/compiler-rt/lib/msan/msan_poisoning.h59
-rw-r--r--contrib/compiler-rt/lib/msan/msan_report.cc277
-rw-r--r--contrib/compiler-rt/lib/msan/msan_thread.cc82
-rw-r--r--contrib/compiler-rt/lib/msan/msan_thread.h71
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_loadable.cc27
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_test.cc4285
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_test_config.h20
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_test_main.cc21
-rw-r--r--contrib/compiler-rt/lib/mulsf3.c112
-rw-r--r--contrib/compiler-rt/lib/profile/GCDAProfiling.c587
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfiling.c48
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfiling.h92
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c104
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingFile.c199
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingInternal.h40
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c43
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c74
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc30
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h342
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc150
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h1451
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h38
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h63
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h40
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h66
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h100
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h97
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h116
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h253
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h351
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h165
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc350
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h622
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc4958
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc559
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc608
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc135
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc2852
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc731
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc130
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h416
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc189
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cc428
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h93
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc153
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h121
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc87
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h55
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc148
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h137
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h58
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h300
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h73
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc261
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h129
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc100
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h83
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc933
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h93
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc519
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h145
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc333
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h38
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_mutex.h219
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.cc19
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h71
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_placement_new.h25
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h120
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h247
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cc105
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc1205
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h1316
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc324
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc205
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc325
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h99
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc178
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc88
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc90
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc190
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h185
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h47
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc163
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h71
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h176
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc116
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h138
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc71
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc132
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h62
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h68
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc468
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc139
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h55
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc100
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h142
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc211
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h50
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc28
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc766
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc158
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc34
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc91
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cc301
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h148
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc131
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h60
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc158
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc623
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh140
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py4024
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py89
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py72
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py23
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py147
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc860
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc162
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc128
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc176
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc339
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc229
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc496
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc142
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc259
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc103
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc161
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc268
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc173
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc137
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc31
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc19
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc80
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc153
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc58
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h66
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc93
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc122
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc154
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc194
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc53
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc134
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h30
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc22
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h127
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc232
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc87
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/analyze_libtsan.sh43
-rw-r--r--contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_local.cc49
-rw-r--r--contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_shared.cc51
-rw-r--r--contrib/compiler-rt/lib/tsan/benchmarks/start_many_threads.cc52
-rw-r--r--contrib/compiler-rt/lib/tsan/benchmarks/vts_many_threads_bench.cc120
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/check_analyze.sh44
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/check_cmake.sh18
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/check_memcpy.sh31
-rw-r--r--contrib/compiler-rt/lib/tsan/dd/dd_interceptors.cc333
-rw-r--r--contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc159
-rw-r--r--contrib/compiler-rt/lib/tsan/dd/dd_rtl.h67
-rw-r--r--contrib/compiler-rt/lib/tsan/go/build.bat4
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/go/buildgo.sh130
-rw-r--r--contrib/compiler-rt/lib/tsan/go/test.c65
-rw-r--r--contrib/compiler-rt/lib/tsan/go/tsan_go.cc211
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan.syms.extra14
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc429
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_clock.h129
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h162
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h137
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_fd.cc298
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_fd.h65
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc104
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_flags.h35
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc79
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.cc47
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.h38
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc2629
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface.cc121
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface.h70
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc459
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.h33
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc954
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h85
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc251
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.h96
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_md5.cc243
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc226
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h81
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc287
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h88
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.cc89
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.h70
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h299
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc412
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc94
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc39
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc413
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_report.h129
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc1006
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h766
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S324
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc491
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc687
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc408
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cc46
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.h39
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc178
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h182
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc157
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h37
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc88
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.h35
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_sync.cc225
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h103
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h74
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_update_shadow_word_inl.h65
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_vector.h127
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc105
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc233
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc221
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc146
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc82
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc53
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h122
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc470
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc59
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc432
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc55
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc180
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc153
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc126
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc127
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc78
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc95
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc123
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc19
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc43
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan.syms.extra1
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_diag.cc358
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_diag.h243
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_flags.cc79
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_flags.h42
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_flags.inc25
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc421
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers.h145
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc81
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h40
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_init.cc63
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_init.h24
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_type_hash.cc250
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_type_hash.h63
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_value.cc102
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_value.h204
686 files changed, 100580 insertions, 2350 deletions
diff --git a/contrib/compiler-rt/CREDITS.TXT b/contrib/compiler-rt/CREDITS.TXT
index 818f4fa104da..6964eba020b8 100644
--- a/contrib/compiler-rt/CREDITS.TXT
+++ b/contrib/compiler-rt/CREDITS.TXT
@@ -22,3 +22,15 @@ D: Maintain Solaris & AuroraUX ports of Compiler-RT
N: Howard Hinnant
E: hhinnant@apple.com
D: Architect and primary author of compiler-rt
+
+N: Guan-Hong Liu
+E: koviankevin@hotmail.com
+D: IEEE Quad-precision functions
+
+N: Joerg Sonnenberger
+E: joerg@NetBSD.org
+D: Maintains NetBSD port.
+
+N: Matt Thomas
+E: matt@NetBSD.org
+D: ARM improvements.
diff --git a/contrib/compiler-rt/LICENSE.TXT b/contrib/compiler-rt/LICENSE.TXT
index 6aab1f694cc2..aee8347b0c35 100644
--- a/contrib/compiler-rt/LICENSE.TXT
+++ b/contrib/compiler-rt/LICENSE.TXT
@@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
University of Illinois/NCSA
Open Source License
-Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
All rights reserved.
@@ -55,7 +55,7 @@ SOFTWARE.
==============================================================================
-Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -89,9 +89,3 @@ other licenses gives permission to use the names of the LLVM Team or the
University of Illinois to endorse or promote products derived from this
Software.
-The following pieces of software have additional or alternate copyrights,
-licenses, and/or restrictions:
-
-Program Directory
-------- ---------
-mach_override lib/interception/mach_override
diff --git a/contrib/compiler-rt/README.txt b/contrib/compiler-rt/README.txt
index b37c0aecdeb2..fc8843246e25 100644
--- a/contrib/compiler-rt/README.txt
+++ b/contrib/compiler-rt/README.txt
@@ -9,335 +9,3 @@ terms of the license agreement found in LICENSE.txt.
================================
-This is a replacement library for libgcc. Each function is contained
-in its own file. Each function has a corresponding unit test under
-test/Unit.
-
-A rudimentary script to test each file is in the file called
-test/Unit/test.
-
-Here is the specification for this library:
-
-http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
-
-Here is a synopsis of the contents of this library:
-
-typedef int si_int;
-typedef unsigned su_int;
-
-typedef long long di_int;
-typedef unsigned long long du_int;
-
-// Integral bit manipulation
-
-di_int __ashldi3(di_int a, si_int b); // a << b
-ti_int __ashlti3(ti_int a, si_int b); // a << b
-
-di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
-ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
-di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
-ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
-
-si_int __clzsi2(si_int a); // count leading zeros
-si_int __clzdi2(di_int a); // count leading zeros
-si_int __clzti2(ti_int a); // count leading zeros
-si_int __ctzsi2(si_int a); // count trailing zeros
-si_int __ctzdi2(di_int a); // count trailing zeros
-si_int __ctzti2(ti_int a); // count trailing zeros
-
-si_int __ffsdi2(di_int a); // find least significant 1 bit
-si_int __ffsti2(ti_int a); // find least significant 1 bit
-
-si_int __paritysi2(si_int a); // bit parity
-si_int __paritydi2(di_int a); // bit parity
-si_int __parityti2(ti_int a); // bit parity
-
-si_int __popcountsi2(si_int a); // bit population
-si_int __popcountdi2(di_int a); // bit population
-si_int __popcountti2(ti_int a); // bit population
-
-uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
-uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
-
-// Integral arithmetic
-
-di_int __negdi2 (di_int a); // -a
-ti_int __negti2 (ti_int a); // -a
-di_int __muldi3 (di_int a, di_int b); // a * b
-ti_int __multi3 (ti_int a, ti_int b); // a * b
-si_int __divsi3 (si_int a, si_int b); // a / b signed
-di_int __divdi3 (di_int a, di_int b); // a / b signed
-ti_int __divti3 (ti_int a, ti_int b); // a / b signed
-su_int __udivsi3 (su_int n, su_int d); // a / b unsigned
-du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
-tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned
-si_int __modsi3 (si_int a, si_int b); // a % b signed
-di_int __moddi3 (di_int a, di_int b); // a % b signed
-ti_int __modti3 (ti_int a, ti_int b); // a % b signed
-su_int __umodsi3 (su_int a, su_int b); // a % b unsigned
-du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
-tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned
-du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b unsigned
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned
-su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned
-si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed
-
-
-
-// Integral arithmetic with trapping overflow
-
-si_int __absvsi2(si_int a); // abs(a)
-di_int __absvdi2(di_int a); // abs(a)
-ti_int __absvti2(ti_int a); // abs(a)
-
-si_int __negvsi2(si_int a); // -a
-di_int __negvdi2(di_int a); // -a
-ti_int __negvti2(ti_int a); // -a
-
-si_int __addvsi3(si_int a, si_int b); // a + b
-di_int __addvdi3(di_int a, di_int b); // a + b
-ti_int __addvti3(ti_int a, ti_int b); // a + b
-
-si_int __subvsi3(si_int a, si_int b); // a - b
-di_int __subvdi3(di_int a, di_int b); // a - b
-ti_int __subvti3(ti_int a, ti_int b); // a - b
-
-si_int __mulvsi3(si_int a, si_int b); // a * b
-di_int __mulvdi3(di_int a, di_int b); // a * b
-ti_int __mulvti3(ti_int a, ti_int b); // a * b
-
-
-// Integral arithmetic which returns if overflow
-
-si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range
-di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range
-ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to
- one if result not in signed range
-
-
-// Integral comparison: a < b -> 0
-// a == b -> 1
-// a > b -> 2
-
-si_int __cmpdi2 (di_int a, di_int b);
-si_int __cmpti2 (ti_int a, ti_int b);
-si_int __ucmpdi2(du_int a, du_int b);
-si_int __ucmpti2(tu_int a, tu_int b);
-
-// Integral / floating point conversion
-
-di_int __fixsfdi( float a);
-di_int __fixdfdi( double a);
-di_int __fixxfdi(long double a);
-
-ti_int __fixsfti( float a);
-ti_int __fixdfti( double a);
-ti_int __fixxfti(long double a);
-uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation
-
-su_int __fixunssfsi( float a);
-su_int __fixunsdfsi( double a);
-su_int __fixunsxfsi(long double a);
-
-du_int __fixunssfdi( float a);
-du_int __fixunsdfdi( double a);
-du_int __fixunsxfdi(long double a);
-
-tu_int __fixunssfti( float a);
-tu_int __fixunsdfti( double a);
-tu_int __fixunsxfti(long double a);
-uint64_t __fixunstfdi(long double input); // ppc only
-
-float __floatdisf(di_int a);
-double __floatdidf(di_int a);
-long double __floatdixf(di_int a);
-long double __floatditf(int64_t a); // ppc only
-
-float __floattisf(ti_int a);
-double __floattidf(ti_int a);
-long double __floattixf(ti_int a);
-
-float __floatundisf(du_int a);
-double __floatundidf(du_int a);
-long double __floatundixf(du_int a);
-long double __floatunditf(uint64_t a); // ppc only
-
-float __floatuntisf(tu_int a);
-double __floatuntidf(tu_int a);
-long double __floatuntixf(tu_int a);
-
-// Floating point raised to integer power
-
-float __powisf2( float a, si_int b); // a ^ b
-double __powidf2( double a, si_int b); // a ^ b
-long double __powixf2(long double a, si_int b); // a ^ b
-long double __powitf2(long double a, si_int b); // ppc only, a ^ b
-
-// Complex arithmetic
-
-// (a + ib) * (c + id)
-
- float _Complex __mulsc3( float a, float b, float c, float d);
- double _Complex __muldc3(double a, double b, double c, double d);
-long double _Complex __mulxc3(long double a, long double b,
- long double c, long double d);
-long double _Complex __multc3(long double a, long double b,
- long double c, long double d); // ppc only
-
-// (a + ib) / (c + id)
-
- float _Complex __divsc3( float a, float b, float c, float d);
- double _Complex __divdc3(double a, double b, double c, double d);
-long double _Complex __divxc3(long double a, long double b,
- long double c, long double d);
-long double _Complex __divtc3(long double a, long double b,
- long double c, long double d); // ppc only
-
-
-// Runtime support
-
-// __clear_cache() is used to tell process that new instructions have been
-// written to an address range. Necessary on processors that do not have
-// a unified instuction and data cache.
-void __clear_cache(void* start, void* end);
-
-// __enable_execute_stack() is used with nested functions when a trampoline
-// function is written onto the stack and that page range needs to be made
-// executable.
-void __enable_execute_stack(void* addr);
-
-// __gcc_personality_v0() is normally only called by the system unwinder.
-// C code (as opposed to C++) normally does not need a personality function
-// because there are no catch clauses or destructors to be run. But there
-// is a C language extension __attribute__((cleanup(func))) which marks local
-// variables as needing the cleanup function "func" to be run when the
-// variable goes out of scope. That includes when an exception is thrown,
-// so a personality handler is needed.
-_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
- uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- _Unwind_Context_t context);
-
-// for use with some implementations of assert() in <assert.h>
-void __eprintf(const char* format, const char* assertion_expression,
- const char* line, const char* file);
-
-
-
-// Power PC specific functions
-
-// There is no C interface to the saveFP/restFP functions. They are helper
-// functions called by the prolog and epilog of functions that need to save
-// a number of non-volatile float point registers.
-saveFP
-restFP
-
-// PowerPC has a standard template for trampoline functions. This function
-// generates a custom trampoline function with the specific realFunc
-// and localsPtr values.
-void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
- const void* realFunc, void* localsPtr);
-
-// adds two 128-bit double-double precision values ( x + y )
-long double __gcc_qadd(long double x, long double y);
-
-// subtracts two 128-bit double-double precision values ( x - y )
-long double __gcc_qsub(long double x, long double y);
-
-// multiples two 128-bit double-double precision values ( x * y )
-long double __gcc_qmul(long double x, long double y);
-
-// divides two 128-bit double-double precision values ( x / y )
-long double __gcc_qdiv(long double a, long double b);
-
-
-// ARM specific functions
-
-// There is no C interface to the switch* functions. These helper functions
-// are only needed by Thumb1 code for efficient switch table generation.
-switch16
-switch32
-switch8
-switchu8
-
-// There is no C interface to the *_vfp_d8_d15_regs functions. There are
-// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
-// SJLJ for exceptions, each function with a catch clause or destuctors needs
-// to save and restore all registers in it prolog and epliog. But there is
-// no way to access vector and high float registers from thumb1 code, so the
-// compiler must add call outs to these helper functions in the prolog and
-// epilog.
-restore_vfp_d8_d15_regs
-save_vfp_d8_d15_regs
-
-
-// Note: long ago ARM processors did not have floating point hardware support.
-// Floating point was done in software and floating point parameters were
-// passed in integer registers. When hardware support was added for floating
-// point, new *vfp functions were added to do the same operations but with
-// floating point parameters in floating point registers.
-
-// Undocumented functions
-
-float __addsf3vfp(float a, float b); // Appears to return a + b
-double __adddf3vfp(double a, double b); // Appears to return a + b
-float __divsf3vfp(float a, float b); // Appears to return a / b
-double __divdf3vfp(double a, double b); // Appears to return a / b
-int __eqsf2vfp(float a, float b); // Appears to return one
- // iff a == b and neither is NaN.
-int __eqdf2vfp(double a, double b); // Appears to return one
- // iff a == b and neither is NaN.
-double __extendsfdf2vfp(float a); // Appears to convert from
- // float to double.
-int __fixdfsivfp(double a); // Appears to convert from
- // double to int.
-int __fixsfsivfp(float a); // Appears to convert from
- // float to int.
-unsigned int __fixunssfsivfp(float a); // Appears to convert from
- // float to unsigned int.
-unsigned int __fixunsdfsivfp(double a); // Appears to convert from
- // double to unsigned int.
-double __floatsidfvfp(int a); // Appears to convert from
- // int to double.
-float __floatsisfvfp(int a); // Appears to convert from
- // int to float.
-double __floatunssidfvfp(unsigned int a); // Appears to convert from
- // unisgned int to double.
-float __floatunssisfvfp(unsigned int a); // Appears to convert from
- // unisgned int to float.
-int __gedf2vfp(double a, double b); // Appears to return __gedf2
- // (a >= b)
-int __gesf2vfp(float a, float b); // Appears to return __gesf2
- // (a >= b)
-int __gtdf2vfp(double a, double b); // Appears to return __gtdf2
- // (a > b)
-int __gtsf2vfp(float a, float b); // Appears to return __gtsf2
- // (a > b)
-int __ledf2vfp(double a, double b); // Appears to return __ledf2
- // (a <= b)
-int __lesf2vfp(float a, float b); // Appears to return __lesf2
- // (a <= b)
-int __ltdf2vfp(double a, double b); // Appears to return __ltdf2
- // (a < b)
-int __ltsf2vfp(float a, float b); // Appears to return __ltsf2
- // (a < b)
-double __muldf3vfp(double a, double b); // Appears to return a * b
-float __mulsf3vfp(float a, float b); // Appears to return a * b
-int __nedf2vfp(double a, double b); // Appears to return __nedf2
- // (a != b)
-double __negdf2vfp(double a); // Appears to return -a
-float __negsf2vfp(float a); // Appears to return -a
-float __negsf2vfp(float a); // Appears to return -a
-double __subdf3vfp(double a, double b); // Appears to return a - b
-float __subsf3vfp(float a, float b); // Appears to return a - b
-float __truncdfsf2vfp(double a); // Appears to convert from
- // double to float.
-int __unorddf2vfp(double a, double b); // Appears to return __unorddf2
-int __unordsf2vfp(float a, float b); // Appears to return __unordsf2
-
-
-Preconditions are listed for each function at the definition when there are any.
-Any preconditions reflect the specification at
-http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc.
-
-Assumptions are listed in "int_lib.h", and in individual files. Where possible
-assumptions are checked at compile time.
diff --git a/contrib/compiler-rt/include/sanitizer/allocator_interface.h b/contrib/compiler-rt/include/sanitizer/allocator_interface.h
new file mode 100644
index 000000000000..ab251f89c619
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/allocator_interface.h
@@ -0,0 +1,66 @@
+//===-- allocator_interface.h ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Public interface header for allocator used in sanitizers (ASan/TSan/MSan).
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
+#define SANITIZER_ALLOCATOR_INTERFACE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* Returns the estimated number of bytes that will be reserved by allocator
+ for request of "size" bytes. If allocator can't allocate that much
+ memory, returns the maximal possible allocation size, otherwise returns
+ "size". */
+ size_t __sanitizer_get_estimated_allocated_size(size_t size);
+
+ /* Returns true if p was returned by the allocator and
+ is not yet freed. */
+ int __sanitizer_get_ownership(const volatile void *p);
+
+ /* Returns the number of bytes reserved for the pointer p.
+ Requires (get_ownership(p) == true) or (p == 0). */
+ size_t __sanitizer_get_allocated_size(const volatile void *p);
+
+ /* Number of bytes, allocated and not yet freed by the application. */
+ size_t __sanitizer_get_current_allocated_bytes();
+
+ /* Number of bytes, mmaped by the allocator to fulfill allocation requests.
+ Generally, for request of X bytes, allocator can reserve and add to free
+ lists a large number of chunks of size X to use them for future requests.
+ All these chunks count toward the heap size. Currently, allocator never
+ releases memory to OS (instead, it just puts freed chunks to free
+ lists). */
+ size_t __sanitizer_get_heap_size();
+
+ /* Number of bytes, mmaped by the allocator, which can be used to fulfill
+ allocation requests. When a user program frees memory chunk, it can first
+ fall into quarantine and will count toward __sanitizer_get_free_bytes()
+ later. */
+ size_t __sanitizer_get_free_bytes();
+
+ /* Number of bytes in unmapped pages, that are released to OS. Currently,
+ always returns 0. */
+ size_t __sanitizer_get_unmapped_bytes();
+
+ /* Malloc hooks that may be optionally provided by user.
+ __sanitizer_malloc_hook(ptr, size) is called immediately after
+ allocation of "size" bytes, which returned "ptr".
+ __sanitizer_free_hook(ptr) is called immediately before
+ deallocation of "ptr". */
+ void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
+ void __sanitizer_free_hook(const volatile void *ptr);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/contrib/compiler-rt/include/sanitizer/asan_interface.h b/contrib/compiler-rt/include/sanitizer/asan_interface.h
new file mode 100644
index 000000000000..7763389ab257
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/asan_interface.h
@@ -0,0 +1,155 @@
+//===-- sanitizer/asan_interface.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.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ASAN_INTERFACE_H
+#define SANITIZER_ASAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Marks memory region [addr, addr+size) as unaddressable.
+ // This memory must be previously allocated by the user program. Accessing
+ // addresses in this region from instrumented code is forbidden until
+ // this region is unpoisoned. This function is not guaranteed to poison
+ // the whole region - it may poison only subregion of [addr, addr+size) due
+ // to ASan alignment restrictions.
+ // Method is NOT thread-safe in the sense that no two threads can
+ // (un)poison memory in the same memory region simultaneously.
+ void __asan_poison_memory_region(void const volatile *addr, size_t size);
+ // Marks memory region [addr, addr+size) as addressable.
+ // This memory must be previously allocated by the user program. Accessing
+ // addresses in this region is allowed until this region is poisoned again.
+ // This function may unpoison a superregion of [addr, addr+size) due to
+ // ASan alignment restrictions.
+ // Method is NOT thread-safe in the sense that no two threads can
+ // (un)poison memory in the same memory region simultaneously.
+ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+
+// User code should use macros instead of functions.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+#else
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#endif
+
+ // Returns 1 if addr is poisoned (i.e. 1-byte read/write access to this
+ // address will result in error report from AddressSanitizer).
+ // Otherwise returns 0.
+ int __asan_address_is_poisoned(void const volatile *addr);
+
+ // If at least one byte in [beg, beg+size) is poisoned, return the address
+ // of the first such byte. Otherwise return 0.
+ void *__asan_region_is_poisoned(void *beg, size_t size);
+
+ // Print the description of addr (useful when debugging in gdb).
+ void __asan_describe_address(void *addr);
+
+ // Useful for calling from a debugger to get information about an ASan error.
+ // Returns 1 if an error has been (or is being) reported, otherwise returns 0.
+ int __asan_report_present();
+
+ // Useful for calling from a debugger to get information about an ASan error.
+ // If an error has been (or is being) reported, the following functions return
+ // the pc, bp, sp, address, access type (0 = read, 1 = write), access size and
+ // bug description (e.g. "heap-use-after-free"). Otherwise they return 0.
+ void *__asan_get_report_pc();
+ void *__asan_get_report_bp();
+ void *__asan_get_report_sp();
+ void *__asan_get_report_address();
+ int __asan_get_report_access_type();
+ size_t __asan_get_report_access_size();
+ const char *__asan_get_report_description();
+
+ // Useful for calling from the debugger to get information about a pointer.
+ // Returns the category of the given pointer as a constant string.
+ // Possible return values are "global", "stack", "stack-fake", "heap",
+ // "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
+ // If global or stack, tries to also return the variable name, address and
+ // size. If heap, tries to return the chunk address and size. 'name' should
+ // point to an allocated buffer of size 'name_size'.
+ const char *__asan_locate_address(void *addr, char *name, size_t name_size,
+ void **region_address, size_t *region_size);
+
+ // Useful for calling from the debugger to get the allocation stack trace
+ // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+ // returns the number of stored frames or 0 on error.
+ size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
+ int *thread_id);
+
+ // Useful for calling from the debugger to get the free stack trace
+ // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+ // returns the number of stored frames or 0 on error.
+ size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
+ int *thread_id);
+
+ // Useful for calling from the debugger to get the current shadow memory
+ // mapping.
+ void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
+
+ // This is an internal function that is called to report an error.
+ // However it is still a part of the interface because users may want to
+ // set a breakpoint on this function in a debugger.
+ void __asan_report_error(void *pc, void *bp, void *sp,
+ void *addr, int is_write, size_t access_size);
+
+ // Sets the exit code to use when reporting an error.
+ // Returns the old value.
+ int __asan_set_error_exit_code(int exit_code);
+
+ // Deprecated. Call __sanitizer_set_death_callback instead.
+ void __asan_set_death_callback(void (*callback)(void));
+
+ void __asan_set_error_report_callback(void (*callback)(const char*));
+
+ // User may provide function that would be called right when ASan detects
+ // an error. This can be used to notice cases when ASan detects an error, but
+ // the program crashes before ASan report is printed.
+ void __asan_on_error();
+
+ // Prints accumulated stats to stderr. Used for debugging.
+ void __asan_print_accumulated_stats();
+
+ // This function may be optionally provided by user and should return
+ // a string containing ASan runtime options. See asan_flags.h for details.
+ const char* __asan_default_options();
+
+ // The following 2 functions facilitate garbage collection in presence of
+ // asan's fake stack.
+
+ // Returns an opaque handler to be used later in __asan_addr_is_in_fake_stack.
+ // Returns NULL if the current thread does not have a fake stack.
+ void *__asan_get_current_fake_stack();
+
+ // If fake_stack is non-NULL and addr belongs to a fake frame in
+ // fake_stack, returns the address on real stack that corresponds to
+ // the fake frame and sets beg/end to the boundaries of this fake frame.
+ // Otherwise returns NULL and does not touch beg/end.
+ // If beg/end are NULL, they are not touched.
+ // This function may be called from a thread other than the owner of
+ // fake_stack, but the owner thread need to be alive.
+ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
+ void **end);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_ASAN_INTERFACE_H
diff --git a/contrib/compiler-rt/include/sanitizer/common_interface_defs.h b/contrib/compiler-rt/include/sanitizer/common_interface_defs.h
new file mode 100644
index 000000000000..ef645e527119
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/common_interface_defs.h
@@ -0,0 +1,118 @@
+//===-- sanitizer/common_interface_defs.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common part of the public sanitizer interface.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
+#define SANITIZER_COMMON_INTERFACE_DEFS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+// GCC does not understand __has_feature.
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Arguments for __sanitizer_sandbox_on_notify() below.
+ typedef struct {
+ // Enable sandbox support in sanitizer coverage.
+ int coverage_sandboxed;
+ // File descriptor to write coverage data to. If -1 is passed, a file will
+ // be pre-opened by __sanitizer_sandobx_on_notify(). This field has no
+ // effect if coverage_sandboxed == 0.
+ intptr_t coverage_fd;
+ // If non-zero, split the coverage data into well-formed blocks. This is
+ // useful when coverage_fd is a socket descriptor. Each block will contain
+ // a header, allowing data from multiple processes to be sent over the same
+ // socket.
+ unsigned int coverage_max_block_size;
+ } __sanitizer_sandbox_arguments;
+
+ // Tell the tools to write their reports to "path.<pid>" instead of stderr.
+ void __sanitizer_set_report_path(const char *path);
+
+ // Notify the tools that the sandbox is going to be turned on. The reserved
+ // parameter will be used in the future to hold a structure with functions
+ // that the tools may call to bypass the sandbox.
+ void __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
+
+ // This function is called by the tool when it has just finished reporting
+ // an error. 'error_summary' is a one-line string that summarizes
+ // the error message. This function can be overridden by the client.
+ void __sanitizer_report_error_summary(const char *error_summary);
+
+ // Some of the sanitizers (e.g. asan/tsan) may miss bugs that happen
+ // in unaligned loads/stores. In order to find such bugs reliably one needs
+ // to replace plain unaligned loads/stores with these calls.
+ uint16_t __sanitizer_unaligned_load16(const void *p);
+ uint32_t __sanitizer_unaligned_load32(const void *p);
+ uint64_t __sanitizer_unaligned_load64(const void *p);
+ void __sanitizer_unaligned_store16(void *p, uint16_t x);
+ void __sanitizer_unaligned_store32(void *p, uint32_t x);
+ void __sanitizer_unaligned_store64(void *p, uint64_t x);
+
+ // Annotate the current state of a contiguous container, such as
+ // std::vector, std::string or similar.
+ // A contiguous container is a container that keeps all of its elements
+ // in a contiguous region of memory. The container owns the region of memory
+ // [beg, end); the memory [beg, mid) is used to store the current elements
+ // and the memory [mid, end) is reserved for future elements;
+ // beg <= mid <= end. For example, in "std::vector<> v"
+ // beg = &v[0];
+ // end = beg + v.capacity() * sizeof(v[0]);
+ // mid = beg + v.size() * sizeof(v[0]);
+ //
+ // This annotation tells the Sanitizer tool about the current state of the
+ // container so that the tool can report errors when memory from [mid, end)
+ // is accessed. Insert this annotation into methods like push_back/pop_back.
+ // Supply the old and the new values of mid (old_mid/new_mid).
+ // In the initial state mid == end and so should be the final
+ // state when the container is destroyed or when it reallocates the storage.
+ //
+ // Use with caution and don't use for anything other than vector-like classes.
+ //
+ // For AddressSanitizer, 'beg' should be 8-aligned and 'end' should
+ // be either 8-aligned or it should point to the end of a separate heap-,
+ // stack-, or global- allocated buffer. I.e. the following will not work:
+ // int64_t x[2]; // 16 bytes, 8-aligned.
+ // char *beg = (char *)&x[0];
+ // char *end = beg + 12; // Not 8 aligned, not the end of the buffer.
+ // This however will work fine:
+ // int32_t x[3]; // 12 bytes, but 8-aligned under AddressSanitizer.
+ // char *beg = (char*)&x[0];
+ // char *end = beg + 12; // Not 8-aligned, but is the end of the buffer.
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
+ // Returns true if the contiguous container [beg, end) is properly poisoned
+ // (e.g. with __sanitizer_annotate_contiguous_container), i.e. if
+ // - [beg, mid) is addressable,
+ // - [mid, end) is unaddressable.
+ // Full verification requires O(end-beg) time; this function tries to avoid
+ // such complexity by touching only parts of the container around beg/mid/end.
+ int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
+ const void *end);
+
+ // Print the stack trace leading to this call. Useful for debugging user code.
+ void __sanitizer_print_stack_trace();
+
+ // Sets the callback to be called right before death on error.
+ // Passing 0 will unset the callback.
+ void __sanitizer_set_death_callback(void (*callback)(void));
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_COMMON_INTERFACE_DEFS_H
diff --git a/contrib/compiler-rt/include/sanitizer/coverage_interface.h b/contrib/compiler-rt/include/sanitizer/coverage_interface.h
new file mode 100644
index 000000000000..88a7e480081d
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/coverage_interface.h
@@ -0,0 +1,46 @@
+//===-- sanitizer/coverage_interface.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Public interface for sanitizer coverage.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_COVERAG_INTERFACE_H
+#define SANITIZER_COVERAG_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Initialize coverage.
+ void __sanitizer_cov_init();
+ // Record and dump coverage info.
+ void __sanitizer_cov_dump();
+ // Open <name>.sancov.packed in the coverage directory and return the file
+ // descriptor. Returns -1 on failure, or if coverage dumping is disabled.
+ // This is intended for use by sandboxing code.
+ intptr_t __sanitizer_maybe_open_cov_file(const char *name);
+ // Get the number of total unique covered entities (blocks, edges, calls).
+ // This can be useful for coverage-directed in-process fuzzers.
+ uintptr_t __sanitizer_get_total_unique_coverage();
+
+ // Reset the basic-block (edge) coverage to the initial state.
+ // Useful for in-process fuzzing to start collecting coverage from scratch.
+ // Experimental, will likely not work for multi-threaded process.
+ void __sanitizer_reset_coverage();
+ // Set *data to the array of covered PCs and return the size of that array.
+ // Some of the entries in *data will be zero.
+ uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_COVERAG_INTERFACE_H
diff --git a/contrib/compiler-rt/include/sanitizer/dfsan_interface.h b/contrib/compiler-rt/include/sanitizer/dfsan_interface.h
new file mode 100644
index 000000000000..79dbf2f364c2
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/dfsan_interface.h
@@ -0,0 +1,104 @@
+//===-- dfsan_interface.h -------------------------------------------------===//
+//
+// 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 DataFlowSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef DFSAN_INTERFACE_H
+#define DFSAN_INTERFACE_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint16_t dfsan_label;
+
+/// Stores information associated with a specific label identifier. A label
+/// may be a base label created using dfsan_create_label, with associated
+/// text description and user data, or an automatically created union label,
+/// which represents the union of two label identifiers (which may themselves
+/// be base or union labels).
+struct dfsan_label_info {
+ // Fields for union labels, set to 0 for base labels.
+ dfsan_label l1;
+ dfsan_label l2;
+
+ // Fields for base labels.
+ const char *desc;
+ void *userdata;
+};
+
+/// Signature of the callback argument to dfsan_set_write_callback().
+typedef void (*dfsan_write_callback_t)(int fd, const void *buf, size_t count);
+
+/// Computes the union of \c l1 and \c l2, possibly creating a union label in
+/// the process.
+dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
+
+/// Creates and returns a base label with the given description and user data.
+dfsan_label dfsan_create_label(const char *desc, void *userdata);
+
+/// Sets the label for each address in [addr,addr+size) to \c label.
+void dfsan_set_label(dfsan_label label, void *addr, size_t size);
+
+/// Sets the label for each address in [addr,addr+size) to the union of the
+/// current label for that address and \c label.
+void dfsan_add_label(dfsan_label label, void *addr, size_t size);
+
+/// Retrieves the label associated with the given data.
+///
+/// The type of 'data' is arbitrary. The function accepts a value of any type,
+/// which can be truncated or extended (implicitly or explicitly) as necessary.
+/// The truncation/extension operations will preserve the label of the original
+/// value.
+dfsan_label dfsan_get_label(long data);
+
+/// Retrieves the label associated with the data at the given address.
+dfsan_label dfsan_read_label(const void *addr, size_t size);
+
+/// Retrieves a pointer to the dfsan_label_info struct for the given label.
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
+
+/// Returns whether the given label label contains the label elem.
+int dfsan_has_label(dfsan_label label, dfsan_label elem);
+
+/// If the given label label contains a label with the description desc, returns
+/// that label, else returns 0.
+dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
+
+/// Returns the number of labels allocated.
+size_t dfsan_get_label_count(void);
+
+/// Sets a callback to be invoked on calls to write(). The callback is invoked
+/// before the write is done. The write is not guaranteed to succeed when the
+/// callback executes. Pass in NULL to remove any callback.
+void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback);
+
+/// Writes the labels currently used by the program to the given file
+/// descriptor. The lines of the output have the following format:
+///
+/// <label> <parent label 1> <parent label 2> <label description if any>
+void dfsan_dump_labels(int fd);
+
+#ifdef __cplusplus
+} // extern "C"
+
+template <typename T>
+void dfsan_set_label(dfsan_label label, T &data) { // NOLINT
+ dfsan_set_label(label, (void *)&data, sizeof(T));
+}
+
+#endif
+
+#endif // DFSAN_INTERFACE_H
diff --git a/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h b/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h
new file mode 100644
index 000000000000..89867c15190a
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h
@@ -0,0 +1,3070 @@
+//===-- linux_syscall_hooks.h ---------------------------------------------===//
+//
+// 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 public sanitizer interface.
+//
+// System call handlers.
+//
+// Interface methods declared in this header implement pre- and post- syscall
+// actions for the active sanitizer.
+// Usage:
+// __sanitizer_syscall_pre_getfoo(...args...);
+// long res = syscall(__NR_getfoo, ...args...);
+// __sanitizer_syscall_post_getfoo(res, ...args...);
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H
+#define SANITIZER_LINUX_SYSCALL_HOOKS_H
+
+#define __sanitizer_syscall_pre_time(tloc) \
+ __sanitizer_syscall_pre_impl_time((long)(tloc))
+#define __sanitizer_syscall_post_time(res, tloc) \
+ __sanitizer_syscall_post_impl_time(res, (long)(tloc))
+#define __sanitizer_syscall_pre_stime(tptr) \
+ __sanitizer_syscall_pre_impl_stime((long)(tptr))
+#define __sanitizer_syscall_post_stime(res, tptr) \
+ __sanitizer_syscall_post_impl_stime(res, (long)(tptr))
+#define __sanitizer_syscall_pre_gettimeofday(tv, tz) \
+ __sanitizer_syscall_pre_impl_gettimeofday((long)(tv), (long)(tz))
+#define __sanitizer_syscall_post_gettimeofday(res, tv, tz) \
+ __sanitizer_syscall_post_impl_gettimeofday(res, (long)(tv), (long)(tz))
+#define __sanitizer_syscall_pre_settimeofday(tv, tz) \
+ __sanitizer_syscall_pre_impl_settimeofday((long)(tv), (long)(tz))
+#define __sanitizer_syscall_post_settimeofday(res, tv, tz) \
+ __sanitizer_syscall_post_impl_settimeofday(res, (long)(tv), (long)(tz))
+#define __sanitizer_syscall_pre_adjtimex(txc_p) \
+ __sanitizer_syscall_pre_impl_adjtimex((long)(txc_p))
+#define __sanitizer_syscall_post_adjtimex(res, txc_p) \
+ __sanitizer_syscall_post_impl_adjtimex(res, (long)(txc_p))
+#define __sanitizer_syscall_pre_times(tbuf) \
+ __sanitizer_syscall_pre_impl_times((long)(tbuf))
+#define __sanitizer_syscall_post_times(res, tbuf) \
+ __sanitizer_syscall_post_impl_times(res, (long)(tbuf))
+#define __sanitizer_syscall_pre_gettid() __sanitizer_syscall_pre_impl_gettid()
+#define __sanitizer_syscall_post_gettid(res) \
+ __sanitizer_syscall_post_impl_gettid(res)
+#define __sanitizer_syscall_pre_nanosleep(rqtp, rmtp) \
+ __sanitizer_syscall_pre_impl_nanosleep((long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_post_nanosleep(res, rqtp, rmtp) \
+ __sanitizer_syscall_post_impl_nanosleep(res, (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_pre_alarm(seconds) \
+ __sanitizer_syscall_pre_impl_alarm((long)(seconds))
+#define __sanitizer_syscall_post_alarm(res, seconds) \
+ __sanitizer_syscall_post_impl_alarm(res, (long)(seconds))
+#define __sanitizer_syscall_pre_getpid() __sanitizer_syscall_pre_impl_getpid()
+#define __sanitizer_syscall_post_getpid(res) \
+ __sanitizer_syscall_post_impl_getpid(res)
+#define __sanitizer_syscall_pre_getppid() __sanitizer_syscall_pre_impl_getppid()
+#define __sanitizer_syscall_post_getppid(res) \
+ __sanitizer_syscall_post_impl_getppid(res)
+#define __sanitizer_syscall_pre_getuid() __sanitizer_syscall_pre_impl_getuid()
+#define __sanitizer_syscall_post_getuid(res) \
+ __sanitizer_syscall_post_impl_getuid(res)
+#define __sanitizer_syscall_pre_geteuid() __sanitizer_syscall_pre_impl_geteuid()
+#define __sanitizer_syscall_post_geteuid(res) \
+ __sanitizer_syscall_post_impl_geteuid(res)
+#define __sanitizer_syscall_pre_getgid() __sanitizer_syscall_pre_impl_getgid()
+#define __sanitizer_syscall_post_getgid(res) \
+ __sanitizer_syscall_post_impl_getgid(res)
+#define __sanitizer_syscall_pre_getegid() __sanitizer_syscall_pre_impl_getegid()
+#define __sanitizer_syscall_post_getegid(res) \
+ __sanitizer_syscall_post_impl_getegid(res)
+#define __sanitizer_syscall_pre_getresuid(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_getresuid((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_getresuid(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_getresuid(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_getresgid(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_getresgid((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_getresgid(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_getresgid(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_getpgid(pid) \
+ __sanitizer_syscall_pre_impl_getpgid((long)(pid))
+#define __sanitizer_syscall_post_getpgid(res, pid) \
+ __sanitizer_syscall_post_impl_getpgid(res, (long)(pid))
+#define __sanitizer_syscall_pre_getpgrp() __sanitizer_syscall_pre_impl_getpgrp()
+#define __sanitizer_syscall_post_getpgrp(res) \
+ __sanitizer_syscall_post_impl_getpgrp(res)
+#define __sanitizer_syscall_pre_getsid(pid) \
+ __sanitizer_syscall_pre_impl_getsid((long)(pid))
+#define __sanitizer_syscall_post_getsid(res, pid) \
+ __sanitizer_syscall_post_impl_getsid(res, (long)(pid))
+#define __sanitizer_syscall_pre_getgroups(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_getgroups((long)(gidsetsize), (long)(grouplist))
+#define __sanitizer_syscall_post_getgroups(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_getgroups(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_setregid(rgid, egid) \
+ __sanitizer_syscall_pre_impl_setregid((long)(rgid), (long)(egid))
+#define __sanitizer_syscall_post_setregid(res, rgid, egid) \
+ __sanitizer_syscall_post_impl_setregid(res, (long)(rgid), (long)(egid))
+#define __sanitizer_syscall_pre_setgid(gid) \
+ __sanitizer_syscall_pre_impl_setgid((long)(gid))
+#define __sanitizer_syscall_post_setgid(res, gid) \
+ __sanitizer_syscall_post_impl_setgid(res, (long)(gid))
+#define __sanitizer_syscall_pre_setreuid(ruid, euid) \
+ __sanitizer_syscall_pre_impl_setreuid((long)(ruid), (long)(euid))
+#define __sanitizer_syscall_post_setreuid(res, ruid, euid) \
+ __sanitizer_syscall_post_impl_setreuid(res, (long)(ruid), (long)(euid))
+#define __sanitizer_syscall_pre_setuid(uid) \
+ __sanitizer_syscall_pre_impl_setuid((long)(uid))
+#define __sanitizer_syscall_post_setuid(res, uid) \
+ __sanitizer_syscall_post_impl_setuid(res, (long)(uid))
+#define __sanitizer_syscall_pre_setresuid(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_setresuid((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_setresuid(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_setresuid(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_setresgid(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_setresgid((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_setresgid(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_setresgid(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_setfsuid(uid) \
+ __sanitizer_syscall_pre_impl_setfsuid((long)(uid))
+#define __sanitizer_syscall_post_setfsuid(res, uid) \
+ __sanitizer_syscall_post_impl_setfsuid(res, (long)(uid))
+#define __sanitizer_syscall_pre_setfsgid(gid) \
+ __sanitizer_syscall_pre_impl_setfsgid((long)(gid))
+#define __sanitizer_syscall_post_setfsgid(res, gid) \
+ __sanitizer_syscall_post_impl_setfsgid(res, (long)(gid))
+#define __sanitizer_syscall_pre_setpgid(pid, pgid) \
+ __sanitizer_syscall_pre_impl_setpgid((long)(pid), (long)(pgid))
+#define __sanitizer_syscall_post_setpgid(res, pid, pgid) \
+ __sanitizer_syscall_post_impl_setpgid(res, (long)(pid), (long)(pgid))
+#define __sanitizer_syscall_pre_setsid() __sanitizer_syscall_pre_impl_setsid()
+#define __sanitizer_syscall_post_setsid(res) \
+ __sanitizer_syscall_post_impl_setsid(res)
+#define __sanitizer_syscall_pre_setgroups(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_setgroups((long)(gidsetsize), (long)(grouplist))
+#define __sanitizer_syscall_post_setgroups(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_setgroups(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_acct(name) \
+ __sanitizer_syscall_pre_impl_acct((long)(name))
+#define __sanitizer_syscall_post_acct(res, name) \
+ __sanitizer_syscall_post_impl_acct(res, (long)(name))
+#define __sanitizer_syscall_pre_capget(header, dataptr) \
+ __sanitizer_syscall_pre_impl_capget((long)(header), (long)(dataptr))
+#define __sanitizer_syscall_post_capget(res, header, dataptr) \
+ __sanitizer_syscall_post_impl_capget(res, (long)(header), (long)(dataptr))
+#define __sanitizer_syscall_pre_capset(header, data) \
+ __sanitizer_syscall_pre_impl_capset((long)(header), (long)(data))
+#define __sanitizer_syscall_post_capset(res, header, data) \
+ __sanitizer_syscall_post_impl_capset(res, (long)(header), (long)(data))
+#define __sanitizer_syscall_pre_personality(personality) \
+ __sanitizer_syscall_pre_impl_personality((long)(personality))
+#define __sanitizer_syscall_post_personality(res, personality) \
+ __sanitizer_syscall_post_impl_personality(res, (long)(personality))
+#define __sanitizer_syscall_pre_sigpending(set) \
+ __sanitizer_syscall_pre_impl_sigpending((long)(set))
+#define __sanitizer_syscall_post_sigpending(res, set) \
+ __sanitizer_syscall_post_impl_sigpending(res, (long)(set))
+#define __sanitizer_syscall_pre_sigprocmask(how, set, oset) \
+ __sanitizer_syscall_pre_impl_sigprocmask((long)(how), (long)(set), \
+ (long)(oset))
+#define __sanitizer_syscall_post_sigprocmask(res, how, set, oset) \
+ __sanitizer_syscall_post_impl_sigprocmask(res, (long)(how), (long)(set), \
+ (long)(oset))
+#define __sanitizer_syscall_pre_getitimer(which, value) \
+ __sanitizer_syscall_pre_impl_getitimer((long)(which), (long)(value))
+#define __sanitizer_syscall_post_getitimer(res, which, value) \
+ __sanitizer_syscall_post_impl_getitimer(res, (long)(which), (long)(value))
+#define __sanitizer_syscall_pre_setitimer(which, value, ovalue) \
+ __sanitizer_syscall_pre_impl_setitimer((long)(which), (long)(value), \
+ (long)(ovalue))
+#define __sanitizer_syscall_post_setitimer(res, which, value, ovalue) \
+ __sanitizer_syscall_post_impl_setitimer(res, (long)(which), (long)(value), \
+ (long)(ovalue))
+#define __sanitizer_syscall_pre_timer_create(which_clock, timer_event_spec, \
+ created_timer_id) \
+ __sanitizer_syscall_pre_impl_timer_create( \
+ (long)(which_clock), (long)(timer_event_spec), (long)(created_timer_id))
+#define __sanitizer_syscall_post_timer_create( \
+ res, which_clock, timer_event_spec, created_timer_id) \
+ __sanitizer_syscall_post_impl_timer_create(res, (long)(which_clock), \
+ (long)(timer_event_spec), \
+ (long)(created_timer_id))
+#define __sanitizer_syscall_pre_timer_gettime(timer_id, setting) \
+ __sanitizer_syscall_pre_impl_timer_gettime((long)(timer_id), (long)(setting))
+#define __sanitizer_syscall_post_timer_gettime(res, timer_id, setting) \
+ __sanitizer_syscall_post_impl_timer_gettime(res, (long)(timer_id), \
+ (long)(setting))
+#define __sanitizer_syscall_pre_timer_getoverrun(timer_id) \
+ __sanitizer_syscall_pre_impl_timer_getoverrun((long)(timer_id))
+#define __sanitizer_syscall_post_timer_getoverrun(res, timer_id) \
+ __sanitizer_syscall_post_impl_timer_getoverrun(res, (long)(timer_id))
+#define __sanitizer_syscall_pre_timer_settime(timer_id, flags, new_setting, \
+ old_setting) \
+ __sanitizer_syscall_pre_impl_timer_settime((long)(timer_id), (long)(flags), \
+ (long)(new_setting), \
+ (long)(old_setting))
+#define __sanitizer_syscall_post_timer_settime(res, timer_id, flags, \
+ new_setting, old_setting) \
+ __sanitizer_syscall_post_impl_timer_settime( \
+ res, (long)(timer_id), (long)(flags), (long)(new_setting), \
+ (long)(old_setting))
+#define __sanitizer_syscall_pre_timer_delete(timer_id) \
+ __sanitizer_syscall_pre_impl_timer_delete((long)(timer_id))
+#define __sanitizer_syscall_post_timer_delete(res, timer_id) \
+ __sanitizer_syscall_post_impl_timer_delete(res, (long)(timer_id))
+#define __sanitizer_syscall_pre_clock_settime(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_settime((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_settime(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_settime(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_gettime(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_gettime((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_gettime(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_gettime(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_adjtime(which_clock, tx) \
+ __sanitizer_syscall_pre_impl_clock_adjtime((long)(which_clock), (long)(tx))
+#define __sanitizer_syscall_post_clock_adjtime(res, which_clock, tx) \
+ __sanitizer_syscall_post_impl_clock_adjtime(res, (long)(which_clock), \
+ (long)(tx))
+#define __sanitizer_syscall_pre_clock_getres(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_getres((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_getres(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_getres(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_nanosleep(which_clock, flags, rqtp, \
+ rmtp) \
+ __sanitizer_syscall_pre_impl_clock_nanosleep( \
+ (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_post_clock_nanosleep(res, which_clock, flags, \
+ rqtp, rmtp) \
+ __sanitizer_syscall_post_impl_clock_nanosleep( \
+ res, (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_pre_nice(increment) \
+ __sanitizer_syscall_pre_impl_nice((long)(increment))
+#define __sanitizer_syscall_post_nice(res, increment) \
+ __sanitizer_syscall_post_impl_nice(res, (long)(increment))
+#define __sanitizer_syscall_pre_sched_setscheduler(pid, policy, param) \
+ __sanitizer_syscall_pre_impl_sched_setscheduler((long)(pid), (long)(policy), \
+ (long)(param))
+#define __sanitizer_syscall_post_sched_setscheduler(res, pid, policy, param) \
+ __sanitizer_syscall_post_impl_sched_setscheduler( \
+ res, (long)(pid), (long)(policy), (long)(param))
+#define __sanitizer_syscall_pre_sched_setparam(pid, param) \
+ __sanitizer_syscall_pre_impl_sched_setparam((long)(pid), (long)(param))
+#define __sanitizer_syscall_post_sched_setparam(res, pid, param) \
+ __sanitizer_syscall_post_impl_sched_setparam(res, (long)(pid), (long)(param))
+#define __sanitizer_syscall_pre_sched_getscheduler(pid) \
+ __sanitizer_syscall_pre_impl_sched_getscheduler((long)(pid))
+#define __sanitizer_syscall_post_sched_getscheduler(res, pid) \
+ __sanitizer_syscall_post_impl_sched_getscheduler(res, (long)(pid))
+#define __sanitizer_syscall_pre_sched_getparam(pid, param) \
+ __sanitizer_syscall_pre_impl_sched_getparam((long)(pid), (long)(param))
+#define __sanitizer_syscall_post_sched_getparam(res, pid, param) \
+ __sanitizer_syscall_post_impl_sched_getparam(res, (long)(pid), (long)(param))
+#define __sanitizer_syscall_pre_sched_setaffinity(pid, len, user_mask_ptr) \
+ __sanitizer_syscall_pre_impl_sched_setaffinity((long)(pid), (long)(len), \
+ (long)(user_mask_ptr))
+#define __sanitizer_syscall_post_sched_setaffinity(res, pid, len, \
+ user_mask_ptr) \
+ __sanitizer_syscall_post_impl_sched_setaffinity( \
+ res, (long)(pid), (long)(len), (long)(user_mask_ptr))
+#define __sanitizer_syscall_pre_sched_getaffinity(pid, len, user_mask_ptr) \
+ __sanitizer_syscall_pre_impl_sched_getaffinity((long)(pid), (long)(len), \
+ (long)(user_mask_ptr))
+#define __sanitizer_syscall_post_sched_getaffinity(res, pid, len, \
+ user_mask_ptr) \
+ __sanitizer_syscall_post_impl_sched_getaffinity( \
+ res, (long)(pid), (long)(len), (long)(user_mask_ptr))
+#define __sanitizer_syscall_pre_sched_yield() \
+ __sanitizer_syscall_pre_impl_sched_yield()
+#define __sanitizer_syscall_post_sched_yield(res) \
+ __sanitizer_syscall_post_impl_sched_yield(res)
+#define __sanitizer_syscall_pre_sched_get_priority_max(policy) \
+ __sanitizer_syscall_pre_impl_sched_get_priority_max((long)(policy))
+#define __sanitizer_syscall_post_sched_get_priority_max(res, policy) \
+ __sanitizer_syscall_post_impl_sched_get_priority_max(res, (long)(policy))
+#define __sanitizer_syscall_pre_sched_get_priority_min(policy) \
+ __sanitizer_syscall_pre_impl_sched_get_priority_min((long)(policy))
+#define __sanitizer_syscall_post_sched_get_priority_min(res, policy) \
+ __sanitizer_syscall_post_impl_sched_get_priority_min(res, (long)(policy))
+#define __sanitizer_syscall_pre_sched_rr_get_interval(pid, interval) \
+ __sanitizer_syscall_pre_impl_sched_rr_get_interval((long)(pid), \
+ (long)(interval))
+#define __sanitizer_syscall_post_sched_rr_get_interval(res, pid, interval) \
+ __sanitizer_syscall_post_impl_sched_rr_get_interval(res, (long)(pid), \
+ (long)(interval))
+#define __sanitizer_syscall_pre_setpriority(which, who, niceval) \
+ __sanitizer_syscall_pre_impl_setpriority((long)(which), (long)(who), \
+ (long)(niceval))
+#define __sanitizer_syscall_post_setpriority(res, which, who, niceval) \
+ __sanitizer_syscall_post_impl_setpriority(res, (long)(which), (long)(who), \
+ (long)(niceval))
+#define __sanitizer_syscall_pre_getpriority(which, who) \
+ __sanitizer_syscall_pre_impl_getpriority((long)(which), (long)(who))
+#define __sanitizer_syscall_post_getpriority(res, which, who) \
+ __sanitizer_syscall_post_impl_getpriority(res, (long)(which), (long)(who))
+#define __sanitizer_syscall_pre_shutdown(arg0, arg1) \
+ __sanitizer_syscall_pre_impl_shutdown((long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_post_shutdown(res, arg0, arg1) \
+ __sanitizer_syscall_post_impl_shutdown(res, (long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_pre_reboot(magic1, magic2, cmd, arg) \
+ __sanitizer_syscall_pre_impl_reboot((long)(magic1), (long)(magic2), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_reboot(res, magic1, magic2, cmd, arg) \
+ __sanitizer_syscall_post_impl_reboot(res, (long)(magic1), (long)(magic2), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_restart_syscall() \
+ __sanitizer_syscall_pre_impl_restart_syscall()
+#define __sanitizer_syscall_post_restart_syscall(res) \
+ __sanitizer_syscall_post_impl_restart_syscall(res)
+#define __sanitizer_syscall_pre_kexec_load(entry, nr_segments, segments, \
+ flags) \
+ __sanitizer_syscall_pre_impl_kexec_load((long)(entry), (long)(nr_segments), \
+ (long)(segments), (long)(flags))
+#define __sanitizer_syscall_post_kexec_load(res, entry, nr_segments, segments, \
+ flags) \
+ __sanitizer_syscall_post_impl_kexec_load(res, (long)(entry), \
+ (long)(nr_segments), \
+ (long)(segments), (long)(flags))
+#define __sanitizer_syscall_pre_exit(error_code) \
+ __sanitizer_syscall_pre_impl_exit((long)(error_code))
+#define __sanitizer_syscall_post_exit(res, error_code) \
+ __sanitizer_syscall_post_impl_exit(res, (long)(error_code))
+#define __sanitizer_syscall_pre_exit_group(error_code) \
+ __sanitizer_syscall_pre_impl_exit_group((long)(error_code))
+#define __sanitizer_syscall_post_exit_group(res, error_code) \
+ __sanitizer_syscall_post_impl_exit_group(res, (long)(error_code))
+#define __sanitizer_syscall_pre_wait4(pid, stat_addr, options, ru) \
+ __sanitizer_syscall_pre_impl_wait4((long)(pid), (long)(stat_addr), \
+ (long)(options), (long)(ru))
+#define __sanitizer_syscall_post_wait4(res, pid, stat_addr, options, ru) \
+ __sanitizer_syscall_post_impl_wait4(res, (long)(pid), (long)(stat_addr), \
+ (long)(options), (long)(ru))
+#define __sanitizer_syscall_pre_waitid(which, pid, infop, options, ru) \
+ __sanitizer_syscall_pre_impl_waitid( \
+ (long)(which), (long)(pid), (long)(infop), (long)(options), (long)(ru))
+#define __sanitizer_syscall_post_waitid(res, which, pid, infop, options, ru) \
+ __sanitizer_syscall_post_impl_waitid(res, (long)(which), (long)(pid), \
+ (long)(infop), (long)(options), \
+ (long)(ru))
+#define __sanitizer_syscall_pre_waitpid(pid, stat_addr, options) \
+ __sanitizer_syscall_pre_impl_waitpid((long)(pid), (long)(stat_addr), \
+ (long)(options))
+#define __sanitizer_syscall_post_waitpid(res, pid, stat_addr, options) \
+ __sanitizer_syscall_post_impl_waitpid(res, (long)(pid), (long)(stat_addr), \
+ (long)(options))
+#define __sanitizer_syscall_pre_set_tid_address(tidptr) \
+ __sanitizer_syscall_pre_impl_set_tid_address((long)(tidptr))
+#define __sanitizer_syscall_post_set_tid_address(res, tidptr) \
+ __sanitizer_syscall_post_impl_set_tid_address(res, (long)(tidptr))
+#define __sanitizer_syscall_pre_init_module(umod, len, uargs) \
+ __sanitizer_syscall_pre_impl_init_module((long)(umod), (long)(len), \
+ (long)(uargs))
+#define __sanitizer_syscall_post_init_module(res, umod, len, uargs) \
+ __sanitizer_syscall_post_impl_init_module(res, (long)(umod), (long)(len), \
+ (long)(uargs))
+#define __sanitizer_syscall_pre_delete_module(name_user, flags) \
+ __sanitizer_syscall_pre_impl_delete_module((long)(name_user), (long)(flags))
+#define __sanitizer_syscall_post_delete_module(res, name_user, flags) \
+ __sanitizer_syscall_post_impl_delete_module(res, (long)(name_user), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_rt_sigprocmask(how, set, oset, sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigprocmask( \
+ (long)(how), (long)(set), (long)(oset), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigprocmask(res, how, set, oset, \
+ sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigprocmask( \
+ res, (long)(how), (long)(set), (long)(oset), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_sigpending(set, sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigpending((long)(set), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigpending(res, set, sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigpending(res, (long)(set), \
+ (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_sigtimedwait(uthese, uinfo, uts, \
+ sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigtimedwait( \
+ (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigtimedwait(res, uthese, uinfo, uts, \
+ sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigtimedwait( \
+ res, (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(tgid, pid, sig, uinfo) \
+ __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo((long)(tgid), (long)(pid), \
+ (long)(sig), (long)(uinfo))
+#define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, tgid, pid, sig, uinfo) \
+ __sanitizer_syscall_post_impl_rt_tgsigqueueinfo( \
+ res, (long)(tgid), (long)(pid), (long)(sig), (long)(uinfo))
+#define __sanitizer_syscall_pre_kill(pid, sig) \
+ __sanitizer_syscall_pre_impl_kill((long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_kill(res, pid, sig) \
+ __sanitizer_syscall_post_impl_kill(res, (long)(pid), (long)(sig))
+#define __sanitizer_syscall_pre_tgkill(tgid, pid, sig) \
+ __sanitizer_syscall_pre_impl_tgkill((long)(tgid), (long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_tgkill(res, tgid, pid, sig) \
+ __sanitizer_syscall_post_impl_tgkill(res, (long)(tgid), (long)(pid), \
+ (long)(sig))
+#define __sanitizer_syscall_pre_tkill(pid, sig) \
+ __sanitizer_syscall_pre_impl_tkill((long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_tkill(res, pid, sig) \
+ __sanitizer_syscall_post_impl_tkill(res, (long)(pid), (long)(sig))
+#define __sanitizer_syscall_pre_rt_sigqueueinfo(pid, sig, uinfo) \
+ __sanitizer_syscall_pre_impl_rt_sigqueueinfo((long)(pid), (long)(sig), \
+ (long)(uinfo))
+#define __sanitizer_syscall_post_rt_sigqueueinfo(res, pid, sig, uinfo) \
+ __sanitizer_syscall_post_impl_rt_sigqueueinfo(res, (long)(pid), (long)(sig), \
+ (long)(uinfo))
+#define __sanitizer_syscall_pre_sgetmask() \
+ __sanitizer_syscall_pre_impl_sgetmask()
+#define __sanitizer_syscall_post_sgetmask(res) \
+ __sanitizer_syscall_post_impl_sgetmask(res)
+#define __sanitizer_syscall_pre_ssetmask(newmask) \
+ __sanitizer_syscall_pre_impl_ssetmask((long)(newmask))
+#define __sanitizer_syscall_post_ssetmask(res, newmask) \
+ __sanitizer_syscall_post_impl_ssetmask(res, (long)(newmask))
+#define __sanitizer_syscall_pre_signal(sig, handler) \
+ __sanitizer_syscall_pre_impl_signal((long)(sig), (long)(handler))
+#define __sanitizer_syscall_post_signal(res, sig, handler) \
+ __sanitizer_syscall_post_impl_signal(res, (long)(sig), (long)(handler))
+#define __sanitizer_syscall_pre_pause() __sanitizer_syscall_pre_impl_pause()
+#define __sanitizer_syscall_post_pause(res) \
+ __sanitizer_syscall_post_impl_pause(res)
+#define __sanitizer_syscall_pre_sync() __sanitizer_syscall_pre_impl_sync()
+#define __sanitizer_syscall_post_sync(res) \
+ __sanitizer_syscall_post_impl_sync(res)
+#define __sanitizer_syscall_pre_fsync(fd) \
+ __sanitizer_syscall_pre_impl_fsync((long)(fd))
+#define __sanitizer_syscall_post_fsync(res, fd) \
+ __sanitizer_syscall_post_impl_fsync(res, (long)(fd))
+#define __sanitizer_syscall_pre_fdatasync(fd) \
+ __sanitizer_syscall_pre_impl_fdatasync((long)(fd))
+#define __sanitizer_syscall_post_fdatasync(res, fd) \
+ __sanitizer_syscall_post_impl_fdatasync(res, (long)(fd))
+#define __sanitizer_syscall_pre_bdflush(func, data) \
+ __sanitizer_syscall_pre_impl_bdflush((long)(func), (long)(data))
+#define __sanitizer_syscall_post_bdflush(res, func, data) \
+ __sanitizer_syscall_post_impl_bdflush(res, (long)(func), (long)(data))
+#define __sanitizer_syscall_pre_mount(dev_name, dir_name, type, flags, data) \
+ __sanitizer_syscall_pre_impl_mount((long)(dev_name), (long)(dir_name), \
+ (long)(type), (long)(flags), \
+ (long)(data))
+#define __sanitizer_syscall_post_mount(res, dev_name, dir_name, type, flags, \
+ data) \
+ __sanitizer_syscall_post_impl_mount(res, (long)(dev_name), (long)(dir_name), \
+ (long)(type), (long)(flags), \
+ (long)(data))
+#define __sanitizer_syscall_pre_umount(name, flags) \
+ __sanitizer_syscall_pre_impl_umount((long)(name), (long)(flags))
+#define __sanitizer_syscall_post_umount(res, name, flags) \
+ __sanitizer_syscall_post_impl_umount(res, (long)(name), (long)(flags))
+#define __sanitizer_syscall_pre_oldumount(name) \
+ __sanitizer_syscall_pre_impl_oldumount((long)(name))
+#define __sanitizer_syscall_post_oldumount(res, name) \
+ __sanitizer_syscall_post_impl_oldumount(res, (long)(name))
+#define __sanitizer_syscall_pre_truncate(path, length) \
+ __sanitizer_syscall_pre_impl_truncate((long)(path), (long)(length))
+#define __sanitizer_syscall_post_truncate(res, path, length) \
+ __sanitizer_syscall_post_impl_truncate(res, (long)(path), (long)(length))
+#define __sanitizer_syscall_pre_ftruncate(fd, length) \
+ __sanitizer_syscall_pre_impl_ftruncate((long)(fd), (long)(length))
+#define __sanitizer_syscall_post_ftruncate(res, fd, length) \
+ __sanitizer_syscall_post_impl_ftruncate(res, (long)(fd), (long)(length))
+#define __sanitizer_syscall_pre_stat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_stat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_stat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_stat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_statfs(path, buf) \
+ __sanitizer_syscall_pre_impl_statfs((long)(path), (long)(buf))
+#define __sanitizer_syscall_post_statfs(res, path, buf) \
+ __sanitizer_syscall_post_impl_statfs(res, (long)(path), (long)(buf))
+#define __sanitizer_syscall_pre_statfs64(path, sz, buf) \
+ __sanitizer_syscall_pre_impl_statfs64((long)(path), (long)(sz), (long)(buf))
+#define __sanitizer_syscall_post_statfs64(res, path, sz, buf) \
+ __sanitizer_syscall_post_impl_statfs64(res, (long)(path), (long)(sz), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_fstatfs(fd, buf) \
+ __sanitizer_syscall_pre_impl_fstatfs((long)(fd), (long)(buf))
+#define __sanitizer_syscall_post_fstatfs(res, fd, buf) \
+ __sanitizer_syscall_post_impl_fstatfs(res, (long)(fd), (long)(buf))
+#define __sanitizer_syscall_pre_fstatfs64(fd, sz, buf) \
+ __sanitizer_syscall_pre_impl_fstatfs64((long)(fd), (long)(sz), (long)(buf))
+#define __sanitizer_syscall_post_fstatfs64(res, fd, sz, buf) \
+ __sanitizer_syscall_post_impl_fstatfs64(res, (long)(fd), (long)(sz), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_lstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_lstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_lstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_lstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_fstat(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_fstat((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_fstat(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_fstat(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_newstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_newstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_newstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_newstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_newlstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_newlstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_newlstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_newlstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_newfstat(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_newfstat((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_newfstat(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_newfstat(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_ustat(dev, ubuf) \
+ __sanitizer_syscall_pre_impl_ustat((long)(dev), (long)(ubuf))
+#define __sanitizer_syscall_post_ustat(res, dev, ubuf) \
+ __sanitizer_syscall_post_impl_ustat(res, (long)(dev), (long)(ubuf))
+#define __sanitizer_syscall_pre_stat64(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_stat64((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_stat64(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_stat64(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_fstat64(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_fstat64((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_fstat64(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_fstat64(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_lstat64(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_lstat64((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_lstat64(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_lstat64(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_setxattr(path, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_setxattr( \
+ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_setxattr(res, path, name, value, size, flags) \
+ __sanitizer_syscall_post_impl_setxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_lsetxattr(path, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_lsetxattr( \
+ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_lsetxattr(res, path, name, value, size, \
+ flags) \
+ __sanitizer_syscall_post_impl_lsetxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_fsetxattr(fd, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_fsetxattr( \
+ (long)(fd), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_fsetxattr(res, fd, name, value, size, flags) \
+ __sanitizer_syscall_post_impl_fsetxattr(res, (long)(fd), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_getxattr(path, name, value, size) \
+ __sanitizer_syscall_pre_impl_getxattr((long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_getxattr(res, path, name, value, size) \
+ __sanitizer_syscall_post_impl_getxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_lgetxattr(path, name, value, size) \
+ __sanitizer_syscall_pre_impl_lgetxattr((long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_lgetxattr(res, path, name, value, size) \
+ __sanitizer_syscall_post_impl_lgetxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_fgetxattr(fd, name, value, size) \
+ __sanitizer_syscall_pre_impl_fgetxattr((long)(fd), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_fgetxattr(res, fd, name, value, size) \
+ __sanitizer_syscall_post_impl_fgetxattr(res, (long)(fd), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_listxattr(path, list, size) \
+ __sanitizer_syscall_pre_impl_listxattr((long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_listxattr(res, path, list, size) \
+ __sanitizer_syscall_post_impl_listxattr(res, (long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_llistxattr(path, list, size) \
+ __sanitizer_syscall_pre_impl_llistxattr((long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_llistxattr(res, path, list, size) \
+ __sanitizer_syscall_post_impl_llistxattr(res, (long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_flistxattr(fd, list, size) \
+ __sanitizer_syscall_pre_impl_flistxattr((long)(fd), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_flistxattr(res, fd, list, size) \
+ __sanitizer_syscall_post_impl_flistxattr(res, (long)(fd), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_removexattr(path, name) \
+ __sanitizer_syscall_pre_impl_removexattr((long)(path), (long)(name))
+#define __sanitizer_syscall_post_removexattr(res, path, name) \
+ __sanitizer_syscall_post_impl_removexattr(res, (long)(path), (long)(name))
+#define __sanitizer_syscall_pre_lremovexattr(path, name) \
+ __sanitizer_syscall_pre_impl_lremovexattr((long)(path), (long)(name))
+#define __sanitizer_syscall_post_lremovexattr(res, path, name) \
+ __sanitizer_syscall_post_impl_lremovexattr(res, (long)(path), (long)(name))
+#define __sanitizer_syscall_pre_fremovexattr(fd, name) \
+ __sanitizer_syscall_pre_impl_fremovexattr((long)(fd), (long)(name))
+#define __sanitizer_syscall_post_fremovexattr(res, fd, name) \
+ __sanitizer_syscall_post_impl_fremovexattr(res, (long)(fd), (long)(name))
+#define __sanitizer_syscall_pre_brk(brk) \
+ __sanitizer_syscall_pre_impl_brk((long)(brk))
+#define __sanitizer_syscall_post_brk(res, brk) \
+ __sanitizer_syscall_post_impl_brk(res, (long)(brk))
+#define __sanitizer_syscall_pre_mprotect(start, len, prot) \
+ __sanitizer_syscall_pre_impl_mprotect((long)(start), (long)(len), \
+ (long)(prot))
+#define __sanitizer_syscall_post_mprotect(res, start, len, prot) \
+ __sanitizer_syscall_post_impl_mprotect(res, (long)(start), (long)(len), \
+ (long)(prot))
+#define __sanitizer_syscall_pre_mremap(addr, old_len, new_len, flags, \
+ new_addr) \
+ __sanitizer_syscall_pre_impl_mremap((long)(addr), (long)(old_len), \
+ (long)(new_len), (long)(flags), \
+ (long)(new_addr))
+#define __sanitizer_syscall_post_mremap(res, addr, old_len, new_len, flags, \
+ new_addr) \
+ __sanitizer_syscall_post_impl_mremap(res, (long)(addr), (long)(old_len), \
+ (long)(new_len), (long)(flags), \
+ (long)(new_addr))
+#define __sanitizer_syscall_pre_remap_file_pages(start, size, prot, pgoff, \
+ flags) \
+ __sanitizer_syscall_pre_impl_remap_file_pages( \
+ (long)(start), (long)(size), (long)(prot), (long)(pgoff), (long)(flags))
+#define __sanitizer_syscall_post_remap_file_pages(res, start, size, prot, \
+ pgoff, flags) \
+ __sanitizer_syscall_post_impl_remap_file_pages(res, (long)(start), \
+ (long)(size), (long)(prot), \
+ (long)(pgoff), (long)(flags))
+#define __sanitizer_syscall_pre_msync(start, len, flags) \
+ __sanitizer_syscall_pre_impl_msync((long)(start), (long)(len), (long)(flags))
+#define __sanitizer_syscall_post_msync(res, start, len, flags) \
+ __sanitizer_syscall_post_impl_msync(res, (long)(start), (long)(len), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_munmap(addr, len) \
+ __sanitizer_syscall_pre_impl_munmap((long)(addr), (long)(len))
+#define __sanitizer_syscall_post_munmap(res, addr, len) \
+ __sanitizer_syscall_post_impl_munmap(res, (long)(addr), (long)(len))
+#define __sanitizer_syscall_pre_mlock(start, len) \
+ __sanitizer_syscall_pre_impl_mlock((long)(start), (long)(len))
+#define __sanitizer_syscall_post_mlock(res, start, len) \
+ __sanitizer_syscall_post_impl_mlock(res, (long)(start), (long)(len))
+#define __sanitizer_syscall_pre_munlock(start, len) \
+ __sanitizer_syscall_pre_impl_munlock((long)(start), (long)(len))
+#define __sanitizer_syscall_post_munlock(res, start, len) \
+ __sanitizer_syscall_post_impl_munlock(res, (long)(start), (long)(len))
+#define __sanitizer_syscall_pre_mlockall(flags) \
+ __sanitizer_syscall_pre_impl_mlockall((long)(flags))
+#define __sanitizer_syscall_post_mlockall(res, flags) \
+ __sanitizer_syscall_post_impl_mlockall(res, (long)(flags))
+#define __sanitizer_syscall_pre_munlockall() \
+ __sanitizer_syscall_pre_impl_munlockall()
+#define __sanitizer_syscall_post_munlockall(res) \
+ __sanitizer_syscall_post_impl_munlockall(res)
+#define __sanitizer_syscall_pre_madvise(start, len, behavior) \
+ __sanitizer_syscall_pre_impl_madvise((long)(start), (long)(len), \
+ (long)(behavior))
+#define __sanitizer_syscall_post_madvise(res, start, len, behavior) \
+ __sanitizer_syscall_post_impl_madvise(res, (long)(start), (long)(len), \
+ (long)(behavior))
+#define __sanitizer_syscall_pre_mincore(start, len, vec) \
+ __sanitizer_syscall_pre_impl_mincore((long)(start), (long)(len), (long)(vec))
+#define __sanitizer_syscall_post_mincore(res, start, len, vec) \
+ __sanitizer_syscall_post_impl_mincore(res, (long)(start), (long)(len), \
+ (long)(vec))
+#define __sanitizer_syscall_pre_pivot_root(new_root, put_old) \
+ __sanitizer_syscall_pre_impl_pivot_root((long)(new_root), (long)(put_old))
+#define __sanitizer_syscall_post_pivot_root(res, new_root, put_old) \
+ __sanitizer_syscall_post_impl_pivot_root(res, (long)(new_root), \
+ (long)(put_old))
+#define __sanitizer_syscall_pre_chroot(filename) \
+ __sanitizer_syscall_pre_impl_chroot((long)(filename))
+#define __sanitizer_syscall_post_chroot(res, filename) \
+ __sanitizer_syscall_post_impl_chroot(res, (long)(filename))
+#define __sanitizer_syscall_pre_mknod(filename, mode, dev) \
+ __sanitizer_syscall_pre_impl_mknod((long)(filename), (long)(mode), \
+ (long)(dev))
+#define __sanitizer_syscall_post_mknod(res, filename, mode, dev) \
+ __sanitizer_syscall_post_impl_mknod(res, (long)(filename), (long)(mode), \
+ (long)(dev))
+#define __sanitizer_syscall_pre_link(oldname, newname) \
+ __sanitizer_syscall_pre_impl_link((long)(oldname), (long)(newname))
+#define __sanitizer_syscall_post_link(res, oldname, newname) \
+ __sanitizer_syscall_post_impl_link(res, (long)(oldname), (long)(newname))
+#define __sanitizer_syscall_pre_symlink(old, new_) \
+ __sanitizer_syscall_pre_impl_symlink((long)(old), (long)(new_))
+#define __sanitizer_syscall_post_symlink(res, old, new_) \
+ __sanitizer_syscall_post_impl_symlink(res, (long)(old), (long)(new_))
+#define __sanitizer_syscall_pre_unlink(pathname) \
+ __sanitizer_syscall_pre_impl_unlink((long)(pathname))
+#define __sanitizer_syscall_post_unlink(res, pathname) \
+ __sanitizer_syscall_post_impl_unlink(res, (long)(pathname))
+#define __sanitizer_syscall_pre_rename(oldname, newname) \
+ __sanitizer_syscall_pre_impl_rename((long)(oldname), (long)(newname))
+#define __sanitizer_syscall_post_rename(res, oldname, newname) \
+ __sanitizer_syscall_post_impl_rename(res, (long)(oldname), (long)(newname))
+#define __sanitizer_syscall_pre_chmod(filename, mode) \
+ __sanitizer_syscall_pre_impl_chmod((long)(filename), (long)(mode))
+#define __sanitizer_syscall_post_chmod(res, filename, mode) \
+ __sanitizer_syscall_post_impl_chmod(res, (long)(filename), (long)(mode))
+#define __sanitizer_syscall_pre_fchmod(fd, mode) \
+ __sanitizer_syscall_pre_impl_fchmod((long)(fd), (long)(mode))
+#define __sanitizer_syscall_post_fchmod(res, fd, mode) \
+ __sanitizer_syscall_post_impl_fchmod(res, (long)(fd), (long)(mode))
+#define __sanitizer_syscall_pre_fcntl(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_fcntl((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_fcntl(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_fcntl(res, (long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_fcntl64(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_fcntl64((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_fcntl64(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_fcntl64(res, (long)(fd), (long)(cmd), \
+ (long)(arg))
+#define __sanitizer_syscall_pre_pipe(fildes) \
+ __sanitizer_syscall_pre_impl_pipe((long)(fildes))
+#define __sanitizer_syscall_post_pipe(res, fildes) \
+ __sanitizer_syscall_post_impl_pipe(res, (long)(fildes))
+#define __sanitizer_syscall_pre_pipe2(fildes, flags) \
+ __sanitizer_syscall_pre_impl_pipe2((long)(fildes), (long)(flags))
+#define __sanitizer_syscall_post_pipe2(res, fildes, flags) \
+ __sanitizer_syscall_post_impl_pipe2(res, (long)(fildes), (long)(flags))
+#define __sanitizer_syscall_pre_dup(fildes) \
+ __sanitizer_syscall_pre_impl_dup((long)(fildes))
+#define __sanitizer_syscall_post_dup(res, fildes) \
+ __sanitizer_syscall_post_impl_dup(res, (long)(fildes))
+#define __sanitizer_syscall_pre_dup2(oldfd, newfd) \
+ __sanitizer_syscall_pre_impl_dup2((long)(oldfd), (long)(newfd))
+#define __sanitizer_syscall_post_dup2(res, oldfd, newfd) \
+ __sanitizer_syscall_post_impl_dup2(res, (long)(oldfd), (long)(newfd))
+#define __sanitizer_syscall_pre_dup3(oldfd, newfd, flags) \
+ __sanitizer_syscall_pre_impl_dup3((long)(oldfd), (long)(newfd), (long)(flags))
+#define __sanitizer_syscall_post_dup3(res, oldfd, newfd, flags) \
+ __sanitizer_syscall_post_impl_dup3(res, (long)(oldfd), (long)(newfd), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_ioperm(from, num, on) \
+ __sanitizer_syscall_pre_impl_ioperm((long)(from), (long)(num), (long)(on))
+#define __sanitizer_syscall_post_ioperm(res, from, num, on) \
+ __sanitizer_syscall_post_impl_ioperm(res, (long)(from), (long)(num), \
+ (long)(on))
+#define __sanitizer_syscall_pre_ioctl(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_ioctl((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_ioctl(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_ioctl(res, (long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_flock(fd, cmd) \
+ __sanitizer_syscall_pre_impl_flock((long)(fd), (long)(cmd))
+#define __sanitizer_syscall_post_flock(res, fd, cmd) \
+ __sanitizer_syscall_post_impl_flock(res, (long)(fd), (long)(cmd))
+#define __sanitizer_syscall_pre_io_setup(nr_reqs, ctx) \
+ __sanitizer_syscall_pre_impl_io_setup((long)(nr_reqs), (long)(ctx))
+#define __sanitizer_syscall_post_io_setup(res, nr_reqs, ctx) \
+ __sanitizer_syscall_post_impl_io_setup(res, (long)(nr_reqs), (long)(ctx))
+#define __sanitizer_syscall_pre_io_destroy(ctx) \
+ __sanitizer_syscall_pre_impl_io_destroy((long)(ctx))
+#define __sanitizer_syscall_post_io_destroy(res, ctx) \
+ __sanitizer_syscall_post_impl_io_destroy(res, (long)(ctx))
+#define __sanitizer_syscall_pre_io_getevents(ctx_id, min_nr, nr, events, \
+ timeout) \
+ __sanitizer_syscall_pre_impl_io_getevents((long)(ctx_id), (long)(min_nr), \
+ (long)(nr), (long)(events), \
+ (long)(timeout))
+#define __sanitizer_syscall_post_io_getevents(res, ctx_id, min_nr, nr, events, \
+ timeout) \
+ __sanitizer_syscall_post_impl_io_getevents(res, (long)(ctx_id), \
+ (long)(min_nr), (long)(nr), \
+ (long)(events), (long)(timeout))
+#define __sanitizer_syscall_pre_io_submit(ctx_id, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_io_submit((long)(ctx_id), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_io_submit(res, ctx_id, arg1, arg2) \
+ __sanitizer_syscall_post_impl_io_submit(res, (long)(ctx_id), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_io_cancel(ctx_id, iocb, result) \
+ __sanitizer_syscall_pre_impl_io_cancel((long)(ctx_id), (long)(iocb), \
+ (long)(result))
+#define __sanitizer_syscall_post_io_cancel(res, ctx_id, iocb, result) \
+ __sanitizer_syscall_post_impl_io_cancel(res, (long)(ctx_id), (long)(iocb), \
+ (long)(result))
+#define __sanitizer_syscall_pre_sendfile(out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_pre_impl_sendfile((long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_post_sendfile(res, out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_post_impl_sendfile(res, (long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_pre_sendfile64(out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_pre_impl_sendfile64((long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_post_sendfile64(res, out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_post_impl_sendfile64(res, (long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_pre_readlink(path, buf, bufsiz) \
+ __sanitizer_syscall_pre_impl_readlink((long)(path), (long)(buf), \
+ (long)(bufsiz))
+#define __sanitizer_syscall_post_readlink(res, path, buf, bufsiz) \
+ __sanitizer_syscall_post_impl_readlink(res, (long)(path), (long)(buf), \
+ (long)(bufsiz))
+#define __sanitizer_syscall_pre_creat(pathname, mode) \
+ __sanitizer_syscall_pre_impl_creat((long)(pathname), (long)(mode))
+#define __sanitizer_syscall_post_creat(res, pathname, mode) \
+ __sanitizer_syscall_post_impl_creat(res, (long)(pathname), (long)(mode))
+#define __sanitizer_syscall_pre_open(filename, flags, mode) \
+ __sanitizer_syscall_pre_impl_open((long)(filename), (long)(flags), \
+ (long)(mode))
+#define __sanitizer_syscall_post_open(res, filename, flags, mode) \
+ __sanitizer_syscall_post_impl_open(res, (long)(filename), (long)(flags), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_close(fd) \
+ __sanitizer_syscall_pre_impl_close((long)(fd))
+#define __sanitizer_syscall_post_close(res, fd) \
+ __sanitizer_syscall_post_impl_close(res, (long)(fd))
+#define __sanitizer_syscall_pre_access(filename, mode) \
+ __sanitizer_syscall_pre_impl_access((long)(filename), (long)(mode))
+#define __sanitizer_syscall_post_access(res, filename, mode) \
+ __sanitizer_syscall_post_impl_access(res, (long)(filename), (long)(mode))
+#define __sanitizer_syscall_pre_vhangup() __sanitizer_syscall_pre_impl_vhangup()
+#define __sanitizer_syscall_post_vhangup(res) \
+ __sanitizer_syscall_post_impl_vhangup(res)
+#define __sanitizer_syscall_pre_chown(filename, user, group) \
+ __sanitizer_syscall_pre_impl_chown((long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_post_chown(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_chown(res, (long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_lchown(filename, user, group) \
+ __sanitizer_syscall_pre_impl_lchown((long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_post_lchown(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_lchown(res, (long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_fchown(fd, user, group) \
+ __sanitizer_syscall_pre_impl_fchown((long)(fd), (long)(user), (long)(group))
+#define __sanitizer_syscall_post_fchown(res, fd, user, group) \
+ __sanitizer_syscall_post_impl_fchown(res, (long)(fd), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_chown16(filename, user, group) \
+ __sanitizer_syscall_pre_impl_chown16((long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_post_chown16(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_chown16(res, (long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_lchown16(filename, user, group) \
+ __sanitizer_syscall_pre_impl_lchown16((long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_post_lchown16(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_lchown16(res, (long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_fchown16(fd, user, group) \
+ __sanitizer_syscall_pre_impl_fchown16((long)(fd), (long)user, (long)group)
+#define __sanitizer_syscall_post_fchown16(res, fd, user, group) \
+ __sanitizer_syscall_post_impl_fchown16(res, (long)(fd), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_setregid16(rgid, egid) \
+ __sanitizer_syscall_pre_impl_setregid16((long)rgid, (long)egid)
+#define __sanitizer_syscall_post_setregid16(res, rgid, egid) \
+ __sanitizer_syscall_post_impl_setregid16(res, (long)rgid, (long)egid)
+#define __sanitizer_syscall_pre_setgid16(gid) \
+ __sanitizer_syscall_pre_impl_setgid16((long)gid)
+#define __sanitizer_syscall_post_setgid16(res, gid) \
+ __sanitizer_syscall_post_impl_setgid16(res, (long)gid)
+#define __sanitizer_syscall_pre_setreuid16(ruid, euid) \
+ __sanitizer_syscall_pre_impl_setreuid16((long)ruid, (long)euid)
+#define __sanitizer_syscall_post_setreuid16(res, ruid, euid) \
+ __sanitizer_syscall_post_impl_setreuid16(res, (long)ruid, (long)euid)
+#define __sanitizer_syscall_pre_setuid16(uid) \
+ __sanitizer_syscall_pre_impl_setuid16((long)uid)
+#define __sanitizer_syscall_post_setuid16(res, uid) \
+ __sanitizer_syscall_post_impl_setuid16(res, (long)uid)
+#define __sanitizer_syscall_pre_setresuid16(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_setresuid16((long)ruid, (long)euid, (long)suid)
+#define __sanitizer_syscall_post_setresuid16(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_setresuid16(res, (long)ruid, (long)euid, \
+ (long)suid)
+#define __sanitizer_syscall_pre_getresuid16(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_getresuid16((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_getresuid16(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_getresuid16(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_setresgid16(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_setresgid16((long)rgid, (long)egid, (long)sgid)
+#define __sanitizer_syscall_post_setresgid16(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_setresgid16(res, (long)rgid, (long)egid, \
+ (long)sgid)
+#define __sanitizer_syscall_pre_getresgid16(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_getresgid16((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_getresgid16(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_getresgid16(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_setfsuid16(uid) \
+ __sanitizer_syscall_pre_impl_setfsuid16((long)uid)
+#define __sanitizer_syscall_post_setfsuid16(res, uid) \
+ __sanitizer_syscall_post_impl_setfsuid16(res, (long)uid)
+#define __sanitizer_syscall_pre_setfsgid16(gid) \
+ __sanitizer_syscall_pre_impl_setfsgid16((long)gid)
+#define __sanitizer_syscall_post_setfsgid16(res, gid) \
+ __sanitizer_syscall_post_impl_setfsgid16(res, (long)gid)
+#define __sanitizer_syscall_pre_getgroups16(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_getgroups16((long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_post_getgroups16(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_getgroups16(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_setgroups16(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_setgroups16((long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_post_setgroups16(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_setgroups16(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_getuid16() \
+ __sanitizer_syscall_pre_impl_getuid16()
+#define __sanitizer_syscall_post_getuid16(res) \
+ __sanitizer_syscall_post_impl_getuid16(res)
+#define __sanitizer_syscall_pre_geteuid16() \
+ __sanitizer_syscall_pre_impl_geteuid16()
+#define __sanitizer_syscall_post_geteuid16(res) \
+ __sanitizer_syscall_post_impl_geteuid16(res)
+#define __sanitizer_syscall_pre_getgid16() \
+ __sanitizer_syscall_pre_impl_getgid16()
+#define __sanitizer_syscall_post_getgid16(res) \
+ __sanitizer_syscall_post_impl_getgid16(res)
+#define __sanitizer_syscall_pre_getegid16() \
+ __sanitizer_syscall_pre_impl_getegid16()
+#define __sanitizer_syscall_post_getegid16(res) \
+ __sanitizer_syscall_post_impl_getegid16(res)
+#define __sanitizer_syscall_pre_utime(filename, times) \
+ __sanitizer_syscall_pre_impl_utime((long)(filename), (long)(times))
+#define __sanitizer_syscall_post_utime(res, filename, times) \
+ __sanitizer_syscall_post_impl_utime(res, (long)(filename), (long)(times))
+#define __sanitizer_syscall_pre_utimes(filename, utimes) \
+ __sanitizer_syscall_pre_impl_utimes((long)(filename), (long)(utimes))
+#define __sanitizer_syscall_post_utimes(res, filename, utimes) \
+ __sanitizer_syscall_post_impl_utimes(res, (long)(filename), (long)(utimes))
+#define __sanitizer_syscall_pre_lseek(fd, offset, origin) \
+ __sanitizer_syscall_pre_impl_lseek((long)(fd), (long)(offset), (long)(origin))
+#define __sanitizer_syscall_post_lseek(res, fd, offset, origin) \
+ __sanitizer_syscall_post_impl_lseek(res, (long)(fd), (long)(offset), \
+ (long)(origin))
+#define __sanitizer_syscall_pre_llseek(fd, offset_high, offset_low, result, \
+ origin) \
+ __sanitizer_syscall_pre_impl_llseek((long)(fd), (long)(offset_high), \
+ (long)(offset_low), (long)(result), \
+ (long)(origin))
+#define __sanitizer_syscall_post_llseek(res, fd, offset_high, offset_low, \
+ result, origin) \
+ __sanitizer_syscall_post_impl_llseek(res, (long)(fd), (long)(offset_high), \
+ (long)(offset_low), (long)(result), \
+ (long)(origin))
+#define __sanitizer_syscall_pre_read(fd, buf, count) \
+ __sanitizer_syscall_pre_impl_read((long)(fd), (long)(buf), (long)(count))
+#define __sanitizer_syscall_post_read(res, fd, buf, count) \
+ __sanitizer_syscall_post_impl_read(res, (long)(fd), (long)(buf), \
+ (long)(count))
+#define __sanitizer_syscall_pre_readv(fd, vec, vlen) \
+ __sanitizer_syscall_pre_impl_readv((long)(fd), (long)(vec), (long)(vlen))
+#define __sanitizer_syscall_post_readv(res, fd, vec, vlen) \
+ __sanitizer_syscall_post_impl_readv(res, (long)(fd), (long)(vec), \
+ (long)(vlen))
+#define __sanitizer_syscall_pre_write(fd, buf, count) \
+ __sanitizer_syscall_pre_impl_write((long)(fd), (long)(buf), (long)(count))
+#define __sanitizer_syscall_post_write(res, fd, buf, count) \
+ __sanitizer_syscall_post_impl_write(res, (long)(fd), (long)(buf), \
+ (long)(count))
+#define __sanitizer_syscall_pre_writev(fd, vec, vlen) \
+ __sanitizer_syscall_pre_impl_writev((long)(fd), (long)(vec), (long)(vlen))
+#define __sanitizer_syscall_post_writev(res, fd, vec, vlen) \
+ __sanitizer_syscall_post_impl_writev(res, (long)(fd), (long)(vec), \
+ (long)(vlen))
+
+#ifdef _LP64
+#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos) \
+ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
+ (long)(pos))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos) \
+ __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos) \
+ __sanitizer_syscall_pre_impl_pwrite64((long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos) \
+ __sanitizer_syscall_post_impl_pwrite64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#else
+#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
+ (long)(pos0), (long)(pos1))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos0), \
+ (long)(pos1))
+#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_pre_impl_pwrite64( \
+ (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
+#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_post_impl_pwrite64( \
+ res, (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
+#endif
+
+#define __sanitizer_syscall_pre_preadv(fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_pre_impl_preadv((long)(fd), (long)(vec), (long)(vlen), \
+ (long)(pos_l), (long)(pos_h))
+#define __sanitizer_syscall_post_preadv(res, fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_post_impl_preadv(res, (long)(fd), (long)(vec), \
+ (long)(vlen), (long)(pos_l), \
+ (long)(pos_h))
+#define __sanitizer_syscall_pre_pwritev(fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_pre_impl_pwritev((long)(fd), (long)(vec), (long)(vlen), \
+ (long)(pos_l), (long)(pos_h))
+#define __sanitizer_syscall_post_pwritev(res, fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_post_impl_pwritev(res, (long)(fd), (long)(vec), \
+ (long)(vlen), (long)(pos_l), \
+ (long)(pos_h))
+#define __sanitizer_syscall_pre_getcwd(buf, size) \
+ __sanitizer_syscall_pre_impl_getcwd((long)(buf), (long)(size))
+#define __sanitizer_syscall_post_getcwd(res, buf, size) \
+ __sanitizer_syscall_post_impl_getcwd(res, (long)(buf), (long)(size))
+#define __sanitizer_syscall_pre_mkdir(pathname, mode) \
+ __sanitizer_syscall_pre_impl_mkdir((long)(pathname), (long)(mode))
+#define __sanitizer_syscall_post_mkdir(res, pathname, mode) \
+ __sanitizer_syscall_post_impl_mkdir(res, (long)(pathname), (long)(mode))
+#define __sanitizer_syscall_pre_chdir(filename) \
+ __sanitizer_syscall_pre_impl_chdir((long)(filename))
+#define __sanitizer_syscall_post_chdir(res, filename) \
+ __sanitizer_syscall_post_impl_chdir(res, (long)(filename))
+#define __sanitizer_syscall_pre_fchdir(fd) \
+ __sanitizer_syscall_pre_impl_fchdir((long)(fd))
+#define __sanitizer_syscall_post_fchdir(res, fd) \
+ __sanitizer_syscall_post_impl_fchdir(res, (long)(fd))
+#define __sanitizer_syscall_pre_rmdir(pathname) \
+ __sanitizer_syscall_pre_impl_rmdir((long)(pathname))
+#define __sanitizer_syscall_post_rmdir(res, pathname) \
+ __sanitizer_syscall_post_impl_rmdir(res, (long)(pathname))
+#define __sanitizer_syscall_pre_lookup_dcookie(cookie64, buf, len) \
+ __sanitizer_syscall_pre_impl_lookup_dcookie((long)(cookie64), (long)(buf), \
+ (long)(len))
+#define __sanitizer_syscall_post_lookup_dcookie(res, cookie64, buf, len) \
+ __sanitizer_syscall_post_impl_lookup_dcookie(res, (long)(cookie64), \
+ (long)(buf), (long)(len))
+#define __sanitizer_syscall_pre_quotactl(cmd, special, id, addr) \
+ __sanitizer_syscall_pre_impl_quotactl((long)(cmd), (long)(special), \
+ (long)(id), (long)(addr))
+#define __sanitizer_syscall_post_quotactl(res, cmd, special, id, addr) \
+ __sanitizer_syscall_post_impl_quotactl(res, (long)(cmd), (long)(special), \
+ (long)(id), (long)(addr))
+#define __sanitizer_syscall_pre_getdents(fd, dirent, count) \
+ __sanitizer_syscall_pre_impl_getdents((long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_post_getdents(res, fd, dirent, count) \
+ __sanitizer_syscall_post_impl_getdents(res, (long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_pre_getdents64(fd, dirent, count) \
+ __sanitizer_syscall_pre_impl_getdents64((long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_post_getdents64(res, fd, dirent, count) \
+ __sanitizer_syscall_post_impl_getdents64(res, (long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_pre_setsockopt(fd, level, optname, optval, optlen) \
+ __sanitizer_syscall_pre_impl_setsockopt((long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_post_setsockopt(res, fd, level, optname, optval, \
+ optlen) \
+ __sanitizer_syscall_post_impl_setsockopt(res, (long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_pre_getsockopt(fd, level, optname, optval, optlen) \
+ __sanitizer_syscall_pre_impl_getsockopt((long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_post_getsockopt(res, fd, level, optname, optval, \
+ optlen) \
+ __sanitizer_syscall_post_impl_getsockopt(res, (long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_pre_bind(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_bind((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_bind(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_bind(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_connect(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_connect((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_connect(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_connect(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_accept(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_accept((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_accept(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_accept(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_accept4(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_accept4((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_post_accept4(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_accept4(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_getsockname(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_getsockname((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_getsockname(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_getsockname(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_getpeername(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_getpeername((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_getpeername(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_getpeername(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_send(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_send((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3))
+#define __sanitizer_syscall_post_send(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_send(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_sendto(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_sendto((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_sendto(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_sendto(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_sendmsg(fd, msg, flags) \
+ __sanitizer_syscall_pre_impl_sendmsg((long)(fd), (long)(msg), (long)(flags))
+#define __sanitizer_syscall_post_sendmsg(res, fd, msg, flags) \
+ __sanitizer_syscall_post_impl_sendmsg(res, (long)(fd), (long)(msg), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_sendmmsg(fd, msg, vlen, flags) \
+ __sanitizer_syscall_pre_impl_sendmmsg((long)(fd), (long)(msg), (long)(vlen), \
+ (long)(flags))
+#define __sanitizer_syscall_post_sendmmsg(res, fd, msg, vlen, flags) \
+ __sanitizer_syscall_post_impl_sendmmsg(res, (long)(fd), (long)(msg), \
+ (long)(vlen), (long)(flags))
+#define __sanitizer_syscall_pre_recv(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_recv((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3))
+#define __sanitizer_syscall_post_recv(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_recv(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_recvfrom(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_recvfrom((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_recvfrom(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_recvfrom(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_recvmsg(fd, msg, flags) \
+ __sanitizer_syscall_pre_impl_recvmsg((long)(fd), (long)(msg), (long)(flags))
+#define __sanitizer_syscall_post_recvmsg(res, fd, msg, flags) \
+ __sanitizer_syscall_post_impl_recvmsg(res, (long)(fd), (long)(msg), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_recvmmsg(fd, msg, vlen, flags, timeout) \
+ __sanitizer_syscall_pre_impl_recvmmsg((long)(fd), (long)(msg), (long)(vlen), \
+ (long)(flags), (long)(timeout))
+#define __sanitizer_syscall_post_recvmmsg(res, fd, msg, vlen, flags, timeout) \
+ __sanitizer_syscall_post_impl_recvmmsg(res, (long)(fd), (long)(msg), \
+ (long)(vlen), (long)(flags), \
+ (long)(timeout))
+#define __sanitizer_syscall_pre_socket(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_socket((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_socket(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_socket(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_socketpair(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_socketpair((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_post_socketpair(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_socketpair(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_socketcall(call, args) \
+ __sanitizer_syscall_pre_impl_socketcall((long)(call), (long)(args))
+#define __sanitizer_syscall_post_socketcall(res, call, args) \
+ __sanitizer_syscall_post_impl_socketcall(res, (long)(call), (long)(args))
+#define __sanitizer_syscall_pre_listen(arg0, arg1) \
+ __sanitizer_syscall_pre_impl_listen((long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_post_listen(res, arg0, arg1) \
+ __sanitizer_syscall_post_impl_listen(res, (long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_pre_poll(ufds, nfds, timeout) \
+ __sanitizer_syscall_pre_impl_poll((long)(ufds), (long)(nfds), (long)(timeout))
+#define __sanitizer_syscall_post_poll(res, ufds, nfds, timeout) \
+ __sanitizer_syscall_post_impl_poll(res, (long)(ufds), (long)(nfds), \
+ (long)(timeout))
+#define __sanitizer_syscall_pre_select(n, inp, outp, exp, tvp) \
+ __sanitizer_syscall_pre_impl_select((long)(n), (long)(inp), (long)(outp), \
+ (long)(exp), (long)(tvp))
+#define __sanitizer_syscall_post_select(res, n, inp, outp, exp, tvp) \
+ __sanitizer_syscall_post_impl_select(res, (long)(n), (long)(inp), \
+ (long)(outp), (long)(exp), (long)(tvp))
+#define __sanitizer_syscall_pre_old_select(arg) \
+ __sanitizer_syscall_pre_impl_old_select((long)(arg))
+#define __sanitizer_syscall_post_old_select(res, arg) \
+ __sanitizer_syscall_post_impl_old_select(res, (long)(arg))
+#define __sanitizer_syscall_pre_epoll_create(size) \
+ __sanitizer_syscall_pre_impl_epoll_create((long)(size))
+#define __sanitizer_syscall_post_epoll_create(res, size) \
+ __sanitizer_syscall_post_impl_epoll_create(res, (long)(size))
+#define __sanitizer_syscall_pre_epoll_create1(flags) \
+ __sanitizer_syscall_pre_impl_epoll_create1((long)(flags))
+#define __sanitizer_syscall_post_epoll_create1(res, flags) \
+ __sanitizer_syscall_post_impl_epoll_create1(res, (long)(flags))
+#define __sanitizer_syscall_pre_epoll_ctl(epfd, op, fd, event) \
+ __sanitizer_syscall_pre_impl_epoll_ctl((long)(epfd), (long)(op), (long)(fd), \
+ (long)(event))
+#define __sanitizer_syscall_post_epoll_ctl(res, epfd, op, fd, event) \
+ __sanitizer_syscall_post_impl_epoll_ctl(res, (long)(epfd), (long)(op), \
+ (long)(fd), (long)(event))
+#define __sanitizer_syscall_pre_epoll_wait(epfd, events, maxevents, timeout) \
+ __sanitizer_syscall_pre_impl_epoll_wait((long)(epfd), (long)(events), \
+ (long)(maxevents), (long)(timeout))
+#define __sanitizer_syscall_post_epoll_wait(res, epfd, events, maxevents, \
+ timeout) \
+ __sanitizer_syscall_post_impl_epoll_wait(res, (long)(epfd), (long)(events), \
+ (long)(maxevents), (long)(timeout))
+#define __sanitizer_syscall_pre_epoll_pwait(epfd, events, maxevents, timeout, \
+ sigmask, sigsetsize) \
+ __sanitizer_syscall_pre_impl_epoll_pwait( \
+ (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \
+ (long)(sigmask), (long)(sigsetsize))
+#define __sanitizer_syscall_post_epoll_pwait(res, epfd, events, maxevents, \
+ timeout, sigmask, sigsetsize) \
+ __sanitizer_syscall_post_impl_epoll_pwait( \
+ res, (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \
+ (long)(sigmask), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_gethostname(name, len) \
+ __sanitizer_syscall_pre_impl_gethostname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_gethostname(res, name, len) \
+ __sanitizer_syscall_post_impl_gethostname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_sethostname(name, len) \
+ __sanitizer_syscall_pre_impl_sethostname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_sethostname(res, name, len) \
+ __sanitizer_syscall_post_impl_sethostname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_setdomainname(name, len) \
+ __sanitizer_syscall_pre_impl_setdomainname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_setdomainname(res, name, len) \
+ __sanitizer_syscall_post_impl_setdomainname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_newuname(name) \
+ __sanitizer_syscall_pre_impl_newuname((long)(name))
+#define __sanitizer_syscall_post_newuname(res, name) \
+ __sanitizer_syscall_post_impl_newuname(res, (long)(name))
+#define __sanitizer_syscall_pre_uname(arg0) \
+ __sanitizer_syscall_pre_impl_uname((long)(arg0))
+#define __sanitizer_syscall_post_uname(res, arg0) \
+ __sanitizer_syscall_post_impl_uname(res, (long)(arg0))
+#define __sanitizer_syscall_pre_olduname(arg0) \
+ __sanitizer_syscall_pre_impl_olduname((long)(arg0))
+#define __sanitizer_syscall_post_olduname(res, arg0) \
+ __sanitizer_syscall_post_impl_olduname(res, (long)(arg0))
+#define __sanitizer_syscall_pre_getrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_getrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_getrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_getrlimit(res, (long)(resource), (long)(rlim))
+#define __sanitizer_syscall_pre_old_getrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_old_getrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_old_getrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_old_getrlimit(res, (long)(resource), \
+ (long)(rlim))
+#define __sanitizer_syscall_pre_setrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_setrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_setrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_setrlimit(res, (long)(resource), (long)(rlim))
+#define __sanitizer_syscall_pre_prlimit64(pid, resource, new_rlim, old_rlim) \
+ __sanitizer_syscall_pre_impl_prlimit64((long)(pid), (long)(resource), \
+ (long)(new_rlim), (long)(old_rlim))
+#define __sanitizer_syscall_post_prlimit64(res, pid, resource, new_rlim, \
+ old_rlim) \
+ __sanitizer_syscall_post_impl_prlimit64(res, (long)(pid), (long)(resource), \
+ (long)(new_rlim), (long)(old_rlim))
+#define __sanitizer_syscall_pre_getrusage(who, ru) \
+ __sanitizer_syscall_pre_impl_getrusage((long)(who), (long)(ru))
+#define __sanitizer_syscall_post_getrusage(res, who, ru) \
+ __sanitizer_syscall_post_impl_getrusage(res, (long)(who), (long)(ru))
+#define __sanitizer_syscall_pre_umask(mask) \
+ __sanitizer_syscall_pre_impl_umask((long)(mask))
+#define __sanitizer_syscall_post_umask(res, mask) \
+ __sanitizer_syscall_post_impl_umask(res, (long)(mask))
+#define __sanitizer_syscall_pre_msgget(key, msgflg) \
+ __sanitizer_syscall_pre_impl_msgget((long)(key), (long)(msgflg))
+#define __sanitizer_syscall_post_msgget(res, key, msgflg) \
+ __sanitizer_syscall_post_impl_msgget(res, (long)(key), (long)(msgflg))
+#define __sanitizer_syscall_pre_msgsnd(msqid, msgp, msgsz, msgflg) \
+ __sanitizer_syscall_pre_impl_msgsnd((long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgflg))
+#define __sanitizer_syscall_post_msgsnd(res, msqid, msgp, msgsz, msgflg) \
+ __sanitizer_syscall_post_impl_msgsnd(res, (long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgflg))
+#define __sanitizer_syscall_pre_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) \
+ __sanitizer_syscall_pre_impl_msgrcv((long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgtyp), \
+ (long)(msgflg))
+#define __sanitizer_syscall_post_msgrcv(res, msqid, msgp, msgsz, msgtyp, \
+ msgflg) \
+ __sanitizer_syscall_post_impl_msgrcv(res, (long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgtyp), \
+ (long)(msgflg))
+#define __sanitizer_syscall_pre_msgctl(msqid, cmd, buf) \
+ __sanitizer_syscall_pre_impl_msgctl((long)(msqid), (long)(cmd), (long)(buf))
+#define __sanitizer_syscall_post_msgctl(res, msqid, cmd, buf) \
+ __sanitizer_syscall_post_impl_msgctl(res, (long)(msqid), (long)(cmd), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_semget(key, nsems, semflg) \
+ __sanitizer_syscall_pre_impl_semget((long)(key), (long)(nsems), \
+ (long)(semflg))
+#define __sanitizer_syscall_post_semget(res, key, nsems, semflg) \
+ __sanitizer_syscall_post_impl_semget(res, (long)(key), (long)(nsems), \
+ (long)(semflg))
+#define __sanitizer_syscall_pre_semop(semid, sops, nsops) \
+ __sanitizer_syscall_pre_impl_semop((long)(semid), (long)(sops), (long)(nsops))
+#define __sanitizer_syscall_post_semop(res, semid, sops, nsops) \
+ __sanitizer_syscall_post_impl_semop(res, (long)(semid), (long)(sops), \
+ (long)(nsops))
+#define __sanitizer_syscall_pre_semctl(semid, semnum, cmd, arg) \
+ __sanitizer_syscall_pre_impl_semctl((long)(semid), (long)(semnum), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_semctl(res, semid, semnum, cmd, arg) \
+ __sanitizer_syscall_post_impl_semctl(res, (long)(semid), (long)(semnum), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_semtimedop(semid, sops, nsops, timeout) \
+ __sanitizer_syscall_pre_impl_semtimedop((long)(semid), (long)(sops), \
+ (long)(nsops), (long)(timeout))
+#define __sanitizer_syscall_post_semtimedop(res, semid, sops, nsops, timeout) \
+ __sanitizer_syscall_post_impl_semtimedop(res, (long)(semid), (long)(sops), \
+ (long)(nsops), (long)(timeout))
+#define __sanitizer_syscall_pre_shmat(shmid, shmaddr, shmflg) \
+ __sanitizer_syscall_pre_impl_shmat((long)(shmid), (long)(shmaddr), \
+ (long)(shmflg))
+#define __sanitizer_syscall_post_shmat(res, shmid, shmaddr, shmflg) \
+ __sanitizer_syscall_post_impl_shmat(res, (long)(shmid), (long)(shmaddr), \
+ (long)(shmflg))
+#define __sanitizer_syscall_pre_shmget(key, size, flag) \
+ __sanitizer_syscall_pre_impl_shmget((long)(key), (long)(size), (long)(flag))
+#define __sanitizer_syscall_post_shmget(res, key, size, flag) \
+ __sanitizer_syscall_post_impl_shmget(res, (long)(key), (long)(size), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_shmdt(shmaddr) \
+ __sanitizer_syscall_pre_impl_shmdt((long)(shmaddr))
+#define __sanitizer_syscall_post_shmdt(res, shmaddr) \
+ __sanitizer_syscall_post_impl_shmdt(res, (long)(shmaddr))
+#define __sanitizer_syscall_pre_shmctl(shmid, cmd, buf) \
+ __sanitizer_syscall_pre_impl_shmctl((long)(shmid), (long)(cmd), (long)(buf))
+#define __sanitizer_syscall_post_shmctl(res, shmid, cmd, buf) \
+ __sanitizer_syscall_post_impl_shmctl(res, (long)(shmid), (long)(cmd), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_ipc(call, first, second, third, ptr, fifth) \
+ __sanitizer_syscall_pre_impl_ipc((long)(call), (long)(first), \
+ (long)(second), (long)(third), (long)(ptr), \
+ (long)(fifth))
+#define __sanitizer_syscall_post_ipc(res, call, first, second, third, ptr, \
+ fifth) \
+ __sanitizer_syscall_post_impl_ipc(res, (long)(call), (long)(first), \
+ (long)(second), (long)(third), \
+ (long)(ptr), (long)(fifth))
+#define __sanitizer_syscall_pre_mq_open(name, oflag, mode, attr) \
+ __sanitizer_syscall_pre_impl_mq_open((long)(name), (long)(oflag), \
+ (long)(mode), (long)(attr))
+#define __sanitizer_syscall_post_mq_open(res, name, oflag, mode, attr) \
+ __sanitizer_syscall_post_impl_mq_open(res, (long)(name), (long)(oflag), \
+ (long)(mode), (long)(attr))
+#define __sanitizer_syscall_pre_mq_unlink(name) \
+ __sanitizer_syscall_pre_impl_mq_unlink((long)(name))
+#define __sanitizer_syscall_post_mq_unlink(res, name) \
+ __sanitizer_syscall_post_impl_mq_unlink(res, (long)(name))
+#define __sanitizer_syscall_pre_mq_timedsend(mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_pre_impl_mq_timedsend((long)(mqdes), (long)(msg_ptr), \
+ (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_post_mq_timedsend(res, mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_post_impl_mq_timedsend( \
+ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_pre_mq_timedreceive(mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_pre_impl_mq_timedreceive( \
+ (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_post_mq_timedreceive(res, mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_post_impl_mq_timedreceive( \
+ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_pre_mq_notify(mqdes, notification) \
+ __sanitizer_syscall_pre_impl_mq_notify((long)(mqdes), (long)(notification))
+#define __sanitizer_syscall_post_mq_notify(res, mqdes, notification) \
+ __sanitizer_syscall_post_impl_mq_notify(res, (long)(mqdes), \
+ (long)(notification))
+#define __sanitizer_syscall_pre_mq_getsetattr(mqdes, mqstat, omqstat) \
+ __sanitizer_syscall_pre_impl_mq_getsetattr((long)(mqdes), (long)(mqstat), \
+ (long)(omqstat))
+#define __sanitizer_syscall_post_mq_getsetattr(res, mqdes, mqstat, omqstat) \
+ __sanitizer_syscall_post_impl_mq_getsetattr(res, (long)(mqdes), \
+ (long)(mqstat), (long)(omqstat))
+#define __sanitizer_syscall_pre_pciconfig_iobase(which, bus, devfn) \
+ __sanitizer_syscall_pre_impl_pciconfig_iobase((long)(which), (long)(bus), \
+ (long)(devfn))
+#define __sanitizer_syscall_post_pciconfig_iobase(res, which, bus, devfn) \
+ __sanitizer_syscall_post_impl_pciconfig_iobase(res, (long)(which), \
+ (long)(bus), (long)(devfn))
+#define __sanitizer_syscall_pre_pciconfig_read(bus, dfn, off, len, buf) \
+ __sanitizer_syscall_pre_impl_pciconfig_read( \
+ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_post_pciconfig_read(res, bus, dfn, off, len, buf) \
+ __sanitizer_syscall_post_impl_pciconfig_read( \
+ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_pre_pciconfig_write(bus, dfn, off, len, buf) \
+ __sanitizer_syscall_pre_impl_pciconfig_write( \
+ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_post_pciconfig_write(res, bus, dfn, off, len, buf) \
+ __sanitizer_syscall_post_impl_pciconfig_write( \
+ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_pre_swapon(specialfile, swap_flags) \
+ __sanitizer_syscall_pre_impl_swapon((long)(specialfile), (long)(swap_flags))
+#define __sanitizer_syscall_post_swapon(res, specialfile, swap_flags) \
+ __sanitizer_syscall_post_impl_swapon(res, (long)(specialfile), \
+ (long)(swap_flags))
+#define __sanitizer_syscall_pre_swapoff(specialfile) \
+ __sanitizer_syscall_pre_impl_swapoff((long)(specialfile))
+#define __sanitizer_syscall_post_swapoff(res, specialfile) \
+ __sanitizer_syscall_post_impl_swapoff(res, (long)(specialfile))
+#define __sanitizer_syscall_pre_sysctl(args) \
+ __sanitizer_syscall_pre_impl_sysctl((long)(args))
+#define __sanitizer_syscall_post_sysctl(res, args) \
+ __sanitizer_syscall_post_impl_sysctl(res, (long)(args))
+#define __sanitizer_syscall_pre_sysinfo(info) \
+ __sanitizer_syscall_pre_impl_sysinfo((long)(info))
+#define __sanitizer_syscall_post_sysinfo(res, info) \
+ __sanitizer_syscall_post_impl_sysinfo(res, (long)(info))
+#define __sanitizer_syscall_pre_sysfs(option, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_sysfs((long)(option), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_sysfs(res, option, arg1, arg2) \
+ __sanitizer_syscall_post_impl_sysfs(res, (long)(option), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_syslog(type, buf, len) \
+ __sanitizer_syscall_pre_impl_syslog((long)(type), (long)(buf), (long)(len))
+#define __sanitizer_syscall_post_syslog(res, type, buf, len) \
+ __sanitizer_syscall_post_impl_syslog(res, (long)(type), (long)(buf), \
+ (long)(len))
+#define __sanitizer_syscall_pre_uselib(library) \
+ __sanitizer_syscall_pre_impl_uselib((long)(library))
+#define __sanitizer_syscall_post_uselib(res, library) \
+ __sanitizer_syscall_post_impl_uselib(res, (long)(library))
+#define __sanitizer_syscall_pre_ni_syscall() \
+ __sanitizer_syscall_pre_impl_ni_syscall()
+#define __sanitizer_syscall_post_ni_syscall(res) \
+ __sanitizer_syscall_post_impl_ni_syscall(res)
+#define __sanitizer_syscall_pre_ptrace(request, pid, addr, data) \
+ __sanitizer_syscall_pre_impl_ptrace((long)(request), (long)(pid), \
+ (long)(addr), (long)(data))
+#define __sanitizer_syscall_post_ptrace(res, request, pid, addr, data) \
+ __sanitizer_syscall_post_impl_ptrace(res, (long)(request), (long)(pid), \
+ (long)(addr), (long)(data))
+#define __sanitizer_syscall_pre_add_key(_type, _description, _payload, plen, \
+ destringid) \
+ __sanitizer_syscall_pre_impl_add_key((long)(_type), (long)(_description), \
+ (long)(_payload), (long)(plen), \
+ (long)(destringid))
+#define __sanitizer_syscall_post_add_key(res, _type, _description, _payload, \
+ plen, destringid) \
+ __sanitizer_syscall_post_impl_add_key( \
+ res, (long)(_type), (long)(_description), (long)(_payload), \
+ (long)(plen), (long)(destringid))
+#define __sanitizer_syscall_pre_request_key(_type, _description, \
+ _callout_info, destringid) \
+ __sanitizer_syscall_pre_impl_request_key( \
+ (long)(_type), (long)(_description), (long)(_callout_info), \
+ (long)(destringid))
+#define __sanitizer_syscall_post_request_key(res, _type, _description, \
+ _callout_info, destringid) \
+ __sanitizer_syscall_post_impl_request_key( \
+ res, (long)(_type), (long)(_description), (long)(_callout_info), \
+ (long)(destringid))
+#define __sanitizer_syscall_pre_keyctl(cmd, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_keyctl((long)(cmd), (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_keyctl(res, cmd, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_post_impl_keyctl(res, (long)(cmd), (long)(arg2), \
+ (long)(arg3), (long)(arg4), \
+ (long)(arg5))
+#define __sanitizer_syscall_pre_ioprio_set(which, who, ioprio) \
+ __sanitizer_syscall_pre_impl_ioprio_set((long)(which), (long)(who), \
+ (long)(ioprio))
+#define __sanitizer_syscall_post_ioprio_set(res, which, who, ioprio) \
+ __sanitizer_syscall_post_impl_ioprio_set(res, (long)(which), (long)(who), \
+ (long)(ioprio))
+#define __sanitizer_syscall_pre_ioprio_get(which, who) \
+ __sanitizer_syscall_pre_impl_ioprio_get((long)(which), (long)(who))
+#define __sanitizer_syscall_post_ioprio_get(res, which, who) \
+ __sanitizer_syscall_post_impl_ioprio_get(res, (long)(which), (long)(who))
+#define __sanitizer_syscall_pre_set_mempolicy(mode, nmask, maxnode) \
+ __sanitizer_syscall_pre_impl_set_mempolicy((long)(mode), (long)(nmask), \
+ (long)(maxnode))
+#define __sanitizer_syscall_post_set_mempolicy(res, mode, nmask, maxnode) \
+ __sanitizer_syscall_post_impl_set_mempolicy(res, (long)(mode), \
+ (long)(nmask), (long)(maxnode))
+#define __sanitizer_syscall_pre_migrate_pages(pid, maxnode, from, to) \
+ __sanitizer_syscall_pre_impl_migrate_pages((long)(pid), (long)(maxnode), \
+ (long)(from), (long)(to))
+#define __sanitizer_syscall_post_migrate_pages(res, pid, maxnode, from, to) \
+ __sanitizer_syscall_post_impl_migrate_pages( \
+ res, (long)(pid), (long)(maxnode), (long)(from), (long)(to))
+#define __sanitizer_syscall_pre_move_pages(pid, nr_pages, pages, nodes, \
+ status, flags) \
+ __sanitizer_syscall_pre_impl_move_pages((long)(pid), (long)(nr_pages), \
+ (long)(pages), (long)(nodes), \
+ (long)(status), (long)(flags))
+#define __sanitizer_syscall_post_move_pages(res, pid, nr_pages, pages, nodes, \
+ status, flags) \
+ __sanitizer_syscall_post_impl_move_pages(res, (long)(pid), (long)(nr_pages), \
+ (long)(pages), (long)(nodes), \
+ (long)(status), (long)(flags))
+#define __sanitizer_syscall_pre_mbind(start, len, mode, nmask, maxnode, flags) \
+ __sanitizer_syscall_pre_impl_mbind((long)(start), (long)(len), (long)(mode), \
+ (long)(nmask), (long)(maxnode), \
+ (long)(flags))
+#define __sanitizer_syscall_post_mbind(res, start, len, mode, nmask, maxnode, \
+ flags) \
+ __sanitizer_syscall_post_impl_mbind(res, (long)(start), (long)(len), \
+ (long)(mode), (long)(nmask), \
+ (long)(maxnode), (long)(flags))
+#define __sanitizer_syscall_pre_get_mempolicy(policy, nmask, maxnode, addr, \
+ flags) \
+ __sanitizer_syscall_pre_impl_get_mempolicy((long)(policy), (long)(nmask), \
+ (long)(maxnode), (long)(addr), \
+ (long)(flags))
+#define __sanitizer_syscall_post_get_mempolicy(res, policy, nmask, maxnode, \
+ addr, flags) \
+ __sanitizer_syscall_post_impl_get_mempolicy(res, (long)(policy), \
+ (long)(nmask), (long)(maxnode), \
+ (long)(addr), (long)(flags))
+#define __sanitizer_syscall_pre_inotify_init() \
+ __sanitizer_syscall_pre_impl_inotify_init()
+#define __sanitizer_syscall_post_inotify_init(res) \
+ __sanitizer_syscall_post_impl_inotify_init(res)
+#define __sanitizer_syscall_pre_inotify_init1(flags) \
+ __sanitizer_syscall_pre_impl_inotify_init1((long)(flags))
+#define __sanitizer_syscall_post_inotify_init1(res, flags) \
+ __sanitizer_syscall_post_impl_inotify_init1(res, (long)(flags))
+#define __sanitizer_syscall_pre_inotify_add_watch(fd, path, mask) \
+ __sanitizer_syscall_pre_impl_inotify_add_watch((long)(fd), (long)(path), \
+ (long)(mask))
+#define __sanitizer_syscall_post_inotify_add_watch(res, fd, path, mask) \
+ __sanitizer_syscall_post_impl_inotify_add_watch(res, (long)(fd), \
+ (long)(path), (long)(mask))
+#define __sanitizer_syscall_pre_inotify_rm_watch(fd, wd) \
+ __sanitizer_syscall_pre_impl_inotify_rm_watch((long)(fd), (long)(wd))
+#define __sanitizer_syscall_post_inotify_rm_watch(res, fd, wd) \
+ __sanitizer_syscall_post_impl_inotify_rm_watch(res, (long)(fd), (long)(wd))
+#define __sanitizer_syscall_pre_spu_run(fd, unpc, ustatus) \
+ __sanitizer_syscall_pre_impl_spu_run((long)(fd), (long)(unpc), \
+ (long)(ustatus))
+#define __sanitizer_syscall_post_spu_run(res, fd, unpc, ustatus) \
+ __sanitizer_syscall_post_impl_spu_run(res, (long)(fd), (long)(unpc), \
+ (long)(ustatus))
+#define __sanitizer_syscall_pre_spu_create(name, flags, mode, fd) \
+ __sanitizer_syscall_pre_impl_spu_create((long)(name), (long)(flags), \
+ (long)(mode), (long)(fd))
+#define __sanitizer_syscall_post_spu_create(res, name, flags, mode, fd) \
+ __sanitizer_syscall_post_impl_spu_create(res, (long)(name), (long)(flags), \
+ (long)(mode), (long)(fd))
+#define __sanitizer_syscall_pre_mknodat(dfd, filename, mode, dev) \
+ __sanitizer_syscall_pre_impl_mknodat((long)(dfd), (long)(filename), \
+ (long)(mode), (long)(dev))
+#define __sanitizer_syscall_post_mknodat(res, dfd, filename, mode, dev) \
+ __sanitizer_syscall_post_impl_mknodat(res, (long)(dfd), (long)(filename), \
+ (long)(mode), (long)(dev))
+#define __sanitizer_syscall_pre_mkdirat(dfd, pathname, mode) \
+ __sanitizer_syscall_pre_impl_mkdirat((long)(dfd), (long)(pathname), \
+ (long)(mode))
+#define __sanitizer_syscall_post_mkdirat(res, dfd, pathname, mode) \
+ __sanitizer_syscall_post_impl_mkdirat(res, (long)(dfd), (long)(pathname), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_unlinkat(dfd, pathname, flag) \
+ __sanitizer_syscall_pre_impl_unlinkat((long)(dfd), (long)(pathname), \
+ (long)(flag))
+#define __sanitizer_syscall_post_unlinkat(res, dfd, pathname, flag) \
+ __sanitizer_syscall_post_impl_unlinkat(res, (long)(dfd), (long)(pathname), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_symlinkat(oldname, newdfd, newname) \
+ __sanitizer_syscall_pre_impl_symlinkat((long)(oldname), (long)(newdfd), \
+ (long)(newname))
+#define __sanitizer_syscall_post_symlinkat(res, oldname, newdfd, newname) \
+ __sanitizer_syscall_post_impl_symlinkat(res, (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_pre_linkat(olddfd, oldname, newdfd, newname, \
+ flags) \
+ __sanitizer_syscall_pre_impl_linkat((long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname), \
+ (long)(flags))
+#define __sanitizer_syscall_post_linkat(res, olddfd, oldname, newdfd, newname, \
+ flags) \
+ __sanitizer_syscall_post_impl_linkat(res, (long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_renameat(olddfd, oldname, newdfd, newname) \
+ __sanitizer_syscall_pre_impl_renameat((long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_post_renameat(res, olddfd, oldname, newdfd, \
+ newname) \
+ __sanitizer_syscall_post_impl_renameat(res, (long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_pre_futimesat(dfd, filename, utimes) \
+ __sanitizer_syscall_pre_impl_futimesat((long)(dfd), (long)(filename), \
+ (long)(utimes))
+#define __sanitizer_syscall_post_futimesat(res, dfd, filename, utimes) \
+ __sanitizer_syscall_post_impl_futimesat(res, (long)(dfd), (long)(filename), \
+ (long)(utimes))
+#define __sanitizer_syscall_pre_faccessat(dfd, filename, mode) \
+ __sanitizer_syscall_pre_impl_faccessat((long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_post_faccessat(res, dfd, filename, mode) \
+ __sanitizer_syscall_post_impl_faccessat(res, (long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_fchmodat(dfd, filename, mode) \
+ __sanitizer_syscall_pre_impl_fchmodat((long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_post_fchmodat(res, dfd, filename, mode) \
+ __sanitizer_syscall_post_impl_fchmodat(res, (long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_fchownat(dfd, filename, user, group, flag) \
+ __sanitizer_syscall_pre_impl_fchownat((long)(dfd), (long)(filename), \
+ (long)(user), (long)(group), \
+ (long)(flag))
+#define __sanitizer_syscall_post_fchownat(res, dfd, filename, user, group, \
+ flag) \
+ __sanitizer_syscall_post_impl_fchownat(res, (long)(dfd), (long)(filename), \
+ (long)(user), (long)(group), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_openat(dfd, filename, flags, mode) \
+ __sanitizer_syscall_pre_impl_openat((long)(dfd), (long)(filename), \
+ (long)(flags), (long)(mode))
+#define __sanitizer_syscall_post_openat(res, dfd, filename, flags, mode) \
+ __sanitizer_syscall_post_impl_openat(res, (long)(dfd), (long)(filename), \
+ (long)(flags), (long)(mode))
+#define __sanitizer_syscall_pre_newfstatat(dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_pre_impl_newfstatat((long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_post_newfstatat(res, dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_post_impl_newfstatat(res, (long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_pre_fstatat64(dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_pre_impl_fstatat64((long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_post_fstatat64(res, dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_post_impl_fstatat64(res, (long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_pre_readlinkat(dfd, path, buf, bufsiz) \
+ __sanitizer_syscall_pre_impl_readlinkat((long)(dfd), (long)(path), \
+ (long)(buf), (long)(bufsiz))
+#define __sanitizer_syscall_post_readlinkat(res, dfd, path, buf, bufsiz) \
+ __sanitizer_syscall_post_impl_readlinkat(res, (long)(dfd), (long)(path), \
+ (long)(buf), (long)(bufsiz))
+#define __sanitizer_syscall_pre_utimensat(dfd, filename, utimes, flags) \
+ __sanitizer_syscall_pre_impl_utimensat((long)(dfd), (long)(filename), \
+ (long)(utimes), (long)(flags))
+#define __sanitizer_syscall_post_utimensat(res, dfd, filename, utimes, flags) \
+ __sanitizer_syscall_post_impl_utimensat(res, (long)(dfd), (long)(filename), \
+ (long)(utimes), (long)(flags))
+#define __sanitizer_syscall_pre_unshare(unshare_flags) \
+ __sanitizer_syscall_pre_impl_unshare((long)(unshare_flags))
+#define __sanitizer_syscall_post_unshare(res, unshare_flags) \
+ __sanitizer_syscall_post_impl_unshare(res, (long)(unshare_flags))
+#define __sanitizer_syscall_pre_splice(fd_in, off_in, fd_out, off_out, len, \
+ flags) \
+ __sanitizer_syscall_pre_impl_splice((long)(fd_in), (long)(off_in), \
+ (long)(fd_out), (long)(off_out), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_post_splice(res, fd_in, off_in, fd_out, off_out, \
+ len, flags) \
+ __sanitizer_syscall_post_impl_splice(res, (long)(fd_in), (long)(off_in), \
+ (long)(fd_out), (long)(off_out), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_pre_vmsplice(fd, iov, nr_segs, flags) \
+ __sanitizer_syscall_pre_impl_vmsplice((long)(fd), (long)(iov), \
+ (long)(nr_segs), (long)(flags))
+#define __sanitizer_syscall_post_vmsplice(res, fd, iov, nr_segs, flags) \
+ __sanitizer_syscall_post_impl_vmsplice(res, (long)(fd), (long)(iov), \
+ (long)(nr_segs), (long)(flags))
+#define __sanitizer_syscall_pre_tee(fdin, fdout, len, flags) \
+ __sanitizer_syscall_pre_impl_tee((long)(fdin), (long)(fdout), (long)(len), \
+ (long)(flags))
+#define __sanitizer_syscall_post_tee(res, fdin, fdout, len, flags) \
+ __sanitizer_syscall_post_impl_tee(res, (long)(fdin), (long)(fdout), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_pre_get_robust_list(pid, head_ptr, len_ptr) \
+ __sanitizer_syscall_pre_impl_get_robust_list((long)(pid), (long)(head_ptr), \
+ (long)(len_ptr))
+#define __sanitizer_syscall_post_get_robust_list(res, pid, head_ptr, len_ptr) \
+ __sanitizer_syscall_post_impl_get_robust_list( \
+ res, (long)(pid), (long)(head_ptr), (long)(len_ptr))
+#define __sanitizer_syscall_pre_set_robust_list(head, len) \
+ __sanitizer_syscall_pre_impl_set_robust_list((long)(head), (long)(len))
+#define __sanitizer_syscall_post_set_robust_list(res, head, len) \
+ __sanitizer_syscall_post_impl_set_robust_list(res, (long)(head), (long)(len))
+#define __sanitizer_syscall_pre_getcpu(cpu, node, cache) \
+ __sanitizer_syscall_pre_impl_getcpu((long)(cpu), (long)(node), (long)(cache))
+#define __sanitizer_syscall_post_getcpu(res, cpu, node, cache) \
+ __sanitizer_syscall_post_impl_getcpu(res, (long)(cpu), (long)(node), \
+ (long)(cache))
+#define __sanitizer_syscall_pre_signalfd(ufd, user_mask, sizemask) \
+ __sanitizer_syscall_pre_impl_signalfd((long)(ufd), (long)(user_mask), \
+ (long)(sizemask))
+#define __sanitizer_syscall_post_signalfd(res, ufd, user_mask, sizemask) \
+ __sanitizer_syscall_post_impl_signalfd(res, (long)(ufd), (long)(user_mask), \
+ (long)(sizemask))
+#define __sanitizer_syscall_pre_signalfd4(ufd, user_mask, sizemask, flags) \
+ __sanitizer_syscall_pre_impl_signalfd4((long)(ufd), (long)(user_mask), \
+ (long)(sizemask), (long)(flags))
+#define __sanitizer_syscall_post_signalfd4(res, ufd, user_mask, sizemask, \
+ flags) \
+ __sanitizer_syscall_post_impl_signalfd4(res, (long)(ufd), (long)(user_mask), \
+ (long)(sizemask), (long)(flags))
+#define __sanitizer_syscall_pre_timerfd_create(clockid, flags) \
+ __sanitizer_syscall_pre_impl_timerfd_create((long)(clockid), (long)(flags))
+#define __sanitizer_syscall_post_timerfd_create(res, clockid, flags) \
+ __sanitizer_syscall_post_impl_timerfd_create(res, (long)(clockid), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_timerfd_settime(ufd, flags, utmr, otmr) \
+ __sanitizer_syscall_pre_impl_timerfd_settime((long)(ufd), (long)(flags), \
+ (long)(utmr), (long)(otmr))
+#define __sanitizer_syscall_post_timerfd_settime(res, ufd, flags, utmr, otmr) \
+ __sanitizer_syscall_post_impl_timerfd_settime( \
+ res, (long)(ufd), (long)(flags), (long)(utmr), (long)(otmr))
+#define __sanitizer_syscall_pre_timerfd_gettime(ufd, otmr) \
+ __sanitizer_syscall_pre_impl_timerfd_gettime((long)(ufd), (long)(otmr))
+#define __sanitizer_syscall_post_timerfd_gettime(res, ufd, otmr) \
+ __sanitizer_syscall_post_impl_timerfd_gettime(res, (long)(ufd), (long)(otmr))
+#define __sanitizer_syscall_pre_eventfd(count) \
+ __sanitizer_syscall_pre_impl_eventfd((long)(count))
+#define __sanitizer_syscall_post_eventfd(res, count) \
+ __sanitizer_syscall_post_impl_eventfd(res, (long)(count))
+#define __sanitizer_syscall_pre_eventfd2(count, flags) \
+ __sanitizer_syscall_pre_impl_eventfd2((long)(count), (long)(flags))
+#define __sanitizer_syscall_post_eventfd2(res, count, flags) \
+ __sanitizer_syscall_post_impl_eventfd2(res, (long)(count), (long)(flags))
+#define __sanitizer_syscall_pre_old_readdir(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_old_readdir((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_old_readdir(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_old_readdir(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_pselect6(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_pselect6((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_pselect6(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_pselect6(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_ppoll(arg0, arg1, arg2, arg3, arg4) \
+ __sanitizer_syscall_pre_impl_ppoll((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3), (long)(arg4))
+#define __sanitizer_syscall_post_ppoll(res, arg0, arg1, arg2, arg3, arg4) \
+ __sanitizer_syscall_post_impl_ppoll(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4))
+#define __sanitizer_syscall_pre_syncfs(fd) \
+ __sanitizer_syscall_pre_impl_syncfs((long)(fd))
+#define __sanitizer_syscall_post_syncfs(res, fd) \
+ __sanitizer_syscall_post_impl_syncfs(res, (long)(fd))
+#define __sanitizer_syscall_pre_perf_event_open(attr_uptr, pid, cpu, group_fd, \
+ flags) \
+ __sanitizer_syscall_pre_impl_perf_event_open((long)(attr_uptr), (long)(pid), \
+ (long)(cpu), (long)(group_fd), \
+ (long)(flags))
+#define __sanitizer_syscall_post_perf_event_open(res, attr_uptr, pid, cpu, \
+ group_fd, flags) \
+ __sanitizer_syscall_post_impl_perf_event_open( \
+ res, (long)(attr_uptr), (long)(pid), (long)(cpu), (long)(group_fd), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_mmap_pgoff(addr, len, prot, flags, fd, pgoff) \
+ __sanitizer_syscall_pre_impl_mmap_pgoff((long)(addr), (long)(len), \
+ (long)(prot), (long)(flags), \
+ (long)(fd), (long)(pgoff))
+#define __sanitizer_syscall_post_mmap_pgoff(res, addr, len, prot, flags, fd, \
+ pgoff) \
+ __sanitizer_syscall_post_impl_mmap_pgoff(res, (long)(addr), (long)(len), \
+ (long)(prot), (long)(flags), \
+ (long)(fd), (long)(pgoff))
+#define __sanitizer_syscall_pre_old_mmap(arg) \
+ __sanitizer_syscall_pre_impl_old_mmap((long)(arg))
+#define __sanitizer_syscall_post_old_mmap(res, arg) \
+ __sanitizer_syscall_post_impl_old_mmap(res, (long)(arg))
+#define __sanitizer_syscall_pre_name_to_handle_at(dfd, name, handle, mnt_id, \
+ flag) \
+ __sanitizer_syscall_pre_impl_name_to_handle_at( \
+ (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), (long)(flag))
+#define __sanitizer_syscall_post_name_to_handle_at(res, dfd, name, handle, \
+ mnt_id, flag) \
+ __sanitizer_syscall_post_impl_name_to_handle_at( \
+ res, (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_open_by_handle_at(mountdirfd, handle, flags) \
+ __sanitizer_syscall_pre_impl_open_by_handle_at( \
+ (long)(mountdirfd), (long)(handle), (long)(flags))
+#define __sanitizer_syscall_post_open_by_handle_at(res, mountdirfd, handle, \
+ flags) \
+ __sanitizer_syscall_post_impl_open_by_handle_at( \
+ res, (long)(mountdirfd), (long)(handle), (long)(flags))
+#define __sanitizer_syscall_pre_setns(fd, nstype) \
+ __sanitizer_syscall_pre_impl_setns((long)(fd), (long)(nstype))
+#define __sanitizer_syscall_post_setns(res, fd, nstype) \
+ __sanitizer_syscall_post_impl_setns(res, (long)(fd), (long)(nstype))
+#define __sanitizer_syscall_pre_process_vm_readv(pid, lvec, liovcnt, rvec, \
+ riovcnt, flags) \
+ __sanitizer_syscall_pre_impl_process_vm_readv( \
+ (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_post_process_vm_readv(res, pid, lvec, liovcnt, \
+ rvec, riovcnt, flags) \
+ __sanitizer_syscall_post_impl_process_vm_readv( \
+ res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_pre_process_vm_writev(pid, lvec, liovcnt, rvec, \
+ riovcnt, flags) \
+ __sanitizer_syscall_pre_impl_process_vm_writev( \
+ (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_post_process_vm_writev(res, pid, lvec, liovcnt, \
+ rvec, riovcnt, flags) \
+ __sanitizer_syscall_post_impl_process_vm_writev( \
+ res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_pre_fork() \
+ __sanitizer_syscall_pre_impl_fork()
+#define __sanitizer_syscall_post_fork(res) \
+ __sanitizer_syscall_post_impl_fork(res)
+#define __sanitizer_syscall_pre_vfork() \
+ __sanitizer_syscall_pre_impl_vfork()
+#define __sanitizer_syscall_post_vfork(res) \
+ __sanitizer_syscall_post_impl_vfork(res)
+
+// And now a few syscalls we don't handle yet.
+#define __sanitizer_syscall_pre_afs_syscall(...)
+#define __sanitizer_syscall_pre_arch_prctl(...)
+#define __sanitizer_syscall_pre_break(...)
+#define __sanitizer_syscall_pre_chown32(...)
+#define __sanitizer_syscall_pre_clone(...)
+#define __sanitizer_syscall_pre_create_module(...)
+#define __sanitizer_syscall_pre_epoll_ctl_old(...)
+#define __sanitizer_syscall_pre_epoll_wait_old(...)
+#define __sanitizer_syscall_pre_execve(...)
+#define __sanitizer_syscall_pre_fadvise64(...)
+#define __sanitizer_syscall_pre_fadvise64_64(...)
+#define __sanitizer_syscall_pre_fallocate(...)
+#define __sanitizer_syscall_pre_fanotify_init(...)
+#define __sanitizer_syscall_pre_fanotify_mark(...)
+#define __sanitizer_syscall_pre_fchown32(...)
+#define __sanitizer_syscall_pre_ftime(...)
+#define __sanitizer_syscall_pre_ftruncate64(...)
+#define __sanitizer_syscall_pre_futex(...)
+#define __sanitizer_syscall_pre_getegid32(...)
+#define __sanitizer_syscall_pre_geteuid32(...)
+#define __sanitizer_syscall_pre_getgid32(...)
+#define __sanitizer_syscall_pre_getgroups32(...)
+#define __sanitizer_syscall_pre_get_kernel_syms(...)
+#define __sanitizer_syscall_pre_getpmsg(...)
+#define __sanitizer_syscall_pre_getresgid32(...)
+#define __sanitizer_syscall_pre_getresuid32(...)
+#define __sanitizer_syscall_pre_get_thread_area(...)
+#define __sanitizer_syscall_pre_getuid32(...)
+#define __sanitizer_syscall_pre_gtty(...)
+#define __sanitizer_syscall_pre_idle(...)
+#define __sanitizer_syscall_pre_iopl(...)
+#define __sanitizer_syscall_pre_lchown32(...)
+#define __sanitizer_syscall_pre__llseek(...)
+#define __sanitizer_syscall_pre_lock(...)
+#define __sanitizer_syscall_pre_madvise1(...)
+#define __sanitizer_syscall_pre_mmap(...)
+#define __sanitizer_syscall_pre_mmap2(...)
+#define __sanitizer_syscall_pre_modify_ldt(...)
+#define __sanitizer_syscall_pre_mpx(...)
+#define __sanitizer_syscall_pre__newselect(...)
+#define __sanitizer_syscall_pre_nfsservctl(...)
+#define __sanitizer_syscall_pre_oldfstat(...)
+#define __sanitizer_syscall_pre_oldlstat(...)
+#define __sanitizer_syscall_pre_oldolduname(...)
+#define __sanitizer_syscall_pre_oldstat(...)
+#define __sanitizer_syscall_pre_prctl(...)
+#define __sanitizer_syscall_pre_prof(...)
+#define __sanitizer_syscall_pre_profil(...)
+#define __sanitizer_syscall_pre_putpmsg(...)
+#define __sanitizer_syscall_pre_query_module(...)
+#define __sanitizer_syscall_pre_readahead(...)
+#define __sanitizer_syscall_pre_readdir(...)
+#define __sanitizer_syscall_pre_rt_sigaction(...)
+#define __sanitizer_syscall_pre_rt_sigreturn(...)
+#define __sanitizer_syscall_pre_rt_sigsuspend(...)
+#define __sanitizer_syscall_pre_security(...)
+#define __sanitizer_syscall_pre_setfsgid32(...)
+#define __sanitizer_syscall_pre_setfsuid32(...)
+#define __sanitizer_syscall_pre_setgid32(...)
+#define __sanitizer_syscall_pre_setgroups32(...)
+#define __sanitizer_syscall_pre_setregid32(...)
+#define __sanitizer_syscall_pre_setresgid32(...)
+#define __sanitizer_syscall_pre_setresuid32(...)
+#define __sanitizer_syscall_pre_setreuid32(...)
+#define __sanitizer_syscall_pre_set_thread_area(...)
+#define __sanitizer_syscall_pre_setuid32(...)
+#define __sanitizer_syscall_pre_sigaction(...)
+#define __sanitizer_syscall_pre_sigaltstack(...)
+#define __sanitizer_syscall_pre_sigreturn(...)
+#define __sanitizer_syscall_pre_sigsuspend(...)
+#define __sanitizer_syscall_pre_stty(...)
+#define __sanitizer_syscall_pre_sync_file_range(...)
+#define __sanitizer_syscall_pre__sysctl(...)
+#define __sanitizer_syscall_pre_truncate64(...)
+#define __sanitizer_syscall_pre_tuxcall(...)
+#define __sanitizer_syscall_pre_ugetrlimit(...)
+#define __sanitizer_syscall_pre_ulimit(...)
+#define __sanitizer_syscall_pre_umount2(...)
+#define __sanitizer_syscall_pre_vm86(...)
+#define __sanitizer_syscall_pre_vm86old(...)
+#define __sanitizer_syscall_pre_vserver(...)
+
+#define __sanitizer_syscall_post_afs_syscall(res, ...)
+#define __sanitizer_syscall_post_arch_prctl(res, ...)
+#define __sanitizer_syscall_post_break(res, ...)
+#define __sanitizer_syscall_post_chown32(res, ...)
+#define __sanitizer_syscall_post_clone(res, ...)
+#define __sanitizer_syscall_post_create_module(res, ...)
+#define __sanitizer_syscall_post_epoll_ctl_old(res, ...)
+#define __sanitizer_syscall_post_epoll_wait_old(res, ...)
+#define __sanitizer_syscall_post_execve(res, ...)
+#define __sanitizer_syscall_post_fadvise64(res, ...)
+#define __sanitizer_syscall_post_fadvise64_64(res, ...)
+#define __sanitizer_syscall_post_fallocate(res, ...)
+#define __sanitizer_syscall_post_fanotify_init(res, ...)
+#define __sanitizer_syscall_post_fanotify_mark(res, ...)
+#define __sanitizer_syscall_post_fchown32(res, ...)
+#define __sanitizer_syscall_post_ftime(res, ...)
+#define __sanitizer_syscall_post_ftruncate64(res, ...)
+#define __sanitizer_syscall_post_futex(res, ...)
+#define __sanitizer_syscall_post_getegid32(res, ...)
+#define __sanitizer_syscall_post_geteuid32(res, ...)
+#define __sanitizer_syscall_post_getgid32(res, ...)
+#define __sanitizer_syscall_post_getgroups32(res, ...)
+#define __sanitizer_syscall_post_get_kernel_syms(res, ...)
+#define __sanitizer_syscall_post_getpmsg(res, ...)
+#define __sanitizer_syscall_post_getresgid32(res, ...)
+#define __sanitizer_syscall_post_getresuid32(res, ...)
+#define __sanitizer_syscall_post_get_thread_area(res, ...)
+#define __sanitizer_syscall_post_getuid32(res, ...)
+#define __sanitizer_syscall_post_gtty(res, ...)
+#define __sanitizer_syscall_post_idle(res, ...)
+#define __sanitizer_syscall_post_iopl(res, ...)
+#define __sanitizer_syscall_post_lchown32(res, ...)
+#define __sanitizer_syscall_post__llseek(res, ...)
+#define __sanitizer_syscall_post_lock(res, ...)
+#define __sanitizer_syscall_post_madvise1(res, ...)
+#define __sanitizer_syscall_post_mmap2(res, ...)
+#define __sanitizer_syscall_post_mmap(res, ...)
+#define __sanitizer_syscall_post_modify_ldt(res, ...)
+#define __sanitizer_syscall_post_mpx(res, ...)
+#define __sanitizer_syscall_post__newselect(res, ...)
+#define __sanitizer_syscall_post_nfsservctl(res, ...)
+#define __sanitizer_syscall_post_oldfstat(res, ...)
+#define __sanitizer_syscall_post_oldlstat(res, ...)
+#define __sanitizer_syscall_post_oldolduname(res, ...)
+#define __sanitizer_syscall_post_oldstat(res, ...)
+#define __sanitizer_syscall_post_prctl(res, ...)
+#define __sanitizer_syscall_post_profil(res, ...)
+#define __sanitizer_syscall_post_prof(res, ...)
+#define __sanitizer_syscall_post_putpmsg(res, ...)
+#define __sanitizer_syscall_post_query_module(res, ...)
+#define __sanitizer_syscall_post_readahead(res, ...)
+#define __sanitizer_syscall_post_readdir(res, ...)
+#define __sanitizer_syscall_post_rt_sigaction(res, ...)
+#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
+#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
+#define __sanitizer_syscall_post_security(res, ...)
+#define __sanitizer_syscall_post_setfsgid32(res, ...)
+#define __sanitizer_syscall_post_setfsuid32(res, ...)
+#define __sanitizer_syscall_post_setgid32(res, ...)
+#define __sanitizer_syscall_post_setgroups32(res, ...)
+#define __sanitizer_syscall_post_setregid32(res, ...)
+#define __sanitizer_syscall_post_setresgid32(res, ...)
+#define __sanitizer_syscall_post_setresuid32(res, ...)
+#define __sanitizer_syscall_post_setreuid32(res, ...)
+#define __sanitizer_syscall_post_set_thread_area(res, ...)
+#define __sanitizer_syscall_post_setuid32(res, ...)
+#define __sanitizer_syscall_post_sigaction(res, ...)
+#define __sanitizer_syscall_post_sigaltstack(res, ...)
+#define __sanitizer_syscall_post_sigreturn(res, ...)
+#define __sanitizer_syscall_post_sigsuspend(res, ...)
+#define __sanitizer_syscall_post_stty(res, ...)
+#define __sanitizer_syscall_post_sync_file_range(res, ...)
+#define __sanitizer_syscall_post__sysctl(res, ...)
+#define __sanitizer_syscall_post_truncate64(res, ...)
+#define __sanitizer_syscall_post_tuxcall(res, ...)
+#define __sanitizer_syscall_post_ugetrlimit(res, ...)
+#define __sanitizer_syscall_post_ulimit(res, ...)
+#define __sanitizer_syscall_post_umount2(res, ...)
+#define __sanitizer_syscall_post_vm86old(res, ...)
+#define __sanitizer_syscall_post_vm86(res, ...)
+#define __sanitizer_syscall_post_vserver(res, ...)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Private declarations. Do not call directly from user code. Use macros above.
+void __sanitizer_syscall_pre_impl_time(long tloc);
+void __sanitizer_syscall_post_impl_time(long res, long tloc);
+void __sanitizer_syscall_pre_impl_stime(long tptr);
+void __sanitizer_syscall_post_impl_stime(long res, long tptr);
+void __sanitizer_syscall_pre_impl_gettimeofday(long tv, long tz);
+void __sanitizer_syscall_post_impl_gettimeofday(long res, long tv, long tz);
+void __sanitizer_syscall_pre_impl_settimeofday(long tv, long tz);
+void __sanitizer_syscall_post_impl_settimeofday(long res, long tv, long tz);
+void __sanitizer_syscall_pre_impl_adjtimex(long txc_p);
+void __sanitizer_syscall_post_impl_adjtimex(long res, long txc_p);
+void __sanitizer_syscall_pre_impl_times(long tbuf);
+void __sanitizer_syscall_post_impl_times(long res, long tbuf);
+void __sanitizer_syscall_pre_impl_gettid();
+void __sanitizer_syscall_post_impl_gettid(long res);
+void __sanitizer_syscall_pre_impl_nanosleep(long rqtp, long rmtp);
+void __sanitizer_syscall_post_impl_nanosleep(long res, long rqtp, long rmtp);
+void __sanitizer_syscall_pre_impl_alarm(long seconds);
+void __sanitizer_syscall_post_impl_alarm(long res, long seconds);
+void __sanitizer_syscall_pre_impl_getpid();
+void __sanitizer_syscall_post_impl_getpid(long res);
+void __sanitizer_syscall_pre_impl_getppid();
+void __sanitizer_syscall_post_impl_getppid(long res);
+void __sanitizer_syscall_pre_impl_getuid();
+void __sanitizer_syscall_post_impl_getuid(long res);
+void __sanitizer_syscall_pre_impl_geteuid();
+void __sanitizer_syscall_post_impl_geteuid(long res);
+void __sanitizer_syscall_pre_impl_getgid();
+void __sanitizer_syscall_post_impl_getgid(long res);
+void __sanitizer_syscall_pre_impl_getegid();
+void __sanitizer_syscall_post_impl_getegid(long res);
+void __sanitizer_syscall_pre_impl_getresuid(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_getresuid(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_getresgid(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_getresgid(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_getpgid(long pid);
+void __sanitizer_syscall_post_impl_getpgid(long res, long pid);
+void __sanitizer_syscall_pre_impl_getpgrp();
+void __sanitizer_syscall_post_impl_getpgrp(long res);
+void __sanitizer_syscall_pre_impl_getsid(long pid);
+void __sanitizer_syscall_post_impl_getsid(long res, long pid);
+void __sanitizer_syscall_pre_impl_getgroups(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_getgroups(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_setregid(long rgid, long egid);
+void __sanitizer_syscall_post_impl_setregid(long res, long rgid, long egid);
+void __sanitizer_syscall_pre_impl_setgid(long gid);
+void __sanitizer_syscall_post_impl_setgid(long res, long gid);
+void __sanitizer_syscall_pre_impl_setreuid(long ruid, long euid);
+void __sanitizer_syscall_post_impl_setreuid(long res, long ruid, long euid);
+void __sanitizer_syscall_pre_impl_setuid(long uid);
+void __sanitizer_syscall_post_impl_setuid(long res, long uid);
+void __sanitizer_syscall_pre_impl_setresuid(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_setresuid(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_setresgid(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_setresgid(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_setfsuid(long uid);
+void __sanitizer_syscall_post_impl_setfsuid(long res, long uid);
+void __sanitizer_syscall_pre_impl_setfsgid(long gid);
+void __sanitizer_syscall_post_impl_setfsgid(long res, long gid);
+void __sanitizer_syscall_pre_impl_setpgid(long pid, long pgid);
+void __sanitizer_syscall_post_impl_setpgid(long res, long pid, long pgid);
+void __sanitizer_syscall_pre_impl_setsid();
+void __sanitizer_syscall_post_impl_setsid(long res);
+void __sanitizer_syscall_pre_impl_setgroups(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_setgroups(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_acct(long name);
+void __sanitizer_syscall_post_impl_acct(long res, long name);
+void __sanitizer_syscall_pre_impl_capget(long header, long dataptr);
+void __sanitizer_syscall_post_impl_capget(long res, long header, long dataptr);
+void __sanitizer_syscall_pre_impl_capset(long header, long data);
+void __sanitizer_syscall_post_impl_capset(long res, long header, long data);
+void __sanitizer_syscall_pre_impl_personality(long personality);
+void __sanitizer_syscall_post_impl_personality(long res, long personality);
+void __sanitizer_syscall_pre_impl_sigpending(long set);
+void __sanitizer_syscall_post_impl_sigpending(long res, long set);
+void __sanitizer_syscall_pre_impl_sigprocmask(long how, long set, long oset);
+void __sanitizer_syscall_post_impl_sigprocmask(long res, long how, long set,
+ long oset);
+void __sanitizer_syscall_pre_impl_getitimer(long which, long value);
+void __sanitizer_syscall_post_impl_getitimer(long res, long which, long value);
+void __sanitizer_syscall_pre_impl_setitimer(long which, long value,
+ long ovalue);
+void __sanitizer_syscall_post_impl_setitimer(long res, long which, long value,
+ long ovalue);
+void __sanitizer_syscall_pre_impl_timer_create(long which_clock,
+ long timer_event_spec,
+ long created_timer_id);
+void __sanitizer_syscall_post_impl_timer_create(long res, long which_clock,
+ long timer_event_spec,
+ long created_timer_id);
+void __sanitizer_syscall_pre_impl_timer_gettime(long timer_id, long setting);
+void __sanitizer_syscall_post_impl_timer_gettime(long res, long timer_id,
+ long setting);
+void __sanitizer_syscall_pre_impl_timer_getoverrun(long timer_id);
+void __sanitizer_syscall_post_impl_timer_getoverrun(long res, long timer_id);
+void __sanitizer_syscall_pre_impl_timer_settime(long timer_id, long flags,
+ long new_setting,
+ long old_setting);
+void __sanitizer_syscall_post_impl_timer_settime(long res, long timer_id,
+ long flags, long new_setting,
+ long old_setting);
+void __sanitizer_syscall_pre_impl_timer_delete(long timer_id);
+void __sanitizer_syscall_post_impl_timer_delete(long res, long timer_id);
+void __sanitizer_syscall_pre_impl_clock_settime(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_settime(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_gettime(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_gettime(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_adjtime(long which_clock, long tx);
+void __sanitizer_syscall_post_impl_clock_adjtime(long res, long which_clock,
+ long tx);
+void __sanitizer_syscall_pre_impl_clock_getres(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_getres(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_nanosleep(long which_clock, long flags,
+ long rqtp, long rmtp);
+void __sanitizer_syscall_post_impl_clock_nanosleep(long res, long which_clock,
+ long flags, long rqtp,
+ long rmtp);
+void __sanitizer_syscall_pre_impl_nice(long increment);
+void __sanitizer_syscall_post_impl_nice(long res, long increment);
+void __sanitizer_syscall_pre_impl_sched_setscheduler(long pid, long policy,
+ long param);
+void __sanitizer_syscall_post_impl_sched_setscheduler(long res, long pid,
+ long policy, long param);
+void __sanitizer_syscall_pre_impl_sched_setparam(long pid, long param);
+void __sanitizer_syscall_post_impl_sched_setparam(long res, long pid,
+ long param);
+void __sanitizer_syscall_pre_impl_sched_getscheduler(long pid);
+void __sanitizer_syscall_post_impl_sched_getscheduler(long res, long pid);
+void __sanitizer_syscall_pre_impl_sched_getparam(long pid, long param);
+void __sanitizer_syscall_post_impl_sched_getparam(long res, long pid,
+ long param);
+void __sanitizer_syscall_pre_impl_sched_setaffinity(long pid, long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_post_impl_sched_setaffinity(long res, long pid,
+ long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_pre_impl_sched_getaffinity(long pid, long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_post_impl_sched_getaffinity(long res, long pid,
+ long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_pre_impl_sched_yield();
+void __sanitizer_syscall_post_impl_sched_yield(long res);
+void __sanitizer_syscall_pre_impl_sched_get_priority_max(long policy);
+void __sanitizer_syscall_post_impl_sched_get_priority_max(long res,
+ long policy);
+void __sanitizer_syscall_pre_impl_sched_get_priority_min(long policy);
+void __sanitizer_syscall_post_impl_sched_get_priority_min(long res,
+ long policy);
+void __sanitizer_syscall_pre_impl_sched_rr_get_interval(long pid,
+ long interval);
+void __sanitizer_syscall_post_impl_sched_rr_get_interval(long res, long pid,
+ long interval);
+void __sanitizer_syscall_pre_impl_setpriority(long which, long who,
+ long niceval);
+void __sanitizer_syscall_post_impl_setpriority(long res, long which, long who,
+ long niceval);
+void __sanitizer_syscall_pre_impl_getpriority(long which, long who);
+void __sanitizer_syscall_post_impl_getpriority(long res, long which, long who);
+void __sanitizer_syscall_pre_impl_shutdown(long arg0, long arg1);
+void __sanitizer_syscall_post_impl_shutdown(long res, long arg0, long arg1);
+void __sanitizer_syscall_pre_impl_reboot(long magic1, long magic2, long cmd,
+ long arg);
+void __sanitizer_syscall_post_impl_reboot(long res, long magic1, long magic2,
+ long cmd, long arg);
+void __sanitizer_syscall_pre_impl_restart_syscall();
+void __sanitizer_syscall_post_impl_restart_syscall(long res);
+void __sanitizer_syscall_pre_impl_kexec_load(long entry, long nr_segments,
+ long segments, long flags);
+void __sanitizer_syscall_post_impl_kexec_load(long res, long entry,
+ long nr_segments, long segments,
+ long flags);
+void __sanitizer_syscall_pre_impl_exit(long error_code);
+void __sanitizer_syscall_post_impl_exit(long res, long error_code);
+void __sanitizer_syscall_pre_impl_exit_group(long error_code);
+void __sanitizer_syscall_post_impl_exit_group(long res, long error_code);
+void __sanitizer_syscall_pre_impl_wait4(long pid, long stat_addr, long options,
+ long ru);
+void __sanitizer_syscall_post_impl_wait4(long res, long pid, long stat_addr,
+ long options, long ru);
+void __sanitizer_syscall_pre_impl_waitid(long which, long pid, long infop,
+ long options, long ru);
+void __sanitizer_syscall_post_impl_waitid(long res, long which, long pid,
+ long infop, long options, long ru);
+void __sanitizer_syscall_pre_impl_waitpid(long pid, long stat_addr,
+ long options);
+void __sanitizer_syscall_post_impl_waitpid(long res, long pid, long stat_addr,
+ long options);
+void __sanitizer_syscall_pre_impl_set_tid_address(long tidptr);
+void __sanitizer_syscall_post_impl_set_tid_address(long res, long tidptr);
+void __sanitizer_syscall_pre_impl_init_module(long umod, long len, long uargs);
+void __sanitizer_syscall_post_impl_init_module(long res, long umod, long len,
+ long uargs);
+void __sanitizer_syscall_pre_impl_delete_module(long name_user, long flags);
+void __sanitizer_syscall_post_impl_delete_module(long res, long name_user,
+ long flags);
+void __sanitizer_syscall_pre_impl_rt_sigprocmask(long how, long set, long oset,
+ long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigprocmask(long res, long how, long set,
+ long oset, long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_sigpending(long set, long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigpending(long res, long set,
+ long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_sigtimedwait(long uthese, long uinfo,
+ long uts, long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigtimedwait(long res, long uthese,
+ long uinfo, long uts,
+ long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo(long tgid, long pid,
+ long sig, long uinfo);
+void __sanitizer_syscall_post_impl_rt_tgsigqueueinfo(long res, long tgid,
+ long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_pre_impl_kill(long pid, long sig);
+void __sanitizer_syscall_post_impl_kill(long res, long pid, long sig);
+void __sanitizer_syscall_pre_impl_tgkill(long tgid, long pid, long sig);
+void __sanitizer_syscall_post_impl_tgkill(long res, long tgid, long pid,
+ long sig);
+void __sanitizer_syscall_pre_impl_tkill(long pid, long sig);
+void __sanitizer_syscall_post_impl_tkill(long res, long pid, long sig);
+void __sanitizer_syscall_pre_impl_rt_sigqueueinfo(long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_post_impl_rt_sigqueueinfo(long res, long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_pre_impl_sgetmask();
+void __sanitizer_syscall_post_impl_sgetmask(long res);
+void __sanitizer_syscall_pre_impl_ssetmask(long newmask);
+void __sanitizer_syscall_post_impl_ssetmask(long res, long newmask);
+void __sanitizer_syscall_pre_impl_signal(long sig, long handler);
+void __sanitizer_syscall_post_impl_signal(long res, long sig, long handler);
+void __sanitizer_syscall_pre_impl_pause();
+void __sanitizer_syscall_post_impl_pause(long res);
+void __sanitizer_syscall_pre_impl_sync();
+void __sanitizer_syscall_post_impl_sync(long res);
+void __sanitizer_syscall_pre_impl_fsync(long fd);
+void __sanitizer_syscall_post_impl_fsync(long res, long fd);
+void __sanitizer_syscall_pre_impl_fdatasync(long fd);
+void __sanitizer_syscall_post_impl_fdatasync(long res, long fd);
+void __sanitizer_syscall_pre_impl_bdflush(long func, long data);
+void __sanitizer_syscall_post_impl_bdflush(long res, long func, long data);
+void __sanitizer_syscall_pre_impl_mount(long dev_name, long dir_name, long type,
+ long flags, long data);
+void __sanitizer_syscall_post_impl_mount(long res, long dev_name, long dir_name,
+ long type, long flags, long data);
+void __sanitizer_syscall_pre_impl_umount(long name, long flags);
+void __sanitizer_syscall_post_impl_umount(long res, long name, long flags);
+void __sanitizer_syscall_pre_impl_oldumount(long name);
+void __sanitizer_syscall_post_impl_oldumount(long res, long name);
+void __sanitizer_syscall_pre_impl_truncate(long path, long length);
+void __sanitizer_syscall_post_impl_truncate(long res, long path, long length);
+void __sanitizer_syscall_pre_impl_ftruncate(long fd, long length);
+void __sanitizer_syscall_post_impl_ftruncate(long res, long fd, long length);
+void __sanitizer_syscall_pre_impl_stat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_stat(long res, long filename, long statbuf);
+void __sanitizer_syscall_pre_impl_statfs(long path, long buf);
+void __sanitizer_syscall_post_impl_statfs(long res, long path, long buf);
+void __sanitizer_syscall_pre_impl_statfs64(long path, long sz, long buf);
+void __sanitizer_syscall_post_impl_statfs64(long res, long path, long sz,
+ long buf);
+void __sanitizer_syscall_pre_impl_fstatfs(long fd, long buf);
+void __sanitizer_syscall_post_impl_fstatfs(long res, long fd, long buf);
+void __sanitizer_syscall_pre_impl_fstatfs64(long fd, long sz, long buf);
+void __sanitizer_syscall_post_impl_fstatfs64(long res, long fd, long sz,
+ long buf);
+void __sanitizer_syscall_pre_impl_lstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_lstat(long res, long filename, long statbuf);
+void __sanitizer_syscall_pre_impl_fstat(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_fstat(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_newstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_newstat(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_newlstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_newlstat(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_newfstat(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_newfstat(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_ustat(long dev, long ubuf);
+void __sanitizer_syscall_post_impl_ustat(long res, long dev, long ubuf);
+void __sanitizer_syscall_pre_impl_stat64(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_stat64(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_fstat64(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_fstat64(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_lstat64(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_lstat64(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_setxattr(long path, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_setxattr(long res, long path, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_lsetxattr(long path, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_lsetxattr(long res, long path, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_fsetxattr(long fd, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_fsetxattr(long res, long fd, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_getxattr(long path, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_getxattr(long res, long path, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_lgetxattr(long path, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_lgetxattr(long res, long path, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_fgetxattr(long fd, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_fgetxattr(long res, long fd, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_listxattr(long path, long list, long size);
+void __sanitizer_syscall_post_impl_listxattr(long res, long path, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_llistxattr(long path, long list, long size);
+void __sanitizer_syscall_post_impl_llistxattr(long res, long path, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_flistxattr(long fd, long list, long size);
+void __sanitizer_syscall_post_impl_flistxattr(long res, long fd, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_removexattr(long path, long name);
+void __sanitizer_syscall_post_impl_removexattr(long res, long path, long name);
+void __sanitizer_syscall_pre_impl_lremovexattr(long path, long name);
+void __sanitizer_syscall_post_impl_lremovexattr(long res, long path, long name);
+void __sanitizer_syscall_pre_impl_fremovexattr(long fd, long name);
+void __sanitizer_syscall_post_impl_fremovexattr(long res, long fd, long name);
+void __sanitizer_syscall_pre_impl_brk(long brk);
+void __sanitizer_syscall_post_impl_brk(long res, long brk);
+void __sanitizer_syscall_pre_impl_mprotect(long start, long len, long prot);
+void __sanitizer_syscall_post_impl_mprotect(long res, long start, long len,
+ long prot);
+void __sanitizer_syscall_pre_impl_mremap(long addr, long old_len, long new_len,
+ long flags, long new_addr);
+void __sanitizer_syscall_post_impl_mremap(long res, long addr, long old_len,
+ long new_len, long flags,
+ long new_addr);
+void __sanitizer_syscall_pre_impl_remap_file_pages(long start, long size,
+ long prot, long pgoff,
+ long flags);
+void __sanitizer_syscall_post_impl_remap_file_pages(long res, long start,
+ long size, long prot,
+ long pgoff, long flags);
+void __sanitizer_syscall_pre_impl_msync(long start, long len, long flags);
+void __sanitizer_syscall_post_impl_msync(long res, long start, long len,
+ long flags);
+void __sanitizer_syscall_pre_impl_munmap(long addr, long len);
+void __sanitizer_syscall_post_impl_munmap(long res, long addr, long len);
+void __sanitizer_syscall_pre_impl_mlock(long start, long len);
+void __sanitizer_syscall_post_impl_mlock(long res, long start, long len);
+void __sanitizer_syscall_pre_impl_munlock(long start, long len);
+void __sanitizer_syscall_post_impl_munlock(long res, long start, long len);
+void __sanitizer_syscall_pre_impl_mlockall(long flags);
+void __sanitizer_syscall_post_impl_mlockall(long res, long flags);
+void __sanitizer_syscall_pre_impl_munlockall();
+void __sanitizer_syscall_post_impl_munlockall(long res);
+void __sanitizer_syscall_pre_impl_madvise(long start, long len, long behavior);
+void __sanitizer_syscall_post_impl_madvise(long res, long start, long len,
+ long behavior);
+void __sanitizer_syscall_pre_impl_mincore(long start, long len, long vec);
+void __sanitizer_syscall_post_impl_mincore(long res, long start, long len,
+ long vec);
+void __sanitizer_syscall_pre_impl_pivot_root(long new_root, long put_old);
+void __sanitizer_syscall_post_impl_pivot_root(long res, long new_root,
+ long put_old);
+void __sanitizer_syscall_pre_impl_chroot(long filename);
+void __sanitizer_syscall_post_impl_chroot(long res, long filename);
+void __sanitizer_syscall_pre_impl_mknod(long filename, long mode, long dev);
+void __sanitizer_syscall_post_impl_mknod(long res, long filename, long mode,
+ long dev);
+void __sanitizer_syscall_pre_impl_link(long oldname, long newname);
+void __sanitizer_syscall_post_impl_link(long res, long oldname, long newname);
+void __sanitizer_syscall_pre_impl_symlink(long old, long new_);
+void __sanitizer_syscall_post_impl_symlink(long res, long old, long new_);
+void __sanitizer_syscall_pre_impl_unlink(long pathname);
+void __sanitizer_syscall_post_impl_unlink(long res, long pathname);
+void __sanitizer_syscall_pre_impl_rename(long oldname, long newname);
+void __sanitizer_syscall_post_impl_rename(long res, long oldname, long newname);
+void __sanitizer_syscall_pre_impl_chmod(long filename, long mode);
+void __sanitizer_syscall_post_impl_chmod(long res, long filename, long mode);
+void __sanitizer_syscall_pre_impl_fchmod(long fd, long mode);
+void __sanitizer_syscall_post_impl_fchmod(long res, long fd, long mode);
+void __sanitizer_syscall_pre_impl_fcntl(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_fcntl(long res, long fd, long cmd, long arg);
+void __sanitizer_syscall_pre_impl_fcntl64(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_fcntl64(long res, long fd, long cmd,
+ long arg);
+void __sanitizer_syscall_pre_impl_pipe(long fildes);
+void __sanitizer_syscall_post_impl_pipe(long res, long fildes);
+void __sanitizer_syscall_pre_impl_pipe2(long fildes, long flags);
+void __sanitizer_syscall_post_impl_pipe2(long res, long fildes, long flags);
+void __sanitizer_syscall_pre_impl_dup(long fildes);
+void __sanitizer_syscall_post_impl_dup(long res, long fildes);
+void __sanitizer_syscall_pre_impl_dup2(long oldfd, long newfd);
+void __sanitizer_syscall_post_impl_dup2(long res, long oldfd, long newfd);
+void __sanitizer_syscall_pre_impl_dup3(long oldfd, long newfd, long flags);
+void __sanitizer_syscall_post_impl_dup3(long res, long oldfd, long newfd,
+ long flags);
+void __sanitizer_syscall_pre_impl_ioperm(long from, long num, long on);
+void __sanitizer_syscall_post_impl_ioperm(long res, long from, long num,
+ long on);
+void __sanitizer_syscall_pre_impl_ioctl(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_ioctl(long res, long fd, long cmd, long arg);
+void __sanitizer_syscall_pre_impl_flock(long fd, long cmd);
+void __sanitizer_syscall_post_impl_flock(long res, long fd, long cmd);
+void __sanitizer_syscall_pre_impl_io_setup(long nr_reqs, long ctx);
+void __sanitizer_syscall_post_impl_io_setup(long res, long nr_reqs, long ctx);
+void __sanitizer_syscall_pre_impl_io_destroy(long ctx);
+void __sanitizer_syscall_post_impl_io_destroy(long res, long ctx);
+void __sanitizer_syscall_pre_impl_io_getevents(long ctx_id, long min_nr,
+ long nr, long events,
+ long timeout);
+void __sanitizer_syscall_post_impl_io_getevents(long res, long ctx_id,
+ long min_nr, long nr,
+ long events, long timeout);
+void __sanitizer_syscall_pre_impl_io_submit(long ctx_id, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_io_submit(long res, long ctx_id, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_io_cancel(long ctx_id, long iocb,
+ long result);
+void __sanitizer_syscall_post_impl_io_cancel(long res, long ctx_id, long iocb,
+ long result);
+void __sanitizer_syscall_pre_impl_sendfile(long out_fd, long in_fd, long offset,
+ long count);
+void __sanitizer_syscall_post_impl_sendfile(long res, long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_pre_impl_sendfile64(long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_post_impl_sendfile64(long res, long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_pre_impl_readlink(long path, long buf, long bufsiz);
+void __sanitizer_syscall_post_impl_readlink(long res, long path, long buf,
+ long bufsiz);
+void __sanitizer_syscall_pre_impl_creat(long pathname, long mode);
+void __sanitizer_syscall_post_impl_creat(long res, long pathname, long mode);
+void __sanitizer_syscall_pre_impl_open(long filename, long flags, long mode);
+void __sanitizer_syscall_post_impl_open(long res, long filename, long flags,
+ long mode);
+void __sanitizer_syscall_pre_impl_close(long fd);
+void __sanitizer_syscall_post_impl_close(long res, long fd);
+void __sanitizer_syscall_pre_impl_access(long filename, long mode);
+void __sanitizer_syscall_post_impl_access(long res, long filename, long mode);
+void __sanitizer_syscall_pre_impl_vhangup();
+void __sanitizer_syscall_post_impl_vhangup(long res);
+void __sanitizer_syscall_pre_impl_chown(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_chown(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_lchown(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_lchown(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_fchown(long fd, long user, long group);
+void __sanitizer_syscall_post_impl_fchown(long res, long fd, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_chown16(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_chown16(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_lchown16(long filename, long user,
+ long group);
+void __sanitizer_syscall_post_impl_lchown16(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_fchown16(long fd, long user, long group);
+void __sanitizer_syscall_post_impl_fchown16(long res, long fd, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_setregid16(long rgid, long egid);
+void __sanitizer_syscall_post_impl_setregid16(long res, long rgid, long egid);
+void __sanitizer_syscall_pre_impl_setgid16(long gid);
+void __sanitizer_syscall_post_impl_setgid16(long res, long gid);
+void __sanitizer_syscall_pre_impl_setreuid16(long ruid, long euid);
+void __sanitizer_syscall_post_impl_setreuid16(long res, long ruid, long euid);
+void __sanitizer_syscall_pre_impl_setuid16(long uid);
+void __sanitizer_syscall_post_impl_setuid16(long res, long uid);
+void __sanitizer_syscall_pre_impl_setresuid16(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_setresuid16(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_getresuid16(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_getresuid16(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_setresgid16(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_setresgid16(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_getresgid16(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_getresgid16(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_setfsuid16(long uid);
+void __sanitizer_syscall_post_impl_setfsuid16(long res, long uid);
+void __sanitizer_syscall_pre_impl_setfsgid16(long gid);
+void __sanitizer_syscall_post_impl_setfsgid16(long res, long gid);
+void __sanitizer_syscall_pre_impl_getgroups16(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_getgroups16(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_setgroups16(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_setgroups16(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_getuid16();
+void __sanitizer_syscall_post_impl_getuid16(long res);
+void __sanitizer_syscall_pre_impl_geteuid16();
+void __sanitizer_syscall_post_impl_geteuid16(long res);
+void __sanitizer_syscall_pre_impl_getgid16();
+void __sanitizer_syscall_post_impl_getgid16(long res);
+void __sanitizer_syscall_pre_impl_getegid16();
+void __sanitizer_syscall_post_impl_getegid16(long res);
+void __sanitizer_syscall_pre_impl_utime(long filename, long times);
+void __sanitizer_syscall_post_impl_utime(long res, long filename, long times);
+void __sanitizer_syscall_pre_impl_utimes(long filename, long utimes);
+void __sanitizer_syscall_post_impl_utimes(long res, long filename, long utimes);
+void __sanitizer_syscall_pre_impl_lseek(long fd, long offset, long origin);
+void __sanitizer_syscall_post_impl_lseek(long res, long fd, long offset,
+ long origin);
+void __sanitizer_syscall_pre_impl_llseek(long fd, long offset_high,
+ long offset_low, long result,
+ long origin);
+void __sanitizer_syscall_post_impl_llseek(long res, long fd, long offset_high,
+ long offset_low, long result,
+ long origin);
+void __sanitizer_syscall_pre_impl_read(long fd, long buf, long count);
+void __sanitizer_syscall_post_impl_read(long res, long fd, long buf,
+ long count);
+void __sanitizer_syscall_pre_impl_readv(long fd, long vec, long vlen);
+void __sanitizer_syscall_post_impl_readv(long res, long fd, long vec,
+ long vlen);
+void __sanitizer_syscall_pre_impl_write(long fd, long buf, long count);
+void __sanitizer_syscall_post_impl_write(long res, long fd, long buf,
+ long count);
+void __sanitizer_syscall_pre_impl_writev(long fd, long vec, long vlen);
+void __sanitizer_syscall_post_impl_writev(long res, long fd, long vec,
+ long vlen);
+
+#ifdef _LP64
+void __sanitizer_syscall_pre_impl_pread64(long fd, long buf, long count,
+ long pos);
+void __sanitizer_syscall_post_impl_pread64(long res, long fd, long buf,
+ long count, long pos);
+void __sanitizer_syscall_pre_impl_pwrite64(long fd, long buf, long count,
+ long pos);
+void __sanitizer_syscall_post_impl_pwrite64(long res, long fd, long buf,
+ long count, long pos);
+#else
+void __sanitizer_syscall_pre_impl_pread64(long fd, long buf, long count,
+ long pos0, long pos1);
+void __sanitizer_syscall_post_impl_pread64(long res, long fd, long buf,
+ long count, long pos0, long pos1);
+void __sanitizer_syscall_pre_impl_pwrite64(long fd, long buf, long count,
+ long pos0, long pos1);
+void __sanitizer_syscall_post_impl_pwrite64(long res, long fd, long buf,
+ long count, long pos0, long pos1);
+#endif
+
+void __sanitizer_syscall_pre_impl_preadv(long fd, long vec, long vlen,
+ long pos_l, long pos_h);
+void __sanitizer_syscall_post_impl_preadv(long res, long fd, long vec,
+ long vlen, long pos_l, long pos_h);
+void __sanitizer_syscall_pre_impl_pwritev(long fd, long vec, long vlen,
+ long pos_l, long pos_h);
+void __sanitizer_syscall_post_impl_pwritev(long res, long fd, long vec,
+ long vlen, long pos_l, long pos_h);
+void __sanitizer_syscall_pre_impl_getcwd(long buf, long size);
+void __sanitizer_syscall_post_impl_getcwd(long res, long buf, long size);
+void __sanitizer_syscall_pre_impl_mkdir(long pathname, long mode);
+void __sanitizer_syscall_post_impl_mkdir(long res, long pathname, long mode);
+void __sanitizer_syscall_pre_impl_chdir(long filename);
+void __sanitizer_syscall_post_impl_chdir(long res, long filename);
+void __sanitizer_syscall_pre_impl_fchdir(long fd);
+void __sanitizer_syscall_post_impl_fchdir(long res, long fd);
+void __sanitizer_syscall_pre_impl_rmdir(long pathname);
+void __sanitizer_syscall_post_impl_rmdir(long res, long pathname);
+void __sanitizer_syscall_pre_impl_lookup_dcookie(long cookie64, long buf,
+ long len);
+void __sanitizer_syscall_post_impl_lookup_dcookie(long res, long cookie64,
+ long buf, long len);
+void __sanitizer_syscall_pre_impl_quotactl(long cmd, long special, long id,
+ long addr);
+void __sanitizer_syscall_post_impl_quotactl(long res, long cmd, long special,
+ long id, long addr);
+void __sanitizer_syscall_pre_impl_getdents(long fd, long dirent, long count);
+void __sanitizer_syscall_post_impl_getdents(long res, long fd, long dirent,
+ long count);
+void __sanitizer_syscall_pre_impl_getdents64(long fd, long dirent, long count);
+void __sanitizer_syscall_post_impl_getdents64(long res, long fd, long dirent,
+ long count);
+void __sanitizer_syscall_pre_impl_setsockopt(long fd, long level, long optname,
+ long optval, long optlen);
+void __sanitizer_syscall_post_impl_setsockopt(long res, long fd, long level,
+ long optname, long optval,
+ long optlen);
+void __sanitizer_syscall_pre_impl_getsockopt(long fd, long level, long optname,
+ long optval, long optlen);
+void __sanitizer_syscall_post_impl_getsockopt(long res, long fd, long level,
+ long optname, long optval,
+ long optlen);
+void __sanitizer_syscall_pre_impl_bind(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_bind(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_connect(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_connect(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_accept(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_accept(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_accept4(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_accept4(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_getsockname(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_getsockname(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_getpeername(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_getpeername(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_send(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_send(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_sendto(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_sendto(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_sendmsg(long fd, long msg, long flags);
+void __sanitizer_syscall_post_impl_sendmsg(long res, long fd, long msg,
+ long flags);
+void __sanitizer_syscall_pre_impl_sendmmsg(long fd, long msg, long vlen,
+ long flags);
+void __sanitizer_syscall_post_impl_sendmmsg(long res, long fd, long msg,
+ long vlen, long flags);
+void __sanitizer_syscall_pre_impl_recv(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_recv(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_recvfrom(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_recvfrom(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_recvmsg(long fd, long msg, long flags);
+void __sanitizer_syscall_post_impl_recvmsg(long res, long fd, long msg,
+ long flags);
+void __sanitizer_syscall_pre_impl_recvmmsg(long fd, long msg, long vlen,
+ long flags, long timeout);
+void __sanitizer_syscall_post_impl_recvmmsg(long res, long fd, long msg,
+ long vlen, long flags,
+ long timeout);
+void __sanitizer_syscall_pre_impl_socket(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_socket(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_socketpair(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_socketpair(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_socketcall(long call, long args);
+void __sanitizer_syscall_post_impl_socketcall(long res, long call, long args);
+void __sanitizer_syscall_pre_impl_listen(long arg0, long arg1);
+void __sanitizer_syscall_post_impl_listen(long res, long arg0, long arg1);
+void __sanitizer_syscall_pre_impl_poll(long ufds, long nfds, long timeout);
+void __sanitizer_syscall_post_impl_poll(long res, long ufds, long nfds,
+ long timeout);
+void __sanitizer_syscall_pre_impl_select(long n, long inp, long outp, long exp,
+ long tvp);
+void __sanitizer_syscall_post_impl_select(long res, long n, long inp, long outp,
+ long exp, long tvp);
+void __sanitizer_syscall_pre_impl_old_select(long arg);
+void __sanitizer_syscall_post_impl_old_select(long res, long arg);
+void __sanitizer_syscall_pre_impl_epoll_create(long size);
+void __sanitizer_syscall_post_impl_epoll_create(long res, long size);
+void __sanitizer_syscall_pre_impl_epoll_create1(long flags);
+void __sanitizer_syscall_post_impl_epoll_create1(long res, long flags);
+void __sanitizer_syscall_pre_impl_epoll_ctl(long epfd, long op, long fd,
+ long event);
+void __sanitizer_syscall_post_impl_epoll_ctl(long res, long epfd, long op,
+ long fd, long event);
+void __sanitizer_syscall_pre_impl_epoll_wait(long epfd, long events,
+ long maxevents, long timeout);
+void __sanitizer_syscall_post_impl_epoll_wait(long res, long epfd, long events,
+ long maxevents, long timeout);
+void __sanitizer_syscall_pre_impl_epoll_pwait(long epfd, long events,
+ long maxevents, long timeout,
+ long sigmask, long sigsetsize);
+void __sanitizer_syscall_post_impl_epoll_pwait(long res, long epfd, long events,
+ long maxevents, long timeout,
+ long sigmask, long sigsetsize);
+void __sanitizer_syscall_pre_impl_gethostname(long name, long len);
+void __sanitizer_syscall_post_impl_gethostname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_sethostname(long name, long len);
+void __sanitizer_syscall_post_impl_sethostname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_setdomainname(long name, long len);
+void __sanitizer_syscall_post_impl_setdomainname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_newuname(long name);
+void __sanitizer_syscall_post_impl_newuname(long res, long name);
+void __sanitizer_syscall_pre_impl_uname(long arg0);
+void __sanitizer_syscall_post_impl_uname(long res, long arg0);
+void __sanitizer_syscall_pre_impl_olduname(long arg0);
+void __sanitizer_syscall_post_impl_olduname(long res, long arg0);
+void __sanitizer_syscall_pre_impl_getrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_getrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_old_getrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_old_getrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_setrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_setrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_prlimit64(long pid, long resource,
+ long new_rlim, long old_rlim);
+void __sanitizer_syscall_post_impl_prlimit64(long res, long pid, long resource,
+ long new_rlim, long old_rlim);
+void __sanitizer_syscall_pre_impl_getrusage(long who, long ru);
+void __sanitizer_syscall_post_impl_getrusage(long res, long who, long ru);
+void __sanitizer_syscall_pre_impl_umask(long mask);
+void __sanitizer_syscall_post_impl_umask(long res, long mask);
+void __sanitizer_syscall_pre_impl_msgget(long key, long msgflg);
+void __sanitizer_syscall_post_impl_msgget(long res, long key, long msgflg);
+void __sanitizer_syscall_pre_impl_msgsnd(long msqid, long msgp, long msgsz,
+ long msgflg);
+void __sanitizer_syscall_post_impl_msgsnd(long res, long msqid, long msgp,
+ long msgsz, long msgflg);
+void __sanitizer_syscall_pre_impl_msgrcv(long msqid, long msgp, long msgsz,
+ long msgtyp, long msgflg);
+void __sanitizer_syscall_post_impl_msgrcv(long res, long msqid, long msgp,
+ long msgsz, long msgtyp, long msgflg);
+void __sanitizer_syscall_pre_impl_msgctl(long msqid, long cmd, long buf);
+void __sanitizer_syscall_post_impl_msgctl(long res, long msqid, long cmd,
+ long buf);
+void __sanitizer_syscall_pre_impl_semget(long key, long nsems, long semflg);
+void __sanitizer_syscall_post_impl_semget(long res, long key, long nsems,
+ long semflg);
+void __sanitizer_syscall_pre_impl_semop(long semid, long sops, long nsops);
+void __sanitizer_syscall_post_impl_semop(long res, long semid, long sops,
+ long nsops);
+void __sanitizer_syscall_pre_impl_semctl(long semid, long semnum, long cmd,
+ long arg);
+void __sanitizer_syscall_post_impl_semctl(long res, long semid, long semnum,
+ long cmd, long arg);
+void __sanitizer_syscall_pre_impl_semtimedop(long semid, long sops, long nsops,
+ long timeout);
+void __sanitizer_syscall_post_impl_semtimedop(long res, long semid, long sops,
+ long nsops, long timeout);
+void __sanitizer_syscall_pre_impl_shmat(long shmid, long shmaddr, long shmflg);
+void __sanitizer_syscall_post_impl_shmat(long res, long shmid, long shmaddr,
+ long shmflg);
+void __sanitizer_syscall_pre_impl_shmget(long key, long size, long flag);
+void __sanitizer_syscall_post_impl_shmget(long res, long key, long size,
+ long flag);
+void __sanitizer_syscall_pre_impl_shmdt(long shmaddr);
+void __sanitizer_syscall_post_impl_shmdt(long res, long shmaddr);
+void __sanitizer_syscall_pre_impl_shmctl(long shmid, long cmd, long buf);
+void __sanitizer_syscall_post_impl_shmctl(long res, long shmid, long cmd,
+ long buf);
+void __sanitizer_syscall_pre_impl_ipc(long call, long first, long second,
+ long third, long ptr, long fifth);
+void __sanitizer_syscall_post_impl_ipc(long res, long call, long first,
+ long second, long third, long ptr,
+ long fifth);
+void __sanitizer_syscall_pre_impl_mq_open(long name, long oflag, long mode,
+ long attr);
+void __sanitizer_syscall_post_impl_mq_open(long res, long name, long oflag,
+ long mode, long attr);
+void __sanitizer_syscall_pre_impl_mq_unlink(long name);
+void __sanitizer_syscall_post_impl_mq_unlink(long res, long name);
+void __sanitizer_syscall_pre_impl_mq_timedsend(long mqdes, long msg_ptr,
+ long msg_len, long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_post_impl_mq_timedsend(long res, long mqdes,
+ long msg_ptr, long msg_len,
+ long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_pre_impl_mq_timedreceive(long mqdes, long msg_ptr,
+ long msg_len, long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_post_impl_mq_timedreceive(long res, long mqdes,
+ long msg_ptr, long msg_len,
+ long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_pre_impl_mq_notify(long mqdes, long notification);
+void __sanitizer_syscall_post_impl_mq_notify(long res, long mqdes,
+ long notification);
+void __sanitizer_syscall_pre_impl_mq_getsetattr(long mqdes, long mqstat,
+ long omqstat);
+void __sanitizer_syscall_post_impl_mq_getsetattr(long res, long mqdes,
+ long mqstat, long omqstat);
+void __sanitizer_syscall_pre_impl_pciconfig_iobase(long which, long bus,
+ long devfn);
+void __sanitizer_syscall_post_impl_pciconfig_iobase(long res, long which,
+ long bus, long devfn);
+void __sanitizer_syscall_pre_impl_pciconfig_read(long bus, long dfn, long off,
+ long len, long buf);
+void __sanitizer_syscall_post_impl_pciconfig_read(long res, long bus, long dfn,
+ long off, long len, long buf);
+void __sanitizer_syscall_pre_impl_pciconfig_write(long bus, long dfn, long off,
+ long len, long buf);
+void __sanitizer_syscall_post_impl_pciconfig_write(long res, long bus, long dfn,
+ long off, long len,
+ long buf);
+void __sanitizer_syscall_pre_impl_swapon(long specialfile, long swap_flags);
+void __sanitizer_syscall_post_impl_swapon(long res, long specialfile,
+ long swap_flags);
+void __sanitizer_syscall_pre_impl_swapoff(long specialfile);
+void __sanitizer_syscall_post_impl_swapoff(long res, long specialfile);
+void __sanitizer_syscall_pre_impl_sysctl(long args);
+void __sanitizer_syscall_post_impl_sysctl(long res, long args);
+void __sanitizer_syscall_pre_impl_sysinfo(long info);
+void __sanitizer_syscall_post_impl_sysinfo(long res, long info);
+void __sanitizer_syscall_pre_impl_sysfs(long option, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_sysfs(long res, long option, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_syslog(long type, long buf, long len);
+void __sanitizer_syscall_post_impl_syslog(long res, long type, long buf,
+ long len);
+void __sanitizer_syscall_pre_impl_uselib(long library);
+void __sanitizer_syscall_post_impl_uselib(long res, long library);
+void __sanitizer_syscall_pre_impl_ni_syscall();
+void __sanitizer_syscall_post_impl_ni_syscall(long res);
+void __sanitizer_syscall_pre_impl_ptrace(long request, long pid, long addr,
+ long data);
+void __sanitizer_syscall_post_impl_ptrace(long res, long request, long pid,
+ long addr, long data);
+void __sanitizer_syscall_pre_impl_add_key(long _type, long _description,
+ long _payload, long plen,
+ long destringid);
+void __sanitizer_syscall_post_impl_add_key(long res, long _type,
+ long _description, long _payload,
+ long plen, long destringid);
+void __sanitizer_syscall_pre_impl_request_key(long _type, long _description,
+ long _callout_info,
+ long destringid);
+void __sanitizer_syscall_post_impl_request_key(long res, long _type,
+ long _description,
+ long _callout_info,
+ long destringid);
+void __sanitizer_syscall_pre_impl_keyctl(long cmd, long arg2, long arg3,
+ long arg4, long arg5);
+void __sanitizer_syscall_post_impl_keyctl(long res, long cmd, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_pre_impl_ioprio_set(long which, long who, long ioprio);
+void __sanitizer_syscall_post_impl_ioprio_set(long res, long which, long who,
+ long ioprio);
+void __sanitizer_syscall_pre_impl_ioprio_get(long which, long who);
+void __sanitizer_syscall_post_impl_ioprio_get(long res, long which, long who);
+void __sanitizer_syscall_pre_impl_set_mempolicy(long mode, long nmask,
+ long maxnode);
+void __sanitizer_syscall_post_impl_set_mempolicy(long res, long mode,
+ long nmask, long maxnode);
+void __sanitizer_syscall_pre_impl_migrate_pages(long pid, long maxnode,
+ long from, long to);
+void __sanitizer_syscall_post_impl_migrate_pages(long res, long pid,
+ long maxnode, long from,
+ long to);
+void __sanitizer_syscall_pre_impl_move_pages(long pid, long nr_pages,
+ long pages, long nodes,
+ long status, long flags);
+void __sanitizer_syscall_post_impl_move_pages(long res, long pid, long nr_pages,
+ long pages, long nodes,
+ long status, long flags);
+void __sanitizer_syscall_pre_impl_mbind(long start, long len, long mode,
+ long nmask, long maxnode, long flags);
+void __sanitizer_syscall_post_impl_mbind(long res, long start, long len,
+ long mode, long nmask, long maxnode,
+ long flags);
+void __sanitizer_syscall_pre_impl_get_mempolicy(long policy, long nmask,
+ long maxnode, long addr,
+ long flags);
+void __sanitizer_syscall_post_impl_get_mempolicy(long res, long policy,
+ long nmask, long maxnode,
+ long addr, long flags);
+void __sanitizer_syscall_pre_impl_inotify_init();
+void __sanitizer_syscall_post_impl_inotify_init(long res);
+void __sanitizer_syscall_pre_impl_inotify_init1(long flags);
+void __sanitizer_syscall_post_impl_inotify_init1(long res, long flags);
+void __sanitizer_syscall_pre_impl_inotify_add_watch(long fd, long path,
+ long mask);
+void __sanitizer_syscall_post_impl_inotify_add_watch(long res, long fd,
+ long path, long mask);
+void __sanitizer_syscall_pre_impl_inotify_rm_watch(long fd, long wd);
+void __sanitizer_syscall_post_impl_inotify_rm_watch(long res, long fd, long wd);
+void __sanitizer_syscall_pre_impl_spu_run(long fd, long unpc, long ustatus);
+void __sanitizer_syscall_post_impl_spu_run(long res, long fd, long unpc,
+ long ustatus);
+void __sanitizer_syscall_pre_impl_spu_create(long name, long flags, long mode,
+ long fd);
+void __sanitizer_syscall_post_impl_spu_create(long res, long name, long flags,
+ long mode, long fd);
+void __sanitizer_syscall_pre_impl_mknodat(long dfd, long filename, long mode,
+ long dev);
+void __sanitizer_syscall_post_impl_mknodat(long res, long dfd, long filename,
+ long mode, long dev);
+void __sanitizer_syscall_pre_impl_mkdirat(long dfd, long pathname, long mode);
+void __sanitizer_syscall_post_impl_mkdirat(long res, long dfd, long pathname,
+ long mode);
+void __sanitizer_syscall_pre_impl_unlinkat(long dfd, long pathname, long flag);
+void __sanitizer_syscall_post_impl_unlinkat(long res, long dfd, long pathname,
+ long flag);
+void __sanitizer_syscall_pre_impl_symlinkat(long oldname, long newdfd,
+ long newname);
+void __sanitizer_syscall_post_impl_symlinkat(long res, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_pre_impl_linkat(long olddfd, long oldname, long newdfd,
+ long newname, long flags);
+void __sanitizer_syscall_post_impl_linkat(long res, long olddfd, long oldname,
+ long newdfd, long newname,
+ long flags);
+void __sanitizer_syscall_pre_impl_renameat(long olddfd, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_post_impl_renameat(long res, long olddfd, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_pre_impl_futimesat(long dfd, long filename,
+ long utimes);
+void __sanitizer_syscall_post_impl_futimesat(long res, long dfd, long filename,
+ long utimes);
+void __sanitizer_syscall_pre_impl_faccessat(long dfd, long filename, long mode);
+void __sanitizer_syscall_post_impl_faccessat(long res, long dfd, long filename,
+ long mode);
+void __sanitizer_syscall_pre_impl_fchmodat(long dfd, long filename, long mode);
+void __sanitizer_syscall_post_impl_fchmodat(long res, long dfd, long filename,
+ long mode);
+void __sanitizer_syscall_pre_impl_fchownat(long dfd, long filename, long user,
+ long group, long flag);
+void __sanitizer_syscall_post_impl_fchownat(long res, long dfd, long filename,
+ long user, long group, long flag);
+void __sanitizer_syscall_pre_impl_openat(long dfd, long filename, long flags,
+ long mode);
+void __sanitizer_syscall_post_impl_openat(long res, long dfd, long filename,
+ long flags, long mode);
+void __sanitizer_syscall_pre_impl_newfstatat(long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_post_impl_newfstatat(long res, long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_pre_impl_fstatat64(long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_post_impl_fstatat64(long res, long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_pre_impl_readlinkat(long dfd, long path, long buf,
+ long bufsiz);
+void __sanitizer_syscall_post_impl_readlinkat(long res, long dfd, long path,
+ long buf, long bufsiz);
+void __sanitizer_syscall_pre_impl_utimensat(long dfd, long filename,
+ long utimes, long flags);
+void __sanitizer_syscall_post_impl_utimensat(long res, long dfd, long filename,
+ long utimes, long flags);
+void __sanitizer_syscall_pre_impl_unshare(long unshare_flags);
+void __sanitizer_syscall_post_impl_unshare(long res, long unshare_flags);
+void __sanitizer_syscall_pre_impl_splice(long fd_in, long off_in, long fd_out,
+ long off_out, long len, long flags);
+void __sanitizer_syscall_post_impl_splice(long res, long fd_in, long off_in,
+ long fd_out, long off_out, long len,
+ long flags);
+void __sanitizer_syscall_pre_impl_vmsplice(long fd, long iov, long nr_segs,
+ long flags);
+void __sanitizer_syscall_post_impl_vmsplice(long res, long fd, long iov,
+ long nr_segs, long flags);
+void __sanitizer_syscall_pre_impl_tee(long fdin, long fdout, long len,
+ long flags);
+void __sanitizer_syscall_post_impl_tee(long res, long fdin, long fdout,
+ long len, long flags);
+void __sanitizer_syscall_pre_impl_get_robust_list(long pid, long head_ptr,
+ long len_ptr);
+void __sanitizer_syscall_post_impl_get_robust_list(long res, long pid,
+ long head_ptr, long len_ptr);
+void __sanitizer_syscall_pre_impl_set_robust_list(long head, long len);
+void __sanitizer_syscall_post_impl_set_robust_list(long res, long head,
+ long len);
+void __sanitizer_syscall_pre_impl_getcpu(long cpu, long node, long cache);
+void __sanitizer_syscall_post_impl_getcpu(long res, long cpu, long node,
+ long cache);
+void __sanitizer_syscall_pre_impl_signalfd(long ufd, long user_mask,
+ long sizemask);
+void __sanitizer_syscall_post_impl_signalfd(long res, long ufd, long user_mask,
+ long sizemask);
+void __sanitizer_syscall_pre_impl_signalfd4(long ufd, long user_mask,
+ long sizemask, long flags);
+void __sanitizer_syscall_post_impl_signalfd4(long res, long ufd, long user_mask,
+ long sizemask, long flags);
+void __sanitizer_syscall_pre_impl_timerfd_create(long clockid, long flags);
+void __sanitizer_syscall_post_impl_timerfd_create(long res, long clockid,
+ long flags);
+void __sanitizer_syscall_pre_impl_timerfd_settime(long ufd, long flags,
+ long utmr, long otmr);
+void __sanitizer_syscall_post_impl_timerfd_settime(long res, long ufd,
+ long flags, long utmr,
+ long otmr);
+void __sanitizer_syscall_pre_impl_timerfd_gettime(long ufd, long otmr);
+void __sanitizer_syscall_post_impl_timerfd_gettime(long res, long ufd,
+ long otmr);
+void __sanitizer_syscall_pre_impl_eventfd(long count);
+void __sanitizer_syscall_post_impl_eventfd(long res, long count);
+void __sanitizer_syscall_pre_impl_eventfd2(long count, long flags);
+void __sanitizer_syscall_post_impl_eventfd2(long res, long count, long flags);
+void __sanitizer_syscall_pre_impl_old_readdir(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_old_readdir(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_pselect6(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_pselect6(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_ppoll(long arg0, long arg1, long arg2,
+ long arg3, long arg4);
+void __sanitizer_syscall_post_impl_ppoll(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4);
+void __sanitizer_syscall_pre_impl_fanotify_init(long flags, long event_f_flags);
+void __sanitizer_syscall_post_impl_fanotify_init(long res, long flags,
+ long event_f_flags);
+void __sanitizer_syscall_pre_impl_fanotify_mark(long fanotify_fd, long flags,
+ long mask, long fd,
+ long pathname);
+void __sanitizer_syscall_post_impl_fanotify_mark(long res, long fanotify_fd,
+ long flags, long mask, long fd,
+ long pathname);
+void __sanitizer_syscall_pre_impl_syncfs(long fd);
+void __sanitizer_syscall_post_impl_syncfs(long res, long fd);
+void __sanitizer_syscall_pre_impl_perf_event_open(long attr_uptr, long pid,
+ long cpu, long group_fd,
+ long flags);
+void __sanitizer_syscall_post_impl_perf_event_open(long res, long attr_uptr,
+ long pid, long cpu,
+ long group_fd, long flags);
+void __sanitizer_syscall_pre_impl_mmap_pgoff(long addr, long len, long prot,
+ long flags, long fd, long pgoff);
+void __sanitizer_syscall_post_impl_mmap_pgoff(long res, long addr, long len,
+ long prot, long flags, long fd,
+ long pgoff);
+void __sanitizer_syscall_pre_impl_old_mmap(long arg);
+void __sanitizer_syscall_post_impl_old_mmap(long res, long arg);
+void __sanitizer_syscall_pre_impl_name_to_handle_at(long dfd, long name,
+ long handle, long mnt_id,
+ long flag);
+void __sanitizer_syscall_post_impl_name_to_handle_at(long res, long dfd,
+ long name, long handle,
+ long mnt_id, long flag);
+void __sanitizer_syscall_pre_impl_open_by_handle_at(long mountdirfd,
+ long handle, long flags);
+void __sanitizer_syscall_post_impl_open_by_handle_at(long res, long mountdirfd,
+ long handle, long flags);
+void __sanitizer_syscall_pre_impl_setns(long fd, long nstype);
+void __sanitizer_syscall_post_impl_setns(long res, long fd, long nstype);
+void __sanitizer_syscall_pre_impl_process_vm_readv(long pid, long lvec,
+ long liovcnt, long rvec,
+ long riovcnt, long flags);
+void __sanitizer_syscall_post_impl_process_vm_readv(long res, long pid,
+ long lvec, long liovcnt,
+ long rvec, long riovcnt,
+ long flags);
+void __sanitizer_syscall_pre_impl_process_vm_writev(long pid, long lvec,
+ long liovcnt, long rvec,
+ long riovcnt, long flags);
+void __sanitizer_syscall_post_impl_process_vm_writev(long res, long pid,
+ long lvec, long liovcnt,
+ long rvec, long riovcnt,
+ long flags);
+void __sanitizer_syscall_pre_impl_fork();
+void __sanitizer_syscall_post_impl_fork(long res);
+void __sanitizer_syscall_pre_impl_vfork();
+void __sanitizer_syscall_post_impl_vfork(long res);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H
diff --git a/contrib/compiler-rt/include/sanitizer/lsan_interface.h b/contrib/compiler-rt/include/sanitizer/lsan_interface.h
new file mode 100644
index 000000000000..46d2668cec24
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/lsan_interface.h
@@ -0,0 +1,73 @@
+//===-- sanitizer/lsan_interface.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 LeakSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LSAN_INTERFACE_H
+#define SANITIZER_LSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Allocations made between calls to __lsan_disable() and __lsan_enable() will
+ // be treated as non-leaks. Disable/enable pairs may be nested.
+ void __lsan_disable();
+ void __lsan_enable();
+
+ // The heap object into which p points will be treated as a non-leak.
+ void __lsan_ignore_object(const void *p);
+
+ // Memory regions registered through this interface will be treated as sources
+ // of live pointers during leak checking. Useful if you store pointers in
+ // mapped memory.
+ // Points of note:
+ // - __lsan_unregister_root_region() must be called with the same pointer and
+ // size that have earlier been passed to __lsan_register_root_region()
+ // - LSan will skip any inaccessible memory when scanning a root region. E.g.,
+ // if you map memory within a larger region that you have mprotect'ed, you can
+ // register the entire large region.
+ // - the implementation is not optimized for performance. This interface is
+ // intended to be used for a small number of relatively static regions.
+ void __lsan_register_root_region(const void *p, size_t size);
+ void __lsan_unregister_root_region(const void *p, size_t size);
+
+ // Calling this function makes LSan enter the leak checking phase immediately.
+ // Use this if normal end-of-process leak checking happens too late (e.g. if
+ // you have intentional memory leaks in your shutdown code). Calling this
+ // function overrides end-of-process leak checking; it must be called at
+ // most once per process. This function will terminate the process if there
+ // are memory leaks and the exit_code flag is non-zero.
+ void __lsan_do_leak_check();
+
+ // The user may optionally provide this function to disallow leak checking
+ // for the program it is linked into (if the return value is non-zero). This
+ // function must be defined as returning a constant value; any behavior beyond
+ // that is unsupported.
+ int __lsan_is_turned_off();
+
+ // This function may be optionally provided by the user and should return
+ // a string containing LSan suppressions.
+ const char *__lsan_default_suppressions();
+#ifdef __cplusplus
+} // extern "C"
+
+namespace __lsan {
+class ScopedDisabler {
+ public:
+ ScopedDisabler() { __lsan_disable(); }
+ ~ScopedDisabler() { __lsan_enable(); }
+};
+} // namespace __lsan
+#endif
+
+#endif // SANITIZER_LSAN_INTERFACE_H
diff --git a/contrib/compiler-rt/include/sanitizer/msan_interface.h b/contrib/compiler-rt/include/sanitizer/msan_interface.h
new file mode 100644
index 000000000000..c3a19bf345ac
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/msan_interface.h
@@ -0,0 +1,102 @@
+//===-- msan_interface.h --------------------------------------------------===//
+//
+// 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 MemorySanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_INTERFACE_H
+#define MSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* Set raw origin for the memory range. */
+ void __msan_set_origin(const volatile void *a, size_t size, uint32_t origin);
+
+ /* Get raw origin for an address. */
+ uint32_t __msan_get_origin(const volatile void *a);
+
+ /* Returns non-zero if tracking origins. */
+ int __msan_get_track_origins();
+
+ /* Returns the origin id of the latest UMR in the calling thread. */
+ uint32_t __msan_get_umr_origin();
+
+ /* Make memory region fully initialized (without changing its contents). */
+ void __msan_unpoison(const volatile void *a, size_t size);
+
+ /* Make a null-terminated string fully initialized (without changing its
+ contents). */
+ void __msan_unpoison_string(const volatile char *a);
+
+ /* Make memory region fully uninitialized (without changing its contents).
+ This is a legacy interface that does not update origin information. Use
+ __msan_allocated_memory() instead. */
+ void __msan_poison(const volatile void *a, size_t size);
+
+ /* Make memory region partially uninitialized (without changing its contents).
+ */
+ void __msan_partial_poison(const volatile void *data, void *shadow,
+ size_t size);
+
+ /* Returns the offset of the first (at least partially) poisoned byte in the
+ memory range, or -1 if the whole range is good. */
+ intptr_t __msan_test_shadow(const volatile void *x, size_t size);
+
+ /* Checks that memory range is fully initialized, and reports an error if it
+ * is not. */
+ void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
+
+ /* Set exit code when error(s) were detected.
+ Value of 0 means don't change the program exit code. */
+ void __msan_set_exit_code(int exit_code);
+
+ /* For testing:
+ __msan_set_expect_umr(1);
+ ... some buggy code ...
+ __msan_set_expect_umr(0);
+ The last line will verify that a UMR happened. */
+ void __msan_set_expect_umr(int expect_umr);
+
+ /* Change the value of keep_going flag. Non-zero value means don't terminate
+ program execution when an error is detected. This will not affect error in
+ modules that were compiled without the corresponding compiler flag. */
+ void __msan_set_keep_going(int keep_going);
+
+ /* Print shadow and origin for the memory range to stderr in a human-readable
+ format. */
+ void __msan_print_shadow(const volatile void *x, size_t size);
+
+ /* Print shadow for the memory range to stderr in a minimalistic
+ human-readable format. */
+ void __msan_dump_shadow(const volatile void *x, size_t size);
+
+ /* Returns true if running under a dynamic tool (DynamoRio-based). */
+ int __msan_has_dynamic_component();
+
+ /* Tell MSan about newly allocated memory (ex.: custom allocator).
+ Memory will be marked uninitialized, with origin at the call site. */
+ void __msan_allocated_memory(const volatile void* data, size_t size);
+
+ /* This function may be optionally provided by user and should return
+ a string containing Msan runtime options. See msan_flags.h for details. */
+ const char* __msan_default_options();
+
+ /* Sets the callback to be called right before death on error.
+ Passing 0 will unset the callback. */
+ void __msan_set_death_callback(void (*callback)(void));
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/contrib/compiler-rt/include/sanitizer/tsan_interface_atomic.h b/contrib/compiler-rt/include/sanitizer/tsan_interface_atomic.h
new file mode 100644
index 000000000000..4ea77d22a0d9
--- /dev/null
+++ b/contrib/compiler-rt/include/sanitizer/tsan_interface_atomic.h
@@ -0,0 +1,222 @@
+//===-- tsan_interface_atomic.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 ThreadSanitizer (TSan), a race detector.
+//
+// Public interface header for TSan atomics.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_INTERFACE_ATOMIC_H
+#define TSAN_INTERFACE_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char __tsan_atomic8;
+typedef short __tsan_atomic16; // NOLINT
+typedef int __tsan_atomic32;
+typedef long __tsan_atomic64; // NOLINT
+#if defined(__SIZEOF_INT128__) \
+ || (__clang_major__ * 100 + __clang_minor__ >= 302)
+__extension__ typedef __int128 __tsan_atomic128;
+# define __TSAN_HAS_INT128 1
+#else
+# define __TSAN_HAS_INT128 0
+#endif
+
+// Part of ABI, do not change.
+// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
+typedef enum {
+ __tsan_memory_order_relaxed,
+ __tsan_memory_order_consume,
+ __tsan_memory_order_acquire,
+ __tsan_memory_order_release,
+ __tsan_memory_order_acq_rel,
+ __tsan_memory_order_seq_cst
+} __tsan_memory_order;
+
+__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
+ __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
+ __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
+ __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
+ __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
+ __tsan_memory_order mo);
+#endif
+
+void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
+ __tsan_memory_order mo);
+void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
+ __tsan_memory_order mo);
+void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
+ __tsan_memory_order mo);
+void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
+ __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
+ __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_sub(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_sub(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_sub(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_sub(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_sub(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#if __TSAN_HAS_INT128
+int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#endif
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#if __TSAN_HAS_INT128
+int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
+ volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
+ volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
+ volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
+ volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
+ volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+#endif
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+void __tsan_atomic_signal_fence(__tsan_memory_order mo);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // TSAN_INTERFACE_ATOMIC_H
diff --git a/contrib/compiler-rt/BlocksRuntime/Block.h b/contrib/compiler-rt/lib/BlocksRuntime/Block.h
index 55cdd01a9123..55cdd01a9123 100644
--- a/contrib/compiler-rt/BlocksRuntime/Block.h
+++ b/contrib/compiler-rt/lib/BlocksRuntime/Block.h
diff --git a/contrib/compiler-rt/BlocksRuntime/Block_private.h b/contrib/compiler-rt/lib/BlocksRuntime/Block_private.h
index 8ae821815ebe..8ae821815ebe 100644
--- a/contrib/compiler-rt/BlocksRuntime/Block_private.h
+++ b/contrib/compiler-rt/lib/BlocksRuntime/Block_private.h
diff --git a/contrib/compiler-rt/BlocksRuntime/data.c b/contrib/compiler-rt/lib/BlocksRuntime/data.c
index b4eb02e0b01e..b4eb02e0b01e 100644
--- a/contrib/compiler-rt/BlocksRuntime/data.c
+++ b/contrib/compiler-rt/lib/BlocksRuntime/data.c
diff --git a/contrib/compiler-rt/BlocksRuntime/runtime.c b/contrib/compiler-rt/lib/BlocksRuntime/runtime.c
index a059c2234df1..a059c2234df1 100644
--- a/contrib/compiler-rt/BlocksRuntime/runtime.c
+++ b/contrib/compiler-rt/lib/BlocksRuntime/runtime.c
diff --git a/contrib/compiler-rt/lib/adddf3.c b/contrib/compiler-rt/lib/adddf3.c
deleted file mode 100644
index a55e82d21179..000000000000
--- a/contrib/compiler-rt/lib/adddf3.c
+++ /dev/null
@@ -1,152 +0,0 @@
-//===-- lib/adddf3.c - Double-precision addition ------------------*- C -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements double-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(dadd, adddf3)
-
-COMPILER_RT_ABI fp_t
-__adddf3(fp_t a, fp_t b) {
-
- rep_t aRep = toRep(a);
- rep_t bRep = toRep(b);
- const rep_t aAbs = aRep & absMask;
- const rep_t bAbs = bRep & absMask;
-
- // Detect if a or b is zero, infinity, or NaN.
- if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
-
- // NaN + anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything + NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // +/-infinity + -/+infinity = qNaN
- if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
- // +/-infinity + anything remaining = +/- infinity
- else return a;
- }
-
- // anything remaining + +/-infinity = +/-infinity
- if (bAbs == infRep) return b;
-
- // zero + anything = anything
- if (!aAbs) {
- // but we need to get the sign right for zero + zero
- if (!bAbs) return fromRep(toRep(a) & toRep(b));
- else return b;
- }
-
- // anything + zero = anything
- if (!bAbs) return a;
- }
-
- // Swap a and b if necessary so that a has the larger absolute value.
- if (bAbs > aAbs) {
- const rep_t temp = aRep;
- aRep = bRep;
- bRep = temp;
- }
-
- // Extract the exponent and significand from the (possibly swapped) a and b.
- int aExponent = aRep >> significandBits & maxExponent;
- int bExponent = bRep >> significandBits & maxExponent;
- rep_t aSignificand = aRep & significandMask;
- rep_t bSignificand = bRep & significandMask;
-
- // Normalize any denormals, and adjust the exponent accordingly.
- if (aExponent == 0) aExponent = normalize(&aSignificand);
- if (bExponent == 0) bExponent = normalize(&bSignificand);
-
- // The sign of the result is the sign of the larger operand, a. If they
- // have opposite signs, we are performing a subtraction; otherwise addition.
- const rep_t resultSign = aRep & signBit;
- const bool subtraction = (aRep ^ bRep) & signBit;
-
- // Shift the significands to give us round, guard and sticky, and or in the
- // implicit significand bit. (If we fell through from the denormal path it
- // was already set by normalize( ), but setting it twice won't hurt
- // anything.)
- aSignificand = (aSignificand | implicitBit) << 3;
- bSignificand = (bSignificand | implicitBit) << 3;
-
- // Shift the significand of b by the difference in exponents, with a sticky
- // bottom bit to get rounding correct.
- const unsigned int align = aExponent - bExponent;
- if (align) {
- if (align < typeWidth) {
- const bool sticky = bSignificand << (typeWidth - align);
- bSignificand = bSignificand >> align | sticky;
- } else {
- bSignificand = 1; // sticky; b is known to be non-zero.
- }
- }
-
- if (subtraction) {
- aSignificand -= bSignificand;
-
- // If a == -b, return +zero.
- if (aSignificand == 0) return fromRep(0);
-
- // If partial cancellation occured, we need to left-shift the result
- // and adjust the exponent:
- if (aSignificand < implicitBit << 3) {
- const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
- aSignificand <<= shift;
- aExponent -= shift;
- }
- }
-
- else /* addition */ {
- aSignificand += bSignificand;
-
- // If the addition carried up, we need to right-shift the result and
- // adjust the exponent:
- if (aSignificand & implicitBit << 4) {
- const bool sticky = aSignificand & 1;
- aSignificand = aSignificand >> 1 | sticky;
- aExponent += 1;
- }
- }
-
- // If we have overflowed the type, return +/- infinity:
- if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
-
- if (aExponent <= 0) {
- // Result is denormal before rounding; the exponent is zero and we
- // need to shift the significand.
- const int shift = 1 - aExponent;
- const bool sticky = aSignificand << (typeWidth - shift);
- aSignificand = aSignificand >> shift | sticky;
- aExponent = 0;
- }
-
- // Low three bits are round, guard, and sticky.
- const int roundGuardSticky = aSignificand & 0x7;
-
- // Shift the significand into place, and mask off the implicit bit.
- rep_t result = aSignificand >> 3 & significandMask;
-
- // Insert the exponent and sign.
- result |= (rep_t)aExponent << significandBits;
- result |= resultSign;
-
- // Final rounding. The result may overflow to infinity, but that is the
- // correct result in that case.
- if (roundGuardSticky > 0x4) result++;
- if (roundGuardSticky == 0x4) result += result & 1;
- return fromRep(result);
-}
diff --git a/contrib/compiler-rt/lib/arm/udivmodsi4.S b/contrib/compiler-rt/lib/arm/udivmodsi4.S
deleted file mode 100644
index d164a751d089..000000000000
--- a/contrib/compiler-rt/lib/arm/udivmodsi4.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
- * modulus) function for the ARM architecture. A naive digit-by-digit
- * computation is employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r4, r7, lr} ;\
- add r7, sp, #4
-#define CLEAR_FRAME_AND_RETURN \
- pop {r4, r7, pc}
-
-#define a r0
-#define b r1
-#define i r3
-#define r r4
-#define q ip
-#define one lr
-
-.syntax unified
-.align 3
-DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
-// We use a simple digit by digit algorithm; before we get into the actual
-// divide loop, we must calculate the left-shift amount necessary to align
-// the MSB of the divisor with that of the dividend (If this shift is
-// negative, then the result is zero, and we early out). We also conjure a
-// bit mask of 1 to use in constructing the quotient, and initialize the
-// quotient to zero.
- ESTABLISH_FRAME
- clz r4, a
- tst b, b // detect divide-by-zero
- clz r3, b
- mov q, #0
- beq LOCAL_LABEL(return) // return 0 if b is zero.
- mov one, #1
- subs i, r3, r4
- blt LOCAL_LABEL(return) // return 0 if MSB(a) < MSB(b)
-
-LOCAL_LABEL(mainLoop):
-// This loop basically implements the following:
-//
-// do {
-// if (a >= b << i) {
-// a -= b << i;
-// q |= 1 << i;
-// if (a == 0) break;
-// }
-// } while (--i)
-//
-// Note that this does not perform the final iteration (i == 0); by doing it
-// this way, we can merge the two branches which is a substantial win for
-// such a tight loop on current ARM architectures.
- subs r, a, b, lsl i
- orrhs q, q,one, lsl i
- movhs a, r
- subsne i, i, #1
- bhi LOCAL_LABEL(mainLoop)
-
-// Do the final test subtraction and update of quotient (i == 0), as it is
-// not performed in the main loop.
- subs r, a, b
- orrhs q, #1
- movhs a, r
-
-LOCAL_LABEL(return):
-// Store the remainder, and move the quotient to r0, then return.
- str a, [r2]
- mov r0, q
- CLEAR_FRAME_AND_RETURN
diff --git a/contrib/compiler-rt/lib/arm/udivsi3.S b/contrib/compiler-rt/lib/arm/udivsi3.S
deleted file mode 100644
index 28979fee4bdc..000000000000
--- a/contrib/compiler-rt/lib/arm/udivsi3.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __udivsi3 (32-bit unsigned integer divide)
- * function for the ARM architecture. A naive digit-by-digit computation is
- * employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r7, lr} ;\
- mov r7, sp
-#define CLEAR_FRAME_AND_RETURN \
- pop {r7, pc}
-
-#define a r0
-#define b r1
-#define r r2
-#define i r3
-#define q ip
-#define one lr
-
-.syntax unified
-.align 3
-// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
-DEFINE_COMPILERRT_FUNCTION(__udivsi3)
-#if __ARM_ARCH_7S__
- tst r1,r1
- beq LOCAL_LABEL(divzero)
- udiv r0, r0, r1
- bx lr
- LOCAL_LABEL(divzero):
- mov r0,#0
- bx lr
-#else
-// We use a simple digit by digit algorithm; before we get into the actual
-// divide loop, we must calculate the left-shift amount necessary to align
-// the MSB of the divisor with that of the dividend (If this shift is
-// negative, then the result is zero, and we early out). We also conjure a
-// bit mask of 1 to use in constructing the quotient, and initialize the
-// quotient to zero.
- ESTABLISH_FRAME
- clz r2, a
- tst b, b // detect divide-by-zero
- clz r3, b
- mov q, #0
- beq LOCAL_LABEL(return) // return 0 if b is zero.
- mov one, #1
- subs i, r3, r2
- blt LOCAL_LABEL(return) // return 0 if MSB(a) < MSB(b)
-
-LOCAL_LABEL(mainLoop):
-// This loop basically implements the following:
-//
-// do {
-// if (a >= b << i) {
-// a -= b << i;
-// q |= 1 << i;
-// if (a == 0) break;
-// }
-// } while (--i)
-//
-// Note that this does not perform the final iteration (i == 0); by doing it
-// this way, we can merge the two branches which is a substantial win for
-// such a tight loop on current ARM architectures.
- subs r, a, b, lsl i
- orrhs q, q,one, lsl i
- movhs a, r
- subsne i, i, #1
- bhi LOCAL_LABEL(mainLoop)
-
-// Do the final test subtraction and update of quotient (i == 0), as it is
-// not performed in the main loop.
- subs r, a, b
- orrhs q, #1
-
-LOCAL_LABEL(return):
-// Move the quotient to r0 and return.
- mov r0, q
- CLEAR_FRAME_AND_RETURN
-#endif
diff --git a/contrib/compiler-rt/lib/arm/umodsi3.S b/contrib/compiler-rt/lib/arm/umodsi3.S
deleted file mode 100644
index 3a2ab2b87751..000000000000
--- a/contrib/compiler-rt/lib/arm/umodsi3.S
+++ /dev/null
@@ -1,58 +0,0 @@
-/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __umodsi3 (32-bit unsigned integer modulus)
- * function for the ARM architecture. A naive digit-by-digit computation is
- * employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define a r0
-#define b r1
-#define r r2
-#define i r3
-
-.syntax unified
-.align 3
-DEFINE_COMPILERRT_FUNCTION(__umodsi3)
-// We use a simple digit by digit algorithm; before we get into the actual
-// divide loop, we must calculate the left-shift amount necessary to align
-// the MSB of the divisor with that of the dividend.
- clz r2, a
- tst b, b // detect b == 0
- clz r3, b
- bxeq lr // return a if b == 0
- subs i, r3, r2
- bxlt lr // return a if MSB(a) < MSB(b)
-
-LOCAL_LABEL(mainLoop):
-// This loop basically implements the following:
-//
-// do {
-// if (a >= b << i) {
-// a -= b << i;
-// if (a == 0) break;
-// }
-// } while (--i)
-//
-// Note that this does not perform the final iteration (i == 0); by doing it
-// this way, we can merge the two branches which is a substantial win for
-// such a tight loop on current ARM architectures.
- subs r, a, b, lsl i
- movhs a, r
- subsne i, i, #1
- bhi LOCAL_LABEL(mainLoop)
-
-// Do the final test subtraction and update of remainder (i == 0), as it is
-// not performed in the main loop.
- subs r, a, b
- movhs a, r
- bx lr
diff --git a/contrib/compiler-rt/lib/asan/README.txt b/contrib/compiler-rt/lib/asan/README.txt
new file mode 100644
index 000000000000..8cc9bb17b59d
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/README.txt
@@ -0,0 +1,26 @@
+AddressSanitizer RT
+================================
+This directory contains sources of the AddressSanitizer (ASan) runtime library.
+
+Directory structure:
+README.txt : This file.
+Makefile.mk : File for make-based build.
+CMakeLists.txt : File for cmake-based build.
+asan_*.{cc,h} : Sources of the asan runtime library.
+scripts/* : Helper scripts.
+tests/* : ASan unit tests.
+
+Also ASan runtime needs the following libraries:
+lib/interception/ : Machinery used to intercept function calls.
+lib/sanitizer_common/ : Code shared between various sanitizers.
+
+ASan runtime currently also embeds part of LeakSanitizer runtime for
+leak detection (lib/lsan/lsan_common.{cc,h}).
+
+ASan runtime can only be built by CMake. You can run ASan tests
+from the root of your CMake build tree:
+
+make check-asan
+
+For more instructions see:
+http://code.google.com/p/address-sanitizer/wiki/HowToBuild
diff --git a/contrib/compiler-rt/lib/asan/asan.syms.extra b/contrib/compiler-rt/lib/asan/asan.syms.extra
new file mode 100644
index 000000000000..007aafe380a8
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan.syms.extra
@@ -0,0 +1,3 @@
+__asan_*
+__lsan_*
+__ubsan_*
diff --git a/contrib/compiler-rt/lib/asan/asan_activation.cc b/contrib/compiler-rt/lib/asan/asan_activation.cc
new file mode 100644
index 000000000000..3bc01984898d
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_activation.cc
@@ -0,0 +1,142 @@
+//===-- asan_activation.cc --------------------------------------*- 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 activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_poisoning.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+static struct AsanDeactivatedFlags {
+ AllocatorOptions allocator_options;
+ int malloc_context_size;
+ bool poison_heap;
+ bool coverage;
+ const char *coverage_dir;
+
+ void RegisterActivationFlags(FlagParser *parser, Flags *f, CommonFlags *cf) {
+#define ASAN_ACTIVATION_FLAG(Type, Name) \
+ RegisterFlag(parser, #Name, "", &f->Name);
+#define COMMON_ACTIVATION_FLAG(Type, Name) \
+ RegisterFlag(parser, #Name, "", &cf->Name);
+#include "asan_activation_flags.inc"
+#undef ASAN_ACTIVATION_FLAG
+#undef COMMON_ACTIVATION_FLAG
+
+ RegisterIncludeFlag(parser, cf);
+ }
+
+ void OverrideFromActivationFlags() {
+ Flags f;
+ CommonFlags cf;
+ FlagParser parser;
+ RegisterActivationFlags(&parser, &f, &cf);
+
+ // Copy the current activation flags.
+ allocator_options.CopyTo(&f, &cf);
+ cf.malloc_context_size = malloc_context_size;
+ f.poison_heap = poison_heap;
+ cf.coverage = coverage;
+ cf.coverage_dir = coverage_dir;
+ cf.verbosity = Verbosity();
+ cf.help = false; // this is activation-specific help
+
+ // Check if activation flags need to be overriden.
+ if (const char *env = GetEnv("ASAN_ACTIVATION_OPTIONS")) {
+ parser.ParseString(env);
+ }
+
+ // Override from getprop asan.options.
+ char buf[100];
+ GetExtraActivationFlags(buf, sizeof(buf));
+ parser.ParseString(buf);
+
+ SetVerbosity(cf.verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (cf.help) parser.PrintFlagDescriptions();
+
+ allocator_options.SetFrom(&f, &cf);
+ malloc_context_size = cf.malloc_context_size;
+ poison_heap = f.poison_heap;
+ coverage = cf.coverage;
+ coverage_dir = cf.coverage_dir;
+ }
+
+ void Print() {
+ Report(
+ "quarantine_size_mb %d, max_redzone %d, poison_heap %d, "
+ "malloc_context_size %d, alloc_dealloc_mismatch %d, "
+ "allocator_may_return_null %d, coverage %d, coverage_dir %s\n",
+ allocator_options.quarantine_size_mb, allocator_options.max_redzone,
+ poison_heap, malloc_context_size,
+ allocator_options.alloc_dealloc_mismatch,
+ allocator_options.may_return_null, coverage, coverage_dir);
+ }
+} asan_deactivated_flags;
+
+static bool asan_is_deactivated;
+
+void AsanDeactivate() {
+ CHECK(!asan_is_deactivated);
+ VReport(1, "Deactivating ASan\n");
+
+ // Stash runtime state.
+ GetAllocatorOptions(&asan_deactivated_flags.allocator_options);
+ asan_deactivated_flags.malloc_context_size = GetMallocContextSize();
+ asan_deactivated_flags.poison_heap = CanPoisonMemory();
+ asan_deactivated_flags.coverage = common_flags()->coverage;
+ asan_deactivated_flags.coverage_dir = common_flags()->coverage_dir;
+
+ // Deactivate the runtime.
+ SetCanPoisonMemory(false);
+ SetMallocContextSize(1);
+ ReInitializeCoverage(false, nullptr);
+
+ AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
+ disabled.quarantine_size_mb = 0;
+ disabled.min_redzone = 16; // Redzone must be at least 16 bytes long.
+ disabled.max_redzone = 16;
+ disabled.alloc_dealloc_mismatch = false;
+ disabled.may_return_null = true;
+ ReInitializeAllocator(disabled);
+
+ asan_is_deactivated = true;
+}
+
+void AsanActivate() {
+ if (!asan_is_deactivated) return;
+ VReport(1, "Activating ASan\n");
+
+ asan_deactivated_flags.OverrideFromActivationFlags();
+
+ SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
+ SetMallocContextSize(asan_deactivated_flags.malloc_context_size);
+ ReInitializeCoverage(asan_deactivated_flags.coverage,
+ asan_deactivated_flags.coverage_dir);
+ ReInitializeAllocator(asan_deactivated_flags.allocator_options);
+
+ asan_is_deactivated = false;
+ if (Verbosity()) {
+ Report("Activated with flags:\n");
+ asan_deactivated_flags.Print();
+ }
+}
+
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_activation.h b/contrib/compiler-rt/lib/asan/asan_activation.h
new file mode 100644
index 000000000000..d5e1ce433001
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_activation.h
@@ -0,0 +1,23 @@
+//===-- asan_activation.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 activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_ACTIVATION_H
+#define ASAN_ACTIVATION_H
+
+namespace __asan {
+void AsanDeactivate();
+void AsanActivate();
+} // namespace __asan
+
+#endif // ASAN_ACTIVATION_H
diff --git a/contrib/compiler-rt/lib/asan/asan_activation_flags.inc b/contrib/compiler-rt/lib/asan/asan_activation_flags.inc
new file mode 100644
index 000000000000..d4c089ec6538
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_activation_flags.inc
@@ -0,0 +1,35 @@
+//===-- asan_activation_flags.inc -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A subset of ASan (and common) runtime flags supported at activation time.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_ACTIVATION_FLAG
+# error "Define ASAN_ACTIVATION_FLAG prior to including this file!"
+#endif
+
+#ifndef COMMON_ACTIVATION_FLAG
+# error "Define COMMON_ACTIVATION_FLAG prior to including this file!"
+#endif
+
+// ASAN_ACTIVATION_FLAG(Type, Name)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+ASAN_ACTIVATION_FLAG(int, redzone)
+ASAN_ACTIVATION_FLAG(int, max_redzone)
+ASAN_ACTIVATION_FLAG(int, quarantine_size_mb)
+ASAN_ACTIVATION_FLAG(bool, alloc_dealloc_mismatch)
+ASAN_ACTIVATION_FLAG(bool, poison_heap)
+
+COMMON_ACTIVATION_FLAG(bool, allocator_may_return_null)
+COMMON_ACTIVATION_FLAG(int, malloc_context_size)
+COMMON_ACTIVATION_FLAG(bool, coverage)
+COMMON_ACTIVATION_FLAG(const char *, coverage_dir)
+COMMON_ACTIVATION_FLAG(int, verbosity)
+COMMON_ACTIVATION_FLAG(bool, help)
diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.cc b/contrib/compiler-rt/lib/asan/asan_allocator.cc
new file mode 100644
index 000000000000..fd63ac68c09e
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_allocator.cc
@@ -0,0 +1,909 @@
+//===-- asan_allocator.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.
+//
+// Implementation of ASan's memory allocator, 2-nd version.
+// This variant uses the allocator from sanitizer_common, i.e. the one shared
+// with ThreadSanitizer and MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_list.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_quarantine.h"
+#include "lsan/lsan_common.h"
+
+namespace __asan {
+
+// Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits.
+// We use adaptive redzones: for larger allocation larger redzones are used.
+static u32 RZLog2Size(u32 rz_log) {
+ CHECK_LT(rz_log, 8);
+ return 16 << rz_log;
+}
+
+static u32 RZSize2Log(u32 rz_size) {
+ CHECK_GE(rz_size, 16);
+ CHECK_LE(rz_size, 2048);
+ CHECK(IsPowerOfTwo(rz_size));
+ u32 res = Log2(rz_size) - 4;
+ CHECK_EQ(rz_size, RZLog2Size(res));
+ return res;
+}
+
+static AsanAllocator &get_allocator();
+
+// The memory chunk allocated from the underlying allocator looks like this:
+// L L L L L L H H U U U U U U R R
+// L -- left redzone words (0 or more bytes)
+// H -- ChunkHeader (16 bytes), which is also a part of the left redzone.
+// U -- user memory.
+// R -- right redzone (0 or more bytes)
+// ChunkBase consists of ChunkHeader and other bytes that overlap with user
+// memory.
+
+// If the left redzone is greater than the ChunkHeader size we store a magic
+// value in the first uptr word of the memory block and store the address of
+// ChunkBase in the next uptr.
+// M B L L L L L L L L L H H U U U U U U
+// | ^
+// ---------------------|
+// M -- magic value kAllocBegMagic
+// B -- address of ChunkHeader pointing to the first 'H'
+static const uptr kAllocBegMagic = 0xCC6E96B9;
+
+struct ChunkHeader {
+ // 1-st 8 bytes.
+ u32 chunk_state : 8; // Must be first.
+ u32 alloc_tid : 24;
+
+ u32 free_tid : 24;
+ u32 from_memalign : 1;
+ u32 alloc_type : 2;
+ u32 rz_log : 3;
+ u32 lsan_tag : 2;
+ // 2-nd 8 bytes
+ // 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 alloc_context_id;
+};
+
+struct ChunkBase : ChunkHeader {
+ // Header2, intersects with user memory.
+ u32 free_context_id;
+};
+
+static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
+static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize;
+COMPILER_CHECK(kChunkHeaderSize == 16);
+COMPILER_CHECK(kChunkHeader2Size <= 16);
+
+// Every chunk of memory allocated by this allocator can be in one of 3 states:
+// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
+// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
+// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
+enum {
+ CHUNK_AVAILABLE = 0, // 0 is the default value even if we didn't set it.
+ CHUNK_ALLOCATED = 2,
+ CHUNK_QUARANTINE = 3
+};
+
+struct AsanChunk: ChunkBase {
+ uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
+ uptr UsedSize(bool locked_version = false) {
+ if (user_requested_size != SizeClassMap::kMaxSize)
+ return user_requested_size;
+ return *reinterpret_cast<uptr *>(
+ get_allocator().GetMetaData(AllocBeg(locked_version)));
+ }
+ void *AllocBeg(bool locked_version = false) {
+ if (from_memalign) {
+ if (locked_version)
+ return get_allocator().GetBlockBeginFastLocked(
+ reinterpret_cast<void *>(this));
+ return get_allocator().GetBlockBegin(reinterpret_cast<void *>(this));
+ }
+ return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
+ }
+ bool AddrIsInside(uptr addr, bool locked_version = false) {
+ return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
+ }
+};
+
+struct QuarantineCallback {
+ explicit QuarantineCallback(AllocatorCache *cache)
+ : cache_(cache) {
+ }
+
+ void Recycle(AsanChunk *m) {
+ CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
+ atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed);
+ CHECK_NE(m->alloc_tid, kInvalidTid);
+ CHECK_NE(m->free_tid, kInvalidTid);
+ PoisonShadow(m->Beg(),
+ RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
+ kAsanHeapLeftRedzoneMagic);
+ void *p = reinterpret_cast<void *>(m->AllocBeg());
+ if (p != m) {
+ uptr *alloc_magic = reinterpret_cast<uptr *>(p);
+ CHECK_EQ(alloc_magic[0], kAllocBegMagic);
+ // Clear the magic value, as allocator internals may overwrite the
+ // contents of deallocated chunk, confusing GetAsanChunk lookup.
+ alloc_magic[0] = 0;
+ CHECK_EQ(alloc_magic[1], reinterpret_cast<uptr>(m));
+ }
+
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.real_frees++;
+ thread_stats.really_freed += m->UsedSize();
+
+ get_allocator().Deallocate(cache_, p);
+ }
+
+ void *Allocate(uptr size) {
+ return get_allocator().Allocate(cache_, size, 1, false);
+ }
+
+ void Deallocate(void *p) {
+ get_allocator().Deallocate(cache_, p);
+ }
+
+ AllocatorCache *cache_;
+};
+
+typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine;
+typedef AsanQuarantine::Cache QuarantineCache;
+
+void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
+ PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.mmaps++;
+ thread_stats.mmaped += size;
+}
+void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
+ PoisonShadow(p, size, 0);
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededASanShadowMemory(p, size);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.munmaps++;
+ thread_stats.munmaped += size;
+}
+
+// We can not use THREADLOCAL because it is not supported on some of the
+// platforms we care about (OSX 10.6, Android).
+// static THREADLOCAL AllocatorCache cache;
+AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ return &ms->allocator_cache;
+}
+
+QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache));
+ return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache);
+}
+
+void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
+ quarantine_size_mb = f->quarantine_size_mb;
+ min_redzone = f->redzone;
+ max_redzone = f->max_redzone;
+ may_return_null = cf->allocator_may_return_null;
+ alloc_dealloc_mismatch = f->alloc_dealloc_mismatch;
+}
+
+void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
+ f->quarantine_size_mb = quarantine_size_mb;
+ f->redzone = min_redzone;
+ f->max_redzone = max_redzone;
+ cf->allocator_may_return_null = may_return_null;
+ f->alloc_dealloc_mismatch = alloc_dealloc_mismatch;
+}
+
+struct Allocator {
+ static const uptr kMaxAllowedMallocSize =
+ FIRST_32_SECOND_64(3UL << 30, 64UL << 30);
+ static const uptr kMaxThreadLocalQuarantine =
+ FIRST_32_SECOND_64(1 << 18, 1 << 20);
+
+ AsanAllocator allocator;
+ AsanQuarantine quarantine;
+ StaticSpinMutex fallback_mutex;
+ AllocatorCache fallback_allocator_cache;
+ QuarantineCache fallback_quarantine_cache;
+
+ // ------------------- Options --------------------------
+ atomic_uint16_t min_redzone;
+ atomic_uint16_t max_redzone;
+ atomic_uint8_t alloc_dealloc_mismatch;
+
+ // ------------------- Initialization ------------------------
+ explicit Allocator(LinkerInitialized)
+ : quarantine(LINKER_INITIALIZED),
+ fallback_quarantine_cache(LINKER_INITIALIZED) {}
+
+ void CheckOptions(const AllocatorOptions &options) const {
+ CHECK_GE(options.min_redzone, 16);
+ CHECK_GE(options.max_redzone, options.min_redzone);
+ CHECK_LE(options.max_redzone, 2048);
+ CHECK(IsPowerOfTwo(options.min_redzone));
+ CHECK(IsPowerOfTwo(options.max_redzone));
+ }
+
+ void SharedInitCode(const AllocatorOptions &options) {
+ CheckOptions(options);
+ quarantine.Init((uptr)options.quarantine_size_mb << 20,
+ kMaxThreadLocalQuarantine);
+ atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
+ memory_order_release);
+ atomic_store(&min_redzone, options.min_redzone, memory_order_release);
+ atomic_store(&max_redzone, options.max_redzone, memory_order_release);
+ }
+
+ void Initialize(const AllocatorOptions &options) {
+ allocator.Init(options.may_return_null);
+ SharedInitCode(options);
+ }
+
+ void ReInitialize(const AllocatorOptions &options) {
+ allocator.SetMayReturnNull(options.may_return_null);
+ SharedInitCode(options);
+ }
+
+ void GetOptions(AllocatorOptions *options) const {
+ options->quarantine_size_mb = quarantine.GetSize() >> 20;
+ options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
+ options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
+ options->may_return_null = allocator.MayReturnNull();
+ options->alloc_dealloc_mismatch =
+ atomic_load(&alloc_dealloc_mismatch, memory_order_acquire);
+ }
+
+ // -------------------- Helper methods. -------------------------
+ uptr ComputeRZLog(uptr user_requested_size) {
+ u32 rz_log =
+ user_requested_size <= 64 - 16 ? 0 :
+ user_requested_size <= 128 - 32 ? 1 :
+ user_requested_size <= 512 - 64 ? 2 :
+ user_requested_size <= 4096 - 128 ? 3 :
+ user_requested_size <= (1 << 14) - 256 ? 4 :
+ user_requested_size <= (1 << 15) - 512 ? 5 :
+ user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
+ u32 min_rz = atomic_load(&min_redzone, memory_order_acquire);
+ u32 max_rz = atomic_load(&max_redzone, memory_order_acquire);
+ return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
+ }
+
+ // We have an address between two chunks, and we want to report just one.
+ AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
+ AsanChunk *right_chunk) {
+ // Prefer an allocated chunk over freed chunk and freed chunk
+ // over available chunk.
+ if (left_chunk->chunk_state != right_chunk->chunk_state) {
+ if (left_chunk->chunk_state == CHUNK_ALLOCATED)
+ return left_chunk;
+ if (right_chunk->chunk_state == CHUNK_ALLOCATED)
+ return right_chunk;
+ if (left_chunk->chunk_state == CHUNK_QUARANTINE)
+ return left_chunk;
+ if (right_chunk->chunk_state == CHUNK_QUARANTINE)
+ return right_chunk;
+ }
+ // Same chunk_state: choose based on offset.
+ sptr l_offset = 0, r_offset = 0;
+ CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
+ CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
+ if (l_offset < r_offset)
+ return left_chunk;
+ return right_chunk;
+ }
+
+ // -------------------- Allocation/Deallocation routines ---------------
+ void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
+ AllocType alloc_type, bool can_fill) {
+ if (UNLIKELY(!asan_inited))
+ AsanInitFromRtl();
+ Flags &fl = *flags();
+ CHECK(stack);
+ const uptr min_alignment = SHADOW_GRANULARITY;
+ if (alignment < min_alignment)
+ alignment = min_alignment;
+ if (size == 0) {
+ // We'd be happy to avoid allocating memory for zero-size requests, but
+ // some programs/tests depend on this behavior and assume that malloc
+ // would not return NULL even for zero-size allocations. Moreover, it
+ // looks like operator new should never return NULL, and results of
+ // consecutive "new" calls must be different even if the allocated size
+ // is zero.
+ size = 1;
+ }
+ CHECK(IsPowerOfTwo(alignment));
+ uptr rz_log = ComputeRZLog(size);
+ uptr rz_size = RZLog2Size(rz_log);
+ uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
+ uptr needed_size = rounded_size + rz_size;
+ if (alignment > min_alignment)
+ needed_size += alignment;
+ bool using_primary_allocator = true;
+ // If we are allocating from the secondary allocator, there will be no
+ // automatic right redzone, so add the right redzone manually.
+ if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) {
+ needed_size += rz_size;
+ using_primary_allocator = false;
+ }
+ CHECK(IsAligned(needed_size, min_alignment));
+ if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
+ Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
+ (void*)size);
+ return allocator.ReturnNullOrDie();
+ }
+
+ AsanThread *t = GetCurrentThread();
+ void *allocated;
+ bool check_rss_limit = true;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated =
+ allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocated =
+ allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
+ }
+
+ if (!allocated)
+ return allocator.ReturnNullOrDie();
+
+ if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
+ // Heap poisoning is enabled, but the allocator provides an unpoisoned
+ // chunk. This is possible if CanPoisonMemory() was false for some
+ // time, for example, due to flags()->start_disabled.
+ // Anyway, poison the block before using it for anything else.
+ uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated);
+ PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic);
+ }
+
+ uptr alloc_beg = reinterpret_cast<uptr>(allocated);
+ uptr alloc_end = alloc_beg + needed_size;
+ uptr beg_plus_redzone = alloc_beg + rz_size;
+ uptr user_beg = beg_plus_redzone;
+ if (!IsAligned(user_beg, alignment))
+ user_beg = RoundUpTo(user_beg, alignment);
+ uptr user_end = user_beg + size;
+ CHECK_LE(user_end, alloc_end);
+ uptr chunk_beg = user_beg - kChunkHeaderSize;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ m->alloc_type = alloc_type;
+ m->rz_log = rz_log;
+ u32 alloc_tid = t ? t->tid() : 0;
+ m->alloc_tid = alloc_tid;
+ CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield?
+ m->free_tid = kInvalidTid;
+ m->from_memalign = user_beg != beg_plus_redzone;
+ if (alloc_beg != chunk_beg) {
+ CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg);
+ reinterpret_cast<uptr *>(alloc_beg)[0] = kAllocBegMagic;
+ reinterpret_cast<uptr *>(alloc_beg)[1] = chunk_beg;
+ }
+ if (using_primary_allocator) {
+ CHECK(size);
+ m->user_requested_size = size;
+ CHECK(allocator.FromPrimary(allocated));
+ } else {
+ CHECK(!allocator.FromPrimary(allocated));
+ m->user_requested_size = SizeClassMap::kMaxSize;
+ uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated));
+ meta[0] = size;
+ meta[1] = chunk_beg;
+ }
+
+ m->alloc_context_id = StackDepotPut(*stack);
+
+ uptr size_rounded_down_to_granularity =
+ RoundDownTo(size, SHADOW_GRANULARITY);
+ // Unpoison the bulk of the memory region.
+ if (size_rounded_down_to_granularity)
+ PoisonShadow(user_beg, size_rounded_down_to_granularity, 0);
+ // Deal with the end of the region if size is not aligned to granularity.
+ if (size != size_rounded_down_to_granularity && CanPoisonMemory()) {
+ u8 *shadow =
+ (u8 *)MemToShadow(user_beg + size_rounded_down_to_granularity);
+ *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0;
+ }
+
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.mallocs++;
+ thread_stats.malloced += size;
+ thread_stats.malloced_redzones += needed_size - size;
+ uptr class_id =
+ Min(kNumberOfSizeClasses, SizeClassMap::ClassID(needed_size));
+ thread_stats.malloced_by_size[class_id]++;
+ if (needed_size > SizeClassMap::kMaxSize)
+ thread_stats.malloc_large++;
+
+ void *res = reinterpret_cast<void *>(user_beg);
+ if (can_fill && fl.max_malloc_fill_size) {
+ uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
+ REAL(memset)(res, fl.malloc_fill_byte, fill_size);
+ }
+#if CAN_SANITIZE_LEAKS
+ m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored
+ : __lsan::kDirectlyLeaked;
+#endif
+ // Must be the last mutation of metadata in this function.
+ atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
+ ASAN_MALLOC_HOOK(res, size);
+ return res;
+ }
+
+ void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+ BufferedStackTrace *stack) {
+ u8 old_chunk_state = CHUNK_ALLOCATED;
+ // Flip the chunk_state atomically to avoid race on double-free.
+ if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
+ CHUNK_QUARANTINE, memory_order_acquire))
+ ReportInvalidFree(ptr, old_chunk_state, stack);
+ CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
+ }
+
+ // Expects the chunk to already be marked as quarantined by using
+ // AtomicallySetQuarantineFlag.
+ void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
+
+ if (m->alloc_type != alloc_type) {
+ if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
+ ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
+ (AllocType)alloc_type);
+ }
+ }
+
+ CHECK_GE(m->alloc_tid, 0);
+ if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
+ CHECK_EQ(m->free_tid, kInvalidTid);
+ AsanThread *t = GetCurrentThread();
+ m->free_tid = t ? t->tid() : 0;
+ m->free_context_id = StackDepotPut(*stack);
+ // Poison the region.
+ PoisonShadow(m->Beg(),
+ RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
+ kAsanHeapFreeMagic);
+
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.frees++;
+ thread_stats.freed += m->UsedSize();
+
+ // Push into quarantine.
+ if (t) {
+ AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
+ AllocatorCache *ac = GetAllocatorCache(ms);
+ quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), m,
+ m->UsedSize());
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *ac = &fallback_allocator_cache;
+ quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), m,
+ m->UsedSize());
+ }
+ }
+
+ void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ uptr p = reinterpret_cast<uptr>(ptr);
+ if (p == 0) return;
+
+ uptr chunk_beg = p - kChunkHeaderSize;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ if (delete_size && flags()->new_delete_type_mismatch &&
+ delete_size != m->UsedSize()) {
+ ReportNewDeleteSizeMismatch(p, delete_size, stack);
+ }
+ ASAN_FREE_HOOK(ptr);
+ // Must mark the chunk as quarantined before any changes to its metadata.
+ AtomicallySetQuarantineFlag(m, ptr, stack);
+ QuarantineChunk(m, ptr, stack, alloc_type);
+ }
+
+ void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
+ CHECK(old_ptr && new_size);
+ uptr p = reinterpret_cast<uptr>(old_ptr);
+ uptr chunk_beg = p - kChunkHeaderSize;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.reallocs++;
+ thread_stats.realloced += new_size;
+
+ void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
+ if (new_ptr) {
+ u8 chunk_state = m->chunk_state;
+ if (chunk_state != CHUNK_ALLOCATED)
+ ReportInvalidFree(old_ptr, chunk_state, stack);
+ CHECK_NE(REAL(memcpy), (void*)0);
+ uptr memcpy_size = Min(new_size, m->UsedSize());
+ // 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);
+ }
+ return new_ptr;
+ }
+
+ void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return allocator.ReturnNullOrDie();
+ void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
+ // If the memory comes from the secondary allocator no need to clear it
+ // as it comes directly from mmap.
+ if (ptr && allocator.FromPrimary(ptr))
+ REAL(memset)(ptr, 0, nmemb * size);
+ return ptr;
+ }
+
+ void ReportInvalidFree(void *ptr, u8 chunk_state, BufferedStackTrace *stack) {
+ if (chunk_state == CHUNK_QUARANTINE)
+ ReportDoubleFree((uptr)ptr, stack);
+ else
+ ReportFreeNotMalloced((uptr)ptr, stack);
+ }
+
+ void CommitBack(AsanThreadLocalMallocStorage *ms) {
+ AllocatorCache *ac = GetAllocatorCache(ms);
+ quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac));
+ allocator.SwallowCache(ac);
+ }
+
+ // -------------------------- Chunk lookup ----------------------
+
+ // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+ AsanChunk *GetAsanChunk(void *alloc_beg) {
+ if (!alloc_beg) return 0;
+ if (!allocator.FromPrimary(alloc_beg)) {
+ uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
+ return m;
+ }
+ uptr *alloc_magic = reinterpret_cast<uptr *>(alloc_beg);
+ if (alloc_magic[0] == kAllocBegMagic)
+ return reinterpret_cast<AsanChunk *>(alloc_magic[1]);
+ return reinterpret_cast<AsanChunk *>(alloc_beg);
+ }
+
+ AsanChunk *GetAsanChunkByAddr(uptr p) {
+ void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
+ return GetAsanChunk(alloc_beg);
+ }
+
+ // Allocator must be locked when this function is called.
+ AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
+ void *alloc_beg =
+ allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
+ return GetAsanChunk(alloc_beg);
+ }
+
+ uptr AllocationSize(uptr p) {
+ AsanChunk *m = GetAsanChunkByAddr(p);
+ if (!m) return 0;
+ if (m->chunk_state != CHUNK_ALLOCATED) return 0;
+ if (m->Beg() != p) return 0;
+ return m->UsedSize();
+ }
+
+ AsanChunkView FindHeapChunkByAddress(uptr addr) {
+ AsanChunk *m1 = GetAsanChunkByAddr(addr);
+ if (!m1) return AsanChunkView(m1);
+ sptr offset = 0;
+ if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
+ // The address is in the chunk's left redzone, so maybe it is actually
+ // a right buffer overflow from the other chunk to the left.
+ // Search a bit to the left to see if there is another chunk.
+ AsanChunk *m2 = 0;
+ for (uptr l = 1; l < GetPageSizeCached(); l++) {
+ m2 = GetAsanChunkByAddr(addr - l);
+ if (m2 == m1) continue; // Still the same chunk.
+ break;
+ }
+ if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset))
+ m1 = ChooseChunk(addr, m2, m1);
+ }
+ return AsanChunkView(m1);
+ }
+
+ void PrintStats() {
+ allocator.PrintStats();
+ }
+
+ void ForceLock() {
+ allocator.ForceLock();
+ fallback_mutex.Lock();
+ }
+
+ void ForceUnlock() {
+ fallback_mutex.Unlock();
+ allocator.ForceUnlock();
+ }
+};
+
+static Allocator instance(LINKER_INITIALIZED);
+
+static AsanAllocator &get_allocator() {
+ return instance.allocator;
+}
+
+bool AsanChunkView::IsValid() {
+ return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE;
+}
+uptr AsanChunkView::Beg() { return chunk_->Beg(); }
+uptr AsanChunkView::End() { return Beg() + UsedSize(); }
+uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
+uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
+uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
+
+static StackTrace GetStackTraceFromId(u32 id) {
+ CHECK(id);
+ StackTrace res = StackDepotGet(id);
+ CHECK(res.trace);
+ return res;
+}
+
+StackTrace AsanChunkView::GetAllocStack() {
+ return GetStackTraceFromId(chunk_->alloc_context_id);
+}
+
+StackTrace AsanChunkView::GetFreeStack() {
+ return GetStackTraceFromId(chunk_->free_context_id);
+}
+
+void InitializeAllocator(const AllocatorOptions &options) {
+ instance.Initialize(options);
+}
+
+void ReInitializeAllocator(const AllocatorOptions &options) {
+ instance.ReInitialize(options);
+}
+
+void GetAllocatorOptions(AllocatorOptions *options) {
+ instance.GetOptions(options);
+}
+
+AsanChunkView FindHeapChunkByAddress(uptr addr) {
+ return instance.FindHeapChunkByAddress(addr);
+}
+
+void AsanThreadLocalMallocStorage::CommitBack() {
+ instance.CommitBack(this);
+}
+
+void PrintInternalAllocatorStats() {
+ instance.PrintStats();
+}
+
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ return instance.Allocate(size, alignment, stack, alloc_type, true);
+}
+
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
+ instance.Deallocate(ptr, 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_malloc(uptr size, BufferedStackTrace *stack) {
+ return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
+}
+
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
+ return instance.Calloc(nmemb, size, stack);
+}
+
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
+ if (p == 0)
+ return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
+ if (size == 0) {
+ instance.Deallocate(p, 0, stack, FROM_MALLOC);
+ return 0;
+ }
+ return instance.Reallocate(p, size, stack);
+}
+
+void *asan_valloc(uptr size, BufferedStackTrace *stack) {
+ return instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
+}
+
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ return instance.Allocate(size, PageSize, stack, FROM_MALLOC, true);
+}
+
+int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
+ BufferedStackTrace *stack) {
+ void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true);
+ CHECK(IsAligned((uptr)ptr, alignment));
+ *memptr = ptr;
+ return 0;
+}
+
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
+ if (ptr == 0) return 0;
+ uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
+ if (flags()->check_malloc_usable_size && (usable_size == 0)) {
+ GET_STACK_TRACE_FATAL(pc, bp);
+ ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
+ }
+ return usable_size;
+}
+
+uptr asan_mz_size(const void *ptr) {
+ return instance.AllocationSize(reinterpret_cast<uptr>(ptr));
+}
+
+void asan_mz_force_lock() {
+ instance.ForceLock();
+}
+
+void asan_mz_force_unlock() {
+ instance.ForceUnlock();
+}
+
+void AsanSoftRssLimitExceededCallback(bool exceeded) {
+ instance.allocator.SetRssLimitIsExceeded(exceeded);
+}
+
+} // namespace __asan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+void LockAllocator() {
+ __asan::get_allocator().ForceLock();
+}
+
+void UnlockAllocator() {
+ __asan::get_allocator().ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+ *begin = (uptr)&__asan::get_allocator();
+ *end = *begin + sizeof(__asan::get_allocator());
+}
+
+uptr PointsIntoChunk(void* p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr);
+ if (!m) return 0;
+ uptr chunk = m->Beg();
+ if (m->chunk_state != __asan::CHUNK_ALLOCATED)
+ return 0;
+ if (m->AddrIsInside(addr, /*locked_version=*/true))
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true),
+ addr))
+ return chunk;
+ return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+ __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
+ CHECK(m);
+ return m->Beg();
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+ metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
+}
+
+bool LsanMetadata::allocated() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return m->chunk_state == __asan::CHUNK_ALLOCATED;
+}
+
+ChunkTag LsanMetadata::tag() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return static_cast<ChunkTag>(m->lsan_tag);
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ m->lsan_tag = value;
+}
+
+uptr LsanMetadata::requested_size() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return m->UsedSize(/*locked_version=*/true);
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return m->alloc_context_id;
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ __asan::get_allocator().ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr);
+ if (!m) return kIgnoreObjectInvalid;
+ if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) {
+ if (m->lsan_tag == kIgnored)
+ return kIgnoreObjectAlreadyIgnored;
+ m->lsan_tag = __lsan::kIgnored;
+ return kIgnoreObjectSuccess;
+ } else {
+ return kIgnoreObjectInvalid;
+ }
+}
+} // namespace __lsan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// ASan allocator doesn't reserve extra bytes, so normally we would
+// just return "size". We don't want to expose our redzone sizes, etc here.
+uptr __sanitizer_get_estimated_allocated_size(uptr size) {
+ return size;
+}
+
+int __sanitizer_get_ownership(const void *p) {
+ uptr ptr = reinterpret_cast<uptr>(p);
+ return instance.AllocationSize(ptr) > 0;
+}
+
+uptr __sanitizer_get_allocated_size(const void *p) {
+ if (p == 0) return 0;
+ uptr ptr = reinterpret_cast<uptr>(p);
+ uptr allocated_size = instance.AllocationSize(ptr);
+ // Die if p is not malloced or if it is already freed.
+ if (allocated_size == 0) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
+ }
+ return allocated_size;
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+// Provide default (no-op) implementation of malloc hooks.
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
+ (void)ptr;
+ (void)size;
+}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_free_hook(void *ptr) {
+ (void)ptr;
+}
+} // extern "C"
+#endif
diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.h b/contrib/compiler-rt/lib/asan/asan_allocator.h
new file mode 100644
index 000000000000..3208d1f950cd
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_allocator.h
@@ -0,0 +1,179 @@
+//===-- asan_allocator.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_allocator.cc.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_ALLOCATOR_H
+#define ASAN_ALLOCATOR_H
+
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_interceptors.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_list.h"
+
+namespace __asan {
+
+enum AllocType {
+ FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc.
+ FROM_NEW = 2, // Memory block came from operator new.
+ FROM_NEW_BR = 3 // Memory block came from operator new [ ]
+};
+
+static const uptr kNumberOfSizeClasses = 255;
+struct AsanChunk;
+
+struct AllocatorOptions {
+ u32 quarantine_size_mb;
+ u16 min_redzone;
+ u16 max_redzone;
+ u8 may_return_null;
+ u8 alloc_dealloc_mismatch;
+
+ void SetFrom(const Flags *f, const CommonFlags *cf);
+ void CopyTo(Flags *f, CommonFlags *cf);
+};
+
+void InitializeAllocator(const AllocatorOptions &options);
+void ReInitializeAllocator(const AllocatorOptions &options);
+void GetAllocatorOptions(AllocatorOptions *options);
+
+class AsanChunkView {
+ public:
+ explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ uptr Beg(); // First byte of user memory.
+ uptr End(); // Last byte of user memory.
+ uptr UsedSize(); // Size requested by the user.
+ uptr AllocTid();
+ uptr FreeTid();
+ bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
+ StackTrace GetAllocStack();
+ StackTrace GetFreeStack();
+ bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
+ if (addr >= Beg() && (addr + access_size) <= End()) {
+ *offset = addr - Beg();
+ return true;
+ }
+ return false;
+ }
+ bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
+ (void)access_size;
+ if (addr < Beg()) {
+ *offset = Beg() - addr;
+ return true;
+ }
+ return false;
+ }
+ bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
+ if (addr + access_size > End()) {
+ *offset = addr - End();
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ AsanChunk *const chunk_;
+};
+
+AsanChunkView FindHeapChunkByAddress(uptr address);
+
+// List of AsanChunks with total size.
+class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
+ public:
+ explicit AsanChunkFifoList(LinkerInitialized) { }
+ AsanChunkFifoList() { clear(); }
+ void Push(AsanChunk *n);
+ void PushList(AsanChunkFifoList *q);
+ AsanChunk *Pop();
+ uptr size() { return size_; }
+ void clear() {
+ IntrusiveList<AsanChunk>::clear();
+ size_ = 0;
+ }
+ private:
+ uptr size_;
+};
+
+struct AsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const;
+ void OnUnmap(uptr p, uptr size) const;
+};
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+# if defined(__powerpc64__)
+const uptr kAllocatorSpace = 0xa0000000000ULL;
+const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
+# else
+const uptr kAllocatorSpace = 0x600000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+# endif
+typedef DefaultSizeClassMap SizeClassMap;
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
+ SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+#else // Fallback to SizeClassAllocator32.
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+# if SANITIZER_WORDSIZE == 32
+typedef FlatByteMap<kNumRegions> ByteMap;
+# elif SANITIZER_WORDSIZE == 64
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+# endif
+typedef CompactSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
+ SizeClassMap, kRegionSizeLog,
+ ByteMap,
+ AsanMapUnmapCallback> PrimaryAllocator;
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
+
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> AsanAllocator;
+
+
+struct AsanThreadLocalMallocStorage {
+ uptr quarantine_cache[16];
+ AllocatorCache allocator_cache;
+ void CommitBack();
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ 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_malloc(uptr size, BufferedStackTrace *stack);
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
+void *asan_valloc(uptr size, BufferedStackTrace *stack);
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
+
+int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
+ BufferedStackTrace *stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
+
+uptr asan_mz_size(const void *ptr);
+void asan_mz_force_lock();
+void asan_mz_force_unlock();
+
+void PrintInternalAllocatorStats();
+void AsanSoftRssLimitExceededCallback(bool exceeded);
+
+} // namespace __asan
+#endif // ASAN_ALLOCATOR_H
diff --git a/contrib/compiler-rt/lib/asan/asan_blacklist.txt b/contrib/compiler-rt/lib/asan/asan_blacklist.txt
new file mode 100644
index 000000000000..c25921fd5fe7
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_blacklist.txt
@@ -0,0 +1,13 @@
+# Blacklist for AddressSanitizer. Turns off instrumentation of particular
+# functions or sources. Use with care. You may set location of blacklist
+# at compile-time using -fsanitize-blacklist=<path> flag.
+
+# Example usage:
+# fun:*bad_function_name*
+# src:file_with_tricky_code.cc
+# global:*global_with_bad_access_or_initialization*
+# global:*global_with_initialization_issues*=init
+# type:*Namespace::ClassName*=init
+
+# Stack buffer overflow in VC/INCLUDE/xlocnum, see http://goo.gl/L4qqUG
+fun:*_Find_elem@*@std*
diff --git a/contrib/compiler-rt/lib/asan/asan_debugging.cc b/contrib/compiler-rt/lib/asan/asan_debugging.cc
new file mode 100644
index 000000000000..6fc5b690de99
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_debugging.cc
@@ -0,0 +1,141 @@
+//===-- asan_debugging.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.
+//
+// This file contains various functions that are generally useful to call when
+// using a debugger (LLDB, GDB).
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+ descr->region_kind = "stack";
+
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access))
+ return;
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ return;
+ }
+
+ for (uptr i = 0; i < vars.size(); i++) {
+ if (access.offset <= vars[i].beg + vars[i].size) {
+ internal_strncat(descr->name, vars[i].name_pos,
+ Min(descr->name_size, vars[i].name_len));
+ descr->region_address = addr - (access.offset - vars[i].beg);
+ descr->region_size = vars[i].size;
+ return;
+ }
+ }
+}
+
+void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+
+ if (!chunk.IsValid()) {
+ descr->region_kind = "heap-invalid";
+ return;
+ }
+
+ descr->region_address = chunk.Beg();
+ descr->region_size = chunk.UsedSize();
+ descr->region_kind = "heap";
+}
+
+void AsanLocateAddress(uptr addr, AddressDescription *descr) {
+ if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
+ return;
+ }
+ if (GetInfoForAddressIfGlobal(addr, descr)) {
+ return;
+ }
+ asanThreadRegistry().Lock();
+ AsanThread *thread = FindThreadByStackAddress(addr);
+ asanThreadRegistry().Unlock();
+ if (thread) {
+ GetInfoForStackVar(addr, descr, thread);
+ return;
+ }
+ GetInfoForHeapAddress(addr, descr);
+}
+
+static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
+ bool alloc_stack) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) return 0;
+
+ StackTrace stack(nullptr, 0);
+ if (alloc_stack) {
+ if (chunk.AllocTid() == kInvalidTid) return 0;
+ stack = chunk.GetAllocStack();
+ if (thread_id) *thread_id = chunk.AllocTid();
+ } else {
+ if (chunk.FreeTid() == kInvalidTid) return 0;
+ stack = chunk.GetFreeStack();
+ if (thread_id) *thread_id = chunk.FreeTid();
+ }
+
+ if (trace && size) {
+ size = Min(size, Min(stack.size, kStackTraceMax));
+ for (uptr i = 0; i < size; i++)
+ trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
+
+ return size;
+ }
+
+ return 0;
+}
+
+} // namespace __asan
+
+using namespace __asan;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size) {
+ AddressDescription descr = { name, name_size, 0, 0, 0 };
+ AsanLocateAddress(addr, &descr);
+ if (region_address) *region_address = descr.region_address;
+ if (region_size) *region_size = descr.region_size;
+ return descr.region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
+ if (shadow_scale)
+ *shadow_scale = SHADOW_SCALE;
+ if (shadow_offset)
+ *shadow_offset = SHADOW_OFFSET;
+}
diff --git a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc
new file mode 100644
index 000000000000..bf4f1eb4c781
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc
@@ -0,0 +1,256 @@
+//===-- asan_fake_stack.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.
+//
+// FakeStack is used to detect use-after-return bugs.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_poisoning.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+static const u64 kMagic1 = kAsanStackAfterReturnMagic;
+static const u64 kMagic2 = (kMagic1 << 8) | kMagic1;
+static const u64 kMagic4 = (kMagic2 << 16) | kMagic2;
+static const u64 kMagic8 = (kMagic4 << 32) | kMagic4;
+
+// 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) {
+ for (uptr i = 0; i < (1U << class_id); i++) {
+ shadow[i] = magic;
+ SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ }
+ } else {
+ // The size class is too big, it's cheaper to poison only size bytes.
+ PoisonShadow(ptr, size, static_cast<u8>(magic));
+ }
+}
+
+FakeStack *FakeStack::Create(uptr stack_size_log) {
+ static uptr kMinStackSizeLog = 16;
+ static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28);
+ if (stack_size_log < kMinStackSizeLog)
+ stack_size_log = kMinStackSizeLog;
+ if (stack_size_log > kMaxStackSizeLog)
+ stack_size_log = kMaxStackSizeLog;
+ uptr size = RequiredSize(stack_size_log);
+ FakeStack *res = reinterpret_cast<FakeStack *>(
+ flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack")
+ : MmapOrDie(size, "FakeStack"));
+ res->stack_size_log_ = stack_size_log;
+ u8 *p = reinterpret_cast<u8 *>(res);
+ VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; "
+ "mmapped %zdK, noreserve=%d \n",
+ GetCurrentTidOrInvalid(), p,
+ p + FakeStack::RequiredSize(stack_size_log), stack_size_log,
+ size >> 10, flags()->uar_noreserve);
+ return res;
+}
+
+void FakeStack::Destroy(int tid) {
+ PoisonAll(0);
+ if (Verbosity() >= 2) {
+ InternalScopedString str(kNumberOfSizeClasses * 50);
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
+ str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
+ NumberOfFrames(stack_size_log(), class_id));
+ Report("T%d: FakeStack destroyed: %s\n", tid, str.data());
+ }
+ uptr size = RequiredSize(stack_size_log_);
+ FlushUnneededASanShadowMemory(reinterpret_cast<uptr>(this), size);
+ UnmapOrDie(this, size);
+}
+
+void FakeStack::PoisonAll(u8 magic) {
+ PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
+ magic);
+}
+
+ALWAYS_INLINE USED
+FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
+ uptr real_stack) {
+ CHECK_LT(class_id, kNumberOfSizeClasses);
+ if (needs_gc_)
+ GC(real_stack);
+ uptr &hint_position = hint_position_[class_id];
+ const int num_iter = NumberOfFrames(stack_size_log, class_id);
+ u8 *flags = GetFlags(stack_size_log, class_id);
+ for (int i = 0; i < num_iter; i++) {
+ uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++);
+ // This part is tricky. On one hand, checking and setting flags[pos]
+ // should be atomic to ensure async-signal safety. But on the other hand,
+ // if the signal arrives between checking and setting flags[pos], the
+ // signal handler's fake stack will start from a different hint_position
+ // and so will not touch this particular byte. So, it is safe to do this
+ // with regular non-atimic load and store (at least I was not able to make
+ // this code crash).
+ if (flags[pos]) continue;
+ flags[pos] = 1;
+ FakeFrame *res = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log, class_id, pos));
+ res->real_stack = real_stack;
+ *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
+ return res;
+ }
+ return 0; // We are out of fake stack.
+}
+
+uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
+ uptr stack_size_log = this->stack_size_log();
+ uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
+ uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
+ if (ptr < beg || ptr >= end) return 0;
+ uptr class_id = (ptr - beg) >> stack_size_log;
+ uptr base = beg + (class_id << stack_size_log);
+ CHECK_LE(base, ptr);
+ CHECK_LT(ptr, base + (1UL << stack_size_log));
+ uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
+ uptr res = base + pos * BytesInSizeClass(class_id);
+ *frame_end = res + BytesInSizeClass(class_id);
+ *frame_beg = res + sizeof(FakeFrame);
+ return res;
+}
+
+void FakeStack::HandleNoReturn() {
+ needs_gc_ = true;
+}
+
+// When throw, longjmp or some such happens we don't call OnFree() and
+// as the result may leak one or more fake frames, but the good news is that
+// we are notified about all such events by HandleNoReturn().
+// If we recently had such no-return event we need to collect garbage frames.
+// We do it based on their 'real_stack' values -- everything that is lower
+// than the current real_stack is garbage.
+NOINLINE void FakeStack::GC(uptr real_stack) {
+ uptr collected = 0;
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ if (ff->real_stack < real_stack) {
+ flags[i] = 0;
+ collected++;
+ }
+ }
+ }
+ needs_gc_ = false;
+}
+
+void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ uptr begin = reinterpret_cast<uptr>(ff);
+ callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg);
+ }
+ }
+}
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+static THREADLOCAL FakeStack *fake_stack_tls;
+
+FakeStack *GetTLSFakeStack() {
+ return fake_stack_tls;
+}
+void SetTLSFakeStack(FakeStack *fs) {
+ fake_stack_tls = fs;
+}
+#else
+FakeStack *GetTLSFakeStack() { return 0; }
+void SetTLSFakeStack(FakeStack *fs) { }
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+static FakeStack *GetFakeStack() {
+ AsanThread *t = GetCurrentThread();
+ if (!t) return 0;
+ return t->fake_stack();
+}
+
+static FakeStack *GetFakeStackFast() {
+ if (FakeStack *fs = GetTLSFakeStack())
+ return fs;
+ if (!__asan_option_detect_stack_use_after_return)
+ return 0;
+ return GetFakeStack();
+}
+
+ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
+ FakeStack *fs = GetFakeStackFast();
+ if (!fs) return 0;
+ uptr local_stack;
+ uptr real_stack = reinterpret_cast<uptr>(&local_stack);
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
+ if (!ff) return 0; // Out of fake stack.
+ uptr ptr = reinterpret_cast<uptr>(ff);
+ SetShadow(ptr, size, class_id, 0);
+ return ptr;
+}
+
+ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
+ FakeStack::Deallocate(ptr, class_id);
+ SetShadow(ptr, size, class_id, kMagic8);
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;
+#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
+ __asan_stack_malloc_##class_id(uptr size) { \
+ return OnMalloc(class_id, size); \
+ } \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
+ uptr ptr, uptr size) { \
+ OnFree(ptr, class_id, size); \
+ }
+
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
+ void **end) {
+ FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
+ if (!fs) return 0;
+ uptr frame_beg, frame_end;
+ FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
+ reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
+ if (!frame) return 0;
+ if (frame->magic != kCurrentStackFrameMagic)
+ return 0;
+ if (beg) *beg = reinterpret_cast<void*>(frame_beg);
+ if (end) *end = reinterpret_cast<void*>(frame_end);
+ return reinterpret_cast<void*>(frame->real_stack);
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/asan/asan_fake_stack.h b/contrib/compiler-rt/lib/asan/asan_fake_stack.h
new file mode 100644
index 000000000000..3b1d9eb3b57e
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_fake_stack.h
@@ -0,0 +1,175 @@
+//===-- asan_fake_stack.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_fake_stack.cc, implements FakeStack.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_FAKE_STACK_H
+#define ASAN_FAKE_STACK_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __asan {
+
+// Fake stack frame contains local variables of one function.
+struct FakeFrame {
+ uptr magic; // Modified by the instrumented code.
+ uptr descr; // Modified by the instrumented code.
+ uptr pc; // Modified by the instrumented code.
+ uptr real_stack;
+};
+
+// For each thread we create a fake stack and place stack objects on this fake
+// stack instead of the real stack. The fake stack is not really a stack but
+// a fast malloc-like allocator so that when a function exits the fake stack
+// is not popped but remains there for quite some time until gets used again.
+// So, we poison the objects on the fake stack when function returns.
+// It helps us find use-after-return bugs.
+//
+// The FakeStack objects is allocated by a single mmap call and has no other
+// pointers. The size of the fake stack depends on the actual thread stack size
+// and thus can not be a constant.
+// stack_size is a power of two greater or equal to the thread's stack size;
+// we store it as its logarithm (stack_size_log).
+// FakeStack has kNumberOfSizeClasses (11) size classes, each size class
+// is a power of two, starting from 64 bytes. Each size class occupies
+// stack_size bytes and thus can allocate
+// NumberOfFrames=(stack_size/BytesInSizeClass) fake frames (also a power of 2).
+// For each size class we have NumberOfFrames allocation flags,
+// each flag indicates whether the given frame is currently allocated.
+// All flags for size classes 0 .. 10 are stored in a single contiguous region
+// followed by another contiguous region which contains the actual memory for
+// size classes. The addresses are computed by GetFlags and GetFrame without
+// any memory accesses solely based on 'this' and stack_size_log.
+// Allocate() flips the appropriate allocation flag atomically, thus achieving
+// async-signal safety.
+// This allocator does not have quarantine per se, but it tries to allocate the
+// frames in round robin fasion to maximize the delay between a deallocation
+// and the next allocation.
+class FakeStack {
+ static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B.
+ static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K.
+
+ public:
+ static const uptr kNumberOfSizeClasses =
+ kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
+
+ // CTOR: create the FakeStack as a single mmap-ed object.
+ static FakeStack *Create(uptr stack_size_log);
+
+ void Destroy(int tid);
+
+ // stack_size_log is at least 15 (stack_size >= 32K).
+ static uptr SizeRequiredForFlags(uptr stack_size_log) {
+ return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog);
+ }
+
+ // Each size class occupies stack_size bytes.
+ static uptr SizeRequiredForFrames(uptr stack_size_log) {
+ return (1ULL << stack_size_log) * kNumberOfSizeClasses;
+ }
+
+ // Number of bytes requires for the whole object.
+ static uptr RequiredSize(uptr stack_size_log) {
+ return kFlagsOffset + SizeRequiredForFlags(stack_size_log) +
+ SizeRequiredForFrames(stack_size_log);
+ }
+
+ // Offset of the given flag from the first flag.
+ // The flags for class 0 begin at offset 000000000
+ // The flags for class 1 begin at offset 100000000
+ // ....................2................ 110000000
+ // ....................3................ 111000000
+ // and so on.
+ static uptr FlagsOffset(uptr stack_size_log, uptr class_id) {
+ uptr t = kNumberOfSizeClasses - 1 - class_id;
+ const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1;
+ return ((all_ones >> t) << t) << (stack_size_log - 15);
+ }
+
+ static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) {
+ return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id);
+ }
+
+ // Divide n by the numbe of frames in size class.
+ static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) {
+ return n & (NumberOfFrames(stack_size_log, class_id) - 1);
+ }
+
+ // The the pointer to the flags of the given class_id.
+ u8 *GetFlags(uptr stack_size_log, uptr class_id) {
+ return reinterpret_cast<u8 *>(this) + kFlagsOffset +
+ FlagsOffset(stack_size_log, class_id);
+ }
+
+ // Get frame by class_id and pos.
+ u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) {
+ return reinterpret_cast<u8 *>(this) + kFlagsOffset +
+ SizeRequiredForFlags(stack_size_log) +
+ (1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos;
+ }
+
+ // Allocate the fake frame.
+ FakeFrame *Allocate(uptr stack_size_log, uptr class_id, uptr real_stack);
+
+ // Deallocate the fake frame: read the saved flag address and write 0 there.
+ static void Deallocate(uptr x, uptr class_id) {
+ **SavedFlagPtr(x, class_id) = 0;
+ }
+
+ // Poison the entire FakeStack's shadow with the magic value.
+ void PoisonAll(u8 magic);
+
+ // Return the beginning of the FakeFrame or 0 if the address is not ours.
+ uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
+ USED uptr AddrIsInFakeStack(uptr addr) {
+ uptr t1, t2;
+ return AddrIsInFakeStack(addr, &t1, &t2);
+ }
+
+ // Number of bytes in a fake frame of this size class.
+ static uptr BytesInSizeClass(uptr class_id) {
+ return 1UL << (class_id + kMinStackFrameSizeLog);
+ }
+
+ // The fake frame is guaranteed to have a right redzone.
+ // We use the last word of that redzone to store the address of the flag
+ // that corresponds to the current frame to make faster deallocation.
+ static u8 **SavedFlagPtr(uptr x, uptr class_id) {
+ return reinterpret_cast<u8 **>(x + BytesInSizeClass(class_id) - sizeof(x));
+ }
+
+ uptr stack_size_log() const { return stack_size_log_; }
+
+ void HandleNoReturn();
+ void GC(uptr real_stack);
+
+ void ForEachFakeFrame(RangeIteratorCallback callback, void *arg);
+
+ private:
+ FakeStack() { }
+ static const uptr kFlagsOffset = 4096; // This is were the flags begin.
+ // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
+ COMPILER_CHECK(kNumberOfSizeClasses == 11);
+ static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
+
+ uptr hint_position_[kNumberOfSizeClasses];
+ uptr stack_size_log_;
+ // a bit is set if something was allocated from the corresponding size class.
+ bool needs_gc_;
+};
+
+FakeStack *GetTLSFakeStack();
+void SetTLSFakeStack(FakeStack *fs);
+
+} // namespace __asan
+
+#endif // ASAN_FAKE_STACK_H
diff --git a/contrib/compiler-rt/lib/asan/asan_flags.cc b/contrib/compiler-rt/lib/asan/asan_flags.cc
new file mode 100644
index 000000000000..efb7767d5d91
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_flags.cc
@@ -0,0 +1,160 @@
+//===-- asan_flags.cc -------------------------------------------*- 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 flag parsing logic.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_flags.h"
+#include "asan_interface_internal.h"
+#include "asan_stack.h"
+#include "lsan/lsan_common.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+
+namespace __asan {
+
+Flags asan_flags_dont_use_directly; // use via flags().
+
+static const char *MaybeCallAsanDefaultOptions() {
+ return (&__asan_default_options) ? __asan_default_options() : "";
+}
+
+static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {
+#ifdef ASAN_DEFAULT_OPTIONS
+// Stringize the macro value.
+# define ASAN_STRINGIZE(x) #x
+# define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options)
+ return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS);
+#else
+ return "";
+#endif
+}
+
+void Flags::SetDefaults() {
+#define ASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "asan_flags.inc"
+#undef ASAN_FLAG
+}
+
+static void RegisterAsanFlags(FlagParser *parser, Flags *f) {
+#define ASAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "asan_flags.inc"
+#undef ASAN_FLAG
+}
+
+void InitializeFlags() {
+ // Set the default values and prepare for parsing ASan and common flags.
+ SetCommonFlagsDefaults();
+ {
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.detect_leaks = CAN_SANITIZE_LEAKS;
+ cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
+ cf.malloc_context_size = kDefaultMallocContextSize;
+ cf.intercept_tls_get_addr = true;
+ OverrideCommonFlags(cf);
+ }
+ Flags *f = flags();
+ f->SetDefaults();
+
+ FlagParser asan_parser;
+ RegisterAsanFlags(&asan_parser, f);
+ RegisterCommonFlags(&asan_parser);
+
+ // Set the default values and prepare for parsing LSan flags (which can also
+ // overwrite common flags).
+#if CAN_SANITIZE_LEAKS
+ __lsan::Flags *lf = __lsan::flags();
+ lf->SetDefaults();
+
+ FlagParser lsan_parser;
+ __lsan::RegisterLsanFlags(&lsan_parser, lf);
+ RegisterCommonFlags(&lsan_parser);
+#endif
+
+ // Override from ASan compile definition.
+ const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
+ asan_parser.ParseString(asan_compile_def);
+
+ // Override from user-specified string.
+ const char *asan_default_options = MaybeCallAsanDefaultOptions();
+ asan_parser.ParseString(asan_default_options);
+
+ // Override from command line.
+ asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
+#if CAN_SANITIZE_LEAKS
+ lsan_parser.ParseString(GetEnv("LSAN_OPTIONS"));
+#endif
+
+ // Let activation flags override current settings. On Android they come
+ // from a system property. On other platforms this is no-op.
+ if (!flags()->start_deactivated) {
+ char buf[100];
+ GetExtraActivationFlags(buf, sizeof(buf));
+ asan_parser.ParseString(buf);
+ }
+
+ SetVerbosity(common_flags()->verbosity);
+
+ // TODO(eugenis): dump all flags at verbosity>=2?
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) {
+ // TODO(samsonov): print all of the flags (ASan, LSan, common).
+ asan_parser.PrintFlagDescriptions();
+ }
+
+ // Flag validation:
+ if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) {
+ Report("%s: detect_leaks is not supported on this platform.\n",
+ SanitizerToolName);
+ Die();
+ }
+ // 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) {
+ f->check_initialization_order = true;
+ }
+ CHECK_LE((uptr)common_flags()->malloc_context_size, kStackTraceMax);
+ CHECK_LE(f->min_uar_stack_size_log, f->max_uar_stack_size_log);
+ CHECK_GE(f->redzone, 16);
+ CHECK_GE(f->max_redzone, f->redzone);
+ CHECK_LE(f->max_redzone, 2048);
+ CHECK(IsPowerOfTwo(f->redzone));
+ CHECK(IsPowerOfTwo(f->max_redzone));
+
+ // quarantine_size is deprecated but we still honor it.
+ // quarantine_size can not be used together with quarantine_size_mb.
+ if (f->quarantine_size >= 0 && f->quarantine_size_mb >= 0) {
+ Report("%s: please use either 'quarantine_size' (deprecated) or "
+ "quarantine_size_mb, but not both\n", SanitizerToolName);
+ Die();
+ }
+ if (f->quarantine_size >= 0)
+ f->quarantine_size_mb = f->quarantine_size >> 20;
+ if (f->quarantine_size_mb < 0) {
+ const int kDefaultQuarantineSizeMb =
+ (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8;
+ f->quarantine_size_mb = kDefaultQuarantineSizeMb;
+ }
+}
+
+} // namespace __asan
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char* __asan_default_options() { return ""; }
+} // extern "C"
+#endif
diff --git a/contrib/compiler-rt/lib/asan/asan_flags.h b/contrib/compiler-rt/lib/asan/asan_flags.h
new file mode 100644
index 000000000000..4935161c30f1
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_flags.h
@@ -0,0 +1,49 @@
+//===-- asan_flags.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 runtime flags.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_FLAGS_H
+#define ASAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+
+// ASan flag values can be defined in four ways:
+// 1) initialized with default values at startup.
+// 2) overriden during compilation of ASan runtime by providing
+// compile definition ASAN_DEFAULT_OPTIONS.
+// 3) overriden from string returned by user-specified function
+// __asan_default_options().
+// 4) overriden from env variable ASAN_OPTIONS.
+// 5) overriden during ASan activation (for now used on Android only).
+
+namespace __asan {
+
+struct Flags {
+#define ASAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "asan_flags.inc"
+#undef ASAN_FLAG
+
+ void SetDefaults();
+};
+
+extern Flags asan_flags_dont_use_directly;
+inline Flags *flags() {
+ return &asan_flags_dont_use_directly;
+}
+
+void InitializeFlags();
+
+} // namespace __asan
+
+#endif // ASAN_FLAGS_H
diff --git a/contrib/compiler-rt/lib/asan/asan_flags.inc b/contrib/compiler-rt/lib/asan/asan_flags.inc
new file mode 100644
index 000000000000..53a8a4039e7e
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_flags.inc
@@ -0,0 +1,145 @@
+//===-- asan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ASan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_FLAG
+# error "Define ASAN_FLAG prior to including this file!"
+#endif
+
+// ASAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+ASAN_FLAG(int, quarantine_size, -1,
+ "Deprecated, please use quarantine_size_mb.")
+ASAN_FLAG(int, quarantine_size_mb, -1,
+ "Size (in Mb) of quarantine used to detect use-after-free "
+ "errors. Lower value may reduce memory usage but increase the "
+ "chance of false negatives.")
+ASAN_FLAG(int, redzone, 16,
+ "Minimal size (in bytes) of redzones around heap objects. "
+ "Requirement: redzone >= 16, is a power of two.")
+ASAN_FLAG(int, max_redzone, 2048,
+ "Maximal size (in bytes) of redzones around heap objects.")
+ASAN_FLAG(
+ bool, debug, false,
+ "If set, prints some debugging information and does additional checks.")
+ASAN_FLAG(
+ int, report_globals, 1,
+ "Controls the way to handle globals (0 - don't detect buffer overflow on "
+ "globals, 1 - detect buffer overflow, 2 - print data about registered "
+ "globals).")
+ASAN_FLAG(bool, check_initialization_order, false,
+ "If set, attempts to catch initialization order issues.")
+ASAN_FLAG(
+ bool, replace_str, true,
+ "If set, uses custom wrappers and replacements for libc string functions "
+ "to find more errors.")
+ASAN_FLAG(bool, replace_intrin, true,
+ "If set, uses custom wrappers for memset/memcpy/memmove intinsics.")
+ASAN_FLAG(bool, mac_ignore_invalid_free, false,
+ "Ignore invalid free() calls to work around some bugs. Used on OS X "
+ "only.")
+ASAN_FLAG(bool, detect_stack_use_after_return, false,
+ "Enables stack-use-after-return checking at run-time.")
+ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway.
+ "Minimum fake stack size log.")
+ASAN_FLAG(int, max_uar_stack_size_log,
+ 20, // 1Mb per size class, i.e. ~11Mb per thread
+ "Maximum fake stack size log.")
+ASAN_FLAG(bool, uar_noreserve, false,
+ "Use mmap with 'noreserve' flag to allocate fake stack.")
+ASAN_FLAG(
+ int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
+ "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
+ "bytes that will be filled with malloc_fill_byte on malloc.")
+ASAN_FLAG(int, malloc_fill_byte, 0xbe,
+ "Value used to fill the newly allocated memory.")
+ASAN_FLAG(int, exitcode, ASAN_DEFAULT_FAILURE_EXITCODE,
+ "Override the program exit status if the tool found an error.")
+ASAN_FLAG(bool, allow_user_poisoning, true,
+ "If set, user may manually mark memory regions as poisoned or "
+ "unpoisoned.")
+ASAN_FLAG(
+ int, sleep_before_dying, 0,
+ "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(bool, check_malloc_usable_size, true,
+ "Allows the users to work around the bug in Nvidia drivers prior to "
+ "295.*.")
+ASAN_FLAG(bool, unmap_shadow_on_exit, false,
+ "If set, explicitly unmaps the (huge) shadow at exit.")
+ASAN_FLAG(
+ bool, abort_on_error, false,
+ "If set, the tool calls abort() instead of _exit() after printing the "
+ "error report.")
+ASAN_FLAG(bool, print_stats, false,
+ "Print various statistics after printing an error message or if "
+ "atexit=1.")
+ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.")
+ASAN_FLAG(bool, atexit, false,
+ "If set, prints ASan exit stats even after program terminates "
+ "successfully.")
+ASAN_FLAG(
+ bool, print_full_thread_history, true,
+ "If set, prints thread creation stacks for the threads involved in the "
+ "report and their ancestors up to the main thread.")
+ASAN_FLAG(
+ bool, poison_heap, true,
+ "Poison (or not) the heap memory on [de]allocation. Zero value is useful "
+ "for benchmarking the allocator or instrumentator.")
+ASAN_FLAG(bool, poison_partial, true,
+ "If true, poison partially addressable 8-byte aligned words "
+ "(default=true). This flag affects heap and global buffers, but not "
+ "stack buffers.")
+ASAN_FLAG(bool, poison_array_cookie, true,
+ "Poison (or not) the array cookie after operator new[].")
+
+// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
+// https://code.google.com/p/address-sanitizer/issues/detail?id=131
+// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+// TODO(glider,timurrrr): Fix known issues and enable this back.
+ASAN_FLAG(bool, alloc_dealloc_mismatch,
+ (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0),
+ "Report errors on malloc/delete, new/free, new/delete[], etc.")
+
+ASAN_FLAG(bool, new_delete_type_mismatch, true,
+ "Report errors on mismatch betwen size of new and delete.")
+ASAN_FLAG(bool, strict_memcmp, true,
+ "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
+ "comparing p1 and p2.")
+ASAN_FLAG(
+ bool, strict_init_order, false,
+ "If true, assume that dynamic initializers can never access globals from "
+ "other modules, even if the latter are already initialized.")
+ASAN_FLAG(
+ bool, start_deactivated, false,
+ "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap "
+ "poisoning) to reduce memory consumption as much as possible, and "
+ "restores them to original values when the first instrumented module is "
+ "loaded into the process. This is mainly intended to be used on "
+ "Android. ")
+ASAN_FLAG(
+ int, detect_invalid_pointer_pairs, 0,
+ "If non-zero, try to detect operations like <, <=, >, >= and - on "
+ "invalid pointer pairs (e.g. when pointers belong to different objects). "
+ "The bigger the value the harder we try.")
+ASAN_FLAG(
+ bool, detect_container_overflow, true,
+ "If true, honor the container overflow annotations. "
+ "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow")
+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(const char *, suppressions, "", "Suppressions file name.")
diff --git a/contrib/compiler-rt/lib/asan/asan_globals.cc b/contrib/compiler-rt/lib/asan/asan_globals.cc
new file mode 100644
index 000000000000..06140bbb360a
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_globals.cc
@@ -0,0 +1,309 @@
+//===-- asan_globals.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.
+//
+// Handle globals.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __asan {
+
+typedef __asan_global Global;
+
+struct ListOfGlobals {
+ const Global *g;
+ ListOfGlobals *next;
+};
+
+static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_globals;
+static ListOfGlobals *list_of_all_globals;
+
+static const int kDynamicInitGlobalsInitialCapacity = 512;
+struct DynInitGlobal {
+ Global g;
+ bool initialized;
+};
+typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
+// Lazy-initialized and never deleted.
+static VectorOfGlobals *dynamic_init_globals;
+
+// We want to remember where a certain range of globals was registered.
+struct GlobalRegistrationSite {
+ u32 stack_id;
+ Global *g_first, *g_last;
+};
+typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
+static GlobalRegistrationSiteVector *global_registration_site_vector;
+
+ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
+ FastPoisonShadow(g->beg, g->size_with_redzone, value);
+}
+
+ALWAYS_INLINE void PoisonRedZones(const Global &g) {
+ uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
+ FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+ kAsanGlobalRedzoneMagic);
+ if (g.size != aligned_size) {
+ FastPoisonShadowPartialRightRedzone(
+ g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
+ g.size % SHADOW_GRANULARITY,
+ SHADOW_GRANULARITY,
+ kAsanGlobalRedzoneMagic);
+ }
+}
+
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
+ if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
+ if (addr >= g.beg + g.size_with_redzone) return false;
+ return true;
+}
+
+static void ReportGlobal(const Global &g, const char *prefix) {
+ Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+ prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
+ g.module_name, g.has_dynamic_init);
+ if (g.location) {
+ Report(" location (%p): name=%s[%p], %d %d\n", g.location,
+ g.location->filename, g.location->filename, g.location->line_no,
+ g.location->column_no);
+ }
+}
+
+static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
+ Global *output_global) {
+ if (!flags()->report_globals) return false;
+ BlockingMutexLock lock(&mu_for_globals);
+ bool res = false;
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ const Global &g = *l->g;
+ if (print) {
+ if (flags()->report_globals >= 2)
+ ReportGlobal(g, "Search");
+ res |= DescribeAddressRelativeToGlobal(addr, size, g);
+ } else {
+ if (IsAddressNearGlobal(addr, g)) {
+ CHECK(output_global);
+ *output_global = g;
+ return true;
+ }
+ }
+ }
+ return res;
+}
+
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+ return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
+ /* output_global */ nullptr);
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
+ Global g = {};
+ if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
+ internal_strncpy(descr->name, g.name, descr->name_size);
+ descr->region_address = g.beg;
+ descr->region_size = g.size;
+ descr->region_kind = "global";
+ return true;
+ }
+ return false;
+}
+
+u32 FindRegistrationSite(const Global *g) {
+ CHECK(global_registration_site_vector);
+ for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
+ GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
+ if (g >= grs.g_first && g <= grs.g_last)
+ return grs.stack_id;
+ }
+ return 0;
+}
+
+// Register a global variable.
+// This function may be called more than once for every global
+// so we store the globals in a map.
+static void RegisterGlobal(const Global *g) {
+ CHECK(asan_inited);
+ if (flags()->report_globals >= 2)
+ ReportGlobal(*g, "Added");
+ CHECK(flags()->report_globals);
+ CHECK(AddrIsInMem(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ if (flags()->detect_odr_violation) {
+ // Try detecting ODR (One Definition Rule) violation, i.e. the situation
+ // where two globals with the same name are defined in different modules.
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+ }
+ if (CanPoisonMemory())
+ PoisonRedZones(*g);
+ ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
+ l->g = g;
+ l->next = list_of_all_globals;
+ list_of_all_globals = l;
+ if (g->has_dynamic_init) {
+ if (dynamic_init_globals == 0) {
+ dynamic_init_globals = new(allocator_for_globals)
+ VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
+ }
+ DynInitGlobal dyn_global = { *g, false };
+ dynamic_init_globals->push_back(dyn_global);
+ }
+}
+
+static void UnregisterGlobal(const Global *g) {
+ CHECK(asan_inited);
+ if (flags()->report_globals >= 2)
+ ReportGlobal(*g, "Removed");
+ CHECK(flags()->report_globals);
+ CHECK(AddrIsInMem(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ if (CanPoisonMemory())
+ PoisonShadowForGlobal(g, 0);
+ // We unpoison the shadow memory for the global but we do not remove it from
+ // the list because that would require O(n^2) time with the current list
+ // implementation. It might not be worth doing anyway.
+}
+
+void StopInitOrderChecking() {
+ BlockingMutexLock lock(&mu_for_globals);
+ if (!flags()->check_initialization_order || !dynamic_init_globals)
+ return;
+ flags()->check_initialization_order = false;
+ for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+ DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+ const Global *g = &dyn_g.g;
+ // Unpoison the whole global.
+ PoisonShadowForGlobal(g, 0);
+ // Poison redzones back.
+ PoisonRedZones(*g);
+ }
+}
+
+#if SANITIZER_WINDOWS // Should only be called on Windows.
+SANITIZER_INTERFACE_ATTRIBUTE
+void UnregisterGlobalsInRange(void *beg, void *end) {
+ if (!flags()->report_globals)
+ return;
+ BlockingMutexLock lock(&mu_for_globals);
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ void *address = (void *)l->g->beg;
+ if (beg <= address && address < end)
+ UnregisterGlobal(l->g);
+ }
+}
+#endif
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// Register an array of globals.
+void __asan_register_globals(__asan_global *globals, uptr n) {
+ if (!flags()->report_globals) return;
+ GET_STACK_TRACE_FATAL_HERE;
+ u32 stack_id = StackDepotPut(stack);
+ BlockingMutexLock lock(&mu_for_globals);
+ if (!global_registration_site_vector)
+ global_registration_site_vector =
+ new(allocator_for_globals) GlobalRegistrationSiteVector(128);
+ GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
+ global_registration_site_vector->push_back(site);
+ if (flags()->report_globals >= 2) {
+ PRINT_CURRENT_STACK();
+ Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
+ }
+ for (uptr i = 0; i < n; i++) {
+ RegisterGlobal(&globals[i]);
+ }
+}
+
+// Unregister an array of globals.
+// We must do this when a shared objects gets dlclosed.
+void __asan_unregister_globals(__asan_global *globals, uptr n) {
+ if (!flags()->report_globals) return;
+ BlockingMutexLock lock(&mu_for_globals);
+ for (uptr i = 0; i < n; i++) {
+ UnregisterGlobal(&globals[i]);
+ }
+}
+
+// This method runs immediately prior to dynamic initialization in each TU,
+// when all dynamically initialized globals are unpoisoned. This method
+// poisons all global variables not defined in this TU, so that a dynamic
+// initializer can only touch global variables in the same TU.
+void __asan_before_dynamic_init(const char *module_name) {
+ if (!flags()->check_initialization_order ||
+ !CanPoisonMemory())
+ return;
+ bool strict_init_order = flags()->strict_init_order;
+ CHECK(dynamic_init_globals);
+ CHECK(module_name);
+ CHECK(asan_inited);
+ BlockingMutexLock lock(&mu_for_globals);
+ if (flags()->report_globals >= 3)
+ Printf("DynInitPoison module: %s\n", module_name);
+ for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+ DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+ const Global *g = &dyn_g.g;
+ if (dyn_g.initialized)
+ continue;
+ if (g->module_name != module_name)
+ PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
+ else if (!strict_init_order)
+ dyn_g.initialized = true;
+ }
+}
+
+// This method runs immediately after dynamic initialization in each TU, when
+// all dynamically initialized globals except for those defined in the current
+// TU are poisoned. It simply unpoisons all dynamically initialized globals.
+void __asan_after_dynamic_init() {
+ if (!flags()->check_initialization_order ||
+ !CanPoisonMemory())
+ return;
+ CHECK(asan_inited);
+ BlockingMutexLock lock(&mu_for_globals);
+ // FIXME: Optionally report that we're unpoisoning globals from a module.
+ for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+ DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+ const Global *g = &dyn_g.g;
+ if (!dyn_g.initialized) {
+ // Unpoison the whole global.
+ PoisonShadowForGlobal(g, 0);
+ // Poison redzones back.
+ PoisonRedZones(*g);
+ }
+ }
+}
diff --git a/contrib/compiler-rt/lib/asan/asan_init_version.h b/contrib/compiler-rt/lib/asan/asan_init_version.h
new file mode 100644
index 000000000000..6cf57c4aa2a8
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_init_version.h
@@ -0,0 +1,34 @@
+//===-- asan_init_version.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.
+//
+// This header defines a versioned __asan_init function to be called at the
+// startup of the instrumented program.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INIT_VERSION_H
+#define ASAN_INIT_VERSION_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
+ // versions will not link with run-time.
+ // Changes between ABI versions:
+ // v1=>v2: added 'module_name' to __asan_global
+ // v2=>v3: stack frame description (created by the compiler)
+ // contains the function PC as the 3-rd field (see
+ // DescribeAddressIfStack).
+ // v3=>v4: added '__asan_global_source_location' to __asan_global.
+ // v4=>v5: changed the semantics and format of __asan_stack_malloc_ and
+ // __asan_stack_free_ functions.
+ #define __asan_init __asan_init_v5
+ #define __asan_init_name "__asan_init_v5"
+}
+
+#endif // ASAN_INIT_VERSION_H
diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.cc b/contrib/compiler-rt/lib/asan/asan_interceptors.cc
new file mode 100644
index 000000000000..3dc7ec67a3e5
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_interceptors.cc
@@ -0,0 +1,930 @@
+//===-- asan_interceptors.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.
+//
+// Intercept various libc functions.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_suppressions.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+namespace __asan {
+
+// Return true if we can quickly decide that the region is unpoisoned.
+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);
+ 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; \
+ __asan_report_error(pc, bp, sp, __bad, isWrite, __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)
+
+static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
+#if ASAN_INTERCEPT_STRNLEN
+ if (REAL(strnlen) != 0) {
+ return REAL(strnlen)(s, maxlen);
+ }
+#endif
+ return internal_strnlen(s, maxlen);
+}
+
+void SetThreadName(const char *name) {
+ AsanThread *t = GetCurrentThread();
+ if (t)
+ asanThreadRegistry().SetThreadName(t->tid(), name);
+}
+
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
+} // namespace __asan
+
+// ---------------------- Wrappers ---------------- {{{1
+using namespace __asan; // NOLINT
+
+DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
+
+#if !SANITIZER_MAC
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif // SANITIZER_MAC
+
+#define ASAN_INTERCEPTOR_ENTER(ctx, func) \
+ AsanInterceptorContext _ctx = {#func}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx; \
+
+#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ ASAN_WRITE_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ ASAN_READ_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ ASAN_INTERCEPTOR_ENTER(ctx, func); \
+ do { \
+ if (asan_init_is_running) \
+ return REAL(func)(__VA_ARGS__); \
+ if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
+ return REAL(func)(__VA_ARGS__); \
+ ENSURE_ASAN_INITED(); \
+ } while (false)
+#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
+// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
+// But asan does not remember UserId's for threads (pthread_t);
+// and remembers all ever existed threads, so the linear search by UserId
+// can be slow.
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
+ CoverageUpdateMapping()
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping()
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
+#include "sanitizer_common/sanitizer_common_interceptors.inc"
+
+// Syscall interceptors don't have contexts, we don't support suppressions
+// for them.
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
+struct ThreadStartParam {
+ atomic_uintptr_t t;
+ atomic_uintptr_t is_registered;
+};
+
+static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
+#if SANITIZER_WINDOWS
+ // FIXME: this is a bandaid fix for PR22025.
+ AsanThread *t = (AsanThread*)arg;
+ SetCurrentThread(t);
+ return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
+#else
+ ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
+ AsanThread *t = nullptr;
+ while ((t = reinterpret_cast<AsanThread *>(
+ atomic_load(&param->t, memory_order_acquire))) == 0)
+ internal_sched_yield();
+ SetCurrentThread(t);
+ return t->ThreadStart(GetTid(), &param->is_registered);
+#endif
+}
+
+#if ASAN_INTERCEPT_PTHREAD_CREATE
+INTERCEPTOR(int, pthread_create, void *thread,
+ void *attr, void *(*start_routine)(void*), void *arg) {
+ EnsureMainThreadIDIsCorrect();
+ // Strict init-order checking is thread-hostile.
+ if (flags()->strict_init_order)
+ StopInitOrderChecking();
+ GET_STACK_TRACE_THREAD;
+ int detached = 0;
+ if (attr != 0)
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
+ ThreadStartParam param;
+ atomic_store(&param.t, 0, memory_order_relaxed);
+ atomic_store(&param.is_registered, 0, memory_order_relaxed);
+ int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+ if (result == 0) {
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
+ // Wait until the AsanThread object is initialized and the ThreadRegistry
+ // entry is in "started" state. One reason for this is that after this
+ // interceptor exits, the child thread's stack may be the only thing holding
+ // the |arg| pointer. This may cause LSan to report a leak if leak checking
+ // happens at a point when the interceptor has already exited, but the stack
+ // range for the child thread is not yet known.
+ while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
+ internal_sched_yield();
+ }
+ return result;
+}
+
+INTERCEPTOR(int, pthread_join, void *t, void **arg) {
+ return real_pthread_join(t, 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 (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ return REAL(bsd_signal)(signum, handler);
+ }
+ return 0;
+}
+#else
+INTERCEPTOR(void*, signal, int signum, void *handler) {
+ if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ return REAL(signal)(signum, handler);
+ }
+ return 0;
+}
+#endif
+
+INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
+ struct sigaction *oldact) {
+ if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ 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.
+ uptr PageSize = GetPageSizeCached();
+ uptr bottom = stack & ~(PageSize - 1);
+ ssize += stack - bottom;
+ ssize = RoundUpTo(ssize, PageSize);
+ static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb
+ if (ssize && ssize <= kMaxSaneContextStackSize) {
+ PoisonShadow(bottom, ssize, 0);
+ }
+}
+
+INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
+ struct ucontext_t *ucp) {
+ static bool reported_warning = false;
+ if (!reported_warning) {
+ Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
+ "functions and may produce false positives in some cases!\n");
+ reported_warning = true;
+ }
+ // Clear shadow memory for new context (it may share stack
+ // with current context).
+ uptr stack, ssize;
+ ReadContextStack(ucp, &stack, &ssize);
+ ClearShadowMemoryForContextStack(stack, ssize);
+ int res = REAL(swapcontext)(oucp, ucp);
+ // swapcontext technically does not return, but program may swap context to
+ // "oucp" later, that would look as if swapcontext() returned 0.
+ // We need to clear shadow for ucp once again, as it may be in arbitrary
+ // state.
+ ClearShadowMemoryForContextStack(stack, ssize);
+ return res;
+}
+#endif // ASAN_INTERCEPT_SWAPCONTEXT
+
+INTERCEPTOR(void, longjmp, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(longjmp)(env, val);
+}
+
+#if ASAN_INTERCEPT__LONGJMP
+INTERCEPTOR(void, _longjmp, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(_longjmp)(env, val);
+}
+#endif
+
+#if ASAN_INTERCEPT_SIGLONGJMP
+INTERCEPTOR(void, siglongjmp, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(siglongjmp)(env, val);
+}
+#endif
+
+#if ASAN_INTERCEPT___CXA_THROW
+INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
+ CHECK(REAL(__cxa_throw));
+ __asan_handle_no_return();
+ REAL(__cxa_throw)(a, b, c);
+}
+#endif
+
+#if SANITIZER_WINDOWS
+INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(RaiseException));
+ __asan_handle_no_return();
+ REAL(RaiseException)(a, b, c, d);
+}
+
+INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler3));
+ __asan_handle_no_return();
+ return REAL(_except_handler3)(a, b, c, d);
+}
+
+#if ASAN_DYNAMIC
+// This handler is named differently in -MT and -MD CRTs.
+#define _except_handler4 _except_handler4_common
+#endif
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler4));
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+#endif
+
+static inline int CharCmp(unsigned char c1, unsigned char c2) {
+ return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
+
+INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memcmp);
+ if (UNLIKELY(!asan_inited)) return internal_memcmp(a1, a2, size);
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_intrin) {
+ if (flags()->strict_memcmp) {
+ // Check the entire regions even if the first bytes of the buffers are
+ // different.
+ ASAN_READ_RANGE(ctx, a1, size);
+ ASAN_READ_RANGE(ctx, a2, size);
+ // Fallthrough to REAL(memcmp) below.
+ } else {
+ unsigned char c1 = 0, c2 = 0;
+ const unsigned char *s1 = (const unsigned char*)a1;
+ const unsigned char *s2 = (const unsigned char*)a2;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if (c1 != c2) break;
+ }
+ ASAN_READ_RANGE(ctx, s1, Min(i + 1, size));
+ ASAN_READ_RANGE(ctx, s2, Min(i + 1, size));
+ return CharCmp(c1, c2);
+ }
+ }
+ return REAL(memcmp(a1, a2, size));
+}
+
+// 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)
+
+
+void *__asan_memcpy(void *to, const void *from, uptr size) {
+ ASAN_MEMCPY_IMPL(nullptr, to, from, size);
+}
+
+// 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)
+
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+}
+
+#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)
+
+void *__asan_memmove(void *to, const void *from, uptr size) {
+ ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
+}
+
+INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memmove);
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
+}
+
+INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
+#if !SANITIZER_MAC
+ ASAN_MEMCPY_IMPL(ctx, to, from, size);
+#else
+ // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
+ // with WRAP(memcpy). As a result, false positives are reported for memmove()
+ // calls. If we just disable error reporting with
+ // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
+ // internal_memcpy(), which may lead to crashes, see
+ // http://llvm.org/bugs/show_bug.cgi?id=16362.
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
+#endif // !SANITIZER_MAC
+}
+
+INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memset);
+ ASAN_MEMSET_IMPL(ctx, block, c, size);
+}
+
+INTERCEPTOR(char*, strchr, const char *str, int c) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strchr);
+ if (UNLIKELY(!asan_inited)) return internal_strchr(str, c);
+ // strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
+ // used.
+ if (asan_init_is_running) {
+ return REAL(strchr)(str, c);
+ }
+ ENSURE_ASAN_INITED();
+ char *result = REAL(strchr)(str, c);
+ if (flags()->replace_str) {
+ uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
+ ASAN_READ_RANGE(ctx, str, bytes_read);
+ }
+ return result;
+}
+
+#if ASAN_INTERCEPT_INDEX
+# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+INTERCEPTOR(char*, index, const char *string, int c)
+ ALIAS(WRAPPER_NAME(strchr));
+# else
+# if SANITIZER_MAC
+DECLARE_REAL(char*, index, const char *string, int c)
+OVERRIDE_FUNCTION(index, strchr);
+# else
+DEFINE_REAL(char*, index, const char *string, int c)
+# endif
+# endif
+#endif // ASAN_INTERCEPT_INDEX
+
+// For both strcat() and strncat() we need to check the validity of |to|
+// argument irrespective of the |from| length.
+INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_length = REAL(strlen)(from);
+ ASAN_READ_RANGE(ctx, from, from_length + 1);
+ uptr to_length = REAL(strlen)(to);
+ ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
+ // If the copying actually happens, the |from| string should not overlap
+ // with the resulting string starting at |to|, which has a length of
+ // to_length + from_length + 1.
+ if (from_length > 0) {
+ CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1,
+ from, from_length + 1);
+ }
+ }
+ return REAL(strcat)(to, from); // NOLINT
+}
+
+INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncat);
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_length = MaybeRealStrnlen(from, size);
+ uptr copy_length = Min(size, from_length + 1);
+ ASAN_READ_RANGE(ctx, from, copy_length);
+ uptr to_length = REAL(strlen)(to);
+ ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
+ if (from_length > 0) {
+ CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
+ from, copy_length);
+ }
+ }
+ return REAL(strncat)(to, from, size);
+}
+
+INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
+#endif
+ // strcpy is called from malloc_default_purgeable_zone()
+ // in __asan::ReplaceSystemAlloc() on Mac.
+ if (asan_init_is_running) {
+ return REAL(strcpy)(to, from); // NOLINT
+ }
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_size = REAL(strlen)(from) + 1;
+ CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, from_size);
+ }
+ return REAL(strcpy)(to, from); // NOLINT
+}
+
+#if ASAN_INTERCEPT_STRDUP
+INTERCEPTOR(char*, strdup, const char *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strdup);
+ if (UNLIKELY(!asan_inited)) return internal_strdup(s);
+ ENSURE_ASAN_INITED();
+ uptr length = REAL(strlen)(s);
+ if (flags()->replace_str) {
+ ASAN_READ_RANGE(ctx, s, length + 1);
+ }
+ GET_STACK_TRACE_MALLOC;
+ void *new_mem = asan_malloc(length + 1, &stack);
+ REAL(memcpy)(new_mem, s, length + 1);
+ return reinterpret_cast<char*>(new_mem);
+}
+#endif
+
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strlen);
+ if (UNLIKELY(!asan_inited)) return internal_strlen(s);
+ // strlen is called from malloc_default_purgeable_zone()
+ // in __asan::ReplaceSystemAlloc() on Mac.
+ if (asan_init_is_running) {
+ return REAL(strlen)(s);
+ }
+ ENSURE_ASAN_INITED();
+ SIZE_T length = REAL(strlen)(s);
+ if (flags()->replace_str) {
+ ASAN_READ_RANGE(ctx, s, length + 1);
+ }
+ return length;
+}
+
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
+ SIZE_T length = REAL(wcslen)(s);
+ if (!asan_init_is_running) {
+ ENSURE_ASAN_INITED();
+ ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
+ }
+ return length;
+}
+
+INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
+ CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, size);
+ }
+ return REAL(strncpy)(to, from, size);
+}
+
+#if ASAN_INTERCEPT_STRNLEN
+INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
+ ENSURE_ASAN_INITED();
+ uptr length = REAL(strnlen)(s, maxlen);
+ if (flags()->replace_str) {
+ ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
+ }
+ return length;
+}
+#endif // ASAN_INTERCEPT_STRNLEN
+
+static inline bool IsValidStrtolBase(int base) {
+ return (base == 0) || (2 <= base && base <= 36);
+}
+
+static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
+ CHECK(endptr);
+ if (nptr == *endptr) {
+ // No digits were found at strtol call, we need to find out the last
+ // symbol accessed by strtoll on our own.
+ // We get this symbol by skipping leading blanks and optional +/- sign.
+ while (IsSpace(*nptr)) nptr++;
+ if (*nptr == '+' || *nptr == '-') nptr++;
+ *endptr = const_cast<char *>(nptr);
+ }
+ CHECK(*endptr >= nptr);
+}
+
+INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
+ char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtol);
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(strtol)(nptr, endptr, base);
+ }
+ char *real_endptr;
+ long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
+ if (endptr != 0) {
+ *endptr = real_endptr;
+ }
+ if (IsValidStrtolBase(base)) {
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ }
+ return result;
+}
+
+INTERCEPTOR(int, atoi, const char *nptr) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoi);
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
+#endif
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(atoi)(nptr);
+ }
+ char *real_endptr;
+ // "man atoi" tells that behavior of atoi(nptr) is the same as
+ // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
+ // parsed integer can't be stored in *long* type (even if it's
+ // different from int). So, we just imitate this behavior.
+ int result = REAL(strtol)(nptr, &real_endptr, 10);
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ return result;
+}
+
+INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atol);
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
+#endif
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(atol)(nptr);
+ }
+ char *real_endptr;
+ long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ return result;
+}
+
+#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
+ char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(strtoll)(nptr, endptr, base);
+ }
+ char *real_endptr;
+ long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
+ if (endptr != 0) {
+ *endptr = real_endptr;
+ }
+ // If base has unsupported value, strtoll can exit with EINVAL
+ // without reading any characters. So do additional checks only
+ // if base is valid.
+ if (IsValidStrtolBase(base)) {
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ }
+ return result;
+}
+
+INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoll);
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(atoll)(nptr);
+ }
+ char *real_endptr;
+ long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ return result;
+}
+#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+
+static void AtCxaAtexit(void *unused) {
+ (void)unused;
+ StopInitOrderChecking();
+}
+
+#if ASAN_INTERCEPT___CXA_ATEXIT
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
+#endif
+ ENSURE_ASAN_INITED();
+ int res = REAL(__cxa_atexit)(func, arg, dso_handle);
+ REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
+ return res;
+}
+#endif // ASAN_INTERCEPT___CXA_ATEXIT
+
+#if ASAN_INTERCEPT_FORK
+INTERCEPTOR(int, fork, void) {
+ ENSURE_ASAN_INITED();
+ if (common_flags()->coverage) CovBeforeFork();
+ int pid = REAL(fork)();
+ if (common_flags()->coverage) CovAfterFork(pid);
+ return pid;
+}
+#endif // ASAN_INTERCEPT_FORK
+
+#if SANITIZER_WINDOWS
+INTERCEPTOR_WINAPI(DWORD, CreateThread,
+ void* security, uptr stack_size,
+ DWORD (__stdcall *start_routine)(void*), void* arg,
+ DWORD thr_flags, void* tid) {
+ // Strict init-order checking is thread-hostile.
+ if (flags()->strict_init_order)
+ StopInitOrderChecking();
+ GET_STACK_TRACE_THREAD;
+ // FIXME: The CreateThread interceptor is not the same as a pthread_create
+ // one. This is a bandaid fix for PR22025.
+ bool detached = false; // FIXME: how can we determine it on Windows?
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ return REAL(CreateThread)(security, stack_size,
+ asan_thread_start, t, thr_flags, tid);
+}
+
+namespace __asan {
+void InitializeWindowsInterceptors() {
+ ASAN_INTERCEPT_FUNC(CreateThread);
+ ASAN_INTERCEPT_FUNC(RaiseException);
+ ASAN_INTERCEPT_FUNC(_except_handler3);
+ ASAN_INTERCEPT_FUNC(_except_handler4);
+}
+
+} // namespace __asan
+#endif
+
+// ---------------------- InitializeAsanInterceptors ---------------- {{{1
+namespace __asan {
+void InitializeAsanInterceptors() {
+ static bool was_called_once;
+ CHECK(was_called_once == false);
+ was_called_once = true;
+ InitializeCommonInterceptors();
+
+ // Intercept mem* functions.
+ ASAN_INTERCEPT_FUNC(memcmp);
+ ASAN_INTERCEPT_FUNC(memmove);
+ ASAN_INTERCEPT_FUNC(memset);
+ if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
+ ASAN_INTERCEPT_FUNC(memcpy);
+ }
+
+ // Intercept str* functions.
+ ASAN_INTERCEPT_FUNC(strcat); // NOLINT
+ ASAN_INTERCEPT_FUNC(strchr);
+ ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
+ ASAN_INTERCEPT_FUNC(strlen);
+ ASAN_INTERCEPT_FUNC(wcslen);
+ ASAN_INTERCEPT_FUNC(strncat);
+ ASAN_INTERCEPT_FUNC(strncpy);
+#if ASAN_INTERCEPT_STRDUP
+ ASAN_INTERCEPT_FUNC(strdup);
+#endif
+#if ASAN_INTERCEPT_STRNLEN
+ ASAN_INTERCEPT_FUNC(strnlen);
+#endif
+#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+ ASAN_INTERCEPT_FUNC(index);
+#endif
+
+ ASAN_INTERCEPT_FUNC(atoi);
+ ASAN_INTERCEPT_FUNC(atol);
+ ASAN_INTERCEPT_FUNC(strtol);
+#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+ ASAN_INTERCEPT_FUNC(atoll);
+ ASAN_INTERCEPT_FUNC(strtoll);
+#endif
+
+ // Intecept signal- and 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);
+#else
+ ASAN_INTERCEPT_FUNC(signal);
+#endif
+#endif
+#if ASAN_INTERCEPT_SWAPCONTEXT
+ ASAN_INTERCEPT_FUNC(swapcontext);
+#endif
+#if ASAN_INTERCEPT__LONGJMP
+ ASAN_INTERCEPT_FUNC(_longjmp);
+#endif
+#if ASAN_INTERCEPT_SIGLONGJMP
+ ASAN_INTERCEPT_FUNC(siglongjmp);
+#endif
+
+ // Intercept exception handling functions.
+#if ASAN_INTERCEPT___CXA_THROW
+ ASAN_INTERCEPT_FUNC(__cxa_throw);
+#endif
+
+ // Intercept threading-related functions
+#if ASAN_INTERCEPT_PTHREAD_CREATE
+ ASAN_INTERCEPT_FUNC(pthread_create);
+ ASAN_INTERCEPT_FUNC(pthread_join);
+#endif
+
+ // Intercept atexit function.
+#if ASAN_INTERCEPT___CXA_ATEXIT
+ ASAN_INTERCEPT_FUNC(__cxa_atexit);
+#endif
+
+#if ASAN_INTERCEPT_FORK
+ ASAN_INTERCEPT_FUNC(fork);
+#endif
+
+ // Some Windows-specific interceptors.
+#if SANITIZER_WINDOWS
+ InitializeWindowsInterceptors();
+#endif
+
+ VReport(1, "AddressSanitizer: libc interceptors initialized\n");
+}
+
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.h b/contrib/compiler-rt/lib/asan/asan_interceptors.h
new file mode 100644
index 000000000000..ee3b82aa7ef9
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_interceptors.h
@@ -0,0 +1,108 @@
+//===-- asan_interceptors.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_interceptors.cc
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERCEPTORS_H
+#define ASAN_INTERCEPTORS_H
+
+#include "asan_internal.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+// Use macro to describe if specific function should be
+// intercepted on a given platform.
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
+# define ASAN_INTERCEPT__LONGJMP 1
+# define ASAN_INTERCEPT_STRDUP 1
+# define ASAN_INTERCEPT_INDEX 1
+# define ASAN_INTERCEPT_PTHREAD_CREATE 1
+# define ASAN_INTERCEPT_FORK 1
+#else
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
+# define ASAN_INTERCEPT__LONGJMP 0
+# define ASAN_INTERCEPT_STRDUP 0
+# define ASAN_INTERCEPT_INDEX 0
+# define ASAN_INTERCEPT_PTHREAD_CREATE 0
+# define ASAN_INTERCEPT_FORK 0
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
+#else
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
+#endif
+
+#if !SANITIZER_MAC
+# define ASAN_INTERCEPT_STRNLEN 1
+#else
+# define ASAN_INTERCEPT_STRNLEN 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# 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
+#endif
+
+// Android bug: https://code.google.com/p/android/issues/detail?id=61799
+#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
+ !(SANITIZER_ANDROID && defined(__i386))
+# define ASAN_INTERCEPT___CXA_THROW 1
+#else
+# define ASAN_INTERCEPT___CXA_THROW 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT___CXA_ATEXIT 1
+#else
+# define ASAN_INTERCEPT___CXA_ATEXIT 0
+#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)
+
+namespace __asan {
+
+void InitializeAsanInterceptors();
+
+#define ENSURE_ASAN_INITED() do { \
+ CHECK(!asan_init_is_running); \
+ if (UNLIKELY(!asan_inited)) { \
+ AsanInitFromRtl(); \
+ } \
+} while (0)
+
+} // namespace __asan
+
+#endif // ASAN_INTERCEPTORS_H
diff --git a/contrib/compiler-rt/lib/asan/asan_interface_internal.h b/contrib/compiler-rt/lib/asan/asan_interface_internal.h
new file mode 100644
index 000000000000..ea7540f6bb56
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_interface_internal.h
@@ -0,0 +1,185 @@
+//===-- asan_interface_internal.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.
+//
+// This header declares the AddressSanitizer runtime interface functions.
+// The runtime library has to define these functions so the instrumented program
+// could call them.
+//
+// See also include/sanitizer/asan_interface.h
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERFACE_INTERNAL_H
+#define ASAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+#include "asan_init_version.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+ // This function should be called at the very beginning of the process,
+ // before any instrumented code is executed and before any call to malloc.
+ // Please note that __asan_init is a macro that is replaced with
+ // __asan_init_vXXX at compile-time.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
+
+ // This structure is used to describe the source location of a place where
+ // global was defined.
+ struct __asan_global_source_location {
+ const char *filename;
+ int line_no;
+ int column_no;
+ };
+
+ // This structure describes an instrumented global variable.
+ struct __asan_global {
+ uptr beg; // The address of the global.
+ uptr size; // The original size of the global.
+ uptr size_with_redzone; // The size with the redzone.
+ const char *name; // Name as a C string.
+ const char *module_name; // Module name as a C string. This pointer is a
+ // unique identifier of a module.
+ uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
+ __asan_global_source_location *location; // Source location of a global,
+ // or NULL if it is unknown.
+ };
+
+ // These two functions should be called by the instrumented code.
+ // 'globals' is an array of structures describing 'n' globals.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_register_globals(__asan_global *globals, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unregister_globals(__asan_global *globals, uptr n);
+
+ // These two functions should be called before and after dynamic initializers
+ // of a single module run, respectively.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_before_dynamic_init(const char *module_name);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_after_dynamic_init();
+
+ // These two functions are used by instrumented code in the
+ // use-after-scope mode. They mark memory for local variables as
+ // unaddressable when they leave scope and addressable before the
+ // function exits.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_stack_memory(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_stack_memory(uptr addr, uptr size);
+
+ // Performs cleanup before a NoReturn function. Must be called before things
+ // like _exit and execl to avoid false positives on stack.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_memory_region(void const volatile *addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_memory_region(void const volatile *addr, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_address_is_poisoned(void const volatile *addr);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_region_is_poisoned(uptr beg, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_describe_address(uptr addr);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_report_present();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_pc();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_bp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_sp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_address();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_get_report_access_type();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_access_size();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_get_report_description();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_report_error(uptr pc, uptr bp, uptr sp,
+ uptr addr, int is_write, uptr access_size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_set_error_exit_code(int exit_code);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_death_callback(void (*callback)(void));
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_error_report_callback(void (*callback)(const char*));
+
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __asan_on_error();
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
+
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ const char* __asan_default_options();
+
+ // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern int __asan_option_detect_stack_use_after_return;
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern uptr *__asan_test_only_reported_buggy_pointer;
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memcpy(void *dst, const void *src, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memset(void *s, int c, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memmove(void* dest, const void* src, uptr n);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_cxx_array_cookie(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_load_cxx_array_cookie(uptr *p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_intra_object_redzone(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
+} // extern "C"
+
+#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/asan/asan_internal.h b/contrib/compiler-rt/lib/asan/asan_internal.h
new file mode 100644
index 000000000000..ffd3ff82d71e
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_internal.h
@@ -0,0 +1,162 @@
+//===-- asan_internal.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 which defines various general utilities.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERNAL_H
+#define ASAN_INTERNAL_H
+
+#include "asan_flags.h"
+#include "asan_interface_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+#define ASAN_DEFAULT_FAILURE_EXITCODE 1
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# error "The AddressSanitizer run-time should not be"
+ " instrumented by AddressSanitizer"
+#endif
+
+// Build-time configuration options.
+
+// If set, asan will intercept C++ exception api call(s).
+#ifndef ASAN_HAS_EXCEPTIONS
+# define ASAN_HAS_EXCEPTIONS 1
+#endif
+
+// If set, values like allocator chunk size, as well as defaults for some flags
+// will be changed towards less memory overhead.
+#ifndef ASAN_LOW_MEMORY
+#if SANITIZER_WORDSIZE == 32
+# define ASAN_LOW_MEMORY 1
+#else
+# define ASAN_LOW_MEMORY 0
+# endif
+#endif
+
+#ifndef ASAN_DYNAMIC
+# ifdef PIC
+# define ASAN_DYNAMIC 1
+# else
+# define ASAN_DYNAMIC 0
+# endif
+#endif
+
+// All internal functions in asan reside inside the __asan namespace
+// to avoid namespace collisions with the user programs.
+// Separate namespace also makes it simpler to distinguish the asan run-time
+// functions from the instrumented user code in a profile.
+namespace __asan {
+
+class AsanThread;
+using __sanitizer::StackTrace;
+
+struct SignalContext {
+ void *context;
+ uptr addr;
+ uptr pc;
+ uptr sp;
+ uptr bp;
+
+ SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
+ context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
+ }
+
+ // Creates signal context in a platform-specific manner.
+ static SignalContext Create(void *siginfo, void *context);
+};
+
+void AsanInitFromRtl();
+
+// asan_rtl.cc
+void NORETURN ShowStatsAndAbort();
+
+// asan_malloc_linux.cc / asan_malloc_mac.cc
+void ReplaceSystemMalloc();
+
+// asan_linux.cc / asan_mac.cc / asan_win.cc
+void *AsanDoesNotSupportStaticLinkage();
+void AsanCheckDynamicRTPrereqs();
+void AsanCheckIncompatibleRT();
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+void AsanOnSIGSEGV(int, void *siginfo, void *context);
+
+void DisableReexec();
+void MaybeReexec();
+void ReadContextStack(void *context, uptr *stack, uptr *ssize);
+void AsanPlatformThreadInit();
+void StopInitOrderChecking();
+
+// Wrapper for TLS/TSD.
+void AsanTSDInit(void (*destructor)(void *tsd));
+void *AsanTSDGet();
+void AsanTSDSet(void *tsd);
+void PlatformTSDDtor(void *tsd);
+
+void AppendToErrorMessageBuffer(const char *buffer);
+
+void *AsanDlSymNext(const char *sym);
+
+void ReserveShadowMemoryRange(uptr beg, uptr end);
+
+// Platform-specific options.
+#if SANITIZER_MAC
+bool PlatformHasDifferentMemcpyAndMemmove();
+# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
+ (PlatformHasDifferentMemcpyAndMemmove())
+#else
+# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
+#endif // SANITIZER_MAC
+
+// Add convenient macro for interface functions that may be represented as
+// weak hooks.
+#define ASAN_MALLOC_HOOK(ptr, size) \
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
+#define ASAN_FREE_HOOK(ptr) \
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
+#define ASAN_ON_ERROR() \
+ if (&__asan_on_error) __asan_on_error()
+
+extern int asan_inited;
+// Used to avoid infinite recursion in __asan_init().
+extern bool asan_init_is_running;
+extern void (*death_callback)(void);
+
+// These magic values are written to shadow for better error reporting.
+const int kAsanHeapLeftRedzoneMagic = 0xfa;
+const int kAsanHeapRightRedzoneMagic = 0xfb;
+const int kAsanHeapFreeMagic = 0xfd;
+const int kAsanStackLeftRedzoneMagic = 0xf1;
+const int kAsanStackMidRedzoneMagic = 0xf2;
+const int kAsanStackRightRedzoneMagic = 0xf3;
+const int kAsanStackPartialRedzoneMagic = 0xf4;
+const int kAsanStackAfterReturnMagic = 0xf5;
+const int kAsanInitializationOrderMagic = 0xf6;
+const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanContiguousContainerOOBMagic = 0xfc;
+const int kAsanStackUseAfterScopeMagic = 0xf8;
+const int kAsanGlobalRedzoneMagic = 0xf9;
+const int kAsanInternalHeapMagic = 0xfe;
+const int kAsanArrayCookieMagic = 0xac;
+const int kAsanIntraObjectRedzone = 0xbb;
+const int kAsanAllocaLeftMagic = 0xca;
+const int kAsanAllocaRightMagic = 0xcb;
+
+static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
+static const uptr kRetiredStackFrameMagic = 0x45E0360E;
+
+} // namespace __asan
+
+#endif // ASAN_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/asan/asan_linux.cc b/contrib/compiler-rt/lib/asan/asan_linux.cc
new file mode 100644
index 000000000000..8e8bafd47af6
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_linux.cc
@@ -0,0 +1,249 @@
+//===-- asan_linux.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.
+//
+// Linux-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_freebsd.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <unwind.h>
+
+#if SANITIZER_FREEBSD
+#include <sys/link_elf.h>
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <ucontext.h>
+extern "C" void* _DYNAMIC;
+#else
+#include <sys/ucontext.h>
+#include <link.h>
+#endif
+
+// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
+// 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
+ __FreeBSD_version <= 902001 // v9.2
+#define ucontext_t xucontext_t
+#endif
+
+typedef enum {
+ ASAN_RT_VERSION_UNDEFINED = 0,
+ ASAN_RT_VERSION_DYNAMIC,
+ ASAN_RT_VERSION_STATIC,
+} asan_rt_version_t;
+
+// FIXME: perhaps also store abi version here?
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+asan_rt_version_t __asan_rt_version;
+}
+
+namespace __asan {
+
+void DisableReexec() {
+ // No need to re-exec on Linux.
+}
+
+void MaybeReexec() {
+ // No need to re-exec on Linux.
+}
+
+void *AsanDoesNotSupportStaticLinkage() {
+ // This will fail to link with -static.
+ return &_DYNAMIC; // defined in link.h
+}
+
+#if SANITIZER_ANDROID
+// FIXME: should we do anything for Android?
+void AsanCheckDynamicRTPrereqs() {}
+void AsanCheckIncompatibleRT() {}
+#else
+static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ // Continue until the first dynamic library is found
+ if (!info->dlpi_name || info->dlpi_name[0] == 0)
+ return 0;
+
+ // Ignore vDSO
+ if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
+ return 0;
+
+ *(const char **)data = info->dlpi_name;
+ return 1;
+}
+
+static bool IsDynamicRTName(const char *libname) {
+ return internal_strstr(libname, "libclang_rt.asan") ||
+ internal_strstr(libname, "libasan.so");
+}
+
+static void ReportIncompatibleRT() {
+ Report("Your application is linked against incompatible ASan runtimes.\n");
+ Die();
+}
+
+void AsanCheckDynamicRTPrereqs() {
+ // Ensure that dynamic RT is the first DSO in the list
+ const char *first_dso_name = 0;
+ dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
+ if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
+ Report("ASan runtime does not come first in initial library list; "
+ "you should either link runtime to your application or "
+ "manually preload it with LD_PRELOAD.\n");
+ Die();
+ }
+}
+
+void AsanCheckIncompatibleRT() {
+ if (ASAN_DYNAMIC) {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
+ ReportIncompatibleRT();
+ }
+ } else {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ // Ensure that dynamic runtime is not present. We should detect it
+ // as early as possible, otherwise ASan interceptors could bind to
+ // the functions in dynamic ASan runtime instead of the functions in
+ // system libraries, causing crashes later in ASan initialization.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ char filename[128];
+ while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) {
+ if (IsDynamicRTName(filename)) {
+ Report("Your application is linked against "
+ "incompatible ASan runtimes.\n");
+ Die();
+ }
+ }
+ __asan_rt_version = ASAN_RT_VERSION_STATIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
+ ReportIncompatibleRT();
+ }
+ }
+}
+#endif // SANITIZER_ANDROID
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+#if defined(__arm__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.arm_pc;
+ *bp = ucontext->uc_mcontext.arm_fp;
+ *sp = ucontext->uc_mcontext.arm_sp;
+#elif defined(__aarch64__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.pc;
+ *bp = ucontext->uc_mcontext.regs[29];
+ *sp = ucontext->uc_mcontext.sp;
+#elif defined(__hppa__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.sc_iaoq[0];
+ /* GCC uses %r3 whenever a frame pointer is needed. */
+ *bp = ucontext->uc_mcontext.sc_gr[3];
+ *sp = ucontext->uc_mcontext.sc_gr[30];
+#elif defined(__x86_64__)
+# if SANITIZER_FREEBSD
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.mc_rip;
+ *bp = ucontext->uc_mcontext.mc_rbp;
+ *sp = ucontext->uc_mcontext.mc_rsp;
+# else
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.gregs[REG_RIP];
+ *bp = ucontext->uc_mcontext.gregs[REG_RBP];
+ *sp = ucontext->uc_mcontext.gregs[REG_RSP];
+# endif
+#elif defined(__i386__)
+# if SANITIZER_FREEBSD
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.mc_eip;
+ *bp = ucontext->uc_mcontext.mc_ebp;
+ *sp = ucontext->uc_mcontext.mc_esp;
+# else
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.gregs[REG_EIP];
+ *bp = ucontext->uc_mcontext.gregs[REG_EBP];
+ *sp = ucontext->uc_mcontext.gregs[REG_ESP];
+# endif
+#elif defined(__powerpc__) || defined(__powerpc64__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.regs->nip;
+ *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
+ // The powerpc{,64}-linux ABIs do not specify r31 as the frame
+ // pointer, but GCC always uses r31 when we need a frame pointer.
+ *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
+#elif defined(__sparc__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ uptr *stk_ptr;
+# if defined (__arch64__)
+ *pc = ucontext->uc_mcontext.mc_gregs[MC_PC];
+ *sp = ucontext->uc_mcontext.mc_gregs[MC_O6];
+ stk_ptr = (uptr *) (*sp + 2047);
+ *bp = stk_ptr[15];
+# else
+ *pc = ucontext->uc_mcontext.gregs[REG_PC];
+ *sp = ucontext->uc_mcontext.gregs[REG_O6];
+ stk_ptr = (uptr *) *sp;
+ *bp = stk_ptr[15];
+# endif
+#elif defined(__mips__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.gregs[31];
+ *bp = ucontext->uc_mcontext.gregs[30];
+ *sp = ucontext->uc_mcontext.gregs[29];
+#else
+# error "Unsupported arch"
+#endif
+}
+
+void AsanPlatformThreadInit() {
+ // Nothing here for now.
+}
+
+#if !SANITIZER_ANDROID
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ ucontext_t *ucp = (ucontext_t*)context;
+ *stack = (uptr)ucp->uc_stack.ss_sp;
+ *ssize = ucp->uc_stack.ss_size;
+}
+#else
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ UNIMPLEMENTED();
+}
+#endif
+
+void *AsanDlSymNext(const char *sym) {
+ return dlsym(RTLD_NEXT, sym);
+}
+
+} // namespace __asan
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/asan/asan_lock.h b/contrib/compiler-rt/lib/asan/asan_lock.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_lock.h
diff --git a/contrib/compiler-rt/lib/asan/asan_mac.cc b/contrib/compiler-rt/lib/asan/asan_mac.cc
new file mode 100644
index 000000000000..b35368617dca
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_mac.cc
@@ -0,0 +1,436 @@
+//===-- asan_mac.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.
+//
+// Mac-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mac.h"
+
+#include <crt_externs.h> // for _NSGetArgv
+#include <dlfcn.h> // for dladdr()
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/ucontext.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdlib.h> // for free()
+#include <unistd.h>
+#include <libkern/OSAtomic.h>
+
+namespace __asan {
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+ ucontext_t *ucontext = (ucontext_t*)context;
+# if SANITIZER_WORDSIZE == 64
+ *pc = ucontext->uc_mcontext->__ss.__rip;
+ *bp = ucontext->uc_mcontext->__ss.__rbp;
+ *sp = ucontext->uc_mcontext->__ss.__rsp;
+# else
+ *pc = ucontext->uc_mcontext->__ss.__eip;
+ *bp = ucontext->uc_mcontext->__ss.__ebp;
+ *sp = ucontext->uc_mcontext->__ss.__esp;
+# endif // SANITIZER_WORDSIZE
+}
+
+
+bool PlatformHasDifferentMemcpyAndMemmove() {
+ // On OS X 10.7 memcpy() and memmove() are both resolved
+ // into memmove$VARIANT$sse42.
+ // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34.
+ // TODO(glider): need to check dynamically that memcpy() and memmove() are
+ // actually the same function.
+ return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
+}
+
+extern "C"
+void __asan_init();
+
+static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
+LowLevelAllocator allocator_for_env;
+
+// Change the value of the env var |name|, leaking the original value.
+// If |name_value| is NULL, the variable is deleted from the environment,
+// otherwise the corresponding "NAME=value" string is replaced with
+// |name_value|.
+void LeakyResetEnv(const char *name, const char *name_value) {
+ char ***env_ptr = _NSGetEnviron();
+ CHECK(env_ptr);
+ char **environ = *env_ptr;
+ CHECK(environ);
+ uptr name_len = internal_strlen(name);
+ while (*environ != 0) {
+ uptr len = internal_strlen(*environ);
+ if (len > name_len) {
+ const char *p = *environ;
+ if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
+ // Match.
+ if (name_value) {
+ // Replace the old value with the new one.
+ *environ = const_cast<char*>(name_value);
+ } else {
+ // Shift the subsequent pointers back.
+ char **del = environ;
+ do {
+ del[0] = del[1];
+ } while (*del++);
+ }
+ }
+ }
+ environ++;
+ }
+}
+
+static bool reexec_disabled = false;
+
+void DisableReexec() {
+ reexec_disabled = true;
+}
+
+void MaybeReexec() {
+ if (reexec_disabled) return;
+
+ // Make sure the dynamic ASan runtime library is preloaded so that the
+ // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
+ // ourselves.
+ Dl_info info;
+ CHECK(dladdr((void*)((uptr)__asan_init), &info));
+ char *dyld_insert_libraries =
+ const_cast<char*>(GetEnv(kDyldInsertLibraries));
+ uptr old_env_len = dyld_insert_libraries ?
+ internal_strlen(dyld_insert_libraries) : 0;
+ uptr fname_len = internal_strlen(info.dli_fname);
+ const char *dylib_name = StripModuleName(info.dli_fname);
+ uptr dylib_name_len = internal_strlen(dylib_name);
+ if (!dyld_insert_libraries ||
+ !REAL(strstr)(dyld_insert_libraries, dylib_name)) {
+ // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
+ // library.
+ char program_name[1024];
+ uint32_t buf_size = sizeof(program_name);
+ _NSGetExecutablePath(program_name, &buf_size);
+ char *new_env = const_cast<char*>(info.dli_fname);
+ if (dyld_insert_libraries) {
+ // Append the runtime dylib name to the existing value of
+ // DYLD_INSERT_LIBRARIES.
+ new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
+ internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
+ new_env[old_env_len] = ':';
+ // Copy fname_len and add a trailing zero.
+ internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
+ fname_len + 1);
+ // Ok to use setenv() since the wrappers don't depend on the value of
+ // asan_inited.
+ setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
+ } else {
+ // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
+ setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
+ }
+ VReport(1, "exec()-ing the program with\n");
+ VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
+ VReport(1, "to enable ASan wrappers.\n");
+ execv(program_name, *_NSGetArgv());
+
+ // We get here only if execv() failed.
+ Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
+ "which is required for ASan to work. ASan tried to set the "
+ "environment variable and re-execute itself, but execv() failed, "
+ "possibly because of sandbox restrictions. Make sure to launch the "
+ "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
+ CHECK("execv failed" && 0);
+ }
+
+ // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
+ // the dylib from the environment variable, because interceptors are installed
+ // and we don't want our children to inherit the variable.
+
+ uptr env_name_len = internal_strlen(kDyldInsertLibraries);
+ // Allocate memory to hold the previous env var name, its value, the '='
+ // sign and the '\0' char.
+ char *new_env = (char*)allocator_for_env.Allocate(
+ old_env_len + 2 + env_name_len);
+ CHECK(new_env);
+ internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
+ internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
+ new_env[env_name_len] = '=';
+ char *new_env_pos = new_env + env_name_len + 1;
+
+ // Iterate over colon-separated pieces of |dyld_insert_libraries|.
+ char *piece_start = dyld_insert_libraries;
+ char *piece_end = NULL;
+ char *old_env_end = dyld_insert_libraries + old_env_len;
+ do {
+ if (piece_start[0] == ':') piece_start++;
+ piece_end = REAL(strchr)(piece_start, ':');
+ if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
+ if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
+ uptr piece_len = piece_end - piece_start;
+
+ char *filename_start =
+ (char *)internal_memrchr(piece_start, '/', piece_len);
+ uptr filename_len = piece_len;
+ if (filename_start) {
+ filename_start += 1;
+ filename_len = piece_len - (filename_start - piece_start);
+ } else {
+ filename_start = piece_start;
+ }
+
+ // If the current piece isn't the runtime library name,
+ // append it to new_env.
+ if ((dylib_name_len != filename_len) ||
+ (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
+ if (new_env_pos != new_env + env_name_len + 1) {
+ new_env_pos[0] = ':';
+ new_env_pos++;
+ }
+ internal_strncpy(new_env_pos, piece_start, piece_len);
+ new_env_pos += piece_len;
+ }
+ // Move on to the next piece.
+ piece_start = piece_end;
+ } while (piece_start < old_env_end);
+
+ // Can't use setenv() here, because it requires the allocator to be
+ // initialized.
+ // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
+ // a separate function called after InitializeAllocator().
+ if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
+ LeakyResetEnv(kDyldInsertLibraries, new_env);
+}
+
+// No-op. Mac does not support static linkage anyway.
+void *AsanDoesNotSupportStaticLinkage() {
+ return 0;
+}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckDynamicRTPrereqs() {}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckIncompatibleRT() {}
+
+void AsanPlatformThreadInit() {
+}
+
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ UNIMPLEMENTED();
+}
+
+// Support for the following functions from libdispatch on Mac OS:
+// dispatch_async_f()
+// dispatch_async()
+// dispatch_sync_f()
+// dispatch_sync()
+// dispatch_after_f()
+// dispatch_after()
+// dispatch_group_async_f()
+// dispatch_group_async()
+// TODO(glider): libdispatch API contains other functions that we don't support
+// yet.
+//
+// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
+// they can cause jobs to run on a thread different from the current one.
+// TODO(glider): if so, we need a test for this (otherwise we should remove
+// them).
+//
+// The following functions use dispatch_barrier_async_f() (which isn't a library
+// function but is exported) and are thus supported:
+// dispatch_source_set_cancel_handler_f()
+// dispatch_source_set_cancel_handler()
+// dispatch_source_set_event_handler_f()
+// dispatch_source_set_event_handler()
+//
+// The reference manual for Grand Central Dispatch is available at
+// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// The implementation details are at
+// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
+
+typedef void* dispatch_group_t;
+typedef void* dispatch_queue_t;
+typedef void* dispatch_source_t;
+typedef u64 dispatch_time_t;
+typedef void (*dispatch_function_t)(void *block);
+typedef void* (*worker_t)(void *block);
+
+// A wrapper for the ObjC blocks used to support libdispatch.
+typedef struct {
+ void *block;
+ dispatch_function_t func;
+ u32 parent_tid;
+} asan_block_context_t;
+
+ALWAYS_INLINE
+void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
+ AsanThread *t = GetCurrentThread();
+ if (!t) {
+ t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
+ parent_tid, stack, /* detached */ true);
+ t->Init();
+ asanThreadRegistry().StartThread(t->tid(), 0, 0);
+ SetCurrentThread(t);
+ }
+}
+
+// For use by only those functions that allocated the context via
+// alloc_asan_context().
+extern "C"
+void asan_dispatch_call_block_and_release(void *block) {
+ GET_STACK_TRACE_THREAD;
+ asan_block_context_t *context = (asan_block_context_t*)block;
+ VReport(2,
+ "asan_dispatch_call_block_and_release(): "
+ "context: %p, pthread_self: %p\n",
+ block, pthread_self());
+ asan_register_worker_thread(context->parent_tid, &stack);
+ // Call the original dispatcher for the block.
+ context->func(context->block);
+ asan_free(context, &stack, FROM_MALLOC);
+}
+
+} // namespace __asan
+
+using namespace __asan; // NOLINT
+
+// Wrap |ctxt| and |func| into an asan_block_context_t.
+// The caller retains control of the allocated context.
+extern "C"
+asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
+ BufferedStackTrace *stack) {
+ asan_block_context_t *asan_ctxt =
+ (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
+ asan_ctxt->block = ctxt;
+ asan_ctxt->func = func;
+ asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
+ return asan_ctxt;
+}
+
+// Define interceptor for dispatch_*_f function with the three most common
+// parameters: dispatch_queue_t, context, dispatch_function_t.
+#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
+ INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
+ dispatch_function_t func) { \
+ GET_STACK_TRACE_THREAD; \
+ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
+ if (Verbosity() >= 2) { \
+ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
+ asan_ctxt, pthread_self()); \
+ PRINT_CURRENT_STACK(); \
+ } \
+ return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
+ asan_dispatch_call_block_and_release); \
+ }
+
+INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
+
+INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
+ dispatch_queue_t dq, void *ctxt,
+ dispatch_function_t func) {
+ GET_STACK_TRACE_THREAD;
+ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+ if (Verbosity() >= 2) {
+ Report("dispatch_after_f: %p\n", asan_ctxt);
+ PRINT_CURRENT_STACK();
+ }
+ return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
+ asan_dispatch_call_block_and_release);
+}
+
+INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
+ dispatch_queue_t dq, void *ctxt,
+ dispatch_function_t func) {
+ GET_STACK_TRACE_THREAD;
+ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+ if (Verbosity() >= 2) {
+ Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
+ asan_ctxt, pthread_self());
+ PRINT_CURRENT_STACK();
+ }
+ REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
+ asan_dispatch_call_block_and_release);
+}
+
+#if !defined(MISSING_BLOCKS_SUPPORT)
+extern "C" {
+void dispatch_async(dispatch_queue_t dq, void(^work)(void));
+void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
+ void(^work)(void));
+void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
+ void(^work)(void));
+void dispatch_source_set_cancel_handler(dispatch_source_t ds,
+ void(^work)(void));
+void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
+}
+
+#define GET_ASAN_BLOCK(work) \
+ void (^asan_block)(void); \
+ int parent_tid = GetCurrentTidOrInvalid(); \
+ asan_block = ^(void) { \
+ GET_STACK_TRACE_THREAD; \
+ asan_register_worker_thread(parent_tid, &stack); \
+ work(); \
+ }
+
+INTERCEPTOR(void, dispatch_async,
+ dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_async)(dq, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_group_async,
+ dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_group_async)(dg, dq, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_after,
+ dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_after)(when, queue, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_cancel_handler,
+ dispatch_source_t ds, void(^work)(void)) {
+ if (!work) {
+ REAL(dispatch_source_set_cancel_handler)(ds, work);
+ return;
+ }
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_event_handler,
+ dispatch_source_t ds, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_source_set_event_handler)(ds, asan_block);
+}
+#endif
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc b/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc
new file mode 100644
index 000000000000..46a6a9db4a81
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc
@@ -0,0 +1,186 @@
+//===-- asan_malloc_linux.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.
+//
+// Linux-specific malloc interception.
+// We simply define functions like malloc, free, realloc, etc.
+// They will replace the corresponding libc functions automagically.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+
+// ---------------------- Replacement functions ---------------- {{{1
+using namespace __asan; // NOLINT
+
+INTERCEPTOR(void, free, void *ptr) {
+ GET_STACK_TRACE_FREE;
+ asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void, cfree, void *ptr) {
+ GET_STACK_TRACE_FREE;
+ asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_malloc(size, &stack);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ if (UNLIKELY(!asan_inited)) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const uptr kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static uptr allocated;
+ uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ GET_STACK_TRACE_MALLOC;
+ return asan_calloc(nmemb, size, &stack);
+}
+
+INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_realloc(ptr, size, &stack);
+}
+
+INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
+ DTLS_on_libc_memalign(res, size * boundary);
+ return res;
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
+}
+
+// We avoid including malloc.h for portability reasons.
+// man mallinfo says the fields are "long", but the implementation uses int.
+// It doesn't matter much -- we just need to make sure that the libc's mallinfo
+// is not called.
+struct fake_mallinfo {
+ int x[10];
+};
+
+INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
+ struct fake_mallinfo res;
+ REAL(memset)(&res, 0, sizeof(res));
+ return res;
+}
+
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ // Printf("posix_memalign: %zx %zu\n", alignment, size);
+ return asan_posix_memalign(memptr, alignment, size, &stack);
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_valloc(size, &stack);
+}
+
+INTERCEPTOR(void*, pvalloc, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_pvalloc(size, &stack);
+}
+
+INTERCEPTOR(void, malloc_stats, void) {
+ __asan_print_accumulated_stats();
+}
+
+#if SANITIZER_ANDROID
+// Format of __libc_malloc_dispatch has changed in Android L.
+// While we are moving towards a solution that does not depend on bionic
+// internals, here is something to support both K* and L releases.
+struct MallocDebugK {
+ void *(*malloc)(uptr bytes);
+ void (*free)(void *mem);
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+};
+
+struct MallocDebugL {
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void (*free)(void *mem);
+ fake_mallinfo (*mallinfo)(void);
+ void *(*malloc)(uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
+ void* (*pvalloc)(uptr size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void* (*valloc)(uptr size);
+};
+
+ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
+ WRAP(malloc), WRAP(free), WRAP(calloc),
+ WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
+
+ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
+ WRAP(calloc), WRAP(free), WRAP(mallinfo),
+ WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
+ WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
+ WRAP(valloc)};
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+ void **__libc_malloc_dispatch_p =
+ (void **)AsanDlSymNext("__libc_malloc_dispatch");
+ if (__libc_malloc_dispatch_p) {
+ // Decide on K vs L dispatch format by the presence of
+ // __libc_malloc_default_dispatch export in libc.
+ void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
+ if (default_dispatch_p)
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
+ else
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
+ }
+}
+} // namespace __asan
+
+#else // SANITIZER_ANDROID
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+}
+} // namespace __asan
+#endif // SANITIZER_ANDROID
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc b/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc
new file mode 100644
index 000000000000..d7a6307c9bdc
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc
@@ -0,0 +1,362 @@
+//===-- asan_malloc_mac.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.
+//
+// Mac-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include <AvailabilityMacros.h>
+#include <CoreFoundation/CFBase.h>
+#include <dlfcn.h>
+#include <malloc/malloc.h>
+#include <sys/mman.h>
+
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "sanitizer_common/sanitizer_mac.h"
+
+// Similar code is used in Google Perftools,
+// http://code.google.com/p/google-perftools.
+
+// ---------------------- Replacement functions ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// TODO(glider): do we need both zones?
+static malloc_zone_t *system_malloc_zone = 0;
+static malloc_zone_t asan_zone;
+
+INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
+ vm_size_t start_size, unsigned zone_flags) {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ uptr page_size = GetPageSizeCached();
+ uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
+ malloc_zone_t *new_zone =
+ (malloc_zone_t*)asan_memalign(page_size, allocated_size,
+ &stack, FROM_MALLOC);
+ internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
+ new_zone->zone_name = NULL; // The name will be changed anyway.
+ if (GetMacosVersion() >= MACOS_VERSION_LION) {
+ // Prevent the client app from overwriting the zone contents.
+ // Library functions that need to modify the zone will set PROT_WRITE on it.
+ // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
+ mprotect(new_zone, allocated_size, PROT_READ);
+ }
+ return new_zone;
+}
+
+INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
+ ENSURE_ASAN_INITED();
+ return &asan_zone;
+}
+
+INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
+ // FIXME: ASan should support purgeable allocations.
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=139
+ ENSURE_ASAN_INITED();
+ return &asan_zone;
+}
+
+INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
+ // FIXME: ASan should support purgeable allocations. Ignoring them is fine
+ // for now.
+ ENSURE_ASAN_INITED();
+}
+
+INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
+ // FIXME: ASan should support purgeable allocations. Ignoring them is fine
+ // for now.
+ ENSURE_ASAN_INITED();
+ // Must return 0 if the contents were not purged since the last call to
+ // malloc_make_purgeable().
+ return 0;
+}
+
+INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
+ ENSURE_ASAN_INITED();
+ // Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
+ size_t buflen = 6 + (name ? internal_strlen(name) : 0);
+ InternalScopedString new_name(buflen);
+ if (name && zone->introspect == asan_zone.introspect) {
+ new_name.append("asan-%s", name);
+ name = new_name.data();
+ }
+
+ // Call the system malloc's implementation for both external and our zones,
+ // since that appropriately changes VM region protections on the zone.
+ REAL(malloc_set_zone_name)(zone, name);
+}
+
+INTERCEPTOR(void *, malloc, size_t size) {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ void *res = asan_malloc(size, &stack);
+ return res;
+}
+
+INTERCEPTOR(void, free, void *ptr) {
+ ENSURE_ASAN_INITED();
+ if (!ptr) return;
+ GET_STACK_TRACE_FREE;
+ asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ return asan_realloc(ptr, size, &stack);
+}
+
+INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ return asan_calloc(nmemb, size, &stack);
+}
+
+INTERCEPTOR(void *, valloc, size_t size) {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(size_t, malloc_good_size, size_t size) {
+ ENSURE_ASAN_INITED();
+ return asan_zone.introspect->good_size(&asan_zone, size);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
+ ENSURE_ASAN_INITED();
+ CHECK(memptr);
+ GET_STACK_TRACE_MALLOC;
+ void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
+ if (result) {
+ *memptr = result;
+ return 0;
+ }
+ return -1;
+}
+
+namespace {
+
+// TODO(glider): the __asan_mz_* functions should be united with the Linux
+// wrappers, as they are basically copied from there.
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+size_t __asan_mz_size(malloc_zone_t* zone, const void* ptr) {
+ return asan_mz_size(ptr);
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_mz_malloc(malloc_zone_t *zone, uptr size) {
+ if (UNLIKELY(!asan_inited)) {
+ CHECK(system_malloc_zone);
+ return malloc_zone_malloc(system_malloc_zone, size);
+ }
+ GET_STACK_TRACE_MALLOC;
+ return asan_malloc(size, &stack);
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
+ if (UNLIKELY(!asan_inited)) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const size_t kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static size_t allocated;
+ size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ GET_STACK_TRACE_MALLOC;
+ return asan_calloc(nmemb, size, &stack);
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_mz_valloc(malloc_zone_t *zone, size_t size) {
+ if (UNLIKELY(!asan_inited)) {
+ CHECK(system_malloc_zone);
+ return malloc_zone_valloc(system_malloc_zone, size);
+ }
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
+}
+
+#define GET_ZONE_FOR_PTR(ptr) \
+ malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
+ const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
+
+void ALWAYS_INLINE free_common(void *context, void *ptr) {
+ if (!ptr) return;
+ GET_STACK_TRACE_FREE;
+ // FIXME: need to retire this flag.
+ if (!flags()->mac_ignore_invalid_free) {
+ asan_free(ptr, &stack, FROM_MALLOC);
+ } else {
+ GET_ZONE_FOR_PTR(ptr);
+ WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
+ return;
+ }
+}
+
+// TODO(glider): the allocation callbacks need to be refactored.
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_mz_free(malloc_zone_t *zone, void *ptr) {
+ free_common(zone, ptr);
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
+ if (!ptr) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_malloc(size, &stack);
+ } else {
+ if (asan_mz_size(ptr)) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_realloc(ptr, size, &stack);
+ } else {
+ // We can't recover from reallocating an unknown address, because
+ // this would require reading at most |size| bytes from
+ // potentially unaccessible memory.
+ GET_STACK_TRACE_FREE;
+ GET_ZONE_FOR_PTR(ptr);
+ ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
+ }
+ }
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_mz_destroy(malloc_zone_t* zone) {
+ // A no-op -- we will not be destroyed!
+ Report("__asan_mz_destroy() called -- ignoring\n");
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
+ if (UNLIKELY(!asan_inited)) {
+ CHECK(system_malloc_zone);
+ return malloc_zone_memalign(system_malloc_zone, align, size);
+ }
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(align, size, &stack, FROM_MALLOC);
+}
+
+// This function is currently unused, and we build with -Werror.
+#if 0
+void __asan_mz_free_definite_size(
+ malloc_zone_t* zone, void *ptr, size_t size) {
+ // TODO(glider): check that |size| is valid.
+ UNIMPLEMENTED();
+}
+#endif
+
+kern_return_t mi_enumerator(task_t task, void *,
+ unsigned type_mask, vm_address_t zone_address,
+ memory_reader_t reader,
+ vm_range_recorder_t recorder) {
+ // Should enumerate all the pointers we have. Seems like a lot of work.
+ return KERN_FAILURE;
+}
+
+size_t mi_good_size(malloc_zone_t *zone, size_t size) {
+ // I think it's always safe to return size, but we maybe could do better.
+ return size;
+}
+
+boolean_t mi_check(malloc_zone_t *zone) {
+ UNIMPLEMENTED();
+}
+
+void mi_print(malloc_zone_t *zone, boolean_t verbose) {
+ UNIMPLEMENTED();
+}
+
+void mi_log(malloc_zone_t *zone, void *address) {
+ // I don't think we support anything like this
+}
+
+void mi_force_lock(malloc_zone_t *zone) {
+ asan_mz_force_lock();
+}
+
+void mi_force_unlock(malloc_zone_t *zone) {
+ asan_mz_force_unlock();
+}
+
+void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
+ AsanMallocStats malloc_stats;
+ FillMallocStatistics(&malloc_stats);
+ CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
+ internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
+}
+
+boolean_t mi_zone_locked(malloc_zone_t *zone) {
+ // UNIMPLEMENTED();
+ return false;
+}
+
+} // unnamed namespace
+
+namespace __asan {
+
+void ReplaceSystemMalloc() {
+ static malloc_introspection_t asan_introspection;
+ // Ok to use internal_memset, these places are not performance-critical.
+ internal_memset(&asan_introspection, 0, sizeof(asan_introspection));
+
+ asan_introspection.enumerator = &mi_enumerator;
+ asan_introspection.good_size = &mi_good_size;
+ asan_introspection.check = &mi_check;
+ asan_introspection.print = &mi_print;
+ asan_introspection.log = &mi_log;
+ asan_introspection.force_lock = &mi_force_lock;
+ asan_introspection.force_unlock = &mi_force_unlock;
+ asan_introspection.statistics = &mi_statistics;
+ asan_introspection.zone_locked = &mi_zone_locked;
+
+ internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));
+
+ // Use version 6 for OSX >= 10.6.
+ asan_zone.version = 6;
+ asan_zone.zone_name = "asan";
+ asan_zone.size = &__asan_mz_size;
+ asan_zone.malloc = &__asan_mz_malloc;
+ asan_zone.calloc = &__asan_mz_calloc;
+ asan_zone.valloc = &__asan_mz_valloc;
+ asan_zone.free = &__asan_mz_free;
+ asan_zone.realloc = &__asan_mz_realloc;
+ asan_zone.destroy = &__asan_mz_destroy;
+ asan_zone.batch_malloc = 0;
+ asan_zone.batch_free = 0;
+ asan_zone.free_definite_size = 0;
+ asan_zone.memalign = &__asan_mz_memalign;
+ asan_zone.introspect = &asan_introspection;
+
+ // Register the ASan zone.
+ malloc_zone_register(&asan_zone);
+}
+} // namespace __asan
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_win.cc b/contrib/compiler-rt/lib/asan/asan_malloc_win.cc
new file mode 100644
index 000000000000..c99e31234951
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_malloc_win.cc
@@ -0,0 +1,178 @@
+//===-- asan_malloc_win.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.
+//
+// Windows-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "interception/interception.h"
+
+#include <stddef.h>
+
+using namespace __asan; // NOLINT
+
+// MT: Simply defining functions with the same signature in *.obj
+// files overrides the standard functions in the CRT.
+// MD: Memory allocation functions are defined in the CRT .dll,
+// so we have to intercept them before they are called for the first time.
+
+#if ASAN_DYNAMIC
+# define ALLOCATION_FUNCTION_ATTRIBUTE
+#else
+# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#endif
+
+extern "C" {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void free(void *ptr) {
+ GET_STACK_TRACE_FREE;
+ return asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void _free_dbg(void *ptr, int) {
+ free(ptr);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void cfree(void *ptr) {
+ CHECK(!"cfree() should not be used on Windows");
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *malloc(size_t size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_malloc(size, &stack);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_malloc_dbg(size_t size, int, const char *, int) {
+ return malloc(size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *calloc(size_t nmemb, size_t size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_calloc(nmemb, size, &stack);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
+ return calloc(nmemb, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
+ return calloc(nmemb, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *realloc(void *ptr, size_t size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_realloc(ptr, size, &stack);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_realloc_dbg(void *ptr, size_t size, int) {
+ CHECK(!"_realloc_dbg should not exist!");
+ return 0;
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_recalloc(void *p, size_t n, size_t elem_size) {
+ if (!p)
+ return calloc(n, elem_size);
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n)
+ return 0;
+ return realloc(p, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+size_t _msize(void *ptr) {
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand(void *memblock, size_t size) {
+ // _expand is used in realloc-like functions to resize the buffer if possible.
+ // We don't want memory to stand still while resizing buffers, so return 0.
+ return 0;
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand_dbg(void *memblock, size_t size) {
+ return _expand(memblock, size);
+}
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
+int _CrtDbgReport(int, const char*, int,
+ const char*, const char*, ...) {
+ ShowStatsAndAbort();
+}
+
+int _CrtDbgReportW(int reportType, const wchar_t*, int,
+ const wchar_t*, const wchar_t*, ...) {
+ ShowStatsAndAbort();
+}
+
+int _CrtSetReportMode(int, int) {
+ return 0;
+}
+} // extern "C"
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+#if defined(ASAN_DYNAMIC)
+ // We don't check the result because CRT might not be used in the process.
+ __interception::OverrideFunction("free", (uptr)free);
+ __interception::OverrideFunction("malloc", (uptr)malloc);
+ __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
+ __interception::OverrideFunction("calloc", (uptr)calloc);
+ __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
+ __interception::OverrideFunction("realloc", (uptr)realloc);
+ __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
+ __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
+ __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
+ __interception::OverrideFunction("_msize", (uptr)_msize);
+ __interception::OverrideFunction("_expand", (uptr)_expand);
+
+ // Override different versions of 'operator new' and 'operator delete'.
+ // No need to override the nothrow versions as they just wrap the throw
+ // versions.
+ // FIXME: Unfortunately, MSVC miscompiles the statements that take the
+ // addresses of the array versions of these operators,
+ // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
+ // We might want to try to work around this by [inline] assembly or compiling
+ // parts of the RTL with Clang.
+ void *(*op_new)(size_t sz) = operator new;
+ void (*op_delete)(void *p) = operator delete;
+ void *(*op_array_new)(size_t sz) = operator new[];
+ void (*op_array_delete)(void *p) = operator delete[];
+ __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
+ __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
+ __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
+ __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
+#endif
+}
+} // namespace __asan
+
+#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/asan/asan_mapping.h b/contrib/compiler-rt/lib/asan/asan_mapping.h
new file mode 100644
index 000000000000..5cb011d683d3
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_mapping.h
@@ -0,0 +1,288 @@
+//===-- 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.
+//
+// Defines ASan memory mapping.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_MAPPING_H
+#define ASAN_MAPPING_H
+
+#include "asan_internal.h"
+
+// The full explanation of the memory mapping could be found here:
+// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
+//
+// Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000:
+// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
+// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
+// || `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap ||
+// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
+// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
+//
+// When SHADOW_OFFSET is zero (-pie):
+// || `[0x100000000000, 0x7fffffffffff]` || HighMem ||
+// || `[0x020000000000, 0x0fffffffffff]` || HighShadow ||
+// || `[0x000000040000, 0x01ffffffffff]` || ShadowGap ||
+//
+// Special case when something is already mapped between
+// 0x003000000000 and 0x005000000000 (e.g. when prelink is installed):
+// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
+// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
+// || `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 ||
+// || `[0x003000000000, 0x004fffffffff]` || MidMem ||
+// || `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 ||
+// || `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow ||
+// || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap ||
+// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
+// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
+//
+// Default Linux/i386 mapping on x86_64 machine:
+// || `[0x40000000, 0xffffffff]` || HighMem ||
+// || `[0x28000000, 0x3fffffff]` || HighShadow ||
+// || `[0x24000000, 0x27ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
+// Default Linux/i386 mapping on i386 machine
+// (addresses starting with 0xc0000000 are reserved
+// for kernel and thus not sanitized):
+// || `[0x38000000, 0xbfffffff]` || HighMem ||
+// || `[0x27000000, 0x37ffffff]` || HighShadow ||
+// || `[0x24000000, 0x26ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
+// Default Linux/MIPS32 mapping:
+// || `[0x2aaa0000, 0xffffffff]` || HighMem ||
+// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
+// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap ||
+// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow ||
+// || `[0x00000000, 0x0aa9ffff]` || LowMem ||
+//
+// Default Linux/MIPS64 mapping:
+// || `[0x4000000000, 0xffffffffff]` || HighMem ||
+// || `[0x2800000000, 0x3fffffffff]` || HighShadow ||
+// || `[0x2400000000, 0x27ffffffff]` || ShadowGap ||
+// || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
+// || `[0x0000000000, 0x1fffffffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
+// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
+// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
+// || `[0x480000000000, 0x49ffffffffff]` || ShadowGap ||
+// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
+// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/i386 with SHADOW_OFFSET == 0x40000000:
+// || `[0x60000000, 0xffffffff]` || HighMem ||
+// || `[0x4c000000, 0x5fffffff]` || HighShadow ||
+// || `[0x48000000, 0x4bffffff]` || ShadowGap ||
+// || `[0x40000000, 0x47ffffff]` || LowShadow ||
+// || `[0x00000000, 0x3fffffff]` || LowMem ||
+//
+// Default Windows/i386 mapping:
+// (the exact location of HighShadow/HighMem may vary depending
+// on WoW64, /LARGEADDRESSAWARE, etc).
+// || `[0x50000000, 0xffffffff]` || HighMem ||
+// || `[0x3a000000, 0x4fffffff]` || HighShadow ||
+// || `[0x36000000, 0x39ffffff]` || ShadowGap ||
+// || `[0x30000000, 0x35ffffff]` || LowShadow ||
+// || `[0x00000000, 0x2fffffff]` || LowMem ||
+
+static const u64 kDefaultShadowScale = 3;
+static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
+static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
+static const u64 kDefaultShadowOffset64 = 1ULL << 44;
+static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
+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 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
+static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
+static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
+
+#define SHADOW_SCALE kDefaultShadowScale
+#if SANITIZER_ANDROID
+# define SHADOW_OFFSET (0)
+#else
+# if SANITIZER_WORDSIZE == 32
+# if defined(__mips__)
+# define SHADOW_OFFSET kMIPS32_ShadowOffset32
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
+# elif SANITIZER_IOS
+# define SHADOW_OFFSET kIosShadowOffset32
+# elif SANITIZER_WINDOWS
+# define SHADOW_OFFSET kWindowsShadowOffset32
+# else
+# define SHADOW_OFFSET kDefaultShadowOffset32
+# endif
+# else
+# if defined(__aarch64__)
+# define SHADOW_OFFSET kAArch64_ShadowOffset64
+# elif defined(__powerpc64__)
+# define SHADOW_OFFSET kPPC64_ShadowOffset64
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
+# elif SANITIZER_MAC
+# define SHADOW_OFFSET kDefaultShadowOffset64
+# elif defined(__mips64)
+# define SHADOW_OFFSET kMIPS64_ShadowOffset64
+# else
+# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
+# endif
+# endif
+#endif
+
+#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
+#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
+#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
+
+#define kLowMemBeg 0
+#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
+
+#define kLowShadowBeg SHADOW_OFFSET
+#define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd)
+
+#define kHighMemBeg (MEM_TO_SHADOW(kHighMemEnd) + 1)
+
+#define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg)
+#define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd)
+
+# define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg)
+# define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd)
+
+// With the zero shadow base we can not actually map pages starting from 0.
+// This constant is somewhat arbitrary.
+#define kZeroBaseShadowStart (1 << 18)
+
+#define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 \
+ : kZeroBaseShadowStart)
+#define kShadowGapEnd ((kMidMemBeg ? kMidShadowBeg : kHighShadowBeg) - 1)
+
+#define kShadowGap2Beg (kMidMemBeg ? kMidShadowEnd + 1 : 0)
+#define kShadowGap2End (kMidMemBeg ? kMidMemBeg - 1 : 0)
+
+#define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0)
+#define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0)
+
+#define DO_ASAN_MAPPING_PROFILE 0 // Set to 1 to profile the functions below.
+
+#if DO_ASAN_MAPPING_PROFILE
+# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++;
+#else
+# define PROFILE_ASAN_MAPPING()
+#endif
+
+// If 1, all shadow boundaries are constants.
+// Don't set to 1 other than for testing.
+#define ASAN_FIXED_MAPPING 0
+
+namespace __asan {
+
+extern uptr AsanMappingProfile[];
+
+#if ASAN_FIXED_MAPPING
+// Fixed mapping for 64-bit Linux. Mostly used for performance comparison
+// with non-fixed mapping. As of r175253 (Feb 2013) the performance
+// difference between fixed and non-fixed mapping is below the noise level.
+static uptr kHighMemEnd = 0x7fffffffffffULL;
+static uptr kMidMemBeg = 0x3000000000ULL;
+static uptr kMidMemEnd = 0x4fffffffffULL;
+#else
+extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.
+#endif
+
+static inline bool AddrIsInLowMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a < kLowMemEnd;
+}
+
+static inline bool AddrIsInLowShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a >= kLowShadowBeg && a <= kLowShadowEnd;
+}
+
+static inline bool AddrIsInHighMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a >= kHighMemBeg && a <= kHighMemEnd;
+}
+
+static inline bool AddrIsInMidMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd;
+}
+
+static inline bool AddrIsInMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a);
+}
+
+static inline uptr MemToShadow(uptr p) {
+ PROFILE_ASAN_MAPPING();
+ CHECK(AddrIsInMem(p));
+ return MEM_TO_SHADOW(p);
+}
+
+static inline bool AddrIsInHighShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a >= kHighShadowBeg && a <= kHighMemEnd;
+}
+
+static inline bool AddrIsInMidShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd;
+}
+
+static inline bool AddrIsInShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a);
+}
+
+static inline bool AddrIsInShadowGap(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ if (kMidMemBeg) {
+ if (a <= kShadowGapEnd)
+ return SHADOW_OFFSET == 0 || a >= kShadowGapBeg;
+ return (a >= kShadowGap2Beg && a <= kShadowGap2End) ||
+ (a >= kShadowGap3Beg && a <= kShadowGap3End);
+ }
+ // In zero-based shadow mode we treat addresses near zero as addresses
+ // in shadow gap as well.
+ if (SHADOW_OFFSET == 0)
+ return a <= kShadowGapEnd;
+ return a >= kShadowGapBeg && a <= kShadowGapEnd;
+}
+
+static inline bool AddrIsAlignedByGranularity(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return (a & (SHADOW_GRANULARITY - 1)) == 0;
+}
+
+static inline bool AddressIsPoisoned(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ const uptr kAccessSize = 1;
+ u8 *shadow_address = (u8*)MEM_TO_SHADOW(a);
+ s8 shadow_value = *shadow_address;
+ if (shadow_value) {
+ u8 last_accessed_byte = (a & (SHADOW_GRANULARITY - 1))
+ + kAccessSize - 1;
+ return (last_accessed_byte >= shadow_value);
+ }
+ return false;
+}
+
+// Must be after all calls to PROFILE_ASAN_MAPPING().
+static const uptr kAsanMappingProfileSize = __LINE__;
+
+} // namespace __asan
+
+#endif // ASAN_MAPPING_H
diff --git a/contrib/compiler-rt/lib/asan/asan_new_delete.cc b/contrib/compiler-rt/lib/asan/asan_new_delete.cc
new file mode 100644
index 000000000000..e48bdaf03dd3
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_new_delete.cc
@@ -0,0 +1,132 @@
+//===-- asan_interceptors.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.
+//
+// Interceptors for operators new and delete.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+
+#include "interception/interception.h"
+
+#include <stddef.h>
+
+// C++ operators can't have visibility attributes on Windows.
+#if SANITIZER_WINDOWS
+# define CXX_OPERATOR_ATTRIBUTE
+#else
+# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
+#endif
+
+using namespace __asan; // NOLINT
+
+// This code has issues on OSX.
+// See https://code.google.com/p/address-sanitizer/issues/detail?id=131.
+
+// Fake std::nothrow_t to avoid including <new>.
+namespace std {
+struct nothrow_t {};
+} // namespace std
+
+#define OPERATOR_NEW_BODY(type) \
+ GET_STACK_TRACE_MALLOC;\
+ return asan_memalign(0, size, &stack, type);
+
+// On OS X it's not enough to just provide our own 'operator new' and
+// 'operator delete' implementations, because they're going to be in the
+// runtime dylib, and the main executable will depend on both the runtime
+// dylib and libstdc++, each of those'll have its implementation of new and
+// delete.
+// To make sure that C++ allocation/deallocation operators are overridden on
+// OS X we need to intercept them using their mangled names.
+#if !SANITIZER_MAC
+// FreeBSD prior v9.2 have wrong definition of 'size_t'.
+// http://svnweb.freebsd.org/base?view=revision&revision=232261
+#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+#include <sys/param.h>
+#if __FreeBSD_version <= 902001 // v9.2
+#define size_t unsigned
+#endif // __FreeBSD_version
+#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(FROM_NEW); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
+
+#else // SANITIZER_MAC
+INTERCEPTOR(void *, _Znwm, size_t size) {
+ OPERATOR_NEW_BODY(FROM_NEW);
+}
+INTERCEPTOR(void *, _Znam, size_t size) {
+ OPERATOR_NEW_BODY(FROM_NEW_BR);
+}
+INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
+ OPERATOR_NEW_BODY(FROM_NEW);
+}
+INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
+ OPERATOR_NEW_BODY(FROM_NEW_BR);
+}
+#endif
+
+#define OPERATOR_DELETE_BODY(type) \
+ GET_STACK_TRACE_FREE;\
+ asan_free(ptr, &stack, type);
+
+#if !SANITIZER_MAC
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr) throw() {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+CXX_OPERATOR_ATTRIBUTE
+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);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size) throw() {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) throw() {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, 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
diff --git a/contrib/compiler-rt/lib/asan/asan_poisoning.cc b/contrib/compiler-rt/lib/asan/asan_poisoning.cc
new file mode 100644
index 000000000000..e2b1f4dc4d5e
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_poisoning.cc
@@ -0,0 +1,427 @@
+//===-- asan_poisoning.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.
+//
+// Shadow memory poisoning by ASan RTL and by user application.
+//===----------------------------------------------------------------------===//
+
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+static atomic_uint8_t can_poison_memory;
+
+void SetCanPoisonMemory(bool value) {
+ atomic_store(&can_poison_memory, value, memory_order_release);
+}
+
+bool CanPoisonMemory() {
+ return atomic_load(&can_poison_memory, memory_order_acquire);
+}
+
+void PoisonShadow(uptr addr, uptr size, u8 value) {
+ if (!CanPoisonMemory()) return;
+ CHECK(AddrIsAlignedByGranularity(addr));
+ CHECK(AddrIsInMem(addr));
+ CHECK(AddrIsAlignedByGranularity(addr + size));
+ CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
+ CHECK(REAL(memset));
+ FastPoisonShadow(addr, size, value);
+}
+
+void PoisonShadowPartialRightRedzone(uptr addr,
+ uptr size,
+ uptr redzone_size,
+ u8 value) {
+ if (!CanPoisonMemory()) return;
+ CHECK(AddrIsAlignedByGranularity(addr));
+ CHECK(AddrIsInMem(addr));
+ FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value);
+}
+
+struct ShadowSegmentEndpoint {
+ u8 *chunk;
+ s8 offset; // in [0, SHADOW_GRANULARITY)
+ s8 value; // = *chunk;
+
+ explicit ShadowSegmentEndpoint(uptr address) {
+ chunk = (u8*)MemToShadow(address);
+ offset = address & (SHADOW_GRANULARITY - 1);
+ value = *chunk;
+ }
+};
+
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+ // Since asan's mapping is compacting, the shadow chunk may be
+ // not page-aligned, so we only flush the page-aligned portion.
+ uptr page_size = GetPageSizeCached();
+ uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
+ uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
+ FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+}
+
+void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
+ uptr end = ptr + size;
+ if (Verbosity()) {
+ Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
+ poison ? "" : "un", ptr, end, size);
+ if (Verbosity() >= 2)
+ PRINT_CURRENT_STACK();
+ }
+ CHECK(size);
+ CHECK_LE(size, 4096);
+ CHECK(IsAligned(end, SHADOW_GRANULARITY));
+ if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
+ *(u8 *)MemToShadow(ptr) =
+ poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
+ ptr |= SHADOW_GRANULARITY - 1;
+ ptr++;
+ }
+ for (; ptr < end; ptr += SHADOW_GRANULARITY)
+ *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// Current implementation of __asan_(un)poison_memory_region doesn't check
+// that user program (un)poisons the memory it owns. It poisons memory
+// conservatively, and unpoisons progressively to make sure asan shadow
+// mapping invariant is preserved (see detailed mapping description here:
+// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm).
+//
+// * if user asks to poison region [left, right), the program poisons
+// at least [left, AlignDown(right)).
+// * if user asks to unpoison region [left, right), the program unpoisons
+// at most [AlignDown(left), right).
+void __asan_poison_memory_region(void const volatile *addr, uptr size) {
+ if (!flags()->allow_user_poisoning || size == 0) return;
+ uptr beg_addr = (uptr)addr;
+ uptr end_addr = beg_addr + size;
+ VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
+ ShadowSegmentEndpoint beg(beg_addr);
+ ShadowSegmentEndpoint end(end_addr);
+ if (beg.chunk == end.chunk) {
+ CHECK(beg.offset < end.offset);
+ s8 value = beg.value;
+ CHECK(value == end.value);
+ // We can only poison memory if the byte in end.offset is unaddressable.
+ // No need to re-poison memory if it is poisoned already.
+ if (value > 0 && value <= end.offset) {
+ if (beg.offset > 0) {
+ *beg.chunk = Min(value, beg.offset);
+ } else {
+ *beg.chunk = kAsanUserPoisonedMemoryMagic;
+ }
+ }
+ return;
+ }
+ CHECK(beg.chunk < end.chunk);
+ if (beg.offset > 0) {
+ // Mark bytes from beg.offset as unaddressable.
+ if (beg.value == 0) {
+ *beg.chunk = beg.offset;
+ } else {
+ *beg.chunk = Min(beg.value, beg.offset);
+ }
+ beg.chunk++;
+ }
+ REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk);
+ // Poison if byte in end.offset is unaddressable.
+ if (end.value > 0 && end.value <= end.offset) {
+ *end.chunk = kAsanUserPoisonedMemoryMagic;
+ }
+}
+
+void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
+ if (!flags()->allow_user_poisoning || size == 0) return;
+ uptr beg_addr = (uptr)addr;
+ uptr end_addr = beg_addr + size;
+ VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
+ ShadowSegmentEndpoint beg(beg_addr);
+ ShadowSegmentEndpoint end(end_addr);
+ if (beg.chunk == end.chunk) {
+ CHECK(beg.offset < end.offset);
+ s8 value = beg.value;
+ CHECK(value == end.value);
+ // We unpoison memory bytes up to enbytes up to end.offset if it is not
+ // unpoisoned already.
+ if (value != 0) {
+ *beg.chunk = Max(value, end.offset);
+ }
+ return;
+ }
+ CHECK(beg.chunk < end.chunk);
+ if (beg.offset > 0) {
+ *beg.chunk = 0;
+ beg.chunk++;
+ }
+ REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk);
+ if (end.offset > 0 && end.value != 0) {
+ *end.chunk = Max(end.value, end.offset);
+ }
+}
+
+int __asan_address_is_poisoned(void const volatile *addr) {
+ return __asan::AddressIsPoisoned((uptr)addr);
+}
+
+uptr __asan_region_is_poisoned(uptr beg, uptr size) {
+ if (!size) return 0;
+ uptr end = beg + size;
+ if (!AddrIsInMem(beg)) return beg;
+ if (!AddrIsInMem(end)) return end;
+ CHECK_LT(beg, end);
+ uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);
+ uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY);
+ uptr shadow_beg = MemToShadow(aligned_b);
+ uptr shadow_end = MemToShadow(aligned_e);
+ // First check the first and the last application bytes,
+ // then check the SHADOW_GRANULARITY-aligned region by calling
+ // mem_is_zero on the corresponding shadow.
+ if (!__asan::AddressIsPoisoned(beg) &&
+ !__asan::AddressIsPoisoned(end - 1) &&
+ (shadow_end <= shadow_beg ||
+ __sanitizer::mem_is_zero((const char *)shadow_beg,
+ shadow_end - shadow_beg)))
+ return 0;
+ // The fast check failed, so we have a poisoned byte somewhere.
+ // Find it slowly.
+ for (; beg < end; beg++)
+ if (__asan::AddressIsPoisoned(beg))
+ return beg;
+ UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found");
+ return 0;
+}
+
+#define CHECK_SMALL_REGION(p, size, isWrite) \
+ do { \
+ uptr __p = reinterpret_cast<uptr>(p); \
+ uptr __size = size; \
+ if (UNLIKELY(__asan::AddressIsPoisoned(__p) || \
+ __asan::AddressIsPoisoned(__p + __size - 1))) { \
+ GET_CURRENT_PC_BP_SP; \
+ uptr __bad = __asan_region_is_poisoned(__p, __size); \
+ __asan_report_error(pc, bp, sp, __bad, isWrite, __size);\
+ } \
+ } while (false); \
+
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+ CHECK_SMALL_REGION(p, sizeof(*p), false);
+ return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+ CHECK_SMALL_REGION(p, sizeof(*p), false);
+ return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+ CHECK_SMALL_REGION(p, sizeof(*p), false);
+ return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+ CHECK_SMALL_REGION(p, sizeof(*p), true);
+ *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+ CHECK_SMALL_REGION(p, sizeof(*p), true);
+ *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+ CHECK_SMALL_REGION(p, sizeof(*p), true);
+ *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_cxx_array_cookie(uptr p) {
+ if (SANITIZER_WORDSIZE != 64) return;
+ if (!flags()->poison_array_cookie) return;
+ uptr s = MEM_TO_SHADOW(p);
+ *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_load_cxx_array_cookie(uptr *p) {
+ if (SANITIZER_WORDSIZE != 64) return *p;
+ if (!flags()->poison_array_cookie) return *p;
+ uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
+ u8 sval = *reinterpret_cast<u8*>(s);
+ if (sval == kAsanArrayCookieMagic) return *p;
+ // If sval is not kAsanArrayCookieMagic it can only be freed memory,
+ // which means that we are going to get double-free. So, return 0 to avoid
+ // infinite loop of destructors. We don't want to report a double-free here
+ // though, so print a warning just in case.
+ // CHECK_EQ(sval, kAsanHeapFreeMagic);
+ if (sval == kAsanHeapFreeMagic) {
+ Report("AddressSanitizer: loaded array cookie from free-d memory; "
+ "expect a double-free report\n");
+ return 0;
+ }
+ // The cookie may remain unpoisoned if e.g. it comes from a custom
+ // operator new defined inside a class.
+ return *p;
+}
+
+// This is a simplified version of __asan_(un)poison_memory_region, which
+// assumes that left border of region to be poisoned is properly aligned.
+static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
+ if (size == 0) return;
+ uptr aligned_size = size & ~(SHADOW_GRANULARITY - 1);
+ PoisonShadow(addr, aligned_size,
+ do_poison ? kAsanStackUseAfterScopeMagic : 0);
+ if (size == aligned_size)
+ return;
+ s8 end_offset = (s8)(size - aligned_size);
+ s8* shadow_end = (s8*)MemToShadow(addr + aligned_size);
+ s8 end_value = *shadow_end;
+ if (do_poison) {
+ // If possible, mark all the bytes mapping to last shadow byte as
+ // unaddressable.
+ if (end_value > 0 && end_value <= end_offset)
+ *shadow_end = (s8)kAsanStackUseAfterScopeMagic;
+ } else {
+ // If necessary, mark few first bytes mapping to last shadow byte
+ // as addressable
+ if (end_value != 0)
+ *shadow_end = Max(end_value, end_offset);
+ }
+}
+
+void __asan_poison_stack_memory(uptr addr, uptr size) {
+ VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
+ PoisonAlignedStackMemory(addr, size, true);
+}
+
+void __asan_unpoison_stack_memory(uptr addr, uptr size) {
+ VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size);
+ PoisonAlignedStackMemory(addr, size, false);
+}
+
+void __sanitizer_annotate_contiguous_container(const void *beg_p,
+ const void *end_p,
+ const void *old_mid_p,
+ const void *new_mid_p) {
+ if (!flags()->detect_container_overflow) return;
+ VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+ new_mid_p);
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
+ uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
+ uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
+ uptr granularity = SHADOW_GRANULARITY;
+ if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
+ IsAligned(beg, granularity))) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
+ &stack);
+ }
+ CHECK_LE(end - beg,
+ FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
+
+ uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
+ uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
+ uptr d1 = RoundDownTo(old_mid, granularity);
+ // uptr d2 = RoundUpTo(old_mid, granularity);
+ // Currently we should be in this state:
+ // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
+ // Make a quick sanity check that we are indeed in this state.
+ //
+ // FIXME: Two of these three checks are disabled until we fix
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=258.
+ // if (d1 != d2)
+ // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
+ if (a + granularity <= d1)
+ CHECK_EQ(*(u8*)MemToShadow(a), 0);
+ // if (d2 + granularity <= c && c <= end)
+ // CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
+ // kAsanContiguousContainerOOBMagic);
+
+ uptr b1 = RoundDownTo(new_mid, granularity);
+ uptr b2 = RoundUpTo(new_mid, granularity);
+ // New state:
+ // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
+ PoisonShadow(a, b1 - a, 0);
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
+ if (b1 != b2) {
+ CHECK_EQ(b2 - b1, granularity);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
+ }
+}
+
+int __sanitizer_verify_contiguous_container(const void *beg_p,
+ const void *mid_p,
+ const void *end_p) {
+ if (!flags()->detect_container_overflow) return 1;
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
+ uptr mid = reinterpret_cast<uptr>(mid_p);
+ CHECK_LE(beg, mid);
+ CHECK_LE(mid, end);
+ // Check some bytes starting from beg, some bytes around mid, and some bytes
+ // ending with end.
+ uptr kMaxRangeToCheck = 32;
+ uptr r1_beg = beg;
+ uptr r1_end = Min(end + kMaxRangeToCheck, mid);
+ uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
+ uptr r2_end = Min(end, mid + kMaxRangeToCheck);
+ uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
+ uptr r3_end = end;
+ for (uptr i = r1_beg; i < r1_end; i++)
+ if (AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = r2_beg; i < mid; i++)
+ if (AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = mid; i < r2_end; i++)
+ if (!AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = r3_beg; i < r3_end; i++)
+ if (!AddressIsPoisoned(i))
+ return 0;
+ return 1;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
+}
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool WordIsPoisoned(uptr addr) {
+ return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);
+}
+}
+
diff --git a/contrib/compiler-rt/lib/asan/asan_poisoning.h b/contrib/compiler-rt/lib/asan/asan_poisoning.h
new file mode 100644
index 000000000000..3fc94649fb39
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_poisoning.h
@@ -0,0 +1,93 @@
+//===-- asan_poisoning.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.
+//
+// Shadow memory poisoning by ASan RTL and by user application.
+//===----------------------------------------------------------------------===//
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+// Enable/disable memory poisoning.
+void SetCanPoisonMemory(bool value);
+bool CanPoisonMemory();
+
+// Poisons the shadow memory for "size" bytes starting from "addr".
+void PoisonShadow(uptr addr, uptr size, u8 value);
+
+// Poisons the shadow memory for "redzone_size" bytes starting from
+// "addr + size".
+void PoisonShadowPartialRightRedzone(uptr addr,
+ uptr size,
+ uptr redzone_size,
+ u8 value);
+
+// Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that
+// assume that memory addresses are properly aligned. Use in
+// performance-critical code with care.
+ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
+ u8 value) {
+ DCHECK(CanPoisonMemory());
+ uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
+ uptr shadow_end = MEM_TO_SHADOW(
+ aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
+ // FIXME: Page states are different on Windows, so using the same interface
+ // 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 ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_size = GetPageSizeCached();
+ uptr page_beg = RoundUpTo(shadow_beg, page_size);
+ uptr page_end = RoundDownTo(shadow_end, page_size);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ ReserveShadowMemoryRange(page_beg, page_end - 1);
+ }
+ }
+}
+
+ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
+ uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
+ DCHECK(CanPoisonMemory());
+ bool poison_partial = flags()->poison_partial;
+ u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
+ for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
+ if (i + SHADOW_GRANULARITY <= size) {
+ *shadow = 0; // fully addressable
+ } else if (i >= size) {
+ *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
+ } else {
+ // first size-i bytes are addressable
+ *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
+ }
+ }
+}
+
+// Calls __sanitizer::FlushUnneededShadowMemory() on
+// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
+void FlushUnneededASanShadowMemory(uptr p, uptr size);
+
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_posix.cc b/contrib/compiler-rt/lib/asan/asan_posix.cc
new file mode 100644
index 000000000000..ad31458df28d
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_posix.cc
@@ -0,0 +1,119 @@
+//===-- asan_posix.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.
+//
+// Posix-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_POSIX
+
+#include "asan_internal.h"
+#include "asan_interceptors.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+namespace __asan {
+
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
+ uptr pc, sp, bp;
+ GetPcSpBp(context, &pc, &sp, &bp);
+ return SignalContext(context, addr, pc, sp, bp);
+}
+
+void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+ ScopedDeadlySignal signal_scope(GetCurrentThread());
+ int code = (int)((siginfo_t*)siginfo)->si_code;
+ // Write the first message using the bullet-proof write.
+ if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
+ 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.
+ bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
+
+#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, becase 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
+ ReportSIGSEGV("SEGV", sig);
+}
+
+// ---------------------- TSD ---------------- {{{1
+
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_key_inited);
+ tsd_key_inited = true;
+ CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+}
+
+void *AsanTSDGet() {
+ CHECK(tsd_key_inited);
+ return pthread_getspecific(tsd_key);
+}
+
+void AsanTSDSet(void *tsd) {
+ CHECK(tsd_key_inited);
+ pthread_setspecific(tsd_key, tsd);
+}
+
+void PlatformTSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ if (context->destructor_iterations > 1) {
+ context->destructor_iterations--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ AsanThread::TSDDtor(tsd);
+}
+} // namespace __asan
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/asan/asan_preinit.cc b/contrib/compiler-rt/lib/asan/asan_preinit.cc
new file mode 100644
index 000000000000..a3986d24f9c3
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_preinit.cc
@@ -0,0 +1,25 @@
+//===-- asan_preinit.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.
+//
+// Call __asan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+#include "asan_internal.h"
+
+using namespace __asan;
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+ // The symbol is called __local_asan_preinit, because it's not intended to be
+ // exported.
+ // This code linked into the main executable when -fsanitize=address is in
+ // the link flags. It can only use exported interface functions.
+ __attribute__((section(".preinit_array"), used))
+ void (*__local_asan_preinit)(void) = __asan_init;
+#endif
diff --git a/contrib/compiler-rt/lib/asan/asan_report.cc b/contrib/compiler-rt/lib/asan/asan_report.cc
new file mode 100644
index 000000000000..8706d5decc0b
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_report.cc
@@ -0,0 +1,1090 @@
+//===-- asan_report.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.
+//
+// This file contains error reporting code.
+//===----------------------------------------------------------------------===//
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __asan {
+
+// -------------------- User-specified callbacks ----------------- {{{1
+static void (*error_report_callback)(const char*);
+static char *error_message_buffer = 0;
+static uptr error_message_buffer_pos = 0;
+static uptr error_message_buffer_size = 0;
+
+struct ReportData {
+ uptr pc;
+ uptr sp;
+ uptr bp;
+ uptr addr;
+ bool is_write;
+ uptr access_size;
+ const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
+void AppendToErrorMessageBuffer(const char *buffer) {
+ if (error_message_buffer) {
+ uptr length = internal_strlen(buffer);
+ CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
+ uptr remaining = error_message_buffer_size - error_message_buffer_pos;
+ internal_strncpy(error_message_buffer + error_message_buffer_pos,
+ buffer, remaining);
+ error_message_buffer[error_message_buffer_size - 1] = '\0';
+ // FIXME: reallocate the buffer instead of truncating the message.
+ error_message_buffer_pos += Min(remaining, length);
+ }
+}
+
+// ---------------------- Decorator ------------------------------ {{{1
+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) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
+ return Red();
+ case kAsanHeapFreeMagic:
+ return Magenta();
+ case kAsanStackLeftRedzoneMagic:
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ case kAsanStackPartialRedzoneMagic:
+ return Red();
+ case kAsanStackAfterReturnMagic:
+ return Magenta();
+ case kAsanInitializationOrderMagic:
+ return Cyan();
+ case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ return Blue();
+ case kAsanStackUseAfterScopeMagic:
+ return Magenta();
+ case kAsanGlobalRedzoneMagic:
+ return Red();
+ case kAsanInternalHeapMagic:
+ return Yellow();
+ case kAsanIntraObjectRedzone:
+ return Yellow();
+ default:
+ return Default();
+ }
+ }
+ const char *EndShadowByte() { return Default(); }
+ const char *MemoryByte() { return Magenta(); }
+ const char *EndMemoryByte() { return Default(); }
+};
+
+// ---------------------- Helper functions ----------------------- {{{1
+
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+ u8 byte, bool in_shadow, const char *after = "\n") {
+ 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);
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+ u8 byte, const char *after = "\n") {
+ PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
+}
+
+static void PrintShadowBytes(InternalScopedString *str, const char *before,
+ u8 *bytes, u8 *guilty, uptr n) {
+ Decorator d;
+ if (before) str->append("%s%p:", before, bytes);
+ for (uptr i = 0; i < n; i++) {
+ u8 *p = bytes + i;
+ const char *before =
+ p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
+ const char *after = p == guilty ? "]" : "";
+ PrintShadowByte(str, before, *p, after);
+ }
+ str->append("\n");
+}
+
+static void PrintLegend(InternalScopedString *str) {
+ str->append(
+ "Shadow byte legend (one shadow byte represents %d "
+ "application bytes):\n",
+ (int)SHADOW_GRANULARITY);
+ PrintShadowByte(str, " Addressable: ", 0);
+ str->append(" Partially addressable: ");
+ for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
+ str->append("\n");
+ PrintShadowByte(str, " Heap left redzone: ",
+ kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(str, " Heap right redzone: ",
+ kAsanHeapRightRedzoneMagic);
+ PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(str, " Stack left redzone: ",
+ kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(str, " Stack mid redzone: ",
+ kAsanStackMidRedzoneMagic);
+ PrintShadowByte(str, " Stack right redzone: ",
+ kAsanStackRightRedzoneMagic);
+ PrintShadowByte(str, " Stack partial redzone: ",
+ kAsanStackPartialRedzoneMagic);
+ PrintShadowByte(str, " Stack after return: ",
+ kAsanStackAfterReturnMagic);
+ PrintShadowByte(str, " Stack use after scope: ",
+ kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(str, " Global init order: ",
+ kAsanInitializationOrderMagic);
+ PrintShadowByte(str, " Poisoned by user: ",
+ kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(str, " Container overflow: ",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(str, " Array cookie: ",
+ kAsanArrayCookieMagic);
+ PrintShadowByte(str, " Intra object redzone: ",
+ kAsanIntraObjectRedzone);
+ PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
+ PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
+}
+
+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 PrintShadowMemoryForAddress(uptr addr) {
+ if (!AddrIsInMem(addr)) return;
+ uptr shadow_addr = MemToShadow(addr);
+ const uptr n_bytes_per_row = 16;
+ uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
+ InternalScopedString str(4096 * 8);
+ str.append("Shadow bytes around the buggy address:\n");
+ for (int i = -5; i <= 5; i++) {
+ const char *prefix = (i == 0) ? "=>" : " ";
+ PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
+ (u8 *)shadow_addr, n_bytes_per_row);
+ }
+ if (flags()->print_legend) PrintLegend(&str);
+ Printf("%s", str.data());
+}
+
+static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
+ const char *zone_name) {
+ if (zone_ptr) {
+ if (zone_name) {
+ Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
+ ptr, zone_ptr, zone_name);
+ } else {
+ Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
+ ptr, zone_ptr);
+ }
+ } else {
+ Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
+ }
+}
+
+static void DescribeThread(AsanThread *t) {
+ if (t)
+ DescribeThread(t->context());
+}
+
+// ---------------------- Address Descriptions ------------------- {{{1
+
+static bool IsASCII(unsigned char c) {
+ return /*0x00 <= c &&*/ c <= 0x7F;
+}
+
+static const char *MaybeDemangleGlobalName(const char *name) {
+ // We can spoil names of globals with C linkage, so use an heuristic
+ // approach to check if the name should be demangled.
+ bool should_demangle = false;
+ if (name[0] == '_' && name[1] == 'Z')
+ should_demangle = true;
+ else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
+ should_demangle = true;
+
+ return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
+}
+
+// Check if the global is a zero-terminated ASCII string. If so, print it.
+static void PrintGlobalNameIfASCII(InternalScopedString *str,
+ const __asan_global &g) {
+ for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
+ unsigned char c = *(unsigned char*)p;
+ if (c == '\0' || !IsASCII(c)) return;
+ }
+ if (*(char*)(g.beg + g.size - 1) != '\0') return;
+ str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
+ (char *)g.beg);
+}
+
+static const char *GlobalFilename(const __asan_global &g) {
+ const char *res = g.module_name;
+ // Prefer the filename from source location, if is available.
+ if (g.location)
+ res = g.location->filename;
+ CHECK(res);
+ return res;
+}
+
+static void PrintGlobalLocation(InternalScopedString *str,
+ const __asan_global &g) {
+ str->append("%s", GlobalFilename(g));
+ if (!g.location)
+ return;
+ if (g.location->line_no)
+ str->append(":%d", g.location->line_no);
+ if (g.location->column_no)
+ str->append(":%d", g.location->column_no);
+}
+
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
+ const __asan_global &g) {
+ if (!IsAddressNearGlobal(addr, g)) return false;
+ InternalScopedString str(4096);
+ Decorator d;
+ str.append("%s", d.Location());
+ if (addr < g.beg) {
+ str.append("%p is located %zd bytes to the left", (void *)addr,
+ g.beg - addr);
+ } else if (addr + size > g.beg + g.size) {
+ if (addr < g.beg + g.size)
+ addr = g.beg + g.size;
+ str.append("%p is located %zd bytes to the right", (void *)addr,
+ addr - (g.beg + g.size));
+ } else {
+ // Can it happen?
+ str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
+ }
+ str.append(" of global variable '%s' defined in '",
+ MaybeDemangleGlobalName(g.name));
+ PrintGlobalLocation(&str, g);
+ str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
+ str.append("%s", d.EndLocation());
+ PrintGlobalNameIfASCII(&str, g);
+ Printf("%s", str.data());
+ return true;
+}
+
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
+ if (AddrIsInMem(addr))
+ return false;
+ const char *area_type = nullptr;
+ if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
+ else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
+ else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
+ if (area_type != nullptr) {
+ if (print) {
+ Printf("Address %p is located in the %s area.\n", addr, area_type);
+ } else {
+ CHECK(descr);
+ descr->region_kind = area_type;
+ }
+ return true;
+ }
+ CHECK(0 && "Address is not in memory and not in shadow?");
+ return false;
+}
+
+// Return " (thread_name) " or an empty string if the name is empty.
+const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
+ uptr buff_len) {
+ const char *name = t->name;
+ if (name[0] == '\0') return "";
+ buff[0] = 0;
+ internal_strncat(buff, " (", 3);
+ internal_strncat(buff, name, buff_len - 4);
+ internal_strncat(buff, ")", 2);
+ return buff;
+}
+
+const char *ThreadNameWithParenthesis(u32 tid, char buff[],
+ uptr buff_len) {
+ if (tid == kInvalidTid) return "";
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *t = GetThreadContextByTidLocked(tid);
+ return ThreadNameWithParenthesis(t, buff, buff_len);
+}
+
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+ uptr access_size, uptr prev_var_end,
+ uptr next_var_beg) {
+ uptr var_end = var.beg + var.size;
+ uptr addr_end = addr + access_size;
+ const char *pos_descr = 0;
+ // If the variable [var.beg, var_end) is the nearest variable to the
+ // current memory access, indicate it in the log.
+ if (addr >= var.beg) {
+ if (addr_end <= var_end)
+ pos_descr = "is inside"; // May happen if this is a use-after-return.
+ else if (addr < var_end)
+ pos_descr = "partially overflows";
+ else if (addr_end <= next_var_beg &&
+ next_var_beg - addr_end >= addr - var_end)
+ pos_descr = "overflows";
+ } else {
+ if (addr_end > var.beg)
+ pos_descr = "partially underflows";
+ else if (addr >= prev_var_end &&
+ addr - prev_var_end >= var.beg - addr_end)
+ pos_descr = "underflows";
+ }
+ InternalScopedString str(1024);
+ str.append(" [%zd, %zd)", var.beg, var_end);
+ // Render variable name.
+ str.append(" '");
+ for (uptr i = 0; i < var.name_len; ++i) {
+ str.append("%c", var.name_pos[i]);
+ }
+ str.append("'");
+ if (pos_descr) {
+ Decorator d;
+ // 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());
+ } else {
+ str.append("\n");
+ }
+ Printf("%s", str.data());
+}
+
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars) {
+ CHECK(frame_descr);
+ char *p;
+ // This string is created by the compiler and has the following form:
+ // "n alloc_1 alloc_2 ... alloc_n"
+ // where alloc_i looks like "offset size len ObjectName".
+ uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
+ if (n_objects == 0)
+ return false;
+
+ for (uptr i = 0; i < n_objects; i++) {
+ uptr beg = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr len = (uptr)internal_simple_strtoll(p, &p, 10);
+ if (beg == 0 || size == 0 || *p != ' ') {
+ return false;
+ }
+ p++;
+ StackVarDescr var = {beg, size, p, len};
+ vars->push_back(var);
+ p += len;
+ }
+
+ return true;
+}
+
+bool DescribeAddressIfStack(uptr addr, uptr access_size) {
+ AsanThread *t = FindThreadByStackAddress(addr);
+ if (!t) return false;
+
+ Decorator d;
+ char tname[128];
+ Printf("%s", d.Location());
+ Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
+ ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
+
+ // Try to fetch precise stack frame for this access.
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+ Printf("%s\n", d.EndLocation());
+ return true;
+ }
+ Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
+
+ // Now we print the frame where the alloca has happened.
+ // We print this frame as a stack trace with one element.
+ // The symbolizer may print more than one frame if inlining was involved.
+ // The frame numbers may be different than those in the stack trace printed
+ // 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).
+#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ // On PowerPC64 ELFv1, the address of a function actually points to a
+ // three-doubleword data structure with the first field containing
+ // the address of the function's code.
+ access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
+#endif
+ access.frame_pc += 16;
+ Printf("%s", d.EndLocation());
+ StackTrace alloca_stack(&access.frame_pc, 1);
+ alloca_stack.Print();
+
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ Printf("AddressSanitizer can't parse the stack frame "
+ "descriptor: |%s|\n", access.frame_descr);
+ // 'addr' is a stack address, so return true even if we can't parse frame
+ return true;
+ }
+ uptr n_objects = vars.size();
+ // Report the number of stack objects.
+ Printf(" This frame has %zu object(s):\n", n_objects);
+
+ // Report all objects in this frame.
+ for (uptr i = 0; i < n_objects; i++) {
+ uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
+ uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
+ PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
+ prev_var_end, next_var_beg);
+ }
+ Printf("HINT: this may be a false positive if your program uses "
+ "some custom stack unwind mechanism or swapcontext\n");
+ if (SANITIZER_WINDOWS)
+ Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
+ else
+ Printf(" (longjmp and C++ exceptions *are* supported)\n");
+
+ DescribeThread(t);
+ return true;
+}
+
+static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
+ uptr access_size) {
+ sptr offset;
+ Decorator d;
+ InternalScopedString str(4096);
+ str.append("%s", d.Location());
+ if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
+ str.append("%p is located %zd bytes to the left of", (void *)addr, offset);
+ } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
+ if (offset < 0) {
+ addr -= offset;
+ offset = 0;
+ }
+ str.append("%p is located %zd bytes to the right of", (void *)addr, offset);
+ } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
+ str.append("%p is located %zd bytes inside of", (void*)addr, offset);
+ } else {
+ str.append("%p is located somewhere around (this is AddressSanitizer bug!)",
+ (void *)addr);
+ }
+ str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
+ (void *)(chunk.Beg()), (void *)(chunk.End()));
+ str.append("%s", d.EndLocation());
+ Printf("%s", str.data());
+}
+
+void DescribeHeapAddress(uptr addr, uptr access_size) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) {
+ Printf("AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+ return;
+ }
+ DescribeAccessToHeapChunk(chunk, addr, access_size);
+ CHECK(chunk.AllocTid() != kInvalidTid);
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *alloc_thread =
+ GetThreadContextByTidLocked(chunk.AllocTid());
+ StackTrace alloc_stack = chunk.GetAllocStack();
+ char tname[128];
+ Decorator d;
+ AsanThreadContext *free_thread = 0;
+ if (chunk.FreeTid() != kInvalidTid) {
+ free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
+ Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
+ free_thread->tid,
+ ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ StackTrace free_stack = chunk.GetFreeStack();
+ 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());
+ } else {
+ Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
+ alloc_thread->tid,
+ ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ }
+ alloc_stack.Print();
+ DescribeThread(GetCurrentThread());
+ if (free_thread)
+ DescribeThread(free_thread);
+ DescribeThread(alloc_thread);
+}
+
+void DescribeAddress(uptr addr, uptr access_size) {
+ // Check if this is shadow or shadow gap.
+ if (DescribeAddressIfShadow(addr))
+ return;
+ CHECK(AddrIsInMem(addr));
+ if (DescribeAddressIfGlobal(addr, access_size))
+ return;
+ if (DescribeAddressIfStack(addr, access_size))
+ return;
+ // Assume it is a heap address.
+ DescribeHeapAddress(addr, access_size);
+}
+
+// ------------------- Thread description -------------------- {{{1
+
+void DescribeThread(AsanThreadContext *context) {
+ CHECK(context);
+ asanThreadRegistry().CheckLocked();
+ // No need to announce the main thread.
+ if (context->tid == 0 || context->announced) {
+ return;
+ }
+ context->announced = true;
+ char tname[128];
+ InternalScopedString str(1024);
+ str.append("Thread T%d%s", context->tid,
+ ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
+ str.append(
+ " created by T%d%s here:\n", context->parent_tid,
+ ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
+ Printf("%s", str.data());
+ StackDepotGet(context->stack_id).Print();
+ // Recursively described parent thread if needed.
+ if (flags()->print_full_thread_history) {
+ AsanThreadContext *parent_context =
+ GetThreadContextByTidLocked(context->parent_tid);
+ DescribeThread(parent_context);
+ }
+}
+
+// -------------------- Different kinds of reports ----------------- {{{1
+
+// Use ScopedInErrorReport to run common actions just before and
+// immediately after printing error report.
+class ScopedInErrorReport {
+ public:
+ explicit ScopedInErrorReport(ReportData *report = nullptr) {
+ static atomic_uint32_t num_calls;
+ static u32 reporting_thread_tid;
+ if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
+ // Do not print more than one report, otherwise they will mix up.
+ // Error reporting functions shouldn't return at this situation, as
+ // they are defined as no-return.
+ Report("AddressSanitizer: while reporting a bug found another one. "
+ "Ignoring.\n");
+ u32 current_tid = GetCurrentTidOrInvalid();
+ if (current_tid != reporting_thread_tid) {
+ // ASan found two bugs in different threads simultaneously. 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(flags()->exitcode);
+ }
+ if (report) report_data = *report;
+ report_happened = true;
+ ASAN_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();
+ CommonSanitizerReportMutex.Lock();
+ reporting_thread_tid = GetCurrentTidOrInvalid();
+ Printf("===================================================="
+ "=============\n");
+ }
+ // Destructor is NORETURN, as functions that report errors are.
+ NORETURN ~ScopedInErrorReport() {
+ // Make sure the current thread is announced.
+ DescribeThread(GetCurrentThread());
+ // We may want to grab this lock again when printing stats.
+ asanThreadRegistry().Unlock();
+ // Print memory stats.
+ if (flags()->print_stats)
+ __asan_print_accumulated_stats();
+ if (error_report_callback) {
+ error_report_callback(error_message_buffer);
+ }
+ Report("ABORTING\n");
+ Die();
+ }
+};
+
+void ReportStackOverflow(const SignalContext &sig) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: stack-overflow on address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
+ GetCurrentTidOrInvalid());
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ ReportErrorSummary("stack-overflow", &stack);
+}
+
+void ReportSIGSEGV(const char *description, const SignalContext &sig) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: %s on unknown address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
+ (void *)sig.sp, GetCurrentTidOrInvalid());
+ if (sig.pc < GetPageSizeCached()) {
+ Report("Hint: pc points to the zero page.\n");
+ }
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ MaybeDumpInstructionBytes(sig.pc);
+ Printf("AddressSanitizer can not provide additional info.\n");
+ ReportErrorSummary("SEGV", &stack);
+}
+
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: attempting double-free on %p in "
+ "thread T%d%s:\n",
+ addr, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("double-free", &stack);
+}
+
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
+ "thread T%d%s:\n",
+ addr, curr_tid,
+ ThreadNameWithParenthesis(curr_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",
+ asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("new-delete-type-mismatch", &stack);
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+}
+
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: attempting free on address "
+ "which was not malloc()-ed: %p in thread T%d%s\n", addr,
+ curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("bad-free", &stack);
+}
+
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
+ AllocType alloc_type,
+ AllocType dealloc_type) {
+ static const char *alloc_names[] =
+ {"INVALID", "malloc", "operator new", "operator new []"};
+ static const char *dealloc_names[] =
+ {"INVALID", "free", "operator delete", "operator delete []"};
+ CHECK_NE(alloc_type, dealloc_type);
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
+ alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("alloc-dealloc-mismatch", &stack);
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
+}
+
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: attempting to call "
+ "malloc_usable_size() for pointer which is "
+ "not owned: %p\n", addr);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("bad-malloc_usable_size", stack);
+}
+
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: attempting to call "
+ "__sanitizer_get_allocated_size() for pointer which is "
+ "not owned: %p\n", addr);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
+}
+
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ char bug_type[100];
+ internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s: "
+ "memory ranges [%p,%p) and [%p, %p) overlap\n", \
+ bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeAddress((uptr)offset1, length1);
+ DescribeAddress((uptr)offset2, length2);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ const char *bug_type = "negative-size-param";
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeAddress(offset, size);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Report("ERROR: AddressSanitizer: bad parameters to "
+ "__sanitizer_annotate_contiguous_container:\n"
+ " beg : %p\n"
+ " end : %p\n"
+ " old_mid : %p\n"
+ " new_mid : %p\n",
+ beg, end, old_mid, new_mid);
+ stack->Print();
+ ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+}
+
+void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
+ Printf("%s", d.EndWarning());
+ InternalScopedString g1_loc(256), g2_loc(256);
+ PrintGlobalLocation(&g1_loc, *g1);
+ PrintGlobalLocation(&g2_loc, *g2);
+ Printf(" [1] size=%zd '%s' %s\n", g1->size,
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ Printf(" [2] size=%zd '%s' %s\n", g2->size,
+ MaybeDemangleGlobalName(g2->name), g2_loc.data());
+ if (stack_id1 && stack_id2) {
+ Printf("These globals were registered at these points:\n");
+ Printf(" [1]:\n");
+ StackDepotGet(stack_id1).Print();
+ Printf(" [2]:\n");
+ StackDepotGet(stack_id2).Print();
+ }
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=detect_odr_violation=0\n");
+ InternalScopedString error_msg(256);
+ error_msg.append("odr-violation: global '%s' at %s",
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ ReportErrorSummary(error_msg.data());
+}
+
+// ----------------------- CheckForInvalidPointerPair ----------- {{{1
+static NOINLINE void
+ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+ DescribeAddress(a1, 1);
+ DescribeAddress(a2, 1);
+ ReportErrorSummary("invalid-pointer-pair", &stack);
+}
+
+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.IsValid();
+ bool valid2 = chunk2.IsValid();
+ if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
+ GET_CALLER_PC_BP_SP; \
+ return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
+ }
+}
+// ----------------------- Mac-specific reports ----------------- {{{1
+
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
+ // Just print a warning here.
+ Printf("free_common(%p) -- attempting to free unallocated memory.\n"
+ "AddressSanitizer is ignoring this error on Mac OS now.\n",
+ addr);
+ PrintZoneForPointer(addr, zone_ptr, zone_name);
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+}
+
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
+ "This is an unrecoverable problem, exiting now.\n",
+ addr);
+ PrintZoneForPointer(addr, zone_ptr, zone_name);
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+}
+
+void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
+ "This is an unrecoverable problem, exiting now.\n",
+ addr);
+ PrintZoneForPointer(addr, zone_ptr, zone_name);
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+}
+
+} // namespace __asan
+
+// --------------------------- Interface --------------------- {{{1
+using namespace __asan; // NOLINT
+
+void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
+ uptr access_size) {
+ ENABLE_FRAME_POINTER;
+
+ // Determine the error type.
+ const char *bug_descr = "unknown-crash";
+ if (AddrIsInMem(addr)) {
+ u8 *shadow_addr = (u8*)MemToShadow(addr);
+ // If we are accessing 16 bytes, look at the second shadow byte.
+ if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
+ shadow_addr++;
+ // If we are in the partial right redzone, look at the next shadow byte.
+ if (*shadow_addr > 0 && *shadow_addr < 128)
+ shadow_addr++;
+ switch (*shadow_addr) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
+ bug_descr = "heap-buffer-overflow";
+ break;
+ case kAsanHeapFreeMagic:
+ bug_descr = "heap-use-after-free";
+ break;
+ case kAsanStackLeftRedzoneMagic:
+ bug_descr = "stack-buffer-underflow";
+ break;
+ case kAsanInitializationOrderMagic:
+ bug_descr = "initialization-order-fiasco";
+ break;
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ case kAsanStackPartialRedzoneMagic:
+ bug_descr = "stack-buffer-overflow";
+ break;
+ case kAsanStackAfterReturnMagic:
+ bug_descr = "stack-use-after-return";
+ break;
+ case kAsanUserPoisonedMemoryMagic:
+ bug_descr = "use-after-poison";
+ break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ break;
+ case kAsanStackUseAfterScopeMagic:
+ bug_descr = "stack-use-after-scope";
+ break;
+ case kAsanGlobalRedzoneMagic:
+ bug_descr = "global-buffer-overflow";
+ break;
+ case kAsanIntraObjectRedzone:
+ bug_descr = "intra-object-overflow";
+ break;
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ bug_descr = "dynamic-stack-buffer-overflow";
+ break;
+ }
+ }
+
+ ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
+ bug_descr };
+ ScopedInErrorReport in_report(&report);
+
+ Decorator d;
+ Printf("%s", d.Warning());
+ 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());
+
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ 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, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
+ d.EndAccess());
+
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+
+ DescribeAddress(addr, access_size);
+ ReportErrorSummary(bug_descr, &stack);
+ PrintShadowMemoryForAddress(addr);
+}
+
+void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
+ error_report_callback = callback;
+ if (callback) {
+ error_message_buffer_size = 1 << 16;
+ error_message_buffer =
+ (char*)MmapOrDie(error_message_buffer_size, __func__);
+ error_message_buffer_pos = 0;
+ }
+}
+
+void __asan_describe_address(uptr addr) {
+ // Thread registry must be locked while we're describing an address.
+ asanThreadRegistry().Lock();
+ DescribeAddress(addr, 1);
+ asanThreadRegistry().Unlock();
+}
+
+int __asan_report_present() {
+ return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+ return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+ return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+ return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+ return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+ return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+ return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+ return report_data.description;
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_sub(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_cmp(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
+}
+} // extern "C"
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+// Provide default implementation of __asan_on_error that does nothing
+// and may be overriden by user.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
+void __asan_on_error() {}
+#endif
diff --git a/contrib/compiler-rt/lib/asan/asan_report.h b/contrib/compiler-rt/lib/asan/asan_report.h
new file mode 100644
index 000000000000..029c914b8a04
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_report.h
@@ -0,0 +1,95 @@
+//===-- asan_report.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 error reporting functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+struct StackVarDescr {
+ uptr beg;
+ uptr size;
+ const char *name_pos;
+ uptr name_len;
+};
+
+struct AddressDescription {
+ char *name;
+ uptr name_size;
+ uptr region_address;
+ uptr region_size;
+ const char *region_kind;
+};
+
+// The following functions prints address description depending
+// on the memory type (shadow/heap/stack/global).
+void DescribeHeapAddress(uptr addr, uptr access_size);
+bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
+ const __asan_global &g);
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g);
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
+ bool print = true);
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars);
+bool DescribeAddressIfStack(uptr addr, uptr access_size);
+// Determines memory type on its own.
+void DescribeAddress(uptr addr, uptr access_size);
+
+void DescribeThread(AsanThreadContext *context);
+
+// Different kinds of error reports.
+void NORETURN ReportStackOverflow(const SignalContext &sig);
+void NORETURN ReportSIGSEGV(const char *description, const SignalContext &sig);
+void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack);
+void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
+ AllocType alloc_type,
+ AllocType dealloc_type);
+void NORETURN
+ ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
+void NORETURN
+ ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack);
+void NORETURN
+ ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack);
+void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack);
+void NORETURN
+ ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack);
+
+void NORETURN
+ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2);
+
+// Mac-specific errors and warnings.
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack);
+void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
+void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
+
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_rtl.cc b/contrib/compiler-rt/lib/asan/asan_rtl.cc
new file mode 100644
index 000000000000..9126e71a6437
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_rtl.cc
@@ -0,0 +1,523 @@
+//===-- asan_rtl.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.
+//
+// Main file of the ASan run-time library.
+//===----------------------------------------------------------------------===//
+#include "asan_activation.h"
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_interface_internal.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_suppressions.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "lsan/lsan_common.h"
+
+int __asan_option_detect_stack_use_after_return; // Global interface symbol.
+uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
+
+namespace __asan {
+
+uptr AsanMappingProfile[kAsanMappingProfileSize];
+
+static void AsanDie() {
+ static atomic_uint32_t num_calls;
+ if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
+ // Don't die twice - run a busy loop.
+ while (1) { }
+ }
+ if (flags()->sleep_before_dying) {
+ Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
+ SleepForSeconds(flags()->sleep_before_dying);
+ }
+ if (flags()->unmap_shadow_on_exit) {
+ if (kMidMemBeg) {
+ UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
+ UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
+ } else {
+ UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
+ }
+ }
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+ if (flags()->abort_on_error)
+ Abort();
+ internal__exit(flags()->exitcode);
+}
+
+static void AsanCheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
+ line, cond, (uptr)v1, (uptr)v2);
+ // FIXME: check for infinite recursion without a thread-local counter here.
+ PRINT_CURRENT_STACK_CHECK();
+ Die();
+}
+
+// -------------------------- Globals --------------------- {{{1
+int asan_inited;
+bool asan_init_is_running;
+
+#if !ASAN_FIXED_MAPPING
+uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;
+#endif
+
+// -------------------------- Misc ---------------- {{{1
+void ShowStatsAndAbort() {
+ __asan_print_accumulated_stats();
+ 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) {
+ CHECK_EQ((beg % GetPageSizeCached()), 0);
+ CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
+ uptr size = end - beg + 1;
+ DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
+ void *res = MmapFixedNoReserve(beg, size);
+ 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);
+}
+
+// -------------------------- Run-time entry ------------------- {{{1
+// exported functions
+#define ASAN_REPORT_ERROR(type, is_write, size) \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## size(uptr addr); \
+void __asan_report_ ## type ## size(uptr addr) { \
+ GET_CALLER_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, addr, is_write, size); \
+}
+
+ASAN_REPORT_ERROR(load, false, 1)
+ASAN_REPORT_ERROR(load, false, 2)
+ASAN_REPORT_ERROR(load, false, 4)
+ASAN_REPORT_ERROR(load, false, 8)
+ASAN_REPORT_ERROR(load, false, 16)
+ASAN_REPORT_ERROR(store, true, 1)
+ASAN_REPORT_ERROR(store, true, 2)
+ASAN_REPORT_ERROR(store, true, 4)
+ASAN_REPORT_ERROR(store, true, 8)
+ASAN_REPORT_ERROR(store, true, 16)
+
+#define ASAN_REPORT_ERROR_N(type, is_write) \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## _n(uptr addr, uptr size); \
+void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
+ GET_CALLER_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, addr, is_write, size); \
+}
+
+ASAN_REPORT_ERROR_N(load, false)
+ASAN_REPORT_ERROR_N(store, true)
+
+#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
+ extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \
+ void __asan_##type##size(uptr addr) { \
+ uptr sp = MEM_TO_SHADOW(addr); \
+ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
+ : *reinterpret_cast<u16 *>(sp); \
+ if (UNLIKELY(s)) { \
+ if (UNLIKELY(size >= SHADOW_GRANULARITY || \
+ ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \
+ (s8)s)) { \
+ if (__asan_test_only_reported_buggy_pointer) { \
+ *__asan_test_only_reported_buggy_pointer = addr; \
+ } else { \
+ GET_CALLER_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, addr, is_write, size); \
+ } \
+ } \
+ } \
+ }
+
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16)
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ __asan_report_error(pc, bp, sp, addr, false, size);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ __asan_report_error(pc, bp, sp, addr, true, size);
+ }
+}
+
+// Force the linker to keep the symbols for various ASan interface functions.
+// We want to keep those in the executable in order to let the instrumented
+// dynamic libraries access the symbol even if it is not used by the executable
+// itself. This should help if the build system is removing dead code at link
+// time.
+static NOINLINE void force_interface_symbols() {
+ volatile int fake_condition = 0; // prevent dead condition elimination.
+ // __asan_report_* functions are noreturn, so we need a switch to prevent
+ // the compiler from removing any of them.
+ switch (fake_condition) {
+ case 1: __asan_report_load1(0); break;
+ case 2: __asan_report_load2(0); break;
+ case 3: __asan_report_load4(0); break;
+ case 4: __asan_report_load8(0); break;
+ case 5: __asan_report_load16(0); break;
+ case 6: __asan_report_store1(0); break;
+ case 7: __asan_report_store2(0); break;
+ case 8: __asan_report_store4(0); break;
+ case 9: __asan_report_store8(0); break;
+ case 10: __asan_report_store16(0); break;
+ case 12: __asan_register_globals(0, 0); break;
+ case 13: __asan_unregister_globals(0, 0); break;
+ case 14: __asan_set_death_callback(0); break;
+ case 15: __asan_set_error_report_callback(0); break;
+ case 16: __asan_handle_no_return(); break;
+ case 17: __asan_address_is_poisoned(0); break;
+ case 25: __asan_poison_memory_region(0, 0); break;
+ case 26: __asan_unpoison_memory_region(0, 0); break;
+ case 27: __asan_set_error_exit_code(0); break;
+ case 30: __asan_before_dynamic_init(0); break;
+ case 31: __asan_after_dynamic_init(); break;
+ case 32: __asan_poison_stack_memory(0, 0); break;
+ case 33: __asan_unpoison_stack_memory(0, 0); break;
+ case 34: __asan_region_is_poisoned(0, 0); break;
+ case 35: __asan_describe_address(0); break;
+ }
+}
+
+static void asan_atexit() {
+ Printf("AddressSanitizer exit stats:\n");
+ __asan_print_accumulated_stats();
+ // Print AsanMappingProfile.
+ for (uptr i = 0; i < kAsanMappingProfileSize; i++) {
+ if (AsanMappingProfile[i] == 0) continue;
+ Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]);
+ }
+}
+
+static void InitializeHighMemEnd() {
+#if !ASAN_FIXED_MAPPING
+ kHighMemEnd = GetMaxVirtualAddress();
+ // Increase kHighMemEnd to make sure it's properly
+ // aligned together with kHighMemBeg:
+ kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1;
+#endif // !ASAN_FIXED_MAPPING
+ CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
+}
+
+static void ProtectGap(uptr a, uptr size) {
+ void *res = Mprotect(a, size);
+ if (a == (uptr)res)
+ return;
+ Report("ERROR: Failed to protect the shadow gap. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ DumpProcessMap();
+ Die();
+}
+
+static void PrintAddressSpaceLayout() {
+ Printf("|| `[%p, %p]` || HighMem ||\n",
+ (void*)kHighMemBeg, (void*)kHighMemEnd);
+ Printf("|| `[%p, %p]` || HighShadow ||\n",
+ (void*)kHighShadowBeg, (void*)kHighShadowEnd);
+ if (kMidMemBeg) {
+ Printf("|| `[%p, %p]` || ShadowGap3 ||\n",
+ (void*)kShadowGap3Beg, (void*)kShadowGap3End);
+ Printf("|| `[%p, %p]` || MidMem ||\n",
+ (void*)kMidMemBeg, (void*)kMidMemEnd);
+ Printf("|| `[%p, %p]` || ShadowGap2 ||\n",
+ (void*)kShadowGap2Beg, (void*)kShadowGap2End);
+ Printf("|| `[%p, %p]` || MidShadow ||\n",
+ (void*)kMidShadowBeg, (void*)kMidShadowEnd);
+ }
+ Printf("|| `[%p, %p]` || ShadowGap ||\n",
+ (void*)kShadowGapBeg, (void*)kShadowGapEnd);
+ if (kLowShadowBeg) {
+ Printf("|| `[%p, %p]` || LowShadow ||\n",
+ (void*)kLowShadowBeg, (void*)kLowShadowEnd);
+ Printf("|| `[%p, %p]` || LowMem ||\n",
+ (void*)kLowMemBeg, (void*)kLowMemEnd);
+ }
+ Printf("MemToShadow(shadow): %p %p %p %p",
+ (void*)MEM_TO_SHADOW(kLowShadowBeg),
+ (void*)MEM_TO_SHADOW(kLowShadowEnd),
+ (void*)MEM_TO_SHADOW(kHighShadowBeg),
+ (void*)MEM_TO_SHADOW(kHighShadowEnd));
+ if (kMidMemBeg) {
+ Printf(" %p %p",
+ (void*)MEM_TO_SHADOW(kMidShadowBeg),
+ (void*)MEM_TO_SHADOW(kMidShadowEnd));
+ }
+ Printf("\n");
+ Printf("redzone=%zu\n", (uptr)flags()->redzone);
+ Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
+ Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb);
+ Printf("malloc_context_size=%zu\n",
+ (uptr)common_flags()->malloc_context_size);
+
+ Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
+ Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
+ Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET);
+ CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
+ if (kMidMemBeg)
+ CHECK(kMidShadowBeg > kLowShadowEnd &&
+ kMidMemBeg > kMidShadowEnd &&
+ kHighShadowBeg > kMidMemEnd);
+}
+
+static void AsanInitInternal() {
+ if (LIKELY(asan_inited)) return;
+ SanitizerToolName = "AddressSanitizer";
+ CHECK(!asan_init_is_running && "ASan init calls itself!");
+ asan_init_is_running = true;
+
+ // Initialize flags. This must be done early, because most of the
+ // initialization steps look at flags().
+ InitializeFlags();
+
+ SetCanPoisonMemory(flags()->poison_heap);
+ SetMallocContextSize(common_flags()->malloc_context_size);
+
+ InitializeHighMemEnd();
+
+ // Make sure we are not statically linked.
+ AsanDoesNotSupportStaticLinkage();
+
+ // Install tool-specific callbacks in sanitizer_common.
+ SetDieCallback(AsanDie);
+ SetCheckFailedCallback(AsanCheckFailed);
+ SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
+
+ __sanitizer_set_report_path(common_flags()->log_path);
+
+ // Enable UAR detection, if required.
+ __asan_option_detect_stack_use_after_return =
+ flags()->detect_stack_use_after_return;
+
+ // Re-exec ourselves if we need to set additional env or command line args.
+ MaybeReexec();
+
+ // Setup internal allocator callback.
+ SetLowLevelAllocateCallback(OnLowLevelAllocate);
+
+ InitializeAsanInterceptors();
+
+ // Enable system log ("adb logcat") on Android.
+ // Doing this before interceptors are initialized crashes in:
+ // AsanInitInternal -> android_log_write -> __interceptor_strcmp
+ AndroidLogInit();
+
+ ReplaceSystemMalloc();
+
+ uptr shadow_start = kLowShadowBeg;
+ 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();
+
+ DisableCoreDumperIfNecessary();
+
+ if (full_shadow_is_available) {
+ // mmap the low shadow plus at least one page at the left.
+ if (kLowShadowBeg)
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
+ // 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);
+ // mmap the mid shadow.
+ ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd);
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
+ // 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();
+ }
+
+ AsanTSDInit(PlatformTSDDtor);
+ InstallDeadlySignalHandlers(AsanOnSIGSEGV);
+
+ AllocatorOptions allocator_options;
+ allocator_options.SetFrom(flags(), common_flags());
+ InitializeAllocator(allocator_options);
+
+ MaybeStartBackgroudThread();
+ SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback);
+
+ // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
+ // should be set to 1 prior to initializing the threads.
+ asan_inited = 1;
+ asan_init_is_running = false;
+
+ if (flags()->atexit)
+ Atexit(asan_atexit);
+
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+
+ // Now that ASan runtime is (mostly) initialized, deactivate it if
+ // necessary, so that it can be re-activated when requested.
+ if (flags()->start_deactivated)
+ AsanDeactivate();
+
+ // interceptors
+ InitTlsSize();
+
+ // Create main thread.
+ AsanThread *main_thread = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* stack */ nullptr, /* detached */ true);
+ 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);
+ }
+#endif // CAN_SANITIZE_LEAKS
+
+ InitializeSuppressions();
+
+ VReport(1, "AddressSanitizer Init done\n");
+}
+
+// Initialize as requested from some part of ASan runtime library (interceptors,
+// allocator, etc).
+void AsanInitFromRtl() {
+ AsanInitInternal();
+}
+
+#if ASAN_DYNAMIC
+// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
+// (and thus normal initializer from .preinit_array haven't run).
+
+class AsanInitializer {
+public: // NOLINT
+ AsanInitializer() {
+ AsanCheckIncompatibleRT();
+ AsanCheckDynamicRTPrereqs();
+ AsanInitFromRtl();
+ }
+};
+
+static AsanInitializer asan_initializer;
+#endif // ASAN_DYNAMIC
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+int NOINLINE __asan_set_error_exit_code(int exit_code) {
+ int old = flags()->exitcode;
+ flags()->exitcode = exit_code;
+ return old;
+}
+
+void NOINLINE __asan_handle_no_return() {
+ int local_stack;
+ AsanThread *curr_thread = GetCurrentThread();
+ CHECK(curr_thread);
+ uptr PageSize = GetPageSizeCached();
+ uptr top = curr_thread->stack_top();
+ uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1);
+ static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
+ if (top - bottom > kMaxExpectedCleanupSize) {
+ static bool reported_warning = false;
+ if (reported_warning)
+ return;
+ reported_warning = true;
+ Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
+ "stack top: %p; bottom %p; size: %p (%zd)\n"
+ "False positive error reports may follow\n"
+ "For details see "
+ "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
+ top, bottom, top - bottom, top - bottom);
+ return;
+ }
+ PoisonShadow(bottom, top - bottom, 0);
+ if (curr_thread->has_fake_stack())
+ curr_thread->fake_stack()->HandleNoReturn();
+}
+
+void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
+ SetUserDieCallback(callback);
+}
+
+// Initialize as requested from instrumented application code.
+// We use this call as a trigger to wake up ASan from deactivated state.
+void __asan_init() {
+ AsanCheckIncompatibleRT();
+ AsanActivate();
+ AsanInitInternal();
+}
diff --git a/contrib/compiler-rt/lib/asan/asan_stack.cc b/contrib/compiler-rt/lib/asan/asan_stack.cc
new file mode 100644
index 000000000000..cf7a587fa65a
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_stack.cc
@@ -0,0 +1,40 @@
+//===-- asan_stack.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.
+//
+// Code for ASan stack trace.
+//===----------------------------------------------------------------------===//
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+
+namespace __asan {
+
+static atomic_uint32_t malloc_context_size;
+
+void SetMallocContextSize(u32 size) {
+ atomic_store(&malloc_context_size, size, memory_order_release);
+}
+
+u32 GetMallocContextSize() {
+ return atomic_load(&malloc_context_size, memory_order_acquire);
+}
+
+} // namespace __asan
+
+// ------------------ Interface -------------- {{{1
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ using namespace __asan;
+ PRINT_CURRENT_STACK();
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/asan/asan_stack.h b/contrib/compiler-rt/lib/asan/asan_stack.h
new file mode 100644
index 000000000000..122967a152f8
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_stack.h
@@ -0,0 +1,118 @@
+//===-- asan_stack.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_stack.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_STACK_H
+#define ASAN_STACK_H
+
+#include "asan_flags.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __asan {
+
+static const u32 kDefaultMallocContextSize = 30;
+
+void SetMallocContextSize(u32 size);
+u32 GetMallocContextSize();
+
+// Get the stack trace with the given pc and bp.
+// 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) {
+#if SANITIZER_WINDOWS
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
+#else
+ AsanThread *t;
+ 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);
+ stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
+ } else if (t == 0 && !fast) {
+ /* If GetCurrentThread() has failed, try to do slow unwind anyways. */
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
+ }
+ }
+#endif // SANITIZER_WINDOWS
+}
+
+} // namespace __asan
+
+// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
+// 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_FATAL(pc, bp) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&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_FATAL_HERE \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_CHECK_HERE \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
+
+#define GET_STACK_TRACE_THREAD \
+ GET_STACK_TRACE(kStackTraceMax, true)
+
+#define GET_STACK_TRACE_MALLOC \
+ GET_STACK_TRACE(GetMallocContextSize(), common_flags()->fast_unwind_on_malloc)
+
+#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
+
+#define PRINT_CURRENT_STACK() \
+ { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ stack.Print(); \
+ }
+
+#define PRINT_CURRENT_STACK_CHECK() \
+ { \
+ GET_STACK_TRACE_CHECK_HERE; \
+ stack.Print(); \
+ }
+
+#endif // ASAN_STACK_H
diff --git a/contrib/compiler-rt/lib/asan/asan_stats.cc b/contrib/compiler-rt/lib/asan/asan_stats.cc
new file mode 100644
index 000000000000..a78b7b1e926d
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_stats.cc
@@ -0,0 +1,179 @@
+//===-- asan_stats.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.
+//
+// Code related to statistics collected by AddressSanitizer.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __asan {
+
+AsanStats::AsanStats() {
+ Clear();
+}
+
+void AsanStats::Clear() {
+ CHECK(REAL(memset));
+ REAL(memset)(this, 0, sizeof(AsanStats));
+}
+
+static void PrintMallocStatsArray(const char *prefix,
+ uptr (&array)[kNumberOfSizeClasses]) {
+ Printf("%s", prefix);
+ for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
+ if (!array[i]) continue;
+ Printf("%zu:%zu; ", i, array[i]);
+ }
+ Printf("\n");
+}
+
+void AsanStats::Print() {
+ Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
+ malloced>>20, malloced_redzones>>20, mallocs);
+ Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
+ Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
+ Printf("Stats: %zuM really freed by %zu calls\n",
+ really_freed>>20, real_frees);
+ Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n",
+ (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20,
+ mmaps, munmaps);
+
+ PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size);
+ PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
+ PrintMallocStatsArray(" frees by size class: ", freed_by_size);
+ PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size);
+ Printf("Stats: malloc large: %zu small slow: %zu\n",
+ malloc_large, malloc_small_slow);
+}
+
+void AsanStats::MergeFrom(const AsanStats *stats) {
+ uptr *dst_ptr = reinterpret_cast<uptr*>(this);
+ const uptr *src_ptr = reinterpret_cast<const uptr*>(stats);
+ uptr num_fields = sizeof(*this) / sizeof(uptr);
+ for (uptr i = 0; i < num_fields; i++)
+ dst_ptr[i] += src_ptr[i];
+}
+
+static BlockingMutex print_lock(LINKER_INITIALIZED);
+
+static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
+static AsanStats dead_threads_stats(LINKER_INITIALIZED);
+static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED);
+// Required for malloc_zone_statistics() on OS X. This can't be stored in
+// per-thread AsanStats.
+static uptr max_malloced_memory;
+
+static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) {
+ AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg);
+ AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
+ if (AsanThread *t = tctx->thread)
+ accumulated_stats->MergeFrom(&t->stats());
+}
+
+static void GetAccumulatedStats(AsanStats *stats) {
+ stats->Clear();
+ {
+ ThreadRegistryLock l(&asanThreadRegistry());
+ asanThreadRegistry()
+ .RunCallbackForEachThreadLocked(MergeThreadStats, stats);
+ }
+ stats->MergeFrom(&unknown_thread_stats);
+ {
+ BlockingMutexLock lock(&dead_threads_stats_lock);
+ stats->MergeFrom(&dead_threads_stats);
+ }
+ // This is not very accurate: we may miss allocation peaks that happen
+ // between two updates of accumulated_stats_. For more accurate bookkeeping
+ // the maximum should be updated on every malloc(), which is unacceptable.
+ if (max_malloced_memory < stats->malloced) {
+ max_malloced_memory = stats->malloced;
+ }
+}
+
+void FlushToDeadThreadStats(AsanStats *stats) {
+ BlockingMutexLock lock(&dead_threads_stats_lock);
+ dead_threads_stats.MergeFrom(stats);
+ stats->Clear();
+}
+
+void FillMallocStatistics(AsanMallocStats *malloc_stats) {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ malloc_stats->blocks_in_use = stats.mallocs;
+ malloc_stats->size_in_use = stats.malloced;
+ malloc_stats->max_size_in_use = max_malloced_memory;
+ malloc_stats->size_allocated = stats.mmaped;
+}
+
+AsanStats &GetCurrentThreadStats() {
+ AsanThread *t = GetCurrentThread();
+ return (t) ? t->stats() : unknown_thread_stats;
+}
+
+static void PrintAccumulatedStats() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ // Use lock to keep reports from mixing up.
+ BlockingMutexLock lock(&print_lock);
+ stats.Print();
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
+ stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
+ PrintInternalAllocatorStats();
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+uptr __sanitizer_get_current_allocated_bytes() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ uptr malloced = stats.malloced;
+ uptr freed = stats.freed;
+ // Return sane value if malloced < freed due to racy
+ // way we update accumulated stats.
+ return (malloced > freed) ? malloced - freed : 1;
+}
+
+uptr __sanitizer_get_heap_size() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ return stats.mmaped - stats.munmaped;
+}
+
+uptr __sanitizer_get_free_bytes() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ uptr total_free = stats.mmaped
+ - stats.munmaped
+ + stats.really_freed
+ + stats.really_freed_redzones;
+ uptr total_used = stats.malloced
+ + stats.malloced_redzones;
+ // Return sane value if total_free < total_used due to racy
+ // way we update accumulated stats.
+ return (total_free > total_used) ? total_free - total_used : 1;
+}
+
+uptr __sanitizer_get_unmapped_bytes() {
+ return 0;
+}
+
+void __asan_print_accumulated_stats() {
+ PrintAccumulatedStats();
+}
diff --git a/contrib/compiler-rt/lib/asan/asan_stats.h b/contrib/compiler-rt/lib/asan/asan_stats.h
new file mode 100644
index 000000000000..c66848dc5713
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_stats.h
@@ -0,0 +1,78 @@
+//===-- asan_stats.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 statistics.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_STATS_H
+#define ASAN_STATS_H
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+
+namespace __asan {
+
+// AsanStats struct is NOT thread-safe.
+// Each AsanThread has its own AsanStats, which are sometimes flushed
+// to the accumulated AsanStats.
+struct AsanStats {
+ // AsanStats must be a struct consisting of uptr fields only.
+ // When merging two AsanStats structs, we treat them as arrays of uptr.
+ uptr mallocs;
+ uptr malloced;
+ uptr malloced_redzones;
+ uptr frees;
+ uptr freed;
+ uptr real_frees;
+ uptr really_freed;
+ uptr really_freed_redzones;
+ uptr reallocs;
+ uptr realloced;
+ uptr mmaps;
+ uptr mmaped;
+ uptr munmaps;
+ uptr munmaped;
+ uptr mmaped_by_size[kNumberOfSizeClasses];
+ uptr malloced_by_size[kNumberOfSizeClasses];
+ uptr freed_by_size[kNumberOfSizeClasses];
+ uptr really_freed_by_size[kNumberOfSizeClasses];
+
+ uptr malloc_large;
+ uptr malloc_small_slow;
+
+ // Ctor for global AsanStats (accumulated stats for dead threads).
+ explicit AsanStats(LinkerInitialized) { }
+ // Creates empty stats.
+ AsanStats();
+
+ void Print(); // Prints formatted stats to stderr.
+ void Clear();
+ void MergeFrom(const AsanStats *stats);
+};
+
+// Returns stats for GetCurrentThread(), or stats for fake "unknown thread"
+// if GetCurrentThread() returns 0.
+AsanStats &GetCurrentThreadStats();
+// Flushes a given stats into accumulated stats of dead threads.
+void FlushToDeadThreadStats(AsanStats *stats);
+
+// A cross-platform equivalent of malloc_statistics_t on Mac OS.
+struct AsanMallocStats {
+ uptr blocks_in_use;
+ uptr size_in_use;
+ uptr max_size_in_use;
+ uptr size_allocated;
+};
+
+void FillMallocStatistics(AsanMallocStats *malloc_stats);
+
+} // namespace __asan
+
+#endif // ASAN_STATS_H
diff --git a/contrib/compiler-rt/lib/asan/asan_suppressions.cc b/contrib/compiler-rt/lib/asan/asan_suppressions.cc
new file mode 100644
index 000000000000..62198aec64e7
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_suppressions.cc
@@ -0,0 +1,93 @@
+//===-- asan_suppressions.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.
+//
+// Issue suppression and suppression-related functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_suppressions.h"
+
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __asan {
+
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kInterceptorName[] = "interceptor_name";
+static const char kInterceptorViaFunction[] = "interceptor_via_fun";
+static const char kInterceptorViaLibrary[] = "interceptor_via_lib";
+static const char *kSuppressionTypes[] = {
+ kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary};
+
+void InitializeSuppressions() {
+ CHECK_EQ(nullptr, suppression_ctx);
+ suppression_ctx = new (suppression_placeholder) // NOLINT
+ SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+ suppression_ctx->ParseFromFile(flags()->suppressions);
+}
+
+bool IsInterceptorSuppressed(const char *interceptor_name) {
+ CHECK(suppression_ctx);
+ Suppression *s;
+ // Match "interceptor_name" suppressions.
+ return suppression_ctx->Match(interceptor_name, kInterceptorName, &s);
+}
+
+bool HaveStackTraceBasedSuppressions() {
+ CHECK(suppression_ctx);
+ return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) ||
+ suppression_ctx->HasSuppressionType(kInterceptorViaLibrary);
+}
+
+bool IsStackTraceSuppressed(const StackTrace *stack) {
+ if (!HaveStackTraceBasedSuppressions())
+ return false;
+
+ CHECK(suppression_ctx);
+ Symbolizer *symbolizer = Symbolizer::GetOrInit();
+ Suppression *s;
+ for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
+ uptr addr = stack->trace[i];
+
+ if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) {
+ const char *module_name;
+ uptr module_offset;
+ // Match "interceptor_via_lib" suppressions.
+ if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
+ &module_offset) &&
+ suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) {
+ return true;
+ }
+ }
+
+ if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
+ SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ const char *function_name = cur->info.function;
+ if (!function_name) {
+ continue;
+ }
+ // Match "interceptor_via_fun" suppressions.
+ if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
+ &s)) {
+ frames->ClearAll();
+ return true;
+ }
+ }
+ frames->ClearAll();
+ }
+ }
+ return false;
+}
+
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_suppressions.h b/contrib/compiler-rt/lib/asan/asan_suppressions.h
new file mode 100644
index 000000000000..cd7ba2ef0ae7
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_suppressions.h
@@ -0,0 +1,29 @@
+//===-- asan_suppressions.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_suppressions.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_SUPPRESSIONS_H
+#define ASAN_SUPPRESSIONS_H
+
+#include "asan_internal.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __asan {
+
+void InitializeSuppressions();
+bool IsInterceptorSuppressed(const char *interceptor_name);
+bool HaveStackTraceBasedSuppressions();
+bool IsStackTraceSuppressed(const StackTrace *stack);
+
+} // namespace __asan
+
+#endif // ASAN_SUPPRESSIONS_H
diff --git a/contrib/compiler-rt/lib/asan/asan_thread.cc b/contrib/compiler-rt/lib/asan/asan_thread.cc
new file mode 100644
index 000000000000..9af5706d86d0
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_thread.cc
@@ -0,0 +1,358 @@
+//===-- asan_thread.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.
+//
+// Thread-related code.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_poisoning.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+#include "lsan/lsan_common.h"
+
+namespace __asan {
+
+// AsanThreadContext implementation.
+
+struct CreateThreadContextArgs {
+ AsanThread *thread;
+ StackTrace *stack;
+};
+
+void AsanThreadContext::OnCreated(void *arg) {
+ CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
+ if (args->stack)
+ stack_id = StackDepotPut(*args->stack);
+ thread = args->thread;
+ thread->set_context(this);
+}
+
+void AsanThreadContext::OnFinished() {
+ // Drop the link to the AsanThread object.
+ thread = 0;
+}
+
+// MIPS requires aligned address
+static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
+static ThreadRegistry *asan_thread_registry;
+
+static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_thread_context;
+
+static ThreadContextBase *GetAsanThreadContext(u32 tid) {
+ BlockingMutexLock lock(&mu_for_thread_context);
+ return new(allocator_for_thread_context) AsanThreadContext(tid);
+}
+
+ThreadRegistry &asanThreadRegistry() {
+ static bool initialized;
+ // Don't worry about thread_safety - this should be called when there is
+ // a single thread.
+ if (!initialized) {
+ // Never reuse ASan threads: we store pointer to AsanThreadContext
+ // in TSD and can't reliably tell when no more TSD destructors will
+ // be called. It would be wrong to reuse AsanThreadContext for another
+ // thread before all TSD destructors will be called for it.
+ asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
+ GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
+ initialized = true;
+ }
+ return *asan_thread_registry;
+}
+
+AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
+ return static_cast<AsanThreadContext *>(
+ asanThreadRegistry().GetThreadLocked(tid));
+}
+
+// AsanThread implementation.
+
+AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack,
+ bool detached) {
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
+ AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
+ thread->start_routine_ = start_routine;
+ thread->arg_ = arg;
+ CreateThreadContextArgs args = { thread, stack };
+ asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
+ parent_tid, &args);
+
+ return thread;
+}
+
+void AsanThread::TSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ VReport(1, "T%d TSDDtor\n", context->tid);
+ if (context->thread)
+ context->thread->Destroy();
+}
+
+void AsanThread::Destroy() {
+ int tid = this->tid();
+ VReport(1, "T%d exited\n", tid);
+
+ malloc_storage().CommitBack();
+ if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
+ asanThreadRegistry().FinishThread(tid);
+ FlushToDeadThreadStats(&stats_);
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ DeleteFakeStack(tid);
+ uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
+ UnmapOrDie(this, size);
+ DTLS_Destroy();
+}
+
+// We want to create the FakeStack lazyly on the first use, but not eralier
+// than the stack size is known and the procedure has to be async-signal safe.
+FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
+ uptr stack_size = this->stack_size();
+ if (stack_size == 0) // stack_size is not yet available, don't use FakeStack.
+ return 0;
+ uptr old_val = 0;
+ // fake_stack_ has 3 states:
+ // 0 -- not initialized
+ // 1 -- being initialized
+ // ptr -- initialized
+ // This CAS checks if the state was 0 and if so changes it to state 1,
+ // if that was successful, it initializes the pointer.
+ if (atomic_compare_exchange_strong(
+ reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
+ memory_order_relaxed)) {
+ uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
+ CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
+ stack_size_log =
+ Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
+ stack_size_log =
+ Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
+ fake_stack_ = FakeStack::Create(stack_size_log);
+ SetTLSFakeStack(fake_stack_);
+ return fake_stack_;
+ }
+ return 0;
+}
+
+void AsanThread::Init() {
+ fake_stack_ = 0; // Will be initialized lazily if needed.
+ CHECK_EQ(this->stack_size(), 0U);
+ SetThreadStackAndTls();
+ CHECK_GT(this->stack_size(), 0U);
+ CHECK(AddrIsInMem(stack_bottom_));
+ CHECK(AddrIsInMem(stack_top_ - 1));
+ ClearShadowForThreadStackAndTLS();
+ int local = 0;
+ VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
+ (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
+ &local);
+ AsanPlatformThreadInit();
+}
+
+thread_return_t AsanThread::ThreadStart(
+ uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
+ Init();
+ asanThreadRegistry().StartThread(tid(), os_id, 0);
+ if (signal_thread_is_registered)
+ atomic_store(signal_thread_is_registered, 1, memory_order_release);
+
+ if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+
+ if (!start_routine_) {
+ // start_routine_ == 0 if we're on the main thread or on one of the
+ // OS X libdispatch worker threads. But nobody is supposed to call
+ // ThreadStart() for the worker threads.
+ CHECK_EQ(tid(), 0);
+ return 0;
+ }
+
+ thread_return_t res = start_routine_(arg_);
+
+ // On POSIX systems we defer this to the TSD destructor. LSan will consider
+ // the thread's memory as non-live from the moment we call Destroy(), even
+ // though that memory might contain pointers to heap objects which will be
+ // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
+ // the TSD destructors have run might cause false positives in LSan.
+ if (!SANITIZER_POSIX)
+ this->Destroy();
+
+ return res;
+}
+
+void AsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size_, &tls_begin_,
+ &tls_size);
+ stack_top_ = stack_bottom_ + stack_size_;
+ tls_end_ = tls_begin_ + tls_size;
+
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+}
+
+void AsanThread::ClearShadowForThreadStackAndTLS() {
+ PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
+ if (tls_begin_ != tls_end_)
+ PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
+}
+
+bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
+ StackFrameAccess *access) {
+ uptr bottom = 0;
+ if (AddrIsInStack(addr)) {
+ bottom = stack_bottom();
+ } else if (has_fake_stack()) {
+ bottom = fake_stack()->AddrIsInFakeStack(addr);
+ CHECK(bottom);
+ access->offset = addr - bottom;
+ access->frame_pc = ((uptr*)bottom)[2];
+ access->frame_descr = (const char *)((uptr*)bottom)[1];
+ return true;
+ }
+ uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // 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--;
+ }
+
+ while (shadow_ptr >= shadow_bottom &&
+ *shadow_ptr == kAsanStackLeftRedzoneMagic) {
+ shadow_ptr--;
+ }
+
+ if (shadow_ptr < shadow_bottom) {
+ return false;
+ }
+
+ uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
+ CHECK(ptr[0] == kCurrentStackFrameMagic);
+ access->offset = addr - (uptr)ptr;
+ access->frame_pc = ptr[2];
+ access->frame_descr = (const char*)ptr[1];
+ return true;
+}
+
+static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
+ void *addr) {
+ AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
+ AsanThread *t = tctx->thread;
+ if (!t) return false;
+ if (t->AddrIsInStack((uptr)addr)) return true;
+ if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
+ return true;
+ return false;
+}
+
+AsanThread *GetCurrentThread() {
+ AsanThreadContext *context =
+ reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+ if (!context) {
+ if (SANITIZER_ANDROID) {
+ // On Android, libc constructor is called _after_ asan_init, and cleans up
+ // TSD. Try to figure out if this is still the main thread by the stack
+ // address. We are not entirely sure that we have correct main thread
+ // limits, so only do this magic on Android, and only if the found thread
+ // is the main thread.
+ AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
+ if (ThreadStackContainsAddress(tctx, &context)) {
+ SetCurrentThread(tctx->thread);
+ return tctx->thread;
+ }
+ }
+ return 0;
+ }
+ return context->thread;
+}
+
+void SetCurrentThread(AsanThread *t) {
+ CHECK(t->context());
+ VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
+ (void *)GetThreadSelf());
+ // Make sure we do not reset the current AsanThread.
+ CHECK_EQ(0, AsanTSDGet());
+ AsanTSDSet(t->context());
+ CHECK_EQ(t->context(), AsanTSDGet());
+}
+
+u32 GetCurrentTidOrInvalid() {
+ AsanThread *t = GetCurrentThread();
+ return t ? t->tid() : kInvalidTid;
+}
+
+AsanThread *FindThreadByStackAddress(uptr addr) {
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
+ asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
+ (void *)addr));
+ return tctx ? tctx->thread : 0;
+}
+
+void EnsureMainThreadIDIsCorrect() {
+ AsanThreadContext *context =
+ reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+ if (context && (context->tid == 0))
+ context->os_id = GetTid();
+}
+
+__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
+ __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+ __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+ if (!context) return 0;
+ return context->thread;
+}
+} // namespace __asan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (!t) return false;
+ *stack_begin = t->stack_bottom();
+ *stack_end = t->stack_top();
+ *tls_begin = t->tls_begin();
+ *tls_end = t->tls_end();
+ // ASan doesn't keep allocator caches in TLS, so these are unused.
+ *cache_begin = 0;
+ *cache_end = 0;
+ return true;
+}
+
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (t && t->has_fake_stack())
+ t->fake_stack()->ForEachFakeFrame(callback, arg);
+}
+
+void LockThreadRegistry() {
+ __asan::asanThreadRegistry().Lock();
+}
+
+void UnlockThreadRegistry() {
+ __asan::asanThreadRegistry().Unlock();
+}
+
+void EnsureMainThreadIDIsCorrect() {
+ __asan::EnsureMainThreadIDIsCorrect();
+}
+} // namespace __lsan
diff --git a/contrib/compiler-rt/lib/asan/asan_thread.h b/contrib/compiler-rt/lib/asan/asan_thread.h
new file mode 100644
index 000000000000..9da136c87ef1
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_thread.h
@@ -0,0 +1,187 @@
+//===-- asan_thread.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_thread.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_THREAD_H
+#define ASAN_THREAD_H
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_fake_stack.h"
+#include "asan_stats.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+namespace __asan {
+
+const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
+const u32 kMaxNumberOfThreads = (1 << 22); // 4M
+
+class AsanThread;
+
+// These objects are created for every thread and are never deleted,
+// so we can find them by tid even if the thread is long dead.
+class AsanThreadContext : public ThreadContextBase {
+ public:
+ explicit AsanThreadContext(int tid)
+ : ThreadContextBase(tid),
+ announced(false),
+ destructor_iterations(kPthreadDestructorIterations),
+ stack_id(0),
+ thread(0) {
+ }
+ bool announced;
+ u8 destructor_iterations;
+ u32 stack_id;
+ AsanThread *thread;
+
+ void OnCreated(void *arg);
+ void OnFinished();
+};
+
+// AsanThreadContext objects are never freed, so we need many of them.
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
+
+// AsanThread are stored in TSD and destroyed when the thread dies.
+class AsanThread {
+ public:
+ static AsanThread *Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack, bool detached);
+ static void TSDDtor(void *tsd);
+ void Destroy();
+
+ void Init(); // Should be called from the thread itself.
+ thread_return_t ThreadStart(uptr os_id,
+ atomic_uintptr_t *signal_thread_is_registered);
+
+ uptr stack_top() { return stack_top_; }
+ uptr stack_bottom() { return stack_bottom_; }
+ uptr stack_size() { return stack_size_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ u32 tid() { return context_->tid; }
+ AsanThreadContext *context() { return context_; }
+ void set_context(AsanThreadContext *context) { context_ = context; }
+
+ struct StackFrameAccess {
+ uptr offset;
+ uptr frame_pc;
+ const char *frame_descr;
+ };
+ bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
+
+ bool AddrIsInStack(uptr addr) {
+ return addr >= stack_bottom_ && addr < stack_top_;
+ }
+
+ void DeleteFakeStack(int tid) {
+ if (!fake_stack_) return;
+ FakeStack *t = fake_stack_;
+ fake_stack_ = 0;
+ SetTLSFakeStack(0);
+ t->Destroy(tid);
+ }
+
+ bool has_fake_stack() {
+ return (reinterpret_cast<uptr>(fake_stack_) > 1);
+ }
+
+ FakeStack *fake_stack() {
+ if (!__asan_option_detect_stack_use_after_return)
+ return 0;
+ if (!has_fake_stack())
+ return AsyncSignalSafeLazyInitFakeStack();
+ return fake_stack_;
+ }
+
+ // True is this thread is currently unwinding stack (i.e. collecting a stack
+ // trace). Used to prevent deadlocks on platforms where libc unwinder calls
+ // malloc internally. See PR17116 for more details.
+ 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 ClearShadowForThreadStackAndTLS();
+ FakeStack *AsyncSignalSafeLazyInitFakeStack();
+
+ AsanThreadContext *context_;
+ thread_callback_t start_routine_;
+ void *arg_;
+ uptr stack_top_;
+ uptr stack_bottom_;
+ // stack_size_ == stack_top_ - stack_bottom_;
+ // It needs to be set in a async-signal-safe manner.
+ uptr stack_size_;
+ uptr tls_begin_;
+ uptr tls_end_;
+
+ FakeStack *fake_stack_;
+ AsanThreadLocalMallocStorage malloc_storage_;
+ AsanStats stats_;
+ bool unwinding_;
+ bool in_deadly_signal_;
+};
+
+// ScopedUnwinding is a scope for stacktracing member of a context
+class ScopedUnwinding {
+ public:
+ explicit ScopedUnwinding(AsanThread *t) : thread(t) {
+ t->setUnwinding(true);
+ }
+ ~ScopedUnwinding() { thread->setUnwinding(false); }
+
+ private:
+ 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();
+
+// Must be called under ThreadRegistryLock.
+AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
+
+// Get the current thread. May return 0.
+AsanThread *GetCurrentThread();
+void SetCurrentThread(AsanThread *t);
+u32 GetCurrentTidOrInvalid();
+AsanThread *FindThreadByStackAddress(uptr addr);
+
+// Used to handle fork().
+void EnsureMainThreadIDIsCorrect();
+} // namespace __asan
+
+#endif // ASAN_THREAD_H
diff --git a/contrib/compiler-rt/lib/asan/asan_win.cc b/contrib/compiler-rt/lib/asan/asan_win.cc
new file mode 100644
index 000000000000..693f0bcdee8e
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_win.cc
@@ -0,0 +1,168 @@
+//===-- asan_win.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.
+//
+// Windows-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+#include <windows.h>
+
+#include <dbghelp.h>
+#include <stdlib.h>
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_report.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+
+extern "C" {
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_should_detect_stack_use_after_return() {
+ __asan_init();
+ return __asan_option_detect_stack_use_after_return;
+ }
+}
+
+namespace __asan {
+
+// ---------------------- TSD ---------------- {{{1
+static bool tsd_key_inited = false;
+
+static __declspec(thread) void *fake_tsd = 0;
+
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ // FIXME: we're ignoring the destructor for now.
+ tsd_key_inited = true;
+}
+
+void *AsanTSDGet() {
+ CHECK(tsd_key_inited);
+ return fake_tsd;
+}
+
+void AsanTSDSet(void *tsd) {
+ CHECK(tsd_key_inited);
+ fake_tsd = tsd;
+}
+
+void PlatformTSDDtor(void *tsd) {
+ AsanThread::TSDDtor(tsd);
+}
+// ---------------------- Various stuff ---------------- {{{1
+void DisableReexec() {
+ // No need to re-exec on Windows.
+}
+
+void MaybeReexec() {
+ // No need to re-exec on Windows.
+}
+
+void *AsanDoesNotSupportStaticLinkage() {
+#if defined(_DEBUG)
+#error Please build the runtime with a non-debug CRT: /MD or /MT
+#endif
+ return 0;
+}
+
+void AsanCheckDynamicRTPrereqs() {}
+
+void AsanCheckIncompatibleRT() {}
+
+void AsanPlatformThreadInit() {
+ // Nothing here for now.
+}
+
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ UNIMPLEMENTED();
+}
+
+void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+ UNIMPLEMENTED();
+}
+
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
+ CONTEXT *context_record = (CONTEXT*)context;
+
+ uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+ uptr bp = (uptr)context_record->Rbp;
+ uptr sp = (uptr)context_record->Rsp;
+#else
+ uptr bp = (uptr)context_record->Ebp;
+ uptr sp = (uptr)context_record->Esp;
+#endif
+ uptr access_addr = exception_record->ExceptionInformation[1];
+
+ return SignalContext(context, access_addr, pc, sp, bp);
+}
+
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+ const char *description =
+ (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "access-violation"
+ : "in-page-error";
+ SignalContext sig = SignalContext::Create(exception_record, context);
+ ReportSIGSEGV(description, sig);
+ }
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ return default_seh_handler(info);
+}
+
+// We want to install our own exception handler (EH) to print helpful reports
+// on access violations and whatnot. Unfortunately, the CRT initializers assume
+// they are run before any user code and drop any previously-installed EHs on
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module. This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+ // We should only store the previous handler if it's not our own handler in
+ // order to avoid loops in the EH chain.
+ auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+ if (prev_seh_handler != &SEHHandler)
+ default_seh_handler = prev_seh_handler;
+ return 0;
+}
+
+#if !ASAN_DYNAMIC
+// Put a pointer to __asan_set_seh_filter at the end of the global list
+// of C initializers, after the default EH is set by the CRT.
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+static __declspec(allocate(".CRT$XIZ"))
+ int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
+
+} // namespace __asan
+
+#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc
new file mode 100644
index 000000000000..5d39e33096a8
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc
@@ -0,0 +1,412 @@
+//===-- asan_win_dll_thunk.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.
+//
+// This file defines a family of thunks that should be statically linked into
+// the DLLs that have ASan instrumentation in order to delegate the calls to the
+// shared runtime that lives in the main binary.
+// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
+// details.
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dll_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DLL_THUNK
+#include "asan_init_version.h"
+#include "interception/interception.h"
+
+// ---------- Function interception helper functions and macros ----------- {{{1
+extern "C" {
+void *__stdcall GetModuleHandleA(const char *module_name);
+void *__stdcall GetProcAddress(void *module, const char *proc_name);
+void abort();
+}
+
+static void *getRealProcAddressOrDie(const char *name) {
+ void *ret = GetProcAddress(GetModuleHandleA(0), name);
+ if (!ret)
+ abort();
+ return ret;
+}
+
+// We need to intercept some functions (e.g. ASan interface, memory allocator --
+// let's call them "hooks") exported by the DLL thunk and forward the hooks to
+// the runtime in the main module.
+// However, we don't want to keep two lists of these hooks.
+// To avoid that, the list of hooks should be defined using the
+// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
+// at once by calling INTERCEPT_HOOKS().
+
+// Use macro+template magic to automatically generate the list of hooks.
+// Each hook at line LINE defines a template class with a static
+// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
+// The default implementation of FunctionInterceptor<LINE> is to call
+// the Execute() method corresponding to the previous line.
+template<int LINE>
+struct FunctionInterceptor {
+ static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
+};
+
+// There shouldn't be any hooks with negative definition line number.
+template<>
+struct FunctionInterceptor<0> {
+ static void Execute() {}
+};
+
+#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
+ template<> struct FunctionInterceptor<__LINE__> { \
+ static void Execute() { \
+ void *wrapper = getRealProcAddressOrDie(main_function); \
+ if (!__interception::OverrideFunction((uptr)dll_function, \
+ (uptr)wrapper, 0)) \
+ abort(); \
+ FunctionInterceptor<__LINE__-1>::Execute(); \
+ } \
+ };
+
+// Special case of hooks -- ASan own interface functions. Those are only called
+// after __asan_init, thus an empty implementation is sufficient.
+#define INTERFACE_FUNCTION(name) \
+ extern "C" __declspec(noinline) void name() { \
+ volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
+ __debugbreak(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name)
+
+// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
+#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
+
+// We can't define our own version of strlen etc. because that would lead to
+// link-time or even type mismatch errors. Instead, we can declare a function
+// just to be able to get its address. Me may miss the first few calls to the
+// functions since it can be called before __asan_init, but that would lead to
+// false negatives in the startup code before user's global initializers, which
+// isn't a big deal.
+#define INTERCEPT_LIBRARY_FUNCTION(name) \
+ extern "C" void name(); \
+ INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
+
+// Disable compiler warnings that show up if we declare our own version
+// of a compiler intrinsic (e.g. strlen).
+#pragma warning(disable: 4391)
+#pragma warning(disable: 4392)
+
+static void InterceptHooks();
+// }}}
+
+// ---------- Function wrapping helpers ----------------------------------- {{{1
+#define WRAP_V_V(name) \
+ extern "C" void name() { \
+ typedef void (*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_W(name) \
+ extern "C" void name(void *arg) { \
+ typedef void (*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WW(name) \
+ extern "C" void name(void *arg1, void *arg2) { \
+ typedef void (*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WWW(name) \
+ extern "C" void name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_V(name) \
+ extern "C" void *name() { \
+ typedef void *(*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_W(name) \
+ extern "C" void *name(void *arg) { \
+ typedef void *(*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WW(name) \
+ extern "C" void *name(void *arg1, void *arg2) { \
+ typedef void *(*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
+ typedef void *(*fntype)(void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5, void *arg6) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+// }}}
+
+// ----------------- ASan own interface functions --------------------
+// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
+// want to call it in the __asan_init interceptor.
+WRAP_W_V(__asan_should_detect_stack_use_after_return)
+
+extern "C" {
+ int __asan_option_detect_stack_use_after_return;
+
+ // Manually wrap __asan_init as we need to initialize
+ // __asan_option_detect_stack_use_after_return afterwards.
+ void __asan_init() {
+ typedef void (*fntype)();
+ static fntype fn = 0;
+ // __asan_init is expected to be called by only one thread.
+ if (fn) return;
+
+ fn = (fntype)getRealProcAddressOrDie(__asan_init_name);
+ fn();
+ __asan_option_detect_stack_use_after_return =
+ (__asan_should_detect_stack_use_after_return() != 0);
+
+ InterceptHooks();
+ }
+}
+
+INTERFACE_FUNCTION(__asan_handle_no_return)
+
+INTERFACE_FUNCTION(__asan_report_store1)
+INTERFACE_FUNCTION(__asan_report_store2)
+INTERFACE_FUNCTION(__asan_report_store4)
+INTERFACE_FUNCTION(__asan_report_store8)
+INTERFACE_FUNCTION(__asan_report_store16)
+INTERFACE_FUNCTION(__asan_report_store_n)
+
+INTERFACE_FUNCTION(__asan_report_load1)
+INTERFACE_FUNCTION(__asan_report_load2)
+INTERFACE_FUNCTION(__asan_report_load4)
+INTERFACE_FUNCTION(__asan_report_load8)
+INTERFACE_FUNCTION(__asan_report_load16)
+INTERFACE_FUNCTION(__asan_report_load_n)
+
+INTERFACE_FUNCTION(__asan_store1)
+INTERFACE_FUNCTION(__asan_store2)
+INTERFACE_FUNCTION(__asan_store4)
+INTERFACE_FUNCTION(__asan_store8)
+INTERFACE_FUNCTION(__asan_store16)
+INTERFACE_FUNCTION(__asan_storeN)
+
+INTERFACE_FUNCTION(__asan_load1)
+INTERFACE_FUNCTION(__asan_load2)
+INTERFACE_FUNCTION(__asan_load4)
+INTERFACE_FUNCTION(__asan_load8)
+INTERFACE_FUNCTION(__asan_load16)
+INTERFACE_FUNCTION(__asan_loadN)
+
+INTERFACE_FUNCTION(__asan_memcpy);
+INTERFACE_FUNCTION(__asan_memset);
+INTERFACE_FUNCTION(__asan_memmove);
+
+INTERFACE_FUNCTION(__asan_register_globals)
+INTERFACE_FUNCTION(__asan_unregister_globals)
+
+INTERFACE_FUNCTION(__asan_before_dynamic_init)
+INTERFACE_FUNCTION(__asan_after_dynamic_init)
+
+INTERFACE_FUNCTION(__asan_poison_stack_memory)
+INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
+
+INTERFACE_FUNCTION(__asan_poison_memory_region)
+INTERFACE_FUNCTION(__asan_unpoison_memory_region)
+
+INTERFACE_FUNCTION(__asan_address_is_poisoned)
+INTERFACE_FUNCTION(__asan_region_is_poisoned)
+
+INTERFACE_FUNCTION(__asan_get_current_fake_stack)
+INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
+
+INTERFACE_FUNCTION(__asan_stack_malloc_0)
+INTERFACE_FUNCTION(__asan_stack_malloc_1)
+INTERFACE_FUNCTION(__asan_stack_malloc_2)
+INTERFACE_FUNCTION(__asan_stack_malloc_3)
+INTERFACE_FUNCTION(__asan_stack_malloc_4)
+INTERFACE_FUNCTION(__asan_stack_malloc_5)
+INTERFACE_FUNCTION(__asan_stack_malloc_6)
+INTERFACE_FUNCTION(__asan_stack_malloc_7)
+INTERFACE_FUNCTION(__asan_stack_malloc_8)
+INTERFACE_FUNCTION(__asan_stack_malloc_9)
+INTERFACE_FUNCTION(__asan_stack_malloc_10)
+
+INTERFACE_FUNCTION(__asan_stack_free_0)
+INTERFACE_FUNCTION(__asan_stack_free_1)
+INTERFACE_FUNCTION(__asan_stack_free_2)
+INTERFACE_FUNCTION(__asan_stack_free_4)
+INTERFACE_FUNCTION(__asan_stack_free_5)
+INTERFACE_FUNCTION(__asan_stack_free_6)
+INTERFACE_FUNCTION(__asan_stack_free_7)
+INTERFACE_FUNCTION(__asan_stack_free_8)
+INTERFACE_FUNCTION(__asan_stack_free_9)
+INTERFACE_FUNCTION(__asan_stack_free_10)
+
+// FIXME: we might want to have a sanitizer_win_dll_thunk?
+INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_cov)
+INTERFACE_FUNCTION(__sanitizer_cov_dump)
+INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
+INTERFACE_FUNCTION(__sanitizer_cov_init)
+INTERFACE_FUNCTION(__sanitizer_cov_module_init)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
+INTERFACE_FUNCTION(__sanitizer_cov_with_check)
+INTERFACE_FUNCTION(__sanitizer_free_hook)
+INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
+INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
+INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
+INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
+INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
+INTERFACE_FUNCTION(__sanitizer_get_heap_size)
+INTERFACE_FUNCTION(__sanitizer_get_ownership)
+INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
+INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
+INTERFACE_FUNCTION(__sanitizer_malloc_hook)
+INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
+INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
+INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
+INTERFACE_FUNCTION(__sanitizer_ptr_sub)
+INTERFACE_FUNCTION(__sanitizer_report_error_summary)
+INTERFACE_FUNCTION(__sanitizer_reset_coverage)
+INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
+INTERFACE_FUNCTION(__sanitizer_set_death_callback)
+INTERFACE_FUNCTION(__sanitizer_set_report_path)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
+INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
+
+// TODO(timurrrr): Add more interface functions on the as-needed basis.
+
+// ----------------- Memory allocation functions ---------------------
+WRAP_V_W(free)
+WRAP_V_WW(_free_dbg)
+
+WRAP_W_W(malloc)
+WRAP_W_WWWW(_malloc_dbg)
+
+WRAP_W_WW(calloc)
+WRAP_W_WWWWW(_calloc_dbg)
+WRAP_W_WWW(_calloc_impl)
+
+WRAP_W_WW(realloc)
+WRAP_W_WWW(_realloc_dbg)
+WRAP_W_WWW(_recalloc)
+
+WRAP_W_W(_msize)
+WRAP_W_W(_expand)
+WRAP_W_W(_expand_dbg)
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
+// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
+
+INTERCEPT_LIBRARY_FUNCTION(atoi);
+INTERCEPT_LIBRARY_FUNCTION(atol);
+INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
+
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+
+INTERCEPT_LIBRARY_FUNCTION(frexp);
+INTERCEPT_LIBRARY_FUNCTION(longjmp);
+INTERCEPT_LIBRARY_FUNCTION(memchr);
+INTERCEPT_LIBRARY_FUNCTION(memcmp);
+INTERCEPT_LIBRARY_FUNCTION(memcpy);
+INTERCEPT_LIBRARY_FUNCTION(memmove);
+INTERCEPT_LIBRARY_FUNCTION(memset);
+INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strchr);
+INTERCEPT_LIBRARY_FUNCTION(strcmp);
+INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strlen);
+INTERCEPT_LIBRARY_FUNCTION(strncat);
+INTERCEPT_LIBRARY_FUNCTION(strncmp);
+INTERCEPT_LIBRARY_FUNCTION(strncpy);
+INTERCEPT_LIBRARY_FUNCTION(strnlen);
+INTERCEPT_LIBRARY_FUNCTION(strtol);
+INTERCEPT_LIBRARY_FUNCTION(wcslen);
+
+// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
+// is defined.
+void InterceptHooks() {
+ INTERCEPT_HOOKS();
+ INTERCEPT_FUNCTION(_except_handler4);
+}
+
+// We want to call __asan_init before C/C++ initializers/constructors are
+// executed, otherwise functions like memset might be invoked.
+// For some strange reason, merely linking in asan_preinit.cc doesn't work
+// as the callback is never called... Is link.exe doing something too smart?
+
+// In DLLs, the callbacks are expected to return 0,
+// otherwise CRT initialization fails.
+static int call_asan_init() {
+ __asan_init();
+ return 0;
+}
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
+
+#endif // ASAN_DLL_THUNK
diff --git a/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
new file mode 100644
index 000000000000..19456141c1ec
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,119 @@
+//===-- asan_win_uar_thunk.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.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL RTL.
+//
+// This includes:
+// - forwarding the detect_stack_use_after_return runtime option
+// - installing a custom SEH handler
+//
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+#include <windows.h>
+#include <psapi.h>
+
+extern "C" {
+////////////////////////////////////////////////////////////////////////////////
+// Define a copy of __asan_option_detect_stack_use_after_return that should be
+// used when linking an MD runtime with a set of object files on Windows.
+//
+// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
+// so normally we would just dllimport it. Unfortunately, the dllimport
+// attribute adds __imp_ prefix to the symbol name of a variable.
+// Since in general we don't know if a given TU is going to be used
+// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
+// just to work around this issue, let's clone the a variable that is
+// constant after initialization anyways.
+__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
+int __asan_option_detect_stack_use_after_return =
+ __asan_should_detect_stack_use_after_return();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does.
+// To work around this, for each DLL we schedule a call to
+// UnregisterGlobalsInRange atexit() specifying the address range of the DLL
+// image to unregister globals in that range. We don't do the same
+// for the main module (.exe) as the asan_globals.cc allocator is destroyed
+// by the time UnregisterGlobalsInRange is executed.
+// See PR22545 for the details.
+namespace __asan {
+__declspec(dllimport)
+void UnregisterGlobalsInRange(void *beg, void *end);
+}
+
+namespace {
+void *this_module_base, *this_module_end;
+
+void UnregisterGlobals() {
+ __asan::UnregisterGlobalsInRange(this_module_base, this_module_end);
+}
+
+int ScheduleUnregisterGlobals() {
+ HMODULE this_module = 0;
+ // Increments the reference counter of the DLL module, so need to call
+ // FreeLibrary later.
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ (LPCTSTR)&UnregisterGlobals, &this_module))
+ return 1;
+
+ // Skip the main module.
+ if (this_module == GetModuleHandle(0))
+ return 0;
+
+ MODULEINFO mi;
+ bool success =
+ GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi));
+ if (!FreeLibrary(this_module))
+ return 2;
+ if (!success)
+ return 3;
+
+ this_module_base = mi.lpBaseOfDll;
+ this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage;
+
+ return atexit(UnregisterGlobals);
+}
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// ASan SEH handling.
+extern "C" __declspec(dllimport) int __asan_set_seh_filter();
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+
+///////////////////////////////////////////////////////////////////////////////
+// We schedule some work at start-up by placing callbacks to our code to the
+// list of CRT C initializers.
+//
+// First, declare sections we'll be using:
+#pragma section(".CRT$XID", long, read) // NOLINT
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+
+// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized
+// (.CRT$XIC) but before the C++ constructors (.CRT$XCA).
+__declspec(allocate(".CRT$XID"))
+static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
+
+// We need to set the ASan-specific SEH handler at the end of CRT initialization
+// of each module (see also asan_win.cc).
+//
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+extern "C" __declspec(allocate(".CRT$XIZ"))
+int (*__asan_seh_interceptor)() = SetSEHFilter;
+
+#endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/contrib/compiler-rt/lib/asan/scripts/asan_device_setup b/contrib/compiler-rt/lib/asan/scripts/asan_device_setup
new file mode 100755
index 000000000000..104e07b722ca
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/scripts/asan_device_setup
@@ -0,0 +1,344 @@
+#!/bin/bash
+#===- lib/asan/scripts/asan_device_setup -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+# Prepare Android device to run ASan applications.
+#
+#===------------------------------------------------------------------------===#
+
+set -e
+
+HERE="$(cd "$(dirname "$0")" && pwd)"
+
+revert=no
+extra_options=
+device=
+lib=
+use_su=0
+
+function usage {
+ echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
+ echo " --revert: Uninstall ASan from the device."
+ echo " --lib: Path to ASan runtime library."
+ echo " --extra-options: Extra ASAN_OPTIONS."
+ echo " --device: Install to the given device. Use 'adb devices' to find"
+ echo " device-id."
+ echo " --use-su: Use 'su -c' prefix for every adb command instead of using"
+ echo " 'adb root' once."
+ echo
+ exit 1
+}
+
+function adb_push {
+ if [ $use_su -eq 0 ]; then
+ $ADB push "$1" "$2"
+ else
+ local FILENAME=$(basename $1)
+ $ADB push "$1" "/data/local/tmp/$FILENAME"
+ $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null
+ $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\""
+ $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\""
+ fi
+}
+
+function adb_remount {
+ if [ $use_su -eq 0 ]; then
+ $ADB remount
+ else
+ local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1`
+ if [ "$STORAGE" != "" ]; then
+ echo Remounting $STORAGE at /system
+ $ADB shell su -c "mount -o remount,rw $STORAGE /system"
+ else
+ echo Failed to get storage device name for "/system" mount point
+ fi
+ fi
+}
+
+function adb_shell {
+ if [ $use_su -eq 0 ]; then
+ $ADB shell $@
+ else
+ $ADB shell su -c "$*"
+ fi
+}
+
+function adb_root {
+ if [ $use_su -eq 0 ]; then
+ $ADB root
+ fi
+}
+
+function adb_wait_for_device {
+ $ADB wait-for-device
+}
+
+function adb_pull {
+ if [ $use_su -eq 0 ]; then
+ $ADB pull "$1" "$2"
+ else
+ local FILENAME=$(basename $1)
+ $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null
+ $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" &&
+ $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\""
+ fi
+}
+
+function get_device_arch { # OUTVAR
+ local _outvar=$1
+ local _ABI=$(adb_shell getprop ro.product.cpu.abi)
+ local _ARCH=
+ if [[ $_ABI == x86* ]]; then
+ _ARCH=i686
+ elif [[ $_ABI == armeabi* ]]; then
+ _ARCH=arm
+ else
+ echo "Unrecognized device ABI: $_ABI"
+ exit 1
+ fi
+ eval $_outvar=\$_ARCH
+}
+
+while [[ $# > 0 ]]; do
+ case $1 in
+ --revert)
+ revert=yes
+ ;;
+ --extra-options)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--extra-options requires an argument."
+ exit 1
+ fi
+ extra_options="$1"
+ ;;
+ --lib)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--lib requires an argument."
+ exit 1
+ fi
+ lib="$1"
+ ;;
+ --device)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--device requires an argument."
+ exit 1
+ fi
+ device="$1"
+ ;;
+ --use-su)
+ use_su=1
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+ADB=${ADB:-adb}
+if [[ x$device != x ]]; then
+ ADB="$ADB -s $device"
+fi
+
+if [ $use_su -eq 1 ]; then
+ # Test if 'su' is present on the device
+ SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'`
+ if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then
+ echo "ERROR: Cannot use 'su -c':"
+ echo "$ adb shell su -c \"echo foo\""
+ echo $SU_TEST_OUT
+ echo "Check that 'su' binary is correctly installed on the device or omit"
+ echo " --use-su flag"
+ exit 1
+ fi
+fi
+
+echo '>> Remounting /system rw'
+adb_wait_for_device
+adb_root
+adb_wait_for_device
+adb_remount
+adb_wait_for_device
+
+get_device_arch ARCH
+echo "Target architecture: $ARCH"
+ASAN_RT="libclang_rt.asan-$ARCH-android.so"
+
+if [[ x$revert == xyes ]]; then
+ echo '>> Uninstalling ASan'
+
+ if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
+ echo '>> Pre-L device detected.'
+ adb_shell mv /system/bin/app_process.real /system/bin/app_process
+ adb_shell rm /system/bin/asanwrapper
+ else
+ adb_shell rm /system/bin/app_process.wrap
+ adb_shell rm /system/bin/asanwrapper
+ adb_shell rm /system/bin/app_process
+ adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
+ fi
+
+ echo '>> Restarting shell'
+ adb_shell stop
+ adb_shell start
+
+ # Remove the library on the last step to give a chance to the 'su' binary to
+ # be executed without problem.
+ adb_shell rm /system/lib/$ASAN_RT
+
+ echo '>> Done'
+ exit 0
+fi
+
+if [[ -d "$lib" ]]; then
+ ASAN_RT_PATH="$lib"
+elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
+ ASAN_RT_PATH=$(dirname "$lib")
+elif [[ -f "$HERE/$ASAN_RT" ]]; then
+ ASAN_RT_PATH="$HERE"
+elif [[ $(basename "$HERE") == "bin" ]]; then
+ # We could be in the toolchain's base directory.
+ # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux.
+ P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
+ if [[ -n "$P" ]]; then
+ ASAN_RT_PATH="$(dirname "$P")"
+ fi
+fi
+
+if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
+ echo ">> ASan runtime library not found"
+ exit 1
+fi
+
+TMPDIRBASE=$(mktemp -d)
+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
+ echo '>> Old-style ASan installation detected. Reverting.'
+ adb_shell mv /system/bin/app_process.real /system/bin/app_process
+ fi
+
+ echo '>> Pre-L device detected. Setting up app_process symlink.'
+ adb_shell mv /system/bin/app_process /system/bin/app_process32
+ adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
+fi
+
+echo '>> Copying files from the device'
+adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true
+adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
+adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+cp -r "$TMPDIROLD" "$TMPDIR"
+
+if [[ -f "$TMPDIR/app_process.wrap" ]]; then
+ echo ">> Previous installation detected"
+else
+ echo ">> New installation"
+fi
+
+echo '>> Generating wrappers'
+
+cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
+
+# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup,
+# which may or may not be a real bug (probably not).
+ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0
+
+# On Android-L not allowing user segv handler breaks some applications.
+if [[ PRE_L -eq 0 ]]; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
+fi
+
+if [[ x$extra_options != x ]] ; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
+fi
+
+# Zygote wrapper.
+cat <<EOF >"$TMPDIR/app_process.wrap"
+#!/system/bin/sh-from-zygote
+ASAN_OPTIONS=$ASAN_OPTIONS \\
+LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\
+exec /system/bin/app_process32 \$@
+
+EOF
+
+# General command-line tool wrapper (use for anything that's not started as
+# zygote).
+cat <<EOF >"$TMPDIR/asanwrapper"
+#!/system/bin/sh
+LD_PRELOAD=$ASAN_RT \\
+exec \$@
+
+EOF
+
+if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
+ echo '>> Pushing files to the device'
+ adb_push "$TMPDIR/$ASAN_RT" /system/lib/
+ adb_push "$TMPDIR/app_process.wrap" /system/bin
+ adb_push "$TMPDIR/asanwrapper" /system/bin
+
+ adb_shell rm /system/bin/app_process
+ adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
+
+ adb_shell chown root.shell \
+ /system/lib/"$ASAN_RT" \
+ /system/bin/app_process.wrap \
+ /system/bin/asanwrapper
+ adb_shell chmod 644 \
+ /system/lib/"$ASAN_RT"
+ adb_shell chmod 755 \
+ /system/bin/app_process.wrap \
+ /system/bin/asanwrapper
+
+ # Make SELinux happy by keeping app_process wrapper and the shell
+ # it runs on in zygote domain.
+ ENFORCING=0
+ if adb_shell getenforce | grep Enforcing >/dev/null; then
+ # Sometimes shell is not allowed to change file contexts.
+ # Temporarily switch to permissive.
+ ENFORCING=1
+ adb_shell setenforce 0
+ fi
+
+ adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
+
+ if [[ PRE_L -eq 1 ]]; then
+ CTX=u:object_r:system_file:s0
+ else
+ CTX=u:object_r:zygote_exec:s0
+ fi
+ adb_shell chcon $CTX \
+ /system/bin/sh-from-zygote \
+ /system/bin/app_process.wrap \
+ /system/bin/app_process32
+
+ if [ $ENFORCING == 1 ]; then
+ adb_shell setenforce 1
+ fi
+
+ echo '>> Restarting shell (asynchronous)'
+ adb_shell stop
+ adb_shell start
+
+ echo '>> Please wait until the device restarts'
+else
+ echo '>> Device is up to date'
+fi
+
+rm -r "$TMPDIRBASE"
diff --git a/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py b/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py
new file mode 100755
index 000000000000..59fceaaed814
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py
@@ -0,0 +1,479 @@
+#!/usr/bin/env python
+#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+import argparse
+import bisect
+import getopt
+import os
+import re
+import subprocess
+import sys
+
+symbolizers = {}
+DEBUG = False
+demangle = False
+binutils_prefix = None
+sysroot_path = None
+binary_name_filter = None
+fix_filename_patterns = None
+logfile = sys.stdin
+
+# FIXME: merge the code that calls fix_filename().
+def fix_filename(file_name):
+ if fix_filename_patterns:
+ for path_to_cut in fix_filename_patterns:
+ file_name = re.sub('.*' + path_to_cut, '', file_name)
+ file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
+ file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
+ return file_name
+
+def sysroot_path_filter(binary_name):
+ return sysroot_path + binary_name
+
+def guess_arch(addr):
+ # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
+ if len(addr) > 10:
+ return 'x86_64'
+ else:
+ return 'i386'
+
+class Symbolizer(object):
+ def __init__(self):
+ pass
+
+ def symbolize(self, addr, binary, offset):
+ """Symbolize the given address (pair of binary and offset).
+
+ Overriden in subclasses.
+ Args:
+ addr: virtual address of an instruction.
+ binary: path to executable/shared object containing this instruction.
+ offset: instruction offset in the @binary.
+ Returns:
+ list of strings (one string for each inlined frame) describing
+ the code locations for this instruction (that is, function name, file
+ name, line and column numbers).
+ """
+ return None
+
+
+class LLVMSymbolizer(Symbolizer):
+ def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]):
+ super(LLVMSymbolizer, self).__init__()
+ self.symbolizer_path = symbolizer_path
+ self.default_arch = default_arch
+ self.system = system
+ self.dsym_hints = dsym_hints
+ self.pipe = self.open_llvm_symbolizer()
+
+ def open_llvm_symbolizer(self):
+ cmd = [self.symbolizer_path,
+ '--use-symbol-table=true',
+ '--demangle=%s' % demangle,
+ '--functions=short',
+ '--inlining=true',
+ '--default-arch=%s' % self.default_arch]
+ if self.system == 'Darwin':
+ for hint in self.dsym_hints:
+ cmd.append('--dsym-hint=%s' % hint)
+ if DEBUG:
+ print ' '.join(cmd)
+ try:
+ result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ except OSError:
+ result = None
+ return result
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ if not self.pipe:
+ return None
+ result = []
+ try:
+ symbolizer_input = '"%s" %s' % (binary, offset)
+ if DEBUG:
+ print symbolizer_input
+ print >> self.pipe.stdin, symbolizer_input
+ while True:
+ function_name = self.pipe.stdout.readline().rstrip()
+ if not function_name:
+ break
+ file_name = self.pipe.stdout.readline().rstrip()
+ file_name = fix_filename(file_name)
+ if (not function_name.startswith('??') or
+ not file_name.startswith('??')):
+ # Append only non-trivial frames.
+ result.append('%s in %s %s' % (addr, function_name,
+ file_name))
+ except Exception:
+ result = []
+ if not result:
+ result = None
+ return result
+
+
+def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]):
+ symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
+ if not symbolizer_path:
+ symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH')
+ if not symbolizer_path:
+ # Assume llvm-symbolizer is in PATH.
+ symbolizer_path = 'llvm-symbolizer'
+ return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints)
+
+
+class Addr2LineSymbolizer(Symbolizer):
+ def __init__(self, binary):
+ super(Addr2LineSymbolizer, self).__init__()
+ self.binary = binary
+ self.pipe = self.open_addr2line()
+
+ def open_addr2line(self):
+ addr2line_tool = 'addr2line'
+ if binutils_prefix:
+ addr2line_tool = binutils_prefix + addr2line_tool
+ cmd = [addr2line_tool, '-f']
+ if demangle:
+ cmd += ['--demangle']
+ cmd += ['-e', self.binary]
+ if DEBUG:
+ print ' '.join(cmd)
+ return subprocess.Popen(cmd,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ if self.binary != binary:
+ return None
+ try:
+ print >> self.pipe.stdin, offset
+ function_name = self.pipe.stdout.readline().rstrip()
+ file_name = self.pipe.stdout.readline().rstrip()
+ except Exception:
+ function_name = ''
+ file_name = ''
+ file_name = fix_filename(file_name)
+ return ['%s in %s %s' % (addr, function_name, file_name)]
+
+
+class UnbufferedLineConverter(object):
+ """
+ Wrap a child process that responds to each line of input with one line of
+ output. Uses pty to trick the child into providing unbuffered output.
+ """
+ def __init__(self, args, close_stderr=False):
+ # Local imports so that the script can start on Windows.
+ import pty
+ import termios
+ pid, fd = pty.fork()
+ if pid == 0:
+ # We're the child. Transfer control to command.
+ if close_stderr:
+ dev_null = os.open('/dev/null', 0)
+ os.dup2(dev_null, 2)
+ os.execvp(args[0], args)
+ else:
+ # Disable echoing.
+ attr = termios.tcgetattr(fd)
+ attr[3] = attr[3] & ~termios.ECHO
+ termios.tcsetattr(fd, termios.TCSANOW, attr)
+ # Set up a file()-like interface to the child process
+ self.r = os.fdopen(fd, "r", 1)
+ self.w = os.fdopen(os.dup(fd), "w", 1)
+
+ def convert(self, line):
+ self.w.write(line + "\n")
+ return self.readline()
+
+ def readline(self):
+ return self.r.readline().rstrip()
+
+
+class DarwinSymbolizer(Symbolizer):
+ def __init__(self, addr, binary):
+ super(DarwinSymbolizer, self).__init__()
+ self.binary = binary
+ self.arch = guess_arch(addr)
+ self.open_atos()
+
+ def open_atos(self):
+ if DEBUG:
+ print 'atos -o %s -arch %s' % (self.binary, self.arch)
+ cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
+ self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ if self.binary != binary:
+ return None
+ atos_line = self.atos.convert('0x%x' % int(offset, 16))
+ while "got symbolicator for" in atos_line:
+ atos_line = self.atos.readline()
+ # A well-formed atos response looks like this:
+ # foo(type1, type2) (in object.name) (filename.cc:80)
+ match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
+ if DEBUG:
+ print 'atos_line: ', atos_line
+ if match:
+ function_name = match.group(1)
+ function_name = re.sub('\(.*?\)', '', function_name)
+ file_name = fix_filename(match.group(3))
+ return ['%s in %s %s' % (addr, function_name, file_name)]
+ else:
+ return ['%s in %s' % (addr, atos_line)]
+
+
+# Chain several symbolizers so that if one symbolizer fails, we fall back
+# to the next symbolizer in chain.
+class ChainSymbolizer(Symbolizer):
+ def __init__(self, symbolizer_list):
+ super(ChainSymbolizer, self).__init__()
+ self.symbolizer_list = symbolizer_list
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ for symbolizer in self.symbolizer_list:
+ if symbolizer:
+ result = symbolizer.symbolize(addr, binary, offset)
+ if result:
+ return result
+ return None
+
+ def append_symbolizer(self, symbolizer):
+ self.symbolizer_list.append(symbolizer)
+
+
+def BreakpadSymbolizerFactory(binary):
+ suffix = os.getenv('BREAKPAD_SUFFIX')
+ if suffix:
+ filename = binary + suffix
+ if os.access(filename, os.F_OK):
+ return BreakpadSymbolizer(filename)
+ return None
+
+
+def SystemSymbolizerFactory(system, addr, binary):
+ if system == 'Darwin':
+ return DarwinSymbolizer(addr, binary)
+ elif system == 'Linux':
+ return Addr2LineSymbolizer(binary)
+
+
+class BreakpadSymbolizer(Symbolizer):
+ def __init__(self, filename):
+ super(BreakpadSymbolizer, self).__init__()
+ self.filename = filename
+ lines = file(filename).readlines()
+ self.files = []
+ self.symbols = {}
+ self.address_list = []
+ self.addresses = {}
+ # MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t
+ fragments = lines[0].rstrip().split()
+ self.arch = fragments[2]
+ self.debug_id = fragments[3]
+ self.binary = ' '.join(fragments[4:])
+ self.parse_lines(lines[1:])
+
+ def parse_lines(self, lines):
+ cur_function_addr = ''
+ for line in lines:
+ fragments = line.split()
+ if fragments[0] == 'FILE':
+ assert int(fragments[1]) == len(self.files)
+ self.files.append(' '.join(fragments[2:]))
+ elif fragments[0] == 'PUBLIC':
+ self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:])
+ elif fragments[0] in ['CFI', 'STACK']:
+ pass
+ elif fragments[0] == 'FUNC':
+ cur_function_addr = int(fragments[1], 16)
+ if not cur_function_addr in self.symbols.keys():
+ self.symbols[cur_function_addr] = ' '.join(fragments[4:])
+ else:
+ # Line starting with an address.
+ addr = int(fragments[0], 16)
+ self.address_list.append(addr)
+ # Tuple of symbol address, size, line, file number.
+ self.addresses[addr] = (cur_function_addr,
+ int(fragments[1], 16),
+ int(fragments[2]),
+ int(fragments[3]))
+ self.address_list.sort()
+
+ def get_sym_file_line(self, addr):
+ key = None
+ if addr in self.addresses.keys():
+ key = addr
+ else:
+ index = bisect.bisect_left(self.address_list, addr)
+ if index == 0:
+ return None
+ else:
+ key = self.address_list[index - 1]
+ sym_id, size, line_no, file_no = self.addresses[key]
+ symbol = self.symbols[sym_id]
+ filename = self.files[file_no]
+ if addr < key + size:
+ return symbol, filename, line_no
+ else:
+ return None
+
+ def symbolize(self, addr, binary, offset):
+ if self.binary != binary:
+ return None
+ res = self.get_sym_file_line(int(offset, 16))
+ if res:
+ function_name, file_name, line_no = res
+ result = ['%s in %s %s:%d' % (
+ addr, function_name, file_name, line_no)]
+ print result
+ return result
+ else:
+ return None
+
+
+class SymbolizationLoop(object):
+ def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
+ if sys.platform == 'win32':
+ # ASan on Windows uses dbghelp.dll to symbolize in-process, which works
+ # even in sandboxed processes. Nothing needs to be done here.
+ self.process_line = self.process_line_echo
+ else:
+ # Used by clients who may want to supply a different binary name.
+ # E.g. in Chrome several binaries may share a single .dSYM.
+ 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']:
+ raise Exception('Unknown system')
+ self.llvm_symbolizers = {}
+ self.last_llvm_symbolizer = None
+ self.dsym_hints = set([])
+ self.frame_no = 0
+ self.process_line = self.process_line_posix
+
+ def symbolize_address(self, addr, binary, offset):
+ # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
+ # a single symbolizer binary.
+ # On Darwin, if the dsym hint producer is present:
+ # 1. check whether we've seen this binary already; if so,
+ # use |llvm_symbolizers[binary]|, which has already loaded the debug
+ # info for this binary (might not be the case for
+ # |last_llvm_symbolizer|);
+ # 2. otherwise check if we've seen all the hints for this binary already;
+ # if so, reuse |last_llvm_symbolizer| which has the full set of hints;
+ # 3. otherwise create a new symbolizer and pass all currently known
+ # .dSYM hints to it.
+ if not binary in self.llvm_symbolizers:
+ use_new_symbolizer = True
+ if self.system == 'Darwin' and self.dsym_hint_producer:
+ dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
+ use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
+ self.dsym_hints |= dsym_hints_for_binary
+ if self.last_llvm_symbolizer and not use_new_symbolizer:
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+ else:
+ self.last_llvm_symbolizer = LLVMSymbolizerFactory(
+ self.system, guess_arch(addr), self.dsym_hints)
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+ # Use the chain of symbolizers:
+ # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
+ # (fall back to next symbolizer if the previous one fails).
+ if not binary in symbolizers:
+ symbolizers[binary] = ChainSymbolizer(
+ [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
+ result = symbolizers[binary].symbolize(addr, binary, offset)
+ if result is None:
+ # Initialize system symbolizer only if other symbolizers failed.
+ symbolizers[binary].append_symbolizer(
+ SystemSymbolizerFactory(self.system, addr, binary))
+ result = symbolizers[binary].symbolize(addr, binary, offset)
+ # The system symbolizer must produce some result.
+ assert result
+ return result
+
+ def get_symbolized_lines(self, symbolized_lines):
+ if not symbolized_lines:
+ return [self.current_line]
+ else:
+ result = []
+ for symbolized_frame in symbolized_lines:
+ result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
+ self.frame_no += 1
+ return result
+
+ def process_logfile(self):
+ self.frame_no = 0
+ for line in logfile:
+ processed = self.process_line(line)
+ print '\n'.join(processed)
+
+ def process_line_echo(self, line):
+ return [line.rstrip()]
+
+ def process_line_posix(self, line):
+ self.current_line = line.rstrip()
+ #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
+ stack_trace_line_format = (
+ '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
+ match = re.match(stack_trace_line_format, line)
+ if not match:
+ return [self.current_line]
+ if DEBUG:
+ print line
+ _, frameno_str, addr, binary, offset = match.groups()
+ if frameno_str == '0':
+ # Assume that frame #0 is the first frame of new stack trace.
+ self.frame_no = 0
+ original_binary = binary
+ if self.binary_name_filter:
+ binary = self.binary_name_filter(binary)
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ if not symbolized_line:
+ if original_binary != binary:
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ return self.get_symbolized_lines(symbolized_line)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='ASan symbolization script',
+ epilog='Example of use:\n'
+ 'asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" '
+ '-s "$HOME/SymbolFiles" < asan.log')
+ parser.add_argument('path_to_cut', nargs='*',
+ help='pattern to be cut from the result file path ')
+ parser.add_argument('-d','--demangle', action='store_true',
+ help='demangle function names')
+ parser.add_argument('-s', metavar='SYSROOT',
+ help='set path to sysroot for sanitized binaries')
+ parser.add_argument('-c', metavar='CROSS_COMPILE',
+ help='set prefix for binutils')
+ parser.add_argument('-l','--logfile', default=sys.stdin,
+ type=argparse.FileType('r'),
+ help='set log file name to parse, default is stdin')
+ args = parser.parse_args()
+ if args.path_to_cut:
+ fix_filename_patterns = args.path_to_cut
+ if args.demangle:
+ demangle = True
+ if args.s:
+ binary_name_filter = sysroot_path_filter
+ sysroot_path = args.s
+ if args.c:
+ binutils_prefix = args.c
+ if args.logfile:
+ logfile = args.logfile
+ else:
+ logfile = sys.stdin
+ loop = SymbolizationLoop(binary_name_filter)
+ loop.process_logfile()
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc
new file mode 100644
index 000000000000..1d8b04d611bd
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc
@@ -0,0 +1,267 @@
+//===-- asan_asm_test.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#if defined(__linux__)
+
+#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#include <emmintrin.h>
+
+namespace {
+
+template<typename T> void asm_write(T *ptr, T val);
+template<typename T> T asm_read(T *ptr);
+template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#if defined(__x86_64__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "rsi", "rdi", "rcx", "memory"); \
+ }
+
+DECLARE_ASM_WRITE(U8, "8", "movq", "r");
+DECLARE_ASM_READ(U8, "8", "movq", "=r");
+DECLARE_ASM_REP_MOVS(U8, "movsq");
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__)
+
+#if defined(__i386__) && defined(__SSE2__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "esi", "edi", "ecx", "memory"); \
+ }
+
+} // End of anonymous namespace
+
+#endif // defined(__i386__) && defined(__SSE2__)
+
+#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+namespace {
+
+DECLARE_ASM_WRITE(U1, "1", "movb", "r");
+DECLARE_ASM_WRITE(U2, "2", "movw", "r");
+DECLARE_ASM_WRITE(U4, "4", "movl", "r");
+DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
+
+DECLARE_ASM_READ(U1, "1", "movb", "=r");
+DECLARE_ASM_READ(U2, "2", "movw", "=r");
+DECLARE_ASM_READ(U4, "4", "movl", "=r");
+DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
+
+DECLARE_ASM_REP_MOVS(U1, "movsb");
+DECLARE_ASM_REP_MOVS(U2, "movsw");
+DECLARE_ASM_REP_MOVS(U4, "movsl");
+
+template<typename T> void TestAsmWrite(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
+ T var = 0x12;
+ asm_write(&var, static_cast<T>(0x21));
+ ASSERT_EQ(static_cast<T>(0x21), var);
+ delete buf;
+}
+
+template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ __m128i val = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
+ __m128i var = _mm_set1_epi16(0x4321);
+ asm_write(&var, val);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
+ delete [] buf;
+}
+
+template<typename T> void TestAsmRead(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
+ T var = 0x12;
+ ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
+ delete buf;
+}
+
+template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
+ __m128i val = _mm_set1_epi16(0x1234);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
+ delete [] buf;
+}
+
+U4 AsmLoad(U4 *a) {
+ U4 r;
+ __asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
+ return r;
+}
+
+void AsmStore(U4 r, U4 *a) {
+ __asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
+}
+
+template <typename T>
+void TestAsmRepMovs(const char *DeathPatternRead,
+ const char *DeathPatternWrite) {
+ T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
+ T dst_good[4] = {};
+ asm_rep_movs(dst_good, src_good, 4);
+ ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
+ ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
+ ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
+ ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
+
+ T dst_bad[3];
+ EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
+
+ T src_bad[3] = { 0x0, 0x1, 0x2 };
+ EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
+
+ T* dp = dst_bad + 4;
+ T* sp = src_bad + 4;
+ asm_rep_movs(dp, sp, 0);
+}
+
+} // End of anonymous namespace
+
+TEST(AddressSanitizer, asm_load_store) {
+ U4* buf = new U4[2];
+ EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
+ EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
+ delete [] buf;
+}
+
+TEST(AddressSanitizer, asm_rw) {
+ TestAsmWrite<U1>("WRITE of size 1");
+ TestAsmWrite<U2>("WRITE of size 2");
+ TestAsmWrite<U4>("WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmWrite<U8>("WRITE of size 8");
+#endif // defined(__x86_64__)
+ TestAsmWrite<__m128i>("WRITE of size 16");
+
+ TestAsmRead<U1>("READ of size 1");
+ TestAsmRead<U2>("READ of size 2");
+ TestAsmRead<U4>("READ of size 4");
+#if defined(__x86_64__)
+ TestAsmRead<U8>("READ of size 8");
+#endif // defined(__x86_64__)
+ TestAsmRead<__m128i>("READ of size 16");
+}
+
+TEST(AddressSanitizer, asm_flags) {
+ long magic = 0x1234;
+ long r = 0x0;
+
+#if defined(__x86_64__)
+ __asm__("xorq %%rax, %%rax \n\t"
+ "movq (%[p]), %%rax \n\t"
+ "sete %%al \n\t"
+ "movzbq %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "rax", "memory");
+#else
+ __asm__("xorl %%eax, %%eax \n\t"
+ "movl (%[p]), %%eax \n\t"
+ "sete %%al \n\t"
+ "movzbl %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "eax", "memory");
+#endif // defined(__x86_64__)
+
+ ASSERT_EQ(0x1, r);
+}
+
+TEST(AddressSanitizer, asm_rep_movs) {
+ TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
+ TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
+ TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
+#endif // defined(__x86_64__)
+}
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#endif // defined(__linux__)
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc
new file mode 100644
index 000000000000..fc522de475fa
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc
@@ -0,0 +1,85 @@
+//===-- asan_benchmarks_test.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.
+//
+// Some benchmarks for the instrumented code.
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+
+template<class T>
+__attribute__((noinline))
+static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
+ for (size_t iter = 0; iter < n_iter; iter++) {
+ break_optimization(0);
+ // hand unroll the loop to stress the reg alloc.
+ for (size_t i = 0; i <= n_elements - 16; i += 16) {
+ x[i + 0] = i;
+ x[i + 1] = i;
+ x[i + 2] = i;
+ x[i + 3] = i;
+ x[i + 4] = i;
+ x[i + 5] = i;
+ x[i + 6] = i;
+ x[i + 7] = i;
+ x[i + 8] = i;
+ x[i + 9] = i;
+ x[i + 10] = i;
+ x[i + 11] = i;
+ x[i + 12] = i;
+ x[i + 13] = i;
+ x[i + 14] = i;
+ x[i + 15] = i;
+ }
+ }
+}
+
+TEST(AddressSanitizer, ManyAccessBenchmark) {
+ size_t kLen = 1024;
+ int *int_array = new int[kLen];
+ ManyAccessFunc(int_array, kLen, 1 << 24);
+ delete [] int_array;
+}
+
+// access 7 char elements in a 7 byte array (i.e. on the border).
+__attribute__((noinline))
+static void BorderAccessFunc(char *x, size_t n_iter) {
+ for (size_t iter = 0; iter < n_iter; iter++) {
+ break_optimization(x);
+ x[0] = 0;
+ x[1] = 0;
+ x[2] = 0;
+ x[3] = 0;
+ x[4] = 0;
+ x[5] = 0;
+ x[6] = 0;
+ }
+}
+
+TEST(AddressSanitizer, BorderAccessBenchmark) {
+ char *char_7_array = new char[7];
+ BorderAccessFunc(char_7_array, 1 << 30);
+ delete [] char_7_array;
+}
+
+static void FunctionWithLargeStack() {
+ int stack[1000];
+ Ident(stack);
+}
+
+TEST(AddressSanitizer, FakeStackBenchmark) {
+ for (int i = 0; i < 10000000; i++)
+ Ident(&FunctionWithLargeStack)();
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc
new file mode 100644
index 000000000000..ecd406de7561
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc
@@ -0,0 +1,27 @@
+// See http://llvm.org/bugs/show_bug.cgi?id=11468
+#include <stdio.h>
+#include <string>
+
+class Action {
+ public:
+ Action() {}
+ void PrintString(const std::string& msg) const {
+ fprintf(stderr, "%s\n", msg.c_str());
+ }
+ void Throw(const char& arg) const {
+ PrintString("PrintString called!"); // this line is important
+ throw arg;
+ }
+};
+
+int main() {
+ const Action a;
+ fprintf(stderr, "&a before = %p\n", &a);
+ try {
+ a.Throw('c');
+ } catch(const char&) {
+ fprintf(stderr, "&a in catch = %p\n", &a);
+ }
+ fprintf(stderr, "&a final = %p\n", &a);
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc
new file mode 100644
index 000000000000..516142f0c3b7
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc
@@ -0,0 +1,152 @@
+//===-- asan_fake_stack_test.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.
+//
+// Tests for FakeStack.
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_fake_stack.h"
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <map>
+
+namespace __asan {
+
+TEST(FakeStack, FlagsSize) {
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
+}
+
+TEST(FakeStack, RequiredSize) {
+ // for (int i = 15; i < 20; i++) {
+ // uptr alloc_size = FakeStack::RequiredSize(i);
+ // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
+ // }
+ EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
+ EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
+ EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
+ EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
+ EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
+}
+
+TEST(FakeStack, FlagsOffset) {
+ for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
+ uptr stack_size = 1UL << stack_size_log;
+ uptr offset = 0;
+ for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
+ class_id++) {
+ uptr frame_size = FakeStack::BytesInSizeClass(class_id);
+ uptr num_flags = stack_size / frame_size;
+ EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
+ // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
+ // FakeStack::FlagsOffset(stack_size_log, class_id));
+ offset += num_flags;
+ }
+ }
+}
+
+#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
+TEST(FakeStack, CreateDestroy) {
+ for (int i = 0; i < 1000; i++) {
+ for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
+ FakeStack *fake_stack = FakeStack::Create(stack_size_log);
+ fake_stack->Destroy(0);
+ }
+ }
+}
+#endif
+
+TEST(FakeStack, ModuloNumberOfFrames) {
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
+}
+
+TEST(FakeStack, GetFrame) {
+ const uptr stack_size_log = 20;
+ const uptr stack_size = 1 << stack_size_log;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ u8 *base = fs->GetFrame(stack_size_log, 0, 0);
+ EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
+ fs->SizeRequiredForFlags(stack_size_log) + 4096);
+ EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
+ EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
+ EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
+ fs->Destroy(0);
+}
+
+TEST(FakeStack, Allocate) {
+ const uptr stack_size_log = 19;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ std::map<FakeFrame *, uptr> s;
+ for (int iter = 0; iter < 2; iter++) {
+ s.clear();
+ for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
+ uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
+ uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
+ for (uptr j = 0; j < n; j++) {
+ FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
+ uptr x = reinterpret_cast<uptr>(ff);
+ EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
+ EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
+ }
+ // We are out of fake stack, so Allocate should return 0.
+ EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
+ }
+ for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
+ ++it) {
+ fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
+ }
+ }
+ fs->Destroy(0);
+}
+
+static void RecursiveFunction(FakeStack *fs, int depth) {
+ uptr class_id = depth / 3;
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
+ if (depth) {
+ RecursiveFunction(fs, depth - 1);
+ RecursiveFunction(fs, depth - 1);
+ }
+ fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
+}
+
+TEST(FakeStack, RecursiveStressTest) {
+ const uptr stack_size_log = 16;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
+ fs->Destroy(0);
+}
+
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc
new file mode 100644
index 000000000000..5042ef07378d
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc
@@ -0,0 +1,45 @@
+//===-- asan_globals_test.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.
+//
+// Some globals in a separate file.
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+char glob1[1];
+char glob2[2];
+char glob3[3];
+char glob4[4];
+char glob5[5];
+char glob6[6];
+char glob7[7];
+char glob8[8];
+char glob9[9];
+char glob10[10];
+char glob11[11];
+char glob12[12];
+char glob13[13];
+char glob14[14];
+char glob15[15];
+char glob16[16];
+char glob17[17];
+char glob1000[1000];
+char glob10000[10000];
+char glob100000[100000];
+
+static char static10[10];
+
+int GlobalsTest(int zero) {
+ static char func_static15[15];
+ glob5[zero] = 0;
+ static10[zero] = 0;
+ func_static15[zero] = 0;
+ return glob5[1] + func_static15[2];
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc
new file mode 100644
index 000000000000..a34c8528eae0
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc
@@ -0,0 +1,433 @@
+//===-- asan_interface_test.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/asan_interface.h>
+
+TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
+ EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
+ const size_t sizes[] = { 1, 30, 1<<30 };
+ for (size_t i = 0; i < 3; i++) {
+ EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
+ }
+}
+
+static const char* kGetAllocatedSizeErrorMsg =
+ "attempting to call __sanitizer_get_allocated_size";
+
+TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+
+ // Allocated memory is owned by allocator. Allocated size should be
+ // equal to requested size.
+ EXPECT_EQ(true, __sanitizer_get_ownership(array));
+ EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
+ EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
+
+ // We cannot call GetAllocatedSize from the memory we didn't map,
+ // and from the interior pointers (not returned by previous malloc).
+ void *wild_addr = (void*)0x1;
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
+ kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
+ kGetAllocatedSizeErrorMsg);
+
+ // NULL is not owned, but is a valid argument for
+ // __sanitizer_get_allocated_size().
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
+
+ // When memory is freed, it's not owned, and call to GetAllocatedSize
+ // is forbidden.
+ free(array);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array),
+ kGetAllocatedSizeErrorMsg);
+ delete int_ptr;
+
+ void *zero_alloc = Ident(malloc(0));
+ if (zero_alloc != 0) {
+ // If malloc(0) is not null, this pointer is owned and should have valid
+ // allocated size.
+ EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
+ // Allocated size is 0 or 1 depending on the allocator used.
+ EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
+ }
+ free(zero_alloc);
+}
+
+TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
+ size_t before_malloc, after_malloc, after_free;
+ char *array;
+ const size_t kMallocSize = 100;
+ before_malloc = __sanitizer_get_current_allocated_bytes();
+
+ array = Ident((char*)malloc(kMallocSize));
+ after_malloc = __sanitizer_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
+
+ free(array);
+ after_free = __sanitizer_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc, after_free);
+}
+
+TEST(AddressSanitizerInterface, GetHeapSizeTest) {
+ // ASan allocator does not keep huge chunks in free list, but unmaps them.
+ // The chunk should be greater than the quarantine size,
+ // otherwise it will be stuck in quarantine instead of being unmaped.
+ static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
+ free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
+ size_t old_heap_size = __sanitizer_get_heap_size();
+ for (int i = 0; i < 3; i++) {
+ // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
+ free(Ident(malloc(kLargeMallocSize)));
+ EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
+ }
+}
+
+static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
+static const size_t kManyThreadsIterations = 250;
+static const size_t kManyThreadsNumThreads =
+ (SANITIZER_WORDSIZE == 32) ? 40 : 200;
+
+static void *ManyThreadsWithStatsWorker(void *arg) {
+ (void)arg;
+ for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
+ for (size_t size_index = 0; size_index < 4; size_index++) {
+ free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
+ }
+ }
+ // Just one large allocation.
+ free(Ident(malloc(1 << 20)));
+ return 0;
+}
+
+TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
+ size_t before_test, after_test, i;
+ pthread_t threads[kManyThreadsNumThreads];
+ before_test = __sanitizer_get_current_allocated_bytes();
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_CREATE(&threads[i], 0,
+ (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
+ }
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_JOIN(threads[i], 0);
+ }
+ after_test = __sanitizer_get_current_allocated_bytes();
+ // ASan stats also reflect memory usage of internal ASan RTL structs,
+ // so we can't check for equality here.
+ EXPECT_LT(after_test, before_test + (1UL<<20));
+}
+
+static void DoDoubleFree() {
+ int *x = Ident(new int);
+ delete Ident(x);
+ delete Ident(x);
+}
+
+TEST(AddressSanitizerInterface, ExitCode) {
+ int original_exit_code = __asan_set_error_exit_code(7);
+ EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), "");
+ EXPECT_EQ(7, __asan_set_error_exit_code(8));
+ EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), "");
+ EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code));
+ EXPECT_EXIT(DoDoubleFree(),
+ ::testing::ExitedWithCode(original_exit_code), "");
+}
+
+static void MyDeathCallback() {
+ fprintf(stderr, "MyDeathCallback\n");
+ fflush(0); // On Windows, stderr doesn't flush on crash.
+}
+
+TEST(AddressSanitizerInterface, DeathCallbackTest) {
+ __asan_set_death_callback(MyDeathCallback);
+ EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
+ __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))
+
+TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // poison array[40..80)
+ __asan_poison_memory_region(array + 40, 40);
+ GOOD_ACCESS(array, 39);
+ GOOD_ACCESS(array, 80);
+ BAD_ACCESS(array, 40);
+ BAD_ACCESS(array, 60);
+ BAD_ACCESS(array, 79);
+ char value;
+ EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
+ __asan_unpoison_memory_region(array + 40, 40);
+ // access previously poisoned memory.
+ GOOD_ACCESS(array, 40);
+ GOOD_ACCESS(array, 79);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // Poison [0..40) and [80..120)
+ __asan_poison_memory_region(array, 40);
+ __asan_poison_memory_region(array + 80, 40);
+ BAD_ACCESS(array, 20);
+ GOOD_ACCESS(array, 60);
+ BAD_ACCESS(array, 100);
+ // Poison whole array - [0..120)
+ __asan_poison_memory_region(array, 120);
+ BAD_ACCESS(array, 60);
+ // Unpoison [24..96)
+ __asan_unpoison_memory_region(array + 24, 72);
+ BAD_ACCESS(array, 23);
+ GOOD_ACCESS(array, 24);
+ GOOD_ACCESS(array, 60);
+ GOOD_ACCESS(array, 95);
+ BAD_ACCESS(array, 96);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
+ // Vector of capacity 20
+ char *vec = Ident((char*)malloc(20));
+ __asan_poison_memory_region(vec, 20);
+ for (size_t i = 0; i < 7; i++) {
+ // Simulate push_back.
+ __asan_unpoison_memory_region(vec + i, 1);
+ GOOD_ACCESS(vec, i);
+ BAD_ACCESS(vec, i + 1);
+ }
+ for (size_t i = 7; i > 0; i--) {
+ // Simulate pop_back.
+ __asan_poison_memory_region(vec + i - 1, 1);
+ BAD_ACCESS(vec, i - 1);
+ if (i > 1) GOOD_ACCESS(vec, i - 2);
+ }
+ free(vec);
+}
+
+// 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) {
+ bool can_be_poisoned = true;
+ for (int i = length - 1; i >= 0; i--) {
+ if (!shadow[i])
+ can_be_poisoned = false;
+ if (!can_be_poisoned)
+ shadow[i] = false;
+ if (i % (1 << granularity) == 0) {
+ can_be_poisoned = true;
+ }
+ }
+}
+
+TEST(AddressSanitizerInterface, PoisoningStressTest) {
+ const size_t kSize = 24;
+ bool expected[kSize];
+ char *arr = Ident((char*)malloc(kSize));
+ for (size_t l1 = 0; l1 < kSize; l1++) {
+ for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
+ for (size_t l2 = 0; l2 < kSize; l2++) {
+ for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
+ // Poison [l1, l1+s1), [l2, l2+s2) and check result.
+ __asan_unpoison_memory_region(arr, kSize);
+ __asan_poison_memory_region(arr + l1, s1);
+ __asan_poison_memory_region(arr + l2, s2);
+ memset(expected, false, kSize);
+ memset(expected + l1, true, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, true, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
+ __asan_poison_memory_region(arr, kSize);
+ __asan_unpoison_memory_region(arr + l1, s1);
+ __asan_unpoison_memory_region(arr + l2, s2);
+ memset(expected, true, kSize);
+ memset(expected + l1, false, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, false, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ }
+ }
+ }
+ }
+ free(arr);
+}
+
+TEST(AddressSanitizerInterface, GlobalRedzones) {
+ GOOD_ACCESS(glob1, 1 - 1);
+ GOOD_ACCESS(glob2, 2 - 1);
+ GOOD_ACCESS(glob3, 3 - 1);
+ GOOD_ACCESS(glob4, 4 - 1);
+ GOOD_ACCESS(glob5, 5 - 1);
+ GOOD_ACCESS(glob6, 6 - 1);
+ GOOD_ACCESS(glob7, 7 - 1);
+ GOOD_ACCESS(glob8, 8 - 1);
+ GOOD_ACCESS(glob9, 9 - 1);
+ GOOD_ACCESS(glob10, 10 - 1);
+ GOOD_ACCESS(glob11, 11 - 1);
+ GOOD_ACCESS(glob12, 12 - 1);
+ GOOD_ACCESS(glob13, 13 - 1);
+ GOOD_ACCESS(glob14, 14 - 1);
+ GOOD_ACCESS(glob15, 15 - 1);
+ GOOD_ACCESS(glob16, 16 - 1);
+ GOOD_ACCESS(glob17, 17 - 1);
+ GOOD_ACCESS(glob1000, 1000 - 1);
+ GOOD_ACCESS(glob10000, 10000 - 1);
+ GOOD_ACCESS(glob100000, 100000 - 1);
+
+ BAD_ACCESS(glob1, 1);
+ BAD_ACCESS(glob2, 2);
+ BAD_ACCESS(glob3, 3);
+ BAD_ACCESS(glob4, 4);
+ BAD_ACCESS(glob5, 5);
+ BAD_ACCESS(glob6, 6);
+ BAD_ACCESS(glob7, 7);
+ BAD_ACCESS(glob8, 8);
+ BAD_ACCESS(glob9, 9);
+ BAD_ACCESS(glob10, 10);
+ BAD_ACCESS(glob11, 11);
+ BAD_ACCESS(glob12, 12);
+ BAD_ACCESS(glob13, 13);
+ BAD_ACCESS(glob14, 14);
+ BAD_ACCESS(glob15, 15);
+ BAD_ACCESS(glob16, 16);
+ BAD_ACCESS(glob17, 17);
+ BAD_ACCESS(glob1000, 1000);
+ BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
+ BAD_ACCESS(glob10000, 10000);
+ BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
+ BAD_ACCESS(glob100000, 100000);
+ BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
+}
+
+TEST(AddressSanitizerInterface, PoisonedRegion) {
+ size_t rz = 16;
+ for (size_t size = 1; size <= 64; size++) {
+ char *p = new char[size];
+ for (size_t beg = 0; beg < size + rz; beg++) {
+ for (size_t end = beg; end < size + rz; end++) {
+ void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
+ if (beg == end) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg < size && end <= size) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg >= size) {
+ EXPECT_EQ(p + beg, first_poisoned);
+ } else {
+ EXPECT_GT(end, size);
+ EXPECT_EQ(p + size, first_poisoned);
+ }
+ }
+ }
+ delete [] p;
+ }
+}
+
+// This is a performance benchmark for manual runs.
+// asan's memset interceptor calls mem_is_zero for the entire shadow region.
+// the profile should look like this:
+// 89.10% [.] __memset_sse2
+// 10.50% [.] __sanitizer::mem_is_zero
+// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
+// than memset itself.
+TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
+ size_t size = 1 << 20;
+ char *x = new char[size];
+ for (int i = 0; i < 100000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+
+// Same here, but we run memset with small sizes.
+TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
+ size_t size = 32;
+ char *x = new char[size];
+ for (int i = 0; i < 100000000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
+static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
+
+TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
+ char *array = Ident((char*)malloc(120));
+ __asan_unpoison_memory_region(array, 120);
+ // Try to unpoison not owned memory
+ EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
+ kInvalidUnpoisonMessage);
+ EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
+ kInvalidUnpoisonMessage);
+
+ __asan_poison_memory_region(array, 120);
+ // Try to poison not owned memory.
+ EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
+ EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
+ kInvalidPoisonMessage);
+ 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(0, 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;
+ const size_t kNumMallocs = 1 << 9;
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ size_t size = i * 100 + 1;
+ pointers.push_back((char*)malloc(size));
+ sizes.push_back(size);
+ }
+ for (size_t i = 0; i < 4000000; i++) {
+ EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
+ EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
+ size_t idx = i % kNumMallocs;
+ EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
+ EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
+ }
+ for (size_t i = 0, n = pointers.size(); i < n; i++)
+ free(pointers[i]);
+}
+
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc
new file mode 100644
index 000000000000..cabdfd711ea2
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc
@@ -0,0 +1,236 @@
+//===-- asan_test_mac.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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+
+#include "asan_mac_test.h"
+
+#include <malloc/malloc.h>
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#include <CoreFoundation/CFString.h>
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
+ EXPECT_DEATH(
+ CFAllocatorDefaultDoubleFree(NULL),
+ "attempting double-free");
+}
+
+void CFAllocator_DoubleFreeOnPthread() {
+ pthread_t child;
+ PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
+ PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
+}
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
+ EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
+}
+
+namespace {
+
+void *GLOB;
+
+void *CFAllocatorAllocateToGlob(void *unused) {
+ GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
+ return NULL;
+}
+
+void *CFAllocatorDeallocateFromGlob(void *unused) {
+ char *p = (char*)GLOB;
+ p[100] = 'A'; // ASan should report an error here.
+ CFAllocatorDeallocate(NULL, GLOB);
+ return NULL;
+}
+
+void CFAllocator_PassMemoryToAnotherThread() {
+ pthread_t th1, th2;
+ PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
+ PTHREAD_JOIN(th1, NULL);
+ PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
+ PTHREAD_JOIN(th2, NULL);
+}
+
+TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
+ EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
+ "heap-buffer-overflow");
+}
+
+} // namespace
+
+// TODO(glider): figure out whether we still need these tests. Is it correct
+// to intercept the non-default CFAllocators?
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
+ EXPECT_DEATH(
+ CFAllocatorSystemDefaultDoubleFree(),
+ "attempting double-free");
+}
+
+// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
+TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
+ EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
+ EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
+}
+
+// For libdispatch tests below we check that ASan got to the shadow byte
+// legend, i.e. managed to print the thread stacks (this almost certainly
+// means that the libdispatch task creation has been intercepted correctly).
+TEST(AddressSanitizerMac, GCDDispatchAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchSync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
+}
+
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAfter) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDSourceEvent) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDSourceCancel) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDGroupAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
+}
+
+void *MallocIntrospectionLockWorker(void *_) {
+ const int kNumPointers = 100;
+ int i;
+ void *pointers[kNumPointers];
+ for (i = 0; i < kNumPointers; i++) {
+ pointers[i] = malloc(i + 1);
+ }
+ for (i = 0; i < kNumPointers; i++) {
+ free(pointers[i]);
+ }
+
+ return NULL;
+}
+
+void *MallocIntrospectionLockForker(void *_) {
+ pid_t result = fork();
+ if (result == -1) {
+ perror("fork");
+ }
+ assert(result != -1);
+ if (result == 0) {
+ // Call malloc in the child process to make sure we won't deadlock.
+ void *ptr = malloc(42);
+ free(ptr);
+ exit(0);
+ } else {
+ // Return in the parent process.
+ return NULL;
+ }
+}
+
+TEST(AddressSanitizerMac, MallocIntrospectionLock) {
+ // Incorrect implementation of force_lock and force_unlock in our malloc zone
+ // will cause forked processes to deadlock.
+ // TODO(glider): need to detect that none of the child processes deadlocked.
+ const int kNumWorkers = 5, kNumIterations = 100;
+ int i, iter;
+ for (iter = 0; iter < kNumIterations; iter++) {
+ pthread_t workers[kNumWorkers], forker;
+ for (i = 0; i < kNumWorkers; i++) {
+ PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
+ }
+ PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
+ for (i = 0; i < kNumWorkers; i++) {
+ PTHREAD_JOIN(workers[i], 0);
+ }
+ PTHREAD_JOIN(forker, 0);
+ }
+}
+
+void *TSDAllocWorker(void *test_key) {
+ if (test_key) {
+ void *mem = malloc(10);
+ pthread_setspecific(*(pthread_key_t*)test_key, mem);
+ }
+ return NULL;
+}
+
+TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
+ pthread_t th;
+ pthread_key_t test_key;
+ pthread_key_create(&test_key, CallFreeOnWorkqueue);
+ PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
+ PTHREAD_JOIN(th, NULL);
+ pthread_key_delete(test_key);
+}
+
+// Test that CFStringCreateCopy does not copy constant strings.
+TEST(AddressSanitizerMac, CFStringCreateCopy) {
+ CFStringRef str = CFSTR("Hello world!\n");
+ CFStringRef str2 = CFStringCreateCopy(0, str);
+ EXPECT_EQ(str, str2);
+}
+
+TEST(AddressSanitizerMac, NSObjectOOB) {
+ // Make sure that our allocators are used for NSObjects.
+ EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
+}
+
+// Make sure that correct pointer is passed to free() when deallocating a
+// NSURL object.
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=70.
+TEST(AddressSanitizerMac, NSURLDeallocation) {
+ TestNSURLDeallocation();
+}
+
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=109.
+TEST(AddressSanitizerMac, Mstats) {
+ malloc_statistics_t stats1, stats2;
+ malloc_zone_statistics(/*all zones*/NULL, &stats1);
+ const size_t kMallocSize = 100000;
+ void *alloc = Ident(malloc(kMallocSize));
+ malloc_zone_statistics(/*all zones*/NULL, &stats2);
+ EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
+ EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
+ free(alloc);
+ // Even the default OSX allocator may not change the stats after free().
+}
+
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test.h b/contrib/compiler-rt/lib/asan/tests/asan_mac_test.h
new file mode 100644
index 000000000000..441547a5a3dc
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_mac_test.h
@@ -0,0 +1,19 @@
+extern "C" {
+ void *CFAllocatorDefaultDoubleFree(void *unused);
+ void CFAllocatorSystemDefaultDoubleFree();
+ void CFAllocatorMallocDoubleFree();
+ void CFAllocatorMallocZoneDoubleFree();
+ void CallFreeOnWorkqueue(void *mem);
+ void TestGCDDispatchAsync();
+ void TestGCDDispatchSync();
+ void TestGCDReuseWqthreadsAsync();
+ void TestGCDReuseWqthreadsSync();
+ void TestGCDDispatchAfter();
+ void TestGCDInTSDDestructor();
+ void TestGCDSourceEvent();
+ void TestGCDSourceCancel();
+ void TestGCDGroupAsync();
+ void TestOOBNSObjects();
+ void TestNSURLDeallocation();
+ void TestPassCFMemoryToAnotherThread();
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm b/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
new file mode 100644
index 000000000000..a7e4b9d1928b
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
@@ -0,0 +1,240 @@
+// Mac OS X 10.6 or higher only.
+#include <dispatch/dispatch.h>
+#include <pthread.h> // for pthread_yield_np()
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#import <CoreFoundation/CFBase.h>
+#import <Foundation/NSObject.h>
+#import <Foundation/NSURL.h>
+
+// This is a (void*)(void*) function so it can be passed to pthread_create.
+void *CFAllocatorDefaultDoubleFree(void *unused) {
+ void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorDefault, mem);
+ CFAllocatorDeallocate(kCFAllocatorDefault, mem);
+ return 0;
+}
+
+void CFAllocatorSystemDefaultDoubleFree() {
+ void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
+ CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
+}
+
+void CFAllocatorMallocDoubleFree() {
+ void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
+ CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
+}
+
+void CFAllocatorMallocZoneDoubleFree() {
+ void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
+ CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
+}
+
+__attribute__((noinline))
+void access_memory(char *a) {
+ *a = 0;
+}
+
+// Test the +load instrumentation.
+// Because the +load methods are invoked before anything else is initialized,
+// it makes little sense to wrap the code below into a gTest test case.
+// If AddressSanitizer doesn't instrument the +load method below correctly,
+// everything will just crash.
+
+char kStartupStr[] =
+ "If your test didn't crash, AddressSanitizer is instrumenting "
+ "the +load methods correctly.";
+
+@interface LoadSomething : NSObject {
+}
+@end
+
+@implementation LoadSomething
+
++(void) load {
+ for (size_t i = 0; i < strlen(kStartupStr); i++) {
+ access_memory(&kStartupStr[i]); // make sure no optimizations occur.
+ }
+ // Don't print anything here not to interfere with the death tests.
+}
+
+@end
+
+void worker_do_alloc(int size) {
+ char * volatile mem = (char * volatile)malloc(size);
+ mem[0] = 0; // Ok
+ free(mem);
+}
+
+void worker_do_crash(int size) {
+ char * volatile mem = (char * volatile)malloc(size);
+ access_memory(&mem[size]); // BOOM
+ free(mem);
+}
+
+// Used by the GCD tests to avoid a race between the worker thread reporting a
+// memory error and the main thread which may exit with exit code 0 before
+// that.
+void wait_forever() {
+ volatile bool infinite = true;
+ while (infinite) pthread_yield_np();
+}
+
+// Tests for the Grand Central Dispatch. See
+// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// for the reference.
+void TestGCDDispatchAsync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block = ^{ worker_do_crash(1024); };
+ // dispatch_async() runs the task on a worker thread that does not go through
+ // pthread_create(). We need to verify that AddressSanitizer notices that the
+ // thread has started.
+ dispatch_async(queue, block);
+ wait_forever();
+}
+
+void TestGCDDispatchSync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(2, 0);
+ dispatch_block_t block = ^{ worker_do_crash(1024); };
+ // dispatch_sync() runs the task on a worker thread that does not go through
+ // pthread_create(). We need to verify that AddressSanitizer notices that the
+ // thread has started.
+ dispatch_sync(queue, block);
+ wait_forever();
+}
+
+// libdispatch spawns a rather small number of threads and reuses them. We need
+// to make sure AddressSanitizer handles the reusing correctly.
+void TestGCDReuseWqthreadsAsync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
+ dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+ for (int i = 0; i < 100; i++) {
+ dispatch_async(queue, block_alloc);
+ }
+ dispatch_async(queue, block_crash);
+ wait_forever();
+}
+
+// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
+void TestGCDReuseWqthreadsSync() {
+ dispatch_queue_t queue[4];
+ queue[0] = dispatch_get_global_queue(2, 0);
+ queue[1] = dispatch_get_global_queue(0, 0);
+ queue[2] = dispatch_get_global_queue(-2, 0);
+ queue[3] = dispatch_queue_create("my_queue", NULL);
+ dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
+ dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+ for (int i = 0; i < 1000; i++) {
+ dispatch_sync(queue[i % 4], block_alloc);
+ }
+ dispatch_sync(queue[3], block_crash);
+ wait_forever();
+}
+
+void TestGCDDispatchAfter() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+ // Schedule the event one second from the current time.
+ dispatch_time_t milestone =
+ dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+ dispatch_after(milestone, queue, block_crash);
+ wait_forever();
+}
+
+void worker_do_deallocate(void *ptr) {
+ free(ptr);
+}
+
+void CallFreeOnWorkqueue(void *tsd) {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
+ dispatch_async(queue, block_dealloc);
+ // Do not wait for the worker to free the memory -- nobody is going to touch
+ // it.
+}
+
+void TestGCDSourceEvent() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_source_t timer =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+ // Schedule the timer one second from the current time.
+ dispatch_time_t milestone =
+ dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+
+ dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
+ char * volatile mem = (char * volatile)malloc(10);
+ dispatch_source_set_event_handler(timer, ^{
+ access_memory(&mem[10]);
+ });
+ dispatch_resume(timer);
+ wait_forever();
+}
+
+void TestGCDSourceCancel() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_source_t timer =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+ // Schedule the timer one second from the current time.
+ dispatch_time_t milestone =
+ dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+
+ dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
+ char * volatile mem = (char * volatile)malloc(10);
+ // Both dispatch_source_set_cancel_handler() and
+ // dispatch_source_set_event_handler() use dispatch_barrier_async_f().
+ // It's tricky to test dispatch_source_set_cancel_handler() separately,
+ // so we test both here.
+ dispatch_source_set_event_handler(timer, ^{
+ dispatch_source_cancel(timer);
+ });
+ dispatch_source_set_cancel_handler(timer, ^{
+ access_memory(&mem[10]);
+ });
+ dispatch_resume(timer);
+ wait_forever();
+}
+
+void TestGCDGroupAsync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_group_t group = dispatch_group_create();
+ char * volatile mem = (char * volatile)malloc(10);
+ dispatch_group_async(group, queue, ^{
+ access_memory(&mem[10]);
+ });
+ dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+ wait_forever();
+}
+
+@interface FixedArray : NSObject {
+ int items[10];
+}
+@end
+
+@implementation FixedArray
+-(int) access: (int)index {
+ return items[index];
+}
+@end
+
+void TestOOBNSObjects() {
+ id anObject = [FixedArray new];
+ [anObject access:1];
+ [anObject access:11];
+ [anObject release];
+}
+
+void TestNSURLDeallocation() {
+ NSURL *base =
+ [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"];
+ volatile NSURL *u =
+ [[NSURL alloc] initWithString:@"Saved Application State"
+ relativeToURL:base];
+ [u release];
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc
new file mode 100644
index 000000000000..4a941faa0430
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc
@@ -0,0 +1,241 @@
+//===-- asan_mem_test.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+template<typename T>
+void MemSetOOBTestTemplate(size_t length) {
+ if (length == 0) return;
+ size_t size = Ident(sizeof(T) * length);
+ T *array = Ident((T*)malloc(size));
+ int element = Ident(42);
+ int zero = Ident(0);
+ void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
+ // memset interval inside array
+ MEMSET(array, element, size);
+ MEMSET(array, element, size - 1);
+ MEMSET(array + length - 1, element, sizeof(T));
+ MEMSET(array, element, 1);
+
+ // memset 0 bytes
+ MEMSET(array - 10, element, zero);
+ MEMSET(array - 1, element, zero);
+ MEMSET(array, element, zero);
+ MEMSET(array + length, 0, zero);
+ MEMSET(array + length + 1, 0, zero);
+
+ // try to memset bytes to the right of array
+ EXPECT_DEATH(MEMSET(array, 0, size + 1),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
+ RightOOBWriteMessage(0));
+ // whole interval is to the right
+ EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
+ RightOOBWriteMessage(sizeof(T)));
+
+ // try to memset bytes to the left of array
+ EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
+ LeftOOBWriteMessage(1));
+ EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
+ LeftOOBWriteMessage(5));
+ if (length >= 100) {
+ // Large OOB, we find it only if the redzone is large enough.
+ EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+ LeftOOBWriteMessage(5 * sizeof(T)));
+ }
+ // whole interval is to the left
+ EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
+ LeftOOBWriteMessage(2 * sizeof(T)));
+
+ // try to memset bytes both to the left & to the right
+ EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
+ LeftOOBWriteMessage(2));
+
+ free(array);
+}
+
+TEST(AddressSanitizer, MemSetOOBTest) {
+ MemSetOOBTestTemplate<char>(100);
+ MemSetOOBTestTemplate<int>(5);
+ MemSetOOBTestTemplate<double>(256);
+ // We can test arrays of structres/classes here, but what for?
+}
+
+// Try to allocate two arrays of 'size' bytes that are near each other.
+// Strictly speaking we are not guaranteed to find such two pointers,
+// but given the structure of asan's allocator we will.
+static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
+ vector<uintptr_t> v;
+ bool res = false;
+ for (size_t i = 0; i < 1000U && !res; i++) {
+ v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
+ if (i == 0) continue;
+ sort(v.begin(), v.end());
+ for (size_t j = 1; j < v.size(); j++) {
+ assert(v[j] > v[j-1]);
+ if ((size_t)(v[j] - v[j-1]) < size * 2) {
+ *x2 = reinterpret_cast<char*>(v[j]);
+ *x1 = reinterpret_cast<char*>(v[j-1]);
+ res = true;
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < v.size(); i++) {
+ char *p = reinterpret_cast<char *>(v[i]);
+ if (res && p == *x1) continue;
+ if (res && p == *x2) continue;
+ delete [] p;
+ }
+ return res;
+}
+
+TEST(AddressSanitizer, LargeOOBInMemset) {
+ for (size_t size = 200; size < 100000; size += size / 2) {
+ char *x1, *x2;
+ if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
+ continue;
+ // fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
+ // Do a memset on x1 with huge out-of-bound access that will end up in x2.
+ EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
+ "is located 0 bytes to the right");
+ delete [] x1;
+ delete [] x2;
+ return;
+ }
+ assert(0 && "Did not find two adjacent malloc-ed pointers");
+}
+
+// Same test for memcpy and memmove functions
+template <typename T, class M>
+void MemTransferOOBTestTemplate(size_t length) {
+ if (length == 0) return;
+ size_t size = Ident(sizeof(T) * length);
+ T *src = Ident((T*)malloc(size));
+ T *dest = Ident((T*)malloc(size));
+ int zero = Ident(0);
+
+ // valid transfer of bytes between arrays
+ M::transfer(dest, src, size);
+ M::transfer(dest + 1, src, size - sizeof(T));
+ M::transfer(dest, src + length - 1, sizeof(T));
+ M::transfer(dest, src, 1);
+
+ // transfer zero bytes
+ M::transfer(dest - 1, src, 0);
+ M::transfer(dest + length, src, zero);
+ M::transfer(dest, src - 1, zero);
+ M::transfer(dest, src, zero);
+
+ // try to change mem to the right of dest
+ EXPECT_DEATH(M::transfer(dest + 1, src, size),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
+ RightOOBWriteMessage(0));
+
+ // try to change mem to the left of dest
+ EXPECT_DEATH(M::transfer(dest - 2, src, size),
+ LeftOOBWriteMessage(2 * sizeof(T)));
+ EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
+ LeftOOBWriteMessage(3));
+
+ // try to access mem to the right of src
+ EXPECT_DEATH(M::transfer(dest, src + 2, size),
+ RightOOBReadMessage(0));
+ EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
+ RightOOBReadMessage(0));
+
+ // try to access mem to the left of src
+ EXPECT_DEATH(M::transfer(dest, src - 1, size),
+ LeftOOBReadMessage(sizeof(T)));
+ EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
+ LeftOOBReadMessage(6));
+
+ // Generally we don't need to test cases where both accessing src and writing
+ // to dest address to poisoned memory.
+
+ T *big_src = Ident((T*)malloc(size * 2));
+ T *big_dest = Ident((T*)malloc(size * 2));
+ // try to change mem to both sides of dest
+ EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
+ LeftOOBWriteMessage(sizeof(T)));
+ // try to access mem to both sides of src
+ EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
+ LeftOOBReadMessage(2 * sizeof(T)));
+
+ free(src);
+ free(dest);
+ free(big_src);
+ free(big_dest);
+}
+
+class MemCpyWrapper {
+ public:
+ static void* transfer(void *to, const void *from, size_t size) {
+ return Ident(memcpy)(to, from, size);
+ }
+};
+
+TEST(AddressSanitizer, MemCpyOOBTest) {
+ MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
+ MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
+}
+
+class MemMoveWrapper {
+ public:
+ static void* transfer(void *to, const void *from, size_t size) {
+ return Ident(memmove)(to, from, size);
+ }
+};
+
+TEST(AddressSanitizer, MemMoveOOBTest) {
+ MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
+ MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
+}
+
+
+TEST(AddressSanitizer, MemCmpOOBTest) {
+ size_t size = Ident(100);
+ char *s1 = MallocAndMemsetString(size);
+ char *s2 = MallocAndMemsetString(size);
+ // Normal memcmp calls.
+ Ident(memcmp(s1, s2, size));
+ Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
+ Ident(memcmp(s1 - 1, s2 - 1, 0));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
+ // Zero bytes are not terminators and don't prevent from OOB.
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
+
+ // Even if the buffers differ in the first byte, we still assume that
+ // memcmp may access the whole buffer and thus reporting the overflow here:
+ s1[0] = 1;
+ s2[0] = 123;
+ EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
+
+ free(s1);
+ free(s2);
+}
+
+
+
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc
new file mode 100644
index 000000000000..6a428fbbc2b9
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc
@@ -0,0 +1,263 @@
+//===-- asan_noinst_test.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.
+//
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // for memset()
+#include <algorithm>
+#include <vector>
+#include <limits>
+
+// ATTENTION!
+// Please don't call intercepted functions (including malloc() and friends)
+// in this test. The static runtime library is linked explicitly (without
+// -fsanitize=address), thus the interceptors do not work correctly on OS X.
+
+// Make sure __asan_init is called before any test case is run.
+struct AsanInitCaller {
+ AsanInitCaller() {
+ __asan::DisableReexec();
+ __asan_init();
+ }
+};
+static AsanInitCaller asan_init_caller;
+
+TEST(AddressSanitizer, InternalSimpleDeathTest) {
+ EXPECT_DEATH(exit(1), "");
+}
+
+static void MallocStress(size_t n) {
+ u32 seed = my_rand();
+ BufferedStackTrace stack1;
+ stack1.trace_buffer[0] = 0xa123;
+ stack1.trace_buffer[1] = 0xa456;
+ stack1.size = 2;
+
+ BufferedStackTrace stack2;
+ stack2.trace_buffer[0] = 0xb123;
+ stack2.trace_buffer[1] = 0xb456;
+ stack2.size = 2;
+
+ BufferedStackTrace stack3;
+ stack3.trace_buffer[0] = 0xc123;
+ stack3.trace_buffer[1] = 0xc456;
+ stack3.size = 2;
+
+ std::vector<void *> vec;
+ for (size_t i = 0; i < n; i++) {
+ if ((i % 3) == 0) {
+ if (vec.empty()) continue;
+ size_t idx = my_rand_r(&seed) % vec.size();
+ void *ptr = vec[idx];
+ vec[idx] = vec.back();
+ vec.pop_back();
+ __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC);
+ } else {
+ size_t size = my_rand_r(&seed) % 1000 + 1;
+ switch ((my_rand_r(&seed) % 128)) {
+ case 0: size += 1024; break;
+ case 1: size += 2048; break;
+ case 2: size += 4096; break;
+ }
+ size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
+ char *ptr = (char*)__asan::asan_memalign(alignment, size,
+ &stack2, __asan::FROM_MALLOC);
+ EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
+ vec.push_back(ptr);
+ ptr[0] = 0;
+ ptr[size-1] = 0;
+ ptr[size/2] = 0;
+ }
+ }
+ for (size_t i = 0; i < vec.size(); i++)
+ __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC);
+}
+
+
+TEST(AddressSanitizer, NoInstMallocTest) {
+ MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
+}
+
+TEST(AddressSanitizer, ThreadedMallocStressTest) {
+ const int kNumThreads = 4;
+ const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress,
+ (void*)kNumIterations);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+static void PrintShadow(const char *tag, uptr ptr, size_t size) {
+ fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
+ uptr prev_shadow = 0;
+ for (sptr i = -32; i < (sptr)size + 32; i++) {
+ uptr shadow = __asan::MemToShadow(ptr + i);
+ if (i == 0 || i == (sptr)size)
+ fprintf(stderr, ".");
+ if (shadow != prev_shadow) {
+ prev_shadow = shadow;
+ fprintf(stderr, "%02x", (int)*(u8*)shadow);
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
+ for (size_t size = 1; size <= 513; size++) {
+ char *ptr = new char[size];
+ PrintShadow("m", (uptr)ptr, size);
+ delete [] ptr;
+ PrintShadow("f", (uptr)ptr, size);
+ }
+}
+
+TEST(AddressSanitizer, QuarantineTest) {
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ const int size = 1024;
+ void *p = __asan::asan_malloc(size, &stack);
+ __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
+ size_t i;
+ size_t max_i = 1 << 30;
+ for (i = 0; i < max_i; i++) {
+ void *p1 = __asan::asan_malloc(size, &stack);
+ __asan::asan_free(p1, &stack, __asan::FROM_MALLOC);
+ if (p1 == p) break;
+ }
+ EXPECT_GE(i, 10000U);
+ EXPECT_LT(i, max_i);
+}
+
+void *ThreadedQuarantineTestWorker(void *unused) {
+ (void)unused;
+ u32 seed = my_rand();
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (size_t i = 0; i < 1000; i++) {
+ void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack);
+ __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
+ }
+ return NULL;
+}
+
+// Check that the thread local allocators are flushed when threads are
+// destroyed.
+TEST(AddressSanitizer, ThreadedQuarantineTest) {
+ const int n_threads = 3000;
+ size_t mmaped1 = __sanitizer_get_heap_size();
+ for (int i = 0; i < n_threads; i++) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
+ PTHREAD_JOIN(t, 0);
+ size_t mmaped2 = __sanitizer_get_heap_size();
+ EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
+ }
+}
+
+void *ThreadedOneSizeMallocStress(void *unused) {
+ (void)unused;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+ const size_t kNumMallocs = 1000;
+ for (int iter = 0; iter < 1000; iter++) {
+ void *p[kNumMallocs];
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ p[i] = __asan::asan_malloc(32, &stack);
+ }
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC);
+ }
+ }
+ return NULL;
+}
+
+TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
+ const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
+ using __asan::kHighMemEnd;
+ // Check that __asan_region_is_poisoned works for shadow regions.
+ uptr ptr = kLowShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kShadowGapBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kHighShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+}
+
+// Test __asan_load1 & friends.
+TEST(AddressSanitizer, LoadStoreCallbacks) {
+ typedef void (*CB)(uptr p);
+ CB cb[2][5] = {
+ {
+ __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
+ }, {
+ __asan_store1, __asan_store2, __asan_store4, __asan_store8,
+ __asan_store16,
+ }
+ };
+
+ uptr buggy_ptr;
+
+ __asan_test_only_reported_buggy_pointer = &buggy_ptr;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (uptr len = 16; len <= 32; len++) {
+ char *ptr = (char*) __asan::asan_malloc(len, &stack);
+ uptr p = reinterpret_cast<uptr>(ptr);
+ for (uptr is_write = 0; is_write <= 1; is_write++) {
+ for (uptr size_log = 0; size_log <= 4; size_log++) {
+ uptr size = 1 << size_log;
+ CB call = cb[is_write][size_log];
+ // Iterate only size-aligned offsets.
+ for (uptr offset = 0; offset <= len; offset += size) {
+ buggy_ptr = 0;
+ call(p + offset);
+ if (offset + size <= len)
+ EXPECT_EQ(buggy_ptr, 0U);
+ else
+ EXPECT_EQ(buggy_ptr, p + offset);
+ }
+ }
+ }
+ __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
+ }
+ __asan_test_only_reported_buggy_pointer = 0;
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc
new file mode 100644
index 000000000000..0c6bea285864
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc
@@ -0,0 +1,128 @@
+//===-- asan_oob_test.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
+ EXPECT_EQ(0U, ((uintptr_t)p % size));
+ if (size == 1) asan_write((uint8_t*)p);
+ else if (size == 2) asan_write((uint16_t*)p);
+ else if (size == 4) asan_write((uint32_t*)p);
+ else if (size == 8) asan_write((uint64_t*)p);
+}
+
+template<typename T>
+NOINLINE void oob_test(int size, int off) {
+ char *p = (char*)malloc_aaa(size);
+ // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
+ // sizeof(T), p, p + size, off);
+ asan_write((T*)(p + off));
+ free_aaa(p);
+}
+
+template<typename T>
+void OOBTest() {
+ char expected_str[100];
+ for (int size = sizeof(T); size < 20; size += 5) {
+ for (int i = -5; i < 0; i++) {
+ const char *str =
+ "is located.*%d byte.*to the left";
+ sprintf(expected_str, str, abs(i));
+ EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+ }
+
+ for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
+ oob_test<T>(size, i);
+
+ for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) {
+ const char *str =
+ "is located.*%d byte.*to the right";
+ int off = i >= size ? (i - size) : 0;
+ // we don't catch unaligned partially OOB accesses.
+ if (i % sizeof(T)) continue;
+ sprintf(expected_str, str, off);
+ EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+ }
+ }
+
+ EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
+ "is located.*1 byte.*to the left");
+ EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
+ "is located.*0 byte.*to the right");
+}
+
+// TODO(glider): the following tests are EXTREMELY slow on Darwin:
+// AddressSanitizer.OOB_char (125503 ms)
+// AddressSanitizer.OOB_int (126890 ms)
+// AddressSanitizer.OOBRightTest (315605 ms)
+// AddressSanitizer.SimpleStackTest (366559 ms)
+
+TEST(AddressSanitizer, OOB_char) {
+ OOBTest<U1>();
+}
+
+TEST(AddressSanitizer, OOB_int) {
+ OOBTest<U4>();
+}
+
+TEST(AddressSanitizer, OOBRightTest) {
+ size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
+ for (size_t access_size = 1; access_size <= max_access_size;
+ access_size *= 2) {
+ for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
+ for (size_t offset = 0; offset <= 8; offset += access_size) {
+ void *p = malloc(alloc_size);
+ // allocated: [p, p + alloc_size)
+ // accessed: [p + offset, p + offset + access_size)
+ uint8_t *addr = (uint8_t*)p + offset;
+ if (offset + access_size <= alloc_size) {
+ asan_write_sized_aligned(addr, access_size);
+ } else {
+ int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
+ const char *str =
+ "is located.%d *byte.*to the right";
+ char expected_str[100];
+ sprintf(expected_str, str, outside_bytes);
+ EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
+ expected_str);
+ }
+ free(p);
+ }
+ }
+ }
+}
+
+TEST(AddressSanitizer, LargeOOBRightTest) {
+ size_t large_power_of_two = 1 << 19;
+ for (size_t i = 16; i <= 256; i *= 2) {
+ size_t size = large_power_of_two - i;
+ char *p = Ident(new char[size]);
+ EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
+ delete [] p;
+ }
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
+ oob_test<U1>(10, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
+ oob_test<U1>(kLargeMalloc, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
+ oob_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
+ oob_test<U1>(kLargeMalloc, kLargeMalloc);
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc
new file mode 100644
index 000000000000..23240e714d56
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc
@@ -0,0 +1,32 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+const int N = 1000;
+void *x[N];
+
+void *Thread1(void *unused) {
+ for (int i = 0; i < N; i++) {
+ fprintf(stderr, "%s %d\n", __func__, i);
+ free(x[i]);
+ }
+ return NULL;
+}
+
+void *Thread2(void *unused) {
+ for (int i = 0; i < N; i++) {
+ fprintf(stderr, "%s %d\n", __func__, i);
+ free(x[i]);
+ }
+ return NULL;
+}
+
+int main() {
+ for (int i = 0; i < N; i++)
+ x[i] = malloc(128);
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc
new file mode 100644
index 000000000000..1cd2a08b9021
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc
@@ -0,0 +1,602 @@
+//=-- asan_str_test.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#if defined(__APPLE__)
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#endif
+
+// Used for string functions tests
+static char global_string[] = "global";
+static size_t global_string_length = 6;
+
+// Input to a test is a zero-terminated string str with given length
+// Accesses to the bytes to the left and to the right of str
+// are presumed to produce OOB errors
+void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
+ // Normal strlen calls
+ EXPECT_EQ(strlen(str), length);
+ if (length > 0) {
+ EXPECT_EQ(length - 1, strlen(str + 1));
+ EXPECT_EQ(0U, strlen(str + length));
+ }
+ // Arg of strlen is not malloced, OOB access
+ if (!is_global) {
+ // We don't insert RedZones to the left of global variables
+ EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(5));
+ }
+ EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBReadMessage(0));
+ // Overwrite terminator
+ str[length] = 'a';
+ // String is not zero-terminated, strlen will lead to OOB access
+ EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(0));
+ // Restore terminator
+ str[length] = 0;
+}
+TEST(AddressSanitizer, StrLenOOBTest) {
+ // Check heap-allocated string
+ size_t length = Ident(10);
+ char *heap_string = Ident((char*)malloc(length + 1));
+ char stack_string[10 + 1];
+ break_optimization(&stack_string);
+ for (size_t i = 0; i < length; i++) {
+ heap_string[i] = 'a';
+ stack_string[i] = 'b';
+ }
+ heap_string[length] = 0;
+ stack_string[length] = 0;
+ StrLenOOBTestTemplate(heap_string, length, false);
+ // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
+ // make test for stack_string work. Or move it to output tests.
+ // StrLenOOBTestTemplate(stack_string, length, false);
+ StrLenOOBTestTemplate(global_string, global_string_length, true);
+ free(heap_string);
+}
+
+TEST(AddressSanitizer, WcsLenTest) {
+ EXPECT_EQ(0U, wcslen(Ident(L"")));
+ size_t hello_len = 13;
+ size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
+ EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
+ wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
+ memcpy(heap_string, L"Hello, World!", hello_size);
+ EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
+ EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
+ free(heap_string);
+}
+
+#if SANITIZER_TEST_HAS_STRNLEN
+TEST(AddressSanitizer, StrNLenOOBTest) {
+ size_t size = Ident(123);
+ char *str = MallocAndMemsetString(size);
+ // Normal strnlen calls.
+ Ident(strnlen(str - 1, 0));
+ Ident(strnlen(str, size));
+ Ident(strnlen(str + size - 1, 1));
+ str[size - 1] = '\0';
+ Ident(strnlen(str, 2 * size));
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
+ free(str);
+}
+#endif // SANITIZER_TEST_HAS_STRNLEN
+
+TEST(AddressSanitizer, StrDupOOBTest) {
+ size_t size = Ident(42);
+ char *str = MallocAndMemsetString(size);
+ char *new_str;
+ // Normal strdup calls.
+ str[size - 1] = '\0';
+ new_str = strdup(str);
+ free(new_str);
+ new_str = strdup(str + size - 1);
+ free(new_str);
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
+ free(str);
+}
+
+TEST(AddressSanitizer, StrCpyOOBTest) {
+ size_t to_size = Ident(30);
+ size_t from_size = Ident(6); // less than to_size
+ char *to = Ident((char*)malloc(to_size));
+ char *from = Ident((char*)malloc(from_size));
+ // Normal strcpy calls.
+ strcpy(from, "hello");
+ strcpy(to, from);
+ strcpy(to + to_size - from_size, from);
+ // Length of "from" is too small.
+ EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
+ // "to" or "from" points to not allocated memory.
+ EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
+ EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
+ // Overwrite the terminating '\0' character and hit unallocated memory.
+ from[from_size - 1] = '!';
+ EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
+ free(to);
+ free(from);
+}
+
+TEST(AddressSanitizer, StrNCpyOOBTest) {
+ size_t to_size = Ident(20);
+ size_t from_size = Ident(6); // less than to_size
+ char *to = Ident((char*)malloc(to_size));
+ // From is a zero-terminated string "hello\0" of length 6
+ char *from = Ident((char*)malloc(from_size));
+ strcpy(from, "hello");
+ // copy 0 bytes
+ strncpy(to, from, 0);
+ strncpy(to - 1, from - 1, 0);
+ // normal strncpy calls
+ strncpy(to, from, from_size);
+ strncpy(to, from, to_size);
+ strncpy(to, from + from_size - 1, to_size);
+ strncpy(to + to_size - 1, from, 1);
+ // One of {to, from} points to not allocated memory
+ EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
+ LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
+ LeftOOBWriteMessage(1));
+ EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
+ RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
+ RightOOBWriteMessage(0));
+ // Length of "to" is too small
+ EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
+ RightOOBWriteMessage(0));
+ // Overwrite terminator in from
+ from[from_size - 1] = '!';
+ // normal strncpy call
+ strncpy(to, from, from_size);
+ // Length of "from" is too small
+ EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
+ RightOOBReadMessage(0));
+ free(to);
+ free(from);
+}
+
+// Users may have different definitions of "strchr" and "index", so provide
+// function pointer typedefs and overload RunStrChrTest implementation.
+// We can't use macro for RunStrChrTest body here, as this macro would
+// confuse EXPECT_DEATH gtest macro.
+typedef char*(*PointerToStrChr1)(const char*, int);
+typedef char*(*PointerToStrChr2)(char*, int);
+
+UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr) {
+ size_t size = Ident(100);
+ char *str = MallocAndMemsetString(size);
+ str[10] = 'q';
+ str[11] = '\0';
+ EXPECT_EQ(str, StrChr(str, 'z'));
+ EXPECT_EQ(str + 10, StrChr(str, 'q'));
+ EXPECT_EQ(NULL, StrChr(str, 'a'));
+ // StrChr argument points to not allocated memory.
+ EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
+ // Overwrite the terminator and hit not allocated memory.
+ str[11] = 'z';
+ EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
+ free(str);
+}
+UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
+ size_t size = Ident(100);
+ char *str = MallocAndMemsetString(size);
+ str[10] = 'q';
+ str[11] = '\0';
+ EXPECT_EQ(str, StrChr(str, 'z'));
+ EXPECT_EQ(str + 10, StrChr(str, 'q'));
+ EXPECT_EQ(NULL, StrChr(str, 'a'));
+ // StrChr argument points to not allocated memory.
+ EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
+ // Overwrite the terminator and hit not allocated memory.
+ str[11] = 'z';
+ EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
+ free(str);
+}
+
+TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
+ RunStrChrTest(&strchr);
+// No index() on Windows and on Android L.
+#if !defined(_WIN32) && !defined(__ANDROID__)
+ RunStrChrTest(&index);
+#endif
+}
+
+TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
+ // strcmp
+ EXPECT_EQ(0, strcmp("", ""));
+ EXPECT_EQ(0, strcmp("abcd", "abcd"));
+ EXPECT_GT(0, strcmp("ab", "ac"));
+ EXPECT_GT(0, strcmp("abc", "abcd"));
+ EXPECT_LT(0, strcmp("acc", "abc"));
+ EXPECT_LT(0, strcmp("abcd", "abc"));
+
+ // strncmp
+ EXPECT_EQ(0, strncmp("a", "b", 0));
+ EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
+ EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
+ EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
+ EXPECT_GT(0, strncmp("a", "b", 5));
+ EXPECT_GT(0, strncmp("bc", "bcde", 4));
+ EXPECT_LT(0, strncmp("xyz", "xyy", 10));
+ EXPECT_LT(0, strncmp("baa", "aaa", 1));
+ EXPECT_LT(0, strncmp("zyx", "", 2));
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+ // strcasecmp
+ EXPECT_EQ(0, strcasecmp("", ""));
+ EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
+ EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
+ EXPECT_GT(0, strcasecmp("aB", "Ac"));
+ EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
+ EXPECT_LT(0, strcasecmp("acc", "abc"));
+ EXPECT_LT(0, strcasecmp("ABCd", "abc"));
+
+ // strncasecmp
+ EXPECT_EQ(0, strncasecmp("a", "b", 0));
+ EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
+ EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
+ EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
+ EXPECT_GT(0, strncasecmp("a", "B", 5));
+ EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
+ EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
+ EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
+ EXPECT_LT(0, strncasecmp("zyx", "", 2));
+#endif
+
+ // memcmp
+ EXPECT_EQ(0, memcmp("a", "b", 0));
+ EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
+ EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
+ EXPECT_GT(0, memcmp("abb\0", "abba", 4));
+ EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
+ EXPECT_LT(0, memcmp("zza", "zyx", 3));
+}
+
+typedef int(*PointerToStrCmp)(const char*, const char*);
+void RunStrCmpTest(PointerToStrCmp StrCmp) {
+ size_t size = Ident(100);
+ int fill = 'o';
+ char *s1 = MallocAndMemsetString(size, fill);
+ char *s2 = MallocAndMemsetString(size, fill);
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ // Normal StrCmp calls
+ Ident(StrCmp(s1, s2));
+ Ident(StrCmp(s1, s2 + size - 1));
+ Ident(StrCmp(s1 + size - 1, s2 + size - 1));
+ s1[size - 1] = 'z';
+ s2[size - 1] = 'x';
+ Ident(StrCmp(s1, s2));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ s1[size - 1] = fill;
+ EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, StrCmpOOBTest) {
+ RunStrCmpTest(&strcmp);
+}
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+TEST(AddressSanitizer, StrCaseCmpOOBTest) {
+ RunStrCmpTest(&strcasecmp);
+}
+#endif
+
+typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
+void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
+ size_t size = Ident(100);
+ char *s1 = MallocAndMemsetString(size);
+ char *s2 = MallocAndMemsetString(size);
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ // Normal StrNCmp calls
+ Ident(StrNCmp(s1, s2, size + 2));
+ s1[size - 1] = 'z';
+ s2[size - 1] = 'x';
+ Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
+ s2[size - 1] = 'z';
+ Ident(StrNCmp(s1 - 1, s2 - 1, 0));
+ Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, StrNCmpOOBTest) {
+ RunStrNCmpTest(&strncmp);
+}
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
+ RunStrNCmpTest(&strncasecmp);
+}
+#endif
+
+TEST(AddressSanitizer, StrCatOOBTest) {
+ // strcat() reads strlen(to) bytes from |to| before concatenating.
+ size_t to_size = Ident(100);
+ char *to = MallocAndMemsetString(to_size);
+ to[0] = '\0';
+ size_t from_size = Ident(20);
+ char *from = MallocAndMemsetString(from_size);
+ from[from_size - 1] = '\0';
+ // Normal strcat calls.
+ strcat(to, from);
+ strcat(to, from);
+ strcat(to + from_size, from + from_size - 2);
+ // Passing an invalid pointer is an error even when concatenating an empty
+ // string.
+ EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
+ EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(strcat(to + to_size, from), RightOOBWriteMessage(0));
+ EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
+
+ // "from" is not zero-terminated.
+ from[from_size - 1] = 'z';
+ EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
+ from[from_size - 1] = '\0';
+ // "to" is not zero-terminated.
+ memset(to, 'z', to_size);
+ EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
+ // "to" is too short to fit "from".
+ to[to_size - from_size + 1] = '\0';
+ EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
+ // length of "to" is just enough.
+ strcat(to, from + 1);
+
+ free(to);
+ free(from);
+}
+
+TEST(AddressSanitizer, StrNCatOOBTest) {
+ // strncat() reads strlen(to) bytes from |to| before concatenating.
+ size_t to_size = Ident(100);
+ char *to = MallocAndMemsetString(to_size);
+ to[0] = '\0';
+ size_t from_size = Ident(20);
+ char *from = MallocAndMemsetString(from_size);
+ // Normal strncat calls.
+ strncat(to, from, 0);
+ strncat(to, from, from_size);
+ from[from_size - 1] = '\0';
+ strncat(to, from, 2 * from_size);
+ // Catenating empty string with an invalid string is still an error.
+ EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
+ strncat(to, from + from_size - 1, 10);
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
+ EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
+ EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBWriteMessage(0));
+ EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
+
+ memset(from, 'z', from_size);
+ memset(to, 'z', to_size);
+ to[0] = '\0';
+ // "from" is too short.
+ EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
+ // "to" is not zero-terminated.
+ EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBWriteMessage(0));
+ // "to" is too short to fit "from".
+ to[0] = 'z';
+ to[to_size - from_size + 1] = '\0';
+ EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
+ // "to" is just enough.
+ strncat(to, from, from_size - 2);
+
+ free(to);
+ free(from);
+}
+
+static string OverlapErrorMessage(const string &func) {
+ return func + "-param-overlap";
+}
+
+TEST(AddressSanitizer, StrArgsOverlapTest) {
+ size_t size = Ident(100);
+ char *str = Ident((char*)malloc(size));
+
+// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
+// memmove().
+#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
+ (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
+ // Check "memcpy". Use Ident() to avoid inlining.
+ memset(str, 'z', size);
+ Ident(memcpy)(str + 1, str + 11, 10);
+ Ident(memcpy)(str, str, 0);
+ EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
+ EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
+#endif
+
+ // We do not treat memcpy with to==from as a bug.
+ // See http://llvm.org/bugs/show_bug.cgi?id=11763.
+ // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
+ // OverlapErrorMessage("memcpy"));
+
+ // Check "strcpy".
+ memset(str, 'z', size);
+ str[9] = '\0';
+ strcpy(str + 10, str);
+ EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
+ EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
+ strcpy(str, str + 5);
+
+ // Check "strncpy".
+ memset(str, 'z', size);
+ strncpy(str, str + 10, 10);
+ EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
+ EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
+ str[10] = '\0';
+ strncpy(str + 11, str, 20);
+ EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
+
+ // Check "strcat".
+ memset(str, 'z', size);
+ str[10] = '\0';
+ str[20] = '\0';
+ strcat(str, str + 10);
+ EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
+ str[10] = '\0';
+ strcat(str + 11, str);
+ EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
+ EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
+ EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
+
+ // Check "strncat".
+ memset(str, 'z', size);
+ str[10] = '\0';
+ strncat(str, str + 10, 10); // from is empty
+ EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
+ str[10] = '\0';
+ str[20] = '\0';
+ strncat(str + 5, str, 5);
+ str[10] = '\0';
+ EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
+ EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
+
+ free(str);
+}
+
+typedef void(*PointerToCallAtoi)(const char*);
+
+void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
+ char *array = MallocAndMemsetString(10, '1');
+ // Invalid pointer to the string.
+ EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
+ EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
+ // Die if a buffer doesn't have terminating NULL.
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ // Make last symbol a terminating NULL or other non-digit.
+ array[9] = '\0';
+ Atoi(array);
+ array[9] = 'a';
+ Atoi(array);
+ Atoi(array + 9);
+ // Sometimes we need to detect overflow if no digits are found.
+ memset(array, ' ', 10);
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ array[9] = '-';
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
+ array[8] = '-';
+ Atoi(array);
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallAtoi(const char *nptr) {
+ Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+ Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+ Ident(atoll(nptr));
+}
+TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
+ RunAtoiOOBTest(&CallAtoi);
+ RunAtoiOOBTest(&CallAtol);
+ RunAtoiOOBTest(&CallAtoll);
+}
+#endif
+
+typedef void(*PointerToCallStrtol)(const char*, char**, int);
+
+void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
+ char *array = MallocAndMemsetString(3);
+ char *endptr = NULL;
+ array[0] = '1';
+ array[1] = '2';
+ array[2] = '3';
+ // Invalid pointer to the string.
+ EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
+ EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
+ // Buffer overflow if there is no terminating null (depends on base).
+ Strtol(array, &endptr, 3);
+ EXPECT_EQ(array + 2, endptr);
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = 'z';
+ Strtol(array, &endptr, 35);
+ EXPECT_EQ(array + 2, endptr);
+ EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
+ // Add terminating zero to get rid of overflow.
+ array[2] = '\0';
+ Strtol(array, NULL, 36);
+ // Don't check for overflow if base is invalid.
+ Strtol(array - 1, NULL, -1);
+ Strtol(array + 3, NULL, 1);
+ // Sometimes we need to detect overflow if no digits are found.
+ array[0] = array[1] = array[2] = ' ';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = '+';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = '-';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[1] = '+';
+ Strtol(array, NULL, 0);
+ array[1] = array[2] = 'z';
+ Strtol(array, &endptr, 0);
+ EXPECT_EQ(array, endptr);
+ Strtol(array + 2, NULL, 0);
+ EXPECT_EQ(array, endptr);
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallStrtol(const char *nptr, char **endptr, int base) {
+ Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+ Ident(strtoll(nptr, endptr, base));
+}
+TEST(AddressSanitizer, StrtollOOBTest) {
+ RunStrtolOOBTest(&CallStrtoll);
+}
+TEST(AddressSanitizer, StrtolOOBTest) {
+ RunStrtolOOBTest(&CallStrtol);
+}
+#endif
+
+
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_test.cc
new file mode 100644
index 000000000000..952b05e21fe2
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_test.cc
@@ -0,0 +1,1317 @@
+//===-- asan_test.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+NOINLINE void *malloc_fff(size_t size) {
+ void *res = malloc/**/(size); break_optimization(0); return res;}
+NOINLINE void *malloc_eee(size_t size) {
+ void *res = malloc_fff(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ddd(size_t size) {
+ void *res = malloc_eee(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ccc(size_t size) {
+ void *res = malloc_ddd(size); break_optimization(0); return res;}
+NOINLINE void *malloc_bbb(size_t size) {
+ void *res = malloc_ccc(size); break_optimization(0); return res;}
+NOINLINE void *malloc_aaa(size_t size) {
+ void *res = malloc_bbb(size); break_optimization(0); return res;}
+
+NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
+NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
+NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
+
+template<typename T>
+NOINLINE void uaf_test(int size, int off) {
+ char *p = (char *)malloc_aaa(size);
+ free_aaa(p);
+ for (int i = 1; i < 100; i++)
+ free_aaa(malloc_aaa(i));
+ fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
+ (long)sizeof(T), p, off);
+ asan_write((T*)(p + off));
+}
+
+TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
+#if defined(__has_feature) && __has_feature(address_sanitizer)
+ bool asan = 1;
+#elif defined(__SANITIZE_ADDRESS__)
+ bool asan = 1;
+#else
+ bool asan = 0;
+#endif
+ EXPECT_EQ(true, asan);
+}
+
+TEST(AddressSanitizer, SimpleDeathTest) {
+ EXPECT_DEATH(exit(1), "");
+}
+
+TEST(AddressSanitizer, VariousMallocsTest) {
+ int *a = (int*)malloc(100 * sizeof(int));
+ a[50] = 0;
+ free(a);
+
+ int *r = (int*)malloc(10);
+ r = (int*)realloc(r, 2000 * sizeof(int));
+ r[1000] = 0;
+ free(r);
+
+ int *b = new int[100];
+ b[50] = 0;
+ delete [] b;
+
+ int *c = new int;
+ *c = 0;
+ delete c;
+
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int *pm;
+ int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
+ EXPECT_EQ(0, pm_res);
+ free(pm);
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
+
+#if SANITIZER_TEST_HAS_MEMALIGN
+ int *ma = (int*)memalign(kPageSize, kPageSize);
+ EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
+ ma[123] = 0;
+ free(ma);
+#endif // SANITIZER_TEST_HAS_MEMALIGN
+}
+
+TEST(AddressSanitizer, CallocTest) {
+ int *a = (int*)calloc(100, sizeof(int));
+ EXPECT_EQ(0, a[10]);
+ free(a);
+}
+
+TEST(AddressSanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+#if !defined(_WIN32)
+ // FIXME: OOM on Windows. We should just make this a lit test
+ // with quarantine size set to 1.
+ free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+#endif
+ }
+ }
+}
+
+// No valloc on Windows or Android.
+#if !defined(_WIN32) && !defined(__ANDROID__)
+TEST(AddressSanitizer, VallocTest) {
+ void *a = valloc(100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ free(a);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_PVALLOC
+TEST(AddressSanitizer, PvallocTest) {
+ char *a = (char*)pvalloc(kPageSize + 100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ a[kPageSize + 101] = 1; // we should not report an error here.
+ free(a);
+
+ a = (char*)pvalloc(0); // pvalloc(0) should allocate at least one page.
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ a[101] = 1; // we should not report an error here.
+ free(a);
+}
+#endif // SANITIZER_TEST_HAS_PVALLOC
+
+#if !defined(_WIN32)
+// FIXME: Use an equivalent of pthread_setspecific on Windows.
+void *TSDWorker(void *test_key) {
+ if (test_key) {
+ pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
+ }
+ return NULL;
+}
+
+void TSDDestructor(void *tsd) {
+ // Spawning a thread will check that the current thread id is not -1.
+ pthread_t th;
+ PTHREAD_CREATE(&th, NULL, TSDWorker, NULL);
+ PTHREAD_JOIN(th, NULL);
+}
+
+// This tests triggers the thread-specific data destruction fiasco which occurs
+// if we don't manage the TSD destructors ourselves. We create a new pthread
+// key with a non-NULL destructor which is likely to be put after the destructor
+// of AsanThread in the list of destructors.
+// In this case the TSD for AsanThread will be destroyed before TSDDestructor
+// is called for the child thread, and a CHECK will fail when we call
+// pthread_create() to spawn the grandchild.
+TEST(AddressSanitizer, DISABLED_TSDTest) {
+ pthread_t th;
+ pthread_key_t test_key;
+ pthread_key_create(&test_key, TSDDestructor);
+ PTHREAD_CREATE(&th, NULL, TSDWorker, &test_key);
+ PTHREAD_JOIN(th, NULL);
+ pthread_key_delete(test_key);
+}
+#endif
+
+TEST(AddressSanitizer, UAF_char) {
+ const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
+ EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
+}
+
+TEST(AddressSanitizer, UAF_long_double) {
+ if (sizeof(long double) == sizeof(double)) return;
+ long double *p = Ident(new long double[10]);
+ EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
+ EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
+ delete [] Ident(p);
+}
+
+#if !defined(_WIN32)
+struct Packed5 {
+ int x;
+ char c;
+} __attribute__((packed));
+#else
+# pragma pack(push, 1)
+struct Packed5 {
+ int x;
+ char c;
+};
+# pragma pack(pop)
+#endif
+
+TEST(AddressSanitizer, UAF_Packed5) {
+ static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
+ Packed5 *p = Ident(new Packed5[2]);
+ EXPECT_DEATH(p[0] = p[3], "READ of size 5");
+ EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
+ delete [] Ident(p);
+}
+
+#if ASAN_HAS_BLACKLIST
+TEST(AddressSanitizer, IgnoreTest) {
+ int *x = Ident(new int);
+ delete Ident(x);
+ *x = 0;
+}
+#endif // ASAN_HAS_BLACKLIST
+
+struct StructWithBitField {
+ int bf1:1;
+ int bf2:1;
+ int bf3:1;
+ int bf4:29;
+};
+
+TEST(AddressSanitizer, BitFieldPositiveTest) {
+ StructWithBitField *x = new StructWithBitField;
+ delete Ident(x);
+ EXPECT_DEATH(x->bf1 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf2 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf3 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf4 = 0, "use-after-free");
+}
+
+struct StructWithBitFields_8_24 {
+ int a:8;
+ int b:24;
+};
+
+TEST(AddressSanitizer, BitFieldNegativeTest) {
+ StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
+ x->a = 0;
+ x->b = 0;
+ delete Ident(x);
+}
+
+#if ASAN_NEEDS_SEGV
+namespace {
+
+const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address";
+const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
+
+TEST(AddressSanitizer, WildAddressTest) {
+ char *c = (char*)0x123;
+ EXPECT_DEATH(*c = 0, kUnknownCrash);
+}
+
+void my_sigaction_sighandler(int, siginfo_t*, void*) {
+ fprintf(stderr, kOverriddenHandler);
+ exit(1);
+}
+
+void my_signal_sighandler(int signum) {
+ fprintf(stderr, kOverriddenHandler);
+ exit(1);
+}
+
+TEST(AddressSanitizer, SignalTest) {
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = my_sigaction_sighandler;
+ sigact.sa_flags = SA_SIGINFO;
+ // ASan should silently ignore sigaction()...
+ EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
+#ifdef __APPLE__
+ EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
+#endif
+ char *c = (char*)0x123;
+ EXPECT_DEATH(*c = 0, kUnknownCrash);
+ // ... and signal().
+ EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
+ EXPECT_DEATH(*c = 0, kUnknownCrash);
+}
+} // namespace
+#endif
+
+static void TestLargeMalloc(size_t size) {
+ char buff[1024];
+ sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
+ EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
+}
+
+TEST(AddressSanitizer, LargeMallocTest) {
+ const int max_size = (SANITIZER_WORDSIZE == 32) ? 1 << 26 : 1 << 28;
+ for (int i = 113; i < max_size; i = i * 2 + 13) {
+ TestLargeMalloc(i);
+ }
+}
+
+TEST(AddressSanitizer, HugeMallocTest) {
+ if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
+ size_t n_megs = 4100;
+ EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
+ "is located 1 bytes to the left|"
+ "AddressSanitizer failed to allocate");
+}
+
+#if SANITIZER_TEST_HAS_MEMALIGN
+void MemalignRun(size_t align, size_t size, int idx) {
+ char *p = (char *)memalign(align, size);
+ Ident(p)[idx] = 0;
+ free(p);
+}
+
+TEST(AddressSanitizer, memalign) {
+ for (int align = 16; align <= (1 << 23); align *= 2) {
+ size_t size = align * 5;
+ EXPECT_DEATH(MemalignRun(align, size, -1),
+ "is located 1 bytes to the left");
+ EXPECT_DEATH(MemalignRun(align, size, size + 1),
+ "is located 1 bytes to the right");
+ }
+}
+#endif // SANITIZER_TEST_HAS_MEMALIGN
+
+void *ManyThreadsWorker(void *a) {
+ for (int iter = 0; iter < 100; iter++) {
+ for (size_t size = 100; size < 2000; size *= 2) {
+ free(Ident(malloc(size)));
+ }
+ }
+ return 0;
+}
+
+TEST(AddressSanitizer, ManyThreadsTest) {
+ const size_t kNumThreads =
+ (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
+ pthread_t t[kNumThreads];
+ for (size_t i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, ManyThreadsWorker, (void*)i);
+ }
+ for (size_t i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+TEST(AddressSanitizer, ReallocTest) {
+ const int kMinElem = 5;
+ int *ptr = (int*)malloc(sizeof(int) * kMinElem);
+ ptr[3] = 3;
+ for (int i = 0; i < 10000; i++) {
+ ptr = (int*)realloc(ptr,
+ (my_rand() % 1000 + kMinElem) * sizeof(int));
+ EXPECT_EQ(3, ptr[3]);
+ }
+ free(ptr);
+ // Realloc pointer returned by malloc(0).
+ int *ptr2 = Ident((int*)malloc(0));
+ ptr2 = Ident((int*)realloc(ptr2, sizeof(*ptr2)));
+ *ptr2 = 42;
+ EXPECT_EQ(42, *ptr2);
+ free(ptr2);
+}
+
+TEST(AddressSanitizer, ReallocFreedPointerTest) {
+ void *ptr = Ident(malloc(42));
+ ASSERT_TRUE(NULL != ptr);
+ free(ptr);
+ EXPECT_DEATH(ptr = realloc(ptr, 77), "attempting double-free");
+}
+
+TEST(AddressSanitizer, ReallocInvalidPointerTest) {
+ void *ptr = Ident(malloc(42));
+ EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
+ free(ptr);
+}
+
+TEST(AddressSanitizer, ZeroSizeMallocTest) {
+ // Test that malloc(0) and similar functions don't return NULL.
+ void *ptr = Ident(malloc(0));
+ EXPECT_TRUE(NULL != ptr);
+ free(ptr);
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int pm_res = posix_memalign(&ptr, 1<<20, 0);
+ EXPECT_EQ(0, pm_res);
+ EXPECT_TRUE(NULL != ptr);
+ free(ptr);
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int *int_ptr = new int[0];
+ int *int_ptr2 = new int[0];
+ EXPECT_TRUE(NULL != int_ptr);
+ EXPECT_TRUE(NULL != int_ptr2);
+ EXPECT_NE(int_ptr, int_ptr2);
+ delete[] int_ptr;
+ delete[] int_ptr2;
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+static const char *kMallocUsableSizeErrorMsg =
+ "AddressSanitizer: attempting to call malloc_usable_size()";
+
+TEST(AddressSanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
+ EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
+ kMallocUsableSizeErrorMsg);
+ free(array);
+ EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+
+void WrongFree() {
+ int *x = (int*)malloc(100 * sizeof(int));
+ // Use the allocated memory, otherwise Clang will optimize it out.
+ Ident(x);
+ free(x + 1);
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, WrongFreeTest) {
+ EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
+ "ERROR: AddressSanitizer: attempting free.*not malloc"
+ ".*is located 4 bytes inside of 400-byte region"
+ ".*allocated by thread");
+}
+#endif
+
+void DoubleFree() {
+ int *x = (int*)malloc(100 * sizeof(int));
+ fprintf(stderr, "DoubleFree: x=%p\n", x);
+ free(x);
+ free(x);
+ fprintf(stderr, "should have failed in the second free(%p)\n", x);
+ abort();
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, DoubleFreeTest) {
+ EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
+ "ERROR: AddressSanitizer: attempting double-free"
+ ".*is located 0 bytes inside of 400-byte region"
+ ".*freed by thread T0 here"
+ ".*previously allocated by thread T0 here");
+}
+#endif
+
+template<int kSize>
+NOINLINE void SizedStackTest() {
+ char a[kSize];
+ char *A = Ident((char*)&a);
+ const char *expected_death = "AddressSanitizer: stack-buffer-";
+ for (size_t i = 0; i < kSize; i++)
+ A[i] = i;
+ EXPECT_DEATH(A[-1] = 0, expected_death);
+ EXPECT_DEATH(A[-5] = 0, expected_death);
+ EXPECT_DEATH(A[kSize] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
+ if (kSize > 16)
+ EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
+}
+
+TEST(AddressSanitizer, SimpleStackTest) {
+ SizedStackTest<1>();
+ SizedStackTest<2>();
+ SizedStackTest<3>();
+ SizedStackTest<4>();
+ SizedStackTest<5>();
+ SizedStackTest<6>();
+ SizedStackTest<7>();
+ SizedStackTest<16>();
+ SizedStackTest<25>();
+ SizedStackTest<34>();
+ SizedStackTest<43>();
+ SizedStackTest<51>();
+ SizedStackTest<62>();
+ SizedStackTest<64>();
+ SizedStackTest<128>();
+}
+
+#if !defined(_WIN32)
+// FIXME: It's a bit hard to write multi-line death test expectations
+// in a portable way. Anyways, this should just be turned into a lit test.
+TEST(AddressSanitizer, ManyStackObjectsTest) {
+ char XXX[10];
+ char YYY[20];
+ char ZZZ[30];
+ Ident(XXX);
+ Ident(YYY);
+ EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
+}
+#endif
+
+#if 0 // This test requires online symbolizer.
+// Moved to lit_tests/stack-oob-frames.cc.
+// Reenable here once we have online symbolizer by default.
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+ char d[4] = {0};
+ char *D = Ident(d);
+ switch (frame) {
+ case 3: a[5]++; break;
+ case 2: b[5]++; break;
+ case 1: c[5]++; break;
+ case 0: D[5]++; break;
+ }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+ char c[4] = {0}; Frame0(frame, a, b, c);
+ break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+ char b[4] = {0}; Frame1(frame, a, b);
+ break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+ char a[4] = {0}; Frame2(frame, a);
+ break_optimization(0);
+}
+
+TEST(AddressSanitizer, GuiltyStackFrame0Test) {
+ EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
+}
+TEST(AddressSanitizer, GuiltyStackFrame1Test) {
+ EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
+}
+TEST(AddressSanitizer, GuiltyStackFrame2Test) {
+ EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
+}
+TEST(AddressSanitizer, GuiltyStackFrame3Test) {
+ EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
+}
+#endif
+
+NOINLINE void LongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ longjmp(buf, 1);
+}
+
+NOINLINE void TouchStackFunc() {
+ int a[100]; // long array will intersect with redzones from LongJmpFunc1.
+ int *A = Ident(a);
+ for (int i = 0; i < 100; i++)
+ A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report false positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+ static jmp_buf buf;
+ if (!setjmp(buf)) {
+ LongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+#if !defined(_WIN32) // Only basic longjmp is available on Windows.
+NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ __builtin_longjmp((void**)buf, 1);
+}
+
+NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ _longjmp(buf, 1);
+}
+
+NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ siglongjmp(buf, 1);
+}
+
+#if !defined(__ANDROID__) && !defined(__arm__) && \
+ !defined(__powerpc64__) && !defined(__powerpc__) && \
+ !defined(__aarch64__)
+// Does not work on Power and ARM:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=185
+TEST(AddressSanitizer, BuiltinLongJmpTest) {
+ static jmp_buf buf;
+ if (!__builtin_setjmp((void**)buf)) {
+ BuiltinLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
+ // !defined(__powerpc__) && !defined(__arm__)
+
+TEST(AddressSanitizer, UnderscopeLongJmpTest) {
+ static jmp_buf buf;
+ if (!_setjmp(buf)) {
+ UnderscopeLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+TEST(AddressSanitizer, SigLongJmpTest) {
+ static sigjmp_buf buf;
+ if (!sigsetjmp(buf, 1)) {
+ SigLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+#endif
+
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
+NOINLINE void ThrowFunc() {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ ASAN_THROW(1);
+}
+
+TEST(AddressSanitizer, CxxExceptionTest) {
+ if (ASAN_UAR) return;
+ // TODO(kcc): this test crashes on 32-bit for some reason...
+ if (SANITIZER_WORDSIZE == 32) return;
+ try {
+ ThrowFunc();
+ } catch(...) {}
+ TouchStackFunc();
+}
+#endif
+
+void *ThreadStackReuseFunc1(void *unused) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ pthread_exit(0);
+ return 0;
+}
+
+void *ThreadStackReuseFunc2(void *unused) {
+ TouchStackFunc();
+ return 0;
+}
+
+TEST(AddressSanitizer, ThreadStackReuseTest) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if defined(__i686__) || defined(__x86_64__)
+#include <emmintrin.h>
+TEST(AddressSanitizer, Store128Test) {
+ char *a = Ident((char*)malloc(Ident(12)));
+ char *p = a;
+ if (((uintptr_t)a % 16) != 0)
+ p = a + 8;
+ assert(((uintptr_t)p % 16) == 0);
+ __m128i value_wide = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "AddressSanitizer: heap-buffer-overflow");
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "WRITE of size 16");
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "located 0 bytes to the right of 12-byte");
+ free(a);
+}
+#endif
+
+// FIXME: All tests that use this function should be turned into lit tests.
+string RightOOBErrorMessage(int oob_distance, bool is_write) {
+ assert(oob_distance >= 0);
+ char expected_str[100];
+ sprintf(expected_str, ASAN_PCRE_DOTALL
+#if !GTEST_USES_SIMPLE_RE
+ "buffer-overflow.*%s.*"
+#endif
+ "located %d bytes to the right",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
+ return string(expected_str);
+}
+
+string RightOOBWriteMessage(int oob_distance) {
+ return RightOOBErrorMessage(oob_distance, /*is_write*/true);
+}
+
+string RightOOBReadMessage(int oob_distance) {
+ return RightOOBErrorMessage(oob_distance, /*is_write*/false);
+}
+
+// FIXME: All tests that use this function should be turned into lit tests.
+string LeftOOBErrorMessage(int oob_distance, bool is_write) {
+ assert(oob_distance > 0);
+ char expected_str[100];
+ sprintf(expected_str,
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL "%s.*"
+#endif
+ "located %d bytes to the left",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
+ return string(expected_str);
+}
+
+string LeftOOBWriteMessage(int oob_distance) {
+ return LeftOOBErrorMessage(oob_distance, /*is_write*/true);
+}
+
+string LeftOOBReadMessage(int oob_distance) {
+ return LeftOOBErrorMessage(oob_distance, /*is_write*/false);
+}
+
+string LeftOOBAccessMessage(int oob_distance) {
+ assert(oob_distance > 0);
+ char expected_str[100];
+ sprintf(expected_str, "located %d bytes to the left", oob_distance);
+ return string(expected_str);
+}
+
+char* MallocAndMemsetString(size_t size, char ch) {
+ char *s = Ident((char*)malloc(size));
+ memset(s, ch, size);
+ return s;
+}
+
+char* MallocAndMemsetString(size_t size) {
+ return MallocAndMemsetString(size, 'z');
+}
+
+#if defined(__linux__) && !defined(__ANDROID__)
+#define READ_TEST(READ_N_BYTES) \
+ char *x = new char[10]; \
+ int fd = open("/proc/self/stat", O_RDONLY); \
+ ASSERT_GT(fd, 0); \
+ EXPECT_DEATH(READ_N_BYTES, \
+ ASAN_PCRE_DOTALL \
+ "AddressSanitizer: heap-buffer-overflow" \
+ ".* is located 0 bytes to the right of 10-byte region"); \
+ close(fd); \
+ delete [] x; \
+
+TEST(AddressSanitizer, pread) {
+ READ_TEST(pread(fd, x, 15, 0));
+}
+
+TEST(AddressSanitizer, pread64) {
+ READ_TEST(pread64(fd, x, 15, 0));
+}
+
+TEST(AddressSanitizer, read) {
+ READ_TEST(read(fd, x, 15));
+}
+#endif // defined(__linux__) && !defined(__ANDROID__)
+
+// This test case fails
+// Clang optimizes memcpy/memset calls which lead to unaligned access
+TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
+ int size = Ident(4096);
+ char *s = Ident((char*)malloc(size));
+ EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBWriteMessage(0));
+ free(s);
+}
+
+// TODO(samsonov): Add a test with malloc(0)
+// TODO(samsonov): Add tests for str* and mem* functions.
+
+NOINLINE static int LargeFunction(bool do_bad_access) {
+ int *x = new int[100];
+ x[0]++;
+ x[1]++;
+ x[2]++;
+ x[3]++;
+ x[4]++;
+ x[5]++;
+ x[6]++;
+ x[7]++;
+ x[8]++;
+ x[9]++;
+
+ x[do_bad_access ? 100 : 0]++; int res = __LINE__;
+
+ x[10]++;
+ x[11]++;
+ x[12]++;
+ x[13]++;
+ x[14]++;
+ x[15]++;
+ x[16]++;
+ x[17]++;
+ x[18]++;
+ x[19]++;
+
+ delete[] x;
+ return res;
+}
+
+// Test the we have correct debug info for the failing instruction.
+// This test requires the in-process symbolizer to be enabled by default.
+TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
+ int failing_line = LargeFunction(false);
+ char expected_warning[128];
+ sprintf(expected_warning, "LargeFunction.*asan_test.*:%d", failing_line);
+ EXPECT_DEATH(LargeFunction(true), expected_warning);
+}
+
+// Check that we unwind and symbolize correctly.
+TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
+ int *a = (int*)malloc_aaa(sizeof(int));
+ *a = 1;
+ free_aaa(a);
+ EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
+ "malloc_fff.*malloc_eee.*malloc_ddd");
+}
+
+static bool TryToSetThreadName(const char *name) {
+#if defined(__linux__) && defined(PR_SET_NAME)
+ return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
+#else
+ return false;
+#endif
+}
+
+void *ThreadedTestAlloc(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("AllocThr"));
+ int **p = (int**)a;
+ *p = new int;
+ return 0;
+}
+
+void *ThreadedTestFree(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("FreeThr"));
+ int **p = (int**)a;
+ delete *p;
+ return 0;
+}
+
+void *ThreadedTestUse(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("UseThr"));
+ int **p = (int**)a;
+ **p = 1;
+ return 0;
+}
+
+void ThreadedTestSpawn() {
+ pthread_t t;
+ int *x;
+ PTHREAD_CREATE(&t, 0, ThreadedTestAlloc, &x);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadedTestFree, &x);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadedTestUse, &x);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, ThreadedTest) {
+ EXPECT_DEATH(ThreadedTestSpawn(),
+ ASAN_PCRE_DOTALL
+ "Thread T.*created"
+ ".*Thread T.*created"
+ ".*Thread T.*created");
+}
+#endif
+
+void *ThreadedTestFunc(void *unused) {
+ // Check if prctl(PR_SET_NAME) is supported. Return if not.
+ if (!TryToSetThreadName("TestFunc"))
+ return 0;
+ EXPECT_DEATH(ThreadedTestSpawn(),
+ ASAN_PCRE_DOTALL
+ "WRITE .*thread T. .UseThr."
+ ".*freed by thread T. .FreeThr. here:"
+ ".*previously allocated by thread T. .AllocThr. here:"
+ ".*Thread T. .UseThr. created by T.*TestFunc"
+ ".*Thread T. .FreeThr. created by T"
+ ".*Thread T. .AllocThr. created by T"
+ "");
+ return 0;
+}
+
+TEST(AddressSanitizer, ThreadNamesTest) {
+ // Run ThreadedTestFunc in a separate thread because it tries to set a
+ // thread name and we don't want to change the main thread's name.
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, ThreadedTestFunc, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, ShadowGapTest) {
+#if SANITIZER_WORDSIZE == 32
+ char *addr = (char*)0x22000000;
+#else
+# if defined(__powerpc64__)
+ char *addr = (char*)0x024000800000;
+# else
+ char *addr = (char*)0x0000100000080000;
+# endif
+#endif
+ EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
+}
+#endif // ASAN_NEEDS_SEGV
+
+extern "C" {
+NOINLINE static void UseThenFreeThenUse() {
+ char *x = Ident((char*)malloc(8));
+ *x = 1;
+ free_aaa(x);
+ *x = 2;
+}
+}
+
+TEST(AddressSanitizer, UseThenFreeThenUseTest) {
+ EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
+}
+
+TEST(AddressSanitizer, StrDupTest) {
+ free(strdup(Ident("123")));
+}
+
+// Currently we create and poison redzone at right of global variables.
+static char static110[110];
+const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
+static const char StaticConstGlob[3] = {9, 8, 7};
+
+TEST(AddressSanitizer, GlobalTest) {
+ static char func_static15[15];
+
+ static char fs1[10];
+ static char fs2[10];
+ static char fs3[10];
+
+ glob5[Ident(0)] = 0;
+ glob5[Ident(1)] = 0;
+ glob5[Ident(2)] = 0;
+ glob5[Ident(3)] = 0;
+ glob5[Ident(4)] = 0;
+
+ EXPECT_DEATH(glob5[Ident(5)] = 0,
+ "0 bytes to the right of global variable.*glob5.* size 5");
+ EXPECT_DEATH(glob5[Ident(5+6)] = 0,
+ "6 bytes to the right of global variable.*glob5.* size 5");
+ Ident(static110); // avoid optimizations
+ static110[Ident(0)] = 0;
+ static110[Ident(109)] = 0;
+ EXPECT_DEATH(static110[Ident(110)] = 0,
+ "0 bytes to the right of global variable");
+ EXPECT_DEATH(static110[Ident(110+7)] = 0,
+ "7 bytes to the right of global variable");
+
+ Ident(func_static15); // avoid optimizations
+ func_static15[Ident(0)] = 0;
+ EXPECT_DEATH(func_static15[Ident(15)] = 0,
+ "0 bytes to the right of global variable");
+ EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
+ "9 bytes to the right of global variable");
+
+ Ident(fs1);
+ Ident(fs2);
+ Ident(fs3);
+
+ // We don't create left redzones, so this is not 100% guaranteed to fail.
+ // But most likely will.
+ EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
+
+ EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
+ "is located 1 bytes to the right of .*ConstGlob");
+ EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
+ "is located 2 bytes to the right of .*StaticConstGlob");
+
+ // call stuff from another file.
+ GlobalsTest(0);
+}
+
+TEST(AddressSanitizer, GlobalStringConstTest) {
+ static const char *zoo = "FOOBAR123";
+ const char *p = Ident(zoo);
+ EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
+}
+
+TEST(AddressSanitizer, FileNameInGlobalReportTest) {
+ static char zoo[10];
+ const char *p = Ident(zoo);
+ // The file name should be present in the report.
+ EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.");
+}
+
+int *ReturnsPointerToALocalObject() {
+ int a = 0;
+ return Ident(&a);
+}
+
+#if ASAN_UAR == 1
+TEST(AddressSanitizer, LocalReferenceReturnTest) {
+ int *(*f)() = Ident(ReturnsPointerToALocalObject);
+ int *p = f();
+ // Call 'f' a few more times, 'p' should still be poisoned.
+ for (int i = 0; i < 32; i++)
+ f();
+ EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
+ EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
+}
+#endif
+
+template <int kSize>
+NOINLINE static void FuncWithStack() {
+ char x[kSize];
+ Ident(x)[0] = 0;
+ Ident(x)[kSize-1] = 0;
+}
+
+static void LotsOfStackReuse() {
+ int LargeStack[10000];
+ Ident(LargeStack)[0] = 0;
+ for (int i = 0; i < 10000; i++) {
+ FuncWithStack<128 * 1>();
+ FuncWithStack<128 * 2>();
+ FuncWithStack<128 * 4>();
+ FuncWithStack<128 * 8>();
+ FuncWithStack<128 * 16>();
+ FuncWithStack<128 * 32>();
+ FuncWithStack<128 * 64>();
+ FuncWithStack<128 * 128>();
+ FuncWithStack<128 * 256>();
+ FuncWithStack<128 * 512>();
+ Ident(LargeStack)[0] = 0;
+ }
+}
+
+TEST(AddressSanitizer, StressStackReuseTest) {
+ LotsOfStackReuse();
+}
+
+TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
+ const int kNumThreads = 20;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+static void *PthreadExit(void *a) {
+ pthread_exit(0);
+ return 0;
+}
+
+TEST(AddressSanitizer, PthreadExitTest) {
+ pthread_t t;
+ for (int i = 0; i < 1000; i++) {
+ PTHREAD_CREATE(&t, 0, PthreadExit, 0);
+ PTHREAD_JOIN(t, 0);
+ }
+}
+
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
+NOINLINE static void StackReuseAndException() {
+ int large_stack[1000];
+ Ident(large_stack);
+ ASAN_THROW(1);
+}
+
+// TODO(kcc): support exceptions with use-after-return.
+TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
+ for (int i = 0; i < 10000; i++) {
+ try {
+ StackReuseAndException();
+ } catch(...) {
+ }
+ }
+}
+#endif
+
+#if !defined(_WIN32)
+TEST(AddressSanitizer, MlockTest) {
+ EXPECT_EQ(0, mlockall(MCL_CURRENT));
+ EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+ EXPECT_EQ(0, munlockall());
+ EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+#endif
+
+struct LargeStruct {
+ int foo[100];
+};
+
+// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
+// Struct copy should not cause asan warning even if lhs == rhs.
+TEST(AddressSanitizer, LargeStructCopyTest) {
+ LargeStruct a;
+ *Ident(&a) = *Ident(&a);
+}
+
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+static void NoSanitizeAddress() {
+ char *foo = new char[10];
+ Ident(foo)[10] = 0;
+ delete [] foo;
+}
+
+TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
+ Ident(NoSanitizeAddress)();
+}
+
+// The new/delete/etc mismatch checks don't work on Android,
+// as calls to new/delete go through malloc/free.
+// OS X support is tracked here:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=131
+// Windows support is tracked here:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+#if !defined(__ANDROID__) && \
+ !defined(__APPLE__) && \
+ !defined(_WIN32)
+static string MismatchStr(const string &str) {
+ return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
+}
+
+TEST(AddressSanitizer, AllocDeallocMismatch) {
+ EXPECT_DEATH(free(Ident(new int)),
+ MismatchStr("operator new vs free"));
+ EXPECT_DEATH(free(Ident(new int[2])),
+ MismatchStr("operator new \\[\\] vs free"));
+ EXPECT_DEATH(delete (Ident(new int[2])),
+ MismatchStr("operator new \\[\\] vs operator delete"));
+ EXPECT_DEATH(delete (Ident((int*)malloc(2 * sizeof(int)))),
+ MismatchStr("malloc vs operator delete"));
+ EXPECT_DEATH(delete [] (Ident(new int)),
+ MismatchStr("operator new vs operator delete \\[\\]"));
+ EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))),
+ MismatchStr("malloc vs operator delete \\[\\]"));
+}
+#endif
+
+// ------------------ demo tests; run each one-by-one -------------
+// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
+TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
+ ThreadedTestSpawn();
+}
+
+void *SimpleBugOnSTack(void *x = 0) {
+ char a[20];
+ Ident(a)[20] = 0;
+ return 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoStackTest) {
+ SimpleBugOnSTack();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, SimpleBugOnSTack, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
+ uaf_test<U1>(10, 0);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
+ uaf_test<U1>(10, -2);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
+ uaf_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
+ uaf_test<U1>(kLargeMalloc, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOM) {
+ size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
+ printf("%p\n", malloc(size));
+}
+
+TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
+ DoubleFree();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
+ int *a = 0;
+ Ident(a)[10] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
+ static char a[100];
+ static char b[100];
+ static char c[100];
+ Ident(a);
+ Ident(b);
+ Ident(c);
+ Ident(a)[5] = 0;
+ Ident(b)[105] = 0;
+ Ident(a)[5] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
+ const size_t kAllocSize = (1 << 28) - 1024;
+ size_t total_size = 0;
+ while (true) {
+ char *x = (char*)malloc(kAllocSize);
+ memset(x, 0, kAllocSize);
+ total_size += kAllocSize;
+ fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
+ }
+}
+
+// http://code.google.com/p/address-sanitizer/issues/detail?id=66
+TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
+ for (int i = 0; i < 1000000; i++) {
+ delete [] (Ident(new char [8644]));
+ }
+ char *x = new char[8192];
+ EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
+ delete [] Ident(x);
+}
+
+
+// Test that instrumentation of stack allocations takes into account
+// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
+// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
+TEST(AddressSanitizer, LongDoubleNegativeTest) {
+ long double a, b;
+ static long double c;
+ memcpy(Ident(&a), Ident(&b), sizeof(long double));
+ memcpy(Ident(&c), Ident(&b), sizeof(long double));
+}
+
+#if !defined(_WIN32)
+TEST(AddressSanitizer, pthread_getschedparam) {
+ int policy;
+ struct sched_param param;
+ EXPECT_DEATH(
+ pthread_getschedparam(pthread_self(), &policy, Ident(&param) + 2),
+ "AddressSanitizer: stack-buffer-.*flow");
+ EXPECT_DEATH(
+ pthread_getschedparam(pthread_self(), Ident(&policy) - 1, &param),
+ "AddressSanitizer: stack-buffer-.*flow");
+ int res = pthread_getschedparam(pthread_self(), &policy, &param);
+ ASSERT_EQ(0, res);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_PRINTF_L
+static int vsnprintf_l_wrapper(char *s, size_t n,
+ locale_t l, const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int res = vsnprintf_l(s, n , l, format, va);
+ va_end(va);
+ return res;
+}
+
+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()");
+ 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()");
+ 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");
+}
+#endif
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test.ignore b/contrib/compiler-rt/lib/asan/tests/asan_test.ignore
new file mode 100644
index 000000000000..ea5c26099e75
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_test.ignore
@@ -0,0 +1,3 @@
+# blacklisted functions for instrumented ASan unit test
+fun:*IgnoreTest*
+fun:*SomeOtherFunc*
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test_config.h b/contrib/compiler-rt/lib/asan/tests/asan_test_config.h
new file mode 100644
index 000000000000..92f276307481
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_test_config.h
@@ -0,0 +1,54 @@
+//===-- asan_test_config.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.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
+# error "This file should be included into asan_test_utils.h only"
+#endif
+
+#ifndef ASAN_TEST_CONFIG_H
+#define ASAN_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+using std::string;
+using std::vector;
+using std::map;
+
+#ifndef ASAN_UAR
+# error "please define ASAN_UAR"
+#endif
+
+#ifndef ASAN_HAS_EXCEPTIONS
+# error "please define ASAN_HAS_EXCEPTIONS"
+#endif
+
+#ifndef ASAN_HAS_BLACKLIST
+# error "please define ASAN_HAS_BLACKLIST"
+#endif
+
+#ifndef ASAN_NEEDS_SEGV
+# if defined(_WIN32)
+# define ASAN_NEEDS_SEGV 0
+# else
+# define ASAN_NEEDS_SEGV 1
+# endif
+#endif
+
+#ifndef ASAN_AVOID_EXPENSIVE_TESTS
+# define ASAN_AVOID_EXPENSIVE_TESTS 0
+#endif
+
+#define ASAN_PCRE_DOTALL ""
+
+#endif // ASAN_TEST_CONFIG_H
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test_main.cc b/contrib/compiler-rt/lib/asan/tests/asan_test_main.cc
new file mode 100644
index 000000000000..1746c5f4837b
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_test_main.cc
@@ -0,0 +1,19 @@
+//===-- asan_test_main.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.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test_utils.h b/contrib/compiler-rt/lib/asan/tests/asan_test_utils.h
new file mode 100644
index 000000000000..03d17cfb26a7
--- /dev/null
+++ b/contrib/compiler-rt/lib/asan/tests/asan_test_utils.h
@@ -0,0 +1,107 @@
+//===-- asan_test_utils.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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_TEST_UTILS_H
+#define ASAN_TEST_UTILS_H
+
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_ASAN_TEST_UTILS_H
+# include "asan_test_config.h"
+# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
+#endif
+
+#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <algorithm>
+
+#if !defined(_WIN32)
+# include <strings.h>
+# include <sys/mman.h>
+# include <setjmp.h>
+#endif
+
+#ifdef __linux__
+# include <sys/prctl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+
+#if ASAN_HAS_EXCEPTIONS
+# define ASAN_THROW(x) throw (x)
+#else
+# define ASAN_THROW(x)
+#endif
+
+typedef uint8_t U1;
+typedef uint16_t U2;
+typedef uint32_t U4;
+typedef uint64_t U8;
+
+static const int kPageSize = 4096;
+
+const size_t kLargeMalloc = 1 << 24;
+
+extern void free_aaa(void *p);
+extern void *malloc_aaa(size_t size);
+
+template<typename T>
+NOINLINE void asan_write(T *a) {
+ *a = 0;
+}
+
+string RightOOBErrorMessage(int oob_distance, bool is_write);
+string RightOOBWriteMessage(int oob_distance);
+string RightOOBReadMessage(int oob_distance);
+string LeftOOBErrorMessage(int oob_distance, bool is_write);
+string LeftOOBWriteMessage(int oob_distance);
+string LeftOOBReadMessage(int oob_distance);
+string LeftOOBAccessMessage(int oob_distance);
+char* MallocAndMemsetString(size_t size, char ch);
+char* MallocAndMemsetString(size_t size);
+
+extern char glob1[1];
+extern char glob2[2];
+extern char glob3[3];
+extern char glob4[4];
+extern char glob5[5];
+extern char glob6[6];
+extern char glob7[7];
+extern char glob8[8];
+extern char glob9[9];
+extern char glob10[10];
+extern char glob11[11];
+extern char glob12[12];
+extern char glob13[13];
+extern char glob14[14];
+extern char glob15[15];
+extern char glob16[16];
+extern char glob17[17];
+extern char glob1000[1000];
+extern char glob10000[10000];
+extern char glob100000[100000];
+extern int GlobalsTest(int x);
+
+#endif // ASAN_TEST_UTILS_H
diff --git a/contrib/compiler-rt/lib/assembly.h b/contrib/compiler-rt/lib/assembly.h
deleted file mode 100644
index 3d8e50dc8ad9..000000000000
--- a/contrib/compiler-rt/lib/assembly.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file defines macros for use in compiler-rt assembler source.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#ifndef COMPILERRT_ASSEMBLY_H
-#define COMPILERRT_ASSEMBLY_H
-
-#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
-#define SEPARATOR @
-#else
-#define SEPARATOR ;
-#endif
-
-#if defined(__APPLE__)
-#define HIDDEN_DIRECTIVE .private_extern
-#define LOCAL_LABEL(name) L_##name
-#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
-#else
-#define HIDDEN_DIRECTIVE .hidden
-#define LOCAL_LABEL(name) .L_##name
-#define FILE_LEVEL_DIRECTIVE
-#endif
-
-#define GLUE2(a, b) a ## b
-#define GLUE(a, b) GLUE2(a, b)
-#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
-
-#ifdef VISIBILITY_HIDDEN
-#define DECLARE_SYMBOL_VISIBILITY(name) \
- HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR
-#else
-#define DECLARE_SYMBOL_VISIBILITY(name)
-#endif
-
-#define DEFINE_COMPILERRT_FUNCTION(name) \
- FILE_LEVEL_DIRECTIVE SEPARATOR \
- .globl SYMBOL_NAME(name) SEPARATOR \
- DECLARE_SYMBOL_VISIBILITY(name) \
- SYMBOL_NAME(name):
-
-#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
- .globl SYMBOL_NAME(name) SEPARATOR \
- HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \
- SYMBOL_NAME(name):
-
-#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
- .globl name SEPARATOR \
- HIDDEN_DIRECTIVE name SEPARATOR \
- name:
-
-#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
- .globl SYMBOL_NAME(name) SEPARATOR \
- .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
-
-#if defined (__ARM_EABI__)
-# define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
- DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
-#else
-# define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
-#endif
-
-#endif /* COMPILERRT_ASSEMBLY_H */
diff --git a/contrib/compiler-rt/lib/builtins/README.txt b/contrib/compiler-rt/lib/builtins/README.txt
new file mode 100644
index 000000000000..1c08e7415e64
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/README.txt
@@ -0,0 +1,343 @@
+Compiler-RT
+================================
+
+This directory and its subdirectories contain source code for the compiler
+support routines.
+
+Compiler-RT is open source software. You may freely distribute it under the
+terms of the license agreement found in LICENSE.txt.
+
+================================
+
+This is a replacement library for libgcc. Each function is contained
+in its own file. Each function has a corresponding unit test under
+test/Unit.
+
+A rudimentary script to test each file is in the file called
+test/Unit/test.
+
+Here is the specification for this library:
+
+http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
+
+Here is a synopsis of the contents of this library:
+
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+// Integral bit manipulation
+
+di_int __ashldi3(di_int a, si_int b); // a << b
+ti_int __ashlti3(ti_int a, si_int b); // a << b
+
+di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
+ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
+di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
+ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
+
+si_int __clzsi2(si_int a); // count leading zeros
+si_int __clzdi2(di_int a); // count leading zeros
+si_int __clzti2(ti_int a); // count leading zeros
+si_int __ctzsi2(si_int a); // count trailing zeros
+si_int __ctzdi2(di_int a); // count trailing zeros
+si_int __ctzti2(ti_int a); // count trailing zeros
+
+si_int __ffsdi2(di_int a); // find least significant 1 bit
+si_int __ffsti2(ti_int a); // find least significant 1 bit
+
+si_int __paritysi2(si_int a); // bit parity
+si_int __paritydi2(di_int a); // bit parity
+si_int __parityti2(ti_int a); // bit parity
+
+si_int __popcountsi2(si_int a); // bit population
+si_int __popcountdi2(di_int a); // bit population
+si_int __popcountti2(ti_int a); // bit population
+
+uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
+uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
+
+// Integral arithmetic
+
+di_int __negdi2 (di_int a); // -a
+ti_int __negti2 (ti_int a); // -a
+di_int __muldi3 (di_int a, di_int b); // a * b
+ti_int __multi3 (ti_int a, ti_int b); // a * b
+si_int __divsi3 (si_int a, si_int b); // a / b signed
+di_int __divdi3 (di_int a, di_int b); // a / b signed
+ti_int __divti3 (ti_int a, ti_int b); // a / b signed
+su_int __udivsi3 (su_int n, su_int d); // a / b unsigned
+du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
+tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned
+si_int __modsi3 (si_int a, si_int b); // a % b signed
+di_int __moddi3 (di_int a, di_int b); // a % b signed
+ti_int __modti3 (ti_int a, ti_int b); // a % b signed
+su_int __umodsi3 (su_int a, su_int b); // a % b unsigned
+du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
+tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned
+du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b unsigned
+tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned
+su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned
+si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed
+
+
+
+// Integral arithmetic with trapping overflow
+
+si_int __absvsi2(si_int a); // abs(a)
+di_int __absvdi2(di_int a); // abs(a)
+ti_int __absvti2(ti_int a); // abs(a)
+
+si_int __negvsi2(si_int a); // -a
+di_int __negvdi2(di_int a); // -a
+ti_int __negvti2(ti_int a); // -a
+
+si_int __addvsi3(si_int a, si_int b); // a + b
+di_int __addvdi3(di_int a, di_int b); // a + b
+ti_int __addvti3(ti_int a, ti_int b); // a + b
+
+si_int __subvsi3(si_int a, si_int b); // a - b
+di_int __subvdi3(di_int a, di_int b); // a - b
+ti_int __subvti3(ti_int a, ti_int b); // a - b
+
+si_int __mulvsi3(si_int a, si_int b); // a * b
+di_int __mulvdi3(di_int a, di_int b); // a * b
+ti_int __mulvti3(ti_int a, ti_int b); // a * b
+
+
+// Integral arithmetic which returns if overflow
+
+si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range
+di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range
+ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to
+ one if result not in signed range
+
+
+// Integral comparison: a < b -> 0
+// a == b -> 1
+// a > b -> 2
+
+si_int __cmpdi2 (di_int a, di_int b);
+si_int __cmpti2 (ti_int a, ti_int b);
+si_int __ucmpdi2(du_int a, du_int b);
+si_int __ucmpti2(tu_int a, tu_int b);
+
+// Integral / floating point conversion
+
+di_int __fixsfdi( float a);
+di_int __fixdfdi( double a);
+di_int __fixxfdi(long double a);
+
+ti_int __fixsfti( float a);
+ti_int __fixdfti( double a);
+ti_int __fixxfti(long double a);
+uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation
+
+su_int __fixunssfsi( float a);
+su_int __fixunsdfsi( double a);
+su_int __fixunsxfsi(long double a);
+
+du_int __fixunssfdi( float a);
+du_int __fixunsdfdi( double a);
+du_int __fixunsxfdi(long double a);
+
+tu_int __fixunssfti( float a);
+tu_int __fixunsdfti( double a);
+tu_int __fixunsxfti(long double a);
+uint64_t __fixunstfdi(long double input); // ppc only
+
+float __floatdisf(di_int a);
+double __floatdidf(di_int a);
+long double __floatdixf(di_int a);
+long double __floatditf(int64_t a); // ppc only
+
+float __floattisf(ti_int a);
+double __floattidf(ti_int a);
+long double __floattixf(ti_int a);
+
+float __floatundisf(du_int a);
+double __floatundidf(du_int a);
+long double __floatundixf(du_int a);
+long double __floatunditf(uint64_t a); // ppc only
+
+float __floatuntisf(tu_int a);
+double __floatuntidf(tu_int a);
+long double __floatuntixf(tu_int a);
+
+// Floating point raised to integer power
+
+float __powisf2( float a, si_int b); // a ^ b
+double __powidf2( double a, si_int b); // a ^ b
+long double __powixf2(long double a, si_int b); // a ^ b
+long double __powitf2(long double a, si_int b); // ppc only, a ^ b
+
+// Complex arithmetic
+
+// (a + ib) * (c + id)
+
+ float _Complex __mulsc3( float a, float b, float c, float d);
+ double _Complex __muldc3(double a, double b, double c, double d);
+long double _Complex __mulxc3(long double a, long double b,
+ long double c, long double d);
+long double _Complex __multc3(long double a, long double b,
+ long double c, long double d); // ppc only
+
+// (a + ib) / (c + id)
+
+ float _Complex __divsc3( float a, float b, float c, float d);
+ double _Complex __divdc3(double a, double b, double c, double d);
+long double _Complex __divxc3(long double a, long double b,
+ long double c, long double d);
+long double _Complex __divtc3(long double a, long double b,
+ long double c, long double d); // ppc only
+
+
+// Runtime support
+
+// __clear_cache() is used to tell process that new instructions have been
+// written to an address range. Necessary on processors that do not have
+// a unified instruction and data cache.
+void __clear_cache(void* start, void* end);
+
+// __enable_execute_stack() is used with nested functions when a trampoline
+// function is written onto the stack and that page range needs to be made
+// executable.
+void __enable_execute_stack(void* addr);
+
+// __gcc_personality_v0() is normally only called by the system unwinder.
+// C code (as opposed to C++) normally does not need a personality function
+// because there are no catch clauses or destructors to be run. But there
+// is a C language extension __attribute__((cleanup(func))) which marks local
+// variables as needing the cleanup function "func" to be run when the
+// variable goes out of scope. That includes when an exception is thrown,
+// so a personality handler is needed.
+_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
+ uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+ _Unwind_Context_t context);
+
+// for use with some implementations of assert() in <assert.h>
+void __eprintf(const char* format, const char* assertion_expression,
+ const char* line, const char* file);
+
+
+
+// Power PC specific functions
+
+// There is no C interface to the saveFP/restFP functions. They are helper
+// functions called by the prolog and epilog of functions that need to save
+// a number of non-volatile float point registers.
+saveFP
+restFP
+
+// PowerPC has a standard template for trampoline functions. This function
+// generates a custom trampoline function with the specific realFunc
+// and localsPtr values.
+void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
+ const void* realFunc, void* localsPtr);
+
+// adds two 128-bit double-double precision values ( x + y )
+long double __gcc_qadd(long double x, long double y);
+
+// subtracts two 128-bit double-double precision values ( x - y )
+long double __gcc_qsub(long double x, long double y);
+
+// multiples two 128-bit double-double precision values ( x * y )
+long double __gcc_qmul(long double x, long double y);
+
+// divides two 128-bit double-double precision values ( x / y )
+long double __gcc_qdiv(long double a, long double b);
+
+
+// ARM specific functions
+
+// There is no C interface to the switch* functions. These helper functions
+// are only needed by Thumb1 code for efficient switch table generation.
+switch16
+switch32
+switch8
+switchu8
+
+// There is no C interface to the *_vfp_d8_d15_regs functions. There are
+// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
+// SJLJ for exceptions, each function with a catch clause or destuctors needs
+// to save and restore all registers in it prolog and epliog. But there is
+// no way to access vector and high float registers from thumb1 code, so the
+// compiler must add call outs to these helper functions in the prolog and
+// epilog.
+restore_vfp_d8_d15_regs
+save_vfp_d8_d15_regs
+
+
+// Note: long ago ARM processors did not have floating point hardware support.
+// Floating point was done in software and floating point parameters were
+// passed in integer registers. When hardware support was added for floating
+// point, new *vfp functions were added to do the same operations but with
+// floating point parameters in floating point registers.
+
+// Undocumented functions
+
+float __addsf3vfp(float a, float b); // Appears to return a + b
+double __adddf3vfp(double a, double b); // Appears to return a + b
+float __divsf3vfp(float a, float b); // Appears to return a / b
+double __divdf3vfp(double a, double b); // Appears to return a / b
+int __eqsf2vfp(float a, float b); // Appears to return one
+ // iff a == b and neither is NaN.
+int __eqdf2vfp(double a, double b); // Appears to return one
+ // iff a == b and neither is NaN.
+double __extendsfdf2vfp(float a); // Appears to convert from
+ // float to double.
+int __fixdfsivfp(double a); // Appears to convert from
+ // double to int.
+int __fixsfsivfp(float a); // Appears to convert from
+ // float to int.
+unsigned int __fixunssfsivfp(float a); // Appears to convert from
+ // float to unsigned int.
+unsigned int __fixunsdfsivfp(double a); // Appears to convert from
+ // double to unsigned int.
+double __floatsidfvfp(int a); // Appears to convert from
+ // int to double.
+float __floatsisfvfp(int a); // Appears to convert from
+ // int to float.
+double __floatunssidfvfp(unsigned int a); // Appears to convert from
+ // unisgned int to double.
+float __floatunssisfvfp(unsigned int a); // Appears to convert from
+ // unisgned int to float.
+int __gedf2vfp(double a, double b); // Appears to return __gedf2
+ // (a >= b)
+int __gesf2vfp(float a, float b); // Appears to return __gesf2
+ // (a >= b)
+int __gtdf2vfp(double a, double b); // Appears to return __gtdf2
+ // (a > b)
+int __gtsf2vfp(float a, float b); // Appears to return __gtsf2
+ // (a > b)
+int __ledf2vfp(double a, double b); // Appears to return __ledf2
+ // (a <= b)
+int __lesf2vfp(float a, float b); // Appears to return __lesf2
+ // (a <= b)
+int __ltdf2vfp(double a, double b); // Appears to return __ltdf2
+ // (a < b)
+int __ltsf2vfp(float a, float b); // Appears to return __ltsf2
+ // (a < b)
+double __muldf3vfp(double a, double b); // Appears to return a * b
+float __mulsf3vfp(float a, float b); // Appears to return a * b
+int __nedf2vfp(double a, double b); // Appears to return __nedf2
+ // (a != b)
+double __negdf2vfp(double a); // Appears to return -a
+float __negsf2vfp(float a); // Appears to return -a
+float __negsf2vfp(float a); // Appears to return -a
+double __subdf3vfp(double a, double b); // Appears to return a - b
+float __subsf3vfp(float a, float b); // Appears to return a - b
+float __truncdfsf2vfp(double a); // Appears to convert from
+ // double to float.
+int __unorddf2vfp(double a, double b); // Appears to return __unorddf2
+int __unordsf2vfp(float a, float b); // Appears to return __unordsf2
+
+
+Preconditions are listed for each function at the definition when there are any.
+Any preconditions reflect the specification at
+http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc.
+
+Assumptions are listed in "int_lib.h", and in individual files. Where possible
+assumptions are checked at compile time.
diff --git a/contrib/compiler-rt/lib/absvdi2.c b/contrib/compiler-rt/lib/builtins/absvdi2.c
index 682c2355d2ac..682c2355d2ac 100644
--- a/contrib/compiler-rt/lib/absvdi2.c
+++ b/contrib/compiler-rt/lib/builtins/absvdi2.c
diff --git a/contrib/compiler-rt/lib/absvsi2.c b/contrib/compiler-rt/lib/builtins/absvsi2.c
index 4812af815982..4812af815982 100644
--- a/contrib/compiler-rt/lib/absvsi2.c
+++ b/contrib/compiler-rt/lib/builtins/absvsi2.c
diff --git a/contrib/compiler-rt/lib/absvti2.c b/contrib/compiler-rt/lib/builtins/absvti2.c
index 437bc3ddc174..7927770c9ab3 100644
--- a/contrib/compiler-rt/lib/absvti2.c
+++ b/contrib/compiler-rt/lib/builtins/absvti2.c
@@ -20,7 +20,7 @@
/* Effects: aborts if abs(x) < 0 */
-ti_int
+COMPILER_RT_ABI ti_int
__absvti2(ti_int a)
{
const int N = (int)(sizeof(ti_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/builtins/adddf3.c b/contrib/compiler-rt/lib/builtins/adddf3.c
new file mode 100644
index 000000000000..8b7aae0a6f87
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/adddf3.c
@@ -0,0 +1,22 @@
+//===-- lib/adddf3.c - Double-precision addition ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_add_impl.inc"
+
+ARM_EABI_FNALIAS(dadd, adddf3)
+
+COMPILER_RT_ABI double __adddf3(double a, double b){
+ return __addXf3__(a, b);
+}
diff --git a/contrib/compiler-rt/lib/builtins/addsf3.c b/contrib/compiler-rt/lib/builtins/addsf3.c
new file mode 100644
index 000000000000..0f5d6ea4097a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/addsf3.c
@@ -0,0 +1,22 @@
+//===-- lib/addsf3.c - Single-precision addition ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_add_impl.inc"
+
+ARM_EABI_FNALIAS(fadd, addsf3)
+
+COMPILER_RT_ABI float __addsf3(float a, float b) {
+ return __addXf3__(a, b);
+}
diff --git a/contrib/compiler-rt/lib/builtins/addtf3.c b/contrib/compiler-rt/lib/builtins/addtf3.c
new file mode 100644
index 000000000000..e4bbe0227ae6
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/addtf3.c
@@ -0,0 +1,25 @@
+//===-- lib/addtf3.c - Quad-precision addition --------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#include "fp_add_impl.inc"
+
+COMPILER_RT_ABI long double __addtf3(long double a, long double b){
+ return __addXf3__(a, b);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/addvdi3.c b/contrib/compiler-rt/lib/builtins/addvdi3.c
index db45a27f0784..0da38945679d 100644
--- a/contrib/compiler-rt/lib/addvdi3.c
+++ b/contrib/compiler-rt/lib/builtins/addvdi3.c
@@ -21,7 +21,7 @@
COMPILER_RT_ABI di_int
__addvdi3(di_int a, di_int b)
{
- di_int s = a + b;
+ di_int s = (du_int) a + (du_int) b;
if (b >= 0)
{
if (s < a)
diff --git a/contrib/compiler-rt/lib/addvsi3.c b/contrib/compiler-rt/lib/builtins/addvsi3.c
index 81f515cd7bb1..94ca726f42b9 100644
--- a/contrib/compiler-rt/lib/addvsi3.c
+++ b/contrib/compiler-rt/lib/builtins/addvsi3.c
@@ -21,7 +21,7 @@
COMPILER_RT_ABI si_int
__addvsi3(si_int a, si_int b)
{
- si_int s = a + b;
+ si_int s = (su_int) a + (su_int) b;
if (b >= 0)
{
if (s < a)
diff --git a/contrib/compiler-rt/lib/addvti3.c b/contrib/compiler-rt/lib/builtins/addvti3.c
index f2a5c5669752..c224de60aab0 100644
--- a/contrib/compiler-rt/lib/addvti3.c
+++ b/contrib/compiler-rt/lib/builtins/addvti3.c
@@ -20,10 +20,10 @@
/* Effects: aborts if a + b overflows */
-ti_int
+COMPILER_RT_ABI ti_int
__addvti3(ti_int a, ti_int b)
{
- ti_int s = a + b;
+ ti_int s = (tu_int) a + (tu_int) b;
if (b >= 0)
{
if (s < a)
diff --git a/contrib/compiler-rt/lib/builtins/apple_versioning.c b/contrib/compiler-rt/lib/builtins/apple_versioning.c
new file mode 100644
index 000000000000..3797a1ab02da
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/apple_versioning.c
@@ -0,0 +1,350 @@
+/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+
+#if __APPLE__
+ #include <Availability.h>
+
+ #if __IPHONE_OS_VERSION_MIN_REQUIRED
+ #define NOT_HERE_BEFORE_10_6(sym)
+ #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp61 __asm("$ld$hide$os6.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp61 = 0; \
+ extern const char sym##_tmp60 __asm("$ld$hide$os6.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp60 = 0; \
+ extern const char sym##_tmp51 __asm("$ld$hide$os5.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp51 = 0; \
+ extern const char sym##_tmp50 __asm("$ld$hide$os5.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp50 = 0;
+ #else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp8 = 0; \
+ extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+ #endif
+
+
+/* Symbols in libSystem.dylib in 10.6 and later,
+ * but are in libgcc_s.dylib in earlier versions
+ */
+
+NOT_HERE_BEFORE_10_6(__absvdi2)
+NOT_HERE_BEFORE_10_6(__absvsi2)
+NOT_HERE_BEFORE_10_6(__absvti2)
+NOT_HERE_BEFORE_10_6(__addvdi3)
+NOT_HERE_BEFORE_10_6(__addvsi3)
+NOT_HERE_BEFORE_10_6(__addvti3)
+NOT_HERE_BEFORE_10_6(__ashldi3)
+NOT_HERE_BEFORE_10_6(__ashlti3)
+NOT_HERE_BEFORE_10_6(__ashrdi3)
+NOT_HERE_BEFORE_10_6(__ashrti3)
+NOT_HERE_BEFORE_10_6(__clear_cache)
+NOT_HERE_BEFORE_10_6(__clzdi2)
+NOT_HERE_BEFORE_10_6(__clzsi2)
+NOT_HERE_BEFORE_10_6(__clzti2)
+NOT_HERE_BEFORE_10_6(__cmpdi2)
+NOT_HERE_BEFORE_10_6(__cmpti2)
+NOT_HERE_BEFORE_10_6(__ctzdi2)
+NOT_HERE_BEFORE_10_6(__ctzsi2)
+NOT_HERE_BEFORE_10_6(__ctzti2)
+NOT_HERE_BEFORE_10_6(__divdc3)
+NOT_HERE_BEFORE_10_6(__divdi3)
+NOT_HERE_BEFORE_10_6(__divsc3)
+NOT_HERE_BEFORE_10_6(__divtc3)
+NOT_HERE_BEFORE_10_6(__divti3)
+NOT_HERE_BEFORE_10_6(__divxc3)
+NOT_HERE_BEFORE_10_6(__enable_execute_stack)
+NOT_HERE_BEFORE_10_6(__ffsdi2)
+NOT_HERE_BEFORE_10_6(__ffsti2)
+NOT_HERE_BEFORE_10_6(__fixdfdi)
+NOT_HERE_BEFORE_10_6(__fixdfti)
+NOT_HERE_BEFORE_10_6(__fixsfdi)
+NOT_HERE_BEFORE_10_6(__fixsfti)
+NOT_HERE_BEFORE_10_6(__fixtfdi)
+NOT_HERE_BEFORE_10_6(__fixunsdfdi)
+NOT_HERE_BEFORE_10_6(__fixunsdfsi)
+NOT_HERE_BEFORE_10_6(__fixunsdfti)
+NOT_HERE_BEFORE_10_6(__fixunssfdi)
+NOT_HERE_BEFORE_10_6(__fixunssfsi)
+NOT_HERE_BEFORE_10_6(__fixunssfti)
+NOT_HERE_BEFORE_10_6(__fixunstfdi)
+NOT_HERE_BEFORE_10_6(__fixunsxfdi)
+NOT_HERE_BEFORE_10_6(__fixunsxfsi)
+NOT_HERE_BEFORE_10_6(__fixunsxfti)
+NOT_HERE_BEFORE_10_6(__fixxfdi)
+NOT_HERE_BEFORE_10_6(__fixxfti)
+NOT_HERE_BEFORE_10_6(__floatdidf)
+NOT_HERE_BEFORE_10_6(__floatdisf)
+NOT_HERE_BEFORE_10_6(__floatditf)
+NOT_HERE_BEFORE_10_6(__floatdixf)
+NOT_HERE_BEFORE_10_6(__floattidf)
+NOT_HERE_BEFORE_10_6(__floattisf)
+NOT_HERE_BEFORE_10_6(__floattixf)
+NOT_HERE_BEFORE_10_6(__floatundidf)
+NOT_HERE_BEFORE_10_6(__floatundisf)
+NOT_HERE_BEFORE_10_6(__floatunditf)
+NOT_HERE_BEFORE_10_6(__floatundixf)
+NOT_HERE_BEFORE_10_6(__floatuntidf)
+NOT_HERE_BEFORE_10_6(__floatuntisf)
+NOT_HERE_BEFORE_10_6(__floatuntixf)
+NOT_HERE_BEFORE_10_6(__gcc_personality_v0)
+NOT_HERE_BEFORE_10_6(__lshrdi3)
+NOT_HERE_BEFORE_10_6(__lshrti3)
+NOT_HERE_BEFORE_10_6(__moddi3)
+NOT_HERE_BEFORE_10_6(__modti3)
+NOT_HERE_BEFORE_10_6(__muldc3)
+NOT_HERE_BEFORE_10_6(__muldi3)
+NOT_HERE_BEFORE_10_6(__mulsc3)
+NOT_HERE_BEFORE_10_6(__multc3)
+NOT_HERE_BEFORE_10_6(__multi3)
+NOT_HERE_BEFORE_10_6(__mulvdi3)
+NOT_HERE_BEFORE_10_6(__mulvsi3)
+NOT_HERE_BEFORE_10_6(__mulvti3)
+NOT_HERE_BEFORE_10_6(__mulxc3)
+NOT_HERE_BEFORE_10_6(__negdi2)
+NOT_HERE_BEFORE_10_6(__negti2)
+NOT_HERE_BEFORE_10_6(__negvdi2)
+NOT_HERE_BEFORE_10_6(__negvsi2)
+NOT_HERE_BEFORE_10_6(__negvti2)
+NOT_HERE_BEFORE_10_6(__paritydi2)
+NOT_HERE_BEFORE_10_6(__paritysi2)
+NOT_HERE_BEFORE_10_6(__parityti2)
+NOT_HERE_BEFORE_10_6(__popcountdi2)
+NOT_HERE_BEFORE_10_6(__popcountsi2)
+NOT_HERE_BEFORE_10_6(__popcountti2)
+NOT_HERE_BEFORE_10_6(__powidf2)
+NOT_HERE_BEFORE_10_6(__powisf2)
+NOT_HERE_BEFORE_10_6(__powitf2)
+NOT_HERE_BEFORE_10_6(__powixf2)
+NOT_HERE_BEFORE_10_6(__subvdi3)
+NOT_HERE_BEFORE_10_6(__subvsi3)
+NOT_HERE_BEFORE_10_6(__subvti3)
+NOT_HERE_BEFORE_10_6(__ucmpdi2)
+NOT_HERE_BEFORE_10_6(__ucmpti2)
+NOT_HERE_BEFORE_10_6(__udivdi3)
+NOT_HERE_BEFORE_10_6(__udivmoddi4)
+NOT_HERE_BEFORE_10_6(__udivmodti4)
+NOT_HERE_BEFORE_10_6(__udivti3)
+NOT_HERE_BEFORE_10_6(__umoddi3)
+NOT_HERE_BEFORE_10_6(__umodti3)
+
+
+#if __ppc__
+NOT_HERE_BEFORE_10_6(__gcc_qadd)
+NOT_HERE_BEFORE_10_6(__gcc_qdiv)
+NOT_HERE_BEFORE_10_6(__gcc_qmul)
+NOT_HERE_BEFORE_10_6(__gcc_qsub)
+NOT_HERE_BEFORE_10_6(__trampoline_setup)
+#endif /* __ppc__ */
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_8)
+
+
+#if __arm__ && __DYNAMIC__
+ #define NOT_HERE_UNTIL_AFTER_4_3(sym) \
+ extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp1 = 0; \
+ extern const char sym##_tmp2 __asm("$ld$hide$os3.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp2 = 0; \
+ extern const char sym##_tmp3 __asm("$ld$hide$os3.2$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os4.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os4.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os4.2$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0; \
+ extern const char sym##_tmp7 __asm("$ld$hide$os4.3$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp7 = 0;
+
+NOT_HERE_UNTIL_AFTER_4_3(__absvdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__absvsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__adddf3)
+NOT_HERE_UNTIL_AFTER_4_3(__adddf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__addsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__addsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__addvdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__addvsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__ashldi3)
+NOT_HERE_UNTIL_AFTER_4_3(__ashrdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__bswapdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__bswapsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__clzdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__clzsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__cmpdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__ctzdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__ctzsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__divdc3)
+NOT_HERE_UNTIL_AFTER_4_3(__divdf3)
+NOT_HERE_UNTIL_AFTER_4_3(__divdf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__divdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__divsc3)
+NOT_HERE_UNTIL_AFTER_4_3(__divsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__divsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__divsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__eqdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__eqdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__eqsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__eqsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ffsdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__fixdfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixdfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixdfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__fixsfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixsfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixsfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunssfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatdidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatdisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsidfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsisfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatundidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatundisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunsidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunsisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunssidfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunssisfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gedf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gedf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gesf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gesf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gtdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gtdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gtsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gtsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ledf2)
+NOT_HERE_UNTIL_AFTER_4_3(__ledf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__lesf2)
+NOT_HERE_UNTIL_AFTER_4_3(__lesf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__lshrdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__ltdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__ltdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ltsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__ltsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__moddi3)
+NOT_HERE_UNTIL_AFTER_4_3(__modsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__muldc3)
+NOT_HERE_UNTIL_AFTER_4_3(__muldf3)
+NOT_HERE_UNTIL_AFTER_4_3(__muldf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__muldi3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulsc3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__mulvdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulvsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__nedf2)
+NOT_HERE_UNTIL_AFTER_4_3(__nedf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__negdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__negvdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__negvsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__nesf2)
+NOT_HERE_UNTIL_AFTER_4_3(__nesf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__paritydi2)
+NOT_HERE_UNTIL_AFTER_4_3(__paritysi2)
+NOT_HERE_UNTIL_AFTER_4_3(__popcountdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__popcountsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__powidf2)
+NOT_HERE_UNTIL_AFTER_4_3(__powisf2)
+NOT_HERE_UNTIL_AFTER_4_3(__subdf3)
+NOT_HERE_UNTIL_AFTER_4_3(__subdf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__subsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__subsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__subvdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__subvsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ucmpdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__udivdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__udivmoddi4)
+NOT_HERE_UNTIL_AFTER_4_3(__udivsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__umoddi3)
+NOT_HERE_UNTIL_AFTER_4_3(__umodsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__unorddf2)
+NOT_HERE_UNTIL_AFTER_4_3(__unorddf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__unordsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__unordsf2vfp)
+
+NOT_HERE_UNTIL_AFTER_4_3(__divmodsi4)
+NOT_HERE_UNTIL_AFTER_4_3(__udivmodsi4)
+#endif // __arm__ && __DYNAMIC__
+
+
+
+
+
+#else /* !__APPLE__ */
+
+extern int avoid_empty_file;
+
+#endif /* !__APPLE__*/
diff --git a/contrib/compiler-rt/lib/arm/adddf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S
index c90b0c2eabe6..2825ae92cd5a 100644
--- a/contrib/compiler-rt/lib/arm/adddf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S
@@ -16,10 +16,11 @@
// calling convention where double arguments are passsed in GPR pairs
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
vadd.f64 d6, d6, d7
vmov r0, r1, d6 // move result back to r0/r1 pair
bx lr
+END_COMPILERRT_FUNCTION(__adddf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/addsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S
index 43653d5265c0..bff5a7e0fbe8 100644
--- a/contrib/compiler-rt/lib/arm/addsf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S
@@ -16,10 +16,11 @@
// calling convention where single arguments are passsed in GPRs
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vadd.f32 s14, s14, s15
vmov r0, s14 // move result back to r0
bx lr
+END_COMPILERRT_FUNCTION(__addsf3vfp)
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
new file mode 100644
index 000000000000..310c35b74932
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
@@ -0,0 +1,40 @@
+//===-- aeabi_dcmp.S - EABI dcmp* implementation ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) {
+// int result = __{eq,lt,le,ge,gt}df2(a, b);
+// if (result {==,<,<=,>=,>} 0) {
+// return 1;
+// } else {
+// return 0;
+// }
+// }
+
+#define DEFINE_AEABI_DCMP(cond) \
+ .syntax unified SEPARATOR \
+ .p2align 2 SEPARATOR \
+DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
+ push { r4, lr } SEPARATOR \
+ bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
+ cmp r0, #0 SEPARATOR \
+ b ## cond 1f SEPARATOR \
+ mov r0, #0 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+1: SEPARATOR \
+ mov r0, #1 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond)
+
+DEFINE_AEABI_DCMP(eq)
+DEFINE_AEABI_DCMP(lt)
+DEFINE_AEABI_DCMP(le)
+DEFINE_AEABI_DCMP(ge)
+DEFINE_AEABI_DCMP(gt)
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_div0.c b/contrib/compiler-rt/lib/builtins/arm/aeabi_div0.c
new file mode 100644
index 000000000000..ccc95fa5c12e
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_div0.c
@@ -0,0 +1,43 @@
+/* ===-- aeabi_div0.c - ARM Runtime ABI support routines for compiler-rt ---===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements the division by zero helper routines as specified by the
+ * Run-time ABI for the ARM Architecture.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+/*
+ * RTABI 4.3.2 - Division by zero
+ *
+ * The *div0 functions:
+ * - Return the value passed to them as a parameter
+ * - Or, return a fixed value defined by the execution environment (such as 0)
+ * - Or, raise a signal (often SIGFPE) or throw an exception, and do not return
+ *
+ * An application may provide its own implementations of the *div0 functions to
+ * for a particular behaviour from the *div and *divmod functions called out of
+ * line.
+ */
+
+/* provide an unused declaration to pacify pendantic compilation */
+extern unsigned char declaration;
+
+#if defined(__ARM_EABI__)
+int __attribute__((weak)) __attribute__((visibility("hidden")))
+__aeabi_idiv0(int return_value) {
+ return return_value;
+}
+
+long long __attribute__((weak)) __attribute__((visibility("hidden")))
+__aeabi_ldiv0(long long return_value) {
+ return return_value;
+}
+#endif
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
new file mode 100644
index 000000000000..55f49a2b5af6
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
@@ -0,0 +1,40 @@
+//===-- aeabi_fcmp.S - EABI fcmp* implementation ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// int __aeabi_fcmp{eq,lt,le,ge,gt}(float a, float b) {
+// int result = __{eq,lt,le,ge,gt}sf2(a, b);
+// if (result {==,<,<=,>=,>} 0) {
+// return 1;
+// } else {
+// return 0;
+// }
+// }
+
+#define DEFINE_AEABI_FCMP(cond) \
+ .syntax unified SEPARATOR \
+ .p2align 2 SEPARATOR \
+DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \
+ push { r4, lr } SEPARATOR \
+ bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \
+ cmp r0, #0 SEPARATOR \
+ b ## cond 1f SEPARATOR \
+ mov r0, #0 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+1: SEPARATOR \
+ mov r0, #1 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+END_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond)
+
+DEFINE_AEABI_FCMP(eq)
+DEFINE_AEABI_FCMP(lt)
+DEFINE_AEABI_FCMP(le)
+DEFINE_AEABI_FCMP(ge)
+DEFINE_AEABI_FCMP(gt)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_idivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S
index 0237f2221d7b..384add38279e 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_idivmod.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S
@@ -16,7 +16,7 @@
// }
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
push { lr }
sub sp, sp, #4
@@ -25,3 +25,4 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
ldr r1, [sp]
add sp, sp, #4
pop { pc }
+END_COMPILERRT_FUNCTION(__aeabi_idivmod)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_ldivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S
index 197c459eb381..ad06f1de2af4 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_ldivmod.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S
@@ -17,7 +17,7 @@
// }
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
push {r11, lr}
sub sp, sp, #16
@@ -28,3 +28,4 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
ldr r3, [sp, #12]
add sp, sp, #16
pop {r11, pc}
+END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_memcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S
index ca29c10c65b6..051ce435bab9 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_memcmp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S
@@ -11,9 +11,10 @@
// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); }
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
b memcmp
+END_COMPILERRT_FUNCTION(__aeabi_memcmp)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_memcpy.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S
index 8b9c7fdf5f19..cf02332490a1 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_memcpy.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S
@@ -11,9 +11,10 @@
// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
b memcpy
+END_COMPILERRT_FUNCTION(__aeabi_memcpy)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_memmove.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S
index c94ed2b210e8..4dda06f75d04 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_memmove.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S
@@ -11,9 +11,10 @@
// void __aeabi_memmove(void *dest, void *src, size_t n) { memmove(dest, src, n); }
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
b memmove
+END_COMPILERRT_FUNCTION(__aeabi_memmove)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_memset.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S
index 30ab4bae5a5d..c8b49c7809a6 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_memset.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S
@@ -12,20 +12,22 @@
// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); }
// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); }
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
mov r3, r1
mov r1, r2
mov r2, r3
b memset
+END_COMPILERRT_FUNCTION(__aeabi_memset)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
-
+
DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
mov r2, r1
mov r1, #0
b memset
+END_COMPILERRT_FUNCTION(__aeabi_memclr)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_uidivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S
index f7e1d2ebed1a..8ea474d91c6b 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_uidivmod.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S
@@ -17,7 +17,7 @@
// }
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
push { lr }
sub sp, sp, #4
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
ldr r1, [sp]
add sp, sp, #4
pop { pc }
+END_COMPILERRT_FUNCTION(__aeabi_uidivmod)
diff --git a/contrib/compiler-rt/lib/arm/aeabi_uldivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S
index e061a6e1300d..4e1f8e2a6736 100644
--- a/contrib/compiler-rt/lib/arm/aeabi_uldivmod.S
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S
@@ -17,7 +17,7 @@
// }
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
push {r11, lr}
sub sp, sp, #16
@@ -28,4 +28,4 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
ldr r3, [sp, #12]
add sp, sp, #16
pop {r11, pc}
-
+END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
diff --git a/contrib/compiler-rt/lib/arm/bswapdi2.S b/contrib/compiler-rt/lib/builtins/arm/bswapdi2.S
index a0283e14e1e0..86f3bba8c290 100644
--- a/contrib/compiler-rt/lib/arm/bswapdi2.S
+++ b/contrib/compiler-rt/lib/builtins/arm/bswapdi2.S
@@ -9,14 +9,24 @@
#include "../assembly.h"
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
//
// extern uint64_t __bswapdi2(uint64_t);
//
// Reverse all the bytes in a 64-bit integer.
//
-.align 2
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
+#else
DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
-#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__
+#endif
+#if __ARM_ARCH < 6
// before armv6 does not have "rev" instruction
// r2 = rev(r0)
eor r2, r0, r0, ror #16
@@ -33,4 +43,5 @@ DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
rev r0, r1 // r0 = rev(r1)
#endif
mov r1, r2 // r1 = r2 = rev(r0)
- bx lr
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__bswapdi2)
diff --git a/contrib/compiler-rt/lib/arm/bswapsi2.S b/contrib/compiler-rt/lib/builtins/arm/bswapsi2.S
index 4c3af1f6d04d..59ba8158fd57 100644
--- a/contrib/compiler-rt/lib/arm/bswapsi2.S
+++ b/contrib/compiler-rt/lib/builtins/arm/bswapsi2.S
@@ -9,14 +9,24 @@
#include "../assembly.h"
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
//
// extern uint32_t __bswapsi2(uint32_t);
//
// Reverse all the bytes in a 32-bit integer.
//
-.align 2
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
+#else
DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
-#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__
+#endif
+#if __ARM_ARCH < 6
// before armv6 does not have "rev" instruction
eor r1, r0, r0, ror #16
bic r1, r1, #0xff0000
@@ -25,4 +35,5 @@ DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
#else
rev r0, r0
#endif
- bx lr
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__bswapsi2)
diff --git a/contrib/compiler-rt/lib/builtins/arm/clzdi2.S b/contrib/compiler-rt/lib/builtins/arm/clzdi2.S
new file mode 100644
index 000000000000..a55abac0469b
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/clzdi2.S
@@ -0,0 +1,97 @@
+/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements count leading zeros for 64bit arguments.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+
+ .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
+ itee ne
+ clzne r0, r0
+ clzeq r0, r1
+ addeq r0, r0, 32
+#else
+ cmp r1, 0
+ itee ne
+ clzne r0, r1
+ clzeq r0, r0
+ addeq r0, r0, 32
+#endif
+ JMP(lr)
+#else
+ /* Assumption: n != 0 */
+
+ /*
+ * r0: n
+ * r1: upper half of n, overwritten after check
+ * r1: count of leading zeros in n + 1
+ * r2: scratch register for shifted r0
+ */
+#ifdef __ARMEB__
+ cmp r0, 0
+ moveq r0, r1
+#else
+ cmp r1, 0
+ movne r0, r1
+#endif
+ movne r1, 1
+ moveq r1, 33
+
+ /*
+ * Basic block:
+ * if ((r0 >> SHIFT) == 0)
+ * r1 += SHIFT;
+ * else
+ * r0 >>= SHIFT;
+ * for descending powers of two as SHIFT.
+ */
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ /*
+ * The basic block invariants at this point are (r0 >> 2) == 0 and
+ * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ *
+ * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ * ---+----------------+----------------+------------+--------------
+ * 1 | 1 | 0 | 0 | 1
+ * 2 | 0 | 1 | -1 | 0
+ * 3 | 0 | 1 | -1 | 0
+ *
+ * The r1's initial value of 1 compensates for the 1 here.
+ */
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzdi2)
diff --git a/contrib/compiler-rt/lib/builtins/arm/clzsi2.S b/contrib/compiler-rt/lib/builtins/arm/clzsi2.S
new file mode 100644
index 000000000000..1cd379bfb0a9
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/clzsi2.S
@@ -0,0 +1,76 @@
+/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements count leading zeros for 32bit arguments.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .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)
+#else
+ /* Assumption: n != 0 */
+
+ /*
+ * r0: n
+ * r1: count of leading zeros in n + 1
+ * r2: scratch register for shifted r0
+ */
+ mov r1, 1
+
+ /*
+ * Basic block:
+ * if ((r0 >> SHIFT) == 0)
+ * r1 += SHIFT;
+ * else
+ * r0 >>= SHIFT;
+ * for descending powers of two as SHIFT.
+ */
+
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ /*
+ * The basic block invariants at this point are (r0 >> 2) == 0 and
+ * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ *
+ * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ * ---+----------------+----------------+------------+--------------
+ * 1 | 1 | 0 | 0 | 1
+ * 2 | 0 | 1 | -1 | 0
+ * 3 | 0 | 1 | -1 | 0
+ *
+ * The r1's initial value of 1 compensates for the 1 here.
+ */
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzsi2)
diff --git a/contrib/compiler-rt/lib/arm/comparesf2.S b/contrib/compiler-rt/lib/builtins/arm/comparesf2.S
index ee18203392dc..cf71d36e0517 100644
--- a/contrib/compiler-rt/lib/arm/comparesf2.S
+++ b/contrib/compiler-rt/lib/builtins/arm/comparesf2.S
@@ -40,33 +40,32 @@
#include "../assembly.h"
.syntax unified
-.align 2
+.p2align 2
DEFINE_COMPILERRT_FUNCTION(__eqsf2)
-DEFINE_COMPILERRT_FUNCTION(__lesf2)
-DEFINE_COMPILERRT_FUNCTION(__ltsf2)
-DEFINE_COMPILERRT_FUNCTION(__nesf2)
// Make copies of a and b with the sign bit shifted off the top. These will
// be used to detect zeros and NaNs.
mov r2, r0, lsl #1
mov r3, r1, lsl #1
-
+
// We do the comparison in three stages (ignoring NaN values for the time
// being). First, we orr the absolute values of a and b; this sets the Z
// 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.
orrs r12, r2, r3, lsr #1
-
+
// 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.
+ it ne
eorsne r12, r0, r1
-
+
// If a and b are equal (either both zeros or bit identical; again, we're
// 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.
+ it pl
subspl r0, r2, r3
-
+
// If a is smaller in magnitude than b and both have the same sign, place
// the negation of the sign of b in r0. Thus, if both are negative and
// a > b, this sets r0 to 0; if both are positive and a < b, this sets
@@ -77,54 +76,73 @@ DEFINE_COMPILERRT_FUNCTION(__nesf2)
// 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.
+ it lo
mvnlo r0, r1, asr #31
// If a is greater in magnitude than b and both have the same sign, place
// 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.
+ it hi
movhi r0, r1, asr #31
-
+
// If you've been keeping track, at this point r0 contains -1 if a < b and
// 0 if a >= b. All that remains to be done is to set it to 1 if a > b.
// 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.
- orrne r0, r0, #1
-
+ it ne
+ orrne r0, r0, #1
+
// Finally, we need to deal with NaNs. If either argument is NaN, replace
// the value in r0 with 1.
cmp r2, #0xff000000
+ ite ls
cmpls r3, #0xff000000
movhi r0, #1
- bx lr
-
-.align 2
-DEFINE_COMPILERRT_FUNCTION(__gesf2)
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2)
+
+.p2align 2
DEFINE_COMPILERRT_FUNCTION(__gtsf2)
- // Identical to the preceeding except in that we return -1 for NaN values.
+ // Identical to the preceding except in that we return -1 for NaN values.
// Given that the two paths share so much code, one might be tempted to
// unify them; however, the extra code needed to do so makes the code size
// to performance tradeoff very hard to justify for such small functions.
mov r2, r0, lsl #1
mov r3, r1, lsl #1
orrs r12, r2, r3, lsr #1
+ it ne
eorsne r12, r0, r1
+ it pl
subspl r0, r2, r3
+ it lo
mvnlo r0, r1, asr #31
+ it hi
movhi r0, r1, asr #31
- orrne r0, r0, #1
+ it ne
+ orrne r0, r0, #1
cmp r2, #0xff000000
+ ite ls
cmpls r3, #0xff000000
movhi r0, #-1
- bx lr
-
-.align 2
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__gtsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)
+
+.p2align 2
DEFINE_COMPILERRT_FUNCTION(__unordsf2)
// Return 1 for NaN values, 0 otherwise.
mov r2, r0, lsl #1
mov r3, r1, lsl #1
mov r0, #0
cmp r2, #0xff000000
+ ite ls
cmpls r3, #0xff000000
movhi r0, #1
- bx lr
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__unordsf2)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2)
diff --git a/contrib/compiler-rt/lib/arm/divdf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S
index 52de67f7fdcd..6eebef167a2c 100644
--- a/contrib/compiler-rt/lib/arm/divdf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S
@@ -16,10 +16,11 @@
// calling convention where double arguments are passsed in GPR pairs
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
vdiv.f64 d5, d6, d7
vmov r0, r1, d5 // move result back to r0/r1 pair
bx lr
+END_COMPILERRT_FUNCTION(__divdf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/divmodsi4.S b/contrib/compiler-rt/lib/builtins/arm/divmodsi4.S
index cec39a7926f9..646b9ab78fb6 100644
--- a/contrib/compiler-rt/lib/arm/divmodsi4.S
+++ b/contrib/compiler-rt/lib/builtins/arm/divmodsi4.S
@@ -21,9 +21,34 @@
#define CLEAR_FRAME_AND_RETURN \
pop {r4-r7, pc}
-.syntax unified
-.align 3
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ 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)
+ mov r3, r0
+ sdiv r0, r3, r1
+ mls r1, r0, r1, r3
+ str r1, [r2]
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0, #0
+ bx lr
+#else
ESTABLISH_FRAME
// Set aside the sign of the quotient and modulus, and the address for the
// modulus.
@@ -45,3 +70,5 @@ DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
sub r1, r1, r5, asr #31
str r1, [r6]
CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__divmodsi4)
diff --git a/contrib/compiler-rt/lib/arm/divsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S
index 81ba90307897..fdbaebc88371 100644
--- a/contrib/compiler-rt/lib/arm/divsf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S
@@ -16,10 +16,11 @@
// calling convention where single arguments are passsed like 32-bit ints.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vdiv.f32 s13, s14, s15
vmov r0, s13 // move result back to r0
bx lr
+END_COMPILERRT_FUNCTION(__divsf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/divsi3.S b/contrib/compiler-rt/lib/builtins/arm/divsi3.S
index e76fe31bb782..adf8f94fc7b8 100644
--- a/contrib/compiler-rt/lib/arm/divsi3.S
+++ b/contrib/compiler-rt/lib/builtins/arm/divsi3.S
@@ -20,12 +20,25 @@
#define CLEAR_FRAME_AND_RETURN \
pop {r4, r7, pc}
-.syntax unified
-.align 3
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 3
// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
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)
-#if __ARM_ARCH_7S__
+#endif
+#if __ARM_ARCH_EXT_IDIV__
tst r1,r1
beq LOCAL_LABEL(divzero)
sdiv r0, r0, r1
@@ -49,3 +62,4 @@ ESTABLISH_FRAME
sub r0, r0, r4, asr #31
CLEAR_FRAME_AND_RETURN
#endif
+END_COMPILERRT_FUNCTION(__divsi3)
diff --git a/contrib/compiler-rt/lib/arm/eqdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S
index c41e55a34685..7f2fbc3072d4 100644
--- a/contrib/compiler-rt/lib/arm/eqdf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
moveq r0, #1 // set result register to 1 if equal
movne r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__eqdf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/eqsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S
index 730ef88da68c..a318b336ae9e 100644
--- a/contrib/compiler-rt/lib/arm/eqsf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
moveq r0, #1 // set result register to 1 if equal
movne r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__eqsf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/extendsfdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S
index 17a146e0280a..b998e589459e 100644
--- a/contrib/compiler-rt/lib/arm/extendsfdf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S
@@ -17,9 +17,10 @@
// passed in a GPR and a double precision result is returned in R0/R1 pair.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
vmov s15, r0 // load float register from R0
vcvt.f64.f32 d7, s15 // convert single to double
vmov r0, r1, d7 // return result in r0/r1 pair
bx lr
+END_COMPILERRT_FUNCTION(__extendsfdf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/fixdfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S
index b7c3299d1c4d..e3bd8e05e01f 100644
--- a/contrib/compiler-rt/lib/arm/fixdfsivfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S
@@ -17,9 +17,10 @@
// passed in GPR register pair.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
vmov d7, r0, r1 // load double register from R0/R1
vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15
vmov r0, s15 // move s15 to result register
bx lr
+END_COMPILERRT_FUNCTION(__fixdfsivfp)
diff --git a/contrib/compiler-rt/lib/arm/fixsfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S
index 1cea6a486d6d..3d0d0f56d235 100644
--- a/contrib/compiler-rt/lib/arm/fixsfsivfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S
@@ -17,9 +17,10 @@
// passed in a GPR..
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
vmov s15, r0 // load float register from R0
vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15
vmov r0, s15 // move s15 to result register
bx lr
+END_COMPILERRT_FUNCTION(__fixsfsivfp)
diff --git a/contrib/compiler-rt/lib/arm/fixunsdfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S
index 54b03592b457..35dda5b9b034 100644
--- a/contrib/compiler-rt/lib/arm/fixunsdfsivfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S
@@ -18,9 +18,10 @@
// passed in GPR register pair.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
vmov d7, r0, r1 // load double register from R0/R1
vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15
vmov r0, s15 // move s15 to result register
bx lr
+END_COMPILERRT_FUNCTION(__fixunsdfsivfp)
diff --git a/contrib/compiler-rt/lib/arm/fixunssfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S
index 12adb529ae7a..5c3a7d926fcc 100644
--- a/contrib/compiler-rt/lib/arm/fixunssfsivfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S
@@ -18,9 +18,10 @@
// passed in a GPR..
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
vmov s15, r0 // load float register from R0
vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15
vmov r0, s15 // move s15 to result register
bx lr
+END_COMPILERRT_FUNCTION(__fixunssfsivfp)
diff --git a/contrib/compiler-rt/lib/arm/floatsidfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S
index e6a1eb3e497f..d69184914ccd 100644
--- a/contrib/compiler-rt/lib/arm/floatsidfvfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S
@@ -17,9 +17,10 @@
// return in GPR register pair.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
vmov s15, r0 // move int to float register s15
vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7
vmov r0, r1, d7 // move d7 to result register pair r0/r1
bx lr
+END_COMPILERRT_FUNCTION(__floatsidfvfp)
diff --git a/contrib/compiler-rt/lib/arm/floatsisfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S
index 0d3a24fc1ece..4a0cb39d0eb0 100644
--- a/contrib/compiler-rt/lib/arm/floatsisfvfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S
@@ -17,9 +17,10 @@
// return in a GPR..
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
vmov s15, r0 // move int to float register s15
vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15
vmov r0, s15 // move s15 to result register
bx lr
+END_COMPILERRT_FUNCTION(__floatsisfvfp)
diff --git a/contrib/compiler-rt/lib/arm/floatunssidfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S
index 770b20292fd4..d92969ea3453 100644
--- a/contrib/compiler-rt/lib/arm/floatunssidfvfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S
@@ -17,9 +17,10 @@
// return in GPR register pair.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
vmov s15, r0 // move int to float register s15
vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7
vmov r0, r1, d7 // move d7 to result register pair r0/r1
bx lr
+END_COMPILERRT_FUNCTION(__floatunssidfvfp)
diff --git a/contrib/compiler-rt/lib/arm/floatunssisfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S
index 16b3ffb104ba..f6aeba56ae15 100644
--- a/contrib/compiler-rt/lib/arm/floatunssisfvfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S
@@ -17,9 +17,10 @@
// return in a GPR..
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp)
vmov s15, r0 // move int to float register s15
vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15
vmov r0, s15 // move s15 to result register
bx lr
+END_COMPILERRT_FUNCTION(__floatunssisfvfp)
diff --git a/contrib/compiler-rt/lib/arm/gedf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S
index 55603b83e306..9e235270175c 100644
--- a/contrib/compiler-rt/lib/arm/gedf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
movge r0, #1 // set result register to 1 if greater than or equal
movlt r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__gedf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/gesf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S
index 02da35c02e92..0ff608477882 100644
--- a/contrib/compiler-rt/lib/arm/gesf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
movge r0, #1 // set result register to 1 if greater than or equal
movlt r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__gesf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/gtdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S
index b5b1e1482762..3dc5d5b59225 100644
--- a/contrib/compiler-rt/lib/arm/gtdf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
movgt r0, #1 // set result register to 1 if equal
movle r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__gtdf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/gtsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S
index 685a9cec96ca..ddd843acf592 100644
--- a/contrib/compiler-rt/lib/arm/gtsf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
movgt r0, #1 // set result register to 1 if equal
movle r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__gtsf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/ledf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S
index 6e140dde8764..b06ff6db5a33 100644
--- a/contrib/compiler-rt/lib/arm/ledf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
movls r0, #1 // set result register to 1 if equal
movhi r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__ledf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/lesf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S
index 7b2825097a87..9b33c0c53697 100644
--- a/contrib/compiler-rt/lib/arm/lesf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
movls r0, #1 // set result register to 1 if equal
movhi r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__lesf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/ltdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S
index a09e67a2f43d..9f794b026a4a 100644
--- a/contrib/compiler-rt/lib/arm/ltdf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
movmi r0, #1 // set result register to 1 if equal
movpl r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__ltdf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/ltsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S
index 8c7f9a863f34..ba190d9d8dc2 100644
--- a/contrib/compiler-rt/lib/arm/ltsf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
movmi r0, #1 // set result register to 1 if equal
movpl r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__ltsf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/modsi3.S b/contrib/compiler-rt/lib/builtins/arm/modsi3.S
index a4cd2ee54e7b..295a227d862e 100644
--- a/contrib/compiler-rt/lib/arm/modsi3.S
+++ b/contrib/compiler-rt/lib/builtins/arm/modsi3.S
@@ -20,9 +20,31 @@
#define CLEAR_FRAME_AND_RETURN \
pop {r4, r7, pc}
-.syntax unified
-.align 3
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ 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)
+ sdiv r2, r0, r1
+ mls r0, r2, r1, r0
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0, #0
+ bx lr
+#else
ESTABLISH_FRAME
// Set aside the sign of the dividend.
mov r4, r0
@@ -37,3 +59,5 @@ DEFINE_COMPILERRT_FUNCTION(__modsi3)
eor r0, r0, r4, asr #31
sub r0, r0, r4, asr #31
CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__modsi3)
diff --git a/contrib/compiler-rt/lib/arm/muldf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S
index 838581eb1097..636cc711ac1a 100644
--- a/contrib/compiler-rt/lib/arm/muldf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S
@@ -16,10 +16,11 @@
// calling convention where double arguments are passsed in GPR pairs
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__muldf3vfp)
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
vmul.f64 d6, d6, d7
vmov r0, r1, d6 // move result back to r0/r1 pair
bx lr
+END_COMPILERRT_FUNCTION(__muldf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/mulsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S
index ea25913cc49d..7f4008266bff 100644
--- a/contrib/compiler-rt/lib/arm/mulsf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S
@@ -16,10 +16,11 @@
// calling convention where single arguments are passsed like 32-bit ints.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp)
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vmul.f32 s13, s14, s15
vmov r0, s13 // move result back to r0
bx lr
+END_COMPILERRT_FUNCTION(__mulsf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/nedf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S
index 21670816c609..7ab2f5501ce0 100644
--- a/contrib/compiler-rt/lib/arm/nedf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
movne r0, #1 // set result register to 0 if unequal
moveq r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__nedf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/negdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S
index 64c9b692f454..56d73c676176 100644
--- a/contrib/compiler-rt/lib/arm/negdf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S
@@ -16,7 +16,8 @@
// Darwin calling convention where double arguments are passsed in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__negdf2vfp)
eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair
bx lr
+END_COMPILERRT_FUNCTION(__negdf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/negsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S
index b883b733df64..a6e32e1ff89c 100644
--- a/contrib/compiler-rt/lib/arm/negsf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S
@@ -16,7 +16,8 @@
// Darwin calling convention where single arguments are passsed like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__negsf2vfp)
eor r0, r0, #-2147483648 // flip sign bit on float in r0
bx lr
+END_COMPILERRT_FUNCTION(__negsf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/nesf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S
index fa7aa80e1912..9fe8ecdefb37 100644
--- a/contrib/compiler-rt/lib/arm/nesf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
movne r0, #1 // set result register to 1 if unequal
moveq r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__nesf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/restore_vfp_d8_d15_regs.S b/contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S
index 7f441db5383b..0f6ea5136166 100644
--- a/contrib/compiler-rt/lib/arm/restore_vfp_d8_d15_regs.S
+++ b/contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S
@@ -25,13 +25,9 @@
//
// Restore registers d8-d15 from stack
//
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs)
vldmia sp!, {d8-d15} // pop registers d8-d15 off stack
bx lr // return to prolog
-
-
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
+END_COMPILERRT_FUNCTION(__restore_vfp_d8_d15_regs)
diff --git a/contrib/compiler-rt/lib/arm/save_vfp_d8_d15_regs.S b/contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S
index fbd21ba38358..f1d90e75808c 100644
--- a/contrib/compiler-rt/lib/arm/save_vfp_d8_d15_regs.S
+++ b/contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S
@@ -25,11 +25,9 @@
//
// Save registers d8-d15 onto stack
//
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs)
vstmdb sp!, {d8-d15} // push registers d8-d15 onto stack
bx lr // return to prolog
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
+END_COMPILERRT_FUNCTION(__save_vfp_d8_d15_regs)
diff --git a/contrib/compiler-rt/lib/arm/softfloat-alias.list b/contrib/compiler-rt/lib/builtins/arm/softfloat-alias.list
index cc6a4b3cdd2e..cc6a4b3cdd2e 100644
--- a/contrib/compiler-rt/lib/arm/softfloat-alias.list
+++ b/contrib/compiler-rt/lib/builtins/arm/softfloat-alias.list
diff --git a/contrib/compiler-rt/lib/arm/subdf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S
index 3f88baacd5bf..5f3c0f70dbc4 100644
--- a/contrib/compiler-rt/lib/arm/subdf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S
@@ -16,10 +16,11 @@
// the Darwin calling convention where double arguments are passsed in GPR pairs
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__subdf3vfp)
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
vsub.f64 d6, d6, d7
vmov r0, r1, d6 // move result back to r0/r1 pair
bx lr
+END_COMPILERRT_FUNCTION(__subdf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/subsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S
index ed02ba92167f..d6e06df51920 100644
--- a/contrib/compiler-rt/lib/arm/subsf3vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S
@@ -17,10 +17,11 @@
// like 32-bit ints.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__subsf3vfp)
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vsub.f32 s14, s14, s15
vmov r0, s14 // move result back to r0
bx lr
+END_COMPILERRT_FUNCTION(__subsf3vfp)
diff --git a/contrib/compiler-rt/lib/arm/switch16.S b/contrib/compiler-rt/lib/builtins/arm/switch16.S
index e8f08c49c5df..3c3a6b106124 100644
--- a/contrib/compiler-rt/lib/arm/switch16.S
+++ b/contrib/compiler-rt/lib/builtins/arm/switch16.S
@@ -29,16 +29,16 @@
// The table contains signed 2-byte sized elements which are 1/2 the distance
// from lr to the target label.
//
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16)
ldrh ip, [lr, #-1] // get first 16-bit word in table
cmp r0, ip // compare with index
add r0, lr, r0, lsl #1 // compute address of element in table
- ldrshcc r0, [r0, #1] // load 16-bit element if r0 is in range
add ip, lr, ip, lsl #1 // compute address of last element in table
+ ite lo
+ ldrshlo r0, [r0, #1] // load 16-bit element if r0 is in range
ldrshhs r0, [ip, #1] // load 16-bit element if r0 out of range
add ip, lr, r0, lsl #1 // compute label = lr + element*2
bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch16)
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
diff --git a/contrib/compiler-rt/lib/arm/switch32.S b/contrib/compiler-rt/lib/builtins/arm/switch32.S
index 7008fccb18ee..b38cd2b764a4 100644
--- a/contrib/compiler-rt/lib/arm/switch32.S
+++ b/contrib/compiler-rt/lib/builtins/arm/switch32.S
@@ -29,18 +29,16 @@
// The table contains signed 4-byte sized elements which are the distance
// from lr to the target label.
//
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32)
ldr ip, [lr, #-1] // get first 32-bit word in table
cmp r0, ip // compare with index
add r0, lr, r0, lsl #2 // compute address of element in table
- ldrcc r0, [r0, #3] // load 32-bit element if r0 is in range
add ip, lr, ip, lsl #2 // compute address of last element in table
- ldrcs r0, [ip, #3] // load 32-bit element if r0 out of range
+ ite lo
+ ldrlo r0, [r0, #3] // load 32-bit element if r0 is in range
+ ldrhs r0, [ip, #3] // load 32-bit element if r0 out of range
add ip, lr, r0 // compute label = lr + element
bx ip // jump to computed label
-
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
+END_COMPILERRT_FUNCTION(__switch32)
diff --git a/contrib/compiler-rt/lib/arm/switch8.S b/contrib/compiler-rt/lib/builtins/arm/switch8.S
index e784b4082e1f..d7c20423def2 100644
--- a/contrib/compiler-rt/lib/arm/switch8.S
+++ b/contrib/compiler-rt/lib/builtins/arm/switch8.S
@@ -29,15 +29,14 @@
// The table contains signed byte sized elements which are 1/2 the distance
// from lr to the target label.
//
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8)
ldrb ip, [lr, #-1] // get first byte in table
cmp r0, ip // signed compare with index
- ldrsbcc r0, [lr, r0] // get indexed byte out of table
+ ite lo
+ ldrsblo r0, [lr, r0] // get indexed byte out of table
ldrsbhs r0, [lr, ip] // if out of range, use last entry in table
add ip, lr, r0, lsl #1 // compute label = lr + element*2
bx ip // jump to computed label
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
+END_COMPILERRT_FUNCTION(__switch8)
diff --git a/contrib/compiler-rt/lib/arm/switchu8.S b/contrib/compiler-rt/lib/builtins/arm/switchu8.S
index 19bed2f664d7..1844f11c604e 100644
--- a/contrib/compiler-rt/lib/arm/switchu8.S
+++ b/contrib/compiler-rt/lib/builtins/arm/switchu8.S
@@ -29,15 +29,14 @@
// The table contains unsigned byte sized elements which are 1/2 the distance
// from lr to the target label.
//
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8)
ldrb ip, [lr, #-1] // get first byte in table
cmp r0, ip // compare with index
- ldrbcc r0, [lr, r0] // get indexed byte out of table
+ ite lo
+ ldrblo r0, [lr, r0] // get indexed byte out of table
ldrbhs r0, [lr, ip] // if out of range, use last entry in table
add ip, lr, r0, lsl #1 // compute label = lr + element*2
bx ip // jump to computed label
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
+END_COMPILERRT_FUNCTION(__switchu8)
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync-ops.h b/contrib/compiler-rt/lib/builtins/arm/sync-ops.h
new file mode 100644
index 000000000000..ee02c30c6eaa
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync-ops.h
@@ -0,0 +1,64 @@
+/*===-- sync-ops.h - --===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements outline macros for the __sync_fetch_and_*
+ * operations. Different instantiations will generate appropriate assembly for
+ * ARM and Thumb-2 versions of the functions.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define SYNC_OP_4(op) \
+ .p2align 2 ; \
+ .thumb ; \
+ .syntax unified ; \
+ DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
+ dmb ; \
+ mov r12, r0 ; \
+ LOCAL_LABEL(tryatomic_ ## op): \
+ ldrex r0, [r12] ; \
+ op(r2, r0, r1) ; \
+ strex r3, r2, [r12] ; \
+ cmp r3, #0 ; \
+ bne LOCAL_LABEL(tryatomic_ ## op) ; \
+ dmb ; \
+ bx lr
+
+#define SYNC_OP_8(op) \
+ .p2align 2 ; \
+ .thumb ; \
+ .syntax unified ; \
+ DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
+ push {r4, r5, r6, lr} ; \
+ dmb ; \
+ mov r12, r0 ; \
+ LOCAL_LABEL(tryatomic_ ## op): \
+ ldrexd r0, r1, [r12] ; \
+ op(r4, r5, r0, r1, r2, r3) ; \
+ strexd r6, r4, r5, [r12] ; \
+ cmp r6, #0 ; \
+ bne LOCAL_LABEL(tryatomic_ ## op) ; \
+ dmb ; \
+ pop {r4, r5, r6, pc}
+
+#define MINMAX_4(rD, rN, rM, cmp_kind) \
+ cmp rN, rM ; \
+ mov rD, rM ; \
+ it cmp_kind ; \
+ mov##cmp_kind rD, rN
+
+#define MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, cmp_kind) \
+ cmp rN_LO, rM_LO ; \
+ sbcs rN_HI, rM_HI ; \
+ mov rD_LO, rM_LO ; \
+ mov rD_HI, rM_HI ; \
+ itt cmp_kind ; \
+ mov##cmp_kind rD_LO, rN_LO ; \
+ mov##cmp_kind rD_HI, rN_HI
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S
new file mode 100644
index 000000000000..54c33e2d26b7
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_add_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_add_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+/* "adds" is 2 bytes shorter than "add". */
+#define add_4(rD, rN, rM) add rD, rN, rM
+
+SYNC_OP_4(add_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S
new file mode 100644
index 000000000000..5724bb148ba7
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_add_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_add_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define add_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ adds rD_LO, rN_LO, rM_LO ; \
+ adc rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(add_8)
+#endif
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S
new file mode 100644
index 000000000000..e2b77a1a87d4
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S
@@ -0,0 +1,19 @@
+/*===-- sync_fetch_and_and_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_and_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define and_4(rD, rN, rM) and rD, rN, rM
+
+SYNC_OP_4(and_4)
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S
new file mode 100644
index 000000000000..a74163a8600b
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S
@@ -0,0 +1,23 @@
+/*===-- sync_fetch_and_and_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_and_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define and_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ and rD_LO, rN_LO, rM_LO ; \
+ and rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(and_8)
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S
new file mode 100644
index 000000000000..01e4f444c2f7
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_max_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_max_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define max_4(rD, rN, rM) MINMAX_4(rD, rN, rM, gt)
+
+SYNC_OP_4(max_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S
new file mode 100644
index 000000000000..1eef2b223668
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_max_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_max_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define max_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, gt)
+
+SYNC_OP_8(max_8)
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S
new file mode 100644
index 000000000000..015626b63da5
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_min_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_min_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define min_4(rD, rN, rM) MINMAX_4(rD, rN, rM, lt)
+
+SYNC_OP_4(min_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S
new file mode 100644
index 000000000000..ad5cce07544c
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_min_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_min_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define min_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lt)
+
+SYNC_OP_8(min_8)
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S
new file mode 100644
index 000000000000..b32a314b3974
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_nand_4.S - -----------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_nand_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define nand_4(rD, rN, rM) bic rD, rN, rM
+
+SYNC_OP_4(nand_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S
new file mode 100644
index 000000000000..a2c17c09c08f
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_nand_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_nand_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define nand_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ bic rD_LO, rN_LO, rM_LO ; \
+ bic rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(nand_8)
+#endif
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S
new file mode 100644
index 000000000000..f2e08576aaab
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_or_4.S - -------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_or_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define or_4(rD, rN, rM) orr rD, rN, rM
+
+SYNC_OP_4(or_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S
new file mode 100644
index 000000000000..87b940bf620d
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_or_8.S - -------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_or_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define or_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ orr rD_LO, rN_LO, rM_LO ; \
+ orr rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(or_8)
+#endif
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S
new file mode 100644
index 000000000000..460b2bc1ed62
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_sub_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_sub_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+/* "subs" is 2 bytes shorter than "sub". */
+#define sub_4(rD, rN, rM) sub rD, rN, rM
+
+SYNC_OP_4(sub_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S
new file mode 100644
index 000000000000..a8035a276853
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_sub_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_sub_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define sub_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ subs rD_LO, rN_LO, rM_LO ; \
+ sbc rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(sub_8)
+#endif
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S
new file mode 100644
index 000000000000..c59153031931
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_umax_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umax_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define umax_4(rD, rN, rM) MINMAX_4(rD, rN, rM, hi)
+
+SYNC_OP_4(umax_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S
new file mode 100644
index 000000000000..d9b7965e52ba
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_umax_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umax_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define umax_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, hi)
+
+SYNC_OP_8(umax_8)
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S
new file mode 100644
index 000000000000..9f3896fca80e
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_umin_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umin_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define umin_4(rD, rN, rM) MINMAX_4(rD, rN, rM, lo)
+
+SYNC_OP_4(umin_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S
new file mode 100644
index 000000000000..7bf5e235653c
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_umin_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umin_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define umin_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lo)
+
+SYNC_OP_8(umin_8)
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S
new file mode 100644
index 000000000000..7e7c90c96277
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_xor_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_xor_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define xor_4(rD, rN, rM) eor rD, rN, rM
+
+SYNC_OP_4(xor_4)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S
new file mode 100644
index 000000000000..ea9aa6d4b0e2
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_xor_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_xor_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define xor_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ eor rD_LO, rN_LO, rM_LO ; \
+ eor rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(xor_8)
+#endif
+
diff --git a/contrib/compiler-rt/lib/arm/sync_synchronize.S b/contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S
index 06dade964728..178f24534c71 100644
--- a/contrib/compiler-rt/lib/arm/sync_synchronize.S
+++ b/contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S
@@ -21,12 +21,13 @@
#if __APPLE__
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__sync_synchronize)
stmfd sp!, {r7, lr}
add r7, sp, #0
bl _OSMemoryBarrier
ldmfd sp!, {r7, pc}
+END_COMPILERRT_FUNCTION(__sync_synchronize)
// tell linker it can break up file at label boundaries
.subsections_via_symbols
diff --git a/contrib/compiler-rt/lib/arm/truncdfsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S
index 371aee94b16a..fa4362c45e77 100644
--- a/contrib/compiler-rt/lib/arm/truncdfsf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S
@@ -17,9 +17,10 @@
// passed in a R0/R1 pair and a signle precision result is returned in R0.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp)
vmov d7, r0, r1 // load double from r0/r1 pair
vcvt.f32.f64 s15, d7 // convert double to single (trucate precision)
vmov r0, s15 // return result in r0
bx lr
+END_COMPILERRT_FUNCTION(__truncdfsf2vfp)
diff --git a/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S b/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S
new file mode 100644
index 000000000000..85b84936c4b3
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S
@@ -0,0 +1,184 @@
+/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
+ * modulus) function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
+@ unsigned int *remainder)
+@ Calculate the quotient and remainder of the (unsigned) division. The return
+@ 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)
+ mov r3, r0
+ udiv r0, r3, r1
+ mls r1, r0, r1, r3
+ str r1, [r2]
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ beq LOCAL_LABEL(divby1)
+ cmp r0, r1
+ bcc LOCAL_LABEL(quotient0)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 12 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #2
+ sub ip, ip, r3, lsl #3
+ mov r3, #0
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ str r4, [sp, #-8]!
+
+ mov r4, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r4, #16
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(16 * 12)
+
+ lsr r3, r4, #8
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(8 * 12)
+
+ lsr r3, r4, #4
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, #(4 * 12)
+
+ lsr r3, r4, #2
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(2 * 12)
+
+ /* Last block, no need to update r3 or r4. */
+ cmp r1, r4, lsr #1
+ subls ip, ip, #(1 * 12)
+
+ ldr r4, [sp], #8 /* restore r4, we are done with it. */
+ mov r3, #0
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ ITT(hs); \
+ WIDE(addhs) r3, r3, IMM (1 << shift); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+
+ str r0, [r2]
+ mov r0, r3
+ JMP(lr)
+
+LOCAL_LABEL(quotient0):
+ str r0, [r2]
+ mov r0, #0
+ JMP(lr)
+
+LOCAL_LABEL(divby1):
+ mov r3, #0
+ str r3, [r2]
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__udivmodsi4)
diff --git a/contrib/compiler-rt/lib/builtins/arm/udivsi3.S b/contrib/compiler-rt/lib/builtins/arm/udivsi3.S
new file mode 100644
index 000000000000..165b2b58acb4
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/udivsi3.S
@@ -0,0 +1,170 @@
+/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __udivsi3 (32-bit unsigned integer divide)
+ * function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 2
+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)
+ udiv r0, r0, r1
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ IT(eq)
+ JMPc(lr, eq)
+ cmp r0, r1
+ ITT(cc)
+ movcc r0, #0
+ JMPc(lr, cc)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 12 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #2
+ sub ip, ip, r3, lsl #3
+ mov r3, #0
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ mov r2, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r2, #16
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(16 * 12)
+
+ lsr r3, r2, #8
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(8 * 12)
+
+ lsr r3, r2, #4
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, #(4 * 12)
+
+ lsr r3, r2, #2
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(2 * 12)
+
+ /* Last block, no need to update r2 or r3. */
+ cmp r1, r2, lsr #1
+ subls ip, ip, #(1 * 12)
+
+ mov r3, #0
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ ITT(hs); \
+ WIDE(addhs) r3, r3, IMM (1 << shift); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+
+ mov r0, r3
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__udivsi3)
diff --git a/contrib/compiler-rt/lib/builtins/arm/umodsi3.S b/contrib/compiler-rt/lib/builtins/arm/umodsi3.S
new file mode 100644
index 000000000000..9e7a148ce46f
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/umodsi3.S
@@ -0,0 +1,161 @@
+/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __umodsi3 (32-bit unsigned integer modulus)
+ * function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ 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)
+ udiv r2, r0, r1
+ mls r0, r2, r1, r0
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ ITT(eq)
+ moveq r0, #0
+ JMPc(lr, eq)
+ cmp r0, r1
+ IT(cc)
+ JMPc(lr, cc)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 8 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #3
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ mov r2, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r2, #16
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(16 * 8)
+
+ lsr r3, r2, #8
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(8 * 8)
+
+ lsr r3, r2, #4
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, #(4 * 8)
+
+ lsr r3, r2, #2
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(2 * 8)
+
+ /* Last block, no need to update r2 or r3. */
+ cmp r1, r2, lsr #1
+ subls ip, ip, #(1 * 8)
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ IT(hs); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__umodsi3)
diff --git a/contrib/compiler-rt/lib/arm/unorddf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S
index c49e55f29a4b..c4bea2d5eebd 100644
--- a/contrib/compiler-rt/lib/arm/unorddf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S
@@ -17,7 +17,7 @@
// like in GPR pairs.
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
@@ -26,3 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
movvc r0, #0
bx lr
+END_COMPILERRT_FUNCTION(__unorddf2vfp)
diff --git a/contrib/compiler-rt/lib/arm/unordsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S
index 0ab27edf51ad..886e96568103 100644
--- a/contrib/compiler-rt/lib/arm/unordsf2vfp.S
+++ b/contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S
@@ -17,7 +17,7 @@
// like 32-bit ints
//
.syntax unified
- .align 2
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
@@ -26,4 +26,4 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
movvc r0, #0
bx lr
-
+END_COMPILERRT_FUNCTION(__unordsf2vfp)
diff --git a/contrib/compiler-rt/lib/ashldi3.c b/contrib/compiler-rt/lib/builtins/ashldi3.c
index eb4698ac517c..eb4698ac517c 100644
--- a/contrib/compiler-rt/lib/ashldi3.c
+++ b/contrib/compiler-rt/lib/builtins/ashldi3.c
diff --git a/contrib/compiler-rt/lib/ashlti3.c b/contrib/compiler-rt/lib/builtins/ashlti3.c
index 08d2181d47d2..638ae845ff04 100644
--- a/contrib/compiler-rt/lib/ashlti3.c
+++ b/contrib/compiler-rt/lib/builtins/ashlti3.c
@@ -20,7 +20,7 @@
/* Precondition: 0 <= b < bits_in_tword */
-ti_int
+COMPILER_RT_ABI ti_int
__ashlti3(ti_int a, si_int b)
{
const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/ashrdi3.c b/contrib/compiler-rt/lib/builtins/ashrdi3.c
index 14c878bb7793..14c878bb7793 100644
--- a/contrib/compiler-rt/lib/ashrdi3.c
+++ b/contrib/compiler-rt/lib/builtins/ashrdi3.c
diff --git a/contrib/compiler-rt/lib/ashrti3.c b/contrib/compiler-rt/lib/builtins/ashrti3.c
index 6161bd599a11..f78205d961e4 100644
--- a/contrib/compiler-rt/lib/ashrti3.c
+++ b/contrib/compiler-rt/lib/builtins/ashrti3.c
@@ -20,7 +20,7 @@
/* Precondition: 0 <= b < bits_in_tword */
-ti_int
+COMPILER_RT_ABI ti_int
__ashrti3(ti_int a, si_int b)
{
const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/builtins/assembly.h b/contrib/compiler-rt/lib/builtins/assembly.h
new file mode 100644
index 000000000000..8bb0ddc106bd
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/assembly.h
@@ -0,0 +1,149 @@
+/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in compiler-rt assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef COMPILERRT_ASSEMBLY_H
+#define COMPILERRT_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN(name) .private_extern name
+#define LOCAL_LABEL(name) L_##name
+// tell linker it can break up file at label boundaries
+#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
+#define SYMBOL_IS_FUNC(name)
+#define CONST_SECTION .const
+
+#elif defined(__ELF__)
+
+#define HIDDEN(name) .hidden name
+#define LOCAL_LABEL(name) .L_##name
+#define FILE_LEVEL_DIRECTIVE
+#if defined(__arm__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#define CONST_SECTION .section .rodata
+
+#else // !__APPLE__ && !__ELF__
+
+#define HIDDEN(name)
+#define LOCAL_LABEL(name) .L ## name
+#define FILE_LEVEL_DIRECTIVE
+#define SYMBOL_IS_FUNC(name) \
+ .def name SEPARATOR \
+ .scl 2 SEPARATOR \
+ .type 32 SEPARATOR \
+ .endef
+#define CONST_SECTION .section .rdata,"rd"
+
+#endif
+
+#if defined(__arm__)
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && \
+ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
+#define __ARM_FEATURE_CLZ
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#define JMPc(r, c) bx##c r
+#else
+#define JMP(r) mov pc, r
+#define JMPc(r, c) mov##c pc, r
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#else
+#define IT(cond)
+#define ITT(cond)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#endif
+
+#define GLUE2(a, b) a##b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
+ .thumb_func SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ HIDDEN(name) SEPARATOR \
+ name:
+
+#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
+
+#if defined(__ARM_EABI__)
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
+ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
+#else
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
+#endif
+
+#ifdef __ELF__
+#define END_COMPILERRT_FUNCTION(name) \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#endif
+
+#endif /* COMPILERRT_ASSEMBLY_H */
diff --git a/contrib/compiler-rt/lib/atomic.c b/contrib/compiler-rt/lib/builtins/atomic.c
index a291f0d051d1..35c8837dcecf 100644
--- a/contrib/compiler-rt/lib/atomic.c
+++ b/contrib/compiler-rt/lib/builtins/atomic.c
@@ -28,12 +28,14 @@
#include <stdint.h>
#include <string.h>
+#include "assembly.h"
+
// Clang objects if you redefine a builtin. This little hack allows us to
// define a function with the same name as an intrinsic.
-#pragma redefine_extname __atomic_load_c __atomic_load
-#pragma redefine_extname __atomic_store_c __atomic_store
-#pragma redefine_extname __atomic_exchange_c __atomic_exchange
-#pragma redefine_extname __atomic_compare_exchange_c __atomic_compare_exchange
+#pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load)
+#pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store)
+#pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange)
+#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME(__atomic_compare_exchange)
/// Number of locks. This allocates one page on 32-bit platforms, two on
/// 64-bit. This can be specified externally if a different trade between
@@ -70,6 +72,20 @@ inline static void lock(Lock *l) {
}
/// locks for atomic operations
static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} };
+
+#elif defined(__APPLE__)
+#include <libkern/OSAtomic.h>
+typedef OSSpinLock Lock;
+inline static void unlock(Lock *l) {
+ OSSpinLockUnlock(l);
+}
+/// Locks a lock. In the current implementation, this is potentially
+/// unbounded in the contended case.
+inline static void lock(Lock *l) {
+ OSSpinLockLock(l);
+}
+static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0
+
#else
typedef _Atomic(uintptr_t) Lock;
/// Unlock a lock. This is a release operation.
diff --git a/contrib/compiler-rt/lib/builtins/clear_cache.c b/contrib/compiler-rt/lib/builtins/clear_cache.c
new file mode 100644
index 000000000000..18e18e942c46
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/clear_cache.c
@@ -0,0 +1,157 @@
+/* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include <stddef.h>
+
+#if __APPLE__
+ #include <libkern/OSCacheControl.h>
+#endif
+#if defined(__FreeBSD__) && defined(__arm__)
+ #include <sys/types.h>
+ #include <machine/sysarch.h>
+#endif
+
+#if defined(__NetBSD__) && defined(__arm__)
+ #include <machine/sysarch.h>
+#endif
+
+#if defined(__mips__) && !defined(__FreeBSD__)
+ #include <sys/cachectl.h>
+ #include <sys/syscall.h>
+ #if defined(__ANDROID__) && defined(__LP64__)
+ /*
+ * clear_mips_cache - Invalidates instruction cache for Mips.
+ */
+ static void clear_mips_cache(const void* Addr, size_t Size) {
+ asm volatile (
+ ".set push\n"
+ ".set noreorder\n"
+ ".set noat\n"
+ "beq %[Size], $zero, 20f\n" /* If size == 0, branch around. */
+ "nop\n"
+ "daddu %[Size], %[Addr], %[Size]\n" /* Calculate end address + 1 */
+ "rdhwr $v0, $1\n" /* Get step size for SYNCI.
+ $1 is $HW_SYNCI_Step */
+ "beq $v0, $zero, 20f\n" /* If no caches require
+ synchronization, branch
+ around. */
+ "nop\n"
+ "10:\n"
+ "synci 0(%[Addr])\n" /* Synchronize all caches around
+ address. */
+ "daddu %[Addr], %[Addr], $v0\n" /* Add step size. */
+ "sltu $at, %[Addr], %[Size]\n" /* Compare current with end
+ address. */
+ "bne $at, $zero, 10b\n" /* Branch if more to do. */
+ "nop\n"
+ "sync\n" /* Clear memory hazards. */
+ "20:\n"
+ "bal 30f\n"
+ "nop\n"
+ "30:\n"
+ "daddiu $ra, $ra, 12\n" /* $ra has a value of $pc here.
+ Add offset of 12 to point to the
+ instruction after the last nop.
+ */
+ "jr.hb $ra\n" /* Return, clearing instruction
+ hazards. */
+ "nop\n"
+ ".set pop\n"
+ : [Addr] "+r"(Addr), [Size] "+r"(Size)
+ :: "at", "ra", "v0", "memory"
+ );
+ }
+ #endif
+#endif
+
+#if defined(__ANDROID__) && defined(__arm__)
+ #include <asm/unistd.h>
+#endif
+
+/*
+ * The compiler generates calls to __clear_cache() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * It is expected to invalidate the instruction cache for the
+ * specified range.
+ */
+
+void __clear_cache(void *start, void *end) {
+#if __i386__ || __x86_64__
+/*
+ * Intel processors have a unified instruction and data cache
+ * so there is nothing to do
+ */
+#elif defined(__arm__) && !defined(__APPLE__)
+ #if defined(__FreeBSD__) || defined(__NetBSD__)
+ struct arm_sync_icache_args arg;
+
+ arg.addr = (uintptr_t)start;
+ arg.len = (uintptr_t)end - (uintptr_t)start;
+
+ sysarch(ARM_SYNC_ICACHE, &arg);
+ #elif defined(__ANDROID__)
+ register int start_reg __asm("r0") = (int) (intptr_t) start;
+ const register int end_reg __asm("r1") = (int) (intptr_t) end;
+ const register int flags __asm("r2") = 0;
+ const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush;
+ __asm __volatile("svc 0x0" : "=r"(start_reg)
+ : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags) : "r0");
+ if (start_reg != 0) {
+ compilerrt_abort();
+ }
+ #else
+ compilerrt_abort();
+ #endif
+#elif defined(__mips__) && !defined(__FreeBSD__)
+ const uintptr_t start_int = (uintptr_t) start;
+ const uintptr_t end_int = (uintptr_t) end;
+ #if defined(__ANDROID__) && defined(__LP64__)
+ // Call synci implementation for short address range.
+ const uintptr_t address_range_limit = 256;
+ if ((end_int - start_int) <= address_range_limit) {
+ clear_mips_cache(start, (end_int - start_int));
+ } else {
+ syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);
+ }
+ #else
+ syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);
+ #endif
+#elif defined(__aarch64__) && !defined(__APPLE__)
+ uint64_t xstart = (uint64_t)(uintptr_t) start;
+ uint64_t xend = (uint64_t)(uintptr_t) end;
+
+ // Get Cache Type Info
+ uint64_t ctr_el0;
+ __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
+
+ /*
+ * dc & ic instructions must use 64bit registers so we don't use
+ * uintptr_t in case this runs in an IPL32 environment.
+ */
+ const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
+ for (uint64_t addr = xstart; addr < xend; addr += dcache_line_size)
+ __asm __volatile("dc cvau, %0" :: "r"(addr));
+ __asm __volatile("dsb ish");
+
+ const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
+ for (uint64_t addr = xstart; addr < xend; addr += icache_line_size)
+ __asm __volatile("ic ivau, %0" :: "r"(addr));
+ __asm __volatile("isb sy");
+#else
+ #if __APPLE__
+ /* On Darwin, sys_icache_invalidate() provides this functionality */
+ sys_icache_invalidate(start, end-start);
+ #else
+ compilerrt_abort();
+ #endif
+#endif
+}
+
diff --git a/contrib/compiler-rt/lib/clzdi2.c b/contrib/compiler-rt/lib/builtins/clzdi2.c
index b9e64da492bd..b9e64da492bd 100644
--- a/contrib/compiler-rt/lib/clzdi2.c
+++ b/contrib/compiler-rt/lib/builtins/clzdi2.c
diff --git a/contrib/compiler-rt/lib/clzsi2.c b/contrib/compiler-rt/lib/builtins/clzsi2.c
index 25b8ed2c4c24..25b8ed2c4c24 100644
--- a/contrib/compiler-rt/lib/clzsi2.c
+++ b/contrib/compiler-rt/lib/builtins/clzsi2.c
diff --git a/contrib/compiler-rt/lib/clzti2.c b/contrib/compiler-rt/lib/builtins/clzti2.c
index d478db84dbec..15a7b3c90004 100644
--- a/contrib/compiler-rt/lib/clzti2.c
+++ b/contrib/compiler-rt/lib/builtins/clzti2.c
@@ -20,7 +20,7 @@
/* Precondition: a != 0 */
-si_int
+COMPILER_RT_ABI si_int
__clzti2(ti_int a)
{
twords x;
diff --git a/contrib/compiler-rt/lib/cmpdi2.c b/contrib/compiler-rt/lib/builtins/cmpdi2.c
index 52634d9c3362..52634d9c3362 100644
--- a/contrib/compiler-rt/lib/cmpdi2.c
+++ b/contrib/compiler-rt/lib/builtins/cmpdi2.c
diff --git a/contrib/compiler-rt/lib/cmpti2.c b/contrib/compiler-rt/lib/builtins/cmpti2.c
index d287fab82f35..2c8b56e29a06 100644
--- a/contrib/compiler-rt/lib/cmpti2.c
+++ b/contrib/compiler-rt/lib/builtins/cmpti2.c
@@ -21,7 +21,7 @@
* if (a > b) returns 2
*/
-si_int
+COMPILER_RT_ABI si_int
__cmpti2(ti_int a, ti_int b)
{
twords x;
diff --git a/contrib/compiler-rt/lib/comparedf2.c b/contrib/compiler-rt/lib/builtins/comparedf2.c
index fe35fd80aadd..64eea1249055 100644
--- a/contrib/compiler-rt/lib/comparedf2.c
+++ b/contrib/compiler-rt/lib/builtins/comparedf2.c
@@ -47,7 +47,8 @@ enum LE_RESULT {
LE_UNORDERED = 1
};
-enum LE_RESULT __ledf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__ledf2(fp_t a, fp_t b) {
const srep_t aInt = toRep(a);
const srep_t bInt = toRep(b);
@@ -86,7 +87,8 @@ enum GE_RESULT {
GE_UNORDERED = -1 // Note: different from LE_UNORDERED
};
-enum GE_RESULT __gedf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum GE_RESULT
+__gedf2(fp_t a, fp_t b) {
const srep_t aInt = toRep(a);
const srep_t bInt = toRep(b);
@@ -106,27 +108,34 @@ enum GE_RESULT __gedf2(fp_t a, fp_t b) {
}
}
-int __unorddf2(fp_t a, fp_t b) {
+ARM_EABI_FNALIAS(dcmpun, unorddf2)
+
+COMPILER_RT_ABI int
+__unorddf2(fp_t a, fp_t b) {
const rep_t aAbs = toRep(a) & absMask;
const rep_t bAbs = toRep(b) & absMask;
return aAbs > infRep || bAbs > infRep;
}
-// The following are alternative names for the preceeding routines.
+// The following are alternative names for the preceding routines.
-enum LE_RESULT __eqdf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__eqdf2(fp_t a, fp_t b) {
return __ledf2(a, b);
}
-enum LE_RESULT __ltdf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__ltdf2(fp_t a, fp_t b) {
return __ledf2(a, b);
}
-enum LE_RESULT __nedf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__nedf2(fp_t a, fp_t b) {
return __ledf2(a, b);
}
-enum GE_RESULT __gtdf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum GE_RESULT
+__gtdf2(fp_t a, fp_t b) {
return __gedf2(a, b);
}
diff --git a/contrib/compiler-rt/lib/comparesf2.c b/contrib/compiler-rt/lib/builtins/comparesf2.c
index 3f2e358addb5..442289c1004e 100644
--- a/contrib/compiler-rt/lib/comparesf2.c
+++ b/contrib/compiler-rt/lib/builtins/comparesf2.c
@@ -47,7 +47,8 @@ enum LE_RESULT {
LE_UNORDERED = 1
};
-enum LE_RESULT __lesf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__lesf2(fp_t a, fp_t b) {
const srep_t aInt = toRep(a);
const srep_t bInt = toRep(b);
@@ -86,7 +87,8 @@ enum GE_RESULT {
GE_UNORDERED = -1 // Note: different from LE_UNORDERED
};
-enum GE_RESULT __gesf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum GE_RESULT
+__gesf2(fp_t a, fp_t b) {
const srep_t aInt = toRep(a);
const srep_t bInt = toRep(b);
@@ -106,26 +108,33 @@ enum GE_RESULT __gesf2(fp_t a, fp_t b) {
}
}
-int __unordsf2(fp_t a, fp_t b) {
+ARM_EABI_FNALIAS(fcmpun, unordsf2)
+
+COMPILER_RT_ABI int
+__unordsf2(fp_t a, fp_t b) {
const rep_t aAbs = toRep(a) & absMask;
const rep_t bAbs = toRep(b) & absMask;
return aAbs > infRep || bAbs > infRep;
}
-// The following are alternative names for the preceeding routines.
+// The following are alternative names for the preceding routines.
-enum LE_RESULT __eqsf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__eqsf2(fp_t a, fp_t b) {
return __lesf2(a, b);
}
-enum LE_RESULT __ltsf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__ltsf2(fp_t a, fp_t b) {
return __lesf2(a, b);
}
-enum LE_RESULT __nesf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum LE_RESULT
+__nesf2(fp_t a, fp_t b) {
return __lesf2(a, b);
}
-enum GE_RESULT __gtsf2(fp_t a, fp_t b) {
+COMPILER_RT_ABI enum GE_RESULT
+__gtsf2(fp_t a, fp_t b) {
return __gesf2(a, b);
}
diff --git a/contrib/compiler-rt/lib/builtins/comparetf2.c b/contrib/compiler-rt/lib/builtins/comparetf2.c
new file mode 100644
index 000000000000..a6436de89e76
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/comparetf2.c
@@ -0,0 +1,133 @@
+//===-- lib/comparetf2.c - Quad-precision comparisons -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// // This file implements the following soft-float comparison routines:
+//
+// __eqtf2 __getf2 __unordtf2
+// __letf2 __gttf2
+// __lttf2
+// __netf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __letf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __getf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordtf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __letf2( ) and __getf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a floating-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+ else {
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT __getf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+COMPILER_RT_ABI int __unordtf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT __eqtf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT __lttf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT __netf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT __gttf2(fp_t a, fp_t b) {
+ return __getf2(a, b);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/ctzdi2.c b/contrib/compiler-rt/lib/builtins/ctzdi2.c
index db3c6fdc08f1..db3c6fdc08f1 100644
--- a/contrib/compiler-rt/lib/ctzdi2.c
+++ b/contrib/compiler-rt/lib/builtins/ctzdi2.c
diff --git a/contrib/compiler-rt/lib/ctzsi2.c b/contrib/compiler-rt/lib/builtins/ctzsi2.c
index c69486ea445f..c69486ea445f 100644
--- a/contrib/compiler-rt/lib/ctzsi2.c
+++ b/contrib/compiler-rt/lib/builtins/ctzsi2.c
diff --git a/contrib/compiler-rt/lib/ctzti2.c b/contrib/compiler-rt/lib/builtins/ctzti2.c
index 43a8797a1cf7..45de682700cc 100644
--- a/contrib/compiler-rt/lib/ctzti2.c
+++ b/contrib/compiler-rt/lib/builtins/ctzti2.c
@@ -20,7 +20,7 @@
/* Precondition: a != 0 */
-si_int
+COMPILER_RT_ABI si_int
__ctzti2(ti_int a)
{
twords x;
diff --git a/contrib/compiler-rt/lib/divdc3.c b/contrib/compiler-rt/lib/builtins/divdc3.c
index cfbc498e7b44..7de78c8711e1 100644
--- a/contrib/compiler-rt/lib/divdc3.c
+++ b/contrib/compiler-rt/lib/builtins/divdc3.c
@@ -17,7 +17,7 @@
/* Returns: the quotient of (a + ib) / (c + id) */
-double _Complex
+COMPILER_RT_ABI double _Complex
__divdc3(double __a, double __b, double __c, double __d)
{
int __ilogbw = 0;
diff --git a/contrib/compiler-rt/lib/divdf3.c b/contrib/compiler-rt/lib/builtins/divdf3.c
index efce6bb4bedc..ab44c2b25fe5 100644
--- a/contrib/compiler-rt/lib/divdf3.c
+++ b/contrib/compiler-rt/lib/builtins/divdf3.c
@@ -21,7 +21,8 @@
ARM_EABI_FNALIAS(ddiv, divdf3)
-fp_t __divdf3(fp_t a, fp_t b) {
+COMPILER_RT_ABI fp_t
+__divdf3(fp_t a, fp_t b) {
const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
@@ -97,7 +98,7 @@ fp_t __divdf3(fp_t a, fp_t b) {
correction32 = -((uint64_t)recip32 * q31b >> 32);
recip32 = (uint64_t)recip32 * correction32 >> 31;
- // recip32 might have overflowed to exactly zero in the preceeding
+ // recip32 might have overflowed to exactly zero in the preceding
// computation if the high word of b is exactly 1.0. This would sabotage
// the full-width final stage of the computation that follows, so we adjust
// recip32 downward by one bit.
diff --git a/contrib/compiler-rt/lib/divdi3.c b/contrib/compiler-rt/lib/builtins/divdi3.c
index 2c2bcc26d581..b8eebcb20465 100644
--- a/contrib/compiler-rt/lib/divdi3.c
+++ b/contrib/compiler-rt/lib/builtins/divdi3.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem);
-
/* Returns: a / b */
COMPILER_RT_ABI di_int
diff --git a/contrib/compiler-rt/lib/divmoddi4.c b/contrib/compiler-rt/lib/builtins/divmoddi4.c
index 2fe2b48183ff..0d4df67a63e0 100644
--- a/contrib/compiler-rt/lib/divmoddi4.c
+++ b/contrib/compiler-rt/lib/builtins/divmoddi4.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-extern COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
-
/* Returns: a / b, *rem = a % b */
COMPILER_RT_ABI di_int
diff --git a/contrib/compiler-rt/lib/divmodsi4.c b/contrib/compiler-rt/lib/builtins/divmodsi4.c
index c7f7b1a7c322..dabe2874397c 100644
--- a/contrib/compiler-rt/lib/divmodsi4.c
+++ b/contrib/compiler-rt/lib/builtins/divmodsi4.c
@@ -14,9 +14,6 @@
#include "int_lib.h"
-extern COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
-
-
/* Returns: a / b, *rem = a % b */
COMPILER_RT_ABI si_int
diff --git a/contrib/compiler-rt/lib/divsc3.c b/contrib/compiler-rt/lib/builtins/divsc3.c
index caa0c4075eb3..710d5320803f 100644
--- a/contrib/compiler-rt/lib/divsc3.c
+++ b/contrib/compiler-rt/lib/builtins/divsc3.c
@@ -17,7 +17,7 @@
/* Returns: the quotient of (a + ib) / (c + id) */
-float _Complex
+COMPILER_RT_ABI float _Complex
__divsc3(float __a, float __b, float __c, float __d)
{
int __ilogbw = 0;
diff --git a/contrib/compiler-rt/lib/divsf3.c b/contrib/compiler-rt/lib/builtins/divsf3.c
index c91c648fa24c..de2e376125b6 100644
--- a/contrib/compiler-rt/lib/divsf3.c
+++ b/contrib/compiler-rt/lib/builtins/divsf3.c
@@ -21,7 +21,8 @@
ARM_EABI_FNALIAS(fdiv, divsf3)
-fp_t __divsf3(fp_t a, fp_t b) {
+COMPILER_RT_ABI fp_t
+__divsf3(fp_t a, fp_t b) {
const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
diff --git a/contrib/compiler-rt/lib/divsi3.c b/contrib/compiler-rt/lib/builtins/divsi3.c
index cd19de9525c0..bab4aefda30a 100644
--- a/contrib/compiler-rt/lib/divsi3.c
+++ b/contrib/compiler-rt/lib/builtins/divsi3.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-su_int COMPILER_RT_ABI __udivsi3(su_int n, su_int d);
-
/* Returns: a / b */
ARM_EABI_FNALIAS(idiv, divsi3)
diff --git a/contrib/compiler-rt/lib/builtins/divtf3.c b/contrib/compiler-rt/lib/builtins/divtf3.c
new file mode 100644
index 000000000000..e81dab826bdd
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/divtf3.c
@@ -0,0 +1,203 @@
+//===-- lib/divtf3.c - Quad-precision division --------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q63 fixed-point number in the range
+ // [1, 2.0) and get a Q64 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ const uint64_t q63b = bSignificand >> 49;
+ uint64_t recip64 = UINT64_C(0x7504f333F9DE6484) - q63b;
+ // 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2)
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration.
+ uint64_t correction64;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+
+ // recip64 might have overflowed to exactly zero in the preceeding
+ // computation if the high word of b is exactly 1.0. This would sabotage
+ // the full-width final stage of the computation that follows, so we adjust
+ // recip64 downward by one bit.
+ recip64--;
+
+ // We need to perform one more iteration to get us to 112 binary digits;
+ // The last iteration needs to happen with extra precision.
+ const uint64_t q127blo = bSignificand << 15;
+ rep_t correction, reciprocal;
+
+ // NOTE: This operation is equivalent to __multi3, which is not implemented
+ // in some architechure
+ rep_t r64q63, r64q127, r64cH, r64cL, dummy;
+ wideMultiply((rep_t)recip64, (rep_t)q63b, &dummy, &r64q63);
+ wideMultiply((rep_t)recip64, (rep_t)q127blo, &dummy, &r64q127);
+
+ correction = -(r64q63 + (r64q127 >> 64));
+
+ uint64_t cHi = correction >> 64;
+ uint64_t cLo = correction;
+
+ wideMultiply((rep_t)recip64, (rep_t)cHi, &dummy, &r64cH);
+ wideMultiply((rep_t)recip64, (rep_t)cLo, &dummy, &r64cL);
+
+ reciprocal = r64cH + (r64cL >> 64);
+
+ // We already adjusted the 64-bit estimate, now we need to adjust the final
+ // 128-bit reciprocal estimate downward to ensure that it is strictly smaller
+ // than the infinitely precise exact reciprocal. Because the computation
+ // of the Newton-Raphson step is truncating at every step, this adjustment
+ // is small; most of the work is already done.
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-112, lies in the
+ // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
+ // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
+ // in Q127 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0.5, 2.0)
+ // 3. the error in q is bounded away from 2^-113 (actually, we have a
+ // couple of bits to spare, but this is all we need).
+
+ // We need a 128 x 128 multiply high to compute q, which isn't a basic
+ // operation in C, so we need to be a little bit fussy.
+ rep_t quotient, quotientLo;
+ wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ rep_t qb;
+
+ if (quotient < (implicitBit << 1)) {
+ wideMultiply(quotient, bSignificand, &dummy, &qb);
+ residual = (aSignificand << 113) - qb;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ wideMultiply(quotient, bSignificand, &dummy, &qb);
+ residual = (aSignificand << 112) - qb;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+ else {
+ const bool round = (residual << 1) >= bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ const long double result = fromRep(absResult | quotientSign);
+ return result;
+ }
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/divti3.c b/contrib/compiler-rt/lib/builtins/divti3.c
index ad365ab40a23..c73eae28fe08 100644
--- a/contrib/compiler-rt/lib/divti3.c
+++ b/contrib/compiler-rt/lib/builtins/divti3.c
@@ -16,11 +16,9 @@
#ifdef CRT_HAS_128BIT
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
/* Returns: a / b */
-ti_int
+COMPILER_RT_ABI ti_int
__divti3(ti_int a, ti_int b)
{
const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
diff --git a/contrib/compiler-rt/lib/divxc3.c b/contrib/compiler-rt/lib/builtins/divxc3.c
index 5f240e956d84..175ae3cf4aee 100644
--- a/contrib/compiler-rt/lib/divxc3.c
+++ b/contrib/compiler-rt/lib/builtins/divxc3.c
@@ -18,7 +18,7 @@
/* Returns: the quotient of (a + ib) / (c + id) */
-long double _Complex
+COMPILER_RT_ABI long double _Complex
__divxc3(long double __a, long double __b, long double __c, long double __d)
{
int __ilogbw = 0;
diff --git a/contrib/compiler-rt/lib/enable_execute_stack.c b/contrib/compiler-rt/lib/builtins/enable_execute_stack.c
index 278ca246f537..63d836b31d17 100644
--- a/contrib/compiler-rt/lib/enable_execute_stack.c
+++ b/contrib/compiler-rt/lib/builtins/enable_execute_stack.c
@@ -36,7 +36,8 @@
* that means changing the protection on those page(s) to rwx.
*/
-void __enable_execute_stack(void* addr)
+COMPILER_RT_ABI void
+__enable_execute_stack(void* addr)
{
#if __APPLE__
@@ -55,5 +56,3 @@ void __enable_execute_stack(void* addr)
size_t length = endPage - startPage;
(void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC);
}
-
-
diff --git a/contrib/compiler-rt/lib/eprintf.c b/contrib/compiler-rt/lib/builtins/eprintf.c
index b07d624b50f9..89f34b154577 100644
--- a/contrib/compiler-rt/lib/eprintf.c
+++ b/contrib/compiler-rt/lib/builtins/eprintf.c
@@ -22,9 +22,12 @@
* It should never be exported from a dylib, so it is marked
* visibility hidden.
*/
+#ifndef _WIN32
__attribute__((visibility("hidden")))
-void __eprintf(const char* format, const char* assertion_expression,
- const char* line, const char* file)
+#endif
+COMPILER_RT_ABI void
+__eprintf(const char* format, const char* assertion_expression,
+ const char* line, const char* file)
{
fprintf(stderr, format, assertion_expression, line, file);
fflush(stderr);
diff --git a/contrib/compiler-rt/lib/builtins/extenddftf2.c b/contrib/compiler-rt/lib/builtins/extenddftf2.c
new file mode 100644
index 000000000000..86dab8f03a8f
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/extenddftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extenddftf2.c - double -> quad conversion -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_DOUBLE
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extenddftf2(double a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/extendsfdf2.c b/contrib/compiler-rt/lib/builtins/extendsfdf2.c
new file mode 100644
index 000000000000..7a267c2f47ad
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/extendsfdf2.c
@@ -0,0 +1,19 @@
+//===-- lib/extendsfdf2.c - single -> double conversion -----------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define SRC_SINGLE
+#define DST_DOUBLE
+#include "fp_extend_impl.inc"
+
+ARM_EABI_FNALIAS(f2d, extendsfdf2)
+
+COMPILER_RT_ABI double __extendsfdf2(float a) {
+ return __extendXfYf2__(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/extendsftf2.c b/contrib/compiler-rt/lib/builtins/extendsftf2.c
new file mode 100644
index 000000000000..2eeeba284845
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/extendsftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extendsftf2.c - single -> quad conversion -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_SINGLE
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extendsftf2(float a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/ffsdi2.c b/contrib/compiler-rt/lib/builtins/ffsdi2.c
index a5ac9900ff10..a5ac9900ff10 100644
--- a/contrib/compiler-rt/lib/ffsdi2.c
+++ b/contrib/compiler-rt/lib/builtins/ffsdi2.c
diff --git a/contrib/compiler-rt/lib/ffsti2.c b/contrib/compiler-rt/lib/builtins/ffsti2.c
index e64266d35169..dcdb3bd7f807 100644
--- a/contrib/compiler-rt/lib/ffsti2.c
+++ b/contrib/compiler-rt/lib/builtins/ffsti2.c
@@ -20,7 +20,7 @@
* the value zero if a is zero. The least significant bit is index one.
*/
-si_int
+COMPILER_RT_ABI si_int
__ffsti2(ti_int a)
{
twords x;
diff --git a/contrib/compiler-rt/lib/builtins/fixdfdi.c b/contrib/compiler-rt/lib/builtins/fixdfdi.c
new file mode 100644
index 000000000000..67b124a16bbc
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixdfdi.c
@@ -0,0 +1,22 @@
+/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+ARM_EABI_FNALIAS(d2lz, fixdfdi)
+
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixdfdi(fp_t a) {
+ return __fixint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixdfsi.c b/contrib/compiler-rt/lib/builtins/fixdfsi.c
new file mode 100644
index 000000000000..704e65bc43a1
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixdfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixdfsi.c - Implement __fixdfsi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+ARM_EABI_FNALIAS(d2iz, fixdfsi)
+
+COMPILER_RT_ABI si_int
+__fixdfsi(fp_t a) {
+ return __fixint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixdfti.c b/contrib/compiler-rt/lib/builtins/fixdfti.c
new file mode 100644
index 000000000000..aaf225e74f86
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixdfti.c
@@ -0,0 +1,26 @@
+/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixdfti(fp_t a) {
+ return __fixint(a);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/builtins/fixsfdi.c b/contrib/compiler-rt/lib/builtins/fixsfdi.c
new file mode 100644
index 000000000000..835ff852d3e9
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixsfdi.c
@@ -0,0 +1,23 @@
+/* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(f2lz, fixsfdi)
+
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixsfdi(fp_t a) {
+ return __fixint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixsfsi.c b/contrib/compiler-rt/lib/builtins/fixsfsi.c
new file mode 100644
index 000000000000..f045536d6857
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixsfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+ARM_EABI_FNALIAS(f2iz, fixsfsi)
+
+COMPILER_RT_ABI si_int
+__fixsfsi(fp_t a) {
+ return __fixint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixsfti.c b/contrib/compiler-rt/lib/builtins/fixsfti.c
new file mode 100644
index 000000000000..3a159b3e18e4
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixsfti.c
@@ -0,0 +1,26 @@
+/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixsfti(fp_t a) {
+ return __fixint(a);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/builtins/fixtfdi.c b/contrib/compiler-rt/lib/builtins/fixtfdi.c
new file mode 100644
index 000000000000..bc9dea1f4f81
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixtfdi.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfdi.c - Implement __fixtfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixtfdi(fp_t a) {
+ return __fixint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/fixtfsi.c b/contrib/compiler-rt/lib/builtins/fixtfsi.c
new file mode 100644
index 000000000000..feb3de885090
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixtfsi.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfsi.c - Implement __fixtfsi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI si_int
+__fixtfsi(fp_t a) {
+ return __fixint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/fixtfti.c b/contrib/compiler-rt/lib/builtins/fixtfti.c
new file mode 100644
index 000000000000..ee4ada85cb4a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixtfti.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfti.c - Implement __fixtfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixtfti(fp_t a) {
+ return __fixint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/fixunsdfdi.c b/contrib/compiler-rt/lib/builtins/fixunsdfdi.c
new file mode 100644
index 000000000000..f4f689e3993f
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunsdfdi.c
@@ -0,0 +1,21 @@
+/* ===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
+
+COMPILER_RT_ABI du_int
+__fixunsdfdi(fp_t a) {
+ return __fixuint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixunsdfsi.c b/contrib/compiler-rt/lib/builtins/fixunsdfsi.c
new file mode 100644
index 000000000000..232d342d77da
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunsdfsi.c
@@ -0,0 +1,21 @@
+/* ===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+ARM_EABI_FNALIAS(d2uiz, fixunsdfsi)
+
+COMPILER_RT_ABI su_int
+__fixunsdfsi(fp_t a) {
+ return __fixuint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixunsdfti.c b/contrib/compiler-rt/lib/builtins/fixunsdfti.c
new file mode 100644
index 000000000000..c3d7df97fbd8
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunsdfti.c
@@ -0,0 +1,23 @@
+/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunsdftti(fp_t a) {
+ return __fixuint(a);
+}
+#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/builtins/fixunssfdi.c b/contrib/compiler-rt/lib/builtins/fixunssfdi.c
new file mode 100644
index 000000000000..cd21cfd1859b
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunssfdi.c
@@ -0,0 +1,21 @@
+/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
+
+COMPILER_RT_ABI du_int
+__fixunssfdi(fp_t a) {
+ return __fixuint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixunssfsi.c b/contrib/compiler-rt/lib/builtins/fixunssfsi.c
new file mode 100644
index 000000000000..cc2b05bd84f8
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunssfsi.c
@@ -0,0 +1,25 @@
+/* ===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunssfsi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+ARM_EABI_FNALIAS(f2uiz, fixunssfsi)
+
+COMPILER_RT_ABI su_int
+__fixunssfsi(fp_t a) {
+ return __fixuint(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fixunssfti.c b/contrib/compiler-rt/lib/builtins/fixunssfti.c
new file mode 100644
index 000000000000..862d7bd6c7af
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunssfti.c
@@ -0,0 +1,26 @@
+/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunssfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunssfti(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/fixunstfdi.c b/contrib/compiler-rt/lib/builtins/fixunstfdi.c
new file mode 100644
index 000000000000..b2995f65834a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunstfdi.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI du_int
+__fixunstfdi(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/fixunstfsi.c b/contrib/compiler-rt/lib/builtins/fixunstfsi.c
new file mode 100644
index 000000000000..b5d3f6a7d38d
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunstfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI su_int
+__fixunstfsi(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/fixunstfti.c b/contrib/compiler-rt/lib/builtins/fixunstfti.c
new file mode 100644
index 000000000000..22ff9dfc0339
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fixunstfti.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunstfti(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/fixunsxfdi.c b/contrib/compiler-rt/lib/builtins/fixunsxfdi.c
index 6c817d8e1289..075304e78dc9 100644
--- a/contrib/compiler-rt/lib/fixunsxfdi.c
+++ b/contrib/compiler-rt/lib/builtins/fixunsxfdi.c
@@ -30,7 +30,7 @@
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-du_int
+COMPILER_RT_ABI du_int
__fixunsxfdi(long double a)
{
long_double_bits fb;
@@ -38,6 +38,8 @@ __fixunsxfdi(long double a)
int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
if (e < 0 || (fb.u.high.s.low & 0x00008000))
return 0;
+ if ((unsigned)e > sizeof(du_int) * CHAR_BIT)
+ return ~(du_int)0;
return fb.u.low.all >> (63 - e);
}
diff --git a/contrib/compiler-rt/lib/fixunsxfsi.c b/contrib/compiler-rt/lib/builtins/fixunsxfsi.c
index b9da86c4f8ea..c3c70f743de8 100644
--- a/contrib/compiler-rt/lib/fixunsxfsi.c
+++ b/contrib/compiler-rt/lib/builtins/fixunsxfsi.c
@@ -23,14 +23,13 @@
/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
* su_int is a 32 bit integral type
* value in long double is representable in su_int or is negative
- * (no range checking performed)
*/
/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-su_int
+COMPILER_RT_ABI su_int
__fixunsxfsi(long double a)
{
long_double_bits fb;
@@ -38,6 +37,8 @@ __fixunsxfsi(long double a)
int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
if (e < 0 || (fb.u.high.s.low & 0x00008000))
return 0;
+ if ((unsigned)e > sizeof(su_int) * CHAR_BIT)
+ return ~(su_int)0;
return fb.u.low.s.high >> (31 - e);
}
diff --git a/contrib/compiler-rt/lib/fixunsxfti.c b/contrib/compiler-rt/lib/builtins/fixunsxfti.c
index db3c0706faa0..fb39d00ff5b2 100644
--- a/contrib/compiler-rt/lib/fixunsxfti.c
+++ b/contrib/compiler-rt/lib/builtins/fixunsxfti.c
@@ -21,16 +21,15 @@
*/
/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * tu_int is a 64 bit integral type
+ * tu_int is a 128 bit integral type
* value in long double is representable in tu_int or is negative
- * (no range checking performed)
*/
/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-tu_int
+COMPILER_RT_ABI tu_int
__fixunsxfti(long double a)
{
long_double_bits fb;
@@ -38,6 +37,8 @@ __fixunsxfti(long double a)
int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
if (e < 0 || (fb.u.high.s.low & 0x00008000))
return 0;
+ if ((unsigned)e > sizeof(tu_int) * CHAR_BIT)
+ return ~(tu_int)0;
tu_int r = fb.u.low.all;
if (e > 63)
r <<= (e - 63);
diff --git a/contrib/compiler-rt/lib/fixxfdi.c b/contrib/compiler-rt/lib/builtins/fixxfdi.c
index 9592ce43025b..011787f9e4b4 100644
--- a/contrib/compiler-rt/lib/fixxfdi.c
+++ b/contrib/compiler-rt/lib/builtins/fixxfdi.c
@@ -19,7 +19,7 @@
/* Returns: convert a to a signed long long, rounding toward zero. */
/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * su_int is a 32 bit integral type
+ * di_int is a 64 bit integral type
* value in long double is representable in di_int (no range checking performed)
*/
@@ -27,14 +27,18 @@
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-di_int
+COMPILER_RT_ABI di_int
__fixxfdi(long double a)
{
+ const di_int di_max = (di_int)((~(du_int)0) / 2);
+ const di_int di_min = -di_max - 1;
long_double_bits fb;
fb.f = a;
int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
if (e < 0)
return 0;
+ if ((unsigned)e >= sizeof(di_int) * CHAR_BIT)
+ return a > 0 ? di_max : di_min;
di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
di_int r = fb.u.low.all;
r = (du_int)r >> (63 - e);
diff --git a/contrib/compiler-rt/lib/fixxfti.c b/contrib/compiler-rt/lib/builtins/fixxfti.c
index ca3082e87f0f..968a4f0d5eea 100644
--- a/contrib/compiler-rt/lib/fixxfti.c
+++ b/contrib/compiler-rt/lib/builtins/fixxfti.c
@@ -19,17 +19,19 @@
/* Returns: convert a to a signed long long, rounding toward zero. */
/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * su_int is a 32 bit integral type
- * value in long double is representable in ti_int (no range checking performed)
+ * ti_int is a 128 bit integral type
+ * value in long double is representable in ti_int
*/
/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-ti_int
+COMPILER_RT_ABI ti_int
__fixxfti(long double a)
{
+ const ti_int ti_max = (ti_int)((~(tu_int)0) / 2);
+ const ti_int ti_min = -ti_max - 1;
long_double_bits fb;
fb.f = a;
int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
@@ -37,6 +39,8 @@ __fixxfti(long double a)
return 0;
ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
ti_int r = fb.u.low.all;
+ if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT)
+ return a > 0 ? ti_max : ti_min;
if (e > 63)
r <<= (e - 63);
else
diff --git a/contrib/compiler-rt/lib/floatdidf.c b/contrib/compiler-rt/lib/builtins/floatdidf.c
index e53fa2580f6e..e53fa2580f6e 100644
--- a/contrib/compiler-rt/lib/floatdidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatdidf.c
diff --git a/contrib/compiler-rt/lib/floatdisf.c b/contrib/compiler-rt/lib/builtins/floatdisf.c
index 3e47580ef576..3e47580ef576 100644
--- a/contrib/compiler-rt/lib/floatdisf.c
+++ b/contrib/compiler-rt/lib/builtins/floatdisf.c
diff --git a/contrib/compiler-rt/lib/builtins/floatditf.c b/contrib/compiler-rt/lib/builtins/floatditf.c
new file mode 100644
index 000000000000..01261c68db98
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/floatditf.c
@@ -0,0 +1,52 @@
+//===-- lib/floatditf.c - integer -> quad-precision conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements di_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatditf(di_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ unsigned aAbs = (unsigned)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs += 0x80000000;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit. Extra
+ // cast to unsigned int is necessary to get the correct behavior for
+ // the input INT_MIN.
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/floatdixf.c b/contrib/compiler-rt/lib/builtins/floatdixf.c
index ebf62dba0584..d39e81d7ca75 100644
--- a/contrib/compiler-rt/lib/floatdixf.c
+++ b/contrib/compiler-rt/lib/builtins/floatdixf.c
@@ -26,7 +26,7 @@
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-long double
+COMPILER_RT_ABI long double
__floatdixf(di_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floatsidf.c b/contrib/compiler-rt/lib/builtins/floatsidf.c
index 18f378f2a900..1cf99b782a60 100644
--- a/contrib/compiler-rt/lib/floatsidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatsidf.c
@@ -20,7 +20,8 @@
ARM_EABI_FNALIAS(i2d, floatsidf)
-fp_t __floatsidf(int a) {
+COMPILER_RT_ABI fp_t
+__floatsidf(int a) {
const int aWidth = sizeof a * CHAR_BIT;
diff --git a/contrib/compiler-rt/lib/floatsisf.c b/contrib/compiler-rt/lib/builtins/floatsisf.c
index 83983934f590..467dd1d1eaf1 100644
--- a/contrib/compiler-rt/lib/floatsisf.c
+++ b/contrib/compiler-rt/lib/builtins/floatsisf.c
@@ -20,7 +20,8 @@
ARM_EABI_FNALIAS(i2f, floatsisf)
-fp_t __floatsisf(int a) {
+COMPILER_RT_ABI fp_t
+__floatsisf(int a) {
const int aWidth = sizeof a * CHAR_BIT;
diff --git a/contrib/compiler-rt/lib/builtins/floatsitf.c b/contrib/compiler-rt/lib/builtins/floatsitf.c
new file mode 100644
index 000000000000..85346933f81e
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/floatsitf.c
@@ -0,0 +1,52 @@
+//===-- lib/floatsitf.c - integer -> quad-precision conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements integer to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatsitf(int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ unsigned aAbs = (unsigned)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs += 0x80000000;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit. Extra
+ // cast to unsigned int is necessary to get the correct behavior for
+ // the input INT_MIN.
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/floattidf.c b/contrib/compiler-rt/lib/builtins/floattidf.c
index 042c2031a38a..6331ba57376f 100644
--- a/contrib/compiler-rt/lib/floattidf.c
+++ b/contrib/compiler-rt/lib/builtins/floattidf.c
@@ -24,9 +24,7 @@
/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-si_int __clzti2(ti_int a);
-
-double
+COMPILER_RT_ABI double
__floattidf(ti_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floattisf.c b/contrib/compiler-rt/lib/builtins/floattisf.c
index cb4e29aabfe3..f1b585f2c326 100644
--- a/contrib/compiler-rt/lib/floattisf.c
+++ b/contrib/compiler-rt/lib/builtins/floattisf.c
@@ -24,9 +24,7 @@
/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-si_int __clzti2(ti_int a);
-
-float
+COMPILER_RT_ABI float
__floattisf(ti_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floattixf.c b/contrib/compiler-rt/lib/builtins/floattixf.c
index 866051e2a94c..1203b3a96e75 100644
--- a/contrib/compiler-rt/lib/floattixf.c
+++ b/contrib/compiler-rt/lib/builtins/floattixf.c
@@ -26,9 +26,7 @@
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-si_int __clzti2(ti_int a);
-
-long double
+COMPILER_RT_ABI long double
__floattixf(ti_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floatundidf.c b/contrib/compiler-rt/lib/builtins/floatundidf.c
index e52fa0a3359b..73b8bac1c1a1 100644
--- a/contrib/compiler-rt/lib/floatundidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatundidf.c
@@ -29,7 +29,6 @@ ARM_EABI_FNALIAS(ul2d, floatundidf)
* as a side-effect of this computation.
*/
-
COMPILER_RT_ABI double
__floatundidf(du_int a)
{
diff --git a/contrib/compiler-rt/lib/floatundisf.c b/contrib/compiler-rt/lib/builtins/floatundisf.c
index 713a44abc8bd..713a44abc8bd 100644
--- a/contrib/compiler-rt/lib/floatundisf.c
+++ b/contrib/compiler-rt/lib/builtins/floatundisf.c
diff --git a/contrib/compiler-rt/lib/builtins/floatunditf.c b/contrib/compiler-rt/lib/builtins/floatunditf.c
new file mode 100644
index 000000000000..7533f8106d39
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/floatunditf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunditf.c - uint -> quad-precision conversion -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements du_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatunditf(du_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/floatundixf.c b/contrib/compiler-rt/lib/builtins/floatundixf.c
index 64f7662d9525..ca5e06d64dcd 100644
--- a/contrib/compiler-rt/lib/floatundixf.c
+++ b/contrib/compiler-rt/lib/builtins/floatundixf.c
@@ -25,7 +25,7 @@
/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-long double
+COMPILER_RT_ABI long double
__floatundixf(du_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floatunsidf.c b/contrib/compiler-rt/lib/builtins/floatunsidf.c
index ba6c2cfd2a17..445e18041c48 100644
--- a/contrib/compiler-rt/lib/floatunsidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatunsidf.c
@@ -20,7 +20,8 @@
ARM_EABI_FNALIAS(ui2d, floatunsidf)
-fp_t __floatunsidf(unsigned int a) {
+COMPILER_RT_ABI fp_t
+__floatunsidf(unsigned int a) {
const int aWidth = sizeof a * CHAR_BIT;
diff --git a/contrib/compiler-rt/lib/floatunsisf.c b/contrib/compiler-rt/lib/builtins/floatunsisf.c
index e392c0ecf116..ea6f161adc02 100644
--- a/contrib/compiler-rt/lib/floatunsisf.c
+++ b/contrib/compiler-rt/lib/builtins/floatunsisf.c
@@ -20,7 +20,8 @@
ARM_EABI_FNALIAS(ui2f, floatunsisf)
-fp_t __floatunsisf(unsigned int a) {
+COMPILER_RT_ABI fp_t
+__floatunsisf(unsigned int a) {
const int aWidth = sizeof a * CHAR_BIT;
diff --git a/contrib/compiler-rt/lib/builtins/floatunsitf.c b/contrib/compiler-rt/lib/builtins/floatunsitf.c
new file mode 100644
index 000000000000..1cd1842e709a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/floatunsitf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunsitf.c - uint -> quad-precision conversion -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unsigned integer to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatunsitf(unsigned int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/floatuntidf.c b/contrib/compiler-rt/lib/builtins/floatuntidf.c
index e7d6416c1346..06202d9679ee 100644
--- a/contrib/compiler-rt/lib/floatuntidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatuntidf.c
@@ -24,9 +24,7 @@
/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-si_int __clzti2(ti_int a);
-
-double
+COMPILER_RT_ABI double
__floatuntidf(tu_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floatuntisf.c b/contrib/compiler-rt/lib/builtins/floatuntisf.c
index e65db57f1d1d..c0dd0275ddba 100644
--- a/contrib/compiler-rt/lib/floatuntisf.c
+++ b/contrib/compiler-rt/lib/builtins/floatuntisf.c
@@ -24,9 +24,7 @@
/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-si_int __clzti2(ti_int a);
-
-float
+COMPILER_RT_ABI float
__floatuntisf(tu_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/floatuntixf.c b/contrib/compiler-rt/lib/builtins/floatuntixf.c
index d607cc305734..ea81cb1bcdae 100644
--- a/contrib/compiler-rt/lib/floatuntixf.c
+++ b/contrib/compiler-rt/lib/builtins/floatuntixf.c
@@ -26,9 +26,7 @@
* 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
*/
-si_int __clzti2(ti_int a);
-
-long double
+COMPILER_RT_ABI long double
__floatuntixf(tu_int a)
{
if (a == 0)
diff --git a/contrib/compiler-rt/lib/addsf3.c b/contrib/compiler-rt/lib/builtins/fp_add_impl.inc
index 0268324deaab..5741889728cd 100644
--- a/contrib/compiler-rt/lib/addsf3.c
+++ b/contrib/compiler-rt/lib/builtins/fp_add_impl.inc
@@ -1,4 +1,4 @@
-//===-- lib/addsf3.c - Single-precision addition ------------------*- C -*-===//
+//===----- lib/fp_add_impl.inc - floaing point addition -----------*- C -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,81 +7,77 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements single-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
+// This file implements soft-float addition with the IEEE-754 default rounding
+// (to nearest, ties to even).
//
//===----------------------------------------------------------------------===//
-#define SINGLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(fadd, addsf3)
-
-fp_t __addsf3(fp_t a, fp_t b) {
-
+static inline fp_t __addXf3__(fp_t a, fp_t b) {
rep_t aRep = toRep(a);
rep_t bRep = toRep(b);
const rep_t aAbs = aRep & absMask;
const rep_t bAbs = bRep & absMask;
-
+
// Detect if a or b is zero, infinity, or NaN.
- if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
-
+ if (aAbs - REP_C(1) >= infRep - REP_C(1) ||
+ bAbs - REP_C(1) >= infRep - REP_C(1)) {
// NaN + anything = qNaN
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
// anything + NaN = qNaN
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
+
if (aAbs == infRep) {
// +/-infinity + -/+infinity = qNaN
if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
// +/-infinity + anything remaining = +/- infinity
else return a;
}
-
+
// anything remaining + +/-infinity = +/-infinity
if (bAbs == infRep) return b;
-
+
// zero + anything = anything
if (!aAbs) {
// but we need to get the sign right for zero + zero
if (!bAbs) return fromRep(toRep(a) & toRep(b));
else return b;
}
-
+
// anything + zero = anything
if (!bAbs) return a;
}
-
+
// Swap a and b if necessary so that a has the larger absolute value.
if (bAbs > aAbs) {
const rep_t temp = aRep;
aRep = bRep;
bRep = temp;
}
-
+
// Extract the exponent and significand from the (possibly swapped) a and b.
int aExponent = aRep >> significandBits & maxExponent;
int bExponent = bRep >> significandBits & maxExponent;
rep_t aSignificand = aRep & significandMask;
rep_t bSignificand = bRep & significandMask;
-
+
// Normalize any denormals, and adjust the exponent accordingly.
if (aExponent == 0) aExponent = normalize(&aSignificand);
if (bExponent == 0) bExponent = normalize(&bSignificand);
-
+
// The sign of the result is the sign of the larger operand, a. If they
// have opposite signs, we are performing a subtraction; otherwise addition.
const rep_t resultSign = aRep & signBit;
const bool subtraction = (aRep ^ bRep) & signBit;
-
+
// Shift the significands to give us round, guard and sticky, and or in the
// implicit significand bit. (If we fell through from the denormal path it
// was already set by normalize( ), but setting it twice won't hurt
// anything.)
aSignificand = (aSignificand | implicitBit) << 3;
bSignificand = (bSignificand | implicitBit) << 3;
-
+
// Shift the significand of b by the difference in exponents, with a sticky
// bottom bit to get rounding correct.
const unsigned int align = aExponent - bExponent;
@@ -93,13 +89,11 @@ fp_t __addsf3(fp_t a, fp_t b) {
bSignificand = 1; // sticky; b is known to be non-zero.
}
}
-
if (subtraction) {
aSignificand -= bSignificand;
-
// If a == -b, return +zero.
if (aSignificand == 0) return fromRep(0);
-
+
// If partial cancellation occured, we need to left-shift the result
// and adjust the exponent:
if (aSignificand < implicitBit << 3) {
@@ -108,10 +102,9 @@ fp_t __addsf3(fp_t a, fp_t b) {
aExponent -= shift;
}
}
-
else /* addition */ {
aSignificand += bSignificand;
-
+
// If the addition carried up, we need to right-shift the result and
// adjust the exponent:
if (aSignificand & implicitBit << 4) {
@@ -120,10 +113,10 @@ fp_t __addsf3(fp_t a, fp_t b) {
aExponent += 1;
}
}
-
+
// If we have overflowed the type, return +/- infinity:
if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
-
+
if (aExponent <= 0) {
// Result is denormal before rounding; the exponent is zero and we
// need to shift the significand.
@@ -132,17 +125,17 @@ fp_t __addsf3(fp_t a, fp_t b) {
aSignificand = aSignificand >> shift | sticky;
aExponent = 0;
}
-
+
// Low three bits are round, guard, and sticky.
const int roundGuardSticky = aSignificand & 0x7;
-
+
// Shift the significand into place, and mask off the implicit bit.
rep_t result = aSignificand >> 3 & significandMask;
-
+
// Insert the exponent and sign.
result |= (rep_t)aExponent << significandBits;
result |= resultSign;
-
+
// Final rounding. The result may overflow to infinity, but that is the
// correct result in that case.
if (roundGuardSticky > 0x4) result++;
diff --git a/contrib/compiler-rt/lib/builtins/fp_extend.h b/contrib/compiler-rt/lib/builtins/fp_extend.h
new file mode 100644
index 000000000000..fff676eeca8c
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fp_extend.h
@@ -0,0 +1,76 @@
+//===-lib/fp_extend.h - low precision -> high precision conversion -*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination setting
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_EXTEND_HEADER
+#define FP_EXTEND_HEADER
+
+#include "int_lib.h"
+
+#if defined SRC_SINGLE
+typedef float src_t;
+typedef uint32_t src_rep_t;
+#define SRC_REP_C UINT32_C
+static const int srcSigBits = 23;
+#define src_rep_t_clz __builtin_clz
+
+#elif defined SRC_DOUBLE
+typedef double src_t;
+typedef uint64_t src_rep_t;
+#define SRC_REP_C UINT64_C
+static const int srcSigBits = 52;
+static inline int src_rep_t_clz(src_rep_t a) {
+#if defined __LP64__
+ return __builtin_clzl(a);
+#else
+ if (a & REP_C(0xffffffff00000000))
+ return __builtin_clz(a >> 32);
+ else
+ return 32 + __builtin_clz(a & REP_C(0xffffffff));
+#endif
+}
+
+#else
+#error Source should be single precision or double precision!
+#endif //end source precision
+
+#if defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#elif defined DST_QUAD
+typedef long double dst_t;
+typedef __uint128_t dst_rep_t;
+#define DST_REP_C (__uint128_t)
+static const int dstSigBits = 112;
+
+#else
+#error Destination should be double precision or quad precision!
+#endif //end destination precision
+
+// End of specialization parameters. Two helper routines for conversion to and
+// from the representation of floating-point data as integer values follow.
+
+static inline src_rep_t srcToRep(src_t x) {
+ const union { src_t f; src_rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static inline dst_t dstFromRep(dst_rep_t x) {
+ const union { dst_t f; dst_rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+// End helper routines. Conversion implementation follows.
+
+#endif //FP_EXTEND_HEADER
diff --git a/contrib/compiler-rt/lib/extendsfdf2.c b/contrib/compiler-rt/lib/builtins/fp_extend_impl.inc
index 91fd2b436a33..f6953ff4bfae 100644
--- a/contrib/compiler-rt/lib/extendsfdf2.c
+++ b/contrib/compiler-rt/lib/builtins/fp_extend_impl.inc
@@ -1,4 +1,4 @@
-//===-- lib/extendsfdf2.c - single -> double conversion -----------*- C -*-===//
+//=-lib/fp_extend_impl.inc - low precision -> high precision conversion -*-- -//
//
// The LLVM Compiler Infrastructure
//
@@ -11,11 +11,9 @@
// IEEE-754 floating-point type. The constants and types defined following the
// includes below parameterize the conversion.
//
-// This routine can be trivially adapted to support conversions from
-// half-precision or to quad-precision. It does not support types that don't
-// use the usual IEEE-754 interchange formats; specifically, some work would be
-// needed to adapt it to (for example) the Intel 80-bit format or PowerPC
-// double-double format.
+// It does not support types that don't use the usual IEEE-754 interchange
+// formats; specifically, some work would be needed to adapt it to
+// (for example) the Intel 80-bit format or PowerPC double-double format.
//
// Note please, however, that this implementation is only intended to support
// *widening* operations; if you need to convert to a *narrower* floating-point
@@ -38,65 +36,36 @@
//
//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#include "fp_extend.h"
-typedef float src_t;
-typedef uint32_t src_rep_t;
-#define SRC_REP_C UINT32_C
-static const int srcSigBits = 23;
-#define src_rep_t_clz __builtin_clz
-
-typedef double dst_t;
-typedef uint64_t dst_rep_t;
-#define DST_REP_C UINT64_C
-static const int dstSigBits = 52;
-
-// End of specialization parameters. Two helper routines for conversion to and
-// from the representation of floating-point data as integer values follow.
-
-static inline src_rep_t srcToRep(src_t x) {
- const union { src_t f; src_rep_t i; } rep = {.f = x};
- return rep.i;
-}
-
-static inline dst_t dstFromRep(dst_rep_t x) {
- const union { dst_t f; dst_rep_t i; } rep = {.i = x};
- return rep.f;
-}
-
-// End helper routines. Conversion implementation follows.
-
-ARM_EABI_FNALIAS(f2d, extendsfdf2)
-
-dst_t __extendsfdf2(src_t a) {
-
+static inline dst_t __extendXfYf2__(src_t a) {
// Various constants whose values follow from the type parameters.
// Any reasonable optimizer will fold and propagate all of these.
const int srcBits = sizeof(src_t)*CHAR_BIT;
const int srcExpBits = srcBits - srcSigBits - 1;
const int srcInfExp = (1 << srcExpBits) - 1;
const int srcExpBias = srcInfExp >> 1;
-
+
const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
const src_rep_t srcAbsMask = srcSignMask - 1;
const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
const src_rep_t srcNaNCode = srcQNaN - 1;
-
+
const int dstBits = sizeof(dst_t)*CHAR_BIT;
const int dstExpBits = dstBits - dstSigBits - 1;
const int dstInfExp = (1 << dstExpBits) - 1;
const int dstExpBias = dstInfExp >> 1;
-
+
const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
-
+
// Break a into a sign and representation of the absolute value
const src_rep_t aRep = srcToRep(a);
const src_rep_t aAbs = aRep & srcAbsMask;
const src_rep_t sign = aRep & srcSignMask;
dst_rep_t absResult;
-
+
if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) {
// a is a normal number.
// Extend to the destination type by shifting the significand and
@@ -104,7 +73,7 @@ dst_t __extendsfdf2(src_t a) {
absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
}
-
+
else if (aAbs >= srcInfinity) {
// a is NaN or infinity.
// Conjure the result by beginning with infinity, then setting the qNaN
@@ -112,9 +81,9 @@ dst_t __extendsfdf2(src_t a) {
// payload field.
absResult = (dst_rep_t)dstInfExp << dstSigBits;
absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
- absResult |= aAbs & srcNaNCode;
+ absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
}
-
+
else if (aAbs) {
// a is denormal.
// renormalize the significand and clear the leading bit, then insert
@@ -130,7 +99,7 @@ dst_t __extendsfdf2(src_t a) {
// a is zero.
absResult = 0;
}
-
+
// Apply the signbit to (dst_t)abs(a).
const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
return dstFromRep(result);
diff --git a/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc b/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc
new file mode 100644
index 000000000000..035e87ca10e0
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc
@@ -0,0 +1,41 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static inline fixint_t __fixint(fp_t a) {
+ const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
+ const fixint_t fixint_min = -fixint_max - 1;
+ // Break a into sign, exponent, significand
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const fixint_t sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+ // If exponent is negative, the result is zero.
+ if (exponent < 0)
+ return 0;
+
+ // If the value is too large for the integer type, saturate.
+ if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT)
+ return sign == 1 ? fixint_max : fixint_min;
+
+ // If 0 <= exponent < significandBits, right shift to get the result.
+ // Otherwise, shift left.
+ if (exponent < significandBits)
+ return sign * (significand >> (significandBits - exponent));
+ else
+ return sign * ((fixint_t)significand << (exponent - significandBits));
+}
diff --git a/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc b/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc
new file mode 100644
index 000000000000..5fefab0e2d8a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc
@@ -0,0 +1,39 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to unsigned integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static inline fixuint_t __fixuint(fp_t a) {
+ // Break a into sign, exponent, significand
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const int sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+ // If either the value or the exponent is negative, the result is zero.
+ if (sign == -1 || exponent < 0)
+ return 0;
+
+ // If the value is too large for the integer type, saturate.
+ if ((unsigned)exponent > sizeof(fixuint_t) * CHAR_BIT)
+ return ~(fixuint_t)0;
+
+ // If 0 <= exponent < significandBits, right shift to get the result.
+ // Otherwise, shift left.
+ if (exponent < significandBits)
+ return significand >> (significandBits - exponent);
+ else
+ return (fixuint_t)significand << (exponent - significandBits);
+}
diff --git a/contrib/compiler-rt/lib/builtins/fp_lib.h b/contrib/compiler-rt/lib/builtins/fp_lib.h
new file mode 100644
index 000000000000..faebb99ecd5e
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fp_lib.h
@@ -0,0 +1,270 @@
+//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for soft-float routines in compiler-rt.
+// This file does not provide any part of the compiler-rt interface, but defines
+// many useful constants and utility routines that are used in the
+// implementation of the soft-float routines in compiler-rt.
+//
+// Assumes that float, double and long double correspond to the IEEE-754
+// binary32, binary64 and binary 128 types, respectively, and that integer
+// endianness matches floating point endianness on the target platform.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_LIB_HEADER
+#define FP_LIB_HEADER
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <limits.h>
+#include "int_lib.h"
+
+// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
+// 32-bit mode.
+#if defined(__FreeBSD__) && defined(__i386__)
+# include <sys/param.h>
+# if __FreeBSD_version < 903000 // v9.3
+# define uint64_t unsigned long long
+# define int64_t long long
+# undef UINT64_C
+# define UINT64_C(c) (c ## ULL)
+# endif
+#endif
+
+#if defined SINGLE_PRECISION
+
+typedef uint32_t rep_t;
+typedef int32_t srep_t;
+typedef float fp_t;
+#define REP_C UINT32_C
+#define significandBits 23
+
+static inline int rep_clz(rep_t a) {
+ return __builtin_clz(a);
+}
+
+// 32x32 --> 64 bit multiply
+static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+ const uint64_t product = (uint64_t)a*b;
+ *hi = product >> 32;
+ *lo = product;
+}
+COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);
+
+#elif defined DOUBLE_PRECISION
+
+typedef uint64_t rep_t;
+typedef int64_t srep_t;
+typedef double fp_t;
+#define REP_C UINT64_C
+#define significandBits 52
+
+static inline int rep_clz(rep_t a) {
+#if defined __LP64__
+ return __builtin_clzl(a);
+#else
+ if (a & REP_C(0xffffffff00000000))
+ return __builtin_clz(a >> 32);
+ else
+ return 32 + __builtin_clz(a & REP_C(0xffffffff));
+#endif
+}
+
+#define loWord(a) (a & 0xffffffffU)
+#define hiWord(a) (a >> 32)
+
+// 64x64 -> 128 wide multiply for platforms that don't have such an operation;
+// many 64-bit platforms have this operation, but they tend to have hardware
+// floating-point, so we don't bother with a special case for them here.
+static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+ // Each of the component 32x32 -> 64 products
+ const uint64_t plolo = loWord(a) * loWord(b);
+ const uint64_t plohi = loWord(a) * hiWord(b);
+ const uint64_t philo = hiWord(a) * loWord(b);
+ const uint64_t phihi = hiWord(a) * hiWord(b);
+ // Sum terms that contribute to lo in a way that allows us to get the carry
+ const uint64_t r0 = loWord(plolo);
+ const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
+ *lo = r0 + (r1 << 32);
+ // Sum terms contributing to hi with the carry from lo
+ *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
+}
+#undef loWord
+#undef hiWord
+
+COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
+
+#elif defined QUAD_PRECISION
+#if __LDBL_MANT_DIG__ == 113
+#define CRT_LDBL_128BIT
+typedef __uint128_t rep_t;
+typedef __int128_t srep_t;
+typedef long double fp_t;
+#define REP_C (__uint128_t)
+// Note: Since there is no explicit way to tell compiler the constant is a
+// 128-bit integer, we let the constant be casted to 128-bit integer
+#define significandBits 112
+
+static inline int rep_clz(rep_t a) {
+ const union
+ {
+ __uint128_t ll;
+#if _YUGA_BIG_ENDIAN
+ struct { uint64_t high, low; } s;
+#else
+ struct { uint64_t low, high; } s;
+#endif
+ } uu = { .ll = a };
+
+ uint64_t word;
+ uint64_t add;
+
+ if (uu.s.high){
+ word = uu.s.high;
+ add = 0;
+ }
+ else{
+ word = uu.s.low;
+ add = 64;
+ }
+ return __builtin_clzll(word) + add;
+}
+
+#define Word_LoMask UINT64_C(0x00000000ffffffff)
+#define Word_HiMask UINT64_C(0xffffffff00000000)
+#define Word_FullMask UINT64_C(0xffffffffffffffff)
+#define Word_1(a) (uint64_t)((a >> 96) & Word_LoMask)
+#define Word_2(a) (uint64_t)((a >> 64) & Word_LoMask)
+#define Word_3(a) (uint64_t)((a >> 32) & Word_LoMask)
+#define Word_4(a) (uint64_t)(a & Word_LoMask)
+
+// 128x128 -> 256 wide multiply for platforms that don't have such an operation;
+// many 64-bit platforms have this operation, but they tend to have hardware
+// floating-point, so we don't bother with a special case for them here.
+static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+
+ const uint64_t product11 = Word_1(a) * Word_1(b);
+ const uint64_t product12 = Word_1(a) * Word_2(b);
+ const uint64_t product13 = Word_1(a) * Word_3(b);
+ const uint64_t product14 = Word_1(a) * Word_4(b);
+ const uint64_t product21 = Word_2(a) * Word_1(b);
+ const uint64_t product22 = Word_2(a) * Word_2(b);
+ const uint64_t product23 = Word_2(a) * Word_3(b);
+ const uint64_t product24 = Word_2(a) * Word_4(b);
+ const uint64_t product31 = Word_3(a) * Word_1(b);
+ const uint64_t product32 = Word_3(a) * Word_2(b);
+ const uint64_t product33 = Word_3(a) * Word_3(b);
+ const uint64_t product34 = Word_3(a) * Word_4(b);
+ const uint64_t product41 = Word_4(a) * Word_1(b);
+ const uint64_t product42 = Word_4(a) * Word_2(b);
+ const uint64_t product43 = Word_4(a) * Word_3(b);
+ const uint64_t product44 = Word_4(a) * Word_4(b);
+
+ const __uint128_t sum0 = (__uint128_t)product44;
+ const __uint128_t sum1 = (__uint128_t)product34 +
+ (__uint128_t)product43;
+ const __uint128_t sum2 = (__uint128_t)product24 +
+ (__uint128_t)product33 +
+ (__uint128_t)product42;
+ const __uint128_t sum3 = (__uint128_t)product14 +
+ (__uint128_t)product23 +
+ (__uint128_t)product32 +
+ (__uint128_t)product41;
+ const __uint128_t sum4 = (__uint128_t)product13 +
+ (__uint128_t)product22 +
+ (__uint128_t)product31;
+ const __uint128_t sum5 = (__uint128_t)product12 +
+ (__uint128_t)product21;
+ const __uint128_t sum6 = (__uint128_t)product11;
+
+ const __uint128_t r0 = (sum0 & Word_FullMask) +
+ ((sum1 & Word_LoMask) << 32);
+ const __uint128_t r1 = (sum0 >> 64) +
+ ((sum1 >> 32) & Word_FullMask) +
+ (sum2 & Word_FullMask) +
+ ((sum3 << 32) & Word_HiMask);
+
+ *lo = r0 + (r1 << 64);
+ *hi = (r1 >> 64) +
+ (sum1 >> 96) +
+ (sum2 >> 64) +
+ (sum3 >> 32) +
+ sum4 +
+ (sum5 << 32) +
+ (sum6 << 64);
+}
+#undef Word_1
+#undef Word_2
+#undef Word_3
+#undef Word_4
+#undef Word_HiMask
+#undef Word_LoMask
+#undef Word_FullMask
+#endif // __LDBL_MANT_DIG__ == 113
+#else
+#error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined.
+#endif
+
+#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || defined(CRT_LDBL_128BIT)
+#define typeWidth (sizeof(rep_t)*CHAR_BIT)
+#define exponentBits (typeWidth - significandBits - 1)
+#define maxExponent ((1 << exponentBits) - 1)
+#define exponentBias (maxExponent >> 1)
+
+#define implicitBit (REP_C(1) << significandBits)
+#define significandMask (implicitBit - 1U)
+#define signBit (REP_C(1) << (significandBits + exponentBits))
+#define absMask (signBit - 1U)
+#define exponentMask (absMask ^ significandMask)
+#define oneRep ((rep_t)exponentBias << significandBits)
+#define infRep exponentMask
+#define quietBit (implicitBit >> 1)
+#define qnanRep (exponentMask | quietBit)
+
+static inline rep_t toRep(fp_t x) {
+ const union { fp_t f; rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static inline fp_t fromRep(rep_t x) {
+ const union { fp_t f; rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+
+static inline int normalize(rep_t *significand) {
+ const int shift = rep_clz(*significand) - rep_clz(implicitBit);
+ *significand <<= shift;
+ return 1 - shift;
+}
+
+static inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
+ *hi = *hi << count | *lo >> (typeWidth - count);
+ *lo = *lo << count;
+}
+
+static inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) {
+ if (count < typeWidth) {
+ const bool sticky = *lo << (typeWidth - count);
+ *lo = *hi << (typeWidth - count) | *lo >> count | sticky;
+ *hi = *hi >> count;
+ }
+ else if (count < 2*typeWidth) {
+ const bool sticky = *hi << (2*typeWidth - count) | *lo;
+ *lo = *hi >> (count - typeWidth) | sticky;
+ *hi = 0;
+ } else {
+ const bool sticky = *hi | *lo;
+ *lo = sticky;
+ *hi = 0;
+ }
+}
+#endif
+
+#endif // FP_LIB_HEADER
diff --git a/contrib/compiler-rt/lib/muldf3.c b/contrib/compiler-rt/lib/builtins/fp_mul_impl.inc
index c38edba90cf2..ca8a0bb98b10 100644
--- a/contrib/compiler-rt/lib/muldf3.c
+++ b/contrib/compiler-rt/lib/builtins/fp_mul_impl.inc
@@ -1,4 +1,4 @@
-//===-- lib/muldf3.c - Double-precision multiplication ------------*- C -*-===//
+//===---- lib/fp_mul_impl.inc - floating point multiplication -----*- C -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,70 +7,65 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements double-precision soft-float multiplication
-// with the IEEE-754 default rounding (to nearest, ties to even).
+// This file implements soft-float multiplication with the IEEE-754 default
+// rounding (to nearest, ties to even).
//
//===----------------------------------------------------------------------===//
-#define DOUBLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(dmul, muldf3)
-
-COMPILER_RT_ABI fp_t
-__muldf3(fp_t a, fp_t b) {
-
+static inline fp_t __mulXf3__(fp_t a, fp_t b) {
const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit;
-
+
rep_t aSignificand = toRep(a) & significandMask;
rep_t bSignificand = toRep(b) & significandMask;
int scale = 0;
-
+
// Detect if a or b is zero, denormal, infinity, or NaN.
if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
+
const rep_t aAbs = toRep(a) & absMask;
const rep_t bAbs = toRep(b) & absMask;
-
+
// NaN * anything = qNaN
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
// anything * NaN = qNaN
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
+
if (aAbs == infRep) {
// infinity * non-zero = +/- infinity
if (bAbs) return fromRep(aAbs | productSign);
// infinity * zero = NaN
else return fromRep(qnanRep);
}
-
+
if (bAbs == infRep) {
- // non-zero * infinity = +/- infinity
+ //? non-zero * infinity = +/- infinity
if (aAbs) return fromRep(bAbs | productSign);
// zero * infinity = NaN
else return fromRep(qnanRep);
}
-
+
// zero * anything = +/- zero
if (!aAbs) return fromRep(productSign);
// anything * zero = +/- zero
if (!bAbs) return fromRep(productSign);
-
+
// one or both of a or b is denormal, the other (if applicable) is a
// normal number. Renormalize one or both of a and b, and set scale to
// include the necessary exponent adjustment.
if (aAbs < implicitBit) scale += normalize(&aSignificand);
if (bAbs < implicitBit) scale += normalize(&bSignificand);
}
-
+
// Or in the implicit significand bit. (If we fell through from the
// denormal path it was already set by normalize( ), but setting it twice
// won't hurt anything.)
aSignificand |= implicitBit;
bSignificand |= implicitBit;
-
+
// Get the significand of a*b. Before multiplying the significands, shift
// one of them left to left-align it in the field. Thus, the product will
// have (exponentBits + 2) integral digits, all but two of which must be
@@ -79,16 +74,16 @@ __muldf3(fp_t a, fp_t b) {
rep_t productHi, productLo;
wideMultiply(aSignificand, bSignificand << exponentBits,
&productHi, &productLo);
-
+
int productExponent = aExponent + bExponent - exponentBias + scale;
-
+
// Normalize the significand, adjust exponent if needed.
if (productHi & implicitBit) productExponent++;
else wideLeftShift(&productHi, &productLo, 1);
-
+
// If we have overflowed the type, return +/- infinity.
if (productExponent >= maxExponent) return fromRep(infRep | productSign);
-
+
if (productExponent <= 0) {
// Result is denormal before rounding
//
@@ -96,23 +91,22 @@ __muldf3(fp_t a, fp_t b) {
// a zero of the appropriate sign. Mathematically there is no need to
// handle this case separately, but we make it a special case to
// simplify the shift logic.
- const unsigned int shift = 1U - (unsigned int)productExponent;
+ const unsigned int shift = REP_C(1) - (unsigned int)productExponent;
if (shift >= typeWidth) return fromRep(productSign);
-
+
// Otherwise, shift the significand of the result so that the round
// bit is the high bit of productLo.
wideRightShiftWithSticky(&productHi, &productLo, shift);
}
-
else {
// Result is normal before rounding; insert the exponent.
productHi &= significandMask;
productHi |= (rep_t)productExponent << significandBits;
}
-
+
// Insert the sign of the result:
productHi |= productSign;
-
+
// Final rounding. The final result may overflow to infinity, or underflow
// to zero, but those are the correct results in those cases. We use the
// default IEEE-754 round-to-nearest, ties-to-even rounding mode.
diff --git a/contrib/compiler-rt/lib/builtins/fp_trunc.h b/contrib/compiler-rt/lib/builtins/fp_trunc.h
new file mode 100644
index 000000000000..49a9aebbc67d
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/fp_trunc.h
@@ -0,0 +1,64 @@
+//=== lib/fp_trunc.h - high precision -> low precision conversion *- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination precision setting
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_TRUNC_HEADER
+#define FP_TRUNC_HEADER
+
+#include "int_lib.h"
+
+#if defined SRC_DOUBLE
+typedef double src_t;
+typedef uint64_t src_rep_t;
+#define SRC_REP_C UINT64_C
+static const int srcSigBits = 52;
+
+#elif defined SRC_QUAD
+typedef long double src_t;
+typedef __uint128_t src_rep_t;
+#define SRC_REP_C (__uint128_t)
+static const int srcSigBits = 112;
+
+#else
+#error Source should be double precision or quad precision!
+#endif //end source precision
+
+#if defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#elif defined DST_SINGLE
+typedef float dst_t;
+typedef uint32_t dst_rep_t;
+#define DST_REP_C UINT32_C
+static const int dstSigBits = 23;
+
+#else
+#error Destination should be single precision or double precision!
+#endif //end destination precision
+
+// End of specialization parameters. Two helper routines for conversion to and
+// from the representation of floating-point data as integer values follow.
+
+static inline src_rep_t srcToRep(src_t x) {
+ const union { src_t f; src_rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static inline dst_t dstFromRep(dst_rep_t x) {
+ const union { dst_t f; dst_rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+
+#endif // FP_TRUNC_HEADER
diff --git a/contrib/compiler-rt/lib/truncdfsf2.c b/contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc
index 61c909a22d8a..21bffae02bf4 100644
--- a/contrib/compiler-rt/lib/truncdfsf2.c
+++ b/contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc
@@ -1,4 +1,4 @@
-//===-- lib/truncdfsf2.c - double -> single conversion ------------*- C -*-===//
+//= lib/fp_trunc_impl.inc - high precision -> low precision conversion *-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,7 +12,7 @@
// rounding mode. The constants and types defined following the includes below
// parameterize the conversion.
//
-// This routine can be trivially adapted to support conversions to
+// This routine can be trivially adapted to support conversions to
// half-precision or from quad-precision. It does not support types that don't
// use the usual IEEE-754 interchange formats; specifically, some work would be
// needed to adapt it to (for example) the Intel 80-bit format or PowerPC
@@ -37,63 +37,36 @@
//
//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#include "fp_trunc.h"
-typedef double src_t;
-typedef uint64_t src_rep_t;
-#define SRC_REP_C UINT64_C
-static const int srcSigBits = 52;
-
-typedef float dst_t;
-typedef uint32_t dst_rep_t;
-#define DST_REP_C UINT32_C
-static const int dstSigBits = 23;
-
-// End of specialization parameters. Two helper routines for conversion to and
-// from the representation of floating-point data as integer values follow.
-
-static inline src_rep_t srcToRep(src_t x) {
- const union { src_t f; src_rep_t i; } rep = {.f = x};
- return rep.i;
-}
-
-static inline dst_t dstFromRep(dst_rep_t x) {
- const union { dst_t f; dst_rep_t i; } rep = {.i = x};
- return rep.f;
-}
-
-// End helper routines. Conversion implementation follows.
-
-ARM_EABI_FNALIAS(d2f, truncdfsf2)
-
-COMPILER_RT_ABI dst_t
-__truncdfsf2(src_t a) {
-
+static inline dst_t __truncXfYf2__(src_t a) {
// Various constants whose values follow from the type parameters.
// Any reasonable optimizer will fold and propagate all of these.
const int srcBits = sizeof(src_t)*CHAR_BIT;
const int srcExpBits = srcBits - srcSigBits - 1;
const int srcInfExp = (1 << srcExpBits) - 1;
const int srcExpBias = srcInfExp >> 1;
-
+
const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
- const src_rep_t significandMask = srcMinNormal - 1;
+ const src_rep_t srcSignificandMask = srcMinNormal - 1;
const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
const src_rep_t srcAbsMask = srcSignMask - 1;
const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
-
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
+
const int dstBits = sizeof(dst_t)*CHAR_BIT;
const int dstExpBits = dstBits - dstSigBits - 1;
const int dstInfExp = (1 << dstExpBits) - 1;
const int dstExpBias = dstInfExp >> 1;
-
+
const int underflowExponent = srcExpBias + 1 - dstExpBias;
const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
-
+
const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
const dst_rep_t dstNaNCode = dstQNaN - 1;
@@ -102,48 +75,43 @@ __truncdfsf2(src_t a) {
const src_rep_t aAbs = aRep & srcAbsMask;
const src_rep_t sign = aRep & srcSignMask;
dst_rep_t absResult;
-
+
if (aAbs - underflow < aAbs - overflow) {
// The exponent of a is within the range of normal numbers in the
// destination format. We can convert by simply right-shifting with
// rounding and adjusting the exponent.
absResult = aAbs >> (srcSigBits - dstSigBits);
absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
-
+
const src_rep_t roundBits = aAbs & roundMask;
-
// Round to nearest
if (roundBits > halfway)
absResult++;
-
// Ties to even
else if (roundBits == halfway)
absResult += absResult & 1;
}
-
else if (aAbs > srcInfinity) {
// a is NaN.
// Conjure the result by beginning with infinity, setting the qNaN
// bit and inserting the (truncated) trailing NaN field.
absResult = (dst_rep_t)dstInfExp << dstSigBits;
absResult |= dstQNaN;
- absResult |= aAbs & dstNaNCode;
+ absResult |= ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
}
-
else if (aAbs > overflow) {
// a overflows to infinity.
absResult = (dst_rep_t)dstInfExp << dstSigBits;
}
-
else {
// a underflows on conversion to the destination type or is an exact
// zero. The result may be a denormal or zero. Extract the exponent
// to get the shift amount for the denormalization.
const int aExp = aAbs >> srcSigBits;
const int shift = srcExpBias - dstExpBias - aExp + 1;
-
- const src_rep_t significand = (aRep & significandMask) | srcMinNormal;
-
+
+ const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
+
// Right shift by the denormalization amount with sticky.
if (shift > srcSigBits) {
absResult = 0;
@@ -160,9 +128,8 @@ __truncdfsf2(src_t a) {
absResult += absResult & 1;
}
}
-
+
// Apply the signbit to (dst_t)abs(a).
const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
return dstFromRep(result);
-
}
diff --git a/contrib/compiler-rt/lib/gcc_personality_v0.c b/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c
index 8a708cae5974..4b95cfd43b05 100644
--- a/contrib/compiler-rt/lib/gcc_personality_v0.c
+++ b/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -11,47 +11,7 @@
#include "int_lib.h"
-/*
- * _Unwind_* stuff based on C++ ABI public documentation
- * http://refspecs.freestandards.org/abi-eh-1.21.html
- */
-
-typedef enum {
- _URC_NO_REASON = 0,
- _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
- _URC_FATAL_PHASE2_ERROR = 2,
- _URC_FATAL_PHASE1_ERROR = 3,
- _URC_NORMAL_STOP = 4,
- _URC_END_OF_STACK = 5,
- _URC_HANDLER_FOUND = 6,
- _URC_INSTALL_CONTEXT = 7,
- _URC_CONTINUE_UNWIND = 8
-} _Unwind_Reason_Code;
-
-typedef enum {
- _UA_SEARCH_PHASE = 1,
- _UA_CLEANUP_PHASE = 2,
- _UA_HANDLER_FRAME = 4,
- _UA_FORCE_UNWIND = 8,
- _UA_END_OF_STACK = 16
-} _Unwind_Action;
-
-typedef struct _Unwind_Context* _Unwind_Context_t;
-
-struct _Unwind_Exception {
- uint64_t exception_class;
- void (*exception_cleanup)(_Unwind_Reason_Code reason,
- struct _Unwind_Exception* exc);
- uintptr_t private_1;
- uintptr_t private_2;
-};
-
-extern const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c);
-extern void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n);
-extern void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value);
-extern uintptr_t _Unwind_GetIP(_Unwind_Context_t context);
-extern uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context);
-
+#include <unwind.h>
/*
* Pointer encodings documented at:
@@ -107,34 +67,34 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
/* first get value */
switch (encoding & 0x0F) {
case DW_EH_PE_absptr:
- result = *((uintptr_t*)p);
+ result = *((const uintptr_t*)p);
p += sizeof(uintptr_t);
break;
case DW_EH_PE_uleb128:
result = readULEB128(&p);
break;
case DW_EH_PE_udata2:
- result = *((uint16_t*)p);
+ result = *((const uint16_t*)p);
p += sizeof(uint16_t);
break;
case DW_EH_PE_udata4:
- result = *((uint32_t*)p);
+ result = *((const uint32_t*)p);
p += sizeof(uint32_t);
break;
case DW_EH_PE_udata8:
- result = *((uint64_t*)p);
+ result = *((const uint64_t*)p);
p += sizeof(uint64_t);
break;
case DW_EH_PE_sdata2:
- result = *((int16_t*)p);
+ result = *((const int16_t*)p);
p += sizeof(int16_t);
break;
case DW_EH_PE_sdata4:
- result = *((int32_t*)p);
+ result = *((const int32_t*)p);
p += sizeof(int32_t);
break;
case DW_EH_PE_sdata8:
- result = *((int64_t*)p);
+ result = *((const int64_t*)p);
p += sizeof(int64_t);
break;
case DW_EH_PE_sleb128:
@@ -164,7 +124,7 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
/* then apply indirection */
if (encoding & DW_EH_PE_indirect) {
- result = *((uintptr_t*)result);
+ result = *((const uintptr_t*)result);
}
*data = p;
@@ -180,15 +140,17 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
* on each frame as the stack is unwound during a C++ exception
* throw through a C function compiled with -fexceptions.
*/
-#if __arm__
+#if __USING_SJLJ_EXCEPTIONS__
// the setjump-longjump based exceptions personality routine has a different name
-_Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions,
+COMPILER_RT_ABI _Unwind_Reason_Code
+__gcc_personality_sj0(int version, _Unwind_Action actions,
uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- _Unwind_Context_t context)
+ struct _Unwind_Context *context)
#else
-_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
+COMPILER_RT_ABI _Unwind_Reason_Code
+__gcc_personality_v0(int version, _Unwind_Action actions,
uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- _Unwind_Context_t context)
+ struct _Unwind_Context *context)
#endif
{
/* Since C does not have catch clauses, there is nothing to do during */
@@ -197,7 +159,7 @@ _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
return _URC_CONTINUE_UNWIND;
/* There is nothing to do if there is no LSDA for this frame. */
- const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context);
+ const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);
if ( lsda == (uint8_t*) 0 )
return _URC_CONTINUE_UNWIND;
diff --git a/contrib/compiler-rt/lib/i386/ashldi3.S b/contrib/compiler-rt/lib/builtins/i386/ashldi3.S
index 5488ad6e52be..3fbd73903842 100644
--- a/contrib/compiler-rt/lib/i386/ashldi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/ashldi3.S
@@ -16,7 +16,7 @@
#ifdef __SSE2__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__ashldi3)
movd 12(%esp), %xmm2 // Load count
#ifndef TRUST_CALLERS_USE_64_BIT_STORES
@@ -31,11 +31,12 @@ DEFINE_COMPILERRT_FUNCTION(__ashldi3)
psrlq $32, %xmm0
movd %xmm0, %edx
ret
+END_COMPILERRT_FUNCTION(__ashldi3)
#else // Use GPRs instead of SSE2 instructions, if they aren't available.
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__ashldi3)
movl 12(%esp), %ecx // Load count
movl 8(%esp), %edx // Load high
@@ -51,6 +52,7 @@ DEFINE_COMPILERRT_FUNCTION(__ashldi3)
xorl %eax, %eax // clear low
shll %cl, %edx // shift high by count - 32
ret
-
+END_COMPILERRT_FUNCTION(__ashldi3)
+
#endif // __SSE2__
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/ashrdi3.S b/contrib/compiler-rt/lib/builtins/i386/ashrdi3.S
index b1445ddb99c1..8f4742481b42 100644
--- a/contrib/compiler-rt/lib/i386/ashrdi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/ashrdi3.S
@@ -9,7 +9,7 @@
#ifdef __SSE2__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
movd 12(%esp), %xmm2 // Load count
movl 8(%esp), %eax
@@ -41,11 +41,12 @@ DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
psrlq $32, %xmm0
movd %xmm0, %edx
ret
+END_COMPILERRT_FUNCTION(__ashrdi3)
#else // Use GPRs instead of SSE2 instructions, if they aren't available.
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
movl 12(%esp), %ecx // Load count
movl 8(%esp), %edx // Load high
@@ -62,6 +63,7 @@ DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
sarl $31, %edx // clear high
sarl %cl, %eax // shift low by count - 32
ret
-
+END_COMPILERRT_FUNCTION(__ashrdi3)
+
#endif // __SSE2__
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/divdi3.S b/contrib/compiler-rt/lib/builtins/i386/divdi3.S
index 69593e32e9e3..2cb0ddd4c29f 100644
--- a/contrib/compiler-rt/lib/i386/divdi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/divdi3.S
@@ -19,7 +19,7 @@
#ifdef __i386__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__divdi3)
/* This is currently implemented by wrapping the unsigned divide up in an absolute
@@ -157,5 +157,6 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
popl %ebx // Restore callee-save registers
popl %esi
retl // Return
+END_COMPILERRT_FUNCTION(__divdi3)
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/floatdidf.S b/contrib/compiler-rt/lib/builtins/i386/floatdidf.S
index a953d26cec06..dcc32f8ed85d 100644
--- a/contrib/compiler-rt/lib/i386/floatdidf.S
+++ b/contrib/compiler-rt/lib/builtins/i386/floatdidf.S
@@ -7,17 +7,20 @@
#ifdef __i386__
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
-twop32: .quad 0x41f0000000000000
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop32:
+ .quad 0x41f0000000000000
#define REL_ADDR(_a) (_a)-0b(%eax)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatdidf)
cvtsi2sd 8(%esp), %xmm1
movss 4(%esp), %xmm0 // low 32 bits of a
@@ -31,5 +34,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdidf)
movsd %xmm0, 4(%esp)
fldl 4(%esp)
ret
-
+END_COMPILERRT_FUNCTION(__floatdidf)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/floatdisf.S b/contrib/compiler-rt/lib/builtins/i386/floatdisf.S
index a98a46ee33ab..f64276703607 100644
--- a/contrib/compiler-rt/lib/i386/floatdisf.S
+++ b/contrib/compiler-rt/lib/builtins/i386/floatdisf.S
@@ -15,7 +15,7 @@
#ifdef __i386__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatdisf)
#ifndef TRUST_CALLERS_USE_64_BIT_STORES
movd 4(%esp), %xmm0
@@ -27,5 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdisf)
fstps 4(%esp)
flds 4(%esp)
ret
+END_COMPILERRT_FUNCTION(__floatdisf)
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/floatdixf.S b/contrib/compiler-rt/lib/builtins/i386/floatdixf.S
index 412976fb41b1..839b0434c0c6 100644
--- a/contrib/compiler-rt/lib/i386/floatdixf.S
+++ b/contrib/compiler-rt/lib/builtins/i386/floatdixf.S
@@ -15,7 +15,7 @@
// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatdixf)
#ifndef TRUST_CALLERS_USE_64_BIT_STORES
movd 4(%esp), %xmm0
@@ -25,5 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdixf)
#endif
fildll 4(%esp)
ret
+END_COMPILERRT_FUNCTION(__floatdixf)
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/floatundidf.S b/contrib/compiler-rt/lib/builtins/i386/floatundidf.S
index 6bba7e1cf72a..8058c2ac0aed 100644
--- a/contrib/compiler-rt/lib/i386/floatundidf.S
+++ b/contrib/compiler-rt/lib/builtins/i386/floatundidf.S
@@ -17,19 +17,24 @@
#ifdef __i386__
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
twop84_plus_twop52:
- .quad 0x4530000000100000
-twop84: .quad 0x4530000000000000
+ .quad 0x4530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
#define REL_ADDR(_a) (_a)-0b(%eax)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundidf)
movss 8(%esp), %xmm1 // high 32 bits of a
movss 4(%esp), %xmm0 // low 32 bits of a
@@ -42,5 +47,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundidf)
movsd %xmm0, 4(%esp)
fldl 4(%esp)
ret
-
+END_COMPILERRT_FUNCTION(__floatundidf)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/floatundisf.S b/contrib/compiler-rt/lib/builtins/i386/floatundisf.S
index 1afd1d4d05b3..94c97e25aa8c 100644
--- a/contrib/compiler-rt/lib/i386/floatundisf.S
+++ b/contrib/compiler-rt/lib/builtins/i386/floatundisf.S
@@ -18,8 +18,8 @@
#ifdef __i386__
-.const
-.align 3
+CONST_SECTION
+.balign 3
.quad 0x43f0000000000000
twop64: .quad 0x0000000000000000
@@ -27,7 +27,7 @@ twop64: .quad 0x0000000000000000
#define TWOp64 twop64-0b(%ecx,%eax,8)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundisf)
movl 8(%esp), %eax
movd 8(%esp), %xmm1
@@ -42,7 +42,8 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
fstps 4(%esp)
flds 4(%esp)
ret
-
+END_COMPILERRT_FUNCTION(__floatundisf)
+
#endif // __i386__
*/
@@ -51,23 +52,27 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
#ifdef __i386__
-#ifndef __ELF__
-.const
-.align 3
-#else
-.align 8
-#endif
-twop52: .quad 0x4330000000000000
- .quad 0x0000000000000fff
-sticky: .quad 0x0000000000000000
- .long 0x00000012
-twelve: .long 0x00000000
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+ .quad 0x0000000000000fff
+
+ .balign 16
+sticky:
+ .quad 0x0000000000000000
+ .long 0x00000012
+
+ .balign 16
+twelve:
+ .long 0x00000000
#define TWOp52 twop52-0b(%ecx)
#define STICKY sticky-0b(%ecx,%eax,8)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundisf)
movl 8(%esp), %eax
movd 8(%esp), %xmm1
@@ -95,5 +100,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
movd %xmm0, 4(%esp)
flds 4(%esp)
ret
-
+END_COMPILERRT_FUNCTION(__floatundisf)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/floatundixf.S b/contrib/compiler-rt/lib/builtins/i386/floatundixf.S
index 6e6710bd4ac6..814b52f941d8 100644
--- a/contrib/compiler-rt/lib/i386/floatundixf.S
+++ b/contrib/compiler-rt/lib/builtins/i386/floatundixf.S
@@ -7,19 +7,24 @@
#ifdef __i386__
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
twop84_plus_twop52_neg:
- .quad 0xc530000000100000
-twop84: .quad 0x4530000000000000
+ .quad 0xc530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
#define REL_ADDR(_a) (_a)-0b(%eax)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundixf)
calll 0f
0: popl %eax
@@ -33,5 +38,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf)
movsd %xmm0, 4(%esp)
faddl 4(%esp)
ret
-
+END_COMPILERRT_FUNCTION(__floatundixf)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/lshrdi3.S b/contrib/compiler-rt/lib/builtins/i386/lshrdi3.S
index cf411f22e0be..b80f11a3806b 100644
--- a/contrib/compiler-rt/lib/i386/lshrdi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/lshrdi3.S
@@ -16,7 +16,7 @@
#ifdef __SSE2__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
movd 12(%esp), %xmm2 // Load count
#ifndef TRUST_CALLERS_USE_64_BIT_STORES
@@ -31,11 +31,12 @@ DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
psrlq $32, %xmm0
movd %xmm0, %edx
ret
+END_COMPILERRT_FUNCTION(__lshrdi3)
#else // Use GPRs instead of SSE2 instructions, if they aren't available.
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
movl 12(%esp), %ecx // Load count
movl 8(%esp), %edx // Load high
@@ -52,6 +53,7 @@ DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
xorl %edx, %edx // clear high
shrl %cl, %eax // shift low by count - 32
ret
-
+END_COMPILERRT_FUNCTION(__lshrdi3)
+
#endif // __SSE2__
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/moddi3.S b/contrib/compiler-rt/lib/builtins/i386/moddi3.S
index 8839cfc51d95..b9cee9d7aa70 100644
--- a/contrib/compiler-rt/lib/i386/moddi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/moddi3.S
@@ -20,7 +20,7 @@
#ifdef __i386__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__moddi3)
/* This is currently implemented by wrapping the unsigned modulus up in an absolute
@@ -161,6 +161,6 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
xorl %esi, %edx
popl %esi
retl // Return
+END_COMPILERRT_FUNCTION(__moddi3)
-
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/muldi3.S b/contrib/compiler-rt/lib/builtins/i386/muldi3.S
index e56a3553bd31..15b6b4998456 100644
--- a/contrib/compiler-rt/lib/i386/muldi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/muldi3.S
@@ -8,7 +8,7 @@
#ifdef __i386__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__muldi3)
pushl %ebx
movl 16(%esp), %eax // b.lo
@@ -25,5 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__muldi3)
popl %ebx
retl
-
+END_COMPILERRT_FUNCTION(__muldi3)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/udivdi3.S b/contrib/compiler-rt/lib/builtins/i386/udivdi3.S
index 5abeaeaaf476..41b2edf03e34 100644
--- a/contrib/compiler-rt/lib/i386/udivdi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/udivdi3.S
@@ -19,7 +19,7 @@
#ifdef __i386__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__udivdi3)
pushl %ebx
@@ -110,5 +110,6 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3)
movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
popl %ebx //
retl // and return qhi:qlo
-
+END_COMPILERRT_FUNCTION(__udivdi3)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/i386/umoddi3.S b/contrib/compiler-rt/lib/builtins/i386/umoddi3.S
index 7fd84853b5b2..a190a7d397d2 100644
--- a/contrib/compiler-rt/lib/i386/umoddi3.S
+++ b/contrib/compiler-rt/lib/builtins/i386/umoddi3.S
@@ -20,7 +20,7 @@
#ifdef __i386__
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__umoddi3)
pushl %ebx
@@ -121,5 +121,6 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3)
popl %ebx //
xorl %edx, %edx // and return 0:rlo
retl //
-
+END_COMPILERRT_FUNCTION(__umoddi3)
+
#endif // __i386__
diff --git a/contrib/compiler-rt/lib/int_endianness.h b/contrib/compiler-rt/lib/builtins/int_endianness.h
index edb58c810e21..4b35bde079e8 100644
--- a/contrib/compiler-rt/lib/int_endianness.h
+++ b/contrib/compiler-rt/lib/builtins/int_endianness.h
@@ -19,19 +19,22 @@
#if defined(__SVR4) && defined(__sun)
#include <sys/byteorder.h>
-#if _BYTE_ORDER == _BIG_ENDIAN
+#if defined(_BIG_ENDIAN)
#define _YUGA_LITTLE_ENDIAN 0
#define _YUGA_BIG_ENDIAN 1
-#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#elif defined(_LITTLE_ENDIAN)
#define _YUGA_LITTLE_ENDIAN 1
#define _YUGA_BIG_ENDIAN 0
-#endif /* _BYTE_ORDER */
+#else /* !_LITTLE_ENDIAN */
+#error "unknown endianness"
+#endif /* !_LITTLE_ENDIAN */
#endif /* Solaris and AuroraUX. */
/* .. */
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__minix)
#include <sys/endian.h>
#if _BYTE_ORDER == _BIG_ENDIAN
@@ -59,8 +62,9 @@
/* .. */
-/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */
-#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ )
+/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
+ * compiler (at least with GCC) */
+#if defined(__APPLE__) || defined(__ellcc__ )
#ifdef __BIG_ENDIAN__
#if __BIG_ENDIAN__
@@ -81,15 +85,14 @@
/* .. */
#if defined(__linux__)
-#include <endian.h>
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define _YUGA_LITTLE_ENDIAN 0
#define _YUGA_BIG_ENDIAN 1
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define _YUGA_LITTLE_ENDIAN 1
#define _YUGA_BIG_ENDIAN 0
-#endif /* __BYTE_ORDER */
+#endif /* __BYTE_ORDER__ */
#endif /* GNU/Linux */
diff --git a/contrib/compiler-rt/lib/int_lib.h b/contrib/compiler-rt/lib/builtins/int_lib.h
index 594e8128827d..3486ceff77af 100644
--- a/contrib/compiler-rt/lib/int_lib.h
+++ b/contrib/compiler-rt/lib/builtins/int_lib.h
@@ -39,11 +39,21 @@
# define COMPILER_RT_ABI
#endif
+#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
+/*
+ * Kernel and boot environment can't use normal headers,
+ * so use the equivalent system headers.
+ */
+# include <machine/limits.h>
+# include <sys/stdint.h>
+# include <sys/types.h>
+#else
/* Include the standard compiler builtin headers we use functionality from. */
-#include <limits.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <float.h>
+# include <limits.h>
+# include <stdint.h>
+# include <stdbool.h>
+# include <float.h>
+#endif
/* Include the commonly used internal type definitions. */
#include "int_types.h"
@@ -67,8 +77,22 @@
defined(__mips_n64) || defined(__mips_o64))
si_int __clzsi2(si_int);
si_int __ctzsi2(si_int);
-#define __builtin_clz __clzsi2
-#define __builtin_ctz __ctzsi2
+#define __builtin_clz __clzsi2
+#define __builtin_ctz __ctzsi2
+#endif /* FreeBSD && (sparc64 || mips_n64 || mips_o64) */
+
+COMPILER_RT_ABI si_int __paritysi2(si_int a);
+COMPILER_RT_ABI si_int __paritydi2(di_int a);
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
+COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
+COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
+
+COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int* rem);
+COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem);
+#ifdef CRT_HAS_128BIT
+COMPILER_RT_ABI si_int __clzti2(ti_int a);
+COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
#endif
#endif /* INT_LIB_H */
diff --git a/contrib/compiler-rt/lib/int_math.h b/contrib/compiler-rt/lib/builtins/int_math.h
index d6b4bdae162b..d6b4bdae162b 100644
--- a/contrib/compiler-rt/lib/int_math.h
+++ b/contrib/compiler-rt/lib/builtins/int_math.h
diff --git a/contrib/compiler-rt/lib/int_types.h b/contrib/compiler-rt/lib/builtins/int_types.h
index 5107f71550ac..aedae14b2046 100644
--- a/contrib/compiler-rt/lib/int_types.h
+++ b/contrib/compiler-rt/lib/builtins/int_types.h
@@ -56,7 +56,8 @@ typedef union
}s;
} udwords;
-#if __LP64__
+/* MIPS64 issue: PR 20098 */
+#if defined(__LP64__) && !(defined(__mips__) && defined(__clang__))
#define CRT_HAS_128BIT
#endif
diff --git a/contrib/compiler-rt/lib/int_util.c b/contrib/compiler-rt/lib/builtins/int_util.c
index 871d191658cb..323e46179e6c 100644
--- a/contrib/compiler-rt/lib/int_util.c
+++ b/contrib/compiler-rt/lib/builtins/int_util.c
@@ -24,31 +24,36 @@
#ifdef KERNEL_USE
extern void panic(const char *, ...) __attribute__((noreturn));
+#ifndef _WIN32
__attribute__((visibility("hidden")))
+#endif
void compilerrt_abort_impl(const char *file, int line, const char *function) {
panic("%s:%d: abort in %s", file, line, function);
}
-#elif __APPLE__ && !__STATIC__
+#elif __APPLE__
/* from libSystem.dylib */
extern void __assert_rtn(const char *func, const char *file,
int line, const char * message) __attribute__((noreturn));
+#ifndef _WIN32
__attribute__((weak))
__attribute__((visibility("hidden")))
+#endif
void compilerrt_abort_impl(const char *file, int line, const char *function) {
__assert_rtn(function, file, line, "libcompiler_rt abort");
}
-
#else
/* Get the system definition of abort() */
#include <stdlib.h>
+#ifndef _WIN32
__attribute__((weak))
__attribute__((visibility("hidden")))
+#endif
void compilerrt_abort_impl(const char *file, int line, const char *function) {
abort();
}
diff --git a/contrib/compiler-rt/lib/int_util.h b/contrib/compiler-rt/lib/builtins/int_util.h
index 1348b85eb923..a9b595db8d0f 100644
--- a/contrib/compiler-rt/lib/int_util.h
+++ b/contrib/compiler-rt/lib/builtins/int_util.h
@@ -21,7 +21,7 @@
/** \brief Trigger a program abort (or panic for kernel code). */
#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \
- __FUNCTION__)
+ __func__)
void compilerrt_abort_impl(const char *file, int line,
const char *function) __attribute__((noreturn));
diff --git a/contrib/compiler-rt/lib/lshrdi3.c b/contrib/compiler-rt/lib/builtins/lshrdi3.c
index 6b1ea923b778..6b1ea923b778 100644
--- a/contrib/compiler-rt/lib/lshrdi3.c
+++ b/contrib/compiler-rt/lib/builtins/lshrdi3.c
diff --git a/contrib/compiler-rt/lib/lshrti3.c b/contrib/compiler-rt/lib/builtins/lshrti3.c
index 6fc4e1f426d2..e4170ff84a5a 100644
--- a/contrib/compiler-rt/lib/lshrti3.c
+++ b/contrib/compiler-rt/lib/builtins/lshrti3.c
@@ -20,7 +20,7 @@
/* Precondition: 0 <= b < bits_in_tword */
-ti_int
+COMPILER_RT_ABI ti_int
__lshrti3(ti_int a, si_int b)
{
const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/moddi3.c b/contrib/compiler-rt/lib/builtins/moddi3.c
index 2f3b9cc4f291..a04279e3875f 100644
--- a/contrib/compiler-rt/lib/moddi3.c
+++ b/contrib/compiler-rt/lib/builtins/moddi3.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem);
-
/* Returns: a % b */
COMPILER_RT_ABI di_int
@@ -26,7 +24,7 @@ __moddi3(di_int a, di_int b)
b = (b ^ s) - s; /* negate if s == -1 */
s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */
a = (a ^ s) - s; /* negate if s == -1 */
- di_int r;
- __udivmoddi4(a, b, (du_int*)&r);
- return (r ^ s) - s; /* negate if s == -1 */
+ du_int r;
+ __udivmoddi4(a, b, &r);
+ return ((di_int)r ^ s) - s; /* negate if s == -1 */
}
diff --git a/contrib/compiler-rt/lib/modsi3.c b/contrib/compiler-rt/lib/builtins/modsi3.c
index d16213c49038..86c73ce13777 100644
--- a/contrib/compiler-rt/lib/modsi3.c
+++ b/contrib/compiler-rt/lib/builtins/modsi3.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-su_int COMPILER_RT_ABI __divsi3(si_int a, si_int b);
-
/* Returns: a % b */
COMPILER_RT_ABI si_int
diff --git a/contrib/compiler-rt/lib/modti3.c b/contrib/compiler-rt/lib/builtins/modti3.c
index ded24a01779a..d505c07ac162 100644
--- a/contrib/compiler-rt/lib/modti3.c
+++ b/contrib/compiler-rt/lib/builtins/modti3.c
@@ -16,11 +16,9 @@
#ifdef CRT_HAS_128BIT
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
/*Returns: a % b */
-ti_int
+COMPILER_RT_ABI ti_int
__modti3(ti_int a, ti_int b)
{
const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
@@ -28,9 +26,9 @@ __modti3(ti_int a, ti_int b)
b = (b ^ s) - s; /* negate if s == -1 */
s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */
a = (a ^ s) - s; /* negate if s == -1 */
- ti_int r;
- __udivmodti4(a, b, (tu_int*)&r);
- return (r ^ s) - s; /* negate if s == -1 */
+ tu_int r;
+ __udivmodti4(a, b, &r);
+ return ((ti_int)r ^ s) - s; /* negate if s == -1 */
}
#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/muldc3.c b/contrib/compiler-rt/lib/builtins/muldc3.c
index 5f4a6d16ebf0..3bfae2c52224 100644
--- a/contrib/compiler-rt/lib/muldc3.c
+++ b/contrib/compiler-rt/lib/builtins/muldc3.c
@@ -17,7 +17,7 @@
/* Returns: the product of a + ib and c + id */
-double _Complex
+COMPILER_RT_ABI double _Complex
__muldc3(double __a, double __b, double __c, double __d)
{
double __ac = __a * __c;
diff --git a/contrib/compiler-rt/lib/builtins/muldf3.c b/contrib/compiler-rt/lib/builtins/muldf3.c
new file mode 100644
index 000000000000..1eb733849e5a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/muldf3.c
@@ -0,0 +1,22 @@
+//===-- lib/muldf3.c - Double-precision multiplication ------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_mul_impl.inc"
+
+ARM_EABI_FNALIAS(dmul, muldf3)
+
+COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
diff --git a/contrib/compiler-rt/lib/muldi3.c b/contrib/compiler-rt/lib/builtins/muldi3.c
index 2dae44c11b95..2dae44c11b95 100644
--- a/contrib/compiler-rt/lib/muldi3.c
+++ b/contrib/compiler-rt/lib/builtins/muldi3.c
diff --git a/contrib/compiler-rt/lib/mulodi4.c b/contrib/compiler-rt/lib/builtins/mulodi4.c
index 0c1b5cdae768..d2fd7db2bcd3 100644
--- a/contrib/compiler-rt/lib/mulodi4.c
+++ b/contrib/compiler-rt/lib/builtins/mulodi4.c
@@ -18,7 +18,7 @@
/* Effects: sets *overflow to 1 if a * b overflows */
-di_int
+COMPILER_RT_ABI di_int
__mulodi4(di_int a, di_int b, int* overflow)
{
const int N = (int)(sizeof(di_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/mulosi4.c b/contrib/compiler-rt/lib/builtins/mulosi4.c
index f3398d1fc7bd..422528085c44 100644
--- a/contrib/compiler-rt/lib/mulosi4.c
+++ b/contrib/compiler-rt/lib/builtins/mulosi4.c
@@ -18,7 +18,7 @@
/* Effects: sets *overflow to 1 if a * b overflows */
-si_int
+COMPILER_RT_ABI si_int
__mulosi4(si_int a, si_int b, int* overflow)
{
const int N = (int)(sizeof(si_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/muloti4.c b/contrib/compiler-rt/lib/builtins/muloti4.c
index 0aa6f3b4c495..16b218920321 100644
--- a/contrib/compiler-rt/lib/muloti4.c
+++ b/contrib/compiler-rt/lib/builtins/muloti4.c
@@ -20,7 +20,7 @@
/* Effects: sets *overflow to 1 if a * b overflows */
-ti_int
+COMPILER_RT_ABI ti_int
__muloti4(ti_int a, ti_int b, int* overflow)
{
const int N = (int)(sizeof(ti_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/mulsc3.c b/contrib/compiler-rt/lib/builtins/mulsc3.c
index 6d433fbc45f9..29d46c63a799 100644
--- a/contrib/compiler-rt/lib/mulsc3.c
+++ b/contrib/compiler-rt/lib/builtins/mulsc3.c
@@ -17,7 +17,7 @@
/* Returns: the product of a + ib and c + id */
-float _Complex
+COMPILER_RT_ABI float _Complex
__mulsc3(float __a, float __b, float __c, float __d)
{
float __ac = __a * __c;
diff --git a/contrib/compiler-rt/lib/builtins/mulsf3.c b/contrib/compiler-rt/lib/builtins/mulsf3.c
new file mode 100644
index 000000000000..478b3bc0e0e0
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/mulsf3.c
@@ -0,0 +1,22 @@
+//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_mul_impl.inc"
+
+ARM_EABI_FNALIAS(fmul, mulsf3)
+
+COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
diff --git a/contrib/compiler-rt/lib/builtins/multc3.c b/contrib/compiler-rt/lib/builtins/multc3.c
new file mode 100644
index 000000000000..b9953cfd6111
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/multc3.c
@@ -0,0 +1,73 @@
+/* ===-- multc3.c - Implement __multc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __multc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI long double _Complex
+__multc3(long double __a, long double __b, long double __c, long double __d)
+{
+ long double __ac = __a * __c;
+ long double __bd = __b * __d;
+ long double __ad = __a * __d;
+ long double __bc = __b * __c;
+ long double _Complex z;
+ __real__ z = __ac - __bd;
+ __imag__ z = __ad + __bc;
+ if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc)
+ {
+ __real__ z = CRT_INFINITY * (__a * __c - __b * __d);
+ __imag__ z = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
+}
diff --git a/contrib/compiler-rt/lib/builtins/multf3.c b/contrib/compiler-rt/lib/builtins/multf3.c
new file mode 100644
index 000000000000..0b915923ea09
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/multf3.c
@@ -0,0 +1,25 @@
+//===-- lib/multf3.c - Quad-precision multiplication --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#include "fp_mul_impl.inc"
+
+COMPILER_RT_ABI fp_t __multf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/multi3.c b/contrib/compiler-rt/lib/builtins/multi3.c
index 85a6cf45f72a..e0d52d430b66 100644
--- a/contrib/compiler-rt/lib/multi3.c
+++ b/contrib/compiler-rt/lib/builtins/multi3.c
@@ -42,7 +42,7 @@ __mulddi3(du_int a, du_int b)
/* Returns: a * b */
-ti_int
+COMPILER_RT_ABI ti_int
__multi3(ti_int a, ti_int b)
{
twords x;
diff --git a/contrib/compiler-rt/lib/mulvdi3.c b/contrib/compiler-rt/lib/builtins/mulvdi3.c
index bcc8e659be48..e63249e0a04c 100644
--- a/contrib/compiler-rt/lib/mulvdi3.c
+++ b/contrib/compiler-rt/lib/builtins/mulvdi3.c
@@ -18,7 +18,7 @@
/* Effects: aborts if a * b overflows */
-di_int
+COMPILER_RT_ABI di_int
__mulvdi3(di_int a, di_int b)
{
const int N = (int)(sizeof(di_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/mulvsi3.c b/contrib/compiler-rt/lib/builtins/mulvsi3.c
index d372b20175ed..74ea4f2da226 100644
--- a/contrib/compiler-rt/lib/mulvsi3.c
+++ b/contrib/compiler-rt/lib/builtins/mulvsi3.c
@@ -18,7 +18,7 @@
/* Effects: aborts if a * b overflows */
-si_int
+COMPILER_RT_ABI si_int
__mulvsi3(si_int a, si_int b)
{
const int N = (int)(sizeof(si_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/mulvti3.c b/contrib/compiler-rt/lib/builtins/mulvti3.c
index 11d239ac96f2..f4c7d1612ba9 100644
--- a/contrib/compiler-rt/lib/mulvti3.c
+++ b/contrib/compiler-rt/lib/builtins/mulvti3.c
@@ -20,7 +20,7 @@
/* Effects: aborts if a * b overflows */
-ti_int
+COMPILER_RT_ABI ti_int
__mulvti3(ti_int a, ti_int b)
{
const int N = (int)(sizeof(ti_int) * CHAR_BIT);
diff --git a/contrib/compiler-rt/lib/mulxc3.c b/contrib/compiler-rt/lib/builtins/mulxc3.c
index cec0573688ad..161fd0ce0dd4 100644
--- a/contrib/compiler-rt/lib/mulxc3.c
+++ b/contrib/compiler-rt/lib/builtins/mulxc3.c
@@ -19,7 +19,7 @@
/* Returns: the product of a + ib and c + id */
-long double _Complex
+COMPILER_RT_ABI long double _Complex
__mulxc3(long double __a, long double __b, long double __c, long double __d)
{
long double __ac = __a * __c;
diff --git a/contrib/compiler-rt/lib/negdf2.c b/contrib/compiler-rt/lib/builtins/negdf2.c
index 4e17513a9d00..d634b421cb79 100644
--- a/contrib/compiler-rt/lib/negdf2.c
+++ b/contrib/compiler-rt/lib/builtins/negdf2.c
@@ -16,6 +16,7 @@
ARM_EABI_FNALIAS(dneg, negdf2)
-fp_t __negdf2(fp_t a) {
+COMPILER_RT_ABI fp_t
+__negdf2(fp_t a) {
return fromRep(toRep(a) ^ signBit);
}
diff --git a/contrib/compiler-rt/lib/negdi2.c b/contrib/compiler-rt/lib/builtins/negdi2.c
index b000dda3b83d..3d49ba2899d2 100644
--- a/contrib/compiler-rt/lib/negdi2.c
+++ b/contrib/compiler-rt/lib/builtins/negdi2.c
@@ -16,7 +16,7 @@
/* Returns: -a */
-di_int
+COMPILER_RT_ABI di_int
__negdi2(di_int a)
{
/* Note: this routine is here for API compatibility; any sane compiler
diff --git a/contrib/compiler-rt/lib/negsf2.c b/contrib/compiler-rt/lib/builtins/negsf2.c
index 29c17be4145f..29c17be4145f 100644
--- a/contrib/compiler-rt/lib/negsf2.c
+++ b/contrib/compiler-rt/lib/builtins/negsf2.c
diff --git a/contrib/compiler-rt/lib/negti2.c b/contrib/compiler-rt/lib/builtins/negti2.c
index 28ef941e3712..9b00b303f856 100644
--- a/contrib/compiler-rt/lib/negti2.c
+++ b/contrib/compiler-rt/lib/builtins/negti2.c
@@ -18,7 +18,7 @@
/* Returns: -a */
-ti_int
+COMPILER_RT_ABI ti_int
__negti2(ti_int a)
{
/* Note: this routine is here for API compatibility; any sane compiler
diff --git a/contrib/compiler-rt/lib/negvdi2.c b/contrib/compiler-rt/lib/builtins/negvdi2.c
index e336ecf28f0d..e336ecf28f0d 100644
--- a/contrib/compiler-rt/lib/negvdi2.c
+++ b/contrib/compiler-rt/lib/builtins/negvdi2.c
diff --git a/contrib/compiler-rt/lib/negvsi2.c b/contrib/compiler-rt/lib/builtins/negvsi2.c
index b9e93fef06c5..b9e93fef06c5 100644
--- a/contrib/compiler-rt/lib/negvsi2.c
+++ b/contrib/compiler-rt/lib/builtins/negvsi2.c
diff --git a/contrib/compiler-rt/lib/negvti2.c b/contrib/compiler-rt/lib/builtins/negvti2.c
index d15167f53578..85f9f7d19d9d 100644
--- a/contrib/compiler-rt/lib/negvti2.c
+++ b/contrib/compiler-rt/lib/builtins/negvti2.c
@@ -20,7 +20,7 @@
/* Effects: aborts if -a overflows */
-ti_int
+COMPILER_RT_ABI ti_int
__negvti2(ti_int a)
{
const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1);
diff --git a/contrib/compiler-rt/lib/paritydi2.c b/contrib/compiler-rt/lib/builtins/paritydi2.c
index 2ded54c90b93..8ea5ab4214e9 100644
--- a/contrib/compiler-rt/lib/paritydi2.c
+++ b/contrib/compiler-rt/lib/builtins/paritydi2.c
@@ -16,8 +16,6 @@
/* Returns: 1 if number of bits is odd else returns 0 */
-si_int COMPILER_RT_ABI __paritysi2(si_int a);
-
COMPILER_RT_ABI si_int
__paritydi2(di_int a)
{
diff --git a/contrib/compiler-rt/lib/paritysi2.c b/contrib/compiler-rt/lib/builtins/paritysi2.c
index 599984663849..599984663849 100644
--- a/contrib/compiler-rt/lib/paritysi2.c
+++ b/contrib/compiler-rt/lib/builtins/paritysi2.c
diff --git a/contrib/compiler-rt/lib/parityti2.c b/contrib/compiler-rt/lib/builtins/parityti2.c
index fa2838087d66..5a4fe492486f 100644
--- a/contrib/compiler-rt/lib/parityti2.c
+++ b/contrib/compiler-rt/lib/builtins/parityti2.c
@@ -18,9 +18,7 @@
/* Returns: 1 if number of bits is odd else returns 0 */
-si_int __paritydi2(di_int a);
-
-si_int
+COMPILER_RT_ABI si_int
__parityti2(ti_int a)
{
twords x;
diff --git a/contrib/compiler-rt/lib/popcountdi2.c b/contrib/compiler-rt/lib/builtins/popcountdi2.c
index 5e8a62f075eb..5e8a62f075eb 100644
--- a/contrib/compiler-rt/lib/popcountdi2.c
+++ b/contrib/compiler-rt/lib/builtins/popcountdi2.c
diff --git a/contrib/compiler-rt/lib/popcountsi2.c b/contrib/compiler-rt/lib/builtins/popcountsi2.c
index 44544ff49890..44544ff49890 100644
--- a/contrib/compiler-rt/lib/popcountsi2.c
+++ b/contrib/compiler-rt/lib/builtins/popcountsi2.c
diff --git a/contrib/compiler-rt/lib/popcountti2.c b/contrib/compiler-rt/lib/builtins/popcountti2.c
index d7223d926eea..7451bbb286b7 100644
--- a/contrib/compiler-rt/lib/popcountti2.c
+++ b/contrib/compiler-rt/lib/builtins/popcountti2.c
@@ -18,7 +18,7 @@
/* Returns: count of 1 bits */
-si_int
+COMPILER_RT_ABI si_int
__popcountti2(ti_int a)
{
tu_int x3 = (tu_int)a;
diff --git a/contrib/compiler-rt/lib/powidf2.c b/contrib/compiler-rt/lib/builtins/powidf2.c
index ac13b172b043..ac13b172b043 100644
--- a/contrib/compiler-rt/lib/powidf2.c
+++ b/contrib/compiler-rt/lib/builtins/powidf2.c
diff --git a/contrib/compiler-rt/lib/powisf2.c b/contrib/compiler-rt/lib/builtins/powisf2.c
index 0c400ec6dd6a..0c400ec6dd6a 100644
--- a/contrib/compiler-rt/lib/powisf2.c
+++ b/contrib/compiler-rt/lib/builtins/powisf2.c
diff --git a/contrib/compiler-rt/lib/powitf2.c b/contrib/compiler-rt/lib/builtins/powitf2.c
index d3b934924f3e..172f29f58f25 100644
--- a/contrib/compiler-rt/lib/powitf2.c
+++ b/contrib/compiler-rt/lib/builtins/powitf2.c
@@ -18,7 +18,7 @@
/* Returns: a ^ b */
-long double
+COMPILER_RT_ABI long double
__powitf2(long double a, si_int b)
{
const int recip = b < 0;
diff --git a/contrib/compiler-rt/lib/powixf2.c b/contrib/compiler-rt/lib/builtins/powixf2.c
index f050964d3597..0fd96e503e7b 100644
--- a/contrib/compiler-rt/lib/powixf2.c
+++ b/contrib/compiler-rt/lib/builtins/powixf2.c
@@ -18,7 +18,7 @@
/* Returns: a ^ b */
-long double
+COMPILER_RT_ABI long double
__powixf2(long double a, si_int b)
{
const int recip = b < 0;
diff --git a/contrib/compiler-rt/lib/ppc/DD.h b/contrib/compiler-rt/lib/builtins/ppc/DD.h
index 13862dc98404..fc3e41cbe07e 100644
--- a/contrib/compiler-rt/lib/ppc/DD.h
+++ b/contrib/compiler-rt/lib/builtins/ppc/DD.h
@@ -20,7 +20,7 @@ typedef union {
(((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo))
static inline double __attribute__((always_inline))
-fabs(double x)
+local_fabs(double x)
{
doublebits result = { .d = x };
result.x &= UINT64_C(0x7fffffffffffffff);
diff --git a/contrib/compiler-rt/lib/ppc/divtc3.c b/contrib/compiler-rt/lib/builtins/ppc/divtc3.c
index 299128186312..299128186312 100644
--- a/contrib/compiler-rt/lib/ppc/divtc3.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/divtc3.c
diff --git a/contrib/compiler-rt/lib/ppc/fixtfdi.c b/contrib/compiler-rt/lib/builtins/ppc/fixtfdi.c
index 56e7b3fbf3e5..2c7c0f8e279f 100644
--- a/contrib/compiler-rt/lib/ppc/fixtfdi.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/fixtfdi.c
@@ -25,7 +25,7 @@ uint64_t __fixtfdi(long double input)
int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */
result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
- result <<= 10; /* mantissa(hi) with one zero preceeding bit. */
+ result <<= 10; /* mantissa(hi) with one zero preceding bit. */
const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63;
diff --git a/contrib/compiler-rt/lib/ppc/fixunstfdi.c b/contrib/compiler-rt/lib/builtins/ppc/fixunstfdi.c
index 5e6e2cedf6ac..5e6e2cedf6ac 100644
--- a/contrib/compiler-rt/lib/ppc/fixunstfdi.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/fixunstfdi.c
diff --git a/contrib/compiler-rt/lib/ppc/floatditf.c b/contrib/compiler-rt/lib/builtins/ppc/floatditf.c
index beabdd017422..beabdd017422 100644
--- a/contrib/compiler-rt/lib/ppc/floatditf.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/floatditf.c
diff --git a/contrib/compiler-rt/lib/ppc/floatunditf.c b/contrib/compiler-rt/lib/builtins/ppc/floatunditf.c
index b12e1e738fd0..b12e1e738fd0 100644
--- a/contrib/compiler-rt/lib/ppc/floatunditf.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/floatunditf.c
diff --git a/contrib/compiler-rt/lib/ppc/gcc_qadd.c b/contrib/compiler-rt/lib/builtins/ppc/gcc_qadd.c
index c388c7e99c6e..32e16e9d1d11 100644
--- a/contrib/compiler-rt/lib/ppc/gcc_qadd.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/gcc_qadd.c
@@ -55,7 +55,7 @@ long double __gcc_qadd(long double x, long double y)
h = A + (B - (A + B));
t = a + (b - (a + b));
- if (fabs(A) <= fabs(B))
+ if (local_fabs(A) <= local_fabs(B))
w = (a + b) + h;
else
w = (a + b) + H;
@@ -64,7 +64,7 @@ long double __gcc_qadd(long double x, long double y)
Y = (A + B) - W;
Y += w;
- if (fabs(a) <= fabs(b))
+ if (local_fabs(a) <= local_fabs(b))
w = t + Y;
else
w = T + Y;
diff --git a/contrib/compiler-rt/lib/ppc/gcc_qdiv.c b/contrib/compiler-rt/lib/builtins/ppc/gcc_qdiv.c
index 70aa00b64400..70aa00b64400 100644
--- a/contrib/compiler-rt/lib/ppc/gcc_qdiv.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/gcc_qdiv.c
diff --git a/contrib/compiler-rt/lib/ppc/gcc_qmul.c b/contrib/compiler-rt/lib/builtins/ppc/gcc_qmul.c
index fb4c5164ccb5..fb4c5164ccb5 100644
--- a/contrib/compiler-rt/lib/ppc/gcc_qmul.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/gcc_qmul.c
diff --git a/contrib/compiler-rt/lib/ppc/gcc_qsub.c b/contrib/compiler-rt/lib/builtins/ppc/gcc_qsub.c
index 4f1f7ac70f3c..c092e24dbda1 100644
--- a/contrib/compiler-rt/lib/ppc/gcc_qsub.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/gcc_qsub.c
@@ -55,7 +55,7 @@ long double __gcc_qsub(long double x, long double y)
h = A + (B - (A + B));
t = a + (b - (a + b));
- if (fabs(A) <= fabs(B))
+ if (local_fabs(A) <= local_fabs(B))
w = (a + b) + h;
else
w = (a + b) + H;
@@ -64,7 +64,7 @@ long double __gcc_qsub(long double x, long double y)
Y = (A + B) - W;
Y += w;
- if (fabs(a) <= fabs(b))
+ if (local_fabs(a) <= local_fabs(b))
w = t + Y;
else
w = T + Y;
diff --git a/contrib/compiler-rt/lib/ppc/multc3.c b/contrib/compiler-rt/lib/builtins/ppc/multc3.c
index 738b65a83b03..738b65a83b03 100644
--- a/contrib/compiler-rt/lib/ppc/multc3.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/multc3.c
diff --git a/contrib/compiler-rt/lib/ppc/restFP.S b/contrib/compiler-rt/lib/builtins/ppc/restFP.S
index 95032897c0da..95032897c0da 100644
--- a/contrib/compiler-rt/lib/ppc/restFP.S
+++ b/contrib/compiler-rt/lib/builtins/ppc/restFP.S
diff --git a/contrib/compiler-rt/lib/ppc/saveFP.S b/contrib/compiler-rt/lib/builtins/ppc/saveFP.S
index 72bd459f4cc0..72bd459f4cc0 100644
--- a/contrib/compiler-rt/lib/ppc/saveFP.S
+++ b/contrib/compiler-rt/lib/builtins/ppc/saveFP.S
diff --git a/contrib/compiler-rt/lib/sparc64/divmod.m4 b/contrib/compiler-rt/lib/builtins/sparc64/divmod.m4
index 9150a2ed8263..9150a2ed8263 100644
--- a/contrib/compiler-rt/lib/sparc64/divmod.m4
+++ b/contrib/compiler-rt/lib/builtins/sparc64/divmod.m4
diff --git a/contrib/compiler-rt/lib/sparc64/divsi3.S b/contrib/compiler-rt/lib/builtins/sparc64/divsi3.S
index 70fc1f407f48..70fc1f407f48 100644
--- a/contrib/compiler-rt/lib/sparc64/divsi3.S
+++ b/contrib/compiler-rt/lib/builtins/sparc64/divsi3.S
diff --git a/contrib/compiler-rt/lib/sparc64/generate.sh b/contrib/compiler-rt/lib/builtins/sparc64/generate.sh
index 17c1106f9900..17c1106f9900 100644
--- a/contrib/compiler-rt/lib/sparc64/generate.sh
+++ b/contrib/compiler-rt/lib/builtins/sparc64/generate.sh
diff --git a/contrib/compiler-rt/lib/sparc64/modsi3.S b/contrib/compiler-rt/lib/builtins/sparc64/modsi3.S
index e126e3d3d45e..e126e3d3d45e 100644
--- a/contrib/compiler-rt/lib/sparc64/modsi3.S
+++ b/contrib/compiler-rt/lib/builtins/sparc64/modsi3.S
diff --git a/contrib/compiler-rt/lib/sparc64/udivsi3.S b/contrib/compiler-rt/lib/builtins/sparc64/udivsi3.S
index a41885276dfd..a41885276dfd 100644
--- a/contrib/compiler-rt/lib/sparc64/udivsi3.S
+++ b/contrib/compiler-rt/lib/builtins/sparc64/udivsi3.S
diff --git a/contrib/compiler-rt/lib/sparc64/umodsi3.S b/contrib/compiler-rt/lib/builtins/sparc64/umodsi3.S
index a41885276dfd..a41885276dfd 100644
--- a/contrib/compiler-rt/lib/sparc64/umodsi3.S
+++ b/contrib/compiler-rt/lib/builtins/sparc64/umodsi3.S
diff --git a/contrib/compiler-rt/lib/subdf3.c b/contrib/compiler-rt/lib/builtins/subdf3.c
index 66fb1a54fca1..089e062415b7 100644
--- a/contrib/compiler-rt/lib/subdf3.c
+++ b/contrib/compiler-rt/lib/builtins/subdf3.c
@@ -15,9 +15,6 @@
#define DOUBLE_PRECISION
#include "fp_lib.h"
-fp_t COMPILER_RT_ABI __adddf3(fp_t a, fp_t b);
-
-
ARM_EABI_FNALIAS(dsub, subdf3)
// Subtraction; flip the sign bit of b and add.
diff --git a/contrib/compiler-rt/lib/subsf3.c b/contrib/compiler-rt/lib/builtins/subsf3.c
index 3659cd8b8222..47f5e5e46ea8 100644
--- a/contrib/compiler-rt/lib/subsf3.c
+++ b/contrib/compiler-rt/lib/builtins/subsf3.c
@@ -15,8 +15,6 @@
#define SINGLE_PRECISION
#include "fp_lib.h"
-fp_t COMPILER_RT_ABI __addsf3(fp_t a, fp_t b);
-
ARM_EABI_FNALIAS(fsub, subsf3)
// Subtraction; flip the sign bit of b and add.
diff --git a/contrib/compiler-rt/lib/builtins/subtf3.c b/contrib/compiler-rt/lib/builtins/subtf3.c
new file mode 100644
index 000000000000..609b816f41e3
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/subtf3.c
@@ -0,0 +1,27 @@
+//===-- lib/subtf3.c - Quad-precision subtraction -----------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __addtf3(fp_t a, fp_t b);
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__subtf3(fp_t a, fp_t b) {
+ return __addtf3(a, fromRep(toRep(b) ^ signBit));
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/subvdi3.c b/contrib/compiler-rt/lib/builtins/subvdi3.c
index 0f1f924effc7..71fc70ffa92d 100644
--- a/contrib/compiler-rt/lib/subvdi3.c
+++ b/contrib/compiler-rt/lib/builtins/subvdi3.c
@@ -21,7 +21,7 @@
COMPILER_RT_ABI di_int
__subvdi3(di_int a, di_int b)
{
- di_int s = a - b;
+ di_int s = (du_int) a - (du_int) b;
if (b >= 0)
{
if (s > a)
diff --git a/contrib/compiler-rt/lib/subvsi3.c b/contrib/compiler-rt/lib/builtins/subvsi3.c
index ec4594c9f0e9..e6c0fb688c97 100644
--- a/contrib/compiler-rt/lib/subvsi3.c
+++ b/contrib/compiler-rt/lib/builtins/subvsi3.c
@@ -21,7 +21,7 @@
COMPILER_RT_ABI si_int
__subvsi3(si_int a, si_int b)
{
- si_int s = a - b;
+ si_int s = (su_int) a - (su_int) b;
if (b >= 0)
{
if (s > a)
diff --git a/contrib/compiler-rt/lib/subvti3.c b/contrib/compiler-rt/lib/builtins/subvti3.c
index 20a0814fc58d..a6804d2d7b95 100644
--- a/contrib/compiler-rt/lib/subvti3.c
+++ b/contrib/compiler-rt/lib/builtins/subvti3.c
@@ -20,10 +20,10 @@
/* Effects: aborts if a - b overflows */
-ti_int
+COMPILER_RT_ABI ti_int
__subvti3(ti_int a, ti_int b)
{
- ti_int s = a - b;
+ ti_int s = (tu_int) a - (tu_int) b;
if (b >= 0)
{
if (s > a)
diff --git a/contrib/compiler-rt/lib/trampoline_setup.c b/contrib/compiler-rt/lib/builtins/trampoline_setup.c
index e0765b16b0b0..25b627ab7658 100644
--- a/contrib/compiler-rt/lib/trampoline_setup.c
+++ b/contrib/compiler-rt/lib/builtins/trampoline_setup.c
@@ -21,8 +21,9 @@ extern void __clear_cache(void* start, void* end);
*/
#if __ppc__ && !defined(__powerpc64__)
-void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
- const void* realFunc, void* localsPtr)
+COMPILER_RT_ABI void
+__trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
+ const void* realFunc, void* localsPtr)
{
/* should never happen, but if compiler did not allocate */
/* enough space on stack for the trampoline, abort */
diff --git a/contrib/compiler-rt/lib/builtins/truncdfsf2.c b/contrib/compiler-rt/lib/builtins/truncdfsf2.c
new file mode 100644
index 000000000000..46ec11dccd79
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/truncdfsf2.c
@@ -0,0 +1,18 @@
+//===-- lib/truncdfsf2.c - double -> single conversion ------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_DOUBLE
+#define DST_SINGLE
+#include "fp_trunc_impl.inc"
+
+ARM_EABI_FNALIAS(d2f, truncdfsf2)
+
+COMPILER_RT_ABI float __truncdfsf2(double a) {
+ return __truncXfYf2__(a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/trunctfdf2.c b/contrib/compiler-rt/lib/builtins/trunctfdf2.c
new file mode 100644
index 000000000000..741a71b33c5a
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/trunctfdf2.c
@@ -0,0 +1,22 @@
+//===-- lib/truncdfsf2.c - quad -> double conversion --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_QUAD
+#define DST_DOUBLE
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI double __trunctfdf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/trunctfsf2.c b/contrib/compiler-rt/lib/builtins/trunctfsf2.c
new file mode 100644
index 000000000000..de96c1decf63
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/trunctfsf2.c
@@ -0,0 +1,22 @@
+//===-- lib/trunctfsf2.c - quad -> single conversion --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_QUAD
+#define DST_SINGLE
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI float __trunctfsf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/ucmpdi2.c b/contrib/compiler-rt/lib/builtins/ucmpdi2.c
index 40af23613b1f..40af23613b1f 100644
--- a/contrib/compiler-rt/lib/ucmpdi2.c
+++ b/contrib/compiler-rt/lib/builtins/ucmpdi2.c
diff --git a/contrib/compiler-rt/lib/ucmpti2.c b/contrib/compiler-rt/lib/builtins/ucmpti2.c
index 95d1ff836436..bda8083bb2a1 100644
--- a/contrib/compiler-rt/lib/ucmpti2.c
+++ b/contrib/compiler-rt/lib/builtins/ucmpti2.c
@@ -21,7 +21,7 @@
* if (a > b) returns 2
*/
-si_int
+COMPILER_RT_ABI si_int
__ucmpti2(tu_int a, tu_int b)
{
utwords x;
diff --git a/contrib/compiler-rt/lib/udivdi3.c b/contrib/compiler-rt/lib/builtins/udivdi3.c
index 6c0303df3d40..dc68e154b109 100644
--- a/contrib/compiler-rt/lib/udivdi3.c
+++ b/contrib/compiler-rt/lib/builtins/udivdi3.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem);
-
/* Returns: a / b */
COMPILER_RT_ABI du_int
diff --git a/contrib/compiler-rt/lib/udivmoddi4.c b/contrib/compiler-rt/lib/builtins/udivmoddi4.c
index 57282d5b51c0..0c8b4ff46474 100644
--- a/contrib/compiler-rt/lib/udivmoddi4.c
+++ b/contrib/compiler-rt/lib/builtins/udivmoddi4.c
@@ -137,49 +137,35 @@ __udivmoddi4(du_int a, du_int b, du_int* rem)
}
/* K X
* ---
- *0 K
+ * 0 K
*/
sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
/* 2 <= sr <= n_udword_bits - 1
* q.all = n.all << (n_udword_bits - sr);
* r.all = n.all >> sr;
- * if (sr == n_uword_bits)
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low;
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low << (n_uword_bits - sr);
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- * }
- * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1
- * {
- * q.s.low = n.s.low << (n_udword_bits - sr);
- * q.s.high = (n.s.high << (n_udword_bits - sr)) |
- * (n.s.low >> (sr - n_uword_bits));
- * r.s.high = 0;
- * r.s.low = n.s.high >> (sr - n_uword_bits);
- * }
*/
- q.s.low = (n.s.low << (n_udword_bits - sr)) &
- ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1));
- q.s.high = ((n.s.low << ( n_uword_bits - sr)) &
- ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) |
- (((n.s.high << (n_udword_bits - sr)) |
- (n.s.low >> (sr - n_uword_bits))) &
- ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)));
- r.s.high = (n.s.high >> sr) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1));
- r.s.low = ((n.s.high >> (sr - n_uword_bits)) &
- ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) |
- (((n.s.high << (n_uword_bits - sr)) |
- (n.s.low >> sr)) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)));
+ if (sr == n_uword_bits)
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ else // n_uword_bits + 1 <= sr <= n_udword_bits - 1
+ {
+ q.s.low = n.s.low << (n_udword_bits - sr);
+ q.s.high = (n.s.high << (n_udword_bits - sr)) |
+ (n.s.low >> (sr - n_uword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_uword_bits);
+ }
}
else
{
@@ -191,7 +177,7 @@ __udivmoddi4(du_int a, du_int b, du_int* rem)
/* 0 <= sr <= n_uword_bits - 1 or sr large */
if (sr > n_uword_bits - 1)
{
- if (rem)
+ if (rem)
*rem = n.all;
return 0;
}
@@ -199,24 +185,18 @@ __udivmoddi4(du_int a, du_int b, du_int* rem)
/* 1 <= sr <= n_uword_bits */
/* q.all = n.all << (n_udword_bits - sr); */
q.s.low = 0;
- q.s.high = n.s.low << (n_uword_bits - sr);
- /* r.all = n.all >> sr;
- * if (sr < n_uword_bits)
- * {
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- * }
- * else
- * {
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- */
- r.s.high = (n.s.high >> sr) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1));
- r.s.low = (n.s.high << (n_uword_bits - sr)) |
- ((n.s.low >> sr) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)));
+ if (sr == n_uword_bits)
+ {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else
+ {
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
}
}
/* Not a special case
diff --git a/contrib/compiler-rt/lib/udivmodsi4.c b/contrib/compiler-rt/lib/builtins/udivmodsi4.c
index 5b49089fccc4..789c4b5061e4 100644
--- a/contrib/compiler-rt/lib/udivmodsi4.c
+++ b/contrib/compiler-rt/lib/builtins/udivmodsi4.c
@@ -14,9 +14,6 @@
#include "int_lib.h"
-extern su_int COMPILER_RT_ABI __udivsi3(su_int n, su_int d);
-
-
/* Returns: a / b, *rem = a % b */
COMPILER_RT_ABI su_int
diff --git a/contrib/compiler-rt/lib/udivmodti4.c b/contrib/compiler-rt/lib/builtins/udivmodti4.c
index d8cea2ab742f..803168849c6c 100644
--- a/contrib/compiler-rt/lib/udivmodti4.c
+++ b/contrib/compiler-rt/lib/builtins/udivmodti4.c
@@ -22,7 +22,7 @@
/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
-tu_int
+COMPILER_RT_ABI tu_int
__udivmodti4(tu_int a, tu_int b, tu_int* rem)
{
const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
@@ -146,43 +146,29 @@ __udivmodti4(tu_int a, tu_int b, tu_int* rem)
/* 2 <= sr <= n_utword_bits - 1
* q.all = n.all << (n_utword_bits - sr);
* r.all = n.all >> sr;
- * if (sr == n_udword_bits)
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low;
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- * else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low << (n_udword_bits - sr);
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- * }
- * else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
- * {
- * q.s.low = n.s.low << (n_utword_bits - sr);
- * q.s.high = (n.s.high << (n_utword_bits - sr)) |
- * (n.s.low >> (sr - n_udword_bits));
- * r.s.high = 0;
- * r.s.low = n.s.high >> (sr - n_udword_bits);
- * }
*/
- q.s.low = (n.s.low << (n_utword_bits - sr)) &
- ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1));
- q.s.high = ((n.s.low << ( n_udword_bits - sr)) &
- ((di_int)(int)(sr - n_udword_bits - 1) >> (n_udword_bits-1))) |
- (((n.s.high << (n_utword_bits - sr)) |
- (n.s.low >> (sr - n_udword_bits))) &
- ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1)));
- r.s.high = (n.s.high >> sr) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1));
- r.s.low = ((n.s.high >> (sr - n_udword_bits)) &
- ((di_int)(int)(n_udword_bits - sr - 1) >> (n_udword_bits-1))) |
- (((n.s.high << (n_udword_bits - sr)) |
- (n.s.low >> sr)) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));
+ if (sr == n_udword_bits)
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ }
+ else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
+ {
+ q.s.low = n.s.low << (n_utword_bits - sr);
+ q.s.high = (n.s.high << (n_utword_bits - sr)) |
+ (n.s.low >> (sr - n_udword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_udword_bits);
+ }
}
else
{
@@ -199,27 +185,23 @@ __udivmodti4(tu_int a, tu_int b, tu_int* rem)
return 0;
}
++sr;
- /* 1 <= sr <= n_udword_bits */
- /* q.all = n.all << (n_utword_bits - sr); */
- q.s.low = 0;
- q.s.high = n.s.low << (n_udword_bits - sr);
- /* r.all = n.all >> sr;
- * if (sr < n_udword_bits)
- * {
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- * }
- * else
- * {
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
+ /* 1 <= sr <= n_udword_bits
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
*/
- r.s.high = (n.s.high >> sr) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1));
- r.s.low = (n.s.high << (n_udword_bits - sr)) |
- ((n.s.low >> sr) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));
+ q.s.low = 0;
+ if (sr == n_udword_bits)
+ {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else
+ {
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ }
}
}
/* Not a special case
diff --git a/contrib/compiler-rt/lib/udivsi3.c b/contrib/compiler-rt/lib/builtins/udivsi3.c
index 5d0140cc3e75..5d0140cc3e75 100644
--- a/contrib/compiler-rt/lib/udivsi3.c
+++ b/contrib/compiler-rt/lib/builtins/udivsi3.c
diff --git a/contrib/compiler-rt/lib/udivti3.c b/contrib/compiler-rt/lib/builtins/udivti3.c
index 4a942b8ad204..ec94673e25b0 100644
--- a/contrib/compiler-rt/lib/udivti3.c
+++ b/contrib/compiler-rt/lib/builtins/udivti3.c
@@ -16,11 +16,9 @@
#ifdef CRT_HAS_128BIT
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
/* Returns: a / b */
-tu_int
+COMPILER_RT_ABI tu_int
__udivti3(tu_int a, tu_int b)
{
return __udivmodti4(a, b, 0);
diff --git a/contrib/compiler-rt/lib/umoddi3.c b/contrib/compiler-rt/lib/builtins/umoddi3.c
index 3541ab6e91d8..d513f080a1e9 100644
--- a/contrib/compiler-rt/lib/umoddi3.c
+++ b/contrib/compiler-rt/lib/builtins/umoddi3.c
@@ -14,8 +14,6 @@
#include "int_lib.h"
-du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem);
-
/* Returns: a % b */
COMPILER_RT_ABI du_int
diff --git a/contrib/compiler-rt/lib/umodsi3.c b/contrib/compiler-rt/lib/builtins/umodsi3.c
index aae741d896d2..d5fda4a6af1f 100644
--- a/contrib/compiler-rt/lib/umodsi3.c
+++ b/contrib/compiler-rt/lib/builtins/umodsi3.c
@@ -16,8 +16,6 @@
/* Returns: a % b */
-su_int COMPILER_RT_ABI __udivsi3(su_int a, su_int b);
-
COMPILER_RT_ABI su_int
__umodsi3(su_int a, su_int b)
{
diff --git a/contrib/compiler-rt/lib/umodti3.c b/contrib/compiler-rt/lib/builtins/umodti3.c
index 2ab4dd250215..6d1ca7a8cf6f 100644
--- a/contrib/compiler-rt/lib/umodti3.c
+++ b/contrib/compiler-rt/lib/builtins/umodti3.c
@@ -16,11 +16,9 @@
#ifdef CRT_HAS_128BIT
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
/* Returns: a % b */
-tu_int
+COMPILER_RT_ABI tu_int
__umodti3(tu_int a, tu_int b)
{
tu_int r;
diff --git a/contrib/compiler-rt/lib/x86_64/floatdidf.c b/contrib/compiler-rt/lib/builtins/x86_64/floatdidf.c
index 388404e5e089..388404e5e089 100644
--- a/contrib/compiler-rt/lib/x86_64/floatdidf.c
+++ b/contrib/compiler-rt/lib/builtins/x86_64/floatdidf.c
diff --git a/contrib/compiler-rt/lib/x86_64/floatdisf.c b/contrib/compiler-rt/lib/builtins/x86_64/floatdisf.c
index 96c3728e92c3..96c3728e92c3 100644
--- a/contrib/compiler-rt/lib/x86_64/floatdisf.c
+++ b/contrib/compiler-rt/lib/builtins/x86_64/floatdisf.c
diff --git a/contrib/compiler-rt/lib/x86_64/floatdixf.c b/contrib/compiler-rt/lib/builtins/x86_64/floatdixf.c
index c01193a82b5e..c01193a82b5e 100644
--- a/contrib/compiler-rt/lib/x86_64/floatdixf.c
+++ b/contrib/compiler-rt/lib/builtins/x86_64/floatdixf.c
diff --git a/contrib/compiler-rt/lib/x86_64/floatundidf.S b/contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S
index 1be553b7d1e0..3cd5d02a743a 100644
--- a/contrib/compiler-rt/lib/x86_64/floatundidf.S
+++ b/contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S
@@ -17,19 +17,24 @@
#ifdef __x86_64__
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
twop84_plus_twop52:
- .quad 0x4530000000100000
-twop84: .quad 0x4530000000000000
+ .quad 0x4530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
#define REL_ADDR(_a) (_a)(%rip)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundidf)
movd %edi, %xmm0 // low 32 bits of a
shrq $32, %rdi // high 32 bits of a
@@ -39,5 +44,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundidf)
subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
ret
-
+END_COMPILERRT_FUNCTION(__floatundidf)
+
#endif // __x86_64__
diff --git a/contrib/compiler-rt/lib/x86_64/floatundisf.S b/contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S
index 89d3f07dfcc6..61952f40470c 100644
--- a/contrib/compiler-rt/lib/x86_64/floatundisf.S
+++ b/contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S
@@ -7,15 +7,16 @@
#ifdef __x86_64__
-#ifndef __ELF__
-.literal4
-#endif
-two: .single 2.0
+CONST_SECTION
+
+ .balign 16
+two:
+ .single 2.0
#define REL_ADDR(_a) (_a)(%rip)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundisf)
movq $1, %rsi
testq %rdi, %rdi
@@ -29,5 +30,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
cvtsi2ssq %rdi, %xmm0
mulss REL_ADDR(two), %xmm0
ret
-
+END_COMPILERRT_FUNCTION(__floatundisf)
+
#endif // __x86_64__
diff --git a/contrib/compiler-rt/lib/x86_64/floatundixf.S b/contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S
index a7243f2c545a..92961c89115d 100644
--- a/contrib/compiler-rt/lib/x86_64/floatundixf.S
+++ b/contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S
@@ -7,16 +7,17 @@
#ifdef __x86_64__
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop64: .quad 0x43f0000000000000
+CONST_SECTION
+
+ .balign 16
+twop64:
+ .quad 0x43f0000000000000
#define REL_ADDR(_a) (_a)(%rip)
-.text
-.align 4
+ .text
+
+ .balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundixf)
movq %rdi, -8(%rsp)
fildq -8(%rsp)
@@ -25,6 +26,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf)
ret
1: faddl REL_ADDR(twop64)
ret
+END_COMPILERRT_FUNCTION(__floatundixf)
#endif // __x86_64__
@@ -34,17 +36,20 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf)
#ifdef __x86_64__
-.const
-.align 4
-twop52: .quad 0x4330000000000000
+CONST_SECTION
+
+ .balign 4
+twop52:
+ .quad 0x4330000000000000
twop84_plus_twop52_neg:
- .quad 0xc530000000100000
-twop84: .quad 0x4530000000000000
+ .quad 0xc530000000100000
+twop84:
+ .quad 0x4530000000000000
#define REL_ADDR(_a) (_a)(%rip)
.text
-.align 4
+.balign 4
DEFINE_COMPILERRT_FUNCTION(__floatundixf)
movl %edi, %esi // low 32 bits of input
shrq $32, %rdi // hi 32 bits of input
@@ -56,6 +61,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf)
faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs)
faddl -16(%rsp) // hi + lo (as double extended)
ret
+END_COMPILERRT_FUNCTION(__floatundixf)
#endif // __x86_64__
diff --git a/contrib/compiler-rt/lib/clear_cache.c b/contrib/compiler-rt/lib/clear_cache.c
deleted file mode 100644
index b934fd4bdf69..000000000000
--- a/contrib/compiler-rt/lib/clear_cache.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __APPLE__
- #include <libkern/OSCacheControl.h>
-#endif
-
-/*
- * The compiler generates calls to __clear_cache() when creating
- * trampoline functions on the stack for use with nested functions.
- * It is expected to invalidate the instruction cache for the
- * specified range.
- */
-
-void __clear_cache(void* start, void* end)
-{
-#if __i386__ || __x86_64__
-/*
- * Intel processors have a unified instruction and data cache
- * so there is nothing to do
- */
-#else
- #if __APPLE__
- /* On Darwin, sys_icache_invalidate() provides this functionality */
- sys_icache_invalidate(start, end-start);
- #else
- compilerrt_abort();
- #endif
-#endif
-}
-
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan.cc b/contrib/compiler-rt/lib/dfsan/dfsan.cc
new file mode 100644
index 000000000000..de5b2ce107b4
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan.cc
@@ -0,0 +1,380 @@
+//===-- dfsan.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 DataFlowSanitizer.
+//
+// DataFlowSanitizer runtime. This file defines the public interface to
+// DataFlowSanitizer as well as the definition of certain runtime functions
+// called automatically by the compiler (specifically the instrumentation pass
+// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
+//
+// The public interface is defined in include/sanitizer/dfsan_interface.h whose
+// functions are prefixed dfsan_ while the compiler interface functions are
+// prefixed __dfsan_.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+#include "dfsan/dfsan.h"
+
+using namespace __dfsan;
+
+typedef atomic_uint16_t atomic_dfsan_label;
+static const dfsan_label kInitializingLabel = -1;
+
+static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8);
+
+static atomic_dfsan_label __dfsan_last_label;
+static dfsan_label_info __dfsan_label_info[kNumLabels];
+
+Flags __dfsan::flags_data;
+
+SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls;
+SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];
+
+// On Linux/x86_64, memory is laid out as follows:
+//
+// +--------------------+ 0x800000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x700000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x200200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x200000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x000000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x000000000000
+//
+// To derive a shadow memory address from an application memory address,
+// bits 44-46 are cleared to bring the address into the range
+// [0x000000008000,0x100000000000). Then the address is shifted left by 1 to
+// account for the double byte representation of shadow labels and move the
+// address into the shadow memory range. See the function shadow_for below.
+
+// On Linux/MIPS64, memory is laid out as follows:
+//
+// +--------------------+ 0x10000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0xF000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x2200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x2000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x0000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x0000000000
+
+typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels];
+
+#if defined(__x86_64__)
+static const uptr kShadowAddr = 0x10000;
+static const uptr kUnionTableAddr = 0x200000000000;
+static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
+static const uptr kAppAddr = 0x700000008000;
+#elif defined(__mips64)
+static const uptr kShadowAddr = 0x10000;
+static const uptr kUnionTableAddr = 0x2000000000;
+static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
+static const uptr kAppAddr = 0xF000008000;
+#else
+# error "DFSan not supported for this platform!"
+#endif
+
+static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
+ return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
+}
+
+// Checks we do not run out of labels.
+static void dfsan_check_label(dfsan_label label) {
+ if (label == kInitializingLabel) {
+ Report("FATAL: DataFlowSanitizer: out of labels\n");
+ Die();
+ }
+}
+
+// Resolves the union of two unequal labels. Nonequality is a precondition for
+// this function (the instrumentation pass inlines the equality test).
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) {
+ DCHECK_NE(l1, l2);
+
+ if (l1 == 0)
+ return l2;
+ if (l2 == 0)
+ return l1;
+
+ if (l1 > l2)
+ Swap(l1, l2);
+
+ atomic_dfsan_label *table_ent = union_table(l1, l2);
+ // We need to deal with the case where two threads concurrently request
+ // a union of the same pair of labels. If the table entry is uninitialized,
+ // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel
+ // (i.e. -1) to mark that we are initializing it.
+ dfsan_label label = 0;
+ if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel,
+ memory_order_acquire)) {
+ // Check whether l2 subsumes l1. We don't need to check whether l1
+ // subsumes l2 because we are guaranteed here that l1 < l2, and (at least
+ // in the cases we are interested in) a label may only subsume labels
+ // created earlier (i.e. with a lower numerical value).
+ if (__dfsan_label_info[l2].l1 == l1 ||
+ __dfsan_label_info[l2].l2 == l1) {
+ label = l2;
+ } else {
+ label =
+ atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
+ dfsan_check_label(label);
+ __dfsan_label_info[label].l1 = l1;
+ __dfsan_label_info[label].l2 = l2;
+ }
+ atomic_store(table_ent, label, memory_order_release);
+ } else if (label == kInitializingLabel) {
+ // Another thread is initializing the entry. Wait until it is finished.
+ do {
+ internal_sched_yield();
+ label = atomic_load(table_ent, memory_order_acquire);
+ } while (label == kInitializingLabel);
+ }
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {
+ dfsan_label label = ls[0];
+ for (uptr i = 1; i != n; ++i) {
+ dfsan_label next_label = ls[i];
+ if (label != next_label)
+ label = __dfsan_union(label, next_label);
+ }
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __dfsan_unimplemented(char *fname) {
+ if (flags().warn_unimplemented)
+ Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",
+ fname);
+}
+
+// Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function
+// to try to figure out where labels are being introduced in a nominally
+// label-free program.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
+ if (flags().warn_nonzero_labels)
+ Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
+}
+
+// Indirect call to an uninstrumented vararg function. We don't have a way of
+// handling these at the moment.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsan_vararg_wrapper(const char *fname) {
+ Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
+ "function %s\n", fname);
+ Die();
+}
+
+// Like __dfsan_union, but for use from the client or custom functions. Hence
+// the equality comparison is done here before calling __dfsan_union.
+SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_union(dfsan_label l1, dfsan_label l2) {
+ if (l1 == l2)
+ return l1;
+ return __dfsan_union(l1, l2);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label dfsan_create_label(const char *desc, void *userdata) {
+ dfsan_label label =
+ atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
+ dfsan_check_label(label);
+ __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
+ __dfsan_label_info[label].desc = desc;
+ __dfsan_label_info[label].userdata = userdata;
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __dfsan_set_label(dfsan_label label, void *addr, uptr size) {
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) {
+ // Don't write the label if it is already the value we need it to be.
+ // In a program where most addresses are not labeled, it is common that
+ // a page of shadow memory is entirely zeroed. The Linux copy-on-write
+ // implementation will share all of the zeroed pages, making a copy of a
+ // page when any value is written. The un-sharing will happen even if
+ // the value written does not change the value in memory. Avoiding the
+ // write when both |label| and |*labelp| are zero dramatically reduces
+ // the amount of real memory used by large programs.
+ if (label == *labelp)
+ continue;
+
+ *labelp = label;
+ }
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
+ __dfsan_set_label(label, addr, size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void dfsan_add_label(dfsan_label label, void *addr, uptr size) {
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
+ if (*labelp != label)
+ *labelp = __dfsan_union(*labelp, label);
+}
+
+// Unlike the other dfsan interface functions the behavior of this function
+// depends on the label of one of its arguments. Hence it is implemented as a
+// custom function.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+__dfsw_dfsan_get_label(long data, dfsan_label data_label,
+ dfsan_label *ret_label) {
+ *ret_label = 0;
+ return data_label;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_read_label(const void *addr, uptr size) {
+ if (size == 0)
+ return 0;
+ return __dfsan_union_load(shadow_for(addr), size);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
+ return &__dfsan_label_info[label];
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE int
+dfsan_has_label(dfsan_label label, dfsan_label elem) {
+ if (label == elem)
+ return true;
+ const dfsan_label_info *info = dfsan_get_label_info(label);
+ if (info->l1 != 0) {
+ return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem);
+ } else {
+ return false;
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_has_label_with_desc(dfsan_label label, const char *desc) {
+ const dfsan_label_info *info = dfsan_get_label_info(label);
+ if (info->l1 != 0) {
+ return dfsan_has_label_with_desc(info->l1, desc) ||
+ dfsan_has_label_with_desc(info->l2, desc);
+ } else {
+ return internal_strcmp(desc, info->desc) == 0;
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
+dfsan_get_label_count(void) {
+ dfsan_label max_label_allocated =
+ atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+ return static_cast<uptr>(max_label_allocated);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+dfsan_dump_labels(int fd) {
+ dfsan_label last_label =
+ atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+ for (uptr l = 1; l <= last_label; ++l) {
+ char buf[64];
+ internal_snprintf(buf, sizeof(buf), "%u %u %u ", l,
+ __dfsan_label_info[l].l1, __dfsan_label_info[l].l2);
+ internal_write(fd, buf, internal_strlen(buf));
+ if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) {
+ internal_write(fd, __dfsan_label_info[l].desc,
+ internal_strlen(__dfsan_label_info[l].desc));
+ }
+ internal_write(fd, "\n", 1);
+ }
+}
+
+void Flags::SetDefaults() {
+#define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "dfsan_flags.inc"
+#undef DFSAN_FLAG
+}
+
+static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
+#define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "dfsan_flags.inc"
+#undef DFSAN_FLAG
+}
+
+static void InitializeFlags() {
+ FlagParser parser;
+ RegisterDfsanFlags(&parser, &flags());
+ flags().SetDefaults();
+ parser.ParseString(GetEnv("DFSAN_OPTIONS"));
+}
+
+static void dfsan_fini() {
+ if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) {
+ fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */);
+ if (fd == kInvalidFd) {
+ Report("WARNING: DataFlowSanitizer: unable to open output file %s\n",
+ flags().dump_labels_at_exit);
+ return;
+ }
+
+ Report("INFO: DataFlowSanitizer: dumping labels to %s\n",
+ flags().dump_labels_at_exit);
+ dfsan_dump_labels(fd);
+ internal_close(fd);
+ }
+}
+
+#ifdef DFSAN_NOLIBC
+extern "C" void dfsan_init() {
+#else
+static void dfsan_init(int argc, char **argv, char **envp) {
+#endif
+ MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr);
+
+ // Protect the region of memory we don't use, to preserve the one-to-one
+ // mapping from application to shadow memory. But if ASLR is disabled, Linux
+ // will load our executable in the middle of our unused region. This mostly
+ // works so long as the program doesn't use too much memory. We support this
+ // case by disabling memory protection when ASLR is disabled.
+ uptr init_addr = (uptr)&dfsan_init;
+ if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr))
+ Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr);
+
+ InitializeFlags();
+ InitializeInterceptors();
+
+ // Register the fini callback to run when the program terminates successfully
+ // or it is killed by the runtime.
+ Atexit(dfsan_fini);
+ SetDieCallback(dfsan_fini);
+
+ __dfsan_label_info[kInitializingLabel].desc = "<init label>";
+}
+
+#if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
+#endif
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan.h b/contrib/compiler-rt/lib/dfsan/dfsan.h
new file mode 100644
index 000000000000..ceba3533a233
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan.h
@@ -0,0 +1,73 @@
+//===-- dfsan.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 DataFlowSanitizer.
+//
+// Private DFSan header.
+//===----------------------------------------------------------------------===//
+
+#ifndef DFSAN_H
+#define DFSAN_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+// Copy declarations from public sanitizer/dfsan_interface.h header here.
+typedef u16 dfsan_label;
+
+struct dfsan_label_info {
+ dfsan_label l1;
+ dfsan_label l2;
+ const char *desc;
+ void *userdata;
+};
+
+extern "C" {
+void dfsan_add_label(dfsan_label label, void *addr, uptr size);
+void dfsan_set_label(dfsan_label label, void *addr, uptr size);
+dfsan_label dfsan_read_label(const void *addr, uptr size);
+dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
+} // extern "C"
+
+template <typename T>
+void dfsan_set_label(dfsan_label label, T &data) { // NOLINT
+ dfsan_set_label(label, (void *)&data, sizeof(T));
+}
+
+namespace __dfsan {
+
+void InitializeInterceptors();
+
+inline dfsan_label *shadow_for(void *ptr) {
+#if defined(__x86_64__)
+ return (dfsan_label *) ((((uptr) ptr) & ~0x700000000000) << 1);
+#elif defined(__mips64)
+ return (dfsan_label *) ((((uptr) ptr) & ~0xF000000000) << 1);
+#endif
+}
+
+inline const dfsan_label *shadow_for(const void *ptr) {
+ return shadow_for(const_cast<void *>(ptr));
+}
+
+struct Flags {
+#define DFSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "dfsan_flags.inc"
+#undef DFSAN_FLAG
+
+ void SetDefaults();
+};
+
+extern Flags flags_data;
+inline Flags &flags() {
+ return flags_data;
+}
+
+} // namespace __dfsan
+
+#endif // DFSAN_H
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan.syms.extra b/contrib/compiler-rt/lib/dfsan/dfsan.syms.extra
new file mode 100644
index 000000000000..0d507eef0814
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan.syms.extra
@@ -0,0 +1,3 @@
+dfsan_*
+__dfsan_*
+__dfsw_*
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc b/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc
new file mode 100644
index 000000000000..318ecd6fb317
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc
@@ -0,0 +1,1125 @@
+//===-- dfsan.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 DataFlowSanitizer.
+//
+// This file defines the custom functions listed in done_abilist.txt.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+
+#include "dfsan/dfsan.h"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+using namespace __dfsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
+ dfsan_label buf_label, dfsan_label *ret_label) {
+ int ret = stat(path, buf);
+ if (ret == 0)
+ dfsan_set_label(0, buf, sizeof(struct stat));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
+ dfsan_label fd_label,
+ dfsan_label buf_label,
+ dfsan_label *ret_label) {
+ int ret = fstat(fd, buf);
+ if (ret == 0)
+ dfsan_set_label(0, buf, sizeof(struct stat));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label *ret_label) {
+ for (size_t i = 0;; ++i) {
+ if (s[i] == c || s[i] == 0) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = s_label;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s, i + 1),
+ dfsan_union(s_label, c_label));
+ }
+ return s[i] == 0 ? 0 : const_cast<char *>(s+i);
+ }
+ }
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
+ for (size_t i = 0; i != n; ++i) {
+ if (cs1[i] != cs2[i]) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
+ dfsan_read_label(cs2, i + 1));
+ }
+ return cs1[i] - cs2[i];
+ }
+ }
+
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(cs1, n),
+ dfsan_read_label(cs2, n));
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
+ dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label *ret_label) {
+ for (size_t i = 0;; ++i) {
+ if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label *ret_label) {
+ for (size_t i = 0;; ++i) {
+ if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ if (n == 0) {
+ *ret_label = 0;
+ return 0;
+ }
+
+ for (size_t i = 0;; ++i) {
+ if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ if (n == 0) {
+ *ret_label = 0;
+ return 0;
+ }
+
+ for (size_t i = 0;; ++i) {
+ if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0 ||
+ i == n - 1) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
+ dfsan_label nmemb_label,
+ dfsan_label size_label,
+ dfsan_label *ret_label) {
+ void *p = calloc(nmemb, size);
+ dfsan_set_label(0, p, nmemb * size);
+ *ret_label = 0;
+ return p;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE size_t
+__dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
+ size_t ret = strlen(s);
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_read_label(s, ret + 1);
+ }
+ return ret;
+}
+
+
+static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
+ dfsan_label *sdest = shadow_for(dest);
+ const dfsan_label *ssrc = shadow_for(src);
+ internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
+ return internal_memcpy(dest, src, n);
+}
+
+static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
+ internal_memset(s, c, n);
+ dfsan_set_label(c_label, s, n);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__dfsw_memcpy(void *dest, const void *src, size_t n,
+ dfsan_label dest_label, dfsan_label src_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ *ret_label = dest_label;
+ return dfsan_memcpy(dest, src, n);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__dfsw_memset(void *s, int c, size_t n,
+ dfsan_label s_label, dfsan_label c_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ dfsan_memset(s, c, c_label, n);
+ *ret_label = s_label;
+ return s;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *
+__dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
+ size_t len = strlen(s);
+ void *p = malloc(len+1);
+ dfsan_memcpy(p, s, len+1);
+ *ret_label = 0;
+ return static_cast<char *>(p);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *
+__dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label,
+ dfsan_label *ret_label) {
+ size_t len = strlen(s2);
+ if (len < n) {
+ dfsan_memcpy(s1, s2, len+1);
+ dfsan_memset(s1+len+1, 0, 0, n-len-1);
+ } else {
+ dfsan_memcpy(s1, s2, n);
+ }
+
+ *ret_label = s1_label;
+ return s1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE ssize_t
+__dfsw_pread(int fd, void *buf, size_t count, off_t offset,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label, dfsan_label offset_label,
+ dfsan_label *ret_label) {
+ ssize_t ret = pread(fd, buf, count, offset);
+ if (ret > 0)
+ dfsan_set_label(0, buf, ret);
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE ssize_t
+__dfsw_read(int fd, void *buf, size_t count,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label,
+ dfsan_label *ret_label) {
+ ssize_t ret = read(fd, buf, count);
+ if (ret > 0)
+ dfsan_set_label(0, buf, ret);
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
+ struct timespec *tp,
+ dfsan_label clk_id_label,
+ dfsan_label tp_label,
+ dfsan_label *ret_label) {
+ int ret = clock_gettime(clk_id, tp);
+ if (ret == 0)
+ dfsan_set_label(0, tp, sizeof(struct timespec));
+ *ret_label = 0;
+ return ret;
+}
+
+static void unpoison(const void *ptr, uptr size) {
+ dfsan_set_label(0, const_cast<void *>(ptr), size);
+}
+
+// dlopen() ultimately calls mmap() down inside the loader, which generally
+// doesn't participate in dynamic symbol resolution. Therefore we won't
+// intercept its calls to mmap, and we have to hook it here.
+SANITIZER_INTERFACE_ATTRIBUTE void *
+__dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
+ dfsan_label flag_label, dfsan_label *ret_label) {
+ void *handle = dlopen(filename, flag);
+ link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
+ if (map)
+ ForEachMappedRegion(map, unpoison);
+ *ret_label = 0;
+ return handle;
+}
+
+struct pthread_create_info {
+ void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
+ void *start_routine;
+ void *arg;
+};
+
+static void *pthread_create_cb(void *p) {
+ pthread_create_info pci(*(pthread_create_info *)p);
+ free(p);
+ dfsan_label ret_label;
+ return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
+ &ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
+ pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine_trampoline)(void *, void *, dfsan_label,
+ dfsan_label *),
+ void *start_routine, void *arg, dfsan_label thread_label,
+ dfsan_label attr_label, dfsan_label start_routine_label,
+ dfsan_label arg_label, dfsan_label *ret_label) {
+ pthread_create_info *pci =
+ (pthread_create_info *)malloc(sizeof(pthread_create_info));
+ pci->start_routine_trampoline = start_routine_trampoline;
+ pci->start_routine = start_routine;
+ pci->arg = arg;
+ int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
+ if (rv != 0)
+ free(pci);
+ *ret_label = 0;
+ return rv;
+}
+
+struct dl_iterate_phdr_info {
+ int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
+ size_t size, void *data, dfsan_label info_label,
+ dfsan_label size_label, dfsan_label data_label,
+ dfsan_label *ret_label);
+ void *callback;
+ void *data;
+};
+
+int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
+ dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
+ dfsan_set_label(0, *info);
+ dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
+ strlen(info->dlpi_name) + 1);
+ dfsan_set_label(
+ 0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
+ sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
+ dfsan_label ret_label;
+ return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
+ 0, &ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
+ int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
+ size_t size, void *data, dfsan_label info_label,
+ dfsan_label size_label, dfsan_label data_label,
+ dfsan_label *ret_label),
+ void *callback, void *data, dfsan_label callback_label,
+ dfsan_label data_label, dfsan_label *ret_label) {
+ dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
+ *ret_label = 0;
+ return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
+ dfsan_label buf_label, dfsan_label *ret_label) {
+ char *ret = ctime_r(timep, buf);
+ if (ret) {
+ dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
+ strlen(buf) + 1);
+ *ret_label = buf_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
+ dfsan_label size_label, dfsan_label stream_label,
+ dfsan_label *ret_label) {
+ char *ret = fgets(s, size, stream);
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ *ret_label = s_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
+ dfsan_label size_label, dfsan_label *ret_label) {
+ char *ret = getcwd(buf, size);
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ *ret_label = buf_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
+ char *ret = get_current_dir_name();
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
+ dfsan_label len_label, dfsan_label *ret_label) {
+ int ret = gethostname(name, len);
+ if (ret == 0) {
+ dfsan_set_label(0, name, strlen(name) + 1);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getrlimit(int resource, struct rlimit *rlim,
+ dfsan_label resource_label, dfsan_label rlim_label,
+ dfsan_label *ret_label) {
+ int ret = getrlimit(resource, rlim);
+ if (ret == 0) {
+ dfsan_set_label(0, rlim, sizeof(struct rlimit));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
+ dfsan_label usage_label, dfsan_label *ret_label) {
+ int ret = getrusage(who, usage);
+ if (ret == 0) {
+ dfsan_set_label(0, usage, sizeof(struct rusage));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
+ dfsan_label src_label, dfsan_label *ret_label) {
+ char *ret = strcpy(dest, src);
+ if (ret) {
+ internal_memcpy(shadow_for(dest), shadow_for(src),
+ sizeof(dfsan_label) * (strlen(src) + 1));
+ }
+ *ret_label = dst_label;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long int __dfsw_strtol(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long int ret = strtol(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+double __dfsw_strtod(const char *nptr, char **endptr,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label *ret_label) {
+ char *tmp_endptr;
+ double ret = strtod(nptr, &tmp_endptr);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_read_label(
+ nptr,
+ tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long long int ret = strtoll(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
+ dfsan_label nptr_label,
+ int base, dfsan_label endptr_label,
+ dfsan_label base_label,
+ dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
+ time_t ret = time(t);
+ if (ret != (time_t) -1 && t) {
+ dfsan_set_label(0, t, sizeof(time_t));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
+ dfsan_label src_label, dfsan_label dst_label,
+ dfsan_label *ret_label) {
+ int ret = inet_pton(af, src, dst);
+ if (ret == 1) {
+ dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
+ af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
+ dfsan_label timep_label, dfsan_label result_label,
+ dfsan_label *ret_label) {
+ struct tm *ret = localtime_r(timep, result);
+ if (ret) {
+ dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
+ sizeof(struct tm));
+ *ret_label = result_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
+ char *buf, size_t buflen, struct passwd **result,
+ dfsan_label uid_label, dfsan_label pwd_label,
+ dfsan_label buf_label, dfsan_label buflen_label,
+ dfsan_label result_label, dfsan_label *ret_label) {
+ // Store the data in pwd, the strings referenced from pwd in buf, and the
+ // address of pwd in *result. On failure, NULL is stored in *result.
+ int ret = getpwuid_r(uid, pwd, buf, buflen, result);
+ if (ret == 0) {
+ dfsan_set_label(0, pwd, sizeof(struct passwd));
+ dfsan_set_label(0, buf, strlen(buf) + 1);
+ }
+ *ret_label = 0;
+ dfsan_set_label(0, result, sizeof(struct passwd*));
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
+ dfsan_label dfs_label, dfsan_label nfds_label,
+ dfsan_label timeout_label, dfsan_label *ret_label) {
+ int ret = poll(fds, nfds, timeout);
+ if (ret >= 0) {
+ for (; nfds > 0; --nfds) {
+ dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
+ }
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout,
+ dfsan_label nfds_label, dfsan_label readfds_label,
+ dfsan_label writefds_label, dfsan_label exceptfds_label,
+ dfsan_label timeout_label, dfsan_label *ret_label) {
+ int ret = select(nfds, readfds, writefds, exceptfds, timeout);
+ // Clear everything (also on error) since their content is either set or
+ // undefined.
+ if (readfds) {
+ dfsan_set_label(0, readfds, sizeof(fd_set));
+ }
+ if (writefds) {
+ dfsan_set_label(0, writefds, sizeof(fd_set));
+ }
+ if (exceptfds) {
+ dfsan_set_label(0, exceptfds, sizeof(fd_set));
+ }
+ dfsan_set_label(0, timeout, sizeof(struct timeval));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
+ dfsan_label pid_label,
+ dfsan_label cpusetsize_label,
+ dfsan_label mask_label, dfsan_label *ret_label) {
+ int ret = sched_getaffinity(pid, cpusetsize, mask);
+ if (ret == 0) {
+ dfsan_set_label(0, mask, cpusetsize);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
+ dfsan_label *ret_label) {
+ int ret = sigemptyset(set);
+ dfsan_set_label(0, set, sizeof(sigset_t));
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact, dfsan_label signum_label,
+ dfsan_label act_label, dfsan_label oldact_label,
+ dfsan_label *ret_label) {
+ int ret = sigaction(signum, act, oldact);
+ if (oldact) {
+ dfsan_set_label(0, oldact, sizeof(struct sigaction));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
+ dfsan_label tv_label, dfsan_label tz_label,
+ dfsan_label *ret_label) {
+ int ret = gettimeofday(tv, tz);
+ if (tv) {
+ dfsan_set_label(0, tv, sizeof(struct timeval));
+ }
+ if (tz) {
+ dfsan_set_label(0, tz, sizeof(struct timezone));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ void *ret = memchr(s, c, n);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? s_label : 0;
+ } else {
+ size_t len =
+ ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
+ : n;
+ *ret_label =
+ dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label *ret_label) {
+ char *ret = strrchr(s, c);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? s_label : 0;
+ } else {
+ *ret_label =
+ dfsan_union(dfsan_read_label(s, strlen(s) + 1),
+ dfsan_union(s_label, c_label));
+ }
+
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
+ dfsan_label haystack_label,
+ dfsan_label needle_label,
+ dfsan_label *ret_label) {
+ char *ret = strstr(haystack, needle);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? haystack_label : 0;
+ } else {
+ size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
+ *ret_label =
+ dfsan_union(dfsan_read_label(haystack, len),
+ dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
+ dfsan_union(haystack_label, needle_label)));
+ }
+
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
+ struct timespec *rem,
+ dfsan_label req_label,
+ dfsan_label rem_label,
+ dfsan_label *ret_label) {
+ int ret = nanosleep(req, rem);
+ *ret_label = 0;
+ if (ret == -1) {
+ // Interrupted by a signal, rem is filled with the remaining time.
+ dfsan_set_label(0, rem, sizeof(struct timespec));
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_socketpair(int domain, int type, int protocol, int sv[2],
+ dfsan_label domain_label, dfsan_label type_label,
+ dfsan_label protocol_label, dfsan_label sv_label,
+ dfsan_label *ret_label) {
+ int ret = socketpair(domain, type, protocol, sv);
+ *ret_label = 0;
+ if (ret == 0) {
+ dfsan_set_label(0, sv, sizeof(*sv) * 2);
+ }
+ return ret;
+}
+
+// Type of the trampoline function passed to the custom version of
+// dfsan_set_write_callback.
+typedef void (*write_trampoline_t)(
+ void *callback,
+ int fd, const void *buf, ssize_t count,
+ dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
+
+// Calls to dfsan_set_write_callback() set the values in this struct.
+// Calls to the custom version of write() read (and invoke) them.
+static struct {
+ write_trampoline_t write_callback_trampoline = NULL;
+ void *write_callback = NULL;
+} write_callback_info;
+
+SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsw_dfsan_set_write_callback(
+ write_trampoline_t write_callback_trampoline,
+ void *write_callback,
+ dfsan_label write_callback_label,
+ dfsan_label *ret_label) {
+ write_callback_info.write_callback_trampoline = write_callback_trampoline;
+ write_callback_info.write_callback = write_callback;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_write(int fd, const void *buf, size_t count,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label, dfsan_label *ret_label) {
+ if (write_callback_info.write_callback != NULL) {
+ write_callback_info.write_callback_trampoline(
+ write_callback_info.write_callback,
+ fd, buf, count,
+ fd_label, buf_label, count_label);
+ }
+
+ *ret_label = 0;
+ return write(fd, buf, count);
+}
+
+// Type used to extract a dfsan_label with va_arg()
+typedef int dfsan_label_va;
+
+// A chunk of data representing the output of formatting either a constant
+// string or a single format directive.
+struct Chunk {
+ // Address of the beginning of the formatted string
+ const char *ptr;
+ // Size of the formatted string
+ size_t size;
+
+ // Type of DFSan label (depends on the format directive)
+ enum {
+ // Constant string, no argument and thus no label
+ NONE = 0,
+ // Label for an argument of '%n'
+ IGNORED,
+ // Label for a '%s' argument
+ STRING,
+ // Label for any other type of argument
+ NUMERIC,
+ } label_type;
+
+ // Value of the argument (if label_type == STRING)
+ const char *arg;
+};
+
+// Formats the input. The output is stored in 'str' starting from offset
+// 'off'. The format directive is represented by the first 'format_size' bytes
+// of 'format'. If 'has_size' is true, 'size' bounds the number of output
+// bytes. Returns the return value of the vsnprintf call used to format the
+// input.
+static int format_chunk(char *str, size_t off, bool has_size, size_t size,
+ const char *format, size_t format_size, ...) {
+ char *chunk_format = (char *) malloc(format_size + 1);
+ assert(chunk_format);
+ internal_memcpy(chunk_format, format, format_size);
+ chunk_format[format_size] = '\0';
+
+ va_list ap;
+ va_start(ap, format_size);
+ int r = 0;
+ if (has_size) {
+ r = vsnprintf(str + off, off < size ? size - off : 0, chunk_format, ap);
+ } else {
+ r = vsprintf(str + off, chunk_format, ap);
+ }
+ va_end(ap);
+
+ free(chunk_format);
+ return r;
+}
+
+// Formats the input and propagates the input labels to the output. The output
+// is stored in 'str'. If 'has_size' is true, 'size' bounds the number of
+// output bytes. 'format' and 'ap' are the format string and the list of
+// arguments for formatting. Returns the return value vsnprintf would return.
+//
+// The function tokenizes the format string in chunks representing either a
+// constant string or a single format directive (e.g., '%.3f') and formats each
+// chunk independently into the output string. This approach allows to figure
+// out which bytes of the output string depends on which argument and thus to
+// propagate labels more precisely.
+static int format_buffer(char *str, bool has_size, size_t size,
+ const char *format, dfsan_label *va_labels,
+ dfsan_label *ret_label, va_list ap) {
+ InternalMmapVector<Chunk> chunks(8);
+ size_t off = 0;
+
+ while (*format) {
+ chunks.push_back(Chunk());
+ Chunk& chunk = chunks.back();
+ chunk.ptr = str + off;
+ chunk.arg = nullptr;
+
+ int status = 0;
+
+ if (*format != '%') {
+ // Ordinary character. Consume all the characters until a '%' or the end
+ // of the string.
+ size_t format_size = 0;
+ for (; *format && *format != '%'; ++format, ++format_size) {}
+ status = format_chunk(str, off, has_size, size, format - format_size,
+ format_size);
+ chunk.label_type = Chunk::NONE;
+ } else {
+ // Conversion directive. Consume all the characters until a conversion
+ // specifier or the end of the string.
+ bool end_format = false;
+#define FORMAT_CHUNK(t) \
+ format_chunk(str, off, has_size, size, format - format_size, \
+ format_size + 1, va_arg(ap, t))
+
+ for (size_t format_size = 1; *++format && !end_format; ++format_size) {
+ switch (*format) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ switch (*(format - 1)) {
+ case 'h':
+ // Also covers the 'hh' case (since the size of the arg is still
+ // an int).
+ status = FORMAT_CHUNK(int);
+ break;
+ case 'l':
+ if (format_size >= 2 && *(format - 2) == 'l') {
+ status = FORMAT_CHUNK(long long int);
+ } else {
+ status = FORMAT_CHUNK(long int);
+ }
+ break;
+ case 'q':
+ status = FORMAT_CHUNK(long long int);
+ break;
+ case 'j':
+ status = FORMAT_CHUNK(intmax_t);
+ break;
+ case 'z':
+ status = FORMAT_CHUNK(size_t);
+ break;
+ case 't':
+ status = FORMAT_CHUNK(size_t);
+ break;
+ default:
+ status = FORMAT_CHUNK(int);
+ }
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ if (*(format - 1) == 'L') {
+ status = FORMAT_CHUNK(long double);
+ } else {
+ status = FORMAT_CHUNK(double);
+ }
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 'c':
+ status = FORMAT_CHUNK(int);
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 's':
+ chunk.arg = va_arg(ap, char *);
+ status =
+ format_chunk(str, off, has_size, size,
+ format - format_size, format_size + 1,
+ chunk.arg);
+ chunk.label_type = Chunk::STRING;
+ end_format = true;
+ break;
+
+ case 'p':
+ status = FORMAT_CHUNK(void *);
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 'n':
+ *(va_arg(ap, int *)) = (int)off;
+ chunk.label_type = Chunk::IGNORED;
+ end_format = true;
+ break;
+
+ case '%':
+ status = format_chunk(str, off, has_size, size,
+ format - format_size, format_size + 1);
+ chunk.label_type = Chunk::NONE;
+ end_format = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+#undef FORMAT_CHUNK
+ }
+
+ if (status < 0) {
+ return status;
+ }
+
+ // A return value of {v,}snprintf of size or more means that the output was
+ // truncated.
+ if (has_size) {
+ if (off < size) {
+ size_t ustatus = (size_t) status;
+ chunk.size = ustatus >= (size - off) ?
+ ustatus - (size - off) : ustatus;
+ } else {
+ chunk.size = 0;
+ }
+ } else {
+ chunk.size = status;
+ }
+ off += status;
+ }
+
+ // TODO(martignlo): Decide how to combine labels (e.g., whether to ignore or
+ // not the label of the format string).
+
+ // Label each output chunk according to the label supplied as argument to the
+ // function. We need to go through all the chunks and arguments even if the
+ // string was only partially printed ({v,}snprintf case).
+ for (size_t i = 0; i < chunks.size(); ++i) {
+ const Chunk& chunk = chunks[i];
+ void *chunk_ptr = const_cast<char *>(chunk.ptr);
+
+ switch (chunk.label_type) {
+ case Chunk::NONE:
+ dfsan_set_label(0, chunk_ptr, chunk.size);
+ break;
+ case Chunk::IGNORED:
+ va_labels++;
+ dfsan_set_label(0, chunk_ptr, chunk.size);
+ break;
+ case Chunk::NUMERIC: {
+ dfsan_label label = *va_labels++;
+ dfsan_set_label(label, chunk_ptr, chunk.size);
+ break;
+ }
+ case Chunk::STRING: {
+ // Consume the label of the pointer to the string
+ va_labels++;
+ internal_memcpy(shadow_for(chunk_ptr),
+ shadow_for(chunk.arg),
+ sizeof(dfsan_label) * (strlen(chunk.arg)));
+ break;
+ }
+ }
+ }
+
+ *ret_label = 0;
+
+ // Number of bytes written in total.
+ return off;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
+ dfsan_label format_label, dfsan_label *va_labels,
+ dfsan_label *ret_label, ...) {
+ va_list ap;
+ va_start(ap, ret_label);
+ int ret = format_buffer(str, false, 0, format, va_labels, ret_label, ap);
+ va_end(ap);
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_snprintf(char *str, size_t size, const char *format,
+ dfsan_label str_label, dfsan_label size_label,
+ dfsan_label format_label, dfsan_label *va_labels,
+ dfsan_label *ret_label, ...) {
+ va_list ap;
+ va_start(ap, ret_label);
+ int ret = format_buffer(str, true, size, format, va_labels, ret_label, ap);
+ va_end(ap);
+ return ret;
+}
+}
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan_flags.inc b/contrib/compiler-rt/lib/dfsan/dfsan_flags.inc
new file mode 100644
index 000000000000..24fbfcb9e46f
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan_flags.inc
@@ -0,0 +1,32 @@
+//===-- dfsan_flags.inc -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// DFSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DFSAN_FLAG
+# error "Define DFSAN_FLAG prior to including this file!"
+#endif
+
+// DFSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+DFSAN_FLAG(bool, warn_unimplemented, true,
+ "Whether to warn on unimplemented functions.")
+DFSAN_FLAG(bool, warn_nonzero_labels, false,
+ "Whether to warn on unimplemented functions.")
+DFSAN_FLAG(
+ bool, strict_data_dependencies, true,
+ "Whether to propagate labels only when there is an obvious data dependency"
+ "(e.g., when comparing strings, ignore the fact that the output of the"
+ "comparison might be data-dependent on the content of the strings). This"
+ "applies only to the custom functions defined in 'custom.c'.")
+DFSAN_FLAG(const char *, dump_labels_at_exit, "", "The path of the file where "
+ "to dump the labels when the "
+ "program terminates.")
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc b/contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc
new file mode 100644
index 000000000000..8b7d64e25a39
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc
@@ -0,0 +1,44 @@
+//===-- dfsan_interceptors.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 DataFlowSanitizer.
+//
+// Interceptors for standard library functions.
+//===----------------------------------------------------------------------===//
+
+#include "dfsan/dfsan.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF_T offset) {
+ void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF64_T offset) {
+ void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+namespace __dfsan {
+void InitializeInterceptors() {
+ static int inited = 0;
+ CHECK_EQ(inited, 0);
+
+ INTERCEPT_FUNCTION(mmap);
+ INTERCEPT_FUNCTION(mmap64);
+ inited = 1;
+}
+} // namespace __dfsan
diff --git a/contrib/compiler-rt/lib/dfsan/done_abilist.txt b/contrib/compiler-rt/lib/dfsan/done_abilist.txt
new file mode 100644
index 000000000000..15c6d1bb2e39
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/done_abilist.txt
@@ -0,0 +1,260 @@
+fun:main=uninstrumented
+fun:main=discard
+
+###############################################################################
+# DFSan interface functions
+###############################################################################
+fun:dfsan_union=uninstrumented
+fun:dfsan_union=discard
+fun:dfsan_create_label=uninstrumented
+fun:dfsan_create_label=discard
+fun:dfsan_set_label=uninstrumented
+fun:dfsan_set_label=discard
+fun:dfsan_add_label=uninstrumented
+fun:dfsan_add_label=discard
+fun:dfsan_get_label=uninstrumented
+fun:dfsan_get_label=custom
+fun:dfsan_read_label=uninstrumented
+fun:dfsan_read_label=discard
+fun:dfsan_get_label_count=uninstrumented
+fun:dfsan_get_label_count=discard
+fun:dfsan_get_label_info=uninstrumented
+fun:dfsan_get_label_info=discard
+fun:dfsan_has_label=uninstrumented
+fun:dfsan_has_label=discard
+fun:dfsan_has_label_with_desc=uninstrumented
+fun:dfsan_has_label_with_desc=discard
+fun:dfsan_set_write_callback=uninstrumented
+fun:dfsan_set_write_callback=custom
+
+###############################################################################
+# glibc
+###############################################################################
+fun:malloc=discard
+fun:realloc=discard
+fun:free=discard
+
+# Functions that return a value that depends on the input, but the output might
+# not be necessarily data-dependent on the input.
+fun:isalpha=functional
+fun:isdigit=functional
+fun:isprint=functional
+fun:isxdigit=functional
+fun:isalnum=functional
+fun:ispunct=functional
+fun:isspace=functional
+fun:tolower=functional
+fun:toupper=functional
+
+# Functions that return a value that is data-dependent on the input.
+fun:btowc=functional
+fun:exp=functional
+fun:exp2=functional
+fun:fabs=functional
+fun:finite=functional
+fun:floor=functional
+fun:fmod=functional
+fun:isinf=functional
+fun:isnan=functional
+fun:log=functional
+fun:modf=functional
+fun:pow=functional
+fun:round=functional
+fun:sqrt=functional
+fun:wctob=functional
+
+# Functions that produce an output that does not depend on the input (shadow is
+# zeroed automatically).
+fun:__assert_fail=discard
+fun:__ctype_b_loc=discard
+fun:__cxa_atexit=discard
+fun:__errno_location=discard
+fun:__newlocale=discard
+fun:__sbrk=discard
+fun:__sigsetjmp=discard
+fun:__uselocale=discard
+fun:__wctype_l=discard
+fun:access=discard
+fun:alarm=discard
+fun:atexit=discard
+fun:bind=discard
+fun:chdir=discard
+fun:close=discard
+fun:closedir=discard
+fun:connect=discard
+fun:dladdr=discard
+fun:dlclose=discard
+fun:fclose=discard
+fun:feof=discard
+fun:ferror=discard
+fun:fflush=discard
+fun:fileno=discard
+fun:fopen=discard
+fun:fprintf=discard
+fun:fputc=discard
+fun:fputc=discard
+fun:fputs=discard
+fun:fputs=discard
+fun:fseek=discard
+fun:ftell=discard
+fun:fwrite=discard
+fun:getenv=discard
+fun:getuid=discard
+fun:geteuid=discard
+fun:getpagesize=discard
+fun:getpid=discard
+fun:kill=discard
+fun:listen=discard
+fun:lseek=discard
+fun:mkdir=discard
+fun:mmap=discard
+fun:munmap=discard
+fun:open=discard
+fun:pipe=discard
+fun:posix_fadvise=discard
+fun:posix_memalign=discard
+fun:prctl=discard
+fun:printf=discard
+fun:pthread_sigmask=discard
+fun:putc=discard
+fun:putchar=discard
+fun:puts=discard
+fun:rand=discard
+fun:random=discard
+fun:remove=discard
+fun:sched_getcpu=discard
+fun:sched_get_priority_max=discard
+fun:sched_setaffinity=discard
+fun:sched_yield=discard
+fun:sem_destroy=discard
+fun:sem_init=discard
+fun:sem_post=discard
+fun:sem_wait=discard
+fun:send=discard
+fun:sendmsg=discard
+fun:sendto=discard
+fun:setsockopt=discard
+fun:shutdown=discard
+fun:sleep=discard
+fun:socket=discard
+fun:strerror=discard
+fun:strspn=discard
+fun:strcspn=discard
+fun:symlink=discard
+fun:syscall=discard
+fun:unlink=discard
+fun:uselocale=discard
+
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:calloc=custom
+fun:clock_gettime=custom
+fun:dlopen=custom
+fun:fgets=custom
+fun:fstat=custom
+fun:getcwd=custom
+fun:get_current_dir_name=custom
+fun:gethostname=custom
+fun:getrlimit=custom
+fun:getrusage=custom
+fun:nanosleep=custom
+fun:pread=custom
+fun:read=custom
+fun:socketpair=custom
+fun:stat=custom
+fun:time=custom
+
+# Functions that produce an output that depend on the input (propagate the
+# shadow manually).
+fun:ctime_r=custom
+fun:inet_pton=custom
+fun:localtime_r=custom
+fun:memcpy=custom
+fun:memset=custom
+fun:strcpy=custom
+fun:strdup=custom
+fun:strncpy=custom
+fun:strtod=custom
+fun:strtol=custom
+fun:strtoll=custom
+fun:strtoul=custom
+fun:strtoull=custom
+
+# Functions that produce an output that is computed from the input, but is not
+# necessarily data dependent.
+fun:memchr=custom
+fun:memcmp=custom
+fun:strcasecmp=custom
+fun:strchr=custom
+fun:strcmp=custom
+fun:strlen=custom
+fun:strncasecmp=custom
+fun:strncmp=custom
+fun:strrchr=custom
+fun:strstr=custom
+
+# Functions which take action based on global state, such as running a callback
+# set by a sepperate function.
+fun:write=custom
+
+# Functions that take a callback (wrap the callback manually).
+fun:dl_iterate_phdr=custom
+
+fun:getpwuid_r=custom
+fun:poll=custom
+fun:sched_getaffinity=custom
+fun:select=custom
+fun:sigemptyset=custom
+fun:sigaction=custom
+fun:gettimeofday=custom
+
+# sprintf-like
+fun:sprintf=custom
+fun:snprintf=custom
+
+# TODO: custom
+fun:asprintf=discard
+fun:qsort=discard
+
+###############################################################################
+# pthread
+###############################################################################
+fun:pthread_equal=discard
+fun:pthread_getspecific=discard
+fun:pthread_key_create=discard
+fun:pthread_key_delete=discard
+fun:pthread_mutex_destroy=discard
+fun:pthread_mutex_init=discard
+fun:pthread_mutex_lock=discard
+fun:pthread_mutex_trylock=discard
+fun:pthread_mutex_unlock=discard
+fun:pthread_mutexattr_destroy=discard
+fun:pthread_mutexattr_init=discard
+fun:pthread_mutexattr_settype=discard
+fun:pthread_once=discard
+fun:pthread_self=discard
+fun:pthread_setspecific=discard
+
+# Functions that take a callback (wrap the callback manually).
+fun:pthread_create=custom
+
+###############################################################################
+# libffi/libgo
+###############################################################################
+# Functions that are written in asm or are called from asm.
+fun:ffi_call_unix64=uninstrumented
+fun:ffi_call_unix64=discard
+fun:ffi_closure_unix64_inner=uninstrumented
+fun:ffi_closure_unix64_inner=discard
+fun:ffi_closure_unix64=uninstrumented
+fun:ffi_closure_unix64=discard
+fun:__go_get_closure=uninstrumented
+fun:__go_get_closure=discard
+fun:__go_makefunc_can_recover=uninstrumented
+fun:__go_makefunc_can_recover=discard
+fun:__go_makefunc_returning=uninstrumented
+fun:__go_makefunc_returning=discard
+fun:reflect.MakeFuncStubGo=uninstrumented
+fun:reflect.MakeFuncStubGo=discard
+fun:reflect.makeFuncStub=uninstrumented
+fun:reflect.makeFuncStub=discard
diff --git a/contrib/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt b/contrib/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt
new file mode 100644
index 000000000000..a1ea0a06b537
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt
@@ -0,0 +1,3433 @@
+fun:_Exit=uninstrumented
+fun:_IO_adjust_column=uninstrumented
+fun:_IO_adjust_wcolumn=uninstrumented
+fun:_IO_default_doallocate=uninstrumented
+fun:_IO_default_finish=uninstrumented
+fun:_IO_default_pbackfail=uninstrumented
+fun:_IO_default_uflow=uninstrumented
+fun:_IO_default_xsgetn=uninstrumented
+fun:_IO_default_xsputn=uninstrumented
+fun:_IO_do_write=uninstrumented
+fun:_IO_doallocbuf=uninstrumented
+fun:_IO_fclose=uninstrumented
+fun:_IO_fdopen=uninstrumented
+fun:_IO_feof=uninstrumented
+fun:_IO_ferror=uninstrumented
+fun:_IO_fflush=uninstrumented
+fun:_IO_fgetpos=uninstrumented
+fun:_IO_fgetpos64=uninstrumented
+fun:_IO_fgets=uninstrumented
+fun:_IO_file_attach=uninstrumented
+fun:_IO_file_close=uninstrumented
+fun:_IO_file_close_it=uninstrumented
+fun:_IO_file_doallocate=uninstrumented
+fun:_IO_file_finish=uninstrumented
+fun:_IO_file_fopen=uninstrumented
+fun:_IO_file_init=uninstrumented
+fun:_IO_file_open=uninstrumented
+fun:_IO_file_overflow=uninstrumented
+fun:_IO_file_read=uninstrumented
+fun:_IO_file_seek=uninstrumented
+fun:_IO_file_seekoff=uninstrumented
+fun:_IO_file_setbuf=uninstrumented
+fun:_IO_file_stat=uninstrumented
+fun:_IO_file_sync=uninstrumented
+fun:_IO_file_underflow=uninstrumented
+fun:_IO_file_write=uninstrumented
+fun:_IO_file_xsputn=uninstrumented
+fun:_IO_flockfile=uninstrumented
+fun:_IO_flush_all=uninstrumented
+fun:_IO_flush_all_linebuffered=uninstrumented
+fun:_IO_fopen=uninstrumented
+fun:_IO_fprintf=uninstrumented
+fun:_IO_fputs=uninstrumented
+fun:_IO_fread=uninstrumented
+fun:_IO_free_backup_area=uninstrumented
+fun:_IO_free_wbackup_area=uninstrumented
+fun:_IO_fsetpos=uninstrumented
+fun:_IO_fsetpos64=uninstrumented
+fun:_IO_ftell=uninstrumented
+fun:_IO_ftrylockfile=uninstrumented
+fun:_IO_funlockfile=uninstrumented
+fun:_IO_fwrite=uninstrumented
+fun:_IO_getc=uninstrumented
+fun:_IO_getline=uninstrumented
+fun:_IO_getline_info=uninstrumented
+fun:_IO_gets=uninstrumented
+fun:_IO_init=uninstrumented
+fun:_IO_init_marker=uninstrumented
+fun:_IO_init_wmarker=uninstrumented
+fun:_IO_iter_begin=uninstrumented
+fun:_IO_iter_end=uninstrumented
+fun:_IO_iter_file=uninstrumented
+fun:_IO_iter_next=uninstrumented
+fun:_IO_least_wmarker=uninstrumented
+fun:_IO_link_in=uninstrumented
+fun:_IO_list_lock=uninstrumented
+fun:_IO_list_resetlock=uninstrumented
+fun:_IO_list_unlock=uninstrumented
+fun:_IO_marker_delta=uninstrumented
+fun:_IO_marker_difference=uninstrumented
+fun:_IO_padn=uninstrumented
+fun:_IO_peekc_locked=uninstrumented
+fun:_IO_popen=uninstrumented
+fun:_IO_printf=uninstrumented
+fun:_IO_proc_close=uninstrumented
+fun:_IO_proc_open=uninstrumented
+fun:_IO_putc=uninstrumented
+fun:_IO_puts=uninstrumented
+fun:_IO_remove_marker=uninstrumented
+fun:_IO_seekmark=uninstrumented
+fun:_IO_seekoff=uninstrumented
+fun:_IO_seekpos=uninstrumented
+fun:_IO_seekwmark=uninstrumented
+fun:_IO_setb=uninstrumented
+fun:_IO_setbuffer=uninstrumented
+fun:_IO_setvbuf=uninstrumented
+fun:_IO_sgetn=uninstrumented
+fun:_IO_sprintf=uninstrumented
+fun:_IO_sputbackc=uninstrumented
+fun:_IO_sputbackwc=uninstrumented
+fun:_IO_sscanf=uninstrumented
+fun:_IO_str_init_readonly=uninstrumented
+fun:_IO_str_init_static=uninstrumented
+fun:_IO_str_overflow=uninstrumented
+fun:_IO_str_pbackfail=uninstrumented
+fun:_IO_str_seekoff=uninstrumented
+fun:_IO_str_underflow=uninstrumented
+fun:_IO_sungetc=uninstrumented
+fun:_IO_sungetwc=uninstrumented
+fun:_IO_switch_to_get_mode=uninstrumented
+fun:_IO_switch_to_main_wget_area=uninstrumented
+fun:_IO_switch_to_wbackup_area=uninstrumented
+fun:_IO_switch_to_wget_mode=uninstrumented
+fun:_IO_un_link=uninstrumented
+fun:_IO_ungetc=uninstrumented
+fun:_IO_unsave_markers=uninstrumented
+fun:_IO_unsave_wmarkers=uninstrumented
+fun:_IO_vfprintf=uninstrumented
+fun:_IO_vfscanf=uninstrumented
+fun:_IO_vsprintf=uninstrumented
+fun:_IO_wdefault_doallocate=uninstrumented
+fun:_IO_wdefault_finish=uninstrumented
+fun:_IO_wdefault_pbackfail=uninstrumented
+fun:_IO_wdefault_uflow=uninstrumented
+fun:_IO_wdefault_xsgetn=uninstrumented
+fun:_IO_wdefault_xsputn=uninstrumented
+fun:_IO_wdo_write=uninstrumented
+fun:_IO_wdoallocbuf=uninstrumented
+fun:_IO_wfile_overflow=uninstrumented
+fun:_IO_wfile_seekoff=uninstrumented
+fun:_IO_wfile_sync=uninstrumented
+fun:_IO_wfile_underflow=uninstrumented
+fun:_IO_wfile_xsputn=uninstrumented
+fun:_IO_wmarker_delta=uninstrumented
+fun:_IO_wsetb=uninstrumented
+fun:_Unwind_Backtrace=uninstrumented
+fun:_Unwind_DeleteException=uninstrumented
+fun:_Unwind_FindEnclosingFunction=uninstrumented
+fun:_Unwind_Find_FDE=uninstrumented
+fun:_Unwind_ForcedUnwind=uninstrumented
+fun:_Unwind_GetCFA=uninstrumented
+fun:_Unwind_GetDataRelBase=uninstrumented
+fun:_Unwind_GetGR=uninstrumented
+fun:_Unwind_GetIP=uninstrumented
+fun:_Unwind_GetIPInfo=uninstrumented
+fun:_Unwind_GetLanguageSpecificData=uninstrumented
+fun:_Unwind_GetRegionStart=uninstrumented
+fun:_Unwind_GetTextRelBase=uninstrumented
+fun:_Unwind_RaiseException=uninstrumented
+fun:_Unwind_Resume=uninstrumented
+fun:_Unwind_Resume_or_Rethrow=uninstrumented
+fun:_Unwind_SetGR=uninstrumented
+fun:_Unwind_SetIP=uninstrumented
+fun:__absvdi2=uninstrumented
+fun:__absvsi2=uninstrumented
+fun:__absvti2=uninstrumented
+fun:__acos_finite=uninstrumented
+fun:__acosf_finite=uninstrumented
+fun:__acosh_finite=uninstrumented
+fun:__acoshf_finite=uninstrumented
+fun:__acoshl_finite=uninstrumented
+fun:__acosl_finite=uninstrumented
+fun:__addtf3=uninstrumented
+fun:__addvdi3=uninstrumented
+fun:__addvsi3=uninstrumented
+fun:__addvti3=uninstrumented
+fun:__adjtimex=uninstrumented
+fun:__arch_prctl=uninstrumented
+fun:__argz_count=uninstrumented
+fun:__argz_next=uninstrumented
+fun:__argz_stringify=uninstrumented
+fun:__ashlti3=uninstrumented
+fun:__ashrti3=uninstrumented
+fun:__asin_finite=uninstrumented
+fun:__asinf_finite=uninstrumented
+fun:__asinl_finite=uninstrumented
+fun:__asprintf=uninstrumented
+fun:__asprintf_chk=uninstrumented
+fun:__assert=uninstrumented
+fun:__assert_fail=uninstrumented
+fun:__assert_perror_fail=uninstrumented
+fun:__atan2_finite=uninstrumented
+fun:__atan2f_finite=uninstrumented
+fun:__atan2l_finite=uninstrumented
+fun:__atanh_finite=uninstrumented
+fun:__atanhf_finite=uninstrumented
+fun:__atanhl_finite=uninstrumented
+fun:__b64_ntop=uninstrumented
+fun:__b64_pton=uninstrumented
+fun:__backtrace=uninstrumented
+fun:__backtrace_symbols=uninstrumented
+fun:__backtrace_symbols_fd=uninstrumented
+fun:__bid128_abs=uninstrumented
+fun:__bid128_add=uninstrumented
+fun:__bid128_class=uninstrumented
+fun:__bid128_copy=uninstrumented
+fun:__bid128_copySign=uninstrumented
+fun:__bid128_div=uninstrumented
+fun:__bid128_fma=uninstrumented
+fun:__bid128_from_int32=uninstrumented
+fun:__bid128_from_int64=uninstrumented
+fun:__bid128_from_uint32=uninstrumented
+fun:__bid128_from_uint64=uninstrumented
+fun:__bid128_isCanonical=uninstrumented
+fun:__bid128_isFinite=uninstrumented
+fun:__bid128_isInf=uninstrumented
+fun:__bid128_isNaN=uninstrumented
+fun:__bid128_isNormal=uninstrumented
+fun:__bid128_isSignaling=uninstrumented
+fun:__bid128_isSigned=uninstrumented
+fun:__bid128_isSubnormal=uninstrumented
+fun:__bid128_isZero=uninstrumented
+fun:__bid128_mul=uninstrumented
+fun:__bid128_negate=uninstrumented
+fun:__bid128_quiet_equal=uninstrumented
+fun:__bid128_quiet_greater=uninstrumented
+fun:__bid128_quiet_greater_equal=uninstrumented
+fun:__bid128_quiet_greater_unordered=uninstrumented
+fun:__bid128_quiet_less=uninstrumented
+fun:__bid128_quiet_less_equal=uninstrumented
+fun:__bid128_quiet_less_unordered=uninstrumented
+fun:__bid128_quiet_not_equal=uninstrumented
+fun:__bid128_quiet_not_greater=uninstrumented
+fun:__bid128_quiet_not_less=uninstrumented
+fun:__bid128_quiet_ordered=uninstrumented
+fun:__bid128_quiet_unordered=uninstrumented
+fun:__bid128_radix=uninstrumented
+fun:__bid128_sameQuantum=uninstrumented
+fun:__bid128_signaling_greater=uninstrumented
+fun:__bid128_signaling_greater_equal=uninstrumented
+fun:__bid128_signaling_greater_unordered=uninstrumented
+fun:__bid128_signaling_less=uninstrumented
+fun:__bid128_signaling_less_equal=uninstrumented
+fun:__bid128_signaling_less_unordered=uninstrumented
+fun:__bid128_signaling_not_greater=uninstrumented
+fun:__bid128_signaling_not_less=uninstrumented
+fun:__bid128_sub=uninstrumented
+fun:__bid128_to_bid32=uninstrumented
+fun:__bid128_to_bid64=uninstrumented
+fun:__bid128_to_binary128=uninstrumented
+fun:__bid128_to_binary32=uninstrumented
+fun:__bid128_to_binary64=uninstrumented
+fun:__bid128_to_binary80=uninstrumented
+fun:__bid128_to_int32_ceil=uninstrumented
+fun:__bid128_to_int32_floor=uninstrumented
+fun:__bid128_to_int32_int=uninstrumented
+fun:__bid128_to_int32_rnint=uninstrumented
+fun:__bid128_to_int32_rninta=uninstrumented
+fun:__bid128_to_int32_xceil=uninstrumented
+fun:__bid128_to_int32_xfloor=uninstrumented
+fun:__bid128_to_int32_xint=uninstrumented
+fun:__bid128_to_int32_xrnint=uninstrumented
+fun:__bid128_to_int32_xrninta=uninstrumented
+fun:__bid128_to_int64_ceil=uninstrumented
+fun:__bid128_to_int64_floor=uninstrumented
+fun:__bid128_to_int64_int=uninstrumented
+fun:__bid128_to_int64_rnint=uninstrumented
+fun:__bid128_to_int64_rninta=uninstrumented
+fun:__bid128_to_int64_xceil=uninstrumented
+fun:__bid128_to_int64_xfloor=uninstrumented
+fun:__bid128_to_int64_xint=uninstrumented
+fun:__bid128_to_int64_xrnint=uninstrumented
+fun:__bid128_to_int64_xrninta=uninstrumented
+fun:__bid128_to_uint32_ceil=uninstrumented
+fun:__bid128_to_uint32_floor=uninstrumented
+fun:__bid128_to_uint32_int=uninstrumented
+fun:__bid128_to_uint32_rnint=uninstrumented
+fun:__bid128_to_uint32_rninta=uninstrumented
+fun:__bid128_to_uint32_xceil=uninstrumented
+fun:__bid128_to_uint32_xfloor=uninstrumented
+fun:__bid128_to_uint32_xint=uninstrumented
+fun:__bid128_to_uint32_xrnint=uninstrumented
+fun:__bid128_to_uint32_xrninta=uninstrumented
+fun:__bid128_to_uint64_ceil=uninstrumented
+fun:__bid128_to_uint64_floor=uninstrumented
+fun:__bid128_to_uint64_int=uninstrumented
+fun:__bid128_to_uint64_rnint=uninstrumented
+fun:__bid128_to_uint64_rninta=uninstrumented
+fun:__bid128_to_uint64_xceil=uninstrumented
+fun:__bid128_to_uint64_xfloor=uninstrumented
+fun:__bid128_to_uint64_xint=uninstrumented
+fun:__bid128_to_uint64_xrnint=uninstrumented
+fun:__bid128_to_uint64_xrninta=uninstrumented
+fun:__bid128_totalOrder=uninstrumented
+fun:__bid128_totalOrderMag=uninstrumented
+fun:__bid128dd_add=uninstrumented
+fun:__bid128dd_div=uninstrumented
+fun:__bid128dd_mul=uninstrumented
+fun:__bid128dd_sub=uninstrumented
+fun:__bid128ddd_fma=uninstrumented
+fun:__bid128ddq_fma=uninstrumented
+fun:__bid128dq_add=uninstrumented
+fun:__bid128dq_div=uninstrumented
+fun:__bid128dq_mul=uninstrumented
+fun:__bid128dq_sub=uninstrumented
+fun:__bid128dqd_fma=uninstrumented
+fun:__bid128dqq_fma=uninstrumented
+fun:__bid128qd_add=uninstrumented
+fun:__bid128qd_div=uninstrumented
+fun:__bid128qd_mul=uninstrumented
+fun:__bid128qd_sub=uninstrumented
+fun:__bid128qdd_fma=uninstrumented
+fun:__bid128qdq_fma=uninstrumented
+fun:__bid128qqd_fma=uninstrumented
+fun:__bid32_to_bid128=uninstrumented
+fun:__bid32_to_bid64=uninstrumented
+fun:__bid32_to_binary128=uninstrumented
+fun:__bid32_to_binary32=uninstrumented
+fun:__bid32_to_binary64=uninstrumented
+fun:__bid32_to_binary80=uninstrumented
+fun:__bid64_abs=uninstrumented
+fun:__bid64_add=uninstrumented
+fun:__bid64_class=uninstrumented
+fun:__bid64_copy=uninstrumented
+fun:__bid64_copySign=uninstrumented
+fun:__bid64_div=uninstrumented
+fun:__bid64_from_int32=uninstrumented
+fun:__bid64_from_int64=uninstrumented
+fun:__bid64_from_uint32=uninstrumented
+fun:__bid64_from_uint64=uninstrumented
+fun:__bid64_isCanonical=uninstrumented
+fun:__bid64_isFinite=uninstrumented
+fun:__bid64_isInf=uninstrumented
+fun:__bid64_isNaN=uninstrumented
+fun:__bid64_isNormal=uninstrumented
+fun:__bid64_isSignaling=uninstrumented
+fun:__bid64_isSigned=uninstrumented
+fun:__bid64_isSubnormal=uninstrumented
+fun:__bid64_isZero=uninstrumented
+fun:__bid64_mul=uninstrumented
+fun:__bid64_negate=uninstrumented
+fun:__bid64_quiet_equal=uninstrumented
+fun:__bid64_quiet_greater=uninstrumented
+fun:__bid64_quiet_greater_equal=uninstrumented
+fun:__bid64_quiet_greater_unordered=uninstrumented
+fun:__bid64_quiet_less=uninstrumented
+fun:__bid64_quiet_less_equal=uninstrumented
+fun:__bid64_quiet_less_unordered=uninstrumented
+fun:__bid64_quiet_not_equal=uninstrumented
+fun:__bid64_quiet_not_greater=uninstrumented
+fun:__bid64_quiet_not_less=uninstrumented
+fun:__bid64_quiet_ordered=uninstrumented
+fun:__bid64_quiet_unordered=uninstrumented
+fun:__bid64_radix=uninstrumented
+fun:__bid64_sameQuantum=uninstrumented
+fun:__bid64_signaling_greater=uninstrumented
+fun:__bid64_signaling_greater_equal=uninstrumented
+fun:__bid64_signaling_greater_unordered=uninstrumented
+fun:__bid64_signaling_less=uninstrumented
+fun:__bid64_signaling_less_equal=uninstrumented
+fun:__bid64_signaling_less_unordered=uninstrumented
+fun:__bid64_signaling_not_greater=uninstrumented
+fun:__bid64_signaling_not_less=uninstrumented
+fun:__bid64_sub=uninstrumented
+fun:__bid64_to_bid128=uninstrumented
+fun:__bid64_to_bid32=uninstrumented
+fun:__bid64_to_binary128=uninstrumented
+fun:__bid64_to_binary32=uninstrumented
+fun:__bid64_to_binary64=uninstrumented
+fun:__bid64_to_binary80=uninstrumented
+fun:__bid64_to_int32_ceil=uninstrumented
+fun:__bid64_to_int32_floor=uninstrumented
+fun:__bid64_to_int32_int=uninstrumented
+fun:__bid64_to_int32_rnint=uninstrumented
+fun:__bid64_to_int32_rninta=uninstrumented
+fun:__bid64_to_int32_xceil=uninstrumented
+fun:__bid64_to_int32_xfloor=uninstrumented
+fun:__bid64_to_int32_xint=uninstrumented
+fun:__bid64_to_int32_xrnint=uninstrumented
+fun:__bid64_to_int32_xrninta=uninstrumented
+fun:__bid64_to_int64_ceil=uninstrumented
+fun:__bid64_to_int64_floor=uninstrumented
+fun:__bid64_to_int64_int=uninstrumented
+fun:__bid64_to_int64_rnint=uninstrumented
+fun:__bid64_to_int64_rninta=uninstrumented
+fun:__bid64_to_int64_xceil=uninstrumented
+fun:__bid64_to_int64_xfloor=uninstrumented
+fun:__bid64_to_int64_xint=uninstrumented
+fun:__bid64_to_int64_xrnint=uninstrumented
+fun:__bid64_to_int64_xrninta=uninstrumented
+fun:__bid64_to_uint32_ceil=uninstrumented
+fun:__bid64_to_uint32_floor=uninstrumented
+fun:__bid64_to_uint32_int=uninstrumented
+fun:__bid64_to_uint32_rnint=uninstrumented
+fun:__bid64_to_uint32_rninta=uninstrumented
+fun:__bid64_to_uint32_xceil=uninstrumented
+fun:__bid64_to_uint32_xfloor=uninstrumented
+fun:__bid64_to_uint32_xint=uninstrumented
+fun:__bid64_to_uint32_xrnint=uninstrumented
+fun:__bid64_to_uint32_xrninta=uninstrumented
+fun:__bid64_to_uint64_ceil=uninstrumented
+fun:__bid64_to_uint64_floor=uninstrumented
+fun:__bid64_to_uint64_int=uninstrumented
+fun:__bid64_to_uint64_rnint=uninstrumented
+fun:__bid64_to_uint64_rninta=uninstrumented
+fun:__bid64_to_uint64_xceil=uninstrumented
+fun:__bid64_to_uint64_xfloor=uninstrumented
+fun:__bid64_to_uint64_xint=uninstrumented
+fun:__bid64_to_uint64_xrnint=uninstrumented
+fun:__bid64_to_uint64_xrninta=uninstrumented
+fun:__bid64_totalOrder=uninstrumented
+fun:__bid64_totalOrderMag=uninstrumented
+fun:__bid64ddq_fma=uninstrumented
+fun:__bid64dq_add=uninstrumented
+fun:__bid64dq_div=uninstrumented
+fun:__bid64dq_mul=uninstrumented
+fun:__bid64dq_sub=uninstrumented
+fun:__bid64dqd_fma=uninstrumented
+fun:__bid64dqq_fma=uninstrumented
+fun:__bid64qd_add=uninstrumented
+fun:__bid64qd_div=uninstrumented
+fun:__bid64qd_mul=uninstrumented
+fun:__bid64qd_sub=uninstrumented
+fun:__bid64qdd_fma=uninstrumented
+fun:__bid64qdq_fma=uninstrumented
+fun:__bid64qq_add=uninstrumented
+fun:__bid64qq_div=uninstrumented
+fun:__bid64qq_mul=uninstrumented
+fun:__bid64qq_sub=uninstrumented
+fun:__bid64qqd_fma=uninstrumented
+fun:__bid64qqq_fma=uninstrumented
+fun:__bid_adddd3=uninstrumented
+fun:__bid_addsd3=uninstrumented
+fun:__bid_addtd3=uninstrumented
+fun:__bid_divdd3=uninstrumented
+fun:__bid_divsd3=uninstrumented
+fun:__bid_divtd3=uninstrumented
+fun:__bid_eqdd2=uninstrumented
+fun:__bid_eqsd2=uninstrumented
+fun:__bid_eqtd2=uninstrumented
+fun:__bid_extendddtd2=uninstrumented
+fun:__bid_extendddtf=uninstrumented
+fun:__bid_extendddxf=uninstrumented
+fun:__bid_extenddfdd=uninstrumented
+fun:__bid_extenddftd=uninstrumented
+fun:__bid_extendsddd2=uninstrumented
+fun:__bid_extendsddf=uninstrumented
+fun:__bid_extendsdtd2=uninstrumented
+fun:__bid_extendsdtf=uninstrumented
+fun:__bid_extendsdxf=uninstrumented
+fun:__bid_extendsfdd=uninstrumented
+fun:__bid_extendsfsd=uninstrumented
+fun:__bid_extendsftd=uninstrumented
+fun:__bid_extendtftd=uninstrumented
+fun:__bid_extendxftd=uninstrumented
+fun:__bid_fixdddi=uninstrumented
+fun:__bid_fixddsi=uninstrumented
+fun:__bid_fixsddi=uninstrumented
+fun:__bid_fixsdsi=uninstrumented
+fun:__bid_fixtddi=uninstrumented
+fun:__bid_fixtdsi=uninstrumented
+fun:__bid_fixunsdddi=uninstrumented
+fun:__bid_fixunsddsi=uninstrumented
+fun:__bid_fixunssddi=uninstrumented
+fun:__bid_fixunssdsi=uninstrumented
+fun:__bid_fixunstddi=uninstrumented
+fun:__bid_fixunstdsi=uninstrumented
+fun:__bid_floatdidd=uninstrumented
+fun:__bid_floatdisd=uninstrumented
+fun:__bid_floatditd=uninstrumented
+fun:__bid_floatsidd=uninstrumented
+fun:__bid_floatsisd=uninstrumented
+fun:__bid_floatsitd=uninstrumented
+fun:__bid_floatunsdidd=uninstrumented
+fun:__bid_floatunsdisd=uninstrumented
+fun:__bid_floatunsditd=uninstrumented
+fun:__bid_floatunssidd=uninstrumented
+fun:__bid_floatunssisd=uninstrumented
+fun:__bid_floatunssitd=uninstrumented
+fun:__bid_gedd2=uninstrumented
+fun:__bid_gesd2=uninstrumented
+fun:__bid_getd2=uninstrumented
+fun:__bid_gtdd2=uninstrumented
+fun:__bid_gtsd2=uninstrumented
+fun:__bid_gttd2=uninstrumented
+fun:__bid_ledd2=uninstrumented
+fun:__bid_lesd2=uninstrumented
+fun:__bid_letd2=uninstrumented
+fun:__bid_ltdd2=uninstrumented
+fun:__bid_ltsd2=uninstrumented
+fun:__bid_lttd2=uninstrumented
+fun:__bid_muldd3=uninstrumented
+fun:__bid_mulsd3=uninstrumented
+fun:__bid_multd3=uninstrumented
+fun:__bid_nedd2=uninstrumented
+fun:__bid_nesd2=uninstrumented
+fun:__bid_netd2=uninstrumented
+fun:__bid_round128_19_38=uninstrumented
+fun:__bid_round192_39_57=uninstrumented
+fun:__bid_round256_58_76=uninstrumented
+fun:__bid_round64_2_18=uninstrumented
+fun:__bid_subdd3=uninstrumented
+fun:__bid_subsd3=uninstrumented
+fun:__bid_subtd3=uninstrumented
+fun:__bid_truncdddf=uninstrumented
+fun:__bid_truncddsd2=uninstrumented
+fun:__bid_truncddsf=uninstrumented
+fun:__bid_truncdfsd=uninstrumented
+fun:__bid_truncsdsf=uninstrumented
+fun:__bid_trunctddd2=uninstrumented
+fun:__bid_trunctddf=uninstrumented
+fun:__bid_trunctdsd2=uninstrumented
+fun:__bid_trunctdsf=uninstrumented
+fun:__bid_trunctdtf=uninstrumented
+fun:__bid_trunctdxf=uninstrumented
+fun:__bid_trunctfdd=uninstrumented
+fun:__bid_trunctfsd=uninstrumented
+fun:__bid_truncxfdd=uninstrumented
+fun:__bid_truncxfsd=uninstrumented
+fun:__bid_unorddd2=uninstrumented
+fun:__bid_unordsd2=uninstrumented
+fun:__bid_unordtd2=uninstrumented
+fun:__binary128_to_bid128=uninstrumented
+fun:__binary128_to_bid32=uninstrumented
+fun:__binary128_to_bid64=uninstrumented
+fun:__binary32_to_bid128=uninstrumented
+fun:__binary32_to_bid32=uninstrumented
+fun:__binary32_to_bid64=uninstrumented
+fun:__binary64_to_bid128=uninstrumented
+fun:__binary64_to_bid32=uninstrumented
+fun:__binary64_to_bid64=uninstrumented
+fun:__binary80_to_bid128=uninstrumented
+fun:__binary80_to_bid32=uninstrumented
+fun:__binary80_to_bid64=uninstrumented
+fun:__bsd_getpgrp=uninstrumented
+fun:__bswapdi2=uninstrumented
+fun:__bswapsi2=uninstrumented
+fun:__bzero=uninstrumented
+fun:__call_tls_dtors=uninstrumented
+fun:__chk_fail=uninstrumented
+fun:__clear_cache=uninstrumented
+fun:__clock_getcpuclockid=uninstrumented
+fun:__clock_getres=uninstrumented
+fun:__clock_gettime=uninstrumented
+fun:__clock_nanosleep=uninstrumented
+fun:__clock_settime=uninstrumented
+fun:__clog10=uninstrumented
+fun:__clog10f=uninstrumented
+fun:__clog10l=uninstrumented
+fun:__clone=uninstrumented
+fun:__close=uninstrumented
+fun:__clrsbdi2=uninstrumented
+fun:__clrsbti2=uninstrumented
+fun:__clzdi2=uninstrumented
+fun:__clzti2=uninstrumented
+fun:__cmpti2=uninstrumented
+fun:__cmsg_nxthdr=uninstrumented
+fun:__confstr_chk=uninstrumented
+fun:__connect=uninstrumented
+fun:__cosh_finite=uninstrumented
+fun:__coshf_finite=uninstrumented
+fun:__coshl_finite=uninstrumented
+fun:__cpu_indicator_init=uninstrumented
+fun:__create_ib_request=uninstrumented
+fun:__ctype_b_loc=uninstrumented
+fun:__ctype_get_mb_cur_max=uninstrumented
+fun:__ctype_init=uninstrumented
+fun:__ctype_tolower_loc=uninstrumented
+fun:__ctype_toupper_loc=uninstrumented
+fun:__ctzdi2=uninstrumented
+fun:__ctzti2=uninstrumented
+fun:__cxa_at_quick_exit=uninstrumented
+fun:__cxa_atexit=uninstrumented
+fun:__cxa_finalize=uninstrumented
+fun:__cxa_thread_atexit_impl=uninstrumented
+fun:__cyg_profile_func_enter=uninstrumented
+fun:__cyg_profile_func_exit=uninstrumented
+fun:__dcgettext=uninstrumented
+fun:__default_morecore=uninstrumented
+fun:__deregister_frame=uninstrumented
+fun:__deregister_frame_info=uninstrumented
+fun:__deregister_frame_info_bases=uninstrumented
+fun:__dfp_clear_except=uninstrumented
+fun:__dfp_get_round=uninstrumented
+fun:__dfp_raise_except=uninstrumented
+fun:__dfp_set_round=uninstrumented
+fun:__dfp_test_except=uninstrumented
+fun:__dgettext=uninstrumented
+fun:__divdc3=uninstrumented
+fun:__divsc3=uninstrumented
+fun:__divtc3=uninstrumented
+fun:__divtf3=uninstrumented
+fun:__divti3=uninstrumented
+fun:__divxc3=uninstrumented
+fun:__dn_comp=uninstrumented
+fun:__dn_count_labels=uninstrumented
+fun:__dn_expand=uninstrumented
+fun:__dn_skipname=uninstrumented
+fun:__do_niscall3=uninstrumented
+fun:__dprintf_chk=uninstrumented
+fun:__dup2=uninstrumented
+fun:__duplocale=uninstrumented
+fun:__emutls_get_address=uninstrumented
+fun:__emutls_register_common=uninstrumented
+fun:__enable_execute_stack=uninstrumented
+fun:__endmntent=uninstrumented
+fun:__eprintf=uninstrumented
+fun:__eqtf2=uninstrumented
+fun:__errno_location=uninstrumented
+fun:__exp10_finite=uninstrumented
+fun:__exp10f_finite=uninstrumented
+fun:__exp10l_finite=uninstrumented
+fun:__exp2_finite=uninstrumented
+fun:__exp2f_finite=uninstrumented
+fun:__exp2l_finite=uninstrumented
+fun:__exp_finite=uninstrumented
+fun:__expf_finite=uninstrumented
+fun:__expl_finite=uninstrumented
+fun:__extenddftf2=uninstrumented
+fun:__extendsftf2=uninstrumented
+fun:__extendxftf2=uninstrumented
+fun:__fbufsize=uninstrumented
+fun:__fcntl=uninstrumented
+fun:__fdelt_chk=uninstrumented
+fun:__fdelt_warn=uninstrumented
+fun:__fentry__=uninstrumented
+fun:__ffs=uninstrumented
+fun:__ffsdi2=uninstrumented
+fun:__ffsti2=uninstrumented
+fun:__fgets_chk=uninstrumented
+fun:__fgets_unlocked_chk=uninstrumented
+fun:__fgetws_chk=uninstrumented
+fun:__fgetws_unlocked_chk=uninstrumented
+fun:__finite=uninstrumented
+fun:__finitef=uninstrumented
+fun:__finitel=uninstrumented
+fun:__fixdfti=uninstrumented
+fun:__fixsfti=uninstrumented
+fun:__fixtfdi=uninstrumented
+fun:__fixtfsi=uninstrumented
+fun:__fixtfti=uninstrumented
+fun:__fixunsdfdi=uninstrumented
+fun:__fixunsdfti=uninstrumented
+fun:__fixunssfdi=uninstrumented
+fun:__fixunssfti=uninstrumented
+fun:__fixunstfdi=uninstrumented
+fun:__fixunstfsi=uninstrumented
+fun:__fixunstfti=uninstrumented
+fun:__fixunsxfdi=uninstrumented
+fun:__fixunsxfti=uninstrumented
+fun:__fixxfti=uninstrumented
+fun:__flbf=uninstrumented
+fun:__floatditf=uninstrumented
+fun:__floatsitf=uninstrumented
+fun:__floattidf=uninstrumented
+fun:__floattisf=uninstrumented
+fun:__floattitf=uninstrumented
+fun:__floattixf=uninstrumented
+fun:__floatunditf=uninstrumented
+fun:__floatunsitf=uninstrumented
+fun:__floatuntidf=uninstrumented
+fun:__floatuntisf=uninstrumented
+fun:__floatuntitf=uninstrumented
+fun:__floatuntixf=uninstrumented
+fun:__fmod_finite=uninstrumented
+fun:__fmodf_finite=uninstrumented
+fun:__fmodl_finite=uninstrumented
+fun:__follow_path=uninstrumented
+fun:__fork=uninstrumented
+fun:__fortify_fail=uninstrumented
+fun:__fp_nquery=uninstrumented
+fun:__fp_query=uninstrumented
+fun:__fp_resstat=uninstrumented
+fun:__fpclassify=uninstrumented
+fun:__fpclassifyf=uninstrumented
+fun:__fpclassifyl=uninstrumented
+fun:__fpending=uninstrumented
+fun:__fprintf_chk=uninstrumented
+fun:__fpurge=uninstrumented
+fun:__fread_chk=uninstrumented
+fun:__fread_unlocked_chk=uninstrumented
+fun:__freadable=uninstrumented
+fun:__freading=uninstrumented
+fun:__free_fdresult=uninstrumented
+fun:__freelocale=uninstrumented
+fun:__fsetlocking=uninstrumented
+fun:__fstat=uninstrumented
+fun:__fwprintf_chk=uninstrumented
+fun:__fwritable=uninstrumented
+fun:__fwriting=uninstrumented
+fun:__fxstat=uninstrumented
+fun:__fxstat64=uninstrumented
+fun:__fxstatat=uninstrumented
+fun:__fxstatat64=uninstrumented
+fun:__gai_sigqueue=uninstrumented
+fun:__gamma_r_finite=uninstrumented
+fun:__gammaf_r_finite=uninstrumented
+fun:__gammal_r_finite=uninstrumented
+fun:__gcc_bcmp=uninstrumented
+fun:__gcc_personality_v0=uninstrumented
+fun:__gconv_get_alias_db=uninstrumented
+fun:__gconv_get_cache=uninstrumented
+fun:__gconv_get_modules_db=uninstrumented
+fun:__generic_findstack=uninstrumented
+fun:__generic_morestack=uninstrumented
+fun:__generic_morestack_set_initial_sp=uninstrumented
+fun:__generic_releasestack=uninstrumented
+fun:__get_cpu_features=uninstrumented
+fun:__getauxval=uninstrumented
+fun:__getcwd_chk=uninstrumented
+fun:__getdelim=uninstrumented
+fun:__getdomainname_chk=uninstrumented
+fun:__getf2=uninstrumented
+fun:__getgroups_chk=uninstrumented
+fun:__gethostname_chk=uninstrumented
+fun:__getlogin_r_chk=uninstrumented
+fun:__getmntent_r=uninstrumented
+fun:__getpagesize=uninstrumented
+fun:__getpgid=uninstrumented
+fun:__getpid=uninstrumented
+fun:__gets_chk=uninstrumented
+fun:__gettimeofday=uninstrumented
+fun:__getwd_chk=uninstrumented
+fun:__gmtime_r=uninstrumented
+fun:__gttf2=uninstrumented
+fun:__h_errno_location=uninstrumented
+fun:__hostalias=uninstrumented
+fun:__hypot_finite=uninstrumented
+fun:__hypotf_finite=uninstrumented
+fun:__hypotl_finite=uninstrumented
+fun:__internal_endnetgrent=uninstrumented
+fun:__internal_getnetgrent_r=uninstrumented
+fun:__internal_setnetgrent=uninstrumented
+fun:__isalnum_l=uninstrumented
+fun:__isalpha_l=uninstrumented
+fun:__isascii_l=uninstrumented
+fun:__isblank_l=uninstrumented
+fun:__iscntrl_l=uninstrumented
+fun:__isctype=uninstrumented
+fun:__isdigit_l=uninstrumented
+fun:__isgraph_l=uninstrumented
+fun:__isinf=uninstrumented
+fun:__isinff=uninstrumented
+fun:__isinfl=uninstrumented
+fun:__islower_l=uninstrumented
+fun:__isnan=uninstrumented
+fun:__isnanf=uninstrumented
+fun:__isnanl=uninstrumented
+fun:__isoc99_fscanf=uninstrumented
+fun:__isoc99_fwscanf=uninstrumented
+fun:__isoc99_scanf=uninstrumented
+fun:__isoc99_sscanf=uninstrumented
+fun:__isoc99_swscanf=uninstrumented
+fun:__isoc99_vfscanf=uninstrumented
+fun:__isoc99_vfwscanf=uninstrumented
+fun:__isoc99_vscanf=uninstrumented
+fun:__isoc99_vsscanf=uninstrumented
+fun:__isoc99_vswscanf=uninstrumented
+fun:__isoc99_vwscanf=uninstrumented
+fun:__isoc99_wscanf=uninstrumented
+fun:__isprint_l=uninstrumented
+fun:__ispunct_l=uninstrumented
+fun:__issignaling=uninstrumented
+fun:__issignalingf=uninstrumented
+fun:__issignalingl=uninstrumented
+fun:__isspace_l=uninstrumented
+fun:__isupper_l=uninstrumented
+fun:__iswalnum_l=uninstrumented
+fun:__iswalpha_l=uninstrumented
+fun:__iswblank_l=uninstrumented
+fun:__iswcntrl_l=uninstrumented
+fun:__iswctype=uninstrumented
+fun:__iswctype_l=uninstrumented
+fun:__iswdigit_l=uninstrumented
+fun:__iswgraph_l=uninstrumented
+fun:__iswlower_l=uninstrumented
+fun:__iswprint_l=uninstrumented
+fun:__iswpunct_l=uninstrumented
+fun:__iswspace_l=uninstrumented
+fun:__iswupper_l=uninstrumented
+fun:__iswxdigit_l=uninstrumented
+fun:__isxdigit_l=uninstrumented
+fun:__ivaliduser=uninstrumented
+fun:__j0_finite=uninstrumented
+fun:__j0f_finite=uninstrumented
+fun:__j0l_finite=uninstrumented
+fun:__j1_finite=uninstrumented
+fun:__j1f_finite=uninstrumented
+fun:__j1l_finite=uninstrumented
+fun:__jn_finite=uninstrumented
+fun:__jnf_finite=uninstrumented
+fun:__jnl_finite=uninstrumented
+fun:__letf2=uninstrumented
+fun:__lgamma_r_finite=uninstrumented
+fun:__lgammaf_r_finite=uninstrumented
+fun:__lgammal_r_finite=uninstrumented
+fun:__libc_alloca_cutoff=uninstrumented
+fun:__libc_allocate_rtsig=uninstrumented
+fun:__libc_allocate_rtsig_private=uninstrumented
+fun:__libc_calloc=uninstrumented
+fun:__libc_clntudp_bufcreate=uninstrumented
+fun:__libc_csu_fini=uninstrumented
+fun:__libc_csu_init=uninstrumented
+fun:__libc_current_sigrtmax=uninstrumented
+fun:__libc_current_sigrtmax_private=uninstrumented
+fun:__libc_current_sigrtmin=uninstrumented
+fun:__libc_current_sigrtmin_private=uninstrumented
+fun:__libc_dl_error_tsd=uninstrumented
+fun:__libc_dlclose=uninstrumented
+fun:__libc_dlopen_mode=uninstrumented
+fun:__libc_dlsym=uninstrumented
+fun:__libc_fatal=uninstrumented
+fun:__libc_fork=uninstrumented
+fun:__libc_free=uninstrumented
+fun:__libc_freeres=uninstrumented
+fun:__libc_ifunc_impl_list=uninstrumented
+fun:__libc_init_first=uninstrumented
+fun:__libc_longjmp=uninstrumented
+fun:__libc_mallinfo=uninstrumented
+fun:__libc_malloc=uninstrumented
+fun:__libc_mallopt=uninstrumented
+fun:__libc_memalign=uninstrumented
+fun:__libc_pthread_init=uninstrumented
+fun:__libc_pvalloc=uninstrumented
+fun:__libc_pwrite=uninstrumented
+fun:__libc_realloc=uninstrumented
+fun:__libc_res_nquery=uninstrumented
+fun:__libc_res_nsearch=uninstrumented
+fun:__libc_rpc_getport=uninstrumented
+fun:__libc_sa_len=uninstrumented
+fun:__libc_secure_getenv=uninstrumented
+fun:__libc_siglongjmp=uninstrumented
+fun:__libc_start_main=uninstrumented
+fun:__libc_system=uninstrumented
+fun:__libc_thread_freeres=uninstrumented
+fun:__libc_valloc=uninstrumented
+fun:__loc_aton=uninstrumented
+fun:__loc_ntoa=uninstrumented
+fun:__log10_finite=uninstrumented
+fun:__log10f_finite=uninstrumented
+fun:__log10l_finite=uninstrumented
+fun:__log2_finite=uninstrumented
+fun:__log2f_finite=uninstrumented
+fun:__log2l_finite=uninstrumented
+fun:__log_finite=uninstrumented
+fun:__logf_finite=uninstrumented
+fun:__logl_finite=uninstrumented
+fun:__longjmp_chk=uninstrumented
+fun:__lseek=uninstrumented
+fun:__lshrti3=uninstrumented
+fun:__lstat=uninstrumented
+fun:__lttf2=uninstrumented
+fun:__lxstat=uninstrumented
+fun:__lxstat64=uninstrumented
+fun:__madvise=uninstrumented
+fun:__mbrlen=uninstrumented
+fun:__mbrtowc=uninstrumented
+fun:__mbsnrtowcs_chk=uninstrumented
+fun:__mbsrtowcs_chk=uninstrumented
+fun:__mbstowcs_chk=uninstrumented
+fun:__memcpy_chk=uninstrumented
+fun:__memmove_chk=uninstrumented
+fun:__mempcpy=uninstrumented
+fun:__mempcpy_chk=uninstrumented
+fun:__mempcpy_small=uninstrumented
+fun:__memset_chk=uninstrumented
+fun:__mknod=uninstrumented
+fun:__mktemp=uninstrumented
+fun:__modti3=uninstrumented
+fun:__monstartup=uninstrumented
+fun:__morestack=uninstrumented
+fun:__morestack_allocate_stack_space=uninstrumented
+fun:__morestack_block_signals=uninstrumented
+fun:__morestack_fail=uninstrumented
+fun:__morestack_get_guard=uninstrumented
+fun:__morestack_large_model=uninstrumented
+fun:__morestack_load_mmap=uninstrumented
+fun:__morestack_make_guard=uninstrumented
+fun:__morestack_non_split=uninstrumented
+fun:__morestack_release_segments=uninstrumented
+fun:__morestack_set_guard=uninstrumented
+fun:__morestack_unblock_signals=uninstrumented
+fun:__mq_open_2=uninstrumented
+fun:__muldc3=uninstrumented
+fun:__mulsc3=uninstrumented
+fun:__multc3=uninstrumented
+fun:__multf3=uninstrumented
+fun:__multi3=uninstrumented
+fun:__mulvdi3=uninstrumented
+fun:__mulvsi3=uninstrumented
+fun:__mulvti3=uninstrumented
+fun:__mulxc3=uninstrumented
+fun:__nanosleep=uninstrumented
+fun:__negtf2=uninstrumented
+fun:__negti2=uninstrumented
+fun:__negvdi2=uninstrumented
+fun:__negvsi2=uninstrumented
+fun:__negvti2=uninstrumented
+fun:__netf2=uninstrumented
+fun:__newlocale=uninstrumented
+fun:__nis_default_access=uninstrumented
+fun:__nis_default_group=uninstrumented
+fun:__nis_default_owner=uninstrumented
+fun:__nis_default_ttl=uninstrumented
+fun:__nis_finddirectory=uninstrumented
+fun:__nis_hash=uninstrumented
+fun:__nisbind_connect=uninstrumented
+fun:__nisbind_create=uninstrumented
+fun:__nisbind_destroy=uninstrumented
+fun:__nisbind_next=uninstrumented
+fun:__nl_langinfo_l=uninstrumented
+fun:__ns_get16=uninstrumented
+fun:__ns_get32=uninstrumented
+fun:__ns_name_ntop=uninstrumented
+fun:__ns_name_unpack=uninstrumented
+fun:__nss_configure_lookup=uninstrumented
+fun:__nss_database_lookup=uninstrumented
+fun:__nss_disable_nscd=uninstrumented
+fun:__nss_group_lookup=uninstrumented
+fun:__nss_group_lookup2=uninstrumented
+fun:__nss_hostname_digits_dots=uninstrumented
+fun:__nss_hosts_lookup=uninstrumented
+fun:__nss_hosts_lookup2=uninstrumented
+fun:__nss_lookup=uninstrumented
+fun:__nss_lookup_function=uninstrumented
+fun:__nss_next=uninstrumented
+fun:__nss_next2=uninstrumented
+fun:__nss_passwd_lookup=uninstrumented
+fun:__nss_passwd_lookup2=uninstrumented
+fun:__nss_services_lookup2=uninstrumented
+fun:__obstack_printf_chk=uninstrumented
+fun:__obstack_vprintf_chk=uninstrumented
+fun:__open=uninstrumented
+fun:__open64=uninstrumented
+fun:__open64_2=uninstrumented
+fun:__open_2=uninstrumented
+fun:__open_catalog=uninstrumented
+fun:__openat64_2=uninstrumented
+fun:__openat_2=uninstrumented
+fun:__overflow=uninstrumented
+fun:__p_cdname=uninstrumented
+fun:__p_cdnname=uninstrumented
+fun:__p_class=uninstrumented
+fun:__p_fqname=uninstrumented
+fun:__p_fqnname=uninstrumented
+fun:__p_option=uninstrumented
+fun:__p_query=uninstrumented
+fun:__p_rcode=uninstrumented
+fun:__p_secstodate=uninstrumented
+fun:__p_time=uninstrumented
+fun:__p_type=uninstrumented
+fun:__paritydi2=uninstrumented
+fun:__parityti2=uninstrumented
+fun:__pipe=uninstrumented
+fun:__poll=uninstrumented
+fun:__poll_chk=uninstrumented
+fun:__popcountdi2=uninstrumented
+fun:__popcountti2=uninstrumented
+fun:__posix_getopt=uninstrumented
+fun:__pow_finite=uninstrumented
+fun:__powf_finite=uninstrumented
+fun:__powidf2=uninstrumented
+fun:__powisf2=uninstrumented
+fun:__powitf2=uninstrumented
+fun:__powixf2=uninstrumented
+fun:__powl_finite=uninstrumented
+fun:__ppoll_chk=uninstrumented
+fun:__pread64=uninstrumented
+fun:__pread64_chk=uninstrumented
+fun:__pread_chk=uninstrumented
+fun:__prepare_niscall=uninstrumented
+fun:__printf_chk=uninstrumented
+fun:__printf_fp=uninstrumented
+fun:__profile_frequency=uninstrumented
+fun:__pthread_atfork=uninstrumented
+fun:__pthread_cleanup_routine=uninstrumented
+fun:__pthread_clock_gettime=uninstrumented
+fun:__pthread_clock_settime=uninstrumented
+fun:__pthread_get_minstack=uninstrumented
+fun:__pthread_getspecific=uninstrumented
+fun:__pthread_initialize_minimal=uninstrumented
+fun:__pthread_key_create=uninstrumented
+fun:__pthread_mutex_destroy=uninstrumented
+fun:__pthread_mutex_init=uninstrumented
+fun:__pthread_mutex_lock=uninstrumented
+fun:__pthread_mutex_trylock=uninstrumented
+fun:__pthread_mutex_unlock=uninstrumented
+fun:__pthread_mutexattr_destroy=uninstrumented
+fun:__pthread_mutexattr_init=uninstrumented
+fun:__pthread_mutexattr_settype=uninstrumented
+fun:__pthread_once=uninstrumented
+fun:__pthread_register_cancel=uninstrumented
+fun:__pthread_register_cancel_defer=uninstrumented
+fun:__pthread_rwlock_destroy=uninstrumented
+fun:__pthread_rwlock_init=uninstrumented
+fun:__pthread_rwlock_rdlock=uninstrumented
+fun:__pthread_rwlock_tryrdlock=uninstrumented
+fun:__pthread_rwlock_trywrlock=uninstrumented
+fun:__pthread_rwlock_unlock=uninstrumented
+fun:__pthread_rwlock_wrlock=uninstrumented
+fun:__pthread_setspecific=uninstrumented
+fun:__pthread_unregister_cancel=uninstrumented
+fun:__pthread_unregister_cancel_restore=uninstrumented
+fun:__pthread_unwind=uninstrumented
+fun:__pthread_unwind_next=uninstrumented
+fun:__ptsname_r_chk=uninstrumented
+fun:__putlong=uninstrumented
+fun:__putshort=uninstrumented
+fun:__pwrite64=uninstrumented
+fun:__rawmemchr=uninstrumented
+fun:__read=uninstrumented
+fun:__read_chk=uninstrumented
+fun:__readlink_chk=uninstrumented
+fun:__readlinkat_chk=uninstrumented
+fun:__realpath_chk=uninstrumented
+fun:__recv_chk=uninstrumented
+fun:__recvfrom_chk=uninstrumented
+fun:__register_atfork=uninstrumented
+fun:__register_frame=uninstrumented
+fun:__register_frame_info=uninstrumented
+fun:__register_frame_info_bases=uninstrumented
+fun:__register_frame_info_table=uninstrumented
+fun:__register_frame_info_table_bases=uninstrumented
+fun:__register_frame_table=uninstrumented
+fun:__remainder_finite=uninstrumented
+fun:__remainderf_finite=uninstrumented
+fun:__remainderl_finite=uninstrumented
+fun:__res_close=uninstrumented
+fun:__res_dnok=uninstrumented
+fun:__res_hnok=uninstrumented
+fun:__res_hostalias=uninstrumented
+fun:__res_iclose=uninstrumented
+fun:__res_init=uninstrumented
+fun:__res_isourserver=uninstrumented
+fun:__res_mailok=uninstrumented
+fun:__res_maybe_init=uninstrumented
+fun:__res_mkquery=uninstrumented
+fun:__res_nameinquery=uninstrumented
+fun:__res_nclose=uninstrumented
+fun:__res_ninit=uninstrumented
+fun:__res_nmkquery=uninstrumented
+fun:__res_nquery=uninstrumented
+fun:__res_nquerydomain=uninstrumented
+fun:__res_nsearch=uninstrumented
+fun:__res_nsend=uninstrumented
+fun:__res_ownok=uninstrumented
+fun:__res_queriesmatch=uninstrumented
+fun:__res_query=uninstrumented
+fun:__res_querydomain=uninstrumented
+fun:__res_randomid=uninstrumented
+fun:__res_search=uninstrumented
+fun:__res_send=uninstrumented
+fun:__res_state=uninstrumented
+fun:__rpc_thread_createerr=uninstrumented
+fun:__rpc_thread_svc_fdset=uninstrumented
+fun:__rpc_thread_svc_max_pollfd=uninstrumented
+fun:__rpc_thread_svc_pollfd=uninstrumented
+fun:__sbrk=uninstrumented
+fun:__scalb_finite=uninstrumented
+fun:__scalbf_finite=uninstrumented
+fun:__scalbl_finite=uninstrumented
+fun:__sched_cpualloc=uninstrumented
+fun:__sched_cpucount=uninstrumented
+fun:__sched_cpufree=uninstrumented
+fun:__sched_get_priority_max=uninstrumented
+fun:__sched_get_priority_min=uninstrumented
+fun:__sched_getparam=uninstrumented
+fun:__sched_getscheduler=uninstrumented
+fun:__sched_setscheduler=uninstrumented
+fun:__sched_yield=uninstrumented
+fun:__secure_getenv=uninstrumented
+fun:__select=uninstrumented
+fun:__send=uninstrumented
+fun:__sendmmsg=uninstrumented
+fun:__setmntent=uninstrumented
+fun:__setpgid=uninstrumented
+fun:__sfp_handle_exceptions=uninstrumented
+fun:__sigaction=uninstrumented
+fun:__sigaddset=uninstrumented
+fun:__sigdelset=uninstrumented
+fun:__sigismember=uninstrumented
+fun:__signbit=uninstrumented
+fun:__signbitf=uninstrumented
+fun:__signbitl=uninstrumented
+fun:__sigpause=uninstrumented
+fun:__sigsetjmp=uninstrumented
+fun:__sigsuspend=uninstrumented
+fun:__sinh_finite=uninstrumented
+fun:__sinhf_finite=uninstrumented
+fun:__sinhl_finite=uninstrumented
+fun:__snprintf_chk=uninstrumented
+fun:__splitstack_block_signals=uninstrumented
+fun:__splitstack_block_signals_context=uninstrumented
+fun:__splitstack_find=uninstrumented
+fun:__splitstack_find_context=uninstrumented
+fun:__splitstack_getcontext=uninstrumented
+fun:__splitstack_makecontext=uninstrumented
+fun:__splitstack_releasecontext=uninstrumented
+fun:__splitstack_resetcontext=uninstrumented
+fun:__splitstack_setcontext=uninstrumented
+fun:__sprintf_chk=uninstrumented
+fun:__sqrt_finite=uninstrumented
+fun:__sqrtf_finite=uninstrumented
+fun:__sqrtl_finite=uninstrumented
+fun:__stack_chk_fail=uninstrumented
+fun:__stack_chk_fail_local=uninstrumented
+fun:__stack_split_initialize=uninstrumented
+fun:__stat=uninstrumented
+fun:__statfs=uninstrumented
+fun:__stpcpy=uninstrumented
+fun:__stpcpy_chk=uninstrumented
+fun:__stpcpy_small=uninstrumented
+fun:__stpncpy=uninstrumented
+fun:__stpncpy_chk=uninstrumented
+fun:__strcasecmp=uninstrumented
+fun:__strcasecmp_l=uninstrumented
+fun:__strcasestr=uninstrumented
+fun:__strcat_chk=uninstrumented
+fun:__strcoll_l=uninstrumented
+fun:__strcpy_chk=uninstrumented
+fun:__strcpy_small=uninstrumented
+fun:__strcspn_c1=uninstrumented
+fun:__strcspn_c2=uninstrumented
+fun:__strcspn_c3=uninstrumented
+fun:__strdup=uninstrumented
+fun:__strerror_r=uninstrumented
+fun:__strfmon_l=uninstrumented
+fun:__strftime_l=uninstrumented
+fun:__strncasecmp_l=uninstrumented
+fun:__strncat_chk=uninstrumented
+fun:__strncpy_chk=uninstrumented
+fun:__strndup=uninstrumented
+fun:__strpbrk_c2=uninstrumented
+fun:__strpbrk_c3=uninstrumented
+fun:__strsep_1c=uninstrumented
+fun:__strsep_2c=uninstrumented
+fun:__strsep_3c=uninstrumented
+fun:__strsep_g=uninstrumented
+fun:__strspn_c1=uninstrumented
+fun:__strspn_c2=uninstrumented
+fun:__strspn_c3=uninstrumented
+fun:__strtod_internal=uninstrumented
+fun:__strtod_l=uninstrumented
+fun:__strtof_internal=uninstrumented
+fun:__strtof_l=uninstrumented
+fun:__strtok_r=uninstrumented
+fun:__strtok_r_1c=uninstrumented
+fun:__strtol_internal=uninstrumented
+fun:__strtol_l=uninstrumented
+fun:__strtold_internal=uninstrumented
+fun:__strtold_l=uninstrumented
+fun:__strtoll_internal=uninstrumented
+fun:__strtoll_l=uninstrumented
+fun:__strtoul_internal=uninstrumented
+fun:__strtoul_l=uninstrumented
+fun:__strtoull_internal=uninstrumented
+fun:__strtoull_l=uninstrumented
+fun:__strverscmp=uninstrumented
+fun:__strxfrm_l=uninstrumented
+fun:__subtf3=uninstrumented
+fun:__subvdi3=uninstrumented
+fun:__subvsi3=uninstrumented
+fun:__subvti3=uninstrumented
+fun:__swprintf_chk=uninstrumented
+fun:__sym_ntop=uninstrumented
+fun:__sym_ntos=uninstrumented
+fun:__sym_ston=uninstrumented
+fun:__sysconf=uninstrumented
+fun:__sysctl=uninstrumented
+fun:__syslog_chk=uninstrumented
+fun:__sysv_signal=uninstrumented
+fun:__tls_get_addr=uninstrumented
+fun:__toascii_l=uninstrumented
+fun:__tolower_l=uninstrumented
+fun:__toupper_l=uninstrumented
+fun:__towctrans=uninstrumented
+fun:__towctrans_l=uninstrumented
+fun:__towlower_l=uninstrumented
+fun:__towupper_l=uninstrumented
+fun:__trunctfdf2=uninstrumented
+fun:__trunctfsf2=uninstrumented
+fun:__trunctfxf2=uninstrumented
+fun:__ttyname_r_chk=uninstrumented
+fun:__ucmpti2=uninstrumented
+fun:__udiv_w_sdiv=uninstrumented
+fun:__udivmodti4=uninstrumented
+fun:__udivti3=uninstrumented
+fun:__uflow=uninstrumented
+fun:__umodti3=uninstrumented
+fun:__underflow=uninstrumented
+fun:__unordtf2=uninstrumented
+fun:__uselocale=uninstrumented
+fun:__vasprintf_chk=uninstrumented
+fun:__vdprintf_chk=uninstrumented
+fun:__vfork=uninstrumented
+fun:__vfprintf_chk=uninstrumented
+fun:__vfscanf=uninstrumented
+fun:__vfwprintf_chk=uninstrumented
+fun:__vprintf_chk=uninstrumented
+fun:__vsnprintf=uninstrumented
+fun:__vsnprintf_chk=uninstrumented
+fun:__vsprintf_chk=uninstrumented
+fun:__vsscanf=uninstrumented
+fun:__vswprintf_chk=uninstrumented
+fun:__vsyslog_chk=uninstrumented
+fun:__vwprintf_chk=uninstrumented
+fun:__wait=uninstrumented
+fun:__waitpid=uninstrumented
+fun:__warn_memset_zero_len=uninstrumented
+fun:__wcpcpy_chk=uninstrumented
+fun:__wcpncpy_chk=uninstrumented
+fun:__wcrtomb_chk=uninstrumented
+fun:__wcscasecmp_l=uninstrumented
+fun:__wcscat_chk=uninstrumented
+fun:__wcscoll_l=uninstrumented
+fun:__wcscpy_chk=uninstrumented
+fun:__wcsftime_l=uninstrumented
+fun:__wcsncasecmp_l=uninstrumented
+fun:__wcsncat_chk=uninstrumented
+fun:__wcsncpy_chk=uninstrumented
+fun:__wcsnrtombs_chk=uninstrumented
+fun:__wcsrtombs_chk=uninstrumented
+fun:__wcstod_internal=uninstrumented
+fun:__wcstod_l=uninstrumented
+fun:__wcstof_internal=uninstrumented
+fun:__wcstof_l=uninstrumented
+fun:__wcstol_internal=uninstrumented
+fun:__wcstol_l=uninstrumented
+fun:__wcstold_internal=uninstrumented
+fun:__wcstold_l=uninstrumented
+fun:__wcstoll_internal=uninstrumented
+fun:__wcstoll_l=uninstrumented
+fun:__wcstombs_chk=uninstrumented
+fun:__wcstoul_internal=uninstrumented
+fun:__wcstoul_l=uninstrumented
+fun:__wcstoull_internal=uninstrumented
+fun:__wcstoull_l=uninstrumented
+fun:__wcsxfrm_l=uninstrumented
+fun:__wctomb_chk=uninstrumented
+fun:__wctrans_l=uninstrumented
+fun:__wctype_l=uninstrumented
+fun:__wmemcpy_chk=uninstrumented
+fun:__wmemmove_chk=uninstrumented
+fun:__wmempcpy_chk=uninstrumented
+fun:__wmemset_chk=uninstrumented
+fun:__woverflow=uninstrumented
+fun:__wprintf_chk=uninstrumented
+fun:__wrap_pthread_create=uninstrumented
+fun:__write=uninstrumented
+fun:__wuflow=uninstrumented
+fun:__wunderflow=uninstrumented
+fun:__xmknod=uninstrumented
+fun:__xmknodat=uninstrumented
+fun:__xpg_basename=uninstrumented
+fun:__xpg_sigpause=uninstrumented
+fun:__xpg_strerror_r=uninstrumented
+fun:__xstat=uninstrumented
+fun:__xstat64=uninstrumented
+fun:__y0_finite=uninstrumented
+fun:__y0f_finite=uninstrumented
+fun:__y0l_finite=uninstrumented
+fun:__y1_finite=uninstrumented
+fun:__y1f_finite=uninstrumented
+fun:__y1l_finite=uninstrumented
+fun:__yn_finite=uninstrumented
+fun:__ynf_finite=uninstrumented
+fun:__ynl_finite=uninstrumented
+fun:__yp_check=uninstrumented
+fun:_authenticate=uninstrumented
+fun:_dl_addr=uninstrumented
+fun:_dl_allocate_tls=uninstrumented
+fun:_dl_allocate_tls_init=uninstrumented
+fun:_dl_deallocate_tls=uninstrumented
+fun:_dl_debug_state=uninstrumented
+fun:_dl_find_dso_for_object=uninstrumented
+fun:_dl_get_tls_static_info=uninstrumented
+fun:_dl_make_stack_executable=uninstrumented
+fun:_dl_mcount=uninstrumented
+fun:_dl_mcount_wrapper=uninstrumented
+fun:_dl_mcount_wrapper_check=uninstrumented
+fun:_dl_rtld_di_serinfo=uninstrumented
+fun:_dl_sym=uninstrumented
+fun:_dl_tls_setup=uninstrumented
+fun:_dl_vsym=uninstrumented
+fun:_exit=uninstrumented
+fun:_flushlbf=uninstrumented
+fun:_gethtbyaddr=uninstrumented
+fun:_gethtbyname=uninstrumented
+fun:_gethtbyname2=uninstrumented
+fun:_gethtent=uninstrumented
+fun:_getlong=uninstrumented
+fun:_getshort=uninstrumented
+fun:_longjmp=uninstrumented
+fun:_mcleanup=uninstrumented
+fun:_mcount=uninstrumented
+fun:_nsl_default_nss=uninstrumented
+fun:_nss_files_parse_grent=uninstrumented
+fun:_nss_files_parse_pwent=uninstrumented
+fun:_nss_files_parse_sgent=uninstrumented
+fun:_nss_files_parse_spent=uninstrumented
+fun:_obstack_allocated_p=uninstrumented
+fun:_obstack_begin=uninstrumented
+fun:_obstack_begin_1=uninstrumented
+fun:_obstack_free=uninstrumented
+fun:_obstack_memory_used=uninstrumented
+fun:_obstack_newchunk=uninstrumented
+fun:_pthread_cleanup_pop=uninstrumented
+fun:_pthread_cleanup_pop_restore=uninstrumented
+fun:_pthread_cleanup_push=uninstrumented
+fun:_pthread_cleanup_push_defer=uninstrumented
+fun:_rpc_dtablesize=uninstrumented
+fun:_seterr_reply=uninstrumented
+fun:_sethtent=uninstrumented
+fun:_setjmp=uninstrumented
+fun:_tolower=uninstrumented
+fun:_toupper=uninstrumented
+fun:_xdr_ib_request=uninstrumented
+fun:_xdr_nis_result=uninstrumented
+fun:a64l=uninstrumented
+fun:abort=uninstrumented
+fun:abs=uninstrumented
+fun:accept=uninstrumented
+fun:accept4=uninstrumented
+fun:access=uninstrumented
+fun:acct=uninstrumented
+fun:acos=uninstrumented
+fun:acosf=uninstrumented
+fun:acosh=uninstrumented
+fun:acoshf=uninstrumented
+fun:acoshl=uninstrumented
+fun:acosl=uninstrumented
+fun:addmntent=uninstrumented
+fun:addseverity=uninstrumented
+fun:adjtime=uninstrumented
+fun:adjtimex=uninstrumented
+fun:advance=uninstrumented
+fun:aio_cancel=uninstrumented
+fun:aio_cancel64=uninstrumented
+fun:aio_error=uninstrumented
+fun:aio_error64=uninstrumented
+fun:aio_fsync=uninstrumented
+fun:aio_fsync64=uninstrumented
+fun:aio_init=uninstrumented
+fun:aio_read=uninstrumented
+fun:aio_read64=uninstrumented
+fun:aio_return=uninstrumented
+fun:aio_return64=uninstrumented
+fun:aio_suspend=uninstrumented
+fun:aio_suspend64=uninstrumented
+fun:aio_write=uninstrumented
+fun:aio_write64=uninstrumented
+fun:alarm=uninstrumented
+fun:aligned_alloc=uninstrumented
+fun:alphasort=uninstrumented
+fun:alphasort64=uninstrumented
+fun:arch_prctl=uninstrumented
+fun:argp_error=uninstrumented
+fun:argp_failure=uninstrumented
+fun:argp_help=uninstrumented
+fun:argp_parse=uninstrumented
+fun:argp_state_help=uninstrumented
+fun:argp_usage=uninstrumented
+fun:argz_add=uninstrumented
+fun:argz_add_sep=uninstrumented
+fun:argz_append=uninstrumented
+fun:argz_count=uninstrumented
+fun:argz_create=uninstrumented
+fun:argz_create_sep=uninstrumented
+fun:argz_delete=uninstrumented
+fun:argz_extract=uninstrumented
+fun:argz_insert=uninstrumented
+fun:argz_next=uninstrumented
+fun:argz_replace=uninstrumented
+fun:argz_stringify=uninstrumented
+fun:asctime=uninstrumented
+fun:asctime_r=uninstrumented
+fun:asin=uninstrumented
+fun:asinf=uninstrumented
+fun:asinh=uninstrumented
+fun:asinhf=uninstrumented
+fun:asinhl=uninstrumented
+fun:asinl=uninstrumented
+fun:asprintf=uninstrumented
+fun:at_quick_exit=uninstrumented
+fun:atan=uninstrumented
+fun:atan2=uninstrumented
+fun:atan2f=uninstrumented
+fun:atan2l=uninstrumented
+fun:atanf=uninstrumented
+fun:atanh=uninstrumented
+fun:atanhf=uninstrumented
+fun:atanhl=uninstrumented
+fun:atanl=uninstrumented
+fun:atexit=uninstrumented
+fun:atof=uninstrumented
+fun:atoi=uninstrumented
+fun:atol=uninstrumented
+fun:atoll=uninstrumented
+fun:authdes_create=uninstrumented
+fun:authdes_getucred=uninstrumented
+fun:authdes_pk_create=uninstrumented
+fun:authnone_create=uninstrumented
+fun:authunix_create=uninstrumented
+fun:authunix_create_default=uninstrumented
+fun:backtrace=uninstrumented
+fun:backtrace_symbols=uninstrumented
+fun:backtrace_symbols_fd=uninstrumented
+fun:basename=uninstrumented
+fun:bcmp=uninstrumented
+fun:bcopy=uninstrumented
+fun:bdflush=uninstrumented
+fun:bind=uninstrumented
+fun:bind_textdomain_codeset=uninstrumented
+fun:bindresvport=uninstrumented
+fun:bindtextdomain=uninstrumented
+fun:brk=uninstrumented
+fun:bsd_signal=uninstrumented
+fun:bsearch=uninstrumented
+fun:btowc=uninstrumented
+fun:bzero=uninstrumented
+fun:c16rtomb=uninstrumented
+fun:c32rtomb=uninstrumented
+fun:cabs=uninstrumented
+fun:cabsf=uninstrumented
+fun:cabsl=uninstrumented
+fun:cacos=uninstrumented
+fun:cacosf=uninstrumented
+fun:cacosh=uninstrumented
+fun:cacoshf=uninstrumented
+fun:cacoshl=uninstrumented
+fun:cacosl=uninstrumented
+fun:calloc=uninstrumented
+fun:callrpc=uninstrumented
+fun:canonicalize_file_name=uninstrumented
+fun:capget=uninstrumented
+fun:capset=uninstrumented
+fun:carg=uninstrumented
+fun:cargf=uninstrumented
+fun:cargl=uninstrumented
+fun:casin=uninstrumented
+fun:casinf=uninstrumented
+fun:casinh=uninstrumented
+fun:casinhf=uninstrumented
+fun:casinhl=uninstrumented
+fun:casinl=uninstrumented
+fun:catan=uninstrumented
+fun:catanf=uninstrumented
+fun:catanh=uninstrumented
+fun:catanhf=uninstrumented
+fun:catanhl=uninstrumented
+fun:catanl=uninstrumented
+fun:catclose=uninstrumented
+fun:catgets=uninstrumented
+fun:catopen=uninstrumented
+fun:cbc_crypt=uninstrumented
+fun:cbrt=uninstrumented
+fun:cbrtf=uninstrumented
+fun:cbrtl=uninstrumented
+fun:ccos=uninstrumented
+fun:ccosf=uninstrumented
+fun:ccosh=uninstrumented
+fun:ccoshf=uninstrumented
+fun:ccoshl=uninstrumented
+fun:ccosl=uninstrumented
+fun:ceil=uninstrumented
+fun:ceilf=uninstrumented
+fun:ceill=uninstrumented
+fun:cexp=uninstrumented
+fun:cexpf=uninstrumented
+fun:cexpl=uninstrumented
+fun:cfgetispeed=uninstrumented
+fun:cfgetospeed=uninstrumented
+fun:cfmakeraw=uninstrumented
+fun:cfree=uninstrumented
+fun:cfsetispeed=uninstrumented
+fun:cfsetospeed=uninstrumented
+fun:cfsetspeed=uninstrumented
+fun:chdir=uninstrumented
+fun:chflags=uninstrumented
+fun:chmod=uninstrumented
+fun:chown=uninstrumented
+fun:chroot=uninstrumented
+fun:cimag=uninstrumented
+fun:cimagf=uninstrumented
+fun:cimagl=uninstrumented
+fun:clearenv=uninstrumented
+fun:clearerr=uninstrumented
+fun:clearerr_unlocked=uninstrumented
+fun:clnt_broadcast=uninstrumented
+fun:clnt_create=uninstrumented
+fun:clnt_pcreateerror=uninstrumented
+fun:clnt_perrno=uninstrumented
+fun:clnt_perror=uninstrumented
+fun:clnt_spcreateerror=uninstrumented
+fun:clnt_sperrno=uninstrumented
+fun:clnt_sperror=uninstrumented
+fun:clntraw_create=uninstrumented
+fun:clnttcp_create=uninstrumented
+fun:clntudp_bufcreate=uninstrumented
+fun:clntudp_create=uninstrumented
+fun:clntunix_create=uninstrumented
+fun:clock=uninstrumented
+fun:clock_adjtime=uninstrumented
+fun:clock_getcpuclockid=uninstrumented
+fun:clock_getres=uninstrumented
+fun:clock_gettime=uninstrumented
+fun:clock_nanosleep=uninstrumented
+fun:clock_settime=uninstrumented
+fun:clog=uninstrumented
+fun:clog10=uninstrumented
+fun:clog10f=uninstrumented
+fun:clog10l=uninstrumented
+fun:clogf=uninstrumented
+fun:clogl=uninstrumented
+fun:clone=uninstrumented
+fun:close=uninstrumented
+fun:closedir=uninstrumented
+fun:closelog=uninstrumented
+fun:confstr=uninstrumented
+fun:conj=uninstrumented
+fun:conjf=uninstrumented
+fun:conjl=uninstrumented
+fun:connect=uninstrumented
+fun:copysign=uninstrumented
+fun:copysignf=uninstrumented
+fun:copysignl=uninstrumented
+fun:cos=uninstrumented
+fun:cosf=uninstrumented
+fun:cosh=uninstrumented
+fun:coshf=uninstrumented
+fun:coshl=uninstrumented
+fun:cosl=uninstrumented
+fun:cpow=uninstrumented
+fun:cpowf=uninstrumented
+fun:cpowl=uninstrumented
+fun:cproj=uninstrumented
+fun:cprojf=uninstrumented
+fun:cprojl=uninstrumented
+fun:creal=uninstrumented
+fun:crealf=uninstrumented
+fun:creall=uninstrumented
+fun:creat=uninstrumented
+fun:creat64=uninstrumented
+fun:create_module=uninstrumented
+fun:crypt=uninstrumented
+fun:crypt_r=uninstrumented
+fun:csin=uninstrumented
+fun:csinf=uninstrumented
+fun:csinh=uninstrumented
+fun:csinhf=uninstrumented
+fun:csinhl=uninstrumented
+fun:csinl=uninstrumented
+fun:csqrt=uninstrumented
+fun:csqrtf=uninstrumented
+fun:csqrtl=uninstrumented
+fun:ctan=uninstrumented
+fun:ctanf=uninstrumented
+fun:ctanh=uninstrumented
+fun:ctanhf=uninstrumented
+fun:ctanhl=uninstrumented
+fun:ctanl=uninstrumented
+fun:ctermid=uninstrumented
+fun:ctime=uninstrumented
+fun:ctime_r=uninstrumented
+fun:cuserid=uninstrumented
+fun:daemon=uninstrumented
+fun:dcgettext=uninstrumented
+fun:dcngettext=uninstrumented
+fun:delete_module=uninstrumented
+fun:des_setparity=uninstrumented
+fun:dgettext=uninstrumented
+fun:difftime=uninstrumented
+fun:dirfd=uninstrumented
+fun:dirname=uninstrumented
+fun:div=uninstrumented
+fun:dl_iterate_phdr=uninstrumented
+fun:dladdr=uninstrumented
+fun:dladdr1=uninstrumented
+fun:dlclose=uninstrumented
+fun:dlerror=uninstrumented
+fun:dlinfo=uninstrumented
+fun:dlmopen=uninstrumented
+fun:dlopen=uninstrumented
+fun:dlsym=uninstrumented
+fun:dlvsym=uninstrumented
+fun:dngettext=uninstrumented
+fun:dprintf=uninstrumented
+fun:drand48=uninstrumented
+fun:drand48_r=uninstrumented
+fun:drem=uninstrumented
+fun:dremf=uninstrumented
+fun:dreml=uninstrumented
+fun:dup=uninstrumented
+fun:dup2=uninstrumented
+fun:dup3=uninstrumented
+fun:duplocale=uninstrumented
+fun:dysize=uninstrumented
+fun:eaccess=uninstrumented
+fun:ecb_crypt=uninstrumented
+fun:ecvt=uninstrumented
+fun:ecvt_r=uninstrumented
+fun:encrypt=uninstrumented
+fun:encrypt_r=uninstrumented
+fun:endaliasent=uninstrumented
+fun:endfsent=uninstrumented
+fun:endgrent=uninstrumented
+fun:endhostent=uninstrumented
+fun:endmntent=uninstrumented
+fun:endnetent=uninstrumented
+fun:endnetgrent=uninstrumented
+fun:endprotoent=uninstrumented
+fun:endpwent=uninstrumented
+fun:endrpcent=uninstrumented
+fun:endservent=uninstrumented
+fun:endsgent=uninstrumented
+fun:endspent=uninstrumented
+fun:endttyent=uninstrumented
+fun:endusershell=uninstrumented
+fun:endutent=uninstrumented
+fun:endutxent=uninstrumented
+fun:envz_add=uninstrumented
+fun:envz_entry=uninstrumented
+fun:envz_get=uninstrumented
+fun:envz_merge=uninstrumented
+fun:envz_remove=uninstrumented
+fun:envz_strip=uninstrumented
+fun:epoll_create=uninstrumented
+fun:epoll_create1=uninstrumented
+fun:epoll_ctl=uninstrumented
+fun:epoll_pwait=uninstrumented
+fun:epoll_wait=uninstrumented
+fun:erand48=uninstrumented
+fun:erand48_r=uninstrumented
+fun:erf=uninstrumented
+fun:erfc=uninstrumented
+fun:erfcf=uninstrumented
+fun:erfcl=uninstrumented
+fun:erff=uninstrumented
+fun:erfl=uninstrumented
+fun:err=uninstrumented
+fun:error=uninstrumented
+fun:error_at_line=uninstrumented
+fun:errx=uninstrumented
+fun:ether_aton=uninstrumented
+fun:ether_aton_r=uninstrumented
+fun:ether_hostton=uninstrumented
+fun:ether_line=uninstrumented
+fun:ether_ntoa=uninstrumented
+fun:ether_ntoa_r=uninstrumented
+fun:ether_ntohost=uninstrumented
+fun:euidaccess=uninstrumented
+fun:eventfd=uninstrumented
+fun:eventfd_read=uninstrumented
+fun:eventfd_write=uninstrumented
+fun:execl=uninstrumented
+fun:execle=uninstrumented
+fun:execlp=uninstrumented
+fun:execv=uninstrumented
+fun:execve=uninstrumented
+fun:execvp=uninstrumented
+fun:execvpe=uninstrumented
+fun:exit=uninstrumented
+fun:exp=uninstrumented
+fun:exp10=uninstrumented
+fun:exp10f=uninstrumented
+fun:exp10l=uninstrumented
+fun:exp2=uninstrumented
+fun:exp2f=uninstrumented
+fun:exp2l=uninstrumented
+fun:expf=uninstrumented
+fun:expl=uninstrumented
+fun:expm1=uninstrumented
+fun:expm1f=uninstrumented
+fun:expm1l=uninstrumented
+fun:fabs=uninstrumented
+fun:fabsf=uninstrumented
+fun:fabsl=uninstrumented
+fun:faccessat=uninstrumented
+fun:fallocate=uninstrumented
+fun:fallocate64=uninstrumented
+fun:fanotify_init=uninstrumented
+fun:fanotify_mark=uninstrumented
+fun:fattach=uninstrumented
+fun:fchdir=uninstrumented
+fun:fchflags=uninstrumented
+fun:fchmod=uninstrumented
+fun:fchmodat=uninstrumented
+fun:fchown=uninstrumented
+fun:fchownat=uninstrumented
+fun:fclose=uninstrumented
+fun:fcloseall=uninstrumented
+fun:fcntl=uninstrumented
+fun:fcrypt=uninstrumented
+fun:fcvt=uninstrumented
+fun:fcvt_r=uninstrumented
+fun:fdatasync=uninstrumented
+fun:fdetach=uninstrumented
+fun:fdim=uninstrumented
+fun:fdimf=uninstrumented
+fun:fdiml=uninstrumented
+fun:fdopen=uninstrumented
+fun:fdopendir=uninstrumented
+fun:feclearexcept=uninstrumented
+fun:fedisableexcept=uninstrumented
+fun:feenableexcept=uninstrumented
+fun:fegetenv=uninstrumented
+fun:fegetexcept=uninstrumented
+fun:fegetexceptflag=uninstrumented
+fun:fegetround=uninstrumented
+fun:feholdexcept=uninstrumented
+fun:feof=uninstrumented
+fun:feof_unlocked=uninstrumented
+fun:feraiseexcept=uninstrumented
+fun:ferror=uninstrumented
+fun:ferror_unlocked=uninstrumented
+fun:fesetenv=uninstrumented
+fun:fesetexceptflag=uninstrumented
+fun:fesetround=uninstrumented
+fun:fetestexcept=uninstrumented
+fun:feupdateenv=uninstrumented
+fun:fexecve=uninstrumented
+fun:fflush=uninstrumented
+fun:fflush_unlocked=uninstrumented
+fun:ffs=uninstrumented
+fun:ffsl=uninstrumented
+fun:ffsll=uninstrumented
+fun:fgetc=uninstrumented
+fun:fgetc_unlocked=uninstrumented
+fun:fgetgrent=uninstrumented
+fun:fgetgrent_r=uninstrumented
+fun:fgetpos=uninstrumented
+fun:fgetpos64=uninstrumented
+fun:fgetpwent=uninstrumented
+fun:fgetpwent_r=uninstrumented
+fun:fgets=uninstrumented
+fun:fgets_unlocked=uninstrumented
+fun:fgetsgent=uninstrumented
+fun:fgetsgent_r=uninstrumented
+fun:fgetspent=uninstrumented
+fun:fgetspent_r=uninstrumented
+fun:fgetwc=uninstrumented
+fun:fgetwc_unlocked=uninstrumented
+fun:fgetws=uninstrumented
+fun:fgetws_unlocked=uninstrumented
+fun:fgetxattr=uninstrumented
+fun:fileno=uninstrumented
+fun:fileno_unlocked=uninstrumented
+fun:finite=uninstrumented
+fun:finitef=uninstrumented
+fun:finitel=uninstrumented
+fun:flistxattr=uninstrumented
+fun:flock=uninstrumented
+fun:flockfile=uninstrumented
+fun:floor=uninstrumented
+fun:floorf=uninstrumented
+fun:floorl=uninstrumented
+fun:fma=uninstrumented
+fun:fmaf=uninstrumented
+fun:fmal=uninstrumented
+fun:fmax=uninstrumented
+fun:fmaxf=uninstrumented
+fun:fmaxl=uninstrumented
+fun:fmemopen=uninstrumented
+fun:fmin=uninstrumented
+fun:fminf=uninstrumented
+fun:fminl=uninstrumented
+fun:fmod=uninstrumented
+fun:fmodf=uninstrumented
+fun:fmodl=uninstrumented
+fun:fmtmsg=uninstrumented
+fun:fnmatch=uninstrumented
+fun:fopen=uninstrumented
+fun:fopen64=uninstrumented
+fun:fopencookie=uninstrumented
+fun:fork=uninstrumented
+fun:forkpty=uninstrumented
+fun:fpathconf=uninstrumented
+fun:fprintf=uninstrumented
+fun:fputc=uninstrumented
+fun:fputc_unlocked=uninstrumented
+fun:fputs=uninstrumented
+fun:fputs_unlocked=uninstrumented
+fun:fputwc=uninstrumented
+fun:fputwc_unlocked=uninstrumented
+fun:fputws=uninstrumented
+fun:fputws_unlocked=uninstrumented
+fun:fread=uninstrumented
+fun:fread_unlocked=uninstrumented
+fun:free=uninstrumented
+fun:freeaddrinfo=uninstrumented
+fun:freeifaddrs=uninstrumented
+fun:freelocale=uninstrumented
+fun:fremovexattr=uninstrumented
+fun:freopen=uninstrumented
+fun:freopen64=uninstrumented
+fun:frexp=uninstrumented
+fun:frexpf=uninstrumented
+fun:frexpl=uninstrumented
+fun:fscanf=uninstrumented
+fun:fseek=uninstrumented
+fun:fseeko=uninstrumented
+fun:fseeko64=uninstrumented
+fun:fsetpos=uninstrumented
+fun:fsetpos64=uninstrumented
+fun:fsetxattr=uninstrumented
+fun:fstat=uninstrumented
+fun:fstat64=uninstrumented
+fun:fstatat=uninstrumented
+fun:fstatat64=uninstrumented
+fun:fstatfs=uninstrumented
+fun:fstatfs64=uninstrumented
+fun:fstatvfs=uninstrumented
+fun:fstatvfs64=uninstrumented
+fun:fsync=uninstrumented
+fun:ftell=uninstrumented
+fun:ftello=uninstrumented
+fun:ftello64=uninstrumented
+fun:ftime=uninstrumented
+fun:ftok=uninstrumented
+fun:ftruncate=uninstrumented
+fun:ftruncate64=uninstrumented
+fun:ftrylockfile=uninstrumented
+fun:fts_children=uninstrumented
+fun:fts_close=uninstrumented
+fun:fts_open=uninstrumented
+fun:fts_read=uninstrumented
+fun:fts_set=uninstrumented
+fun:ftw=uninstrumented
+fun:ftw64=uninstrumented
+fun:funlockfile=uninstrumented
+fun:futimens=uninstrumented
+fun:futimes=uninstrumented
+fun:futimesat=uninstrumented
+fun:fwide=uninstrumented
+fun:fwprintf=uninstrumented
+fun:fwrite=uninstrumented
+fun:fwrite_unlocked=uninstrumented
+fun:fwscanf=uninstrumented
+fun:gai_cancel=uninstrumented
+fun:gai_error=uninstrumented
+fun:gai_strerror=uninstrumented
+fun:gai_suspend=uninstrumented
+fun:gamma=uninstrumented
+fun:gammaf=uninstrumented
+fun:gammal=uninstrumented
+fun:gcvt=uninstrumented
+fun:get_avphys_pages=uninstrumented
+fun:get_current_dir_name=uninstrumented
+fun:get_kernel_syms=uninstrumented
+fun:get_myaddress=uninstrumented
+fun:get_nprocs=uninstrumented
+fun:get_nprocs_conf=uninstrumented
+fun:get_phys_pages=uninstrumented
+fun:getaddrinfo=uninstrumented
+fun:getaddrinfo_a=uninstrumented
+fun:getaliasbyname=uninstrumented
+fun:getaliasbyname_r=uninstrumented
+fun:getaliasent=uninstrumented
+fun:getaliasent_r=uninstrumented
+fun:getauxval=uninstrumented
+fun:getc=uninstrumented
+fun:getc_unlocked=uninstrumented
+fun:getchar=uninstrumented
+fun:getchar_unlocked=uninstrumented
+fun:getcontext=uninstrumented
+fun:getcwd=uninstrumented
+fun:getdate=uninstrumented
+fun:getdate_r=uninstrumented
+fun:getdelim=uninstrumented
+fun:getdirentries=uninstrumented
+fun:getdirentries64=uninstrumented
+fun:getdomainname=uninstrumented
+fun:getdtablesize=uninstrumented
+fun:getegid=uninstrumented
+fun:getenv=uninstrumented
+fun:geteuid=uninstrumented
+fun:getfsent=uninstrumented
+fun:getfsfile=uninstrumented
+fun:getfsspec=uninstrumented
+fun:getgid=uninstrumented
+fun:getgrent=uninstrumented
+fun:getgrent_r=uninstrumented
+fun:getgrgid=uninstrumented
+fun:getgrgid_r=uninstrumented
+fun:getgrnam=uninstrumented
+fun:getgrnam_r=uninstrumented
+fun:getgrouplist=uninstrumented
+fun:getgroups=uninstrumented
+fun:gethostbyaddr=uninstrumented
+fun:gethostbyaddr_r=uninstrumented
+fun:gethostbyname=uninstrumented
+fun:gethostbyname2=uninstrumented
+fun:gethostbyname2_r=uninstrumented
+fun:gethostbyname_r=uninstrumented
+fun:gethostent=uninstrumented
+fun:gethostent_r=uninstrumented
+fun:gethostid=uninstrumented
+fun:gethostname=uninstrumented
+fun:getifaddrs=uninstrumented
+fun:getipv4sourcefilter=uninstrumented
+fun:getitimer=uninstrumented
+fun:getline=uninstrumented
+fun:getloadavg=uninstrumented
+fun:getlogin=uninstrumented
+fun:getlogin_r=uninstrumented
+fun:getmntent=uninstrumented
+fun:getmntent_r=uninstrumented
+fun:getmsg=uninstrumented
+fun:getnameinfo=uninstrumented
+fun:getnetbyaddr=uninstrumented
+fun:getnetbyaddr_r=uninstrumented
+fun:getnetbyname=uninstrumented
+fun:getnetbyname_r=uninstrumented
+fun:getnetent=uninstrumented
+fun:getnetent_r=uninstrumented
+fun:getnetgrent=uninstrumented
+fun:getnetgrent_r=uninstrumented
+fun:getnetname=uninstrumented
+fun:getopt=uninstrumented
+fun:getopt_long=uninstrumented
+fun:getopt_long_only=uninstrumented
+fun:getpagesize=uninstrumented
+fun:getpass=uninstrumented
+fun:getpeername=uninstrumented
+fun:getpgid=uninstrumented
+fun:getpgrp=uninstrumented
+fun:getpid=uninstrumented
+fun:getpmsg=uninstrumented
+fun:getppid=uninstrumented
+fun:getpriority=uninstrumented
+fun:getprotobyname=uninstrumented
+fun:getprotobyname_r=uninstrumented
+fun:getprotobynumber=uninstrumented
+fun:getprotobynumber_r=uninstrumented
+fun:getprotoent=uninstrumented
+fun:getprotoent_r=uninstrumented
+fun:getpt=uninstrumented
+fun:getpublickey=uninstrumented
+fun:getpw=uninstrumented
+fun:getpwent=uninstrumented
+fun:getpwent_r=uninstrumented
+fun:getpwnam=uninstrumented
+fun:getpwnam_r=uninstrumented
+fun:getpwuid=uninstrumented
+fun:getpwuid_r=uninstrumented
+fun:getresgid=uninstrumented
+fun:getresuid=uninstrumented
+fun:getrlimit=uninstrumented
+fun:getrlimit64=uninstrumented
+fun:getrpcbyname=uninstrumented
+fun:getrpcbyname_r=uninstrumented
+fun:getrpcbynumber=uninstrumented
+fun:getrpcbynumber_r=uninstrumented
+fun:getrpcent=uninstrumented
+fun:getrpcent_r=uninstrumented
+fun:getrpcport=uninstrumented
+fun:getrusage=uninstrumented
+fun:gets=uninstrumented
+fun:getsecretkey=uninstrumented
+fun:getservbyname=uninstrumented
+fun:getservbyname_r=uninstrumented
+fun:getservbyport=uninstrumented
+fun:getservbyport_r=uninstrumented
+fun:getservent=uninstrumented
+fun:getservent_r=uninstrumented
+fun:getsgent=uninstrumented
+fun:getsgent_r=uninstrumented
+fun:getsgnam=uninstrumented
+fun:getsgnam_r=uninstrumented
+fun:getsid=uninstrumented
+fun:getsockname=uninstrumented
+fun:getsockopt=uninstrumented
+fun:getsourcefilter=uninstrumented
+fun:getspent=uninstrumented
+fun:getspent_r=uninstrumented
+fun:getspnam=uninstrumented
+fun:getspnam_r=uninstrumented
+fun:getsubopt=uninstrumented
+fun:gettext=uninstrumented
+fun:gettimeofday=uninstrumented
+fun:getttyent=uninstrumented
+fun:getttynam=uninstrumented
+fun:getuid=uninstrumented
+fun:getusershell=uninstrumented
+fun:getutent=uninstrumented
+fun:getutent_r=uninstrumented
+fun:getutid=uninstrumented
+fun:getutid_r=uninstrumented
+fun:getutline=uninstrumented
+fun:getutline_r=uninstrumented
+fun:getutmp=uninstrumented
+fun:getutmpx=uninstrumented
+fun:getutxent=uninstrumented
+fun:getutxid=uninstrumented
+fun:getutxline=uninstrumented
+fun:getw=uninstrumented
+fun:getwc=uninstrumented
+fun:getwc_unlocked=uninstrumented
+fun:getwchar=uninstrumented
+fun:getwchar_unlocked=uninstrumented
+fun:getwd=uninstrumented
+fun:getxattr=uninstrumented
+fun:glob=uninstrumented
+fun:glob64=uninstrumented
+fun:glob_pattern_p=uninstrumented
+fun:globfree=uninstrumented
+fun:globfree64=uninstrumented
+fun:gmtime=uninstrumented
+fun:gmtime_r=uninstrumented
+fun:gnu_dev_major=uninstrumented
+fun:gnu_dev_makedev=uninstrumented
+fun:gnu_dev_minor=uninstrumented
+fun:gnu_get_libc_release=uninstrumented
+fun:gnu_get_libc_version=uninstrumented
+fun:grantpt=uninstrumented
+fun:group_member=uninstrumented
+fun:gsignal=uninstrumented
+fun:gtty=uninstrumented
+fun:hasmntopt=uninstrumented
+fun:hcreate=uninstrumented
+fun:hcreate_r=uninstrumented
+fun:hdestroy=uninstrumented
+fun:hdestroy_r=uninstrumented
+fun:herror=uninstrumented
+fun:host2netname=uninstrumented
+fun:hsearch=uninstrumented
+fun:hsearch_r=uninstrumented
+fun:hstrerror=uninstrumented
+fun:htonl=uninstrumented
+fun:htons=uninstrumented
+fun:hypot=uninstrumented
+fun:hypotf=uninstrumented
+fun:hypotl=uninstrumented
+fun:iconv=uninstrumented
+fun:iconv_close=uninstrumented
+fun:iconv_open=uninstrumented
+fun:idna_to_ascii_lz=uninstrumented
+fun:idna_to_unicode_lzlz=uninstrumented
+fun:if_freenameindex=uninstrumented
+fun:if_indextoname=uninstrumented
+fun:if_nameindex=uninstrumented
+fun:if_nametoindex=uninstrumented
+fun:ilogb=uninstrumented
+fun:ilogbf=uninstrumented
+fun:ilogbl=uninstrumented
+fun:imaxabs=uninstrumented
+fun:imaxdiv=uninstrumented
+fun:index=uninstrumented
+fun:inet6_opt_append=uninstrumented
+fun:inet6_opt_find=uninstrumented
+fun:inet6_opt_finish=uninstrumented
+fun:inet6_opt_get_val=uninstrumented
+fun:inet6_opt_init=uninstrumented
+fun:inet6_opt_next=uninstrumented
+fun:inet6_opt_set_val=uninstrumented
+fun:inet6_option_alloc=uninstrumented
+fun:inet6_option_append=uninstrumented
+fun:inet6_option_find=uninstrumented
+fun:inet6_option_init=uninstrumented
+fun:inet6_option_next=uninstrumented
+fun:inet6_option_space=uninstrumented
+fun:inet6_rth_add=uninstrumented
+fun:inet6_rth_getaddr=uninstrumented
+fun:inet6_rth_init=uninstrumented
+fun:inet6_rth_reverse=uninstrumented
+fun:inet6_rth_segments=uninstrumented
+fun:inet6_rth_space=uninstrumented
+fun:inet_addr=uninstrumented
+fun:inet_aton=uninstrumented
+fun:inet_lnaof=uninstrumented
+fun:inet_makeaddr=uninstrumented
+fun:inet_net_ntop=uninstrumented
+fun:inet_net_pton=uninstrumented
+fun:inet_neta=uninstrumented
+fun:inet_netof=uninstrumented
+fun:inet_network=uninstrumented
+fun:inet_nsap_addr=uninstrumented
+fun:inet_nsap_ntoa=uninstrumented
+fun:inet_ntoa=uninstrumented
+fun:inet_ntop=uninstrumented
+fun:inet_pton=uninstrumented
+fun:init_module=uninstrumented
+fun:initgroups=uninstrumented
+fun:initstate=uninstrumented
+fun:initstate_r=uninstrumented
+fun:innetgr=uninstrumented
+fun:inotify_add_watch=uninstrumented
+fun:inotify_init=uninstrumented
+fun:inotify_init1=uninstrumented
+fun:inotify_rm_watch=uninstrumented
+fun:insque=uninstrumented
+fun:ioctl=uninstrumented
+fun:ioperm=uninstrumented
+fun:iopl=uninstrumented
+fun:iruserok=uninstrumented
+fun:iruserok_af=uninstrumented
+fun:isalnum=uninstrumented
+fun:isalnum_l=uninstrumented
+fun:isalpha=uninstrumented
+fun:isalpha_l=uninstrumented
+fun:isascii=uninstrumented
+fun:isastream=uninstrumented
+fun:isatty=uninstrumented
+fun:isblank=uninstrumented
+fun:isblank_l=uninstrumented
+fun:iscntrl=uninstrumented
+fun:iscntrl_l=uninstrumented
+fun:isctype=uninstrumented
+fun:isdigit=uninstrumented
+fun:isdigit_l=uninstrumented
+fun:isfdtype=uninstrumented
+fun:isgraph=uninstrumented
+fun:isgraph_l=uninstrumented
+fun:isinf=uninstrumented
+fun:isinfd128=uninstrumented
+fun:isinfd32=uninstrumented
+fun:isinfd64=uninstrumented
+fun:isinff=uninstrumented
+fun:isinfl=uninstrumented
+fun:islower=uninstrumented
+fun:islower_l=uninstrumented
+fun:isnan=uninstrumented
+fun:isnanf=uninstrumented
+fun:isnanl=uninstrumented
+fun:isprint=uninstrumented
+fun:isprint_l=uninstrumented
+fun:ispunct=uninstrumented
+fun:ispunct_l=uninstrumented
+fun:isspace=uninstrumented
+fun:isspace_l=uninstrumented
+fun:isupper=uninstrumented
+fun:isupper_l=uninstrumented
+fun:iswalnum=uninstrumented
+fun:iswalnum_l=uninstrumented
+fun:iswalpha=uninstrumented
+fun:iswalpha_l=uninstrumented
+fun:iswblank=uninstrumented
+fun:iswblank_l=uninstrumented
+fun:iswcntrl=uninstrumented
+fun:iswcntrl_l=uninstrumented
+fun:iswctype=uninstrumented
+fun:iswctype_l=uninstrumented
+fun:iswdigit=uninstrumented
+fun:iswdigit_l=uninstrumented
+fun:iswgraph=uninstrumented
+fun:iswgraph_l=uninstrumented
+fun:iswlower=uninstrumented
+fun:iswlower_l=uninstrumented
+fun:iswprint=uninstrumented
+fun:iswprint_l=uninstrumented
+fun:iswpunct=uninstrumented
+fun:iswpunct_l=uninstrumented
+fun:iswspace=uninstrumented
+fun:iswspace_l=uninstrumented
+fun:iswupper=uninstrumented
+fun:iswupper_l=uninstrumented
+fun:iswxdigit=uninstrumented
+fun:iswxdigit_l=uninstrumented
+fun:isxdigit=uninstrumented
+fun:isxdigit_l=uninstrumented
+fun:j0=uninstrumented
+fun:j0f=uninstrumented
+fun:j0l=uninstrumented
+fun:j1=uninstrumented
+fun:j1f=uninstrumented
+fun:j1l=uninstrumented
+fun:jn=uninstrumented
+fun:jnf=uninstrumented
+fun:jnl=uninstrumented
+fun:jrand48=uninstrumented
+fun:jrand48_r=uninstrumented
+fun:key_decryptsession=uninstrumented
+fun:key_decryptsession_pk=uninstrumented
+fun:key_encryptsession=uninstrumented
+fun:key_encryptsession_pk=uninstrumented
+fun:key_gendes=uninstrumented
+fun:key_get_conv=uninstrumented
+fun:key_secretkey_is_set=uninstrumented
+fun:key_setnet=uninstrumented
+fun:key_setsecret=uninstrumented
+fun:kill=uninstrumented
+fun:killpg=uninstrumented
+fun:klogctl=uninstrumented
+fun:l64a=uninstrumented
+fun:labs=uninstrumented
+fun:lchmod=uninstrumented
+fun:lchown=uninstrumented
+fun:lckpwdf=uninstrumented
+fun:lcong48=uninstrumented
+fun:lcong48_r=uninstrumented
+fun:ldexp=uninstrumented
+fun:ldexpf=uninstrumented
+fun:ldexpl=uninstrumented
+fun:ldiv=uninstrumented
+fun:lfind=uninstrumented
+fun:lgamma=uninstrumented
+fun:lgamma_r=uninstrumented
+fun:lgammaf=uninstrumented
+fun:lgammaf_r=uninstrumented
+fun:lgammal=uninstrumented
+fun:lgammal_r=uninstrumented
+fun:lgetxattr=uninstrumented
+fun:link=uninstrumented
+fun:linkat=uninstrumented
+fun:lio_listio=uninstrumented
+fun:lio_listio64=uninstrumented
+fun:listen=uninstrumented
+fun:listxattr=uninstrumented
+fun:llabs=uninstrumented
+fun:lldiv=uninstrumented
+fun:llistxattr=uninstrumented
+fun:llrint=uninstrumented
+fun:llrintf=uninstrumented
+fun:llrintl=uninstrumented
+fun:llround=uninstrumented
+fun:llroundf=uninstrumented
+fun:llroundl=uninstrumented
+fun:llseek=uninstrumented
+fun:localeconv=uninstrumented
+fun:localtime=uninstrumented
+fun:localtime_r=uninstrumented
+fun:lockf=uninstrumented
+fun:lockf64=uninstrumented
+fun:log=uninstrumented
+fun:log10=uninstrumented
+fun:log10f=uninstrumented
+fun:log10l=uninstrumented
+fun:log1p=uninstrumented
+fun:log1pf=uninstrumented
+fun:log1pl=uninstrumented
+fun:log2=uninstrumented
+fun:log2f=uninstrumented
+fun:log2l=uninstrumented
+fun:logb=uninstrumented
+fun:logbf=uninstrumented
+fun:logbl=uninstrumented
+fun:logf=uninstrumented
+fun:login=uninstrumented
+fun:login_tty=uninstrumented
+fun:logl=uninstrumented
+fun:logout=uninstrumented
+fun:logwtmp=uninstrumented
+fun:longjmp=uninstrumented
+fun:lrand48=uninstrumented
+fun:lrand48_r=uninstrumented
+fun:lremovexattr=uninstrumented
+fun:lrint=uninstrumented
+fun:lrintf=uninstrumented
+fun:lrintl=uninstrumented
+fun:lround=uninstrumented
+fun:lroundf=uninstrumented
+fun:lroundl=uninstrumented
+fun:lsearch=uninstrumented
+fun:lseek=uninstrumented
+fun:lseek64=uninstrumented
+fun:lsetxattr=uninstrumented
+fun:lstat=uninstrumented
+fun:lstat64=uninstrumented
+fun:lutimes=uninstrumented
+fun:madvise=uninstrumented
+fun:makecontext=uninstrumented
+fun:mallinfo=uninstrumented
+fun:malloc=uninstrumented
+fun:malloc_get_state=uninstrumented
+fun:malloc_info=uninstrumented
+fun:malloc_set_state=uninstrumented
+fun:malloc_stats=uninstrumented
+fun:malloc_trim=uninstrumented
+fun:malloc_usable_size=uninstrumented
+fun:mallopt=uninstrumented
+fun:matherr=uninstrumented
+fun:mblen=uninstrumented
+fun:mbrlen=uninstrumented
+fun:mbrtoc16=uninstrumented
+fun:mbrtoc32=uninstrumented
+fun:mbrtowc=uninstrumented
+fun:mbsinit=uninstrumented
+fun:mbsnrtowcs=uninstrumented
+fun:mbsrtowcs=uninstrumented
+fun:mbstowcs=uninstrumented
+fun:mbtowc=uninstrumented
+fun:mcheck=uninstrumented
+fun:mcheck_check_all=uninstrumented
+fun:mcheck_pedantic=uninstrumented
+fun:mcount=uninstrumented
+fun:memalign=uninstrumented
+fun:memccpy=uninstrumented
+fun:memchr=uninstrumented
+fun:memcmp=uninstrumented
+fun:memcpy=uninstrumented
+fun:memfrob=uninstrumented
+fun:memmem=uninstrumented
+fun:memmove=uninstrumented
+fun:mempcpy=uninstrumented
+fun:memrchr=uninstrumented
+fun:memset=uninstrumented
+fun:mincore=uninstrumented
+fun:mkdir=uninstrumented
+fun:mkdirat=uninstrumented
+fun:mkdtemp=uninstrumented
+fun:mkfifo=uninstrumented
+fun:mkfifoat=uninstrumented
+fun:mknod=uninstrumented
+fun:mknodat=uninstrumented
+fun:mkostemp=uninstrumented
+fun:mkostemp64=uninstrumented
+fun:mkostemps=uninstrumented
+fun:mkostemps64=uninstrumented
+fun:mkstemp=uninstrumented
+fun:mkstemp64=uninstrumented
+fun:mkstemps=uninstrumented
+fun:mkstemps64=uninstrumented
+fun:mktemp=uninstrumented
+fun:mktime=uninstrumented
+fun:mlock=uninstrumented
+fun:mlockall=uninstrumented
+fun:mmap=uninstrumented
+fun:mmap64=uninstrumented
+fun:modf=uninstrumented
+fun:modff=uninstrumented
+fun:modfl=uninstrumented
+fun:modify_ldt=uninstrumented
+fun:moncontrol=uninstrumented
+fun:monstartup=uninstrumented
+fun:mount=uninstrumented
+fun:mprobe=uninstrumented
+fun:mprotect=uninstrumented
+fun:mq_close=uninstrumented
+fun:mq_getattr=uninstrumented
+fun:mq_notify=uninstrumented
+fun:mq_open=uninstrumented
+fun:mq_receive=uninstrumented
+fun:mq_send=uninstrumented
+fun:mq_setattr=uninstrumented
+fun:mq_timedreceive=uninstrumented
+fun:mq_timedsend=uninstrumented
+fun:mq_unlink=uninstrumented
+fun:mrand48=uninstrumented
+fun:mrand48_r=uninstrumented
+fun:mremap=uninstrumented
+fun:msgctl=uninstrumented
+fun:msgget=uninstrumented
+fun:msgrcv=uninstrumented
+fun:msgsnd=uninstrumented
+fun:msync=uninstrumented
+fun:mtrace=uninstrumented
+fun:munlock=uninstrumented
+fun:munlockall=uninstrumented
+fun:munmap=uninstrumented
+fun:muntrace=uninstrumented
+fun:name_to_handle_at=uninstrumented
+fun:nan=uninstrumented
+fun:nanf=uninstrumented
+fun:nanl=uninstrumented
+fun:nanosleep=uninstrumented
+fun:nearbyint=uninstrumented
+fun:nearbyintf=uninstrumented
+fun:nearbyintl=uninstrumented
+fun:netname2host=uninstrumented
+fun:netname2user=uninstrumented
+fun:newlocale=uninstrumented
+fun:nextafter=uninstrumented
+fun:nextafterf=uninstrumented
+fun:nextafterl=uninstrumented
+fun:nexttoward=uninstrumented
+fun:nexttowardf=uninstrumented
+fun:nexttowardl=uninstrumented
+fun:nfsservctl=uninstrumented
+fun:nftw=uninstrumented
+fun:nftw64=uninstrumented
+fun:ngettext=uninstrumented
+fun:nice=uninstrumented
+fun:nis_add=uninstrumented
+fun:nis_add_entry=uninstrumented
+fun:nis_addmember=uninstrumented
+fun:nis_checkpoint=uninstrumented
+fun:nis_clone_directory=uninstrumented
+fun:nis_clone_object=uninstrumented
+fun:nis_clone_result=uninstrumented
+fun:nis_creategroup=uninstrumented
+fun:nis_destroy_object=uninstrumented
+fun:nis_destroygroup=uninstrumented
+fun:nis_dir_cmp=uninstrumented
+fun:nis_domain_of=uninstrumented
+fun:nis_domain_of_r=uninstrumented
+fun:nis_first_entry=uninstrumented
+fun:nis_free_directory=uninstrumented
+fun:nis_free_object=uninstrumented
+fun:nis_free_request=uninstrumented
+fun:nis_freenames=uninstrumented
+fun:nis_freeresult=uninstrumented
+fun:nis_freeservlist=uninstrumented
+fun:nis_freetags=uninstrumented
+fun:nis_getnames=uninstrumented
+fun:nis_getservlist=uninstrumented
+fun:nis_ismember=uninstrumented
+fun:nis_leaf_of=uninstrumented
+fun:nis_leaf_of_r=uninstrumented
+fun:nis_lerror=uninstrumented
+fun:nis_list=uninstrumented
+fun:nis_local_directory=uninstrumented
+fun:nis_local_group=uninstrumented
+fun:nis_local_host=uninstrumented
+fun:nis_local_principal=uninstrumented
+fun:nis_lookup=uninstrumented
+fun:nis_mkdir=uninstrumented
+fun:nis_modify=uninstrumented
+fun:nis_modify_entry=uninstrumented
+fun:nis_name_of=uninstrumented
+fun:nis_name_of_r=uninstrumented
+fun:nis_next_entry=uninstrumented
+fun:nis_perror=uninstrumented
+fun:nis_ping=uninstrumented
+fun:nis_print_directory=uninstrumented
+fun:nis_print_entry=uninstrumented
+fun:nis_print_group=uninstrumented
+fun:nis_print_group_entry=uninstrumented
+fun:nis_print_link=uninstrumented
+fun:nis_print_object=uninstrumented
+fun:nis_print_result=uninstrumented
+fun:nis_print_rights=uninstrumented
+fun:nis_print_table=uninstrumented
+fun:nis_read_obj=uninstrumented
+fun:nis_remove=uninstrumented
+fun:nis_remove_entry=uninstrumented
+fun:nis_removemember=uninstrumented
+fun:nis_rmdir=uninstrumented
+fun:nis_servstate=uninstrumented
+fun:nis_sperrno=uninstrumented
+fun:nis_sperror=uninstrumented
+fun:nis_sperror_r=uninstrumented
+fun:nis_stats=uninstrumented
+fun:nis_verifygroup=uninstrumented
+fun:nis_write_obj=uninstrumented
+fun:nl_langinfo=uninstrumented
+fun:nl_langinfo_l=uninstrumented
+fun:nrand48=uninstrumented
+fun:nrand48_r=uninstrumented
+fun:ns_datetosecs=uninstrumented
+fun:ns_format_ttl=uninstrumented
+fun:ns_get16=uninstrumented
+fun:ns_get32=uninstrumented
+fun:ns_initparse=uninstrumented
+fun:ns_makecanon=uninstrumented
+fun:ns_msg_getflag=uninstrumented
+fun:ns_name_compress=uninstrumented
+fun:ns_name_ntol=uninstrumented
+fun:ns_name_ntop=uninstrumented
+fun:ns_name_pack=uninstrumented
+fun:ns_name_pton=uninstrumented
+fun:ns_name_rollback=uninstrumented
+fun:ns_name_skip=uninstrumented
+fun:ns_name_uncompress=uninstrumented
+fun:ns_name_unpack=uninstrumented
+fun:ns_parse_ttl=uninstrumented
+fun:ns_parserr=uninstrumented
+fun:ns_put16=uninstrumented
+fun:ns_put32=uninstrumented
+fun:ns_samedomain=uninstrumented
+fun:ns_samename=uninstrumented
+fun:ns_skiprr=uninstrumented
+fun:ns_sprintrr=uninstrumented
+fun:ns_sprintrrf=uninstrumented
+fun:ns_subdomain=uninstrumented
+fun:ntohl=uninstrumented
+fun:ntohs=uninstrumented
+fun:ntp_adjtime=uninstrumented
+fun:ntp_gettime=uninstrumented
+fun:ntp_gettimex=uninstrumented
+fun:obstack_free=uninstrumented
+fun:obstack_printf=uninstrumented
+fun:obstack_vprintf=uninstrumented
+fun:on_exit=uninstrumented
+fun:open=uninstrumented
+fun:open64=uninstrumented
+fun:open_by_handle_at=uninstrumented
+fun:open_memstream=uninstrumented
+fun:open_wmemstream=uninstrumented
+fun:openat=uninstrumented
+fun:openat64=uninstrumented
+fun:opendir=uninstrumented
+fun:openlog=uninstrumented
+fun:openpty=uninstrumented
+fun:parse_printf_format=uninstrumented
+fun:passwd2des=uninstrumented
+fun:pathconf=uninstrumented
+fun:pause=uninstrumented
+fun:pclose=uninstrumented
+fun:perror=uninstrumented
+fun:personality=uninstrumented
+fun:pipe=uninstrumented
+fun:pipe2=uninstrumented
+fun:pivot_root=uninstrumented
+fun:pmap_getmaps=uninstrumented
+fun:pmap_getport=uninstrumented
+fun:pmap_rmtcall=uninstrumented
+fun:pmap_set=uninstrumented
+fun:pmap_unset=uninstrumented
+fun:poll=uninstrumented
+fun:popen=uninstrumented
+fun:posix_fadvise=uninstrumented
+fun:posix_fadvise64=uninstrumented
+fun:posix_fallocate=uninstrumented
+fun:posix_fallocate64=uninstrumented
+fun:posix_madvise=uninstrumented
+fun:posix_memalign=uninstrumented
+fun:posix_openpt=uninstrumented
+fun:posix_spawn=uninstrumented
+fun:posix_spawn_file_actions_addclose=uninstrumented
+fun:posix_spawn_file_actions_adddup2=uninstrumented
+fun:posix_spawn_file_actions_addopen=uninstrumented
+fun:posix_spawn_file_actions_destroy=uninstrumented
+fun:posix_spawn_file_actions_init=uninstrumented
+fun:posix_spawnattr_destroy=uninstrumented
+fun:posix_spawnattr_getflags=uninstrumented
+fun:posix_spawnattr_getpgroup=uninstrumented
+fun:posix_spawnattr_getschedparam=uninstrumented
+fun:posix_spawnattr_getschedpolicy=uninstrumented
+fun:posix_spawnattr_getsigdefault=uninstrumented
+fun:posix_spawnattr_getsigmask=uninstrumented
+fun:posix_spawnattr_init=uninstrumented
+fun:posix_spawnattr_setflags=uninstrumented
+fun:posix_spawnattr_setpgroup=uninstrumented
+fun:posix_spawnattr_setschedparam=uninstrumented
+fun:posix_spawnattr_setschedpolicy=uninstrumented
+fun:posix_spawnattr_setsigdefault=uninstrumented
+fun:posix_spawnattr_setsigmask=uninstrumented
+fun:posix_spawnp=uninstrumented
+fun:pow=uninstrumented
+fun:pow10=uninstrumented
+fun:pow10f=uninstrumented
+fun:pow10l=uninstrumented
+fun:powf=uninstrumented
+fun:powl=uninstrumented
+fun:ppoll=uninstrumented
+fun:prctl=uninstrumented
+fun:pread=uninstrumented
+fun:pread64=uninstrumented
+fun:preadv=uninstrumented
+fun:preadv64=uninstrumented
+fun:printf=uninstrumented
+fun:printf_size=uninstrumented
+fun:printf_size_info=uninstrumented
+fun:prlimit=uninstrumented
+fun:prlimit64=uninstrumented
+fun:process_vm_readv=uninstrumented
+fun:process_vm_writev=uninstrumented
+fun:profil=uninstrumented
+fun:pselect=uninstrumented
+fun:psiginfo=uninstrumented
+fun:psignal=uninstrumented
+fun:pthread_atfork=uninstrumented
+fun:pthread_attr_destroy=uninstrumented
+fun:pthread_attr_getaffinity_np=uninstrumented
+fun:pthread_attr_getdetachstate=uninstrumented
+fun:pthread_attr_getguardsize=uninstrumented
+fun:pthread_attr_getinheritsched=uninstrumented
+fun:pthread_attr_getschedparam=uninstrumented
+fun:pthread_attr_getschedpolicy=uninstrumented
+fun:pthread_attr_getscope=uninstrumented
+fun:pthread_attr_getstack=uninstrumented
+fun:pthread_attr_getstackaddr=uninstrumented
+fun:pthread_attr_getstacksize=uninstrumented
+fun:pthread_attr_init=uninstrumented
+fun:pthread_attr_setaffinity_np=uninstrumented
+fun:pthread_attr_setdetachstate=uninstrumented
+fun:pthread_attr_setguardsize=uninstrumented
+fun:pthread_attr_setinheritsched=uninstrumented
+fun:pthread_attr_setschedparam=uninstrumented
+fun:pthread_attr_setschedpolicy=uninstrumented
+fun:pthread_attr_setscope=uninstrumented
+fun:pthread_attr_setstack=uninstrumented
+fun:pthread_attr_setstackaddr=uninstrumented
+fun:pthread_attr_setstacksize=uninstrumented
+fun:pthread_barrier_destroy=uninstrumented
+fun:pthread_barrier_init=uninstrumented
+fun:pthread_barrier_wait=uninstrumented
+fun:pthread_barrierattr_destroy=uninstrumented
+fun:pthread_barrierattr_getpshared=uninstrumented
+fun:pthread_barrierattr_init=uninstrumented
+fun:pthread_barrierattr_setpshared=uninstrumented
+fun:pthread_cancel=uninstrumented
+fun:pthread_cond_broadcast=uninstrumented
+fun:pthread_cond_destroy=uninstrumented
+fun:pthread_cond_init=uninstrumented
+fun:pthread_cond_signal=uninstrumented
+fun:pthread_cond_timedwait=uninstrumented
+fun:pthread_cond_wait=uninstrumented
+fun:pthread_condattr_destroy=uninstrumented
+fun:pthread_condattr_getclock=uninstrumented
+fun:pthread_condattr_getpshared=uninstrumented
+fun:pthread_condattr_init=uninstrumented
+fun:pthread_condattr_setclock=uninstrumented
+fun:pthread_condattr_setpshared=uninstrumented
+fun:pthread_create=uninstrumented
+fun:pthread_detach=uninstrumented
+fun:pthread_equal=uninstrumented
+fun:pthread_exit=uninstrumented
+fun:pthread_getaffinity_np=uninstrumented
+fun:pthread_getattr_default_np=uninstrumented
+fun:pthread_getattr_np=uninstrumented
+fun:pthread_getconcurrency=uninstrumented
+fun:pthread_getcpuclockid=uninstrumented
+fun:pthread_getname_np=uninstrumented
+fun:pthread_getschedparam=uninstrumented
+fun:pthread_getspecific=uninstrumented
+fun:pthread_join=uninstrumented
+fun:pthread_key_create=uninstrumented
+fun:pthread_key_delete=uninstrumented
+fun:pthread_kill=uninstrumented
+fun:pthread_kill_other_threads_np=uninstrumented
+fun:pthread_mutex_consistent=uninstrumented
+fun:pthread_mutex_consistent_np=uninstrumented
+fun:pthread_mutex_destroy=uninstrumented
+fun:pthread_mutex_getprioceiling=uninstrumented
+fun:pthread_mutex_init=uninstrumented
+fun:pthread_mutex_lock=uninstrumented
+fun:pthread_mutex_setprioceiling=uninstrumented
+fun:pthread_mutex_timedlock=uninstrumented
+fun:pthread_mutex_trylock=uninstrumented
+fun:pthread_mutex_unlock=uninstrumented
+fun:pthread_mutexattr_destroy=uninstrumented
+fun:pthread_mutexattr_getkind_np=uninstrumented
+fun:pthread_mutexattr_getprioceiling=uninstrumented
+fun:pthread_mutexattr_getprotocol=uninstrumented
+fun:pthread_mutexattr_getpshared=uninstrumented
+fun:pthread_mutexattr_getrobust=uninstrumented
+fun:pthread_mutexattr_getrobust_np=uninstrumented
+fun:pthread_mutexattr_gettype=uninstrumented
+fun:pthread_mutexattr_init=uninstrumented
+fun:pthread_mutexattr_setkind_np=uninstrumented
+fun:pthread_mutexattr_setprioceiling=uninstrumented
+fun:pthread_mutexattr_setprotocol=uninstrumented
+fun:pthread_mutexattr_setpshared=uninstrumented
+fun:pthread_mutexattr_setrobust=uninstrumented
+fun:pthread_mutexattr_setrobust_np=uninstrumented
+fun:pthread_mutexattr_settype=uninstrumented
+fun:pthread_once=uninstrumented
+fun:pthread_rwlock_destroy=uninstrumented
+fun:pthread_rwlock_init=uninstrumented
+fun:pthread_rwlock_rdlock=uninstrumented
+fun:pthread_rwlock_timedrdlock=uninstrumented
+fun:pthread_rwlock_timedwrlock=uninstrumented
+fun:pthread_rwlock_tryrdlock=uninstrumented
+fun:pthread_rwlock_trywrlock=uninstrumented
+fun:pthread_rwlock_unlock=uninstrumented
+fun:pthread_rwlock_wrlock=uninstrumented
+fun:pthread_rwlockattr_destroy=uninstrumented
+fun:pthread_rwlockattr_getkind_np=uninstrumented
+fun:pthread_rwlockattr_getpshared=uninstrumented
+fun:pthread_rwlockattr_init=uninstrumented
+fun:pthread_rwlockattr_setkind_np=uninstrumented
+fun:pthread_rwlockattr_setpshared=uninstrumented
+fun:pthread_self=uninstrumented
+fun:pthread_setaffinity_np=uninstrumented
+fun:pthread_setattr_default_np=uninstrumented
+fun:pthread_setcancelstate=uninstrumented
+fun:pthread_setcanceltype=uninstrumented
+fun:pthread_setconcurrency=uninstrumented
+fun:pthread_setname_np=uninstrumented
+fun:pthread_setschedparam=uninstrumented
+fun:pthread_setschedprio=uninstrumented
+fun:pthread_setspecific=uninstrumented
+fun:pthread_sigmask=uninstrumented
+fun:pthread_sigqueue=uninstrumented
+fun:pthread_spin_destroy=uninstrumented
+fun:pthread_spin_init=uninstrumented
+fun:pthread_spin_lock=uninstrumented
+fun:pthread_spin_trylock=uninstrumented
+fun:pthread_spin_unlock=uninstrumented
+fun:pthread_testcancel=uninstrumented
+fun:pthread_timedjoin_np=uninstrumented
+fun:pthread_tryjoin_np=uninstrumented
+fun:pthread_yield=uninstrumented
+fun:ptrace=uninstrumented
+fun:ptsname=uninstrumented
+fun:ptsname_r=uninstrumented
+fun:putc=uninstrumented
+fun:putc_unlocked=uninstrumented
+fun:putchar=uninstrumented
+fun:putchar_unlocked=uninstrumented
+fun:putenv=uninstrumented
+fun:putgrent=uninstrumented
+fun:putmsg=uninstrumented
+fun:putpmsg=uninstrumented
+fun:putpwent=uninstrumented
+fun:puts=uninstrumented
+fun:putsgent=uninstrumented
+fun:putspent=uninstrumented
+fun:pututline=uninstrumented
+fun:pututxline=uninstrumented
+fun:putw=uninstrumented
+fun:putwc=uninstrumented
+fun:putwc_unlocked=uninstrumented
+fun:putwchar=uninstrumented
+fun:putwchar_unlocked=uninstrumented
+fun:pvalloc=uninstrumented
+fun:pwrite=uninstrumented
+fun:pwrite64=uninstrumented
+fun:pwritev=uninstrumented
+fun:pwritev64=uninstrumented
+fun:qecvt=uninstrumented
+fun:qecvt_r=uninstrumented
+fun:qfcvt=uninstrumented
+fun:qfcvt_r=uninstrumented
+fun:qgcvt=uninstrumented
+fun:qsort=uninstrumented
+fun:qsort_r=uninstrumented
+fun:query_module=uninstrumented
+fun:quick_exit=uninstrumented
+fun:quotactl=uninstrumented
+fun:raise=uninstrumented
+fun:rand=uninstrumented
+fun:rand_r=uninstrumented
+fun:random=uninstrumented
+fun:random_r=uninstrumented
+fun:rawmemchr=uninstrumented
+fun:rcmd=uninstrumented
+fun:rcmd_af=uninstrumented
+fun:re_comp=uninstrumented
+fun:re_compile_fastmap=uninstrumented
+fun:re_compile_pattern=uninstrumented
+fun:re_exec=uninstrumented
+fun:re_match=uninstrumented
+fun:re_match_2=uninstrumented
+fun:re_search=uninstrumented
+fun:re_search_2=uninstrumented
+fun:re_set_registers=uninstrumented
+fun:re_set_syntax=uninstrumented
+fun:read=uninstrumented
+fun:readColdStartFile=uninstrumented
+fun:readahead=uninstrumented
+fun:readdir=uninstrumented
+fun:readdir64=uninstrumented
+fun:readdir64_r=uninstrumented
+fun:readdir_r=uninstrumented
+fun:readlink=uninstrumented
+fun:readlinkat=uninstrumented
+fun:readv=uninstrumented
+fun:realloc=uninstrumented
+fun:realpath=uninstrumented
+fun:reboot=uninstrumented
+fun:recv=uninstrumented
+fun:recvfrom=uninstrumented
+fun:recvmmsg=uninstrumented
+fun:recvmsg=uninstrumented
+fun:regcomp=uninstrumented
+fun:regerror=uninstrumented
+fun:regexec=uninstrumented
+fun:regfree=uninstrumented
+fun:register_printf_function=uninstrumented
+fun:register_printf_modifier=uninstrumented
+fun:register_printf_specifier=uninstrumented
+fun:register_printf_type=uninstrumented
+fun:registerrpc=uninstrumented
+fun:remainder=uninstrumented
+fun:remainderf=uninstrumented
+fun:remainderl=uninstrumented
+fun:remap_file_pages=uninstrumented
+fun:remove=uninstrumented
+fun:removexattr=uninstrumented
+fun:remque=uninstrumented
+fun:remquo=uninstrumented
+fun:remquof=uninstrumented
+fun:remquol=uninstrumented
+fun:rename=uninstrumented
+fun:renameat=uninstrumented
+fun:res_gethostbyaddr=uninstrumented
+fun:res_gethostbyname=uninstrumented
+fun:res_gethostbyname2=uninstrumented
+fun:res_send_setqhook=uninstrumented
+fun:res_send_setrhook=uninstrumented
+fun:revoke=uninstrumented
+fun:rewind=uninstrumented
+fun:rewinddir=uninstrumented
+fun:rexec=uninstrumented
+fun:rexec_af=uninstrumented
+fun:rindex=uninstrumented
+fun:rint=uninstrumented
+fun:rintf=uninstrumented
+fun:rintl=uninstrumented
+fun:rmdir=uninstrumented
+fun:round=uninstrumented
+fun:roundf=uninstrumented
+fun:roundl=uninstrumented
+fun:rpmatch=uninstrumented
+fun:rresvport=uninstrumented
+fun:rresvport_af=uninstrumented
+fun:rtime=uninstrumented
+fun:ruserok=uninstrumented
+fun:ruserok_af=uninstrumented
+fun:ruserpass=uninstrumented
+fun:sbrk=uninstrumented
+fun:scalb=uninstrumented
+fun:scalbf=uninstrumented
+fun:scalbl=uninstrumented
+fun:scalbln=uninstrumented
+fun:scalblnf=uninstrumented
+fun:scalblnl=uninstrumented
+fun:scalbn=uninstrumented
+fun:scalbnf=uninstrumented
+fun:scalbnl=uninstrumented
+fun:scandir=uninstrumented
+fun:scandir64=uninstrumented
+fun:scandirat=uninstrumented
+fun:scandirat64=uninstrumented
+fun:scanf=uninstrumented
+fun:sched_get_priority_max=uninstrumented
+fun:sched_get_priority_min=uninstrumented
+fun:sched_getaffinity=uninstrumented
+fun:sched_getcpu=uninstrumented
+fun:sched_getparam=uninstrumented
+fun:sched_getscheduler=uninstrumented
+fun:sched_rr_get_interval=uninstrumented
+fun:sched_setaffinity=uninstrumented
+fun:sched_setparam=uninstrumented
+fun:sched_setscheduler=uninstrumented
+fun:sched_yield=uninstrumented
+fun:secure_getenv=uninstrumented
+fun:seed48=uninstrumented
+fun:seed48_r=uninstrumented
+fun:seekdir=uninstrumented
+fun:select=uninstrumented
+fun:sem_close=uninstrumented
+fun:sem_destroy=uninstrumented
+fun:sem_getvalue=uninstrumented
+fun:sem_init=uninstrumented
+fun:sem_open=uninstrumented
+fun:sem_post=uninstrumented
+fun:sem_timedwait=uninstrumented
+fun:sem_trywait=uninstrumented
+fun:sem_unlink=uninstrumented
+fun:sem_wait=uninstrumented
+fun:semctl=uninstrumented
+fun:semget=uninstrumented
+fun:semop=uninstrumented
+fun:semtimedop=uninstrumented
+fun:send=uninstrumented
+fun:sendfile=uninstrumented
+fun:sendfile64=uninstrumented
+fun:sendmmsg=uninstrumented
+fun:sendmsg=uninstrumented
+fun:sendto=uninstrumented
+fun:setaliasent=uninstrumented
+fun:setbuf=uninstrumented
+fun:setbuffer=uninstrumented
+fun:setcontext=uninstrumented
+fun:setdomainname=uninstrumented
+fun:setegid=uninstrumented
+fun:setenv=uninstrumented
+fun:seteuid=uninstrumented
+fun:setfsent=uninstrumented
+fun:setfsgid=uninstrumented
+fun:setfsuid=uninstrumented
+fun:setgid=uninstrumented
+fun:setgrent=uninstrumented
+fun:setgroups=uninstrumented
+fun:sethostent=uninstrumented
+fun:sethostid=uninstrumented
+fun:sethostname=uninstrumented
+fun:setipv4sourcefilter=uninstrumented
+fun:setitimer=uninstrumented
+fun:setjmp=uninstrumented
+fun:setkey=uninstrumented
+fun:setkey_r=uninstrumented
+fun:setlinebuf=uninstrumented
+fun:setlocale=uninstrumented
+fun:setlogin=uninstrumented
+fun:setlogmask=uninstrumented
+fun:setmntent=uninstrumented
+fun:setnetent=uninstrumented
+fun:setnetgrent=uninstrumented
+fun:setns=uninstrumented
+fun:setpgid=uninstrumented
+fun:setpgrp=uninstrumented
+fun:setpriority=uninstrumented
+fun:setprotoent=uninstrumented
+fun:setpwent=uninstrumented
+fun:setregid=uninstrumented
+fun:setresgid=uninstrumented
+fun:setresuid=uninstrumented
+fun:setreuid=uninstrumented
+fun:setrlimit=uninstrumented
+fun:setrlimit64=uninstrumented
+fun:setrpcent=uninstrumented
+fun:setservent=uninstrumented
+fun:setsgent=uninstrumented
+fun:setsid=uninstrumented
+fun:setsockopt=uninstrumented
+fun:setsourcefilter=uninstrumented
+fun:setspent=uninstrumented
+fun:setstate=uninstrumented
+fun:setstate_r=uninstrumented
+fun:settimeofday=uninstrumented
+fun:setttyent=uninstrumented
+fun:setuid=uninstrumented
+fun:setusershell=uninstrumented
+fun:setutent=uninstrumented
+fun:setutxent=uninstrumented
+fun:setvbuf=uninstrumented
+fun:setxattr=uninstrumented
+fun:sgetsgent=uninstrumented
+fun:sgetsgent_r=uninstrumented
+fun:sgetspent=uninstrumented
+fun:sgetspent_r=uninstrumented
+fun:shm_open=uninstrumented
+fun:shm_unlink=uninstrumented
+fun:shmat=uninstrumented
+fun:shmctl=uninstrumented
+fun:shmdt=uninstrumented
+fun:shmget=uninstrumented
+fun:shutdown=uninstrumented
+fun:sigaction=uninstrumented
+fun:sigaddset=uninstrumented
+fun:sigaltstack=uninstrumented
+fun:sigandset=uninstrumented
+fun:sigblock=uninstrumented
+fun:sigdelset=uninstrumented
+fun:sigemptyset=uninstrumented
+fun:sigfillset=uninstrumented
+fun:siggetmask=uninstrumented
+fun:sighold=uninstrumented
+fun:sigignore=uninstrumented
+fun:siginterrupt=uninstrumented
+fun:sigisemptyset=uninstrumented
+fun:sigismember=uninstrumented
+fun:siglongjmp=uninstrumented
+fun:signal=uninstrumented
+fun:signalfd=uninstrumented
+fun:significand=uninstrumented
+fun:significandf=uninstrumented
+fun:significandl=uninstrumented
+fun:sigorset=uninstrumented
+fun:sigpause=uninstrumented
+fun:sigpending=uninstrumented
+fun:sigprocmask=uninstrumented
+fun:sigqueue=uninstrumented
+fun:sigrelse=uninstrumented
+fun:sigreturn=uninstrumented
+fun:sigset=uninstrumented
+fun:sigsetmask=uninstrumented
+fun:sigstack=uninstrumented
+fun:sigsuspend=uninstrumented
+fun:sigtimedwait=uninstrumented
+fun:sigvec=uninstrumented
+fun:sigwait=uninstrumented
+fun:sigwaitinfo=uninstrumented
+fun:sin=uninstrumented
+fun:sincos=uninstrumented
+fun:sincosf=uninstrumented
+fun:sincosl=uninstrumented
+fun:sinf=uninstrumented
+fun:sinh=uninstrumented
+fun:sinhf=uninstrumented
+fun:sinhl=uninstrumented
+fun:sinl=uninstrumented
+fun:sleep=uninstrumented
+fun:snprintf=uninstrumented
+fun:sockatmark=uninstrumented
+fun:socket=uninstrumented
+fun:socketpair=uninstrumented
+fun:splice=uninstrumented
+fun:sprintf=uninstrumented
+fun:sprofil=uninstrumented
+fun:sqrt=uninstrumented
+fun:sqrtf=uninstrumented
+fun:sqrtl=uninstrumented
+fun:srand=uninstrumented
+fun:srand48=uninstrumented
+fun:srand48_r=uninstrumented
+fun:srandom=uninstrumented
+fun:srandom_r=uninstrumented
+fun:sscanf=uninstrumented
+fun:ssignal=uninstrumented
+fun:sstk=uninstrumented
+fun:stat=uninstrumented
+fun:stat64=uninstrumented
+fun:statfs=uninstrumented
+fun:statfs64=uninstrumented
+fun:statvfs=uninstrumented
+fun:statvfs64=uninstrumented
+fun:step=uninstrumented
+fun:stime=uninstrumented
+fun:stpcpy=uninstrumented
+fun:stpncpy=uninstrumented
+fun:strcasecmp=uninstrumented
+fun:strcasecmp_l=uninstrumented
+fun:strcasestr=uninstrumented
+fun:strcat=uninstrumented
+fun:strchr=uninstrumented
+fun:strchrnul=uninstrumented
+fun:strcmp=uninstrumented
+fun:strcoll=uninstrumented
+fun:strcoll_l=uninstrumented
+fun:strcpy=uninstrumented
+fun:strcspn=uninstrumented
+fun:strdup=uninstrumented
+fun:strerror=uninstrumented
+fun:strerror_l=uninstrumented
+fun:strerror_r=uninstrumented
+fun:strfmon=uninstrumented
+fun:strfmon_l=uninstrumented
+fun:strfry=uninstrumented
+fun:strftime=uninstrumented
+fun:strftime_l=uninstrumented
+fun:strlen=uninstrumented
+fun:strncasecmp=uninstrumented
+fun:strncasecmp_l=uninstrumented
+fun:strncat=uninstrumented
+fun:strncmp=uninstrumented
+fun:strncpy=uninstrumented
+fun:strndup=uninstrumented
+fun:strnlen=uninstrumented
+fun:strpbrk=uninstrumented
+fun:strptime=uninstrumented
+fun:strptime_l=uninstrumented
+fun:strrchr=uninstrumented
+fun:strsep=uninstrumented
+fun:strsignal=uninstrumented
+fun:strspn=uninstrumented
+fun:strstr=uninstrumented
+fun:strtod=uninstrumented
+fun:strtod_l=uninstrumented
+fun:strtof=uninstrumented
+fun:strtof_l=uninstrumented
+fun:strtoimax=uninstrumented
+fun:strtok=uninstrumented
+fun:strtok_r=uninstrumented
+fun:strtol=uninstrumented
+fun:strtol_l=uninstrumented
+fun:strtold=uninstrumented
+fun:strtold_l=uninstrumented
+fun:strtoll=uninstrumented
+fun:strtoll_l=uninstrumented
+fun:strtoq=uninstrumented
+fun:strtoul=uninstrumented
+fun:strtoul_l=uninstrumented
+fun:strtoull=uninstrumented
+fun:strtoull_l=uninstrumented
+fun:strtoumax=uninstrumented
+fun:strtouq=uninstrumented
+fun:strverscmp=uninstrumented
+fun:strxfrm=uninstrumented
+fun:strxfrm_l=uninstrumented
+fun:stty=uninstrumented
+fun:svc_exit=uninstrumented
+fun:svc_getreq=uninstrumented
+fun:svc_getreq_common=uninstrumented
+fun:svc_getreq_poll=uninstrumented
+fun:svc_getreqset=uninstrumented
+fun:svc_register=uninstrumented
+fun:svc_run=uninstrumented
+fun:svc_sendreply=uninstrumented
+fun:svc_unregister=uninstrumented
+fun:svcerr_auth=uninstrumented
+fun:svcerr_decode=uninstrumented
+fun:svcerr_noproc=uninstrumented
+fun:svcerr_noprog=uninstrumented
+fun:svcerr_progvers=uninstrumented
+fun:svcerr_systemerr=uninstrumented
+fun:svcerr_weakauth=uninstrumented
+fun:svcfd_create=uninstrumented
+fun:svcraw_create=uninstrumented
+fun:svctcp_create=uninstrumented
+fun:svcudp_bufcreate=uninstrumented
+fun:svcudp_create=uninstrumented
+fun:svcudp_enablecache=uninstrumented
+fun:svcunix_create=uninstrumented
+fun:svcunixfd_create=uninstrumented
+fun:swab=uninstrumented
+fun:swapcontext=uninstrumented
+fun:swapoff=uninstrumented
+fun:swapon=uninstrumented
+fun:swprintf=uninstrumented
+fun:swscanf=uninstrumented
+fun:symlink=uninstrumented
+fun:symlinkat=uninstrumented
+fun:sync=uninstrumented
+fun:sync_file_range=uninstrumented
+fun:syncfs=uninstrumented
+fun:syscall=uninstrumented
+fun:sysconf=uninstrumented
+fun:sysctl=uninstrumented
+fun:sysinfo=uninstrumented
+fun:syslog=uninstrumented
+fun:system=uninstrumented
+fun:sysv_signal=uninstrumented
+fun:tan=uninstrumented
+fun:tanf=uninstrumented
+fun:tanh=uninstrumented
+fun:tanhf=uninstrumented
+fun:tanhl=uninstrumented
+fun:tanl=uninstrumented
+fun:tcdrain=uninstrumented
+fun:tcflow=uninstrumented
+fun:tcflush=uninstrumented
+fun:tcgetattr=uninstrumented
+fun:tcgetpgrp=uninstrumented
+fun:tcgetsid=uninstrumented
+fun:tcsendbreak=uninstrumented
+fun:tcsetattr=uninstrumented
+fun:tcsetpgrp=uninstrumented
+fun:td_init=uninstrumented
+fun:td_log=uninstrumented
+fun:td_symbol_list=uninstrumented
+fun:td_ta_clear_event=uninstrumented
+fun:td_ta_delete=uninstrumented
+fun:td_ta_enable_stats=uninstrumented
+fun:td_ta_event_addr=uninstrumented
+fun:td_ta_event_getmsg=uninstrumented
+fun:td_ta_get_nthreads=uninstrumented
+fun:td_ta_get_ph=uninstrumented
+fun:td_ta_get_stats=uninstrumented
+fun:td_ta_map_id2thr=uninstrumented
+fun:td_ta_map_lwp2thr=uninstrumented
+fun:td_ta_new=uninstrumented
+fun:td_ta_reset_stats=uninstrumented
+fun:td_ta_set_event=uninstrumented
+fun:td_ta_setconcurrency=uninstrumented
+fun:td_ta_thr_iter=uninstrumented
+fun:td_ta_tsd_iter=uninstrumented
+fun:td_thr_clear_event=uninstrumented
+fun:td_thr_dbresume=uninstrumented
+fun:td_thr_dbsuspend=uninstrumented
+fun:td_thr_event_enable=uninstrumented
+fun:td_thr_event_getmsg=uninstrumented
+fun:td_thr_get_info=uninstrumented
+fun:td_thr_getfpregs=uninstrumented
+fun:td_thr_getgregs=uninstrumented
+fun:td_thr_getxregs=uninstrumented
+fun:td_thr_getxregsize=uninstrumented
+fun:td_thr_set_event=uninstrumented
+fun:td_thr_setfpregs=uninstrumented
+fun:td_thr_setgregs=uninstrumented
+fun:td_thr_setprio=uninstrumented
+fun:td_thr_setsigpending=uninstrumented
+fun:td_thr_setxregs=uninstrumented
+fun:td_thr_sigsetmask=uninstrumented
+fun:td_thr_tls_get_addr=uninstrumented
+fun:td_thr_tlsbase=uninstrumented
+fun:td_thr_tsd=uninstrumented
+fun:td_thr_validate=uninstrumented
+fun:tdelete=uninstrumented
+fun:tdestroy=uninstrumented
+fun:tee=uninstrumented
+fun:telldir=uninstrumented
+fun:tempnam=uninstrumented
+fun:textdomain=uninstrumented
+fun:tfind=uninstrumented
+fun:tgamma=uninstrumented
+fun:tgammaf=uninstrumented
+fun:tgammal=uninstrumented
+fun:time=uninstrumented
+fun:timegm=uninstrumented
+fun:timelocal=uninstrumented
+fun:timer_create=uninstrumented
+fun:timer_delete=uninstrumented
+fun:timer_getoverrun=uninstrumented
+fun:timer_gettime=uninstrumented
+fun:timer_settime=uninstrumented
+fun:timerfd_create=uninstrumented
+fun:timerfd_gettime=uninstrumented
+fun:timerfd_settime=uninstrumented
+fun:times=uninstrumented
+fun:timespec_get=uninstrumented
+fun:tmpfile=uninstrumented
+fun:tmpfile64=uninstrumented
+fun:tmpnam=uninstrumented
+fun:tmpnam_r=uninstrumented
+fun:toascii=uninstrumented
+fun:tolower=uninstrumented
+fun:tolower_l=uninstrumented
+fun:toupper=uninstrumented
+fun:toupper_l=uninstrumented
+fun:towctrans=uninstrumented
+fun:towctrans_l=uninstrumented
+fun:towlower=uninstrumented
+fun:towlower_l=uninstrumented
+fun:towupper=uninstrumented
+fun:towupper_l=uninstrumented
+fun:tr_break=uninstrumented
+fun:trunc=uninstrumented
+fun:truncate=uninstrumented
+fun:truncate64=uninstrumented
+fun:truncf=uninstrumented
+fun:truncl=uninstrumented
+fun:tsearch=uninstrumented
+fun:ttyname=uninstrumented
+fun:ttyname_r=uninstrumented
+fun:ttyslot=uninstrumented
+fun:twalk=uninstrumented
+fun:tzset=uninstrumented
+fun:ualarm=uninstrumented
+fun:ulckpwdf=uninstrumented
+fun:ulimit=uninstrumented
+fun:umask=uninstrumented
+fun:umount=uninstrumented
+fun:umount2=uninstrumented
+fun:uname=uninstrumented
+fun:ungetc=uninstrumented
+fun:ungetwc=uninstrumented
+fun:unlink=uninstrumented
+fun:unlinkat=uninstrumented
+fun:unlockpt=uninstrumented
+fun:unsetenv=uninstrumented
+fun:unshare=uninstrumented
+fun:updwtmp=uninstrumented
+fun:updwtmpx=uninstrumented
+fun:uselib=uninstrumented
+fun:uselocale=uninstrumented
+fun:user2netname=uninstrumented
+fun:usleep=uninstrumented
+fun:ustat=uninstrumented
+fun:utime=uninstrumented
+fun:utimensat=uninstrumented
+fun:utimes=uninstrumented
+fun:utmpname=uninstrumented
+fun:utmpxname=uninstrumented
+fun:valloc=uninstrumented
+fun:vasprintf=uninstrumented
+fun:vdprintf=uninstrumented
+fun:verr=uninstrumented
+fun:verrx=uninstrumented
+fun:versionsort=uninstrumented
+fun:versionsort64=uninstrumented
+fun:vfork=uninstrumented
+fun:vfprintf=uninstrumented
+fun:vfscanf=uninstrumented
+fun:vfwprintf=uninstrumented
+fun:vfwscanf=uninstrumented
+fun:vhangup=uninstrumented
+fun:vlimit=uninstrumented
+fun:vmsplice=uninstrumented
+fun:vprintf=uninstrumented
+fun:vscanf=uninstrumented
+fun:vsnprintf=uninstrumented
+fun:vsprintf=uninstrumented
+fun:vsscanf=uninstrumented
+fun:vswprintf=uninstrumented
+fun:vswscanf=uninstrumented
+fun:vsyslog=uninstrumented
+fun:vtimes=uninstrumented
+fun:vwarn=uninstrumented
+fun:vwarnx=uninstrumented
+fun:vwprintf=uninstrumented
+fun:vwscanf=uninstrumented
+fun:wait=uninstrumented
+fun:wait3=uninstrumented
+fun:wait4=uninstrumented
+fun:waitid=uninstrumented
+fun:waitpid=uninstrumented
+fun:warn=uninstrumented
+fun:warnx=uninstrumented
+fun:wcpcpy=uninstrumented
+fun:wcpncpy=uninstrumented
+fun:wcrtomb=uninstrumented
+fun:wcscasecmp=uninstrumented
+fun:wcscasecmp_l=uninstrumented
+fun:wcscat=uninstrumented
+fun:wcschr=uninstrumented
+fun:wcschrnul=uninstrumented
+fun:wcscmp=uninstrumented
+fun:wcscoll=uninstrumented
+fun:wcscoll_l=uninstrumented
+fun:wcscpy=uninstrumented
+fun:wcscspn=uninstrumented
+fun:wcsdup=uninstrumented
+fun:wcsftime=uninstrumented
+fun:wcsftime_l=uninstrumented
+fun:wcslen=uninstrumented
+fun:wcsncasecmp=uninstrumented
+fun:wcsncasecmp_l=uninstrumented
+fun:wcsncat=uninstrumented
+fun:wcsncmp=uninstrumented
+fun:wcsncpy=uninstrumented
+fun:wcsnlen=uninstrumented
+fun:wcsnrtombs=uninstrumented
+fun:wcspbrk=uninstrumented
+fun:wcsrchr=uninstrumented
+fun:wcsrtombs=uninstrumented
+fun:wcsspn=uninstrumented
+fun:wcsstr=uninstrumented
+fun:wcstod=uninstrumented
+fun:wcstod_l=uninstrumented
+fun:wcstof=uninstrumented
+fun:wcstof_l=uninstrumented
+fun:wcstoimax=uninstrumented
+fun:wcstok=uninstrumented
+fun:wcstol=uninstrumented
+fun:wcstol_l=uninstrumented
+fun:wcstold=uninstrumented
+fun:wcstold_l=uninstrumented
+fun:wcstoll=uninstrumented
+fun:wcstoll_l=uninstrumented
+fun:wcstombs=uninstrumented
+fun:wcstoq=uninstrumented
+fun:wcstoul=uninstrumented
+fun:wcstoul_l=uninstrumented
+fun:wcstoull=uninstrumented
+fun:wcstoull_l=uninstrumented
+fun:wcstoumax=uninstrumented
+fun:wcstouq=uninstrumented
+fun:wcswcs=uninstrumented
+fun:wcswidth=uninstrumented
+fun:wcsxfrm=uninstrumented
+fun:wcsxfrm_l=uninstrumented
+fun:wctob=uninstrumented
+fun:wctomb=uninstrumented
+fun:wctrans=uninstrumented
+fun:wctrans_l=uninstrumented
+fun:wctype=uninstrumented
+fun:wctype_l=uninstrumented
+fun:wcwidth=uninstrumented
+fun:wmemchr=uninstrumented
+fun:wmemcmp=uninstrumented
+fun:wmemcpy=uninstrumented
+fun:wmemmove=uninstrumented
+fun:wmempcpy=uninstrumented
+fun:wmemset=uninstrumented
+fun:wordexp=uninstrumented
+fun:wordfree=uninstrumented
+fun:wprintf=uninstrumented
+fun:write=uninstrumented
+fun:writeColdStartFile=uninstrumented
+fun:writev=uninstrumented
+fun:wscanf=uninstrumented
+fun:xdecrypt=uninstrumented
+fun:xdr_accepted_reply=uninstrumented
+fun:xdr_array=uninstrumented
+fun:xdr_authdes_cred=uninstrumented
+fun:xdr_authdes_verf=uninstrumented
+fun:xdr_authunix_parms=uninstrumented
+fun:xdr_bool=uninstrumented
+fun:xdr_bytes=uninstrumented
+fun:xdr_callhdr=uninstrumented
+fun:xdr_callmsg=uninstrumented
+fun:xdr_cback_data=uninstrumented
+fun:xdr_char=uninstrumented
+fun:xdr_cryptkeyarg=uninstrumented
+fun:xdr_cryptkeyarg2=uninstrumented
+fun:xdr_cryptkeyres=uninstrumented
+fun:xdr_des_block=uninstrumented
+fun:xdr_domainname=uninstrumented
+fun:xdr_double=uninstrumented
+fun:xdr_enum=uninstrumented
+fun:xdr_float=uninstrumented
+fun:xdr_free=uninstrumented
+fun:xdr_getcredres=uninstrumented
+fun:xdr_hyper=uninstrumented
+fun:xdr_int=uninstrumented
+fun:xdr_int16_t=uninstrumented
+fun:xdr_int32_t=uninstrumented
+fun:xdr_int64_t=uninstrumented
+fun:xdr_int8_t=uninstrumented
+fun:xdr_key_netstarg=uninstrumented
+fun:xdr_key_netstres=uninstrumented
+fun:xdr_keybuf=uninstrumented
+fun:xdr_keydat=uninstrumented
+fun:xdr_keystatus=uninstrumented
+fun:xdr_long=uninstrumented
+fun:xdr_longlong_t=uninstrumented
+fun:xdr_mapname=uninstrumented
+fun:xdr_netnamestr=uninstrumented
+fun:xdr_netobj=uninstrumented
+fun:xdr_obj_p=uninstrumented
+fun:xdr_opaque=uninstrumented
+fun:xdr_opaque_auth=uninstrumented
+fun:xdr_peername=uninstrumented
+fun:xdr_pmap=uninstrumented
+fun:xdr_pmaplist=uninstrumented
+fun:xdr_pointer=uninstrumented
+fun:xdr_quad_t=uninstrumented
+fun:xdr_reference=uninstrumented
+fun:xdr_rejected_reply=uninstrumented
+fun:xdr_replymsg=uninstrumented
+fun:xdr_rmtcall_args=uninstrumented
+fun:xdr_rmtcallres=uninstrumented
+fun:xdr_short=uninstrumented
+fun:xdr_sizeof=uninstrumented
+fun:xdr_string=uninstrumented
+fun:xdr_u_char=uninstrumented
+fun:xdr_u_hyper=uninstrumented
+fun:xdr_u_int=uninstrumented
+fun:xdr_u_long=uninstrumented
+fun:xdr_u_longlong_t=uninstrumented
+fun:xdr_u_quad_t=uninstrumented
+fun:xdr_u_short=uninstrumented
+fun:xdr_uint16_t=uninstrumented
+fun:xdr_uint32_t=uninstrumented
+fun:xdr_uint64_t=uninstrumented
+fun:xdr_uint8_t=uninstrumented
+fun:xdr_union=uninstrumented
+fun:xdr_unixcred=uninstrumented
+fun:xdr_valdat=uninstrumented
+fun:xdr_vector=uninstrumented
+fun:xdr_void=uninstrumented
+fun:xdr_wrapstring=uninstrumented
+fun:xdr_yp_buf=uninstrumented
+fun:xdr_ypall=uninstrumented
+fun:xdr_ypbind_binding=uninstrumented
+fun:xdr_ypbind_resp=uninstrumented
+fun:xdr_ypbind_resptype=uninstrumented
+fun:xdr_ypbind_setdom=uninstrumented
+fun:xdr_ypdelete_args=uninstrumented
+fun:xdr_ypmap_parms=uninstrumented
+fun:xdr_ypmaplist=uninstrumented
+fun:xdr_yppush_status=uninstrumented
+fun:xdr_yppushresp_xfr=uninstrumented
+fun:xdr_ypreq_key=uninstrumented
+fun:xdr_ypreq_nokey=uninstrumented
+fun:xdr_ypreq_xfr=uninstrumented
+fun:xdr_ypresp_all=uninstrumented
+fun:xdr_ypresp_key_val=uninstrumented
+fun:xdr_ypresp_maplist=uninstrumented
+fun:xdr_ypresp_master=uninstrumented
+fun:xdr_ypresp_order=uninstrumented
+fun:xdr_ypresp_val=uninstrumented
+fun:xdr_ypresp_xfr=uninstrumented
+fun:xdr_ypstat=uninstrumented
+fun:xdr_ypupdate_args=uninstrumented
+fun:xdr_ypxfrstat=uninstrumented
+fun:xdrmem_create=uninstrumented
+fun:xdrrec_create=uninstrumented
+fun:xdrrec_endofrecord=uninstrumented
+fun:xdrrec_eof=uninstrumented
+fun:xdrrec_skiprecord=uninstrumented
+fun:xdrstdio_create=uninstrumented
+fun:xencrypt=uninstrumented
+fun:xprt_register=uninstrumented
+fun:xprt_unregister=uninstrumented
+fun:y0=uninstrumented
+fun:y0f=uninstrumented
+fun:y0l=uninstrumented
+fun:y1=uninstrumented
+fun:y1f=uninstrumented
+fun:y1l=uninstrumented
+fun:yn=uninstrumented
+fun:ynf=uninstrumented
+fun:ynl=uninstrumented
+fun:yp_all=uninstrumented
+fun:yp_bind=uninstrumented
+fun:yp_first=uninstrumented
+fun:yp_get_default_domain=uninstrumented
+fun:yp_maplist=uninstrumented
+fun:yp_master=uninstrumented
+fun:yp_match=uninstrumented
+fun:yp_next=uninstrumented
+fun:yp_order=uninstrumented
+fun:yp_unbind=uninstrumented
+fun:yp_update=uninstrumented
+fun:ypbinderr_string=uninstrumented
+fun:yperr_string=uninstrumented
+fun:ypprot_err=uninstrumented
diff --git a/contrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py b/contrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py
new file mode 100755
index 000000000000..eddb6c07e99d
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+#===- lib/dfsan/scripts/build-libc-list.py ---------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+# The purpose of this script is to identify every function symbol in a set of
+# libraries (in this case, libc and libgcc) so that they can be marked as
+# uninstrumented, thus allowing the instrumentation pass to treat calls to those
+# functions correctly.
+
+import os
+import subprocess
+import sys
+from optparse import OptionParser
+
+def defined_function_list(object):
+ functions = []
+ readelf_proc = subprocess.Popen(['readelf', '-s', '-W', object],
+ stdout=subprocess.PIPE)
+ readelf = readelf_proc.communicate()[0].split('\n')
+ if readelf_proc.returncode != 0:
+ raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
+ for line in readelf:
+ if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
+ line[39:44] != 'LOCAL' and \
+ line[55:58] != 'UND':
+ function_name = line[59:].split('@')[0]
+ functions.append(function_name)
+ return functions
+
+p = OptionParser()
+
+p.add_option('--libc-dso-path', metavar='PATH',
+ help='path to libc DSO directory',
+ default='/lib/x86_64-linux-gnu')
+p.add_option('--libc-archive-path', metavar='PATH',
+ help='path to libc archive directory',
+ default='/usr/lib/x86_64-linux-gnu')
+
+p.add_option('--libgcc-dso-path', metavar='PATH',
+ help='path to libgcc DSO directory',
+ default='/lib/x86_64-linux-gnu')
+p.add_option('--libgcc-archive-path', metavar='PATH',
+ help='path to libgcc archive directory',
+ default='/usr/lib/gcc/x86_64-linux-gnu/4.6')
+
+p.add_option('--with-libstdcxx', action='store_true',
+ dest='with_libstdcxx',
+ help='include libstdc++ in the list (inadvisable)')
+p.add_option('--libstdcxx-dso-path', metavar='PATH',
+ help='path to libstdc++ DSO directory',
+ default='/usr/lib/x86_64-linux-gnu')
+
+(options, args) = p.parse_args()
+
+libs = [os.path.join(options.libc_dso_path, name) for name in
+ ['ld-linux-x86-64.so.2',
+ 'libanl.so.1',
+ 'libBrokenLocale.so.1',
+ 'libcidn.so.1',
+ 'libcrypt.so.1',
+ 'libc.so.6',
+ 'libdl.so.2',
+ 'libm.so.6',
+ 'libnsl.so.1',
+ 'libpthread.so.0',
+ 'libresolv.so.2',
+ 'librt.so.1',
+ 'libthread_db.so.1',
+ 'libutil.so.1']]
+libs += [os.path.join(options.libc_archive_path, name) for name in
+ ['libc_nonshared.a',
+ 'libpthread_nonshared.a']]
+
+libs.append(os.path.join(options.libgcc_dso_path, 'libgcc_s.so.1'))
+libs.append(os.path.join(options.libgcc_archive_path, 'libgcc.a'))
+
+if options.with_libstdcxx:
+ libs.append(os.path.join(options.libstdcxx_dso_path, 'libstdc++.so.6'))
+
+functions = []
+for l in libs:
+ if os.path.exists(l):
+ functions += defined_function_list(l)
+ else:
+ print >> sys.stderr, 'warning: library %s not found' % l
+
+functions = list(set(functions))
+functions.sort()
+
+for f in functions:
+ print 'fun:%s=uninstrumented' % f
diff --git a/contrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh b/contrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh
new file mode 100755
index 000000000000..50bc85d4aef5
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+DFSAN_DIR=$(dirname "$0")/../
+DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.cc
+DFSAN_CUSTOM_WRAPPERS=${DFSAN_DIR}/dfsan_custom.cc
+DFSAN_ABI_LIST=${DFSAN_DIR}/done_abilist.txt
+
+DIFFOUT=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+ERRORLOG=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_A=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_B=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+
+on_exit() {
+ rm -f ${DIFFOUT} 2> /dev/null
+ rm -f ${ERRORLOG} 2> /dev/null
+ rm -f ${DIFF_A} 2> /dev/null
+ rm -f ${DIFF_B} 2> /dev/null
+}
+
+trap on_exit EXIT
+grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} | grep -v "dfsan_get_label" \
+ | sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A
+grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
+ | sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
+if [ $? -ne 0 ]
+then
+ echo -n "The following differences between the ABI list and ">> ${ERRORLOG}
+ echo "the implemented custom wrappers have been found:" >> ${ERRORLOG}
+ cat ${DIFFOUT} >> ${ERRORLOG}
+fi
+
+grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
+ | sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
+grep -E "^\\s*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
+ | sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
+if [ $? -ne 0 ]
+then
+ echo -n "The following differences between the implemented " >> ${ERRORLOG}
+ echo "custom wrappers and the tests have been found:" >> ${ERRORLOG}
+ cat ${DIFFOUT} >> ${ERRORLOG}
+fi
+
+if [ -s ${ERRORLOG} ]
+then
+ cat ${ERRORLOG}
+ exit 1
+fi
+
diff --git a/contrib/compiler-rt/lib/fixdfdi.c b/contrib/compiler-rt/lib/fixdfdi.c
deleted file mode 100644
index 86f9f6ce8db3..000000000000
--- a/contrib/compiler-rt/lib/fixdfdi.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * su_int is a 32 bit integral type
- * value in double is representable in di_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(d2lz, fixdfdi)
-
-COMPILER_RT_ABI di_int
-__fixdfdi(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0)
- return 0;
- di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
- dwords r;
- r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
- r.s.low = fb.u.s.low;
- if (e > 52)
- r.all <<= (e - 52);
- else
- r.all >>= (52 - e);
- return (r.all ^ s) - s;
-}
diff --git a/contrib/compiler-rt/lib/fixdfsi.c b/contrib/compiler-rt/lib/fixdfsi.c
deleted file mode 100644
index 614d032a4e14..000000000000
--- a/contrib/compiler-rt/lib/fixdfsi.c
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements double-precision to integer conversion for the
-// compiler-rt library. No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(d2iz, fixdfsi)
-
-int __fixdfsi(fp_t a) {
-
- // Break a into sign, exponent, significand
- const rep_t aRep = toRep(a);
- const rep_t aAbs = aRep & absMask;
- const int sign = aRep & signBit ? -1 : 1;
- const int exponent = (aAbs >> significandBits) - exponentBias;
- const rep_t significand = (aAbs & significandMask) | implicitBit;
-
- // If 0 < exponent < significandBits, right shift to get the result.
- if ((unsigned int)exponent < significandBits) {
- return sign * (significand >> (significandBits - exponent));
- }
-
- // If exponent is negative, the result is zero.
- else if (exponent < 0) {
- return 0;
- }
-
- // If significandBits < exponent, left shift to get the result. This shift
- // may end up being larger than the type width, which incurs undefined
- // behavior, but the conversion itself is undefined in that case, so
- // whatever the compiler decides to do is fine.
- else {
- return sign * (significand << (exponent - significandBits));
- }
-}
diff --git a/contrib/compiler-rt/lib/fixdfti.c b/contrib/compiler-rt/lib/fixdfti.c
deleted file mode 100644
index 3b9ddb2cb362..000000000000
--- a/contrib/compiler-rt/lib/fixdfti.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * su_int is a 32 bit integral type
- * value in double is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-ti_int
-__fixdfti(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0)
- return 0;
- ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
- ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all);
- if (e > 52)
- r <<= (e - 52);
- else
- r >>= (52 - e);
- return (r ^ s) - s;
-}
-
-#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/fixsfdi.c b/contrib/compiler-rt/lib/fixsfdi.c
deleted file mode 100644
index 4f6cfdd7a5c6..000000000000
--- a/contrib/compiler-rt/lib/fixsfdi.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixsfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * su_int is a 32 bit integral type
- * value in float is representable in di_int (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(f2lz, fixsfdi)
-
-COMPILER_RT_ABI di_int
-__fixsfdi(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0)
- return 0;
- di_int s = (si_int)(fb.u & 0x80000000) >> 31;
- di_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return (r ^ s) - s;
-}
diff --git a/contrib/compiler-rt/lib/fixsfsi.c b/contrib/compiler-rt/lib/fixsfsi.c
deleted file mode 100644
index e3cc42d5255a..000000000000
--- a/contrib/compiler-rt/lib/fixsfsi.c
+++ /dev/null
@@ -1,47 +0,0 @@
-//===-- lib/fixsfsi.c - Single-precision -> integer conversion ----*- C -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements single-precision to integer conversion for the
-// compiler-rt library. No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(f2iz, fixsfsi)
-
-COMPILER_RT_ABI int
-__fixsfsi(fp_t a) {
- // Break a into sign, exponent, significand
- const rep_t aRep = toRep(a);
- const rep_t aAbs = aRep & absMask;
- const int sign = aRep & signBit ? -1 : 1;
- const int exponent = (aAbs >> significandBits) - exponentBias;
- const rep_t significand = (aAbs & significandMask) | implicitBit;
-
- // If 0 < exponent < significandBits, right shift to get the result.
- if ((unsigned int)exponent < significandBits) {
- return sign * (significand >> (significandBits - exponent));
- }
-
- // If exponent is negative, the result is zero.
- else if (exponent < 0) {
- return 0;
- }
-
- // If significandBits < exponent, left shift to get the result. This shift
- // may end up being larger than the type width, which incurs undefined
- // behavior, but the conversion itself is undefined in that case, so
- // whatever the compiler decides to do is fine.
- else {
- return sign * (significand << (exponent - significandBits));
- }
-}
diff --git a/contrib/compiler-rt/lib/fixsfti.c b/contrib/compiler-rt/lib/fixsfti.c
deleted file mode 100644
index 31c2702e3144..000000000000
--- a/contrib/compiler-rt/lib/fixsfti.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixsfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * su_int is a 32 bit integral type
- * value in float is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-ti_int
-__fixsfti(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0)
- return 0;
- ti_int s = (si_int)(fb.u & 0x80000000) >> 31;
- ti_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return (r ^ s) - s;
-}
-
-#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/fixunsdfdi.c b/contrib/compiler-rt/lib/fixunsdfdi.c
deleted file mode 100644
index 9e6371390d5c..000000000000
--- a/contrib/compiler-rt/lib/fixunsdfdi.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * du_int is a 64 bit integral type
- * value in double is representable in du_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
-
-COMPILER_RT_ABI du_int
-__fixunsdfdi(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0 || (fb.u.s.high & 0x80000000))
- return 0;
- udwords r;
- r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
- r.s.low = fb.u.s.low;
- if (e > 52)
- r.all <<= (e - 52);
- else
- r.all >>= (52 - e);
- return r.all;
-}
diff --git a/contrib/compiler-rt/lib/fixunsdfsi.c b/contrib/compiler-rt/lib/fixunsdfsi.c
deleted file mode 100644
index c6a3c755e90f..000000000000
--- a/contrib/compiler-rt/lib/fixunsdfsi.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * su_int is a 32 bit integral type
- * value in double is representable in su_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(d2uiz, fixunsdfsi)
-
-COMPILER_RT_ABI su_int
-__fixunsdfsi(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0 || (fb.u.s.high & 0x80000000))
- return 0;
- return (
- 0x80000000u |
- ((fb.u.s.high & 0x000FFFFF) << 11) |
- (fb.u.s.low >> 21)
- ) >> (31 - e);
-}
diff --git a/contrib/compiler-rt/lib/fixunsdfti.c b/contrib/compiler-rt/lib/fixunsdfti.c
deleted file mode 100644
index 76c8592687fe..000000000000
--- a/contrib/compiler-rt/lib/fixunsdfti.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * tu_int is a 64 bit integral type
- * value in double is representable in tu_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-tu_int
-__fixunsdfti(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0 || (fb.u.s.high & 0x80000000))
- return 0;
- tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL);
- if (e > 52)
- r <<= (e - 52);
- else
- r >>= (52 - e);
- return r;
-}
-
-#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/fixunssfdi.c b/contrib/compiler-rt/lib/fixunssfdi.c
deleted file mode 100644
index 69d5952e9607..000000000000
--- a/contrib/compiler-rt/lib/fixunssfdi.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * du_int is a 64 bit integral type
- * value in float is representable in du_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
-
-COMPILER_RT_ABI du_int
-__fixunssfdi(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0 || (fb.u & 0x80000000))
- return 0;
- du_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return r;
-}
diff --git a/contrib/compiler-rt/lib/fixunssfsi.c b/contrib/compiler-rt/lib/fixunssfsi.c
deleted file mode 100644
index e034139ea277..000000000000
--- a/contrib/compiler-rt/lib/fixunssfsi.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * su_int is a 32 bit integral type
- * value in float is representable in su_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(f2uiz, fixunssfsi)
-
-COMPILER_RT_ABI su_int
-__fixunssfsi(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0 || (fb.u & 0x80000000))
- return 0;
- su_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return r;
-}
diff --git a/contrib/compiler-rt/lib/fixunssfti.c b/contrib/compiler-rt/lib/fixunssfti.c
deleted file mode 100644
index 2bb18afeb5c5..000000000000
--- a/contrib/compiler-rt/lib/fixunssfti.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * tu_int is a 64 bit integral type
- * value in float is representable in tu_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-tu_int
-__fixunssfti(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0 || (fb.u & 0x80000000))
- return 0;
- tu_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return r;
-}
-
-#endif /* CRT_HAS_128BIT */
diff --git a/contrib/compiler-rt/lib/fp_lib.h b/contrib/compiler-rt/lib/fp_lib.h
deleted file mode 100644
index 661119ae412a..000000000000
--- a/contrib/compiler-rt/lib/fp_lib.h
+++ /dev/null
@@ -1,144 +0,0 @@
-//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a configuration header for soft-float routines in compiler-rt.
-// This file does not provide any part of the compiler-rt interface, but defines
-// many useful constants and utility routines that are used in the
-// implementation of the soft-float routines in compiler-rt.
-//
-// Assumes that float and double correspond to the IEEE-754 binary32 and
-// binary64 types, respectively, and that integer endianness matches floating
-// point endianness on the target platform.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FP_LIB_HEADER
-#define FP_LIB_HEADER
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <limits.h>
-#include "int_lib.h"
-
-#if defined SINGLE_PRECISION
-
-typedef uint32_t rep_t;
-typedef int32_t srep_t;
-typedef float fp_t;
-#define REP_C UINT32_C
-#define significandBits 23
-
-static inline int rep_clz(rep_t a) {
- return __builtin_clz(a);
-}
-
-// 32x32 --> 64 bit multiply
-static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
- const uint64_t product = (uint64_t)a*b;
- *hi = product >> 32;
- *lo = product;
-}
-
-#elif defined DOUBLE_PRECISION
-
-typedef uint64_t rep_t;
-typedef int64_t srep_t;
-typedef double fp_t;
-#define REP_C UINT64_C
-#define significandBits 52
-
-static inline int rep_clz(rep_t a) {
-#if defined __LP64__
- return __builtin_clzl(a);
-#else
- if (a & REP_C(0xffffffff00000000))
- return __builtin_clz(a >> 32);
- else
- return 32 + __builtin_clz(a & REP_C(0xffffffff));
-#endif
-}
-
-#define loWord(a) (a & 0xffffffffU)
-#define hiWord(a) (a >> 32)
-
-// 64x64 -> 128 wide multiply for platforms that don't have such an operation;
-// many 64-bit platforms have this operation, but they tend to have hardware
-// floating-point, so we don't bother with a special case for them here.
-static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
- // Each of the component 32x32 -> 64 products
- const uint64_t plolo = loWord(a) * loWord(b);
- const uint64_t plohi = loWord(a) * hiWord(b);
- const uint64_t philo = hiWord(a) * loWord(b);
- const uint64_t phihi = hiWord(a) * hiWord(b);
- // Sum terms that contribute to lo in a way that allows us to get the carry
- const uint64_t r0 = loWord(plolo);
- const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
- *lo = r0 + (r1 << 32);
- // Sum terms contributing to hi with the carry from lo
- *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
-}
-
-#else
-#error Either SINGLE_PRECISION or DOUBLE_PRECISION must be defined.
-#endif
-
-#define typeWidth (sizeof(rep_t)*CHAR_BIT)
-#define exponentBits (typeWidth - significandBits - 1)
-#define maxExponent ((1 << exponentBits) - 1)
-#define exponentBias (maxExponent >> 1)
-
-#define implicitBit (REP_C(1) << significandBits)
-#define significandMask (implicitBit - 1U)
-#define signBit (REP_C(1) << (significandBits + exponentBits))
-#define absMask (signBit - 1U)
-#define exponentMask (absMask ^ significandMask)
-#define oneRep ((rep_t)exponentBias << significandBits)
-#define infRep exponentMask
-#define quietBit (implicitBit >> 1)
-#define qnanRep (exponentMask | quietBit)
-
-static inline rep_t toRep(fp_t x) {
- const union { fp_t f; rep_t i; } rep = {.f = x};
- return rep.i;
-}
-
-static inline fp_t fromRep(rep_t x) {
- const union { fp_t f; rep_t i; } rep = {.i = x};
- return rep.f;
-}
-
-static inline int normalize(rep_t *significand) {
- const int shift = rep_clz(*significand) - rep_clz(implicitBit);
- *significand <<= shift;
- return 1 - shift;
-}
-
-static inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
- *hi = *hi << count | *lo >> (typeWidth - count);
- *lo = *lo << count;
-}
-
-static inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) {
- if (count < typeWidth) {
- const bool sticky = *lo << (typeWidth - count);
- *lo = *hi << (typeWidth - count) | *lo >> count | sticky;
- *hi = *hi >> count;
- }
- else if (count < 2*typeWidth) {
- const bool sticky = *hi << (2*typeWidth - count) | *lo;
- *lo = *hi >> (count - typeWidth) | sticky;
- *hi = 0;
- } else {
- const bool sticky = *hi | *lo;
- *lo = sticky;
- *hi = 0;
- }
-}
-
-#endif // FP_LIB_HEADER
diff --git a/contrib/compiler-rt/lib/interception/interception.h b/contrib/compiler-rt/lib/interception/interception.h
new file mode 100644
index 000000000000..52573258bf98
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception.h
@@ -0,0 +1,262 @@
+//===-- interception.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.
+//
+// Machinery for providing replacements/wrappers for system functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef INTERCEPTION_H
+#define INTERCEPTION_H
+
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+ !defined(__APPLE__) && !defined(_WIN32)
+# error "Interception doesn't work on this operating system."
+#endif
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+// These typedefs should be used only in the interceptor definitions to replace
+// the standard system types (e.g. SSIZE_T instead of ssize_t)
+typedef __sanitizer::uptr SIZE_T;
+typedef __sanitizer::sptr SSIZE_T;
+typedef __sanitizer::sptr PTRDIFF_T;
+typedef __sanitizer::s64 INTMAX_T;
+typedef __sanitizer::OFF_T OFF_T;
+typedef __sanitizer::OFF64_T OFF64_T;
+
+// How to add an interceptor:
+// Suppose you need to wrap/replace system function (generally, from libc):
+// int foo(const char *bar, double baz);
+// You'll need to:
+// 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
+// your source file. See the notes below for cases when
+// INTERCEPTOR_WITH_SUFFIX(...) should be used instead.
+// 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
+// INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
+// intercepted successfully.
+// You can access original function by calling REAL(foo)(bar, baz).
+// By default, REAL(foo) will be visible only inside your interceptor, and if
+// you want to use it in other parts of RTL, you'll need to:
+// 3a) add DECLARE_REAL(int, foo, const char*, double) to a
+// header file.
+// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for
+// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to:
+// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double)
+// to a header file.
+
+// Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or
+// DECLARE_REAL(...) are located inside namespaces.
+// 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to
+// effectively redirect calls from "foo" to "zoo". In this case
+// you aren't required to implement
+// INTERCEPTOR(int, foo, const char *bar, double baz) {...}
+// but instead you'll have to add
+// DECLARE_REAL(int, foo, const char *bar, double baz) in your
+// source file (to define a pointer to overriden function).
+// 3. Some Mac functions have symbol variants discriminated by
+// additional suffixes, e.g. _$UNIX2003 (see
+// https://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/index.html
+// for more details). To intercept such functions you need to use the
+// INTERCEPTOR_WITH_SUFFIX(...) macro.
+
+// How it works:
+// To replace system functions on Linux we just need to declare functions
+// with same names in our library and then obtain the real function pointers
+// using dlsym().
+// There is one complication. A user may also intercept some of the functions
+// we intercept. To resolve this we declare our interceptors with __interceptor_
+// prefix, and then make actual interceptors weak aliases to __interceptor_
+// functions.
+//
+// This is not so on Mac OS, where the two-level namespace makes
+// our replacement functions invisible to other libraries. This may be overcomed
+// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
+// libraries in Chromium were noticed when doing so.
+// Instead we create a dylib containing a __DATA,__interpose section that
+// associates library functions with their wrappers. When this dylib is
+// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
+// the calls to interposed functions done through stubs to the wrapper
+// functions.
+// As it's decided at compile time which functions are to be intercepted on Mac,
+// INTERCEPT_FUNCTION() is effectively a no-op on this system.
+
+#if defined(__APPLE__)
+#include <sys/cdefs.h> // For __DARWIN_ALIAS_C().
+
+// Just a pair of pointers.
+struct interpose_substitution {
+ const uptr replacement;
+ const uptr original;
+};
+
+// For a function foo() create a global pair of pointers { wrap_foo, foo } in
+// the __DATA,__interpose section.
+// As a result all the calls to foo() will be routed to wrap_foo() at runtime.
+#define INTERPOSER(func_name) __attribute__((used)) \
+const interpose_substitution substitution_##func_name[] \
+ __attribute__((section("__DATA, __interpose"))) = { \
+ { reinterpret_cast<const uptr>(WRAP(func_name)), \
+ reinterpret_cast<const uptr>(func_name) } \
+}
+
+// For a function foo() and a wrapper function bar() create a global pair
+// of pointers { bar, foo } in the __DATA,__interpose section.
+// As a result all the calls to foo() will be routed to bar() at runtime.
+#define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \
+const interpose_substitution substitution_##func_name[] \
+ __attribute__((section("__DATA, __interpose"))) = { \
+ { reinterpret_cast<const uptr>(wrapper_name), \
+ reinterpret_cast<const uptr>(func_name) } \
+}
+
+# define WRAP(x) wrap_##x
+# define WRAPPER_NAME(x) "wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE
+# define DECLARE_WRAPPER(ret_type, func, ...)
+
+#elif defined(_WIN32)
+# define WRAP(x) __asan_wrap_##x
+# define WRAPPER_NAME(x) "__asan_wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__);
+# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
+ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
+#elif defined(__FreeBSD__)
+# define WRAP(x) __interceptor_ ## x
+# define WRAPPER_NAME(x) "__interceptor_" #x
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+// FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
+// priority than weak ones so weak aliases won't work for indirect calls
+// in position-independent (-fPIC / -fPIE) mode.
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) \
+ __attribute__((alias("__interceptor_" #func), visibility("default")));
+#else
+# define WRAP(x) __interceptor_ ## x
+# define WRAPPER_NAME(x) "__interceptor_" #x
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) \
+ __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
+#endif
+
+#if !defined(__APPLE__)
+# define PTR_TO_REAL(x) real_##x
+# define REAL(x) __interception::PTR_TO_REAL(x)
+# define FUNC_TYPE(x) x##_f
+
+# define DECLARE_REAL(ret_type, func, ...) \
+ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ extern FUNC_TYPE(func) PTR_TO_REAL(func); \
+ }
+#else // __APPLE__
+# define REAL(x) x
+# define DECLARE_REAL(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__);
+#endif // __APPLE__
+
+#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
+ DECLARE_REAL(ret_type, func, __VA_ARGS__) \
+ extern "C" ret_type WRAP(func)(__VA_ARGS__);
+
+// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
+// macros does its job. In exceptional cases you may need to call REAL(foo)
+// without defining INTERCEPTOR(..., foo, ...). For example, if you override
+// foo with an interceptor for other function.
+#if !defined(__APPLE__)
+# define DEFINE_REAL(ret_type, func, ...) \
+ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ FUNC_TYPE(func) PTR_TO_REAL(func); \
+ }
+#else
+# define DEFINE_REAL(ret_type, func, ...)
+#endif
+
+#if !defined(__APPLE__)
+#define INTERCEPTOR(ret_type, func, ...) \
+ DEFINE_REAL(ret_type, func, __VA_ARGS__) \
+ DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
+ extern "C" \
+ INTERCEPTOR_ATTRIBUTE \
+ ret_type WRAP(func)(__VA_ARGS__)
+
+// We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now.
+#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
+ INTERCEPTOR(ret_type, func, __VA_ARGS__)
+
+#else // __APPLE__
+
+#define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) suffix; \
+ extern "C" ret_type WRAP(func)(__VA_ARGS__); \
+ INTERPOSER(func); \
+ extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__)
+
+#define INTERCEPTOR(ret_type, func, ...) \
+ INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__)
+
+#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
+ INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__)
+
+// Override |overridee| with |overrider|.
+#define OVERRIDE_FUNCTION(overridee, overrider) \
+ INTERPOSER_2(overridee, WRAP(overrider))
+#endif
+
+#if defined(_WIN32)
+# define INTERCEPTOR_WINAPI(ret_type, func, ...) \
+ typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ FUNC_TYPE(func) PTR_TO_REAL(func); \
+ } \
+ DECLARE_WRAPPER_WINAPI(ret_type, func, __VA_ARGS__) \
+ extern "C" \
+ INTERCEPTOR_ATTRIBUTE \
+ ret_type __stdcall WRAP(func)(__VA_ARGS__)
+#endif
+
+// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
+// so we use casting via an integral type __interception::uptr,
+// assuming that system is POSIX-compliant. Using other hacks seem
+// challenging, as we don't even pass function type to
+// INTERCEPT_FUNCTION macro, only its name.
+namespace __interception {
+#if defined(_WIN64)
+typedef unsigned long long uptr; // NOLINT
+#else
+typedef unsigned long uptr; // NOLINT
+#endif // _WIN64
+} // namespace __interception
+
+#define INCLUDED_FROM_INTERCEPTION_LIB
+
+#if defined(__linux__) || defined(__FreeBSD__)
+# include "interception_linux.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver)
+#elif defined(__APPLE__)
+# include "interception_mac.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_MAC(func, symver)
+#else // defined(_WIN32)
+# include "interception_win.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_WIN(func, symver)
+#endif
+
+#undef INCLUDED_FROM_INTERCEPTION_LIB
+
+#endif // INTERCEPTION_H
diff --git a/contrib/compiler-rt/lib/interception/interception_linux.cc b/contrib/compiler-rt/lib/interception/interception_linux.cc
new file mode 100644
index 000000000000..6e908ac017b2
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_linux.cc
@@ -0,0 +1,36 @@
+//===-- interception_linux.cc -----------------------------------*- 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.
+//
+// Linux-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__FreeBSD__)
+#include "interception.h"
+
+#include <dlfcn.h> // for dlsym() and dlvsym()
+
+namespace __interception {
+bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
+ uptr real, uptr wrapper) {
+ *func_addr = (uptr)dlsym(RTLD_NEXT, func_name);
+ return real == wrapper;
+}
+
+#if !defined(__ANDROID__) // android does not have dlvsym
+void *GetFuncAddrVer(const char *func_name, const char *ver) {
+ return dlvsym(RTLD_NEXT, func_name, ver);
+}
+#endif // !defined(__ANDROID__)
+
+} // namespace __interception
+
+
+#endif // __linux__ || __FreeBSD__
diff --git a/contrib/compiler-rt/lib/interception/interception_linux.h b/contrib/compiler-rt/lib/interception/interception_linux.h
new file mode 100644
index 000000000000..d3f774bede9f
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_linux.h
@@ -0,0 +1,47 @@
+//===-- interception_linux.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.
+//
+// Linux-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__FreeBSD__)
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_linux.h should be included from interception library only"
+#endif
+
+#ifndef INTERCEPTION_LINUX_H
+#define INTERCEPTION_LINUX_H
+
+namespace __interception {
+// returns true if a function with the given name was found.
+bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
+ uptr real, uptr wrapper);
+void *GetFuncAddrVer(const char *func_name, const char *ver);
+} // namespace __interception
+
+#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
+ ::__interception::GetRealFunctionAddress( \
+ #func, (::__interception::uptr *)&__interception::PTR_TO_REAL(func), \
+ (::__interception::uptr) & (func), \
+ (::__interception::uptr) & WRAP(func))
+
+#if !defined(__ANDROID__) // android does not have dlvsym
+# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ ::__interception::real_##func = (func##_f)(unsigned long) \
+ ::__interception::GetFuncAddrVer(#func, symver)
+#else
+# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
+#endif // !defined(__ANDROID__)
+
+#endif // INTERCEPTION_LINUX_H
+#endif // __linux__ || __FreeBSD__
diff --git a/contrib/compiler-rt/lib/interception/interception_mac.cc b/contrib/compiler-rt/lib/interception/interception_mac.cc
new file mode 100644
index 000000000000..b035cf998140
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_mac.cc
@@ -0,0 +1,20 @@
+//===-- interception_mac.cc -------------------------------------*- 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.
+//
+// Mac-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#include "interception.h"
+
+
+#endif // __APPLE__
diff --git a/contrib/compiler-rt/lib/interception/interception_mac.h b/contrib/compiler-rt/lib/interception/interception_mac.h
new file mode 100644
index 000000000000..e5a35c6971cd
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_mac.h
@@ -0,0 +1,28 @@
+//===-- interception_mac.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.
+//
+// Mac-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_mac.h should be included from interception.h only"
+#endif
+
+#ifndef INTERCEPTION_MAC_H
+#define INTERCEPTION_MAC_H
+
+#define INTERCEPT_FUNCTION_MAC(func)
+#define INTERCEPT_FUNCTION_VER_MAC(func, symver)
+
+#endif // INTERCEPTION_MAC_H
+#endif // __APPLE__
diff --git a/contrib/compiler-rt/lib/interception/interception_type_test.cc b/contrib/compiler-rt/lib/interception/interception_type_test.cc
new file mode 100644
index 000000000000..98ce2e6afc1b
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_type_test.cc
@@ -0,0 +1,39 @@
+//===-- interception_type_test.cc -------------------------------*- 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.
+//
+// Compile-time tests of the internal type definitions.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "interception.h"
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t));
+COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t));
+COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t));
+
+#ifndef __APPLE__
+COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t));
+#endif
+
+// The following are the cases when pread (and friends) is used instead of
+// pread64. In those cases we need OFF_T to match off_t. We don't care about the
+// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
+# if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
+ _FILE_OFFSET_BITS != 64
+COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t));
+# endif
+
+#endif
diff --git a/contrib/compiler-rt/lib/interception/interception_win.cc b/contrib/compiler-rt/lib/interception/interception_win.cc
new file mode 100644
index 000000000000..cd241c3d23c3
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_win.cc
@@ -0,0 +1,216 @@
+//===-- interception_linux.cc -----------------------------------*- 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.
+//
+// Windows-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef _WIN32
+
+#include "interception.h"
+#include <windows.h>
+
+namespace __interception {
+
+// FIXME: internal_str* and internal_mem* functions should be moved from the
+// ASan sources into interception/.
+
+static void _memset(void *p, int value, size_t sz) {
+ for (size_t i = 0; i < sz; ++i)
+ ((char*)p)[i] = (char)value;
+}
+
+static void _memcpy(void *dst, void *src, size_t sz) {
+ char *dst_c = (char*)dst,
+ *src_c = (char*)src;
+ for (size_t i = 0; i < sz; ++i)
+ dst_c[i] = src_c[i];
+}
+
+static void WriteJumpInstruction(char *jmp_from, char *to) {
+ // jmp XXYYZZWW = E9 WW ZZ YY XX, where XXYYZZWW is an offset fromt jmp_from
+ // to the next instruction to the destination.
+ ptrdiff_t offset = to - jmp_from - 5;
+ *jmp_from = '\xE9';
+ *(ptrdiff_t*)(jmp_from + 1) = offset;
+}
+
+static char *GetMemoryForTrampoline(size_t size) {
+ // Trampolines are allocated from a common pool.
+ const int POOL_SIZE = 1024;
+ static char *pool = NULL;
+ static size_t pool_used = 0;
+ if (!pool) {
+ pool = (char *)VirtualAlloc(NULL, POOL_SIZE, MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+ // FIXME: Might want to apply PAGE_EXECUTE_READ access after all the
+ // interceptors are in place.
+ if (!pool)
+ return NULL;
+ _memset(pool, 0xCC /* int 3 */, POOL_SIZE);
+ }
+
+ if (pool_used + size > POOL_SIZE)
+ return NULL;
+
+ char *ret = pool + pool_used;
+ pool_used += size;
+ return ret;
+}
+
+// Returns 0 on error.
+static size_t RoundUpToInstrBoundary(size_t size, char *code) {
+ size_t cursor = 0;
+ while (cursor < size) {
+ switch (code[cursor]) {
+ case '\x51': // push ecx
+ case '\x52': // push edx
+ case '\x53': // push ebx
+ case '\x54': // push esp
+ case '\x55': // push ebp
+ case '\x56': // push esi
+ case '\x57': // push edi
+ case '\x5D': // pop ebp
+ cursor++;
+ continue;
+ case '\x6A': // 6A XX = push XX
+ cursor += 2;
+ continue;
+ case '\xE9': // E9 XX YY ZZ WW = jmp WWZZYYXX
+ cursor += 5;
+ continue;
+ }
+ switch (*(unsigned short*)(code + cursor)) { // NOLINT
+ case 0xFF8B: // 8B FF = mov edi, edi
+ case 0xEC8B: // 8B EC = mov ebp, esp
+ case 0xC033: // 33 C0 = xor eax, eax
+ cursor += 2;
+ continue;
+ case 0x458B: // 8B 45 XX = mov eax, dword ptr [ebp+XXh]
+ case 0x5D8B: // 8B 5D XX = mov ebx, dword ptr [ebp+XXh]
+ case 0xEC83: // 83 EC XX = sub esp, XX
+ case 0x75FF: // FF 75 XX = push dword ptr [ebp+XXh]
+ cursor += 3;
+ continue;
+ case 0xC1F7: // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
+ case 0x25FF: // FF 25 XX YY ZZ WW = jmp dword ptr ds:[WWZZYYXX]
+ cursor += 6;
+ continue;
+ case 0x3D83: // 83 3D XX YY ZZ WW TT = cmp TT, WWZZYYXX
+ cursor += 7;
+ continue;
+ }
+ switch (0x00FFFFFF & *(unsigned int*)(code + cursor)) {
+ case 0x24448A: // 8A 44 24 XX = mov eal, dword ptr [esp+XXh]
+ case 0x24448B: // 8B 44 24 XX = mov eax, dword ptr [esp+XXh]
+ case 0x244C8B: // 8B 4C 24 XX = mov ecx, dword ptr [esp+XXh]
+ case 0x24548B: // 8B 54 24 XX = mov edx, dword ptr [esp+XXh]
+ case 0x24748B: // 8B 74 24 XX = mov esi, dword ptr [esp+XXh]
+ case 0x247C8B: // 8B 7C 24 XX = mov edi, dword ptr [esp+XXh]
+ cursor += 4;
+ continue;
+ }
+
+ // Unknown instruction!
+ // FIXME: Unknown instruction failures might happen when we add a new
+ // interceptor or a new compiler version. In either case, they should result
+ // in visible and readable error messages. However, merely calling abort()
+ // leads to an infinite recursion in CheckFailed.
+ // Do we have a good way to abort with an error message here?
+ __debugbreak();
+ return 0;
+ }
+
+ return cursor;
+}
+
+bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
+#ifdef _WIN64
+#error OverrideFunction is not yet supported on x64
+#endif
+ // Function overriding works basically like this:
+ // We write "jmp <new_func>" (5 bytes) at the beginning of the 'old_func'
+ // to override it.
+ // We might want to be able to execute the original 'old_func' from the
+ // wrapper, in this case we need to keep the leading 5+ bytes ('head')
+ // of the original code somewhere with a "jmp <old_func+head>".
+ // We call these 'head'+5 bytes of instructions a "trampoline".
+ char *old_bytes = (char *)old_func;
+
+ // We'll need at least 5 bytes for a 'jmp'.
+ size_t head = 5;
+ if (orig_old_func) {
+ // Find out the number of bytes of the instructions we need to copy
+ // to the trampoline and store it in 'head'.
+ head = RoundUpToInstrBoundary(head, old_bytes);
+ if (!head)
+ return false;
+
+ // Put the needed instructions into the trampoline bytes.
+ char *trampoline = GetMemoryForTrampoline(head + 5);
+ if (!trampoline)
+ return false;
+ _memcpy(trampoline, old_bytes, head);
+ WriteJumpInstruction(trampoline + head, old_bytes + head);
+ *orig_old_func = (uptr)trampoline;
+ }
+
+ // Now put the "jmp <new_func>" instruction at the original code location.
+ // We should preserve the EXECUTE flag as some of our own code might be
+ // located in the same page (sic!). FIXME: might consider putting the
+ // __interception code into a separate section or something?
+ DWORD old_prot, unused_prot;
+ if (!VirtualProtect((void *)old_bytes, head, PAGE_EXECUTE_READWRITE,
+ &old_prot))
+ return false;
+
+ WriteJumpInstruction(old_bytes, (char *)new_func);
+ _memset(old_bytes + 5, 0xCC /* int 3 */, head - 5);
+
+ // Restore the original permissions.
+ if (!VirtualProtect((void *)old_bytes, head, old_prot, &unused_prot))
+ return false; // not clear if this failure bothers us.
+
+ return true;
+}
+
+static const void **InterestingDLLsAvailable() {
+ const char *InterestingDLLs[] = {"kernel32.dll",
+ "msvcr110.dll", // VS2012
+ "msvcr120.dll", // VS2013
+ NULL};
+ static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
+ if (!result[0]) {
+ for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
+ if (HMODULE h = GetModuleHandleA(InterestingDLLs[i]))
+ result[j++] = (void *)h;
+ }
+ }
+ return (const void **)&result[0];
+}
+
+static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
+ *func_addr = 0;
+ const void **DLLs = InterestingDLLsAvailable();
+ for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
+ *func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
+ return (*func_addr != 0);
+}
+
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) {
+ uptr orig_func;
+ if (!GetFunctionAddressInDLLs(name, &orig_func))
+ return false;
+ return OverrideFunction(orig_func, new_func, orig_old_func);
+}
+
+} // namespace __interception
+
+#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/interception/interception_win.h b/contrib/compiler-rt/lib/interception/interception_win.h
new file mode 100644
index 000000000000..ba768a7233f9
--- /dev/null
+++ b/contrib/compiler-rt/lib/interception/interception_win.h
@@ -0,0 +1,50 @@
+//===-- interception_linux.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.
+//
+// Windows-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef _WIN32
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_win.h should be included from interception library only"
+#endif
+
+#ifndef INTERCEPTION_WIN_H
+#define INTERCEPTION_WIN_H
+
+namespace __interception {
+// All the functions in the OverrideFunction() family return true on success,
+// false on failure (including "couldn't find the function").
+
+// Overrides a function by its address.
+bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
+
+// Overrides a function in a system DLL or DLL CRT by its exported name.
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
+} // namespace __interception
+
+#if defined(INTERCEPTION_DYNAMIC_CRT)
+#define INTERCEPT_FUNCTION_WIN(func) \
+ ::__interception::OverrideFunction(#func, \
+ (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
+#else
+#define INTERCEPT_FUNCTION_WIN(func) \
+ ::__interception::OverrideFunction((::__interception::uptr)func, \
+ (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
+#endif
+
+#define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func)
+
+#endif // INTERCEPTION_WIN_H
+#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/lsan/lsan.cc b/contrib/compiler-rt/lib/lsan/lsan.cc
new file mode 100644
index 000000000000..6018f7bf6f49
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan.cc
@@ -0,0 +1,96 @@
+//=-- lsan.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 LeakSanitizer.
+// Standalone LSan RTL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_allocator.h"
+#include "lsan_common.h"
+#include "lsan_thread.h"
+
+bool lsan_inited;
+bool lsan_init_is_running;
+
+namespace __lsan {
+
+///// Interface to the common LSan module. /////
+bool WordIsPoisoned(uptr addr) {
+ return false;
+}
+
+} // namespace __lsan
+
+using namespace __lsan; // NOLINT
+
+static void InitializeFlags() {
+ // Set all the default values.
+ SetCommonFlagsDefaults();
+ {
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+ cf.malloc_context_size = 30;
+ cf.detect_leaks = true;
+ OverrideCommonFlags(cf);
+ }
+
+ Flags *f = flags();
+ f->SetDefaults();
+
+ FlagParser parser;
+ RegisterLsanFlags(&parser, f);
+ RegisterCommonFlags(&parser);
+
+ parser.ParseString(GetEnv("LSAN_OPTIONS"));
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+}
+
+extern "C" void __lsan_init() {
+ CHECK(!lsan_init_is_running);
+ if (lsan_inited)
+ return;
+ lsan_init_is_running = true;
+ SanitizerToolName = "LeakSanitizer";
+ InitializeFlags();
+ InitCommonLsan();
+ InitializeAllocator();
+ InitTlsSize();
+ InitializeInterceptors();
+ InitializeThreadRegistry();
+ u32 tid = ThreadCreate(0, 0, true);
+ CHECK_EQ(tid, 0);
+ ThreadStart(tid, GetTid());
+ SetCurrentThread(tid);
+
+ if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
+ Atexit(DoLeakCheck);
+
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+
+ lsan_inited = true;
+ lsan_init_is_running = false;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_STACK_TRACE_FATAL;
+ stack.Print();
+}
diff --git a/contrib/compiler-rt/lib/lsan/lsan.h b/contrib/compiler-rt/lib/lsan/lsan.h
new file mode 100644
index 000000000000..53783cdc9c7d
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan.h
@@ -0,0 +1,47 @@
+//=-- lsan.h --------------------------------------------------------------===//
+//
+// 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 LeakSanitizer.
+// Private header for standalone LSan RTL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ { \
+ uptr stack_top = 0, stack_bottom = 0; \
+ ThreadContext *t; \
+ if (fast && (t = CurrentThreadContext())) { \
+ stack_top = t->stack_end(); \
+ stack_bottom = t->stack_begin(); \
+ } \
+ stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ /* context */ 0, stack_top, stack_bottom, fast); \
+ }
+
+#define GET_STACK_TRACE_FATAL \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_MALLOC \
+ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
+ common_flags()->fast_unwind_on_malloc)
+
+namespace __lsan {
+
+void InitializeInterceptors();
+
+} // namespace __lsan
+
+extern bool lsan_inited;
+extern bool lsan_init_is_running;
+
+extern "C" void __lsan_init();
diff --git a/contrib/compiler-rt/lib/lsan/lsan_allocator.cc b/contrib/compiler-rt/lib/lsan/lsan_allocator.cc
new file mode 100644
index 000000000000..67125dbb3e45
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_allocator.cc
@@ -0,0 +1,250 @@
+//=-- lsan_allocator.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 LeakSanitizer.
+// See lsan_allocator.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_allocator.h"
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_common.h"
+
+extern "C" void *memset(void *ptr, int value, uptr num);
+
+namespace __lsan {
+
+struct ChunkMetadata {
+ bool allocated : 8; // Must be first.
+ ChunkTag tag : 2;
+ uptr requested_size : 54;
+ u32 stack_trace_id;
+};
+
+#if defined(__mips64)
+static const uptr kMaxAllowedMallocSize = 4UL << 30;
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+typedef CompactSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
+ sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
+ PrimaryAllocator;
+#else
+static const uptr kMaxAllowedMallocSize = 8UL << 30;
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
+ sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
+#endif
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static THREADLOCAL AllocatorCache cache;
+
+void InitializeAllocator() {
+ allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null);
+}
+
+void AllocatorThreadFinish() {
+ allocator.SwallowCache(&cache);
+}
+
+static ChunkMetadata *Metadata(const void *p) {
+ return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
+}
+
+static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
+ if (!p) return;
+ ChunkMetadata *m = Metadata(p);
+ CHECK(m);
+ m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
+ m->stack_trace_id = StackDepotPut(stack);
+ m->requested_size = size;
+ atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
+}
+
+static void RegisterDeallocation(void *p) {
+ if (!p) return;
+ ChunkMetadata *m = Metadata(p);
+ CHECK(m);
+ atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);
+}
+
+void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
+ bool cleared) {
+ if (size == 0)
+ size = 1;
+ if (size > kMaxAllowedMallocSize) {
+ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
+ return 0;
+ }
+ void *p = allocator.Allocate(&cache, size, alignment, false);
+ // Do not rely on the allocator to clear the memory (it's slow).
+ if (cleared && allocator.FromPrimary(p))
+ memset(p, 0, size);
+ RegisterAllocation(stack, p, size);
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
+ return p;
+}
+
+void Deallocate(void *p) {
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
+ RegisterDeallocation(p);
+ allocator.Deallocate(&cache, p);
+}
+
+void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
+ uptr alignment) {
+ RegisterDeallocation(p);
+ if (new_size > kMaxAllowedMallocSize) {
+ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
+ allocator.Deallocate(&cache, p);
+ return 0;
+ }
+ p = allocator.Reallocate(&cache, p, new_size, alignment);
+ RegisterAllocation(stack, p, new_size);
+ return p;
+}
+
+void GetAllocatorCacheRange(uptr *begin, uptr *end) {
+ *begin = (uptr)&cache;
+ *end = *begin + sizeof(cache);
+}
+
+uptr GetMallocUsableSize(const void *p) {
+ ChunkMetadata *m = Metadata(p);
+ if (!m) return 0;
+ return m->requested_size;
+}
+
+///// Interface to the common LSan module. /////
+
+void LockAllocator() {
+ allocator.ForceLock();
+}
+
+void UnlockAllocator() {
+ allocator.ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+ *begin = (uptr)&allocator;
+ *end = *begin + sizeof(allocator);
+}
+
+uptr PointsIntoChunk(void* p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ uptr chunk = reinterpret_cast<uptr>(allocator.GetBlockBeginFastLocked(p));
+ if (!chunk) return 0;
+ // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
+ // valid, but we don't want that.
+ if (addr < chunk) return 0;
+ ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
+ CHECK(m);
+ if (!m->allocated)
+ return 0;
+ if (addr < chunk + m->requested_size)
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->requested_size, addr))
+ return chunk;
+ return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+ return chunk;
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+ metadata_ = Metadata(reinterpret_cast<void *>(chunk));
+ CHECK(metadata_);
+}
+
+bool LsanMetadata::allocated() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->allocated;
+}
+
+ChunkTag LsanMetadata::tag() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->tag;
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+ reinterpret_cast<ChunkMetadata *>(metadata_)->tag = value;
+}
+
+uptr LsanMetadata::requested_size() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->requested_size;
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+ void *chunk = allocator.GetBlockBegin(p);
+ if (!chunk || p < chunk) return kIgnoreObjectInvalid;
+ ChunkMetadata *m = Metadata(chunk);
+ CHECK(m);
+ if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) {
+ if (m->tag == kIgnored)
+ return kIgnoreObjectAlreadyIgnored;
+ m->tag = kIgnored;
+ return kIgnoreObjectSuccess;
+ } else {
+ return kIgnoreObjectInvalid;
+ }
+}
+} // namespace __lsan
+
+using namespace __lsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatAllocated];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatMapped];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_free_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_unmapped_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_allocated_size(const void *p) {
+ return GetMallocUsableSize(p);
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/lsan/lsan_allocator.h b/contrib/compiler-rt/lib/lsan/lsan_allocator.h
new file mode 100644
index 000000000000..f564601193bd
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_allocator.h
@@ -0,0 +1,39 @@
+//=-- lsan_allocator.h ----------------------------------------------------===//
+//
+// 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 LeakSanitizer.
+// Allocator for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_ALLOCATOR_H
+#define LSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __lsan {
+
+void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
+ bool cleared);
+void Deallocate(void *p);
+void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
+ uptr alignment);
+uptr GetMallocUsableSize(const void *p);
+
+template<typename Callable>
+void ForEachChunk(const Callable &callback);
+
+void GetAllocatorCacheRange(uptr *begin, uptr *end);
+void AllocatorThreadFinish();
+void InitializeAllocator();
+
+} // namespace __lsan
+
+#endif // LSAN_ALLOCATOR_H
diff --git a/contrib/compiler-rt/lib/lsan/lsan_common.cc b/contrib/compiler-rt/lib/lsan/lsan_common.cc
new file mode 100644
index 000000000000..b9e2a1104326
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_common.cc
@@ -0,0 +1,688 @@
+//=-- lsan_common.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 LeakSanitizer.
+// Implementation of common leak checking functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+
+#if CAN_SANITIZE_LEAKS
+namespace __lsan {
+
+// This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and
+// also to protect the global list of root regions.
+BlockingMutex global_mutex(LINKER_INITIALIZED);
+
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+
+Flags lsan_flags;
+
+void Flags::SetDefaults() {
+#define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "lsan_flags.inc"
+#undef LSAN_FLAG
+}
+
+void RegisterLsanFlags(FlagParser *parser, Flags *f) {
+#define LSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "lsan_flags.inc"
+#undef LSAN_FLAG
+}
+
+#define LOG_POINTERS(...) \
+ do { \
+ if (flags()->log_pointers) Report(__VA_ARGS__); \
+ } while (0);
+
+#define LOG_THREADS(...) \
+ do { \
+ if (flags()->log_threads) Report(__VA_ARGS__); \
+ } while (0);
+
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kSuppressionLeak[] = "leak";
+static const char *kSuppressionTypes[] = { kSuppressionLeak };
+
+void InitializeSuppressions() {
+ CHECK_EQ(nullptr, suppression_ctx);
+ suppression_ctx = new (suppression_placeholder) // NOLINT
+ SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+ suppression_ctx->ParseFromFile(flags()->suppressions);
+ if (&__lsan_default_suppressions)
+ suppression_ctx->Parse(__lsan_default_suppressions());
+}
+
+static SuppressionContext *GetSuppressionContext() {
+ CHECK(suppression_ctx);
+ return suppression_ctx;
+}
+
+struct RootRegion {
+ const void *begin;
+ uptr size;
+};
+
+InternalMmapVector<RootRegion> *root_regions;
+
+void InitializeRootRegions() {
+ CHECK(!root_regions);
+ ALIGNED(64) static char placeholder[sizeof(InternalMmapVector<RootRegion>)];
+ root_regions = new(placeholder) InternalMmapVector<RootRegion>(1);
+}
+
+void InitCommonLsan() {
+ InitializeRootRegions();
+ if (common_flags()->detect_leaks) {
+ // Initialization which can fail or print warnings should only be done if
+ // LSan is actually enabled.
+ InitializeSuppressions();
+ InitializePlatformSpecificModules();
+ }
+}
+
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() { }
+ const char *Error() { return Red(); }
+ const char *Leak() { return Blue(); }
+ const char *End() { return Default(); }
+};
+
+static inline bool CanBeAHeapPointer(uptr p) {
+ // Since our heap is located in mmap-ed memory, we can assume a sensible lower
+ // bound on heap addresses.
+ const uptr kMinAddress = 4 * 4096;
+ if (p < kMinAddress) return false;
+#if defined(__x86_64__)
+ // Accept only canonical form user-space addresses.
+ return ((p >> 47) == 0);
+#elif defined(__mips64)
+ return ((p >> 40) == 0);
+#else
+ return true;
+#endif
+}
+
+// Scans the memory range, looking for byte patterns that point into allocator
+// chunks. Marks those chunks with |tag| and adds them to |frontier|.
+// There are two usage modes for this function: finding reachable or ignored
+// chunks (|tag| = kReachable or kIgnored) and finding indirectly leaked chunks
+// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
+// so |frontier| = 0.
+void ScanRangeForPointers(uptr begin, uptr end,
+ Frontier *frontier,
+ const char *region_type, ChunkTag tag) {
+ const uptr alignment = flags()->pointer_alignment();
+ LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, begin, end);
+ uptr pp = begin;
+ if (pp % alignment)
+ pp = pp + alignment - pp % alignment;
+ for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT
+ void *p = *reinterpret_cast<void **>(pp);
+ if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
+ uptr chunk = PointsIntoChunk(p);
+ if (!chunk) continue;
+ // Pointers to self don't count. This matters when tag == kIndirectlyLeaked.
+ if (chunk == begin) continue;
+ LsanMetadata m(chunk);
+ // Reachable beats ignored beats leaked.
+ if (m.tag() == kReachable) continue;
+ if (m.tag() == kIgnored && tag != kReachable) continue;
+
+ // Do this check relatively late so we can log only the interesting cases.
+ if (!flags()->use_poisoned && WordIsPoisoned(pp)) {
+ LOG_POINTERS(
+ "%p is poisoned: ignoring %p pointing into chunk %p-%p of size "
+ "%zu.\n",
+ pp, p, chunk, chunk + m.requested_size(), m.requested_size());
+ continue;
+ }
+
+ m.set_tag(tag);
+ LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,
+ chunk, chunk + m.requested_size(), m.requested_size());
+ if (frontier)
+ frontier->push_back(chunk);
+ }
+}
+
+void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
+ Frontier *frontier = reinterpret_cast<Frontier *>(arg);
+ ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
+}
+
+// Scans thread data (stacks and TLS) for heap pointers.
+static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
+ Frontier *frontier) {
+ InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
+ uptr registers_begin = reinterpret_cast<uptr>(registers.data());
+ uptr registers_end = registers_begin + registers.size();
+ for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
+ uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
+ LOG_THREADS("Processing thread %d.\n", os_id);
+ uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
+ bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
+ &tls_begin, &tls_end,
+ &cache_begin, &cache_end);
+ if (!thread_found) {
+ // If a thread can't be found in the thread registry, it's probably in the
+ // process of destruction. Log this event and move on.
+ LOG_THREADS("Thread %d not found in registry.\n", os_id);
+ continue;
+ }
+ uptr sp;
+ bool have_registers =
+ (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0);
+ if (!have_registers) {
+ Report("Unable to get registers from thread %d.\n");
+ // If unable to get SP, consider the entire stack to be reachable.
+ sp = stack_begin;
+ }
+
+ if (flags()->use_registers && have_registers)
+ ScanRangeForPointers(registers_begin, registers_end, frontier,
+ "REGISTERS", kReachable);
+
+ if (flags()->use_stacks) {
+ LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp);
+ if (sp < stack_begin || sp >= stack_end) {
+ // SP is outside the recorded stack range (e.g. the thread is running a
+ // signal handler on alternate stack). Again, consider the entire stack
+ // range to be reachable.
+ LOG_THREADS("WARNING: stack pointer not in stack range.\n");
+ } else {
+ // Shrink the stack range to ignore out-of-scope values.
+ stack_begin = sp;
+ }
+ ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
+ kReachable);
+ ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier);
+ }
+
+ if (flags()->use_tls) {
+ LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
+ if (cache_begin == cache_end) {
+ ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
+ } else {
+ // Because LSan should not be loaded with dlopen(), we can assume
+ // that allocator cache will be part of static TLS image.
+ CHECK_LE(tls_begin, cache_begin);
+ CHECK_GE(tls_end, cache_end);
+ if (tls_begin < cache_begin)
+ ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
+ kReachable);
+ if (tls_end > cache_end)
+ ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
+ }
+ }
+ }
+}
+
+static void ProcessRootRegion(Frontier *frontier, uptr root_begin,
+ uptr root_end) {
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr begin, end, prot;
+ while (proc_maps.Next(&begin, &end,
+ /*offset*/ 0, /*filename*/ 0, /*filename_size*/ 0,
+ &prot)) {
+ uptr intersection_begin = Max(root_begin, begin);
+ uptr intersection_end = Min(end, root_end);
+ if (intersection_begin >= intersection_end) continue;
+ bool is_readable = prot & MemoryMappingLayout::kProtectionRead;
+ LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
+ root_begin, root_end, begin, end,
+ is_readable ? "readable" : "unreadable");
+ if (is_readable)
+ ScanRangeForPointers(intersection_begin, intersection_end, frontier,
+ "ROOT", kReachable);
+ }
+}
+
+// Scans root regions for heap pointers.
+static void ProcessRootRegions(Frontier *frontier) {
+ if (!flags()->use_root_regions) return;
+ CHECK(root_regions);
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ RootRegion region = (*root_regions)[i];
+ uptr begin_addr = reinterpret_cast<uptr>(region.begin);
+ ProcessRootRegion(frontier, begin_addr, begin_addr + region.size);
+ }
+}
+
+static void FloodFillTag(Frontier *frontier, ChunkTag tag) {
+ while (frontier->size()) {
+ uptr next_chunk = frontier->back();
+ frontier->pop_back();
+ LsanMetadata m(next_chunk);
+ ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier,
+ "HEAP", tag);
+ }
+}
+
+// ForEachChunk callback. If the chunk is marked as leaked, marks all chunks
+// which are reachable from it as indirectly leaked.
+static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() != kReachable) {
+ ScanRangeForPointers(chunk, chunk + m.requested_size(),
+ /* frontier */ 0, "HEAP", kIndirectlyLeaked);
+ }
+}
+
+// ForEachChunk callback. If chunk is marked as ignored, adds its address to
+// frontier.
+static void CollectIgnoredCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() == kIgnored)
+ reinterpret_cast<Frontier *>(arg)->push_back(chunk);
+}
+
+// Sets the appropriate tag on each chunk.
+static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
+ // Holds the flood fill frontier.
+ Frontier frontier(1);
+
+ ProcessGlobalRegions(&frontier);
+ ProcessThreads(suspended_threads, &frontier);
+ ProcessRootRegions(&frontier);
+ FloodFillTag(&frontier, kReachable);
+ // The check here is relatively expensive, so we do this in a separate flood
+ // fill. That way we can skip the check for chunks that are reachable
+ // otherwise.
+ LOG_POINTERS("Processing platform-specific allocations.\n");
+ ProcessPlatformSpecificAllocations(&frontier);
+ FloodFillTag(&frontier, kReachable);
+
+ LOG_POINTERS("Scanning ignored chunks.\n");
+ CHECK_EQ(0, frontier.size());
+ ForEachChunk(CollectIgnoredCb, &frontier);
+ FloodFillTag(&frontier, kIgnored);
+
+ // Iterate over leaked chunks and mark those that are reachable from other
+ // leaked chunks.
+ LOG_POINTERS("Scanning leaked chunks.\n");
+ ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */);
+}
+
+static void PrintStackTraceById(u32 stack_trace_id) {
+ CHECK(stack_trace_id);
+ StackDepotGet(stack_trace_id).Print();
+}
+
+// ForEachChunk callback. Aggregates information about unreachable chunks into
+// a LeakReport.
+static void CollectLeaksCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (!m.allocated()) return;
+ if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
+ u32 resolution = flags()->resolution;
+ u32 stack_trace_id = 0;
+ if (resolution > 0) {
+ StackTrace stack = StackDepotGet(m.stack_trace_id());
+ stack.size = Min(stack.size, resolution);
+ stack_trace_id = StackDepotPut(stack);
+ } else {
+ stack_trace_id = m.stack_trace_id();
+ }
+ leak_report->AddLeakedChunk(chunk, stack_trace_id, m.requested_size(),
+ m.tag());
+ }
+}
+
+static void PrintMatchedSuppressions() {
+ InternalMmapVector<Suppression *> matched(1);
+ GetSuppressionContext()->GetMatched(&matched);
+ if (!matched.size())
+ return;
+ const char *line = "-----------------------------------------------------";
+ Printf("%s\n", line);
+ Printf("Suppressions used:\n");
+ Printf(" count bytes template\n");
+ for (uptr i = 0; i < matched.size(); i++)
+ Printf("%7zu %10zu %s\n", static_cast<uptr>(matched[i]->hit_count),
+ matched[i]->weight, matched[i]->templ);
+ Printf("%s\n\n", line);
+}
+
+struct DoLeakCheckParam {
+ bool success;
+ LeakReport leak_report;
+};
+
+static void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads,
+ void *arg) {
+ DoLeakCheckParam *param = reinterpret_cast<DoLeakCheckParam *>(arg);
+ CHECK(param);
+ CHECK(!param->success);
+ ClassifyAllChunks(suspended_threads);
+ ForEachChunk(CollectLeaksCb, &param->leak_report);
+ param->success = true;
+}
+
+void DoLeakCheck() {
+ EnsureMainThreadIDIsCorrect();
+ BlockingMutexLock l(&global_mutex);
+ static bool already_done;
+ if (already_done) return;
+ already_done = true;
+ if (&__lsan_is_turned_off && __lsan_is_turned_off())
+ return;
+
+ DoLeakCheckParam param;
+ param.success = false;
+ LockThreadRegistry();
+ LockAllocator();
+ StopTheWorld(DoLeakCheckCallback, &param);
+ UnlockAllocator();
+ UnlockThreadRegistry();
+
+ if (!param.success) {
+ Report("LeakSanitizer has encountered a fatal error.\n");
+ Die();
+ }
+ param.leak_report.ApplySuppressions();
+ uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
+ if (unsuppressed_count > 0) {
+ Decorator d;
+ Printf("\n"
+ "================================================================="
+ "\n");
+ Printf("%s", d.Error());
+ Report("ERROR: LeakSanitizer: detected memory leaks\n");
+ Printf("%s", d.End());
+ param.leak_report.ReportTopLeaks(flags()->max_leaks);
+ }
+ if (common_flags()->print_suppressions)
+ PrintMatchedSuppressions();
+ if (unsuppressed_count > 0) {
+ param.leak_report.PrintSummary();
+ if (flags()->exitcode) {
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+ internal__exit(flags()->exitcode);
+ }
+ }
+}
+
+static Suppression *GetSuppressionForAddr(uptr addr) {
+ Suppression *s = nullptr;
+
+ // Suppress by module name.
+ const char *module_name;
+ uptr module_offset;
+ SuppressionContext *suppressions = GetSuppressionContext();
+ if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name,
+ &module_offset) &&
+ suppressions->Match(module_name, kSuppressionLeak, &s))
+ return s;
+
+ // Suppress by file or function name.
+ SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
+ suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
+ break;
+ }
+ }
+ frames->ClearAll();
+ return s;
+}
+
+static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
+ StackTrace stack = StackDepotGet(stack_trace_id);
+ for (uptr i = 0; i < stack.size; i++) {
+ Suppression *s = GetSuppressionForAddr(
+ StackTrace::GetPreviousInstructionPc(stack.trace[i]));
+ if (s) return s;
+ }
+ return 0;
+}
+
+///// LeakReport implementation. /////
+
+// A hard limit on the number of distinct leaks, to avoid quadratic complexity
+// in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks
+// in real-world applications.
+// FIXME: Get rid of this limit by changing the implementation of LeakReport to
+// use a hash table.
+const uptr kMaxLeaksConsidered = 5000;
+
+void LeakReport::AddLeakedChunk(uptr chunk, u32 stack_trace_id,
+ uptr leaked_size, ChunkTag tag) {
+ CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
+ bool is_directly_leaked = (tag == kDirectlyLeaked);
+ uptr i;
+ for (i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].stack_trace_id == stack_trace_id &&
+ leaks_[i].is_directly_leaked == is_directly_leaked) {
+ leaks_[i].hit_count++;
+ leaks_[i].total_size += leaked_size;
+ break;
+ }
+ }
+ if (i == leaks_.size()) {
+ if (leaks_.size() == kMaxLeaksConsidered) return;
+ Leak leak = { next_id_++, /* hit_count */ 1, leaked_size, stack_trace_id,
+ is_directly_leaked, /* is_suppressed */ false };
+ leaks_.push_back(leak);
+ }
+ if (flags()->report_objects) {
+ LeakedObject obj = {leaks_[i].id, chunk, leaked_size};
+ leaked_objects_.push_back(obj);
+ }
+}
+
+static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
+ if (leak1.is_directly_leaked == leak2.is_directly_leaked)
+ return leak1.total_size > leak2.total_size;
+ else
+ return leak1.is_directly_leaked;
+}
+
+void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) {
+ CHECK(leaks_.size() <= kMaxLeaksConsidered);
+ Printf("\n");
+ if (leaks_.size() == kMaxLeaksConsidered)
+ Printf("Too many leaks! Only the first %zu leaks encountered will be "
+ "reported.\n",
+ kMaxLeaksConsidered);
+
+ uptr unsuppressed_count = UnsuppressedLeakCount();
+ if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count)
+ Printf("The %zu top leak(s):\n", num_leaks_to_report);
+ InternalSort(&leaks_, leaks_.size(), LeakComparator);
+ uptr leaks_reported = 0;
+ for (uptr i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].is_suppressed) continue;
+ PrintReportForLeak(i);
+ leaks_reported++;
+ if (leaks_reported == num_leaks_to_report) break;
+ }
+ if (leaks_reported < unsuppressed_count) {
+ uptr remaining = unsuppressed_count - leaks_reported;
+ Printf("Omitting %zu more leak(s).\n", remaining);
+ }
+}
+
+void LeakReport::PrintReportForLeak(uptr index) {
+ Decorator d;
+ Printf("%s", d.Leak());
+ Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
+ leaks_[index].is_directly_leaked ? "Direct" : "Indirect",
+ leaks_[index].total_size, leaks_[index].hit_count);
+ Printf("%s", d.End());
+
+ PrintStackTraceById(leaks_[index].stack_trace_id);
+
+ if (flags()->report_objects) {
+ Printf("Objects leaked above:\n");
+ PrintLeakedObjectsForLeak(index);
+ Printf("\n");
+ }
+}
+
+void LeakReport::PrintLeakedObjectsForLeak(uptr index) {
+ u32 leak_id = leaks_[index].id;
+ for (uptr j = 0; j < leaked_objects_.size(); j++) {
+ if (leaked_objects_[j].leak_id == leak_id)
+ Printf("%p (%zu bytes)\n", leaked_objects_[j].addr,
+ leaked_objects_[j].size);
+ }
+}
+
+void LeakReport::PrintSummary() {
+ CHECK(leaks_.size() <= kMaxLeaksConsidered);
+ uptr bytes = 0, allocations = 0;
+ for (uptr i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].is_suppressed) continue;
+ bytes += leaks_[i].total_size;
+ allocations += leaks_[i].hit_count;
+ }
+ InternalScopedString summary(kMaxSummaryLength);
+ summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
+ allocations);
+ ReportErrorSummary(summary.data());
+}
+
+void LeakReport::ApplySuppressions() {
+ for (uptr i = 0; i < leaks_.size(); i++) {
+ Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
+ if (s) {
+ s->weight += leaks_[i].total_size;
+ s->hit_count += leaks_[i].hit_count;
+ leaks_[i].is_suppressed = true;
+ }
+ }
+}
+
+uptr LeakReport::UnsuppressedLeakCount() {
+ uptr result = 0;
+ for (uptr i = 0; i < leaks_.size(); i++)
+ if (!leaks_[i].is_suppressed) result++;
+ return result;
+}
+
+} // namespace __lsan
+#endif // CAN_SANITIZE_LEAKS
+
+using namespace __lsan; // NOLINT
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_ignore_object(const void *p) {
+#if CAN_SANITIZE_LEAKS
+ if (!common_flags()->detect_leaks)
+ return;
+ // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
+ // locked.
+ BlockingMutexLock l(&global_mutex);
+ IgnoreObjectResult res = IgnoreObjectLocked(p);
+ if (res == kIgnoreObjectInvalid)
+ VReport(1, "__lsan_ignore_object(): no heap object found at %p", p);
+ if (res == kIgnoreObjectAlreadyIgnored)
+ VReport(1, "__lsan_ignore_object(): "
+ "heap object at %p is already being ignored\n", p);
+ if (res == kIgnoreObjectSuccess)
+ VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p);
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_register_root_region(const void *begin, uptr size) {
+#if CAN_SANITIZE_LEAKS
+ BlockingMutexLock l(&global_mutex);
+ CHECK(root_regions);
+ RootRegion region = {begin, size};
+ root_regions->push_back(region);
+ VReport(1, "Registered root region at %p of size %llu\n", begin, size);
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_unregister_root_region(const void *begin, uptr size) {
+#if CAN_SANITIZE_LEAKS
+ BlockingMutexLock l(&global_mutex);
+ CHECK(root_regions);
+ bool removed = false;
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ RootRegion region = (*root_regions)[i];
+ if (region.begin == begin && region.size == size) {
+ removed = true;
+ uptr last_index = root_regions->size() - 1;
+ (*root_regions)[i] = (*root_regions)[last_index];
+ root_regions->pop_back();
+ VReport(1, "Unregistered root region at %p of size %llu\n", begin, size);
+ break;
+ }
+ }
+ if (!removed) {
+ Report(
+ "__lsan_unregister_root_region(): region at %p of size %llu has not "
+ "been registered.\n",
+ begin, size);
+ Die();
+ }
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_disable() {
+#if CAN_SANITIZE_LEAKS
+ __lsan::disable_counter++;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_enable() {
+#if CAN_SANITIZE_LEAKS
+ if (!__lsan::disable_counter && common_flags()->detect_leaks) {
+ Report("Unmatched call to __lsan_enable().\n");
+ Die();
+ }
+ __lsan::disable_counter--;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_do_leak_check() {
+#if CAN_SANITIZE_LEAKS
+ if (common_flags()->detect_leaks)
+ __lsan::DoLeakCheck();
+#endif // CAN_SANITIZE_LEAKS
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __lsan_is_turned_off() {
+ return 0;
+}
+#endif
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/lsan/lsan_common.h b/contrib/compiler-rt/lib/lsan/lsan_common.h
new file mode 100644
index 000000000000..2c3a12ab6bd8
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_common.h
@@ -0,0 +1,183 @@
+//=-- lsan_common.h -------------------------------------------------------===//
+//
+// 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 LeakSanitizer.
+// Private LSan header.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_COMMON_H
+#define LSAN_COMMON_H
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips64)) \
+ && (SANITIZER_WORDSIZE == 64)
+#define CAN_SANITIZE_LEAKS 1
+#else
+#define CAN_SANITIZE_LEAKS 0
+#endif
+
+namespace __sanitizer {
+class FlagParser;
+}
+
+namespace __lsan {
+
+// Chunk tags.
+enum ChunkTag {
+ kDirectlyLeaked = 0, // default
+ kIndirectlyLeaked = 1,
+ kReachable = 2,
+ kIgnored = 3
+};
+
+struct Flags {
+#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "lsan_flags.inc"
+#undef LSAN_FLAG
+
+ void SetDefaults();
+ uptr pointer_alignment() const {
+ return use_unaligned ? 1 : sizeof(uptr);
+ }
+};
+
+extern Flags lsan_flags;
+inline Flags *flags() { return &lsan_flags; }
+void RegisterLsanFlags(FlagParser *parser, Flags *f);
+
+struct Leak {
+ u32 id;
+ uptr hit_count;
+ uptr total_size;
+ u32 stack_trace_id;
+ bool is_directly_leaked;
+ bool is_suppressed;
+};
+
+struct LeakedObject {
+ u32 leak_id;
+ uptr addr;
+ uptr size;
+};
+
+// Aggregates leaks by stack trace prefix.
+class LeakReport {
+ public:
+ LeakReport() : next_id_(0), leaks_(1), leaked_objects_(1) {}
+ void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size,
+ ChunkTag tag);
+ void ReportTopLeaks(uptr max_leaks);
+ void PrintSummary();
+ void ApplySuppressions();
+ uptr UnsuppressedLeakCount();
+
+
+ private:
+ void PrintReportForLeak(uptr index);
+ void PrintLeakedObjectsForLeak(uptr index);
+
+ u32 next_id_;
+ InternalMmapVector<Leak> leaks_;
+ InternalMmapVector<LeakedObject> leaked_objects_;
+};
+
+typedef InternalMmapVector<uptr> Frontier;
+
+// Platform-specific functions.
+void InitializePlatformSpecificModules();
+void ProcessGlobalRegions(Frontier *frontier);
+void ProcessPlatformSpecificAllocations(Frontier *frontier);
+
+void ScanRangeForPointers(uptr begin, uptr end,
+ Frontier *frontier,
+ const char *region_type, ChunkTag tag);
+
+enum IgnoreObjectResult {
+ kIgnoreObjectSuccess,
+ kIgnoreObjectAlreadyIgnored,
+ kIgnoreObjectInvalid
+};
+
+// Functions called from the parent tool.
+void InitCommonLsan();
+void DoLeakCheck();
+bool DisabledInThisThread();
+
+// Special case for "new T[0]" where T is a type with DTOR.
+// new T[0] will allocate one word for the array size (0) and store a pointer
+// to the end of allocated chunk.
+inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
+ uptr addr) {
+ return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
+ *reinterpret_cast<uptr *>(chunk_beg) == 0;
+}
+
+// The following must be implemented in the parent tool.
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg);
+// Returns the address range occupied by the global allocator object.
+void GetAllocatorGlobalRange(uptr *begin, uptr *end);
+// Wrappers for allocator's ForceLock()/ForceUnlock().
+void LockAllocator();
+void UnlockAllocator();
+// Returns true if [addr, addr + sizeof(void *)) is poisoned.
+bool WordIsPoisoned(uptr addr);
+// Wrappers for ThreadRegistry access.
+void LockThreadRegistry();
+void UnlockThreadRegistry();
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end);
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg);
+// If called from the main thread, updates the main thread's TID in the thread
+// registry. We need this to handle processes that fork() without a subsequent
+// exec(), which invalidates the recorded TID. To update it, we must call
+// gettid() from the main thread. Our solution is to call this function before
+// leak checking and also before every call to pthread_create() (to handle cases
+// where leak checking is initiated from a non-main thread).
+void EnsureMainThreadIDIsCorrect();
+// If p points into a chunk that has been allocated to the user, returns its
+// user-visible address. Otherwise, returns 0.
+uptr PointsIntoChunk(void *p);
+// Returns address of user-visible chunk contained in this allocator chunk.
+uptr GetUserBegin(uptr chunk);
+// Helper for __lsan_ignore_object().
+IgnoreObjectResult IgnoreObjectLocked(const void *p);
+// Wrapper for chunk metadata operations.
+class LsanMetadata {
+ public:
+ // Constructor accepts address of user-visible chunk.
+ explicit LsanMetadata(uptr chunk);
+ bool allocated() const;
+ ChunkTag tag() const;
+ void set_tag(ChunkTag value);
+ uptr requested_size() const;
+ u32 stack_trace_id() const;
+ private:
+ void *metadata_;
+};
+
+} // namespace __lsan
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __lsan_is_turned_off();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__lsan_default_suppressions();
+} // extern "C"
+
+#endif // LSAN_COMMON_H
diff --git a/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc b/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc
new file mode 100644
index 000000000000..ba51868c76e8
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc
@@ -0,0 +1,157 @@
+//=-- lsan_common_linux.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 LeakSanitizer.
+// Implementation of common leak checking functionality. Linux-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#include "lsan_common.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX
+#include <link.h>
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __lsan {
+
+static const char kLinkerName[] = "ld";
+// We request 2 modules matching "ld", so we can print a warning if there's more
+// than one match. But only the first one is actually used.
+static char linker_placeholder[2 * sizeof(LoadedModule)] ALIGNED(64);
+static LoadedModule *linker = 0;
+
+static bool IsLinker(const char* full_name) {
+ return LibraryNameIs(full_name, kLinkerName);
+}
+
+void InitializePlatformSpecificModules() {
+ internal_memset(linker_placeholder, 0, sizeof(linker_placeholder));
+ uptr num_matches = GetListOfModules(
+ reinterpret_cast<LoadedModule *>(linker_placeholder), 2, IsLinker);
+ if (num_matches == 1) {
+ linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
+ return;
+ }
+ if (num_matches == 0)
+ VReport(1, "LeakSanitizer: Dynamic linker not found. "
+ "TLS will not be handled correctly.\n");
+ else if (num_matches > 1)
+ VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
+ "TLS will not be handled correctly.\n", kLinkerName);
+ linker = 0;
+}
+
+static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ Frontier *frontier = reinterpret_cast<Frontier *>(data);
+ for (uptr j = 0; j < info->dlpi_phnum; j++) {
+ const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
+ // We're looking for .data and .bss sections, which reside in writeable,
+ // loadable segments.
+ if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
+ (phdr->p_memsz == 0))
+ continue;
+ uptr begin = info->dlpi_addr + phdr->p_vaddr;
+ uptr end = begin + phdr->p_memsz;
+ uptr allocator_begin = 0, allocator_end = 0;
+ GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
+ if (begin <= allocator_begin && allocator_begin < end) {
+ CHECK_LE(allocator_begin, allocator_end);
+ CHECK_LT(allocator_end, end);
+ if (begin < allocator_begin)
+ ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
+ kReachable);
+ if (allocator_end < end)
+ ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL",
+ kReachable);
+ } else {
+ ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
+ }
+ }
+ return 0;
+}
+
+// Scans global variables for heap pointers.
+void ProcessGlobalRegions(Frontier *frontier) {
+ if (!flags()->use_globals) return;
+ // FIXME: dl_iterate_phdr acquires a linker lock, so we run a risk of
+ // deadlocking by running this under StopTheWorld. However, the lock is
+ // reentrant, so we should be able to fix this by acquiring the lock before
+ // suspending threads.
+ dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
+}
+
+static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
+ CHECK(stack_id);
+ StackTrace stack = map->Get(stack_id);
+ // The top frame is our malloc/calloc/etc. The next frame is the caller.
+ if (stack.size >= 2)
+ return stack.trace[1];
+ return 0;
+}
+
+struct ProcessPlatformAllocParam {
+ Frontier *frontier;
+ StackDepotReverseMap *stack_depot_reverse_map;
+};
+
+// ForEachChunk callback. Identifies unreachable chunks which must be treated as
+// reachable. Marks them as reachable and adds them to the frontier.
+static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ ProcessPlatformAllocParam *param =
+ reinterpret_cast<ProcessPlatformAllocParam *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() != kReachable) {
+ u32 stack_id = m.stack_trace_id();
+ uptr caller_pc = 0;
+ if (stack_id > 0)
+ caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map);
+ // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
+ // it as reachable, as we can't properly report its allocation stack anyway.
+ if (caller_pc == 0 || linker->containsAddress(caller_pc)) {
+ m.set_tag(kReachable);
+ param->frontier->push_back(chunk);
+ }
+ }
+}
+
+// Handles dynamically allocated TLS blocks by treating all chunks allocated
+// from ld-linux.so as reachable.
+// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
+// They are allocated with a __libc_memalign() call in allocate_and_init()
+// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
+// blocks, but we can make sure they come from our own allocator by intercepting
+// __libc_memalign(). On top of that, there is no easy way to reach them. Their
+// addresses are stored in a dynamically allocated array (the DTV) which is
+// referenced from the static TLS. Unfortunately, we can't just rely on the DTV
+// being reachable from the static TLS, and the dynamic TLS being reachable from
+// the DTV. This is because the initial DTV is allocated before our interception
+// mechanism kicks in, and thus we don't recognize it as allocated memory. We
+// can't special-case it either, since we don't know its size.
+// Our solution is to include in the root set all allocations made from
+// ld-linux.so (which is where allocate_and_init() is implemented). This is
+// guaranteed to include all dynamic TLS blocks (and possibly other allocations
+// which we don't care about).
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {
+ if (!flags()->use_tls) return;
+ if (!linker) return;
+ StackDepotReverseMap stack_depot_reverse_map;
+ ProcessPlatformAllocParam arg = {frontier, &stack_depot_reverse_map};
+ ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg);
+}
+
+} // namespace __lsan
+#endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/lsan/lsan_flags.inc b/contrib/compiler-rt/lib/lsan/lsan_flags.inc
new file mode 100644
index 000000000000..b19b3452b2fc
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_flags.inc
@@ -0,0 +1,45 @@
+//===-- lsan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LSAN_FLAG
+# error "Define LSAN_FLAG prior to including this file!"
+#endif
+
+// LSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+LSAN_FLAG(bool, report_objects, false,
+ "Print addresses of leaked objects after main leak report.")
+LSAN_FLAG(
+ int, resolution, 0,
+ "Aggregate two objects into one leak if this many stack frames match. If "
+ "zero, the entire stack trace must match.")
+LSAN_FLAG(int, max_leaks, 0, "The number of leaks reported.")
+LSAN_FLAG(int, exitcode, 23,
+ "If nonzero kill the process with this exit code upon finding leaks.")
+
+// Flags controlling the root set of reachable memory.
+LSAN_FLAG(bool, use_globals, true,
+ "Root set: include global variables (.data and .bss)")
+LSAN_FLAG(bool, use_stacks, true, "Root set: include thread stacks")
+LSAN_FLAG(bool, use_registers, true, "Root set: include thread registers")
+LSAN_FLAG(bool, use_tls, true,
+ "Root set: include TLS and thread-specific storage")
+LSAN_FLAG(bool, use_root_regions, true,
+ "Root set: include regions added via __lsan_register_root_region().")
+
+LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.")
+LSAN_FLAG(bool, use_poisoned, false,
+ "Consider pointers found in poisoned memory to be valid.")
+LSAN_FLAG(bool, log_pointers, false, "Debug logging")
+LSAN_FLAG(bool, log_threads, false, "Debug logging")
+LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
diff --git a/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc b/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc
new file mode 100644
index 000000000000..ba2519dcb25d
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc
@@ -0,0 +1,287 @@
+//=-- lsan_interceptors.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 LeakSanitizer.
+// Interceptors for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+using namespace __lsan;
+
+extern "C" {
+int pthread_attr_init(void *attr);
+int pthread_attr_destroy(void *attr);
+int pthread_attr_getdetachstate(void *attr, int *v);
+int pthread_key_create(unsigned *key, void (*destructor)(void* v));
+int pthread_setspecific(unsigned key, const void *v);
+}
+
+#define ENSURE_LSAN_INITED do { \
+ CHECK(!lsan_init_is_running); \
+ if (!lsan_inited) \
+ __lsan_init(); \
+} while (0)
+
+///// Malloc/free interceptors. /////
+
+const bool kAlwaysClearMemory = true;
+
+namespace std {
+ struct nothrow_t;
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, 1, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, free, void *p) {
+ ENSURE_LSAN_INITED;
+ Deallocate(p);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ if (lsan_init_is_running) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const uptr kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static uptr allocated;
+ uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ size *= nmemb;
+ return Allocate(stack, size, 1, true);
+}
+
+INTERCEPTOR(void*, realloc, void *q, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Reallocate(stack, q, size, 1);
+}
+
+INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
+ // FIXME: Return ENOMEM if user requested more than max alloc size.
+ return 0;
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ if (size == 0)
+ size = GetPageSizeCached();
+ return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ ENSURE_LSAN_INITED;
+ return GetMallocUsableSize(ptr);
+}
+
+struct fake_mallinfo {
+ int x[10];
+};
+
+INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
+ struct fake_mallinfo res;
+ internal_memset(&res, 0, sizeof(res));
+ return res;
+}
+
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+
+INTERCEPTOR(void*, pvalloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
+
+#define OPERATOR_NEW_BODY \
+ ENSURE_LSAN_INITED; \
+ GET_STACK_TRACE_MALLOC; \
+ return Allocate(stack, size, 1, kAlwaysClearMemory);
+
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+ ENSURE_LSAN_INITED; \
+ Deallocate(ptr);
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const &) {
+ OPERATOR_DELETE_BODY;
+}
+
+// We need this to intercept the __libc_memalign calls that are used to
+// allocate dynamic TLS space in ld-linux.so.
+INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s)
+ ALIAS(WRAPPER_NAME(memalign));
+
+///// Thread initialization and finalization. /////
+
+static unsigned g_thread_finalize_key;
+
+static void thread_finalize(void *v) {
+ uptr iter = (uptr)v;
+ if (iter > 1) {
+ if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+ Report("LeakSanitizer: failed to set thread key.\n");
+ Die();
+ }
+ return;
+ }
+ ThreadFinish();
+}
+
+struct ThreadParam {
+ void *(*callback)(void *arg);
+ void *param;
+ atomic_uintptr_t tid;
+};
+
+extern "C" void *__lsan_thread_start_func(void *arg) {
+ ThreadParam *p = (ThreadParam*)arg;
+ void* (*callback)(void *arg) = p->callback;
+ void *param = p->param;
+ // Wait until the last iteration to maximize the chance that we are the last
+ // destructor to run.
+ if (pthread_setspecific(g_thread_finalize_key,
+ (void*)kPthreadDestructorIterations)) {
+ Report("LeakSanitizer: failed to set thread key.\n");
+ Die();
+ }
+ int tid = 0;
+ while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
+ internal_sched_yield();
+ SetCurrentThread(tid);
+ ThreadStart(tid, GetTid());
+ atomic_store(&p->tid, 0, memory_order_release);
+ return callback(param);
+}
+
+INTERCEPTOR(int, pthread_create, void *th, void *attr,
+ void *(*callback)(void *), void *param) {
+ ENSURE_LSAN_INITED;
+ EnsureMainThreadIDIsCorrect();
+ __sanitizer_pthread_attr_t myattr;
+ if (attr == 0) {
+ pthread_attr_init(&myattr);
+ attr = &myattr;
+ }
+ AdjustStackSize(attr);
+ int detached = 0;
+ pthread_attr_getdetachstate(attr, &detached);
+ ThreadParam p;
+ p.callback = callback;
+ p.param = param;
+ atomic_store(&p.tid, 0, memory_order_relaxed);
+ int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+ if (res == 0) {
+ int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
+ CHECK_NE(tid, 0);
+ atomic_store(&p.tid, tid, memory_order_release);
+ while (atomic_load(&p.tid, memory_order_acquire) != 0)
+ internal_sched_yield();
+ }
+ if (attr == &myattr)
+ pthread_attr_destroy(&myattr);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **ret) {
+ ENSURE_LSAN_INITED;
+ int tid = ThreadTid((uptr)th);
+ int res = REAL(pthread_join)(th, ret);
+ if (res == 0)
+ ThreadJoin(tid);
+ return res;
+}
+
+namespace __lsan {
+
+void InitializeInterceptors() {
+ INTERCEPT_FUNCTION(malloc);
+ INTERCEPT_FUNCTION(free);
+ INTERCEPT_FUNCTION(cfree);
+ INTERCEPT_FUNCTION(calloc);
+ INTERCEPT_FUNCTION(realloc);
+ INTERCEPT_FUNCTION(memalign);
+ INTERCEPT_FUNCTION(posix_memalign);
+ INTERCEPT_FUNCTION(__libc_memalign);
+ INTERCEPT_FUNCTION(valloc);
+ INTERCEPT_FUNCTION(pvalloc);
+ INTERCEPT_FUNCTION(malloc_usable_size);
+ INTERCEPT_FUNCTION(mallinfo);
+ INTERCEPT_FUNCTION(mallopt);
+ INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_join);
+
+ if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+ Report("LeakSanitizer: failed to create thread key.\n");
+ Die();
+ }
+}
+
+} // namespace __lsan
diff --git a/contrib/compiler-rt/lib/lsan/lsan_preinit.cc b/contrib/compiler-rt/lib/lsan/lsan_preinit.cc
new file mode 100644
index 000000000000..5a190959c15d
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_preinit.cc
@@ -0,0 +1,22 @@
+//===-- lsan_preinit.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 LeakSanitizer.
+//
+// Call __lsan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+ // We force __lsan_init to be called before anyone else by placing it into
+ // .preinit_array section.
+ __attribute__((section(".preinit_array"), used))
+ void (*__local_lsan_preinit)(void) = __lsan_init;
+#endif
diff --git a/contrib/compiler-rt/lib/lsan/lsan_thread.cc b/contrib/compiler-rt/lib/lsan/lsan_thread.cc
new file mode 100644
index 000000000000..0f8efc093b56
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_thread.cc
@@ -0,0 +1,160 @@
+//=-- lsan_thread.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 LeakSanitizer.
+// See lsan_thread.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_thread.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+#include "lsan_allocator.h"
+
+namespace __lsan {
+
+const u32 kInvalidTid = (u32) -1;
+
+static ThreadRegistry *thread_registry;
+static THREADLOCAL u32 current_thread_tid = kInvalidTid;
+
+static ThreadContextBase *CreateThreadContext(u32 tid) {
+ void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
+ return new(mem) ThreadContext(tid);
+}
+
+static const uptr kMaxThreads = 1 << 13;
+static const uptr kThreadQuarantineSize = 64;
+
+void InitializeThreadRegistry() {
+ static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64);
+ thread_registry = new(thread_registry_placeholder)
+ ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
+}
+
+u32 GetCurrentThread() {
+ return current_thread_tid;
+}
+
+void SetCurrentThread(u32 tid) {
+ current_thread_tid = tid;
+}
+
+ThreadContext::ThreadContext(int tid)
+ : ThreadContextBase(tid),
+ stack_begin_(0),
+ stack_end_(0),
+ cache_begin_(0),
+ cache_end_(0),
+ tls_begin_(0),
+ tls_end_(0) {}
+
+struct OnStartedArgs {
+ uptr stack_begin, stack_end,
+ cache_begin, cache_end,
+ tls_begin, tls_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
+ stack_begin_ = args->stack_begin;
+ stack_end_ = args->stack_end;
+ tls_begin_ = args->tls_begin;
+ tls_end_ = args->tls_end;
+ cache_begin_ = args->cache_begin;
+ cache_end_ = args->cache_end;
+}
+
+void ThreadContext::OnFinished() {
+ AllocatorThreadFinish();
+}
+
+u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
+ return thread_registry->CreateThread(user_id, detached, parent_tid,
+ /* arg */ 0);
+}
+
+void ThreadStart(u32 tid, uptr os_id) {
+ OnStartedArgs args;
+ uptr stack_size = 0;
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+ &args.tls_begin, &tls_size);
+ args.stack_end = args.stack_begin + stack_size;
+ args.tls_end = args.tls_begin + tls_size;
+ GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+ thread_registry->StartThread(tid, os_id, &args);
+}
+
+void ThreadFinish() {
+ thread_registry->FinishThread(GetCurrentThread());
+}
+
+ThreadContext *CurrentThreadContext() {
+ if (!thread_registry) return 0;
+ if (GetCurrentThread() == kInvalidTid)
+ return 0;
+ // No lock needed when getting current thread.
+ return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread());
+}
+
+static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
+ uptr uid = (uptr)arg;
+ if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+ return true;
+ }
+ return false;
+}
+
+u32 ThreadTid(uptr uid) {
+ return thread_registry->FindThread(FindThreadByUid, (void*)uid);
+}
+
+void ThreadJoin(u32 tid) {
+ CHECK_NE(tid, kInvalidTid);
+ thread_registry->JoinThread(tid, /* arg */0);
+}
+
+void EnsureMainThreadIDIsCorrect() {
+ if (GetCurrentThread() == 0)
+ CurrentThreadContext()->os_id = GetTid();
+}
+
+///// Interface to the common LSan module. /////
+
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end) {
+ ThreadContext *context = static_cast<ThreadContext *>(
+ thread_registry->FindThreadContextByOsIDLocked(os_id));
+ if (!context) return false;
+ *stack_begin = context->stack_begin();
+ *stack_end = context->stack_end();
+ *tls_begin = context->tls_begin();
+ *tls_end = context->tls_end();
+ *cache_begin = context->cache_begin();
+ *cache_end = context->cache_end();
+ return true;
+}
+
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+}
+
+void LockThreadRegistry() {
+ thread_registry->Lock();
+}
+
+void UnlockThreadRegistry() {
+ thread_registry->Unlock();
+}
+
+} // namespace __lsan
diff --git a/contrib/compiler-rt/lib/lsan/lsan_thread.h b/contrib/compiler-rt/lib/lsan/lsan_thread.h
new file mode 100644
index 000000000000..4641b32ed6e6
--- /dev/null
+++ b/contrib/compiler-rt/lib/lsan/lsan_thread.h
@@ -0,0 +1,53 @@
+//=-- lsan_thread.h -------------------------------------------------------===//
+//
+// 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 LeakSanitizer.
+// Thread registry for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_THREAD_H
+#define LSAN_THREAD_H
+
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+namespace __lsan {
+
+class ThreadContext : public ThreadContextBase {
+ public:
+ explicit ThreadContext(int tid);
+ void OnStarted(void *arg);
+ void OnFinished();
+ uptr stack_begin() { return stack_begin_; }
+ uptr stack_end() { return stack_end_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ uptr cache_begin() { return cache_begin_; }
+ uptr cache_end() { return cache_end_; }
+ private:
+ uptr stack_begin_, stack_end_,
+ cache_begin_, cache_end_,
+ tls_begin_, tls_end_;
+};
+
+void InitializeThreadRegistry();
+
+void ThreadStart(u32 tid, uptr os_id);
+void ThreadFinish();
+u32 ThreadCreate(u32 tid, uptr uid, bool detached);
+void ThreadJoin(u32 tid);
+u32 ThreadTid(uptr uid);
+
+u32 GetCurrentThread();
+void SetCurrentThread(u32 tid);
+ThreadContext *CurrentThreadContext();
+void EnsureMainThreadIDIsCorrect();
+} // namespace __lsan
+
+#endif // LSAN_THREAD_H
diff --git a/contrib/compiler-rt/lib/msan/msan.cc b/contrib/compiler-rt/lib/msan/msan.cc
new file mode 100644
index 000000000000..ed6efbdd682f
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan.cc
@@ -0,0 +1,610 @@
+//===-- msan.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 MemorySanitizer.
+//
+// MemorySanitizer runtime.
+//===----------------------------------------------------------------------===//
+
+#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
+#include "msan_poisoning.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+// ACHTUNG! No system header includes in this file.
+
+using namespace __sanitizer;
+
+// Globals.
+static THREADLOCAL int msan_expect_umr = 0;
+static THREADLOCAL int msan_expected_umr_found = 0;
+
+// Function argument shadow. Each argument starts at the next available 8-byte
+// aligned address.
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)];
+
+// Function argument origin. Each argument starts at the same offset as the
+// corresponding shadow in (__msan_param_tls). Slightly weird, but changing this
+// would break compatibility with older prebuilt binaries.
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u32 __msan_retval_origin_tls;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u32 __msan_origin_tls;
+
+static THREADLOCAL int is_in_symbolizer;
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
+
+int __msan_get_track_origins() {
+ return &__msan_track_origins ? __msan_track_origins : 0;
+}
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
+
+namespace __msan {
+
+void EnterSymbolizer() { ++is_in_symbolizer; }
+void ExitSymbolizer() { --is_in_symbolizer; }
+bool IsInSymbolizer() { return is_in_symbolizer; }
+
+static Flags msan_flags;
+
+Flags *flags() {
+ return &msan_flags;
+}
+
+int msan_inited = 0;
+bool msan_init_is_running;
+
+int msan_report_count = 0;
+
+void (*death_callback)(void);
+
+// Array of stack origins.
+// FIXME: make it resizable.
+static const uptr kNumStackOriginDescrs = 1024 * 1024;
+static const char *StackOriginDescr[kNumStackOriginDescrs];
+static uptr StackOriginPC[kNumStackOriginDescrs];
+static atomic_uint32_t NumStackOriginDescrs;
+
+void Flags::SetDefaults() {
+#define MSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "msan_flags.inc"
+#undef MSAN_FLAG
+}
+
+// keep_going is an old name for halt_on_error,
+// and it has inverse meaning.
+class FlagHandlerKeepGoing : public FlagHandlerBase {
+ bool *halt_on_error_;
+
+ public:
+ explicit FlagHandlerKeepGoing(bool *halt_on_error)
+ : halt_on_error_(halt_on_error) {}
+ bool Parse(const char *value) final {
+ bool tmp;
+ FlagHandler<bool> h(&tmp);
+ if (!h.Parse(value)) return false;
+ *halt_on_error_ = !tmp;
+ return true;
+ }
+};
+
+static void RegisterMsanFlags(FlagParser *parser, Flags *f) {
+#define MSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "msan_flags.inc"
+#undef MSAN_FLAG
+
+ FlagHandlerKeepGoing *fh_keep_going = new (FlagParser::Alloc) // NOLINT
+ FlagHandlerKeepGoing(&f->halt_on_error);
+ parser->RegisterHandler("keep_going", fh_keep_going,
+ "deprecated, use halt_on_error");
+}
+
+static void InitializeFlags() {
+ Flags *f = flags();
+ FlagParser parser;
+ RegisterMsanFlags(&parser, f);
+ RegisterCommonFlags(&parser);
+
+ SetCommonFlagsDefaults();
+ {
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
+ cf.malloc_context_size = 20;
+ cf.handle_ioctl = true;
+ // FIXME: test and enable.
+ cf.check_printf = false;
+ cf.intercept_tls_get_addr = true;
+ OverrideCommonFlags(cf);
+ }
+
+ f->SetDefaults();
+
+ // Override from user-specified string.
+ if (__msan_default_options)
+ parser.ParseString(__msan_default_options());
+
+ const char *msan_options = GetEnv("MSAN_OPTIONS");
+ parser.ParseString(msan_options);
+ VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+
+ // Check flag values:
+ if (f->exit_code < 0 || f->exit_code > 127) {
+ Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
+ Die();
+ }
+ if (f->origin_history_size < 0 ||
+ f->origin_history_size > Origin::kMaxDepth) {
+ Printf(
+ "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] "
+ "range.\n",
+ f->origin_history_size, Origin::kMaxDepth);
+ Die();
+ }
+ // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in
+ // StackDepotHandle::inc_use_count_unsafe.
+ if (f->origin_history_per_stack_limit < 0 ||
+ f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) {
+ Printf(
+ "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, "
+ "%d] range.\n",
+ f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2);
+ Die();
+ }
+ if (f->store_context_size < 1) f->store_context_size = 1;
+}
+
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
+ bool request_fast_unwind) {
+ MsanThread *t = GetCurrentThread();
+ if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
+ // Block reports from our interceptors during _Unwind_Backtrace.
+ SymbolizerScope sym_scope;
+ return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind);
+ }
+ stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(),
+ request_fast_unwind);
+}
+
+void PrintWarning(uptr pc, uptr bp) {
+ PrintWarningWithOrigin(pc, bp, __msan_origin_tls);
+}
+
+void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
+ if (msan_expect_umr) {
+ // Printf("Expected UMR\n");
+ __msan_origin_tls = origin;
+ msan_expected_umr_found = 1;
+ return;
+ }
+
+ ++msan_report_count;
+
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
+
+ u32 report_origin =
+ (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0;
+ ReportUMR(&stack, report_origin);
+
+ if (__msan_get_track_origins() && !Origin::isValidId(origin)) {
+ Printf(
+ " ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin "
+ "tracking.\n This could still be a bug in your code, too!\n",
+ origin);
+ }
+}
+
+void UnpoisonParam(uptr n) {
+ internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
+}
+
+// Backup MSan runtime TLS state.
+// Implementation must be async-signal-safe.
+// Instances of this class may live on the signal handler stack, and data size
+// may be an issue.
+void ScopedThreadLocalStateBackup::Backup() {
+ va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls;
+}
+
+void ScopedThreadLocalStateBackup::Restore() {
+ // A lame implementation that only keeps essential state and resets the rest.
+ __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls;
+
+ internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls));
+ internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
+
+ if (__msan_get_track_origins()) {
+ internal_memset(&__msan_retval_origin_tls, 0,
+ sizeof(__msan_retval_origin_tls));
+ internal_memset(__msan_param_origin_tls, 0,
+ sizeof(__msan_param_origin_tls));
+ }
+}
+
+void UnpoisonThreadLocalState() {
+}
+
+const char *GetStackOriginDescr(u32 id, uptr *pc) {
+ CHECK_LT(id, kNumStackOriginDescrs);
+ if (pc) *pc = StackOriginPC[id];
+ return StackOriginDescr[id];
+}
+
+u32 ChainOrigin(u32 id, StackTrace *stack) {
+ MsanThread *t = GetCurrentThread();
+ if (t && t->InSignalHandler())
+ return id;
+
+ Origin o = Origin::FromRawId(id);
+ stack->tag = StackTrace::TAG_UNKNOWN;
+ Origin chained = Origin::CreateChainedOrigin(o, stack);
+ return chained.raw_id();
+}
+
+} // namespace __msan
+
+// Interface.
+
+using namespace __msan;
+
+#define MSAN_MAYBE_WARNING(type, size) \
+ void __msan_maybe_warning_##size(type s, u32 o) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ if (UNLIKELY(s)) { \
+ PrintWarningWithOrigin(pc, bp, o); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
+ }
+
+MSAN_MAYBE_WARNING(u8, 1)
+MSAN_MAYBE_WARNING(u16, 2)
+MSAN_MAYBE_WARNING(u32, 4)
+MSAN_MAYBE_WARNING(u64, 8)
+
+#define MSAN_MAYBE_STORE_ORIGIN(type, size) \
+ void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \
+ if (UNLIKELY(s)) { \
+ if (__msan_get_track_origins() > 1) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
+ o = ChainOrigin(o, &stack); \
+ } \
+ *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \
+ } \
+ }
+
+MSAN_MAYBE_STORE_ORIGIN(u8, 1)
+MSAN_MAYBE_STORE_ORIGIN(u16, 2)
+MSAN_MAYBE_STORE_ORIGIN(u32, 4)
+MSAN_MAYBE_STORE_ORIGIN(u64, 8)
+
+void __msan_warning() {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ PrintWarning(pc, bp);
+ if (__msan::flags()->halt_on_error) {
+ if (__msan::flags()->print_stats)
+ ReportStats();
+ Printf("Exiting\n");
+ Die();
+ }
+}
+
+void __msan_warning_noreturn() {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ PrintWarning(pc, bp);
+ if (__msan::flags()->print_stats)
+ ReportStats();
+ Printf("Exiting\n");
+ Die();
+}
+
+void __msan_init() {
+ CHECK(!msan_init_is_running);
+ if (msan_inited) return;
+ msan_init_is_running = 1;
+ SanitizerToolName = "MemorySanitizer";
+
+ SetDieCallback(MsanDie);
+ InitTlsSize();
+
+ InitializeFlags();
+ __sanitizer_set_report_path(common_flags()->log_path);
+
+ InitializeInterceptors();
+ InstallAtExitHandler(); // Needs __cxa_atexit interceptor.
+
+ if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
+ ReplaceOperatorsNewAndDelete();
+ DisableCoreDumperIfNecessary();
+ if (StackSizeIsUnlimited()) {
+ VPrintf(1, "Unlimited stack, doing reexec\n");
+ // A reasonably large stack size. It is bigger than the usual 8Mb, because,
+ // well, the program could have been run with unlimited stack for a reason.
+ SetStackSizeLimitInBytes(32 * 1024 * 1024);
+ ReExec();
+ }
+
+ __msan_clear_on_return();
+ if (__msan_get_track_origins())
+ VPrintf(1, "msan_track_origins\n");
+ if (!InitShadow(/* map_shadow */ true, __msan_get_track_origins())) {
+ Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
+ Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
+ Printf("FATAL: Disabling ASLR is known to cause this error.\n");
+ Printf("FATAL: If running under GDB, try "
+ "'set disable-randomization off'.\n");
+ DumpProcessMap();
+ Die();
+ }
+
+ Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+
+ MsanTSDInit(MsanTSDDtor);
+
+ MsanThread *main_thread = MsanThread::Create(0, 0);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart();
+
+ VPrintf(1, "MemorySanitizer init done\n");
+
+ msan_init_is_running = 0;
+ msan_inited = 1;
+}
+
+void __msan_set_exit_code(int exit_code) {
+ flags()->exit_code = exit_code;
+}
+
+void __msan_set_keep_going(int keep_going) {
+ flags()->halt_on_error = !keep_going;
+}
+
+void __msan_set_expect_umr(int expect_umr) {
+ if (expect_umr) {
+ msan_expected_umr_found = 0;
+ } else if (!msan_expected_umr_found) {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
+ ReportExpectedUMRNotFound(&stack);
+ Die();
+ }
+ msan_expect_umr = expect_umr;
+}
+
+void __msan_print_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) {
+ Printf("Not a valid application address: %p\n", x);
+ return;
+ }
+
+ DescribeMemoryRange(x, size);
+}
+
+void __msan_dump_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) {
+ Printf("Not a valid application address: %p\n", x);
+ return;
+ }
+
+ unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x);
+ for (uptr i = 0; i < size; i++) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x ", s[i] & 0xf, s[i] >> 4);
+#else
+ Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
+#endif
+ }
+ Printf("\n");
+}
+
+sptr __msan_test_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) return -1;
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i])
+ return i;
+ return -1;
+}
+
+void __msan_check_mem_is_initialized(const void *x, uptr size) {
+ if (!__msan::flags()->report_umrs) return;
+ sptr offset = __msan_test_shadow(x, size);
+ if (offset < 0)
+ return;
+
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ ReportUMRInsideAddressRange(__func__, x, size, offset);
+ __msan::PrintWarningWithOrigin(pc, bp,
+ __msan_get_origin(((const char *)x) + offset));
+ if (__msan::flags()->halt_on_error) {
+ Printf("Exiting\n");
+ Die();
+ }
+}
+
+int __msan_set_poison_in_malloc(int do_poison) {
+ int old = flags()->poison_in_malloc;
+ flags()->poison_in_malloc = do_poison;
+ return old;
+}
+
+int __msan_has_dynamic_component() { return false; }
+
+NOINLINE
+void __msan_clear_on_return() {
+ __msan_param_tls[0] = 0;
+}
+
+void __msan_partial_poison(const void* data, void* shadow, uptr size) {
+ internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
+}
+
+void __msan_load_unpoisoned(void *src, uptr size, void *dst) {
+ internal_memcpy(dst, src, size);
+ __msan_unpoison(dst, size);
+}
+
+void __msan_set_origin(const void *a, uptr size, u32 origin) {
+ if (__msan_get_track_origins()) SetOrigin(a, size, origin);
+}
+
+// 'descr' is created at compile time and contains '----' in the beginning.
+// When we see descr for the first time we replace '----' with a uniq id
+// and set the origin to (id | (31-th bit)).
+void __msan_set_alloca_origin(void *a, uptr size, char *descr) {
+ __msan_set_alloca_origin4(a, size, descr, 0);
+}
+
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) {
+ static const u32 dash = '-';
+ static const u32 first_timer =
+ dash + (dash << 8) + (dash << 16) + (dash << 24);
+ u32 *id_ptr = (u32*)descr;
+ bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0;
+ u32 id = *id_ptr;
+ if (id == first_timer) {
+ u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed);
+ CHECK_LT(idx, kNumStackOriginDescrs);
+ StackOriginDescr[idx] = descr + 4;
+ StackOriginPC[idx] = pc;
+ id = Origin::CreateStackOrigin(idx).raw_id();
+ *id_ptr = id;
+ if (print)
+ Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc);
+ }
+ if (print)
+ Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id);
+ __msan_set_origin(a, size, id);
+}
+
+u32 __msan_chain_origin(u32 id) {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp);
+ return ChainOrigin(id, &stack);
+}
+
+u32 __msan_get_origin(const void *a) {
+ if (!__msan_get_track_origins()) return 0;
+ uptr x = (uptr)a;
+ uptr aligned = x & ~3ULL;
+ uptr origin_ptr = MEM_TO_ORIGIN(aligned);
+ return *(u32*)origin_ptr;
+}
+
+u32 __msan_get_umr_origin() {
+ return __msan_origin_tls;
+}
+
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+ __msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
+ return *p;
+}
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+ __msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
+ return *p;
+}
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+ __msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
+ return *p;
+}
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+ u16 s = __msan_param_tls[1];
+ *(uu16 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
+ *p = x;
+}
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+ u32 s = __msan_param_tls[1];
+ *(uu32 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
+ *p = x;
+}
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+ u64 s = __msan_param_tls[1];
+ *(uu64 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
+ *p = x;
+}
+
+void __msan_set_death_callback(void (*callback)(void)) {
+ death_callback = callback;
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char* __msan_default_options() { return ""; }
+} // extern "C"
+#endif
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
+ stack.Print();
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/msan/msan.h b/contrib/compiler-rt/lib/msan/msan.h
new file mode 100644
index 000000000000..ed18f21d0282
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan.h
@@ -0,0 +1,218 @@
+//===-- msan.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 MemorySanitizer.
+//
+// Private MSan header.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_H
+#define MSAN_H
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "msan_interface_internal.h"
+#include "msan_flags.h"
+
+#ifndef MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
+# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
+#endif
+
+struct MappingDesc {
+ uptr start;
+ uptr end;
+ enum Type {
+ INVALID, APP, SHADOW, ORIGIN
+ } type;
+ const char *name;
+};
+
+
+#if SANITIZER_LINUX && defined(__mips64)
+
+// Everything is above 0x00e000000000.
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x00a000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x00a000000000ULL, 0x00c000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x00c000000000ULL, 0x00e000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x00e000000000ULL, 0x010000000000ULL, MappingDesc::APP, "app"}};
+
+#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x002000000000)
+
+#elif SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 64
+
+// Low memory: main binary, MAP_32BIT mappings and modules
+// High memory: heap, modules and main thread stack
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "low memory"},
+ {0x010000000000ULL, 0x100000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x100000000000ULL, 0x310000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x310000000000ULL, 0x380000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x380000000000ULL, 0x590000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x590000000000ULL, 0x600000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x600000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}};
+
+// Maps low and high app ranges to contiguous space with zero base:
+// Low: 0000 0000 0000 - 00ff ffff ffff -> 2000 0000 0000 - 20ff ffff ffff
+// High: 6000 0000 0000 - 7fff ffff ffff -> 0000 0000 0000 - 1fff ffff ffff
+#define LINEARIZE_MEM(mem) \
+ (((uptr)(mem) & ~0xc00000000000ULL) ^ 0x200000000000ULL)
+#define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x100000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x280000000000)
+
+#elif SANITIZER_LINUX && SANITIZER_WORDSIZE == 64
+
+// Requries PIE binary and ASLR enabled.
+// Main thread stack and DSOs at 0x7f0000000000 (sometimes 0x7e0000000000).
+// Heap at 0x600000000000.
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x200000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x200000000000ULL, 0x400000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x400000000000ULL, 0x600000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x600000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app"}};
+
+#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL)
+#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x200000000000ULL)
+
+#else
+#error "Unsupported platform"
+#endif
+
+const uptr kMemoryLayoutSize = sizeof(kMemoryLayout) / sizeof(kMemoryLayout[0]);
+
+#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW((mem))))
+
+#ifndef __clang__
+__attribute__((optimize("unroll-loops")))
+#endif
+inline bool addr_is_type(uptr addr, MappingDesc::Type mapping_type) {
+// It is critical for performance that this loop is unrolled (because then it is
+// simplified into just a few constant comparisons).
+#ifdef __clang__
+#pragma unroll
+#endif
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
+ if (kMemoryLayout[i].type == mapping_type &&
+ addr >= kMemoryLayout[i].start && addr < kMemoryLayout[i].end)
+ return true;
+ return false;
+}
+
+#define MEM_IS_APP(mem) addr_is_type((uptr)(mem), MappingDesc::APP)
+#define MEM_IS_SHADOW(mem) addr_is_type((uptr)(mem), MappingDesc::SHADOW)
+#define MEM_IS_ORIGIN(mem) addr_is_type((uptr)(mem), MappingDesc::ORIGIN)
+
+// These constants must be kept in sync with the ones in MemorySanitizer.cc.
+const int kMsanParamTlsSize = 800;
+const int kMsanRetvalTlsSize = 800;
+
+namespace __msan {
+extern int msan_inited;
+extern bool msan_init_is_running;
+extern int msan_report_count;
+
+bool ProtectRange(uptr beg, uptr end);
+bool InitShadow(bool map_shadow, bool init_origins);
+char *GetProcSelfMaps();
+void InitializeInterceptors();
+
+void MsanAllocatorThreadFinish();
+void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size);
+void *MsanReallocate(StackTrace *stack, void *oldp, uptr size,
+ uptr alignment, bool zeroise);
+void MsanDeallocate(StackTrace *stack, void *ptr);
+void InstallTrapHandler();
+void InstallAtExitHandler();
+void ReplaceOperatorsNewAndDelete();
+
+const char *GetStackOriginDescr(u32 id, uptr *pc);
+
+void EnterSymbolizer();
+void ExitSymbolizer();
+bool IsInSymbolizer();
+
+struct SymbolizerScope {
+ SymbolizerScope() { EnterSymbolizer(); }
+ ~SymbolizerScope() { ExitSymbolizer(); }
+};
+
+void MsanDie();
+void PrintWarning(uptr pc, uptr bp);
+void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
+
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
+ bool request_fast_unwind);
+
+void ReportUMR(StackTrace *stack, u32 origin);
+void ReportExpectedUMRNotFound(StackTrace *stack);
+void ReportStats();
+void ReportAtExitStatistics();
+void DescribeMemoryRange(const void *x, uptr size);
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset);
+
+// Unpoison first n function arguments.
+void UnpoisonParam(uptr n);
+void UnpoisonThreadLocalState();
+
+// Returns a "chained" origin id, pointing to the given stack trace followed by
+// the previous origin id.
+u32 ChainOrigin(u32 id, StackTrace *stack);
+
+const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;
+
+#define GET_MALLOC_STACK_TRACE \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() && msan_inited) \
+ GetStackTrace(&stack, common_flags()->malloc_context_size, \
+ StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() > 1 && msan_inited) \
+ GetStackTrace(&stack, flags()->store_context_size, pc, bp, \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (msan_inited) \
+ GetStackTrace(&stack, kStackTraceMax, pc, bp, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STORE_STACK_TRACE \
+ GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
+
+class ScopedThreadLocalStateBackup {
+ public:
+ ScopedThreadLocalStateBackup() { Backup(); }
+ ~ScopedThreadLocalStateBackup() { Restore(); }
+ void Backup();
+ void Restore();
+ private:
+ u64 va_arg_overflow_size_tls;
+};
+
+extern void (*death_callback)(void);
+
+void MsanTSDInit(void (*destructor)(void *tsd));
+void *MsanTSDGet();
+void MsanTSDSet(void *tsd);
+void MsanTSDDtor(void *tsd);
+
+} // namespace __msan
+
+#define MSAN_MALLOC_HOOK(ptr, size) \
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
+#define MSAN_FREE_HOOK(ptr) \
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
+
+#endif // MSAN_H
diff --git a/contrib/compiler-rt/lib/msan/msan.syms.extra b/contrib/compiler-rt/lib/msan/msan.syms.extra
new file mode 100644
index 000000000000..aad41cf1124e
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan.syms.extra
@@ -0,0 +1 @@
+__msan_*
diff --git a/contrib/compiler-rt/lib/msan/msan_allocator.cc b/contrib/compiler-rt/lib/msan/msan_allocator.cc
new file mode 100644
index 000000000000..698b6cddd30b
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_allocator.cc
@@ -0,0 +1,227 @@
+//===-- msan_allocator.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 MemorySanitizer.
+//
+// MemorySanitizer allocator.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "msan.h"
+#include "msan_allocator.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
+#include "msan_poisoning.h"
+
+namespace __msan {
+
+struct Metadata {
+ uptr requested_size;
+};
+
+struct MsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const {}
+ void OnUnmap(uptr p, uptr size) const {
+ __msan_unpoison((void *)p, size);
+
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededShadowMemory(MEM_TO_SHADOW(p), size);
+ if (__msan_get_track_origins())
+ FlushUnneededShadowMemory(MEM_TO_ORIGIN(p), size);
+ }
+};
+
+#if defined(__mips64)
+ static const uptr kMaxAllowedMallocSize = 2UL << 30;
+ static const uptr kRegionSizeLog = 20;
+ static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+ typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+ typedef CompactSizeClassMap SizeClassMap;
+
+ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+ SizeClassMap, kRegionSizeLog, ByteMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+#elif defined(__x86_64__)
+ static const uptr kAllocatorSpace = 0x600000000000ULL;
+ static const uptr kAllocatorSize = 0x80000000000; // 8T.
+ static const uptr kMetadataSize = sizeof(Metadata);
+ static const uptr kMaxAllowedMallocSize = 8UL << 30;
+
+ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
+ DefaultSizeClassMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+#endif
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static AllocatorCache fallback_allocator_cache;
+static SpinMutex fallback_mutex;
+
+static int inited = 0;
+
+static inline void Init() {
+ if (inited) return;
+ __msan_init();
+ inited = true; // this must happen before any threads are created.
+ allocator.Init(common_flags()->allocator_may_return_null);
+}
+
+AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
+ return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
+}
+
+void MsanThreadLocalMallocStorage::CommitBack() {
+ allocator.SwallowCache(GetAllocatorCache(this));
+}
+
+static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
+ bool zeroise) {
+ Init();
+ if (size > kMaxAllowedMallocSize) {
+ Report("WARNING: MemorySanitizer failed to allocate %p bytes\n",
+ (void *)size);
+ return allocator.ReturnNullOrDie();
+ }
+ MsanThread *t = GetCurrentThread();
+ void *allocated;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ }
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
+ meta->requested_size = size;
+ if (zeroise) {
+ __msan_clear_and_unpoison(allocated, size);
+ } else if (flags()->poison_in_malloc) {
+ __msan_poison(allocated, size);
+ if (__msan_get_track_origins()) {
+ stack->tag = StackTrace::TAG_ALLOC;
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(allocated, size, o.raw_id());
+ }
+ }
+ MSAN_MALLOC_HOOK(allocated, size);
+ return allocated;
+}
+
+void MsanDeallocate(StackTrace *stack, void *p) {
+ CHECK(p);
+ Init();
+ MSAN_FREE_HOOK(p);
+ Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
+ uptr size = meta->requested_size;
+ meta->requested_size = 0;
+ // This memory will not be reused by anyone else, so we are free to keep it
+ // poisoned.
+ if (flags()->poison_in_free) {
+ __msan_poison(p, size);
+ if (__msan_get_track_origins()) {
+ stack->tag = StackTrace::TAG_DEALLOC;
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(p, size, o.raw_id());
+ }
+ }
+ MsanThread *t = GetCurrentThread();
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocator.Deallocate(cache, p);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocator.Deallocate(cache, p);
+ }
+}
+
+void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
+ Init();
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return allocator.ReturnNullOrDie();
+ return MsanReallocate(stack, 0, nmemb * size, sizeof(u64), true);
+}
+
+void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
+ uptr alignment, bool zeroise) {
+ if (!old_p)
+ return MsanAllocate(stack, new_size, alignment, zeroise);
+ if (!new_size) {
+ MsanDeallocate(stack, old_p);
+ return 0;
+ }
+ Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
+ uptr old_size = meta->requested_size;
+ uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p);
+ if (new_size <= actually_allocated_size) {
+ // We are not reallocating here.
+ meta->requested_size = new_size;
+ if (new_size > old_size) {
+ if (zeroise) {
+ __msan_clear_and_unpoison((char *)old_p + old_size,
+ new_size - old_size);
+ } else if (flags()->poison_in_malloc) {
+ stack->tag = StackTrace::TAG_ALLOC;
+ PoisonMemory((char *)old_p + old_size, new_size - old_size, stack);
+ }
+ }
+ return old_p;
+ }
+ uptr memcpy_size = Min(new_size, old_size);
+ void *new_p = MsanAllocate(stack, new_size, alignment, zeroise);
+ // Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size);
+ if (new_p) {
+ CopyMemory(new_p, old_p, memcpy_size, stack);
+ MsanDeallocate(stack, old_p);
+ }
+ return new_p;
+}
+
+static uptr AllocationSize(const void *p) {
+ if (p == 0) return 0;
+ const void *beg = allocator.GetBlockBegin(p);
+ if (beg != p) return 0;
+ Metadata *b = (Metadata *)allocator.GetMetaData(p);
+ return b->requested_size;
+}
+
+} // namespace __msan
+
+using namespace __msan;
+
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatAllocated];
+}
+
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatMapped];
+}
+
+uptr __sanitizer_get_free_bytes() { return 1; }
+
+uptr __sanitizer_get_unmapped_bytes() { return 1; }
+
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
+
+int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
+
+uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/contrib/compiler-rt/lib/msan/msan_allocator.h b/contrib/compiler-rt/lib/msan/msan_allocator.h
new file mode 100644
index 000000000000..407942e54c1a
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_allocator.h
@@ -0,0 +1,33 @@
+//===-- msan_allocator.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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_ALLOCATOR_H
+#define MSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+struct MsanThreadLocalMallocStorage {
+ uptr quarantine_cache[16];
+ // Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
+ ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque.
+ void CommitBack();
+
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ MsanThreadLocalMallocStorage() {}
+};
+
+} // namespace __msan
+#endif // MSAN_ALLOCATOR_H
diff --git a/contrib/compiler-rt/lib/msan/msan_blacklist.txt b/contrib/compiler-rt/lib/msan/msan_blacklist.txt
new file mode 100644
index 000000000000..44a5680d4d06
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_blacklist.txt
@@ -0,0 +1,7 @@
+# Blacklist for MemorySanitizer. Turns off instrumentation of particular
+# functions or sources. Use with care. You may set location of blacklist
+# at compile-time using -fsanitize-blacklist=<path> flag.
+
+# Example usage:
+# fun:*bad_function_name*
+# src:file_with_tricky_code.cc
diff --git a/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc
new file mode 100644
index 000000000000..c21e8e82746a
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc
@@ -0,0 +1,126 @@
+//===-- msan_chained_origin_depot.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+
+#include "msan_chained_origin_depot.h"
+
+#include "sanitizer_common/sanitizer_stackdepotbase.h"
+
+namespace __msan {
+
+struct ChainedOriginDepotDesc {
+ u32 here_id;
+ u32 prev_id;
+};
+
+struct ChainedOriginDepotNode {
+ ChainedOriginDepotNode *link;
+ u32 id;
+ u32 here_id;
+ u32 prev_id;
+
+ typedef ChainedOriginDepotDesc args_type;
+ bool eq(u32 hash, const args_type &args) const {
+ return here_id == args.here_id && prev_id == args.prev_id;
+ }
+ static uptr storage_size(const args_type &args) {
+ return sizeof(ChainedOriginDepotNode);
+ }
+ /* This is murmur2 hash for the 64->32 bit case.
+ It does not behave all that well because the keys have a very biased
+ distribution (I've seen 7-element buckets with the table only 14% full).
+
+ here_id is built of
+ * (1 bits) Reserved, zero.
+ * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+ * (23 bits) Sequential number (each part has each own sequence).
+
+ prev_id has either the same distribution as here_id (but with 3:8:21)
+ split, or one of two reserved values (-1) or (-2). Either case can
+ dominate depending on the workload.
+ */
+ static u32 hash(const args_type &args) {
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed;
+ u32 k = args.here_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ k = args.prev_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+ }
+ static bool is_valid(const args_type &args) { return true; }
+ void store(const args_type &args, u32 other_hash) {
+ here_id = args.here_id;
+ prev_id = args.prev_id;
+ }
+ args_type load() const {
+ args_type ret = {here_id, prev_id};
+ return ret;
+ }
+ struct Handle {
+ ChainedOriginDepotNode *node_;
+ Handle() : node_(0) {}
+ explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
+ bool valid() { return node_; }
+ u32 id() { return node_->id; }
+ int here_id() { return node_->here_id; }
+ int prev_id() { return node_->prev_id; }
+ };
+ Handle get_handle() { return Handle(this); }
+
+ typedef Handle handle_type;
+};
+
+static StackDepotBase<ChainedOriginDepotNode, 4, 20> chainedOriginDepot;
+
+StackDepotStats *ChainedOriginDepotGetStats() {
+ return chainedOriginDepot.GetStats();
+}
+
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id) {
+ ChainedOriginDepotDesc desc = {here_id, prev_id};
+ bool inserted;
+ ChainedOriginDepotNode::Handle h = chainedOriginDepot.Put(desc, &inserted);
+ *new_id = h.valid() ? h.id() : 0;
+ return inserted;
+}
+
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other) {
+ ChainedOriginDepotDesc desc = chainedOriginDepot.Get(id);
+ *other = desc.prev_id;
+ return desc.here_id;
+}
+
+void ChainedOriginDepotLockAll() {
+ chainedOriginDepot.LockAll();
+}
+
+void ChainedOriginDepotUnlockAll() {
+ chainedOriginDepot.UnlockAll();
+}
+
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.h b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.h
new file mode 100644
index 000000000000..f7a71cef205f
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.h
@@ -0,0 +1,29 @@
+//===-- msan_chained_origin_depot.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_CHAINED_ORIGIN_DEPOT_H
+#define MSAN_CHAINED_ORIGIN_DEPOT_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+StackDepotStats *ChainedOriginDepotGetStats();
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id);
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other);
+
+void ChainedOriginDepotLockAll();
+void ChainedOriginDepotUnlockAll();
+
+} // namespace __msan
+
+#endif // MSAN_CHAINED_ORIGIN_DEPOT_H
diff --git a/contrib/compiler-rt/lib/msan/msan_flags.h b/contrib/compiler-rt/lib/msan/msan_flags.h
new file mode 100644
index 000000000000..4fc6d172a04a
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_flags.h
@@ -0,0 +1,30 @@
+//===-- msan_flags.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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_FLAGS_H
+#define MSAN_FLAGS_H
+
+namespace __msan {
+
+struct Flags {
+#define MSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "msan_flags.inc"
+#undef MSAN_FLAG
+
+ void SetDefaults();
+};
+
+Flags *flags();
+
+} // namespace __msan
+
+#endif // MSAN_FLAGS_H
diff --git a/contrib/compiler-rt/lib/msan/msan_flags.inc b/contrib/compiler-rt/lib/msan/msan_flags.inc
new file mode 100644
index 000000000000..cb58ffc4aba7
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_flags.inc
@@ -0,0 +1,33 @@
+//===-- msan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// MSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_FLAG
+# error "Define MSAN_FLAG prior to including this file!"
+#endif
+
+// MSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+MSAN_FLAG(int, exit_code, 77, "")
+MSAN_FLAG(int, origin_history_size, Origin::kMaxDepth, "")
+MSAN_FLAG(int, origin_history_per_stack_limit, 20000, "")
+MSAN_FLAG(bool, poison_heap_with_zeroes, false, "")
+MSAN_FLAG(bool, poison_stack_with_zeroes, false, "")
+MSAN_FLAG(bool, poison_in_malloc, true, "")
+MSAN_FLAG(bool, poison_in_free, true, "")
+MSAN_FLAG(bool, report_umrs, true, "")
+MSAN_FLAG(bool, wrap_signals, true, "")
+MSAN_FLAG(bool, print_stats, false, "")
+MSAN_FLAG(bool, halt_on_error, !&__msan_keep_going, "")
+MSAN_FLAG(bool, atexit, false, "")
+MSAN_FLAG(int, store_context_size, 20,
+ "Like malloc_context_size, but for uninit stores.")
diff --git a/contrib/compiler-rt/lib/msan/msan_interceptors.cc b/contrib/compiler-rt/lib/msan/msan_interceptors.cc
new file mode 100644
index 000000000000..4a243941b8a3
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_interceptors.cc
@@ -0,0 +1,1575 @@
+//===-- msan_interceptors.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 MemorySanitizer.
+//
+// Interceptors for standard library functions.
+//
+// FIXME: move as many interceptors as possible into
+// sanitizer_common/sanitizer_common_interceptors.h
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
+#include "msan_poisoning.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+#include <stdarg.h>
+// ACHTUNG! No other system header includes in this file.
+// Ideally, we should get rid of stdarg.h as well.
+
+using namespace __msan;
+
+using __sanitizer::memory_order;
+using __sanitizer::atomic_load;
+using __sanitizer::atomic_store;
+using __sanitizer::atomic_uintptr_t;
+
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#endif
+
+// True if this is a nested interceptor.
+static THREADLOCAL int in_interceptor_scope;
+
+extern "C" int *__errno_location(void);
+
+struct InterceptorScope {
+ InterceptorScope() { ++in_interceptor_scope; }
+ ~InterceptorScope() { --in_interceptor_scope; }
+};
+
+bool IsInInterceptorScope() {
+ return in_interceptor_scope;
+}
+
+#define ENSURE_MSAN_INITED() do { \
+ CHECK(!msan_init_is_running); \
+ if (!msan_inited) { \
+ __msan_init(); \
+ } \
+} while (0)
+
+// Check that [x, x+n) range is unpoisoned.
+#define CHECK_UNPOISONED_0(x, n) \
+ do { \
+ sptr offset = __msan_test_shadow(x, n); \
+ if (__msan::IsInSymbolizer()) \
+ break; \
+ if (offset >= 0 && __msan::flags()->report_umrs) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ ReportUMRInsideAddressRange(__func__, x, n, offset); \
+ __msan::PrintWarningWithOrigin( \
+ pc, bp, __msan_get_origin((const char *)x + offset)); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
+ } while (0)
+
+// Check that [x, x+n) range is unpoisoned unless we are in a nested
+// interceptor.
+#define CHECK_UNPOISONED(x, n) \
+ do { \
+ if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
+ } while (0);
+
+INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
+ if (res > 0)
+ __msan_unpoison(ptr, res *size);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
+ void *file) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file);
+ if (res > 0)
+ __msan_unpoison(ptr, res *size);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
+#endif
+
+INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
+ ENSURE_MSAN_INITED();
+ SSIZE_T res = REAL(readlink)(path, buf, bufsiz);
+ if (res > 0)
+ __msan_unpoison(buf, res);
+ return res;
+}
+
+INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
+ return __msan_memcpy(dest, src, n);
+}
+
+INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
+ return (char *)__msan_memcpy(dest, src, n) + n;
+}
+
+INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memccpy)(dest, src, c, n);
+ CHECK(!res || (res >= dest && res <= (char *)dest + n));
+ SIZE_T sz = res ? (char *)res - (char *)dest : n;
+ CHECK_UNPOISONED(src, sz);
+ __msan_unpoison(dest, sz);
+ return res;
+}
+
+INTERCEPTOR(void *, memmove, void *dest, const void *src, SIZE_T n) {
+ return __msan_memmove(dest, src, n);
+}
+
+INTERCEPTOR(void *, memset, void *s, int c, SIZE_T n) {
+ return __msan_memset(s, c, n);
+}
+
+INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
+ return __msan_memmove(dest, src, n);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(alignment & (alignment - 1), 0);
+ CHECK_NE(memptr, 0);
+ *memptr = MsanReallocate(&stack, 0, size, alignment, false);
+ CHECK_NE(*memptr, 0);
+ __msan_unpoison(memptr, sizeof(*memptr));
+ return 0;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ return ptr;
+}
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
+#else
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
+
+INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ return ptr;
+}
+
+INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ DTLS_on_libc_memalign(ptr, size * boundary);
+ return ptr;
+}
+
+INTERCEPTOR(void *, valloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ void *ptr = MsanReallocate(&stack, 0, size, GetPageSizeCached(), false);
+ return ptr;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void *, pvalloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ void *ptr = MsanReallocate(&stack, 0, size, PageSize, false);
+ return ptr;
+}
+#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
+#else
+#define MSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
+
+INTERCEPTOR(void, free, void *ptr) {
+ GET_MALLOC_STACK_TRACE;
+ if (ptr == 0) return;
+ MsanDeallocate(&stack, ptr);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, cfree, void *ptr) {
+ GET_MALLOC_STACK_TRACE;
+ if (ptr == 0) return;
+ MsanDeallocate(&stack, ptr);
+}
+#define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
+#else
+#define MSAN_MAYBE_INTERCEPT_CFREE
+#endif
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ return __sanitizer_get_allocated_size(ptr);
+}
+
+#if !SANITIZER_FREEBSD
+// This function actually returns a struct by value, but we can't unpoison a
+// temporary! The following is equivalent on all supported platforms, and we
+// have a test to confirm that.
+INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
+ REAL(memset)(sret, 0, sizeof(*sret));
+ __msan_unpoison(sret, sizeof(*sret));
+}
+#define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLINFO
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOPT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, malloc_stats, void) {
+ // FIXME: implement, but don't call REAL(malloc_stats)!
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
+#endif
+
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ if (msan_init_is_running)
+ return REAL(strlen)(s);
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(strlen)(s);
+ CHECK_UNPOISONED(s, res + 1);
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(strnlen)(s, n);
+ SIZE_T scan_size = (res == n) ? res : res + 1;
+ CHECK_UNPOISONED(s, scan_size);
+ return res;
+}
+
+// FIXME: Add stricter shadow checks in str* interceptors (ex.: strcpy should
+// check the shadow of the terminating \0 byte).
+
+INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T n = REAL(strlen)(src);
+ char *res = REAL(strcpy)(dest, src); // NOLINT
+ CopyShadowAndOrigin(dest, src, n + 1, &stack);
+ return res;
+}
+
+INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ if (copy_size < n)
+ copy_size++; // trailing \0
+ char *res = REAL(strncpy)(dest, src, n); // NOLINT
+ CopyShadowAndOrigin(dest, src, copy_size, &stack);
+ __msan_unpoison(dest + copy_size, n - copy_size);
+ return res;
+}
+
+INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T n = REAL(strlen)(src);
+ char *res = REAL(stpcpy)(dest, src); // NOLINT
+ CopyShadowAndOrigin(dest, src, n + 1, &stack);
+ return res;
+}
+
+INTERCEPTOR(char *, strdup, char *src) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ // On FreeBSD strdup() leverages strlen().
+ InterceptorScope interceptor_scope;
+ SIZE_T n = REAL(strlen)(src);
+ char *res = REAL(strdup)(src);
+ CopyShadowAndOrigin(res, src, n + 1, &stack);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(char *, __strdup, char *src) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T n = REAL(strlen)(src);
+ char *res = REAL(__strdup)(src);
+ CopyShadowAndOrigin(res, src, n + 1, &stack);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRDUP
+#endif
+
+INTERCEPTOR(char *, strndup, char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ // On FreeBSD strndup() leverages strnlen().
+ InterceptorScope interceptor_scope;
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ char *res = REAL(strndup)(src, n);
+ CopyShadowAndOrigin(res, src, copy_size, &stack);
+ __msan_unpoison(res + copy_size, 1); // \0
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ char *res = REAL(__strndup)(src, n);
+ CopyShadowAndOrigin(res, src, copy_size, &stack);
+ __msan_unpoison(res + copy_size, 1); // \0
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRNDUP
+#endif
+
+INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(gcvt)(number, ndigit, buf);
+ SIZE_T n = REAL(strlen)(buf);
+ __msan_unpoison(buf, n + 1);
+ return res;
+}
+
+INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T src_size = REAL(strlen)(src);
+ SIZE_T dest_size = REAL(strlen)(dest);
+ char *res = REAL(strcat)(dest, src); // NOLINT
+ CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack);
+ return res;
+}
+
+INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T dest_size = REAL(strlen)(dest);
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ char *res = REAL(strncat)(dest, src, n); // NOLINT
+ CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack);
+ __msan_unpoison(dest + dest_size + copy_size, 1); // \0
+ return res;
+}
+
+// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
+// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
+#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(__VA_ARGS__); \
+ __msan_unpoison(endptr, sizeof(*endptr)); \
+ return res;
+
+#define INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \
+ }
+
+#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \
+ }
+
+#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \
+ }
+
+#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base, void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \
+ }
+
+#define INTERCEPTORS_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
+
+#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
+
+INTERCEPTORS_STRTO(double, strtod, char) // NOLINT
+INTERCEPTORS_STRTO(float, strtof, char) // NOLINT
+INTERCEPTORS_STRTO(long double, strtold, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, strtol, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, strtoll, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char) // NOLINT
+
+INTERCEPTORS_STRTO(double, wcstod, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(float, wcstof, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(long double, wcstold, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t) // NOLINT
+
+#define INTERCEPT_STRTO(func) \
+ INTERCEPT_FUNCTION(func); \
+ INTERCEPT_FUNCTION(func##_l); \
+ INTERCEPT_FUNCTION(__##func##_l); \
+ INTERCEPT_FUNCTION(__##func##_internal);
+
+
+// FIXME: support *wprintf in common format interceptors.
+INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(vswprintf)(str, size, format, ap);
+ if (res >= 0) {
+ __msan_unpoison(str, 4 * (res + 1));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
+ ENSURE_MSAN_INITED();
+ va_list ap;
+ va_start(ap, format);
+ int res = vswprintf(str, size, format, ap);
+ va_end(ap);
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm)(dest, src, n);
+ if (res < n) __msan_unpoison(dest, res + 1);
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n,
+ void *loc) {
+ ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc);
+ if (res < n) __msan_unpoison(dest, res + 1);
+ return res;
+}
+
+#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(s, __VA_ARGS__); \
+ if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \
+ return res;
+
+INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
+}
+
+INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
+ loc);
+}
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L
+#endif
+
+INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
+}
+
+INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
+ loc);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
+ loc);
+}
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
+#endif
+
+INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(mbtowc)(dest, src, n);
+ if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
+ return res;
+}
+
+INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
+ if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(wcslen)(s);
+ CHECK_UNPOISONED(s, sizeof(wchar_t) * (res + 1));
+ return res;
+}
+
+// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
+INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
+ ENSURE_MSAN_INITED();
+ wchar_t *res = REAL(wcschr)(s, wc, ps);
+ return res;
+}
+
+// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
+INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wcscpy)(dest, src);
+ CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1),
+ &stack);
+ return res;
+}
+
+// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
+INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wmemcpy)(dest, src, n);
+ CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
+ return res;
+}
+
+INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wmempcpy)(dest, src, n);
+ CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
+ return res;
+}
+
+INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
+ CHECK(MEM_IS_APP(s));
+ ENSURE_MSAN_INITED();
+ wchar_t *res = REAL(wmemset)(s, c, n);
+ __msan_unpoison(s, n * sizeof(wchar_t));
+ return res;
+}
+
+INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wmemmove)(dest, src, n);
+ MoveShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
+ return res;
+}
+
+INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(wcscmp)(s1, s2);
+ return res;
+}
+
+INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(gettimeofday)(tv, tz);
+ if (tv)
+ __msan_unpoison(tv, 16);
+ if (tz)
+ __msan_unpoison(tz, 8);
+ return res;
+}
+
+INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(fcvt)(x, a, b, c);
+ __msan_unpoison(b, sizeof(*b));
+ __msan_unpoison(c, sizeof(*c));
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+INTERCEPTOR(char *, getenv, char *name) {
+ if (msan_init_is_running)
+ return REAL(getenv)(name);
+ ENSURE_MSAN_INITED();
+ char *res = REAL(getenv)(name);
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+extern char **environ;
+
+static void UnpoisonEnviron() {
+ char **envp = environ;
+ for (; *envp; ++envp) {
+ __msan_unpoison(envp, sizeof(*envp));
+ __msan_unpoison(*envp, REAL(strlen)(*envp) + 1);
+ }
+ // Trailing NULL pointer.
+ __msan_unpoison(envp, sizeof(*envp));
+}
+
+INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(setenv)(name, value, overwrite);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
+INTERCEPTOR(int, putenv, char *string) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(putenv)(string);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstat)(magic, fd, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT INTERCEPT_FUNCTION(__fxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstat64)(magic, fd, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64 INTERCEPT_FUNCTION(__fxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
+
+#if SANITIZER_FREEBSD
+INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(fstatat)(fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(fstatat)
+#else
+INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(__fxstatat)
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64 INTERCEPT_FUNCTION(__fxstatat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64
+#endif
+
+#if SANITIZER_FREEBSD
+INTERCEPTOR(int, stat, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(stat)(path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_STAT INTERCEPT_FUNCTION(stat)
+#else
+INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__xstat)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_STAT INTERCEPT_FUNCTION(__xstat)
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__xstat64)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___XSTAT64 INTERCEPT_FUNCTION(__xstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__lxstat)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT INTERCEPT_FUNCTION(__lxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__lxstat64)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64 INTERCEPT_FUNCTION(__lxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
+
+INTERCEPTOR(int, pipe, int pipefd[2]) {
+ if (msan_init_is_running)
+ return REAL(pipe)(pipefd);
+ ENSURE_MSAN_INITED();
+ int res = REAL(pipe)(pipefd);
+ if (!res)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+ return res;
+}
+
+INTERCEPTOR(int, pipe2, int pipefd[2], int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pipe2)(pipefd, flags);
+ if (!res)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+ return res;
+}
+
+INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(socketpair)(domain, type, protocol, sv);
+ if (!res)
+ __msan_unpoison(sv, sizeof(int[2]));
+ return res;
+}
+
+INTERCEPTOR(char *, fgets, char *s, int size, void *stream) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(fgets)(s, size, stream);
+ if (res)
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(fgets_unlocked)(s, size, stream);
+ if (res)
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
+#endif
+
+INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
+ if (msan_init_is_running)
+ return REAL(getrlimit)(resource, rlim);
+ ENSURE_MSAN_INITED();
+ int res = REAL(getrlimit)(resource, rlim);
+ if (!res)
+ __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
+ if (msan_init_is_running)
+ return REAL(getrlimit64)(resource, rlim);
+ ENSURE_MSAN_INITED();
+ int res = REAL(getrlimit64)(resource, rlim);
+ if (!res)
+ __msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
+#else
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
+#endif
+
+#if SANITIZER_FREEBSD
+// FreeBSD's <sys/utsname.h> define uname() as
+// static __inline int uname(struct utsname *name) {
+// return __xuname(SYS_NMLN, (void*)name);
+// }
+INTERCEPTOR(int, __xuname, int size, void *utsname) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__xuname)(size, utsname);
+ if (!res)
+ __msan_unpoison(utsname, __sanitizer::struct_utsname_sz);
+ return res;
+}
+#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(__xuname)
+#else
+INTERCEPTOR(int, uname, struct utsname *utsname) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(uname)(utsname);
+ if (!res)
+ __msan_unpoison(utsname, __sanitizer::struct_utsname_sz);
+ return res;
+}
+#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(uname)
+#endif
+
+INTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(gethostname)(name, len);
+ if (!res) {
+ SIZE_T real_len = REAL(strnlen)(name, len);
+ if (real_len < len)
+ ++real_len;
+ __msan_unpoison(name, real_len);
+ }
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
+ int timeout) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(epoll_wait)(epfd, events, maxevents, timeout);
+ if (res > 0) {
+ __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
+ }
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
+ int timeout, void *sigmask) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask);
+ if (res > 0) {
+ __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
+ }
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
+#endif
+
+INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
+ ENSURE_MSAN_INITED();
+ SSIZE_T res = REAL(recv)(fd, buf, len, flags);
+ if (res > 0)
+ __msan_unpoison(buf, res);
+ return res;
+}
+
+INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
+ void *srcaddr, int *addrlen) {
+ ENSURE_MSAN_INITED();
+ SIZE_T srcaddr_sz;
+ if (srcaddr) srcaddr_sz = *addrlen;
+ SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
+ if (res > 0) {
+ __msan_unpoison(buf, res);
+ if (srcaddr) {
+ SIZE_T sz = *addrlen;
+ __msan_unpoison(srcaddr, Min(sz, srcaddr_sz));
+ }
+ }
+ return res;
+}
+
+INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ if (UNLIKELY(!msan_inited)) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const SIZE_T kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static SIZE_T allocated;
+ SIZE_T size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ return MsanCalloc(&stack, nmemb, size);
+}
+
+INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ return MsanReallocate(&stack, ptr, size, sizeof(u64), false);
+}
+
+INTERCEPTOR(void *, malloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ return MsanReallocate(&stack, 0, size, sizeof(u64), false);
+}
+
+void __msan_allocated_memory(const void *data, uptr size) {
+ GET_MALLOC_STACK_TRACE;
+ if (flags()->poison_in_malloc) {
+ stack.tag = STACK_TRACE_TAG_POISON;
+ PoisonMemory(data, size, &stack);
+ }
+}
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF_T offset) {
+ if (msan_init_is_running)
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+ ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = 0;
+ }
+ }
+ void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF64_T offset) {
+ ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = 0;
+ }
+ }
+ void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64)
+#else
+#define MSAN_MAYBE_INTERCEPT_MMAP64
+#endif
+
+struct dlinfo {
+ char *dli_fname;
+ void *dli_fbase;
+ char *dli_sname;
+ void *dli_saddr;
+};
+
+INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(dladdr)(addr, info);
+ if (res != 0) {
+ __msan_unpoison(info, sizeof(*info));
+ if (info->dli_fname)
+ __msan_unpoison(info->dli_fname, REAL(strlen)(info->dli_fname) + 1);
+ if (info->dli_sname)
+ __msan_unpoison(info->dli_sname, REAL(strlen)(info->dli_sname) + 1);
+ }
+ return res;
+}
+
+INTERCEPTOR(char *, dlerror, int fake) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(dlerror)(fake);
+ if (res != 0) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
+ void *data);
+struct dl_iterate_phdr_data {
+ dl_iterate_phdr_cb callback;
+ void *data;
+};
+
+static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
+ void *data) {
+ if (info) {
+ __msan_unpoison(info, size);
+ if (info->dlpi_name)
+ __msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
+ }
+ dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
+ UnpoisonParam(3);
+ return cbdata->callback(info, size, cbdata->data);
+}
+
+INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
+ ENSURE_MSAN_INITED();
+ dl_iterate_phdr_data cbdata;
+ cbdata.callback = callback;
+ cbdata.data = data;
+ int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
+ return res;
+}
+
+INTERCEPTOR(int, getrusage, int who, void *usage) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(getrusage)(who, usage);
+ if (res == 0) {
+ __msan_unpoison(usage, __sanitizer::struct_rusage_sz);
+ }
+ return res;
+}
+
+class SignalHandlerScope {
+ public:
+ SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->EnterSignalHandler();
+ }
+ ~SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->LeaveSignalHandler();
+ }
+};
+
+// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
+// Access to sigactions[] is gone with relaxed atomics to avoid data race with
+// the signal handler.
+const int kMaxSignals = 1024;
+static atomic_uintptr_t sigactions[kMaxSignals];
+static StaticSpinMutex sigactions_mu;
+
+static void SignalHandler(int signo) {
+ SignalHandlerScope signal_handler_scope;
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(1);
+
+ typedef void (*signal_cb)(int x);
+ signal_cb cb =
+ (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
+ cb(signo);
+}
+
+static void SignalAction(int signo, void *si, void *uc) {
+ SignalHandlerScope signal_handler_scope;
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(3);
+ __msan_unpoison(si, sizeof(__sanitizer_sigaction));
+ __msan_unpoison(uc, __sanitizer::ucontext_t_sz);
+
+ typedef void (*sigaction_cb)(int, void *, void *);
+ sigaction_cb cb =
+ (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
+ cb(signo, si, uc);
+}
+
+INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
+ __sanitizer_sigaction *oldact) {
+ ENSURE_MSAN_INITED();
+ // FIXME: check that *act is unpoisoned.
+ // That requires intercepting all of sigemptyset, sigfillset, etc.
+ int res;
+ if (flags()->wrap_signals) {
+ SpinMutexLock lock(&sigactions_mu);
+ CHECK_LT(signo, kMaxSignals);
+ uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
+ __sanitizer_sigaction new_act;
+ __sanitizer_sigaction *pnew_act = act ? &new_act : 0;
+ if (act) {
+ REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
+ uptr cb = (uptr)pnew_act->sigaction;
+ uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
+ ? (uptr)SignalAction
+ : (uptr)SignalHandler;
+ if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
+ pnew_act->sigaction = (void (*)(int, void *, void *))new_cb;
+ }
+ }
+ res = REAL(sigaction)(signo, pnew_act, oldact);
+ if (res == 0 && oldact) {
+ uptr cb = (uptr)oldact->sigaction;
+ if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+ oldact->sigaction = (void (*)(int, void *, void *))old_cb;
+ }
+ }
+ } else {
+ res = REAL(sigaction)(signo, act, oldact);
+ }
+
+ if (res == 0 && oldact) {
+ __msan_unpoison(oldact, sizeof(__sanitizer_sigaction));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, signal, int signo, uptr cb) {
+ ENSURE_MSAN_INITED();
+ if (flags()->wrap_signals) {
+ CHECK_LT(signo, kMaxSignals);
+ SpinMutexLock lock(&sigactions_mu);
+ if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
+ cb = (uptr) SignalHandler;
+ }
+ return REAL(signal)(signo, cb);
+ } else {
+ return REAL(signal)(signo, cb);
+ }
+}
+
+extern "C" int pthread_attr_init(void *attr);
+extern "C" int pthread_attr_destroy(void *attr);
+
+static void *MsanThreadStartFunc(void *arg) {
+ MsanThread *t = (MsanThread *)arg;
+ SetCurrentThread(t);
+ return t->ThreadStart();
+}
+
+INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
+ void * param) {
+ ENSURE_MSAN_INITED(); // for GetTlsSize()
+ __sanitizer_pthread_attr_t myattr;
+ if (attr == 0) {
+ pthread_attr_init(&myattr);
+ attr = &myattr;
+ }
+
+ AdjustStackSize(attr);
+
+ MsanThread *t = MsanThread::Create(callback, param);
+
+ int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
+
+ if (attr == &myattr)
+ pthread_attr_destroy(&myattr);
+ if (!res) {
+ __msan_unpoison(th, __sanitizer::pthread_t_sz);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
+ void (*dtor)(void *value)) {
+ if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_key_create)(key, dtor);
+ if (!res && key)
+ __msan_unpoison(key, sizeof(*key));
+ return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **retval) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_join)(th, retval);
+ if (!res && retval)
+ __msan_unpoison(retval, sizeof(*retval));
+ return res;
+}
+
+extern char *tzname[2];
+
+INTERCEPTOR(void, tzset, int fake) {
+ ENSURE_MSAN_INITED();
+ REAL(tzset)(fake);
+ if (tzname[0])
+ __msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
+ if (tzname[1])
+ __msan_unpoison(tzname[1], REAL(strlen)(tzname[1]) + 1);
+ return;
+}
+
+struct MSanAtExitRecord {
+ void (*func)(void *arg);
+ void *arg;
+};
+
+void MSanAtExitWrapper(void *arg) {
+ UnpoisonParam(1);
+ MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
+ r->func(r->arg);
+ InternalFree(r);
+}
+
+// Unpoison argument shadow for C++ module destructors.
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+ if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ ENSURE_MSAN_INITED();
+ MSanAtExitRecord *r =
+ (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
+ r->func = func;
+ r->arg = arg;
+ return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle);
+}
+
+DECLARE_REAL(int, shmctl, int shmid, int cmd, void *buf)
+
+INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
+ ENSURE_MSAN_INITED();
+ void *p = REAL(shmat)(shmid, shmaddr, shmflg);
+ if (p != (void *)-1) {
+ __sanitizer_shmid_ds ds;
+ int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
+ if (!res) {
+ __msan_unpoison(p, ds.shm_segsz);
+ }
+ }
+ return p;
+}
+
+static void BeforeFork() {
+ StackDepotLockAll();
+ ChainedOriginDepotLockAll();
+}
+
+static void AfterFork() {
+ ChainedOriginDepotUnlockAll();
+ StackDepotUnlockAll();
+}
+
+INTERCEPTOR(int, fork, void) {
+ ENSURE_MSAN_INITED();
+ BeforeFork();
+ int pid = REAL(fork)();
+ AfterFork();
+ return pid;
+}
+
+struct MSanInterceptorContext {
+ bool in_interceptor_scope;
+};
+
+namespace __msan {
+
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
+} // namespace __msan
+
+// A version of CHECK_UNPOISONED using a saved scope value. Used in common
+// interceptors.
+#define CHECK_UNPOISONED_CTX(ctx, x, n) \
+ do { \
+ if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
+ CHECK_UNPOISONED_0(x, n); \
+ } while (0)
+
+#define MSAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "MemorySanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+
+#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \
+ UnpoisonParam(count)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ CHECK_UNPOISONED_CTX(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
+ __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
+ MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
+ ctx = (void *)&msan_ctx; \
+ (void)ctx; \
+ InterceptorScope interceptor_scope; \
+ __msan_unpoison(__errno_location(), sizeof(int)); /* NOLINT */ \
+ ENSURE_MSAN_INITED();
+#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
+ do { \
+ link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \
+ if (map) ForEachMappedRegion(map, __msan_unpoison); \
+ } while (false)
+
+#include "sanitizer_common/sanitizer_common_interceptors.inc"
+
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
+ do { \
+ } while (false)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
+// These interface functions reside here so that they can use
+// REAL(memset), etc.
+void __msan_unpoison(const void *a, uptr size) {
+ if (!MEM_IS_APP(a)) return;
+ SetShadow(a, size, 0);
+}
+
+void __msan_poison(const void *a, uptr size) {
+ if (!MEM_IS_APP(a)) return;
+ SetShadow(a, size, __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
+}
+
+void __msan_poison_stack(void *a, uptr size) {
+ if (!MEM_IS_APP(a)) return;
+ SetShadow(a, size, __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
+}
+
+void __msan_clear_and_unpoison(void *a, uptr size) {
+ REAL(memset)(a, 0, size);
+ SetShadow(a, size, 0);
+}
+
+void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memcpy(dest, src, n);
+ if (msan_init_is_running) return REAL(memcpy)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memcpy)(dest, src, n);
+ CopyShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+
+void *__msan_memset(void *s, int c, SIZE_T n) {
+ if (!msan_inited) return internal_memset(s, c, n);
+ if (msan_init_is_running) return REAL(memset)(s, c, n);
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memset)(s, c, n);
+ __msan_unpoison(s, n);
+ return res;
+}
+
+void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memmove(dest, src, n);
+ if (msan_init_is_running) return REAL(memmove)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memmove)(dest, src, n);
+ MoveShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+
+void __msan_unpoison_string(const char* s) {
+ if (!MEM_IS_APP(s)) return;
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
+}
+
+namespace __msan {
+
+void InitializeInterceptors() {
+ static int inited = 0;
+ CHECK_EQ(inited, 0);
+ InitializeCommonInterceptors();
+
+ INTERCEPT_FUNCTION(mmap);
+ MSAN_MAYBE_INTERCEPT_MMAP64;
+ INTERCEPT_FUNCTION(posix_memalign);
+ MSAN_MAYBE_INTERCEPT_MEMALIGN;
+ INTERCEPT_FUNCTION(__libc_memalign);
+ INTERCEPT_FUNCTION(valloc);
+ MSAN_MAYBE_INTERCEPT_PVALLOC;
+ INTERCEPT_FUNCTION(malloc);
+ INTERCEPT_FUNCTION(calloc);
+ INTERCEPT_FUNCTION(realloc);
+ INTERCEPT_FUNCTION(free);
+ MSAN_MAYBE_INTERCEPT_CFREE;
+ INTERCEPT_FUNCTION(malloc_usable_size);
+ MSAN_MAYBE_INTERCEPT_MALLINFO;
+ MSAN_MAYBE_INTERCEPT_MALLOPT;
+ MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
+ INTERCEPT_FUNCTION(fread);
+ MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
+ INTERCEPT_FUNCTION(readlink);
+ INTERCEPT_FUNCTION(memcpy);
+ INTERCEPT_FUNCTION(memccpy);
+ INTERCEPT_FUNCTION(mempcpy);
+ INTERCEPT_FUNCTION(memset);
+ INTERCEPT_FUNCTION(memmove);
+ INTERCEPT_FUNCTION(bcopy);
+ INTERCEPT_FUNCTION(wmemset);
+ INTERCEPT_FUNCTION(wmemcpy);
+ INTERCEPT_FUNCTION(wmempcpy);
+ INTERCEPT_FUNCTION(wmemmove);
+ INTERCEPT_FUNCTION(strcpy); // NOLINT
+ INTERCEPT_FUNCTION(stpcpy); // NOLINT
+ INTERCEPT_FUNCTION(strdup);
+ MSAN_MAYBE_INTERCEPT___STRDUP;
+ INTERCEPT_FUNCTION(strndup);
+ MSAN_MAYBE_INTERCEPT___STRNDUP;
+ INTERCEPT_FUNCTION(strncpy); // NOLINT
+ INTERCEPT_FUNCTION(strlen);
+ INTERCEPT_FUNCTION(strnlen);
+ INTERCEPT_FUNCTION(gcvt);
+ INTERCEPT_FUNCTION(strcat); // NOLINT
+ INTERCEPT_FUNCTION(strncat); // NOLINT
+ INTERCEPT_STRTO(strtod);
+ INTERCEPT_STRTO(strtof);
+ INTERCEPT_STRTO(strtold);
+ INTERCEPT_STRTO(strtol);
+ INTERCEPT_STRTO(strtoul);
+ INTERCEPT_STRTO(strtoll);
+ INTERCEPT_STRTO(strtoull);
+ INTERCEPT_STRTO(wcstod);
+ INTERCEPT_STRTO(wcstof);
+ INTERCEPT_STRTO(wcstold);
+ INTERCEPT_STRTO(wcstol);
+ INTERCEPT_STRTO(wcstoul);
+ INTERCEPT_STRTO(wcstoll);
+ INTERCEPT_STRTO(wcstoull);
+ INTERCEPT_FUNCTION(vswprintf);
+ INTERCEPT_FUNCTION(swprintf);
+ INTERCEPT_FUNCTION(strxfrm);
+ INTERCEPT_FUNCTION(strxfrm_l);
+ INTERCEPT_FUNCTION(strftime);
+ INTERCEPT_FUNCTION(strftime_l);
+ MSAN_MAYBE_INTERCEPT___STRFTIME_L;
+ INTERCEPT_FUNCTION(wcsftime);
+ INTERCEPT_FUNCTION(wcsftime_l);
+ MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
+ INTERCEPT_FUNCTION(mbtowc);
+ INTERCEPT_FUNCTION(mbrtowc);
+ INTERCEPT_FUNCTION(wcslen);
+ INTERCEPT_FUNCTION(wcschr);
+ INTERCEPT_FUNCTION(wcscpy);
+ INTERCEPT_FUNCTION(wcscmp);
+ INTERCEPT_FUNCTION(getenv);
+ INTERCEPT_FUNCTION(setenv);
+ INTERCEPT_FUNCTION(putenv);
+ INTERCEPT_FUNCTION(gettimeofday);
+ INTERCEPT_FUNCTION(fcvt);
+ MSAN_MAYBE_INTERCEPT___FXSTAT;
+ MSAN_INTERCEPT_FSTATAT;
+ MSAN_INTERCEPT_STAT;
+ MSAN_MAYBE_INTERCEPT___LXSTAT;
+ MSAN_MAYBE_INTERCEPT___FXSTAT64;
+ MSAN_MAYBE_INTERCEPT___FXSTATAT64;
+ MSAN_MAYBE_INTERCEPT___XSTAT64;
+ MSAN_MAYBE_INTERCEPT___LXSTAT64;
+ INTERCEPT_FUNCTION(pipe);
+ INTERCEPT_FUNCTION(pipe2);
+ INTERCEPT_FUNCTION(socketpair);
+ INTERCEPT_FUNCTION(fgets);
+ MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
+ INTERCEPT_FUNCTION(getrlimit);
+ MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
+ MSAN_INTERCEPT_UNAME;
+ INTERCEPT_FUNCTION(gethostname);
+ MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
+ MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
+ INTERCEPT_FUNCTION(recv);
+ INTERCEPT_FUNCTION(recvfrom);
+ INTERCEPT_FUNCTION(dladdr);
+ INTERCEPT_FUNCTION(dlerror);
+ INTERCEPT_FUNCTION(dl_iterate_phdr);
+ INTERCEPT_FUNCTION(getrusage);
+ INTERCEPT_FUNCTION(sigaction);
+ INTERCEPT_FUNCTION(signal);
+ INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_key_create);
+ INTERCEPT_FUNCTION(pthread_join);
+ INTERCEPT_FUNCTION(tzset);
+ INTERCEPT_FUNCTION(__cxa_atexit);
+ INTERCEPT_FUNCTION(shmat);
+ INTERCEPT_FUNCTION(fork);
+
+ inited = 1;
+}
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_interface_internal.h b/contrib/compiler-rt/lib/msan/msan_interface_internal.h
new file mode 100644
index 000000000000..8641f814bc5f
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_interface_internal.h
@@ -0,0 +1,158 @@
+//===-- msan_interface_internal.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 MemorySanitizer.
+//
+// Private MSan interface header.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_INTERFACE_INTERNAL_H
+#define MSAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+extern "C" {
+// FIXME: document all interface functions.
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_get_track_origins();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_init();
+
+// Print a warning and maybe return.
+// This function can die based on flags()->exit_code.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_warning();
+
+// Print a warning and die.
+// Intrumentation inserts calls to this function when building in "fast" mode
+// (i.e. -mllvm -msan-keep-going)
+SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn))
+void __msan_warning_noreturn();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_1(u8 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_2(u16 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_4(u32 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_8(u64 s, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_1(u8 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_2(u16 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_4(u32 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_8(u64 s, void *p, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_unpoison(const void *a, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_unpoison_string(const char *s);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_clear_and_unpoison(void *a, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void* __msan_memcpy(void *dst, const void *src, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void* __msan_memset(void *s, int c, uptr n);
+SANITIZER_INTERFACE_ATTRIBUTE
+void* __msan_memmove(void* dest, const void* src, uptr n);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_poison(const void *a, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_poison_stack(void *a, uptr size);
+
+// Copy size bytes from src to dst and unpoison the result.
+// Useful to implement unsafe loads.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_load_unpoisoned(void *src, uptr size, void *dst);
+
+// Returns the offset of the first (at least partially) poisoned byte,
+// or -1 if the whole range is good.
+SANITIZER_INTERFACE_ATTRIBUTE
+sptr __msan_test_shadow(const void *x, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_check_mem_is_initialized(const void *x, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_origin(const void *a, uptr size, u32 origin);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin(void *a, uptr size, char *descr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc);
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __msan_chain_origin(u32 id);
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __msan_get_origin(const void *a);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_clear_on_return();
+
+// Default: -1 (don't exit on error).
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_exit_code(int exit_code);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_keep_going(int keep_going);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_set_poison_in_malloc(int do_poison);
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+/* OPTIONAL */ const char* __msan_default_options();
+
+// For testing.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_expect_umr(int expect_umr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_print_shadow(const void *x, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_dump_shadow(const void *x, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_has_dynamic_component();
+
+// For testing.
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __msan_get_umr_origin();
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_partial_poison(const void* data, void* shadow, uptr size);
+
+// Tell MSan about newly allocated memory (ex.: custom allocator).
+// Memory will be marked uninitialized, with origin at the call site.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_allocated_memory(const void* data, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *p, u64 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_death_callback(void (*callback)(void));
+} // extern "C"
+
+#endif // MSAN_INTERFACE_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/msan/msan_linux.cc b/contrib/compiler-rt/lib/msan/msan_linux.cc
new file mode 100644
index 000000000000..6c185165fc50
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_linux.cc
@@ -0,0 +1,195 @@
+//===-- msan_linux.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 MemorySanitizer.
+//
+// Linux- and FreeBSD-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "msan.h"
+#include "msan_thread.h"
+
+#include <elf.h>
+#include <link.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <unwind.h>
+#include <execinfo.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+namespace __msan {
+
+void ReportMapRange(const char *descr, uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ VPrintf(1, "%s : %p - %p\n", descr, beg, end);
+ }
+}
+
+static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!MemoryRangeIsAvailable(beg, end)) {
+ Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool ProtectMemoryRange(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!Mprotect(beg, size)) {
+ Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void CheckMemoryLayoutSanity() {
+ uptr prev_end = 0;
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
+ uptr start = kMemoryLayout[i].start;
+ uptr end = kMemoryLayout[i].end;
+ MappingDesc::Type type = kMemoryLayout[i].type;
+ CHECK_LT(start, end);
+ CHECK_EQ(prev_end, start);
+ CHECK(addr_is_type(start, type));
+ CHECK(addr_is_type((start + end) / 2, type));
+ CHECK(addr_is_type(end - 1, type));
+ if (type == MappingDesc::APP) {
+ uptr addr = start;
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
+ CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
+
+ addr = (start + end) / 2;
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
+ CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
+
+ addr = end - 1;
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
+ CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
+ }
+ prev_end = end;
+ }
+}
+
+bool InitShadow(bool map_shadow, bool init_origins) {
+ // Let user know mapping parameters first.
+ VPrintf(1, "__msan_init %p\n", &__msan_init);
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
+ VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
+ kMemoryLayout[i].end - 1);
+
+ CheckMemoryLayoutSanity();
+
+ if (!MEM_IS_APP(&__msan_init)) {
+ Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
+ (uptr)&__msan_init);
+ return false;
+ }
+
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
+ uptr start = kMemoryLayout[i].start;
+ uptr end = kMemoryLayout[i].end;
+ uptr size= end - start;
+ MappingDesc::Type type = kMemoryLayout[i].type;
+ if ((map_shadow && type == MappingDesc::SHADOW) ||
+ (init_origins && type == MappingDesc::ORIGIN)) {
+ if (!CheckMemoryRangeAvailability(start, size)) return false;
+ if ((uptr)MmapFixedNoReserve(start, size) != start) return false;
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(start, size);
+ } else if (type == MappingDesc::INVALID) {
+ if (!CheckMemoryRangeAvailability(start, size)) return false;
+ if (!ProtectMemoryRange(start, size)) return false;
+ }
+ }
+
+ return true;
+}
+
+void MsanDie() {
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+ if (death_callback)
+ death_callback();
+ internal__exit(flags()->exit_code);
+}
+
+static void MsanAtExit(void) {
+ if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
+ ReportStats();
+ if (msan_report_count > 0) {
+ ReportAtExitStatistics();
+ if (flags()->exit_code) _exit(flags()->exit_code);
+ }
+}
+
+void InstallAtExitHandler() {
+ atexit(MsanAtExit);
+}
+
+// ---------------------- TSD ---------------- {{{1
+
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
+
+void MsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_key_inited);
+ tsd_key_inited = true;
+ CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+}
+
+static THREADLOCAL MsanThread* msan_current_thread;
+
+MsanThread *GetCurrentThread() {
+ return msan_current_thread;
+}
+
+void SetCurrentThread(MsanThread *t) {
+ // Make sure we do not reset the current MsanThread.
+ CHECK_EQ(0, msan_current_thread);
+ msan_current_thread = t;
+ // Make sure that MsanTSDDtor gets called at the end.
+ CHECK(tsd_key_inited);
+ pthread_setspecific(tsd_key, (void *)t);
+}
+
+void MsanTSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ if (t->destructor_iterations_ > 1) {
+ t->destructor_iterations_--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ msan_current_thread = nullptr;
+ // Make sure that signal handler can not see a stale current thread pointer.
+ atomic_signal_fence(memory_order_seq_cst);
+ MsanThread::TSDDtor(tsd);
+}
+
+} // namespace __msan
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/msan/msan_new_delete.cc b/contrib/compiler-rt/lib/msan/msan_new_delete.cc
new file mode 100644
index 000000000000..9a8e56e4a28a
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_new_delete.cc
@@ -0,0 +1,65 @@
+//===-- msan_new_delete.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 MemorySanitizer.
+//
+// Interceptors for operators new and delete.
+//===----------------------------------------------------------------------===//
+
+#include "msan.h"
+#include "interception/interception.h"
+
+#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
+
+#include <stddef.h>
+
+namespace __msan {
+// This function is a no-op. We need it to make sure that object file
+// with our replacements will actually be loaded from static MSan
+// run-time library at link-time.
+void ReplaceOperatorsNewAndDelete() { }
+}
+
+using namespace __msan; // NOLINT
+
+// Fake std::nothrow_t to avoid including <new>.
+namespace std {
+ struct nothrow_t {};
+} // namespace std
+
+
+#define OPERATOR_NEW_BODY \
+ GET_MALLOC_STACK_TRACE; \
+ return MsanReallocate(&stack, 0, size, sizeof(u64), false)
+
+INTERCEPTOR_ATTRIBUTE
+void *operator new(size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+ GET_MALLOC_STACK_TRACE; \
+ if (ptr) MsanDeallocate(&stack, ptr)
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY;
+}
+
+#endif // MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
diff --git a/contrib/compiler-rt/lib/msan/msan_origin.h b/contrib/compiler-rt/lib/msan/msan_origin.h
new file mode 100644
index 000000000000..1284c01bf2af
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_origin.h
@@ -0,0 +1,169 @@
+//===-- msan_origin.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Origin id utils.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_ORIGIN_H
+#define MSAN_ORIGIN_H
+
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "msan_chained_origin_depot.h"
+
+namespace __msan {
+
+// Origin handling.
+//
+// Origin is a 32-bit identifier that is attached to any uninitialized value in
+// the program and describes, more or less exactly, how this memory came to be
+// uninitialized.
+//
+// There are 3 kinds of origin ids:
+// 1xxx xxxx xxxx xxxx heap origin id
+// 0000 xxxx xxxx xxxx stack origin id
+// 0zzz xxxx xxxx xxxx chained origin id
+//
+// Heap origin id describes a heap memory allocation and contains (in the xxx
+// part) a value of StackDepot.
+//
+// Stack origin id describes a stack memory allocation and contains (in the xxx
+// part) an index into StackOriginDescr and StackOriginPC. We don't store a
+// stack trace for such origins for performance reasons.
+//
+// Chained origin id describes an event of storing an uninitialized value to
+// memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of
+// (stack_id, prev_id) -> id, where
+// * stack_id describes the event.
+// StackDepot keeps a mapping between those and corresponding stack traces.
+// * prev_id is another origin id that describes the earlier part of the
+// uninitialized value history.
+// Following a chain of prev_id provides the full recorded history of an
+// uninitialized value.
+//
+// This, effectively, defines a tree (or 2 trees, see below) where nodes are
+// points in value history marked with origin ids, and edges are events that are
+// marked with stack_id.
+//
+// The "zzz" bits of chained origin id are used to store the length (or depth)
+// of the origin chain.
+
+class Origin {
+ public:
+ static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; }
+
+ u32 raw_id() const { return raw_id_; }
+ bool isHeapOrigin() const {
+ // 1xxx xxxx xxxx xxxx
+ return raw_id_ >> kHeapShift == 0;
+ }
+ bool isStackOrigin() const {
+ // 1000 xxxx xxxx xxxx
+ return (raw_id_ >> kDepthShift) == (1 << kDepthBits);
+ }
+ bool isChainedOrigin() const {
+ // 1zzz xxxx xxxx xxxx, zzz != 000
+ return (raw_id_ >> kDepthShift) > (1 << kDepthBits);
+ }
+ u32 getChainedId() const {
+ CHECK(isChainedOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getStackId() const {
+ CHECK(isStackOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getHeapId() const {
+ CHECK(isHeapOrigin());
+ return raw_id_ & kHeapIdMask;
+ }
+
+ // Returns the next origin in the chain and the current stack trace.
+ Origin getNextChainedOrigin(StackTrace *stack) const {
+ CHECK(isChainedOrigin());
+ u32 prev_id;
+ u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id);
+ *stack = StackDepotGet(stack_id);
+ return Origin(prev_id);
+ }
+
+ StackTrace getStackTraceForHeapOrigin() const {
+ return StackDepotGet(getHeapId());
+ }
+
+ static Origin CreateStackOrigin(u32 id) {
+ CHECK((id & kStackIdMask) == id);
+ return Origin((1 << kHeapShift) | id);
+ }
+
+ static Origin CreateHeapOrigin(StackTrace *stack) {
+ u32 stack_id = StackDepotPut(*stack);
+ CHECK(stack_id);
+ CHECK((stack_id & kHeapIdMask) == stack_id);
+ return Origin(stack_id);
+ }
+
+ static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) {
+ int depth = prev.isChainedOrigin() ? prev.depth() : 0;
+ // depth is the length of the chain minus 1.
+ // origin_history_size of 0 means unlimited depth.
+ if (flags()->origin_history_size > 0) {
+ if (depth + 1 >= flags()->origin_history_size) {
+ return prev;
+ } else {
+ ++depth;
+ CHECK(depth < (1 << kDepthBits));
+ }
+ }
+
+ StackDepotHandle h = StackDepotPut_WithHandle(*stack);
+ if (!h.valid()) return prev;
+
+ if (flags()->origin_history_per_stack_limit > 0) {
+ int use_count = h.use_count();
+ if (use_count > flags()->origin_history_per_stack_limit) return prev;
+ }
+
+ u32 chained_id;
+ bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id);
+ CHECK((chained_id & kChainedIdMask) == chained_id);
+
+ if (inserted && flags()->origin_history_per_stack_limit > 0)
+ h.inc_use_count_unsafe();
+
+ return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id);
+ }
+
+ static Origin FromRawId(u32 id) {
+ return Origin(id);
+ }
+
+ private:
+ static const int kDepthBits = 3;
+ static const int kDepthShift = 32 - kDepthBits - 1;
+
+ static const int kHeapShift = 31;
+ static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift);
+
+ u32 raw_id_;
+
+ explicit Origin(u32 raw_id) : raw_id_(raw_id) {}
+
+ int depth() const {
+ CHECK(isChainedOrigin());
+ return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1);
+ }
+
+ public:
+ static const int kMaxDepth = (1 << kDepthBits) - 1;
+};
+
+} // namespace __msan
+
+#endif // MSAN_ORIGIN_H
diff --git a/contrib/compiler-rt/lib/msan/msan_poisoning.cc b/contrib/compiler-rt/lib/msan/msan_poisoning.cc
new file mode 100644
index 000000000000..96411fdbc31b
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_poisoning.cc
@@ -0,0 +1,174 @@
+//===-- msan_poisoning.cc ---------------------------------------*- 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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "msan_poisoning.h"
+
+#include "interception/interception.h"
+#include "msan_origin.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
+DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
+DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n)
+
+namespace __msan {
+
+u32 GetOriginIfPoisoned(uptr addr, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);
+ return 0;
+}
+
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,
+ u32 src_origin) {
+ uptr dst_s = MEM_TO_SHADOW(addr);
+ uptr src_s = src_shadow;
+ uptr src_s_end = src_s + size;
+
+ for (; src_s < src_s_end; ++dst_s, ++src_s)
+ if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin;
+}
+
+void CopyOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack) {
+ if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
+
+ uptr d = (uptr)dst;
+ uptr beg = d & ~3UL;
+ // Copy left unaligned origin if that memory is poisoned.
+ if (beg < d) {
+ u32 o = GetOriginIfPoisoned((uptr)src, d - beg);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
+ *(u32 *)MEM_TO_ORIGIN(beg) = o;
+ }
+ beg += 4;
+ }
+
+ uptr end = (d + size) & ~3UL;
+ // If both ends fall into the same 4-byte slot, we are done.
+ if (end < beg) return;
+
+ // Copy right unaligned origin if that memory is poisoned.
+ if (end < d + size) {
+ u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
+ *(u32 *)MEM_TO_ORIGIN(end) = o;
+ }
+ }
+
+ if (beg < end) {
+ // Align src up.
+ uptr s = ((uptr)src + 3) & ~3UL;
+ // FIXME: factor out to msan_copy_origin_aligned
+ if (__msan_get_track_origins() > 1) {
+ u32 *src = (u32 *)MEM_TO_ORIGIN(s);
+ u32 *src_s = (u32 *)MEM_TO_SHADOW(s);
+ u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));
+ u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);
+ u32 src_o = 0;
+ u32 dst_o = 0;
+ for (; src < src_end; ++src, ++src_s, ++dst) {
+ if (!*src_s) continue;
+ if (*src != src_o) {
+ src_o = *src;
+ dst_o = ChainOrigin(src_o, stack);
+ }
+ *dst = dst_o;
+ }
+ } else {
+ REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
+ end - beg);
+ }
+ }
+}
+
+void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack) {
+ if (!MEM_IS_APP(dst)) return;
+ if (!MEM_IS_APP(src)) return;
+ if (src == dst) return;
+ REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
+}
+
+void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack) {
+ if (!MEM_IS_APP(dst)) return;
+ if (!MEM_IS_APP(src)) return;
+ REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
+}
+
+void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {
+ REAL(memcpy)(dst, src, size);
+ CopyShadowAndOrigin(dst, src, size, stack);
+}
+
+void SetShadow(const void *ptr, uptr size, u8 value) {
+ uptr PageSize = GetPageSizeCached();
+ uptr shadow_beg = MEM_TO_SHADOW(ptr);
+ uptr shadow_end = MEM_TO_SHADOW((uptr)ptr + size);
+ if (value ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_beg = RoundUpTo(shadow_beg, PageSize);
+ uptr page_end = RoundDownTo(shadow_end, PageSize);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ MmapFixedNoReserve(page_beg, page_end - page_beg);
+ }
+ }
+}
+
+void SetOrigin(const void *dst, uptr size, u32 origin) {
+ // Origin mapping is 4 bytes per 4 bytes of application memory.
+ // Here we extend the range such that its left and right bounds are both
+ // 4 byte aligned.
+ uptr x = MEM_TO_ORIGIN((uptr)dst);
+ uptr beg = x & ~3UL; // align down.
+ uptr end = (x + size + 3) & ~3UL; // align up.
+ u64 origin64 = ((u64)origin << 32) | origin;
+ // This is like memset, but the value is 32-bit. We unroll by 2 to write
+ // 64 bits at once. May want to unroll further to get 128-bit stores.
+ if (beg & 7ULL) {
+ *(u32 *)beg = origin;
+ beg += 4;
+ }
+ for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64;
+ if (end & 7ULL) *(u32 *)(end - 4) = origin;
+}
+
+void PoisonMemory(const void *dst, uptr size, StackTrace *stack) {
+ SetShadow(dst, size, (u8)-1);
+
+ if (__msan_get_track_origins()) {
+ Origin o = Origin::CreateHeapOrigin(stack);
+ SetOrigin(dst, size, o.raw_id());
+ }
+}
+
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_poisoning.h b/contrib/compiler-rt/lib/msan/msan_poisoning.h
new file mode 100644
index 000000000000..edacbeeab0a6
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_poisoning.h
@@ -0,0 +1,59 @@
+//===-- msan_poisoning.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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_POISONING_H
+#define MSAN_POISONING_H
+
+#include "msan.h"
+
+namespace __msan {
+
+// Return origin for the first poisoned byte in the memory range, or 0.
+u32 GetOriginIfPoisoned(uptr addr, uptr size);
+
+// Walk [addr, addr+size) app memory region, copying origin tags from the
+// corresponding positions in [src_origin, src_origin+size) where the
+// corresponding shadow in [src_shadow, src_shadow+size) is non-zero.
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, u32 src_origin);
+
+// Copy origin from src (app address) to dst (app address), creating chained
+// origin ids as necessary, without overriding origin for fully initialized
+// quads.
+void CopyOrigin(const void *dst, const void *src, uptr size, StackTrace *stack);
+
+// memmove() shadow and origin. Dst and src are application addresses.
+// See CopyOrigin() for the origin copying logic.
+void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack);
+
+// memcpy() shadow and origin. Dst and src are application addresses.
+// See CopyOrigin() for the origin copying logic.
+void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack);
+
+// memcpy() app memory, and do "the right thing" to the corresponding shadow and
+// origin regions.
+void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack);
+
+// Fill shadow will value. Ptr is an application address.
+void SetShadow(const void *ptr, uptr size, u8 value);
+
+// Set origin for the memory region.
+void SetOrigin(const void *dst, uptr size, u32 origin);
+
+// Mark memory region uninitialized, with origins.
+void PoisonMemory(const void *dst, uptr size, StackTrace *stack);
+
+} // namespace __msan
+
+#endif // MSAN_POISONING_H
diff --git a/contrib/compiler-rt/lib/msan/msan_report.cc b/contrib/compiler-rt/lib/msan/msan_report.cc
new file mode 100644
index 000000000000..33c28b2fba0e
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_report.cc
@@ -0,0 +1,277 @@
+//===-- msan_report.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 MemorySanitizer.
+//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+using namespace __sanitizer;
+
+namespace __msan {
+
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() { }
+ const char *Warning() { return Red(); }
+ const char *Origin() { return Magenta(); }
+ const char *Name() { return Green(); }
+ const char *End() { return Default(); }
+};
+
+static void DescribeStackOrigin(const char *so, uptr pc) {
+ Decorator d;
+ char *s = internal_strdup(so);
+ char *sep = internal_strchr(s, '@');
+ CHECK(sep);
+ *sep = '\0';
+ Printf("%s", d.Origin());
+ Printf(
+ " %sUninitialized value was created by an allocation of '%s%s%s'"
+ " in the stack frame of function '%s%s%s'%s\n",
+ d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
+ d.End());
+ InternalFree(s);
+
+ if (pc) {
+ // For some reason function address in LLVM IR is 1 less then the address
+ // of the first instruction.
+ pc = StackTrace::GetNextInstructionPc(pc);
+ StackTrace(&pc, 1).Print();
+ }
+}
+
+static void DescribeOrigin(u32 id) {
+ VPrintf(1, " raw origin id: %d\n", id);
+ Decorator d;
+ Origin o = Origin::FromRawId(id);
+ while (o.isChainedOrigin()) {
+ StackTrace stack;
+ o = o.getNextChainedOrigin(&stack);
+ Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),
+ d.End());
+ stack.Print();
+ }
+ if (o.isStackOrigin()) {
+ uptr pc;
+ const char *so = GetStackOriginDescr(o.getStackId(), &pc);
+ DescribeStackOrigin(so, pc);
+ } else {
+ StackTrace stack = o.getStackTraceForHeapOrigin();
+ switch (stack.tag) {
+ case StackTrace::TAG_ALLOC:
+ Printf(" %sUninitialized value was created by a heap allocation%s\n",
+ d.Origin(), d.End());
+ break;
+ case StackTrace::TAG_DEALLOC:
+ Printf(" %sUninitialized value was created by a heap deallocation%s\n",
+ d.Origin(), d.End());
+ break;
+ case STACK_TRACE_TAG_POISON:
+ Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(),
+ d.End());
+ break;
+ default:
+ Printf(" %sUninitialized value was created%s\n", d.Origin(), d.End());
+ break;
+ }
+ stack.Print();
+ }
+}
+
+void ReportUMR(StackTrace *stack, u32 origin) {
+ if (!__msan::flags()->report_umrs) return;
+
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
+ Printf("%s", d.End());
+ stack->Print();
+ if (origin) {
+ DescribeOrigin(origin);
+ }
+ ReportErrorSummary("use-of-uninitialized-value", stack);
+}
+
+void ReportExpectedUMRNotFound(StackTrace *stack) {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ Printf(" WARNING: Expected use of uninitialized value not found\n");
+ stack->Print();
+}
+
+void ReportStats() {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ if (__msan_get_track_origins() > 0) {
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ // FIXME: we want this at normal exit, too!
+ // FIXME: but only with verbosity=1 or something
+ Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids);
+ Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats->allocated);
+
+ StackDepotStats *chained_origin_depot_stats = ChainedOriginDepotGetStats();
+ Printf("Unique origin histories: %zu\n",
+ chained_origin_depot_stats->n_uniq_ids);
+ Printf("History depot allocated bytes: %zu\n",
+ chained_origin_depot_stats->allocated);
+ }
+}
+
+void ReportAtExitStatistics() {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ if (msan_report_count > 0) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
+ Printf("%s", d.End());
+ }
+}
+
+class OriginSet {
+ public:
+ OriginSet() : next_id_(0) {}
+ int insert(u32 o) {
+ // Scan from the end for better locality.
+ for (int i = next_id_ - 1; i >= 0; --i)
+ if (origins_[i] == o) return i;
+ if (next_id_ == kMaxSize_) return OVERFLOW;
+ int id = next_id_++;
+ origins_[id] = o;
+ return id;
+ }
+ int size() { return next_id_; }
+ u32 get(int id) { return origins_[id]; }
+ static char asChar(int id) {
+ switch (id) {
+ case MISSING:
+ return '.';
+ case OVERFLOW:
+ return '*';
+ default:
+ return 'A' + id;
+ }
+ }
+ static const int OVERFLOW = -1;
+ static const int MISSING = -2;
+
+ private:
+ static const int kMaxSize_ = 'Z' - 'A' + 1;
+ u32 origins_[kMaxSize_];
+ int next_id_;
+};
+
+void DescribeMemoryRange(const void *x, uptr size) {
+ // Real limits.
+ uptr start = MEM_TO_SHADOW(x);
+ uptr end = start + size;
+ // Scan limits: align start down to 4; align size up to 16.
+ uptr s = start & ~3UL;
+ size = end - s;
+ size = (size + 15) & ~15UL;
+ uptr e = s + size;
+
+ // Single letter names to origin id mapping.
+ OriginSet origin_set;
+
+ uptr pos = 0; // Offset from aligned start.
+ bool with_origins = __msan_get_track_origins();
+ // True if there is at least 1 poisoned bit in the last 4-byte group.
+ bool last_quad_poisoned;
+ int origin_ids[4]; // Single letter origin ids for the current line.
+
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start);
+ Printf("%s", d.End());
+ while (s < e) {
+ // Line start.
+ if (pos % 16 == 0) {
+ for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
+ Printf("%p:", s);
+ }
+ // Group start.
+ if (pos % 4 == 0) {
+ Printf(" ");
+ last_quad_poisoned = false;
+ }
+ // Print shadow byte.
+ if (s < start || s >= end) {
+ Printf("..");
+ } else {
+ unsigned char v = *(unsigned char *)s;
+ if (v) last_quad_poisoned = true;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x", v & 0xf, v >> 4);
+#else
+ Printf("%x%x", v >> 4, v & 0xf);
+#endif
+ }
+ // Group end.
+ if (pos % 4 == 3 && with_origins) {
+ int id = OriginSet::MISSING;
+ if (last_quad_poisoned) {
+ u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
+ id = origin_set.insert(o);
+ }
+ origin_ids[(pos % 16) / 4] = id;
+ }
+ // Line end.
+ if (pos % 16 == 15) {
+ if (with_origins) {
+ Printf(" |");
+ for (int i = 0; i < 4; ++i) {
+ char c = OriginSet::asChar(origin_ids[i]);
+ Printf("%c", c);
+ if (i != 3) Printf(" ");
+ }
+ Printf("|");
+ }
+ Printf("\n");
+ }
+ size--;
+ s++;
+ pos++;
+ }
+
+ Printf("\n");
+
+ for (int i = 0; i < origin_set.size(); ++i) {
+ u32 o = origin_set.get(i);
+ Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
+ DescribeOrigin(o);
+ }
+}
+
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
+ d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
+ d.End());
+ if (__sanitizer::Verbosity())
+ DescribeMemoryRange(start, size);
+}
+
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_thread.cc b/contrib/compiler-rt/lib/msan/msan_thread.cc
new file mode 100644
index 000000000000..e15a247c6bb8
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_thread.cc
@@ -0,0 +1,82 @@
+
+#include "msan.h"
+#include "msan_thread.h"
+#include "msan_interface_internal.h"
+
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __msan {
+
+MsanThread *MsanThread::Create(thread_callback_t start_routine,
+ void *arg) {
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(MsanThread), PageSize);
+ MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__);
+ thread->start_routine_ = start_routine;
+ thread->arg_ = arg;
+ thread->destructor_iterations_ = kPthreadDestructorIterations;
+
+ return thread;
+}
+
+void MsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ uptr stack_size = 0;
+ GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size,
+ &tls_begin_, &tls_size);
+ stack_top_ = stack_bottom_ + stack_size;
+ tls_end_ = tls_begin_ + tls_size;
+
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+}
+
+void MsanThread::ClearShadowForThreadStackAndTLS() {
+ __msan_unpoison((void *)stack_bottom_, stack_top_ - stack_bottom_);
+ if (tls_begin_ != tls_end_)
+ __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_);
+ DTLS *dtls = DTLS_Get();
+ CHECK_NE(dtls, 0);
+ for (uptr i = 0; i < dtls->dtv_size; ++i)
+ __msan_unpoison((void *)(dtls->dtv[i].beg), dtls->dtv[i].size);
+}
+
+void MsanThread::Init() {
+ SetThreadStackAndTls();
+ CHECK(MEM_IS_APP(stack_bottom_));
+ CHECK(MEM_IS_APP(stack_top_ - 1));
+ ClearShadowForThreadStackAndTLS();
+}
+
+void MsanThread::TSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ t->Destroy();
+}
+
+void MsanThread::Destroy() {
+ malloc_storage().CommitBack();
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached());
+ UnmapOrDie(this, size);
+ DTLS_Destroy();
+}
+
+thread_return_t MsanThread::ThreadStart() {
+ Init();
+
+ if (!start_routine_) {
+ // start_routine_ == 0 if we're on the main thread or on one of the
+ // OS X libdispatch worker threads. But nobody is supposed to call
+ // ThreadStart() for the worker threads.
+ return 0;
+ }
+
+ thread_return_t res = start_routine_(arg_);
+
+ return res;
+}
+
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_thread.h b/contrib/compiler-rt/lib/msan/msan_thread.h
new file mode 100644
index 000000000000..bc605b89a505
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/msan_thread.h
@@ -0,0 +1,71 @@
+//===-- msan_thread.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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_THREAD_H
+#define MSAN_THREAD_H
+
+#include "msan_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+class MsanThread {
+ public:
+ static MsanThread *Create(thread_callback_t start_routine, void *arg);
+ static void TSDDtor(void *tsd);
+ void Destroy();
+
+ void Init(); // Should be called from the thread itself.
+ thread_return_t ThreadStart();
+
+ uptr stack_top() { return stack_top_; }
+ uptr stack_bottom() { return stack_bottom_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ bool IsMainThread() { return start_routine_ == 0; }
+
+ bool AddrIsInStack(uptr addr) {
+ return addr >= stack_bottom_ && addr < stack_top_;
+ }
+
+ bool InSignalHandler() { return in_signal_handler_; }
+ void EnterSignalHandler() { in_signal_handler_++; }
+ void LeaveSignalHandler() { in_signal_handler_--; }
+
+ MsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+
+ int destructor_iterations_;
+
+ private:
+ // NOTE: There is no MsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
+ void SetThreadStackAndTls();
+ void ClearShadowForThreadStackAndTLS();
+ thread_callback_t start_routine_;
+ void *arg_;
+ uptr stack_top_;
+ uptr stack_bottom_;
+ uptr tls_begin_;
+ uptr tls_end_;
+
+ unsigned in_signal_handler_;
+
+ MsanThreadLocalMallocStorage malloc_storage_;
+};
+
+MsanThread *GetCurrentThread();
+void SetCurrentThread(MsanThread *t);
+
+} // namespace __msan
+
+#endif // MSAN_THREAD_H
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc b/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc
new file mode 100644
index 000000000000..06e880f90dee
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc
@@ -0,0 +1,27 @@
+//===-- msan_loadable.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 MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#include "msan/msan_interface_internal.h"
+#include <stdlib.h>
+
+static void *dso_global;
+
+// No name mangling.
+extern "C" {
+
+void **get_dso_global() {
+ return &dso_global;
+}
+
+}
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test.cc b/contrib/compiler-rt/lib/msan/tests/msan_test.cc
new file mode 100644
index 000000000000..317f70cbc32e
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/tests/msan_test.cc
@@ -0,0 +1,4285 @@
+//===-- msan_test.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 MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_EXTERNAL_TEST_CONFIG
+#include "msan_test_config.h"
+#endif // MSAN_EXTERNAL_TEST_CONFIG
+
+#include "sanitizer_common/tests/sanitizer_test_utils.h"
+
+#include "sanitizer/allocator_interface.h"
+#include "sanitizer/msan_interface.h"
+
+#if defined(__FreeBSD__)
+# define _KERNEL // To declare 'shminfo' structure.
+# include <sys/shm.h>
+# undef _KERNEL
+extern "C" {
+// <sys/shm.h> doesn't declare these functions in _KERNEL mode.
+void *shmat(int, const void *, int);
+int shmget(key_t, size_t, int);
+int shmctl(int, int, struct shmid_ds *);
+int shmdt(const void *);
+}
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <math.h>
+
+#include <arpa/inet.h>
+#include <dlfcn.h>
+#include <grp.h>
+#include <unistd.h>
+#include <link.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/statvfs.h>
+#include <sys/utsname.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <wordexp.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#if !defined(__FreeBSD__)
+# include <malloc.h>
+# include <sys/sysinfo.h>
+# include <sys/vfs.h>
+# include <mntent.h>
+# include <netinet/ether.h>
+#else
+# include <signal.h>
+# include <netinet/in.h>
+# include <pthread_np.h>
+# include <sys/uio.h>
+# include <sys/mount.h>
+# include <sys/sysctl.h>
+# include <net/ethernet.h>
+# define f_namelen f_namemax // FreeBSD names this statfs field so.
+# define cpu_set_t cpuset_t
+extern "C" {
+// FreeBSD's <ssp/string.h> defines mempcpy() to be a macro expanding into
+// a __builtin___mempcpy_chk() call, but since Msan RTL defines it as an
+// ordinary function, we can declare it here to complete the tests.
+void *mempcpy(void *dest, const void *src, size_t n);
+}
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+# include <emmintrin.h>
+# define MSAN_HAS_M128 1
+#else
+# define MSAN_HAS_M128 0
+#endif
+
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+
+// On FreeBSD procfs is not enabled by default.
+#if defined(__FreeBSD__)
+# define FILE_TO_READ "/bin/cat"
+# define DIR_TO_READ "/bin"
+# define SUBFILE_TO_READ "cat"
+# define SYMLINK_TO_READ "/usr/bin/tar"
+# define SUPERUSER_GROUP "wheel"
+#else
+# define FILE_TO_READ "/proc/self/stat"
+# define DIR_TO_READ "/proc/self"
+# define SUBFILE_TO_READ "stat"
+# define SYMLINK_TO_READ "/proc/self/exe"
+# define SUPERUSER_GROUP "root"
+#endif
+
+const size_t kPageSize = 4096;
+const size_t kMaxPathLength = 4096;
+
+typedef unsigned char U1;
+typedef unsigned short U2; // NOLINT
+typedef unsigned int U4;
+typedef unsigned long long U8; // NOLINT
+typedef signed char S1;
+typedef signed short S2; // NOLINT
+typedef signed int S4;
+typedef signed long long S8; // NOLINT
+#define NOINLINE __attribute__((noinline))
+#define INLINE __attribute__((always_inline))
+
+static bool TrackingOrigins() {
+ S8 x;
+ __msan_set_origin(&x, sizeof(x), 0x1234);
+ U4 origin = __msan_get_origin(&x);
+ __msan_set_origin(&x, sizeof(x), 0);
+ return origin == 0x1234;
+}
+
+#define EXPECT_UMR(action) \
+ do { \
+ __msan_set_expect_umr(1); \
+ action; \
+ __msan_set_expect_umr(0); \
+ } while (0)
+
+#define EXPECT_UMR_O(action, origin) \
+ do { \
+ __msan_set_expect_umr(1); \
+ action; \
+ __msan_set_expect_umr(0); \
+ if (TrackingOrigins()) \
+ EXPECT_EQ(origin, __msan_get_umr_origin()); \
+ } while (0)
+
+#define EXPECT_POISONED(x) ExpectPoisoned(x)
+
+template<typename T>
+void ExpectPoisoned(const T& t) {
+ EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
+}
+
+#define EXPECT_POISONED_O(x, origin) \
+ ExpectPoisonedWithOrigin(x, origin)
+
+template<typename T>
+void ExpectPoisonedWithOrigin(const T& t, unsigned origin) {
+ EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
+ if (TrackingOrigins())
+ EXPECT_EQ(origin, __msan_get_origin((void*)&t));
+}
+
+#define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x)))
+
+template<typename T>
+bool TestForNotPoisoned(const T& t) {
+ return __msan_test_shadow((void*)&t, sizeof(t)) == -1;
+}
+
+static U8 poisoned_array[100];
+template<class T>
+T *GetPoisoned(int i = 0, T val = 0) {
+ T *res = (T*)&poisoned_array[i];
+ *res = val;
+ __msan_poison(&poisoned_array[i], sizeof(T));
+ return res;
+}
+
+template<class T>
+T *GetPoisonedO(int i, U4 origin, T val = 0) {
+ T *res = (T*)&poisoned_array[i];
+ *res = val;
+ __msan_poison(&poisoned_array[i], sizeof(T));
+ __msan_set_origin(&poisoned_array[i], sizeof(T), origin);
+ return res;
+}
+
+template<typename T>
+T Poisoned(T v = 0, T s = (T)(-1)) {
+ __msan_partial_poison(&v, &s, sizeof(T));
+ return v;
+}
+
+template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); }
+
+static volatile int g_one = 1;
+static volatile int g_zero = 0;
+static volatile int g_0 = 0;
+static volatile int g_1 = 1;
+
+S4 a_s4[100];
+S8 a_s8[100];
+
+// Check that malloc poisons memory.
+// A lot of tests below depend on this.
+TEST(MemorySanitizerSanity, PoisonInMalloc) {
+ int *x = (int*)malloc(sizeof(int));
+ EXPECT_POISONED(*x);
+ free(x);
+}
+
+TEST(MemorySanitizer, NegativeTest1) {
+ S4 *x = GetPoisoned<S4>();
+ if (g_one)
+ *x = 0;
+ EXPECT_NOT_POISONED(*x);
+}
+
+TEST(MemorySanitizer, PositiveTest1) {
+ // Load to store.
+ EXPECT_POISONED(*GetPoisoned<S1>());
+ EXPECT_POISONED(*GetPoisoned<S2>());
+ EXPECT_POISONED(*GetPoisoned<S4>());
+ EXPECT_POISONED(*GetPoisoned<S8>());
+
+ // S->S conversions.
+ EXPECT_POISONED(*GetPoisoned<S1>());
+ EXPECT_POISONED(*GetPoisoned<S1>());
+ EXPECT_POISONED(*GetPoisoned<S1>());
+
+ EXPECT_POISONED(*GetPoisoned<S2>());
+ EXPECT_POISONED(*GetPoisoned<S2>());
+ EXPECT_POISONED(*GetPoisoned<S2>());
+
+ EXPECT_POISONED(*GetPoisoned<S4>());
+ EXPECT_POISONED(*GetPoisoned<S4>());
+ EXPECT_POISONED(*GetPoisoned<S4>());
+
+ EXPECT_POISONED(*GetPoisoned<S8>());
+ EXPECT_POISONED(*GetPoisoned<S8>());
+ EXPECT_POISONED(*GetPoisoned<S8>());
+
+ // ZExt
+ EXPECT_POISONED(*GetPoisoned<U1>());
+ EXPECT_POISONED(*GetPoisoned<U1>());
+ EXPECT_POISONED(*GetPoisoned<U1>());
+ EXPECT_POISONED(*GetPoisoned<U2>());
+ EXPECT_POISONED(*GetPoisoned<U2>());
+ EXPECT_POISONED(*GetPoisoned<U4>());
+
+ // Unary ops.
+ EXPECT_POISONED(- *GetPoisoned<S4>());
+
+ EXPECT_UMR(a_s4[g_zero] = 100 / *GetPoisoned<S4>(0, 1));
+
+
+ a_s4[g_zero] = 1 - *GetPoisoned<S4>();
+ a_s4[g_zero] = 1 + *GetPoisoned<S4>();
+}
+
+TEST(MemorySanitizer, Phi1) {
+ S4 c;
+ if (g_one) {
+ c = *GetPoisoned<S4>();
+ } else {
+ break_optimization(0);
+ c = 0;
+ }
+ EXPECT_POISONED(c);
+}
+
+TEST(MemorySanitizer, Phi2) {
+ S4 i = *GetPoisoned<S4>();
+ S4 n = g_one;
+ EXPECT_UMR(for (; i < g_one; i++););
+ EXPECT_POISONED(i);
+}
+
+NOINLINE void Arg1ExpectUMR(S4 a1) { EXPECT_POISONED(a1); }
+NOINLINE void Arg2ExpectUMR(S4 a1, S4 a2) { EXPECT_POISONED(a2); }
+NOINLINE void Arg3ExpectUMR(S1 a1, S4 a2, S8 a3) { EXPECT_POISONED(a3); }
+
+TEST(MemorySanitizer, ArgTest) {
+ Arg1ExpectUMR(*GetPoisoned<S4>());
+ Arg2ExpectUMR(0, *GetPoisoned<S4>());
+ Arg3ExpectUMR(0, 1, *GetPoisoned<S8>());
+}
+
+
+TEST(MemorySanitizer, CallAndRet) {
+ ReturnPoisoned<S1>();
+ ReturnPoisoned<S2>();
+ ReturnPoisoned<S4>();
+ ReturnPoisoned<S8>();
+
+ EXPECT_POISONED(ReturnPoisoned<S1>());
+ EXPECT_POISONED(ReturnPoisoned<S2>());
+ EXPECT_POISONED(ReturnPoisoned<S4>());
+ EXPECT_POISONED(ReturnPoisoned<S8>());
+}
+
+// malloc() in the following test may be optimized to produce a compile-time
+// undef value. Check that we trap on the volatile assignment anyway.
+TEST(MemorySanitizer, DISABLED_MallocNoIdent) {
+ S4 *x = (int*)malloc(sizeof(S4));
+ EXPECT_POISONED(*x);
+ free(x);
+}
+
+TEST(MemorySanitizer, Malloc) {
+ S4 *x = (int*)Ident(malloc(sizeof(S4)));
+ EXPECT_POISONED(*x);
+ free(x);
+}
+
+TEST(MemorySanitizer, Realloc) {
+ S4 *x = (int*)Ident(realloc(0, sizeof(S4)));
+ EXPECT_POISONED(x[0]);
+ x[0] = 1;
+ x = (int*)Ident(realloc(x, 2 * sizeof(S4)));
+ EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
+ EXPECT_POISONED(x[1]);
+ x = (int*)Ident(realloc(x, 3 * sizeof(S4)));
+ EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
+ EXPECT_POISONED(x[2]);
+ EXPECT_POISONED(x[1]);
+ x[2] = 1; // Init this here. Check that after realloc it is poisoned again.
+ x = (int*)Ident(realloc(x, 2 * sizeof(S4)));
+ EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
+ EXPECT_POISONED(x[1]);
+ x = (int*)Ident(realloc(x, 3 * sizeof(S4)));
+ EXPECT_POISONED(x[1]);
+ EXPECT_POISONED(x[2]);
+ free(x);
+}
+
+TEST(MemorySanitizer, Calloc) {
+ S4 *x = (int*)Ident(calloc(1, sizeof(S4)));
+ EXPECT_NOT_POISONED(*x); // Should not be poisoned.
+ EXPECT_EQ(0, *x);
+ free(x);
+}
+
+TEST(MemorySanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+ }
+ }
+}
+
+TEST(MemorySanitizer, AndOr) {
+ U4 *p = GetPoisoned<U4>();
+ // We poison two bytes in the midle of a 4-byte word to make the test
+ // correct regardless of endianness.
+ ((U1*)p)[1] = 0;
+ ((U1*)p)[2] = 0xff;
+ EXPECT_NOT_POISONED(*p & 0x00ffff00);
+ EXPECT_NOT_POISONED(*p & 0x00ff0000);
+ EXPECT_NOT_POISONED(*p & 0x0000ff00);
+ EXPECT_POISONED(*p & 0xff000000);
+ EXPECT_POISONED(*p & 0x000000ff);
+ EXPECT_POISONED(*p & 0x0000ffff);
+ EXPECT_POISONED(*p & 0xffff0000);
+
+ EXPECT_NOT_POISONED(*p | 0xff0000ff);
+ EXPECT_NOT_POISONED(*p | 0xff00ffff);
+ EXPECT_NOT_POISONED(*p | 0xffff00ff);
+ EXPECT_POISONED(*p | 0xff000000);
+ EXPECT_POISONED(*p | 0x000000ff);
+ EXPECT_POISONED(*p | 0x0000ffff);
+ EXPECT_POISONED(*p | 0xffff0000);
+
+ EXPECT_POISONED(*GetPoisoned<bool>() & *GetPoisoned<bool>());
+}
+
+template<class T>
+static bool applyNot(T value, T shadow) {
+ __msan_partial_poison(&value, &shadow, sizeof(T));
+ return !value;
+}
+
+TEST(MemorySanitizer, Not) {
+ EXPECT_NOT_POISONED(applyNot<U4>(0x0, 0x0));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFFFFFFFF, 0x0));
+ EXPECT_POISONED(applyNot<U4>(0xFFFFFFFF, 0xFFFFFFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0FFFFFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00FFFFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0000FFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00000000));
+ EXPECT_POISONED(applyNot<U4>(0xFF000000, 0xFF000000));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF800000, 0xFF000000));
+ EXPECT_POISONED(applyNot<U4>(0x00008000, 0x00008000));
+
+ EXPECT_NOT_POISONED(applyNot<U1>(0x0, 0x0));
+ EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0xFE));
+ EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0x0));
+ EXPECT_POISONED(applyNot<U1>(0xFF, 0xFF));
+
+ EXPECT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-1)));
+ EXPECT_NOT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-2)));
+}
+
+TEST(MemorySanitizer, Shift) {
+ U4 *up = GetPoisoned<U4>();
+ ((U1*)up)[0] = 0;
+ ((U1*)up)[3] = 0xff;
+ EXPECT_NOT_POISONED(*up >> 30);
+ EXPECT_NOT_POISONED(*up >> 24);
+ EXPECT_POISONED(*up >> 23);
+ EXPECT_POISONED(*up >> 10);
+
+ EXPECT_NOT_POISONED(*up << 30);
+ EXPECT_NOT_POISONED(*up << 24);
+ EXPECT_POISONED(*up << 23);
+ EXPECT_POISONED(*up << 10);
+
+ S4 *sp = (S4*)up;
+ EXPECT_NOT_POISONED(*sp >> 30);
+ EXPECT_NOT_POISONED(*sp >> 24);
+ EXPECT_POISONED(*sp >> 23);
+ EXPECT_POISONED(*sp >> 10);
+
+ sp = GetPoisoned<S4>();
+ ((S1*)sp)[1] = 0;
+ ((S1*)sp)[2] = 0;
+ EXPECT_POISONED(*sp >> 31);
+
+ EXPECT_POISONED(100 >> *GetPoisoned<S4>());
+ EXPECT_POISONED(100U >> *GetPoisoned<S4>());
+}
+
+NOINLINE static int GetPoisonedZero() {
+ int *zero = new int;
+ *zero = 0;
+ __msan_poison(zero, sizeof(*zero));
+ int res = *zero;
+ delete zero;
+ return res;
+}
+
+TEST(MemorySanitizer, LoadFromDirtyAddress) {
+ int *a = new int;
+ *a = 0;
+ EXPECT_UMR(break_optimization((void*)(U8)a[GetPoisonedZero()]));
+ delete a;
+}
+
+TEST(MemorySanitizer, StoreToDirtyAddress) {
+ int *a = new int;
+ EXPECT_UMR(a[GetPoisonedZero()] = 0);
+ break_optimization(a);
+ delete a;
+}
+
+
+NOINLINE void StackTestFunc() {
+ S4 p4;
+ S4 ok4 = 1;
+ S2 p2;
+ S2 ok2 = 1;
+ S1 p1;
+ S1 ok1 = 1;
+ break_optimization(&p4);
+ break_optimization(&ok4);
+ break_optimization(&p2);
+ break_optimization(&ok2);
+ break_optimization(&p1);
+ break_optimization(&ok1);
+
+ EXPECT_POISONED(p4);
+ EXPECT_POISONED(p2);
+ EXPECT_POISONED(p1);
+ EXPECT_NOT_POISONED(ok1);
+ EXPECT_NOT_POISONED(ok2);
+ EXPECT_NOT_POISONED(ok4);
+}
+
+TEST(MemorySanitizer, StackTest) {
+ StackTestFunc();
+}
+
+NOINLINE void StackStressFunc() {
+ int foo[10000];
+ break_optimization(foo);
+}
+
+TEST(MemorySanitizer, DISABLED_StackStressTest) {
+ for (int i = 0; i < 1000000; i++)
+ StackStressFunc();
+}
+
+template<class T>
+void TestFloatingPoint() {
+ static volatile T v;
+ static T g[100];
+ break_optimization(&g);
+ T *x = GetPoisoned<T>();
+ T *y = GetPoisoned<T>(1);
+ EXPECT_POISONED(*x);
+ EXPECT_POISONED((long long)*x);
+ EXPECT_POISONED((int)*x);
+ g[0] = *x;
+ g[1] = *x + *y;
+ g[2] = *x - *y;
+ g[3] = *x * *y;
+}
+
+TEST(MemorySanitizer, FloatingPointTest) {
+ TestFloatingPoint<float>();
+ TestFloatingPoint<double>();
+}
+
+TEST(MemorySanitizer, DynMem) {
+ S4 x = 0;
+ S4 *y = GetPoisoned<S4>();
+ memcpy(y, &x, g_one * sizeof(S4));
+ EXPECT_NOT_POISONED(*y);
+}
+
+static char *DynRetTestStr;
+
+TEST(MemorySanitizer, DynRet) {
+ ReturnPoisoned<S8>();
+ EXPECT_NOT_POISONED(atoi("0"));
+}
+
+TEST(MemorySanitizer, DynRet1) {
+ ReturnPoisoned<S8>();
+}
+
+struct LargeStruct {
+ S4 x[10];
+};
+
+NOINLINE
+LargeStruct LargeRetTest() {
+ LargeStruct res;
+ res.x[0] = *GetPoisoned<S4>();
+ res.x[1] = *GetPoisoned<S4>();
+ res.x[2] = *GetPoisoned<S4>();
+ res.x[3] = *GetPoisoned<S4>();
+ res.x[4] = *GetPoisoned<S4>();
+ res.x[5] = *GetPoisoned<S4>();
+ res.x[6] = *GetPoisoned<S4>();
+ res.x[7] = *GetPoisoned<S4>();
+ res.x[8] = *GetPoisoned<S4>();
+ res.x[9] = *GetPoisoned<S4>();
+ return res;
+}
+
+TEST(MemorySanitizer, strcmp) {
+ char s1[10];
+ char s2[10];
+ strncpy(s1, "foo", 10);
+ s2[0] = 'f';
+ s2[1] = 'n';
+ EXPECT_GT(strcmp(s1, s2), 0);
+ s2[1] = 'o';
+ int res;
+ EXPECT_UMR(res = strcmp(s1, s2));
+ EXPECT_NOT_POISONED(res);
+ EXPECT_EQ(strncmp(s1, s2, 1), 0);
+}
+
+TEST(MemorySanitizer, LargeRet) {
+ LargeStruct a = LargeRetTest();
+ EXPECT_POISONED(a.x[0]);
+ EXPECT_POISONED(a.x[9]);
+}
+
+TEST(MemorySanitizer, strerror) {
+ char *buf = strerror(EINVAL);
+ EXPECT_NOT_POISONED(strlen(buf));
+ buf = strerror(123456);
+ EXPECT_NOT_POISONED(strlen(buf));
+}
+
+TEST(MemorySanitizer, strerror_r) {
+ errno = 0;
+ char buf[1000];
+ char *res = (char*) (size_t) strerror_r(EINVAL, buf, sizeof(buf));
+ ASSERT_EQ(0, errno);
+ if (!res) res = buf; // POSIX version success.
+ EXPECT_NOT_POISONED(strlen(res));
+}
+
+TEST(MemorySanitizer, fread) {
+ char *x = new char[32];
+ FILE *f = fopen(FILE_TO_READ, "r");
+ ASSERT_TRUE(f != NULL);
+ fread(x, 1, 32, f);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[16]);
+ EXPECT_NOT_POISONED(x[31]);
+ fclose(f);
+ delete[] x;
+}
+
+TEST(MemorySanitizer, read) {
+ char *x = new char[32];
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = read(fd, x, 32);
+ ASSERT_EQ(sz, 32);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[16]);
+ EXPECT_NOT_POISONED(x[31]);
+ close(fd);
+ delete[] x;
+}
+
+TEST(MemorySanitizer, pread) {
+ char *x = new char[32];
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = pread(fd, x, 32, 0);
+ ASSERT_EQ(sz, 32);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[16]);
+ EXPECT_NOT_POISONED(x[31]);
+ close(fd);
+ delete[] x;
+}
+
+TEST(MemorySanitizer, readv) {
+ char buf[2011];
+ struct iovec iov[2];
+ iov[0].iov_base = buf + 1;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = readv(fd, iov, 2);
+ ASSERT_GE(sz, 0);
+ ASSERT_LE(sz, 5 + 2000);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
+ EXPECT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[1]);
+ EXPECT_NOT_POISONED(buf[5]);
+ EXPECT_POISONED(buf[6]);
+ EXPECT_POISONED(buf[9]);
+ EXPECT_NOT_POISONED(buf[10]);
+ EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+ EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+ close(fd);
+}
+
+TEST(MemorySanitizer, preadv) {
+ char buf[2011];
+ struct iovec iov[2];
+ iov[0].iov_base = buf + 1;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = preadv(fd, iov, 2, 3);
+ ASSERT_GE(sz, 0);
+ ASSERT_LE(sz, 5 + 2000);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
+ EXPECT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[1]);
+ EXPECT_NOT_POISONED(buf[5]);
+ EXPECT_POISONED(buf[6]);
+ EXPECT_POISONED(buf[9]);
+ EXPECT_NOT_POISONED(buf[10]);
+ EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+ EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+ close(fd);
+}
+
+// FIXME: fails now.
+TEST(MemorySanitizer, DISABLED_ioctl) {
+ struct winsize ws;
+ EXPECT_EQ(ioctl(2, TIOCGWINSZ, &ws), 0);
+ EXPECT_NOT_POISONED(ws.ws_col);
+}
+
+TEST(MemorySanitizer, readlink) {
+ char *x = new char[1000];
+ readlink(SYMLINK_TO_READ, x, 1000);
+ EXPECT_NOT_POISONED(x[0]);
+ delete [] x;
+}
+
+TEST(MemorySanitizer, stat) {
+ struct stat* st = new struct stat;
+ int res = stat(FILE_TO_READ, st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st->st_dev);
+ EXPECT_NOT_POISONED(st->st_mode);
+ EXPECT_NOT_POISONED(st->st_size);
+}
+
+TEST(MemorySanitizer, fstatat) {
+ struct stat* st = new struct stat;
+ int dirfd = open(DIR_TO_READ, O_RDONLY);
+ ASSERT_GT(dirfd, 0);
+ int res = fstatat(dirfd, SUBFILE_TO_READ, st, 0);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st->st_dev);
+ EXPECT_NOT_POISONED(st->st_mode);
+ EXPECT_NOT_POISONED(st->st_size);
+ close(dirfd);
+}
+
+TEST(MemorySanitizer, statfs) {
+ struct statfs st;
+ int res = statfs("/", &st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st.f_type);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namelen);
+}
+
+TEST(MemorySanitizer, statvfs) {
+ struct statvfs st;
+ int res = statvfs("/", &st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st.f_bsize);
+ EXPECT_NOT_POISONED(st.f_blocks);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namemax);
+}
+
+TEST(MemorySanitizer, fstatvfs) {
+ struct statvfs st;
+ int fd = open("/", O_RDONLY | O_DIRECTORY);
+ int res = fstatvfs(fd, &st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st.f_bsize);
+ EXPECT_NOT_POISONED(st.f_blocks);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namemax);
+ close(fd);
+}
+
+TEST(MemorySanitizer, pipe) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pipefd[0]);
+ EXPECT_NOT_POISONED(pipefd[1]);
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, pipe2) {
+ int* pipefd = new int[2];
+ int res = pipe2(pipefd, O_NONBLOCK);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pipefd[0]);
+ EXPECT_NOT_POISONED(pipefd[1]);
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, socketpair) {
+ int sv[2];
+ int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(sv[0]);
+ EXPECT_NOT_POISONED(sv[1]);
+ close(sv[0]);
+ close(sv[1]);
+}
+
+TEST(MemorySanitizer, poll) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ char data = 42;
+ res = write(pipefd[1], &data, 1);
+ ASSERT_EQ(1, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipefd[1];
+ fds[1].events = POLLIN;
+ res = poll(fds, 2, 500);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(fds[0].revents);
+ EXPECT_NOT_POISONED(fds[1].revents);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+// There is no ppoll() on FreeBSD.
+#if !defined (__FreeBSD__)
+TEST(MemorySanitizer, ppoll) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ char data = 42;
+ res = write(pipefd[1], &data, 1);
+ ASSERT_EQ(1, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipefd[1];
+ fds[1].events = POLLIN;
+ sigset_t ss;
+ sigemptyset(&ss);
+ res = ppoll(fds, 2, NULL, &ss);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(fds[0].revents);
+ EXPECT_NOT_POISONED(fds[1].revents);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+#endif
+
+TEST(MemorySanitizer, poll_positive) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ // fds[1].fd uninitialized
+ fds[1].events = POLLIN;
+ EXPECT_UMR(poll(fds, 2, 0));
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, bind_getsockname) {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_UNIX;
+ int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai));
+
+ ASSERT_EQ(0, res);
+ char buf[200];
+ socklen_t addrlen;
+ EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen));
+
+ addrlen = sizeof(buf);
+ res = getsockname(sock, (struct sockaddr *)&buf, &addrlen);
+ EXPECT_NOT_POISONED(addrlen);
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[addrlen - 1]);
+ EXPECT_POISONED(buf[addrlen]);
+ close(sock);
+}
+
+TEST(MemorySanitizer, accept) {
+ int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LT(0, listen_socket);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(0, res);
+
+ res = listen(listen_socket, 1);
+ ASSERT_EQ(0, res);
+
+ socklen_t sz = sizeof(sai);
+ res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+
+ int connect_socket = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LT(0, connect_socket);
+ res = fcntl(connect_socket, F_SETFL, O_NONBLOCK);
+ ASSERT_EQ(0, res);
+ res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai));
+ // On FreeBSD this connection completes immediately.
+ if (res != 0) {
+ ASSERT_EQ(-1, res);
+ ASSERT_EQ(EINPROGRESS, errno);
+ }
+
+ __msan_poison(&sai, sizeof(sai));
+ int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_LT(0, new_sock);
+ ASSERT_EQ(sizeof(sai), sz);
+ EXPECT_NOT_POISONED(sai);
+
+ __msan_poison(&sai, sizeof(sai));
+ res = getpeername(new_sock, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+ EXPECT_NOT_POISONED(sai);
+
+ close(new_sock);
+ close(connect_socket);
+ close(listen_socket);
+}
+
+TEST(MemorySanitizer, getaddrinfo) {
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ int res = getaddrinfo("localhost", NULL, &hints, &ai);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(*ai);
+ ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
+ EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr);
+}
+
+TEST(MemorySanitizer, getnameinfo) {
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 80;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ char host[500];
+ char serv[500];
+ int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
+ sizeof(host), serv, sizeof(serv), 0);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(host[0]);
+ EXPECT_POISONED(host[sizeof(host) - 1]);
+
+ ASSERT_NE(0U, strlen(host));
+ EXPECT_NOT_POISONED(serv[0]);
+ EXPECT_POISONED(serv[sizeof(serv) - 1]);
+ ASSERT_NE(0U, strlen(serv));
+}
+
+#define EXPECT_HOSTENT_NOT_POISONED(he) \
+ do { \
+ EXPECT_NOT_POISONED(*(he)); \
+ ASSERT_NE((void *) 0, (he)->h_name); \
+ ASSERT_NE((void *) 0, (he)->h_aliases); \
+ ASSERT_NE((void *) 0, (he)->h_addr_list); \
+ EXPECT_NOT_POISONED(strlen((he)->h_name)); \
+ char **p = (he)->h_aliases; \
+ while (*p) { \
+ EXPECT_NOT_POISONED(strlen(*p)); \
+ ++p; \
+ } \
+ char **q = (he)->h_addr_list; \
+ while (*q) { \
+ EXPECT_NOT_POISONED(*q[0]); \
+ ++q; \
+ } \
+ EXPECT_NOT_POISONED(*q); \
+ } while (0)
+
+TEST(MemorySanitizer, gethostent) {
+ struct hostent *he = gethostent();
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, gethostbyname) {
+ struct hostent *he = gethostbyname("localhost");
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, recvmsg) {
+ int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_LT(0, server_socket);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(0, res);
+
+ socklen_t sz = sizeof(sai);
+ res = getsockname(server_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+
+
+ int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_LT(0, client_socket);
+
+ struct sockaddr_in client_sai;
+ memset(&client_sai, 0, sizeof(client_sai));
+ client_sai.sin_family = AF_INET;
+ client_sai.sin_port = 0;
+ client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai));
+ ASSERT_EQ(0, res);
+
+ sz = sizeof(client_sai);
+ res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(client_sai), sz);
+
+ const char *s = "message text";
+ struct iovec iov;
+ iov.iov_base = (void *)s;
+ iov.iov_len = strlen(s) + 1;
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &sai;
+ msg.msg_namelen = sizeof(sai);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ res = sendmsg(client_socket, &msg, 0);
+ ASSERT_LT(0, res);
+
+
+ char buf[1000];
+ struct iovec recv_iov;
+ recv_iov.iov_base = (void *)&buf;
+ recv_iov.iov_len = sizeof(buf);
+ struct sockaddr_in recv_sai;
+ struct msghdr recv_msg;
+ memset(&recv_msg, 0, sizeof(recv_msg));
+ recv_msg.msg_name = &recv_sai;
+ recv_msg.msg_namelen = sizeof(recv_sai);
+ recv_msg.msg_iov = &recv_iov;
+ recv_msg.msg_iovlen = 1;
+ res = recvmsg(server_socket, &recv_msg, 0);
+ ASSERT_LT(0, res);
+
+ ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen);
+ EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name);
+ EXPECT_STREQ(s, buf);
+
+ close(server_socket);
+ close(client_socket);
+}
+
+TEST(MemorySanitizer, gethostbyname2) {
+ struct hostent *he = gethostbyname2("localhost", AF_INET);
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+TEST(MemorySanitizer, gethostbyaddr) {
+ in_addr_t addr = inet_addr("127.0.0.1");
+ EXPECT_NOT_POISONED(addr);
+ struct hostent *he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+TEST(MemorySanitizer, gethostent_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostent_r(&he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("bad-host-name", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ((struct hostent *)0, result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r_erange) {
+ char buf[5];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(ERANGE, res);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname2_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname2_r("localhost", AF_INET, &he, buf, sizeof(buf),
+ &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyaddr_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ in_addr_t addr = inet_addr("127.0.0.1");
+ EXPECT_NOT_POISONED(addr);
+ int res = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &he, buf, sizeof(buf),
+ &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, getsockopt) {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ struct linger l[2];
+ socklen_t sz = sizeof(l[0]);
+ int res = getsockopt(sock, SOL_SOCKET, SO_LINGER, &l[0], &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(l[0]), sz);
+ EXPECT_NOT_POISONED(l[0]);
+ EXPECT_POISONED(*(char *)(l + 1));
+}
+
+TEST(MemorySanitizer, getcwd) {
+ char path[PATH_MAX + 1];
+ char* res = getcwd(path, sizeof(path));
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(path[0]);
+}
+
+TEST(MemorySanitizer, getcwd_gnu) {
+ char* res = getcwd(NULL, 0);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+// There's no get_current_dir_name() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, get_current_dir_name) {
+ char* res = get_current_dir_name();
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+#endif
+
+TEST(MemorySanitizer, shmctl) {
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ ASSERT_GT(id, -1);
+
+ struct shmid_ds ds;
+ int res = shmctl(id, IPC_STAT, &ds);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(ds);
+
+ // FreeBSD does not support shmctl(IPC_INFO) and shmctl(SHM_INFO).
+#if !defined(__FreeBSD__)
+ struct shminfo si;
+ res = shmctl(id, IPC_INFO, (struct shmid_ds *)&si);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(si);
+
+ struct shm_info s_i;
+ res = shmctl(id, SHM_INFO, (struct shmid_ds *)&s_i);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(s_i);
+#endif
+
+ res = shmctl(id, IPC_RMID, 0);
+ ASSERT_GT(res, -1);
+}
+
+TEST(MemorySanitizer, shmat) {
+ void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, p);
+
+ ((char *)p)[10] = *GetPoisoned<U1>();
+ ((char *)p)[4095] = *GetPoisoned<U1>();
+
+ int res = munmap(p, 4096);
+ ASSERT_EQ(0, res);
+
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ ASSERT_GT(id, -1);
+
+ void *q = shmat(id, p, 0);
+ ASSERT_EQ(p, q);
+
+ EXPECT_NOT_POISONED(((char *)q)[0]);
+ EXPECT_NOT_POISONED(((char *)q)[10]);
+ EXPECT_NOT_POISONED(((char *)q)[4095]);
+
+ res = shmdt(q);
+ ASSERT_EQ(0, res);
+
+ res = shmctl(id, IPC_RMID, 0);
+ ASSERT_GT(res, -1);
+}
+
+// There's no random_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, random_r) {
+ int32_t x;
+ char z[64];
+ memset(z, 0, sizeof(z));
+
+ struct random_data buf;
+ memset(&buf, 0, sizeof(buf));
+
+ int res = initstate_r(0, z, sizeof(z), &buf);
+ ASSERT_EQ(0, res);
+
+ res = random_r(&buf, &x);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(x);
+}
+#endif
+
+TEST(MemorySanitizer, confstr) {
+ char buf[3];
+ size_t res = confstr(_CS_PATH, buf, sizeof(buf));
+ ASSERT_GT(res, sizeof(buf));
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[sizeof(buf) - 1]);
+
+ char buf2[1000];
+ res = confstr(_CS_PATH, buf2, sizeof(buf2));
+ ASSERT_LT(res, sizeof(buf2));
+ EXPECT_NOT_POISONED(buf2[0]);
+ EXPECT_NOT_POISONED(buf2[res - 1]);
+ EXPECT_POISONED(buf2[res]);
+ ASSERT_EQ(res, strlen(buf2) + 1);
+}
+
+TEST(MemorySanitizer, opendir) {
+ DIR *dir = opendir(".");
+ closedir(dir);
+
+ char name[10] = ".";
+ __msan_poison(name, sizeof(name));
+ EXPECT_UMR(dir = opendir(name));
+ closedir(dir);
+}
+
+TEST(MemorySanitizer, readdir) {
+ DIR *dir = opendir(".");
+ struct dirent *d = readdir(dir);
+ ASSERT_TRUE(d != NULL);
+ EXPECT_NOT_POISONED(d->d_name[0]);
+ closedir(dir);
+}
+
+TEST(MemorySanitizer, readdir_r) {
+ DIR *dir = opendir(".");
+ struct dirent d;
+ struct dirent *pd;
+ int res = readdir_r(dir, &d, &pd);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pd);
+ EXPECT_NOT_POISONED(d.d_name[0]);
+ closedir(dir);
+}
+
+TEST(MemorySanitizer, realpath) {
+ const char* relpath = ".";
+ char path[PATH_MAX + 1];
+ char* res = realpath(relpath, path);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(path[0]);
+}
+
+TEST(MemorySanitizer, realpath_null) {
+ const char* relpath = ".";
+ char* res = realpath(relpath, NULL);
+ printf("%d, %s\n", errno, strerror(errno));
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+// There's no canonicalize_file_name() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, canonicalize_file_name) {
+ const char* relpath = ".";
+ char* res = canonicalize_file_name(relpath);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+#endif
+
+extern char **environ;
+
+TEST(MemorySanitizer, setenv) {
+ setenv("AAA", "BBB", 1);
+ for (char **envp = environ; *envp; ++envp) {
+ EXPECT_NOT_POISONED(*envp);
+ EXPECT_NOT_POISONED(*envp[0]);
+ }
+}
+
+TEST(MemorySanitizer, putenv) {
+ char s[] = "AAA=BBB";
+ putenv(s);
+ for (char **envp = environ; *envp; ++envp) {
+ EXPECT_NOT_POISONED(*envp);
+ EXPECT_NOT_POISONED(*envp[0]);
+ }
+}
+
+TEST(MemorySanitizer, memcpy) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ memcpy(y, x, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
+void TestUnalignedMemcpy(unsigned left, unsigned right, bool src_is_aligned,
+ bool src_is_poisoned, bool dst_is_poisoned) {
+ fprintf(stderr, "%s(%d, %d, %d, %d, %d)\n", __func__, left, right,
+ src_is_aligned, src_is_poisoned, dst_is_poisoned);
+
+ const unsigned sz = 20;
+ U4 dst_origin, src_origin;
+ char *dst = (char *)malloc(sz);
+ if (dst_is_poisoned)
+ dst_origin = __msan_get_origin(dst);
+ else
+ memset(dst, 0, sz);
+
+ char *src = (char *)malloc(sz);
+ if (src_is_poisoned)
+ src_origin = __msan_get_origin(src);
+ else
+ memset(src, 0, sz);
+
+ memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right);
+
+ for (unsigned i = 0; i < (left & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[i], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
+
+ for (unsigned i = 0; i < (right & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[sz - i - 1], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[sz - i - 1]);
+
+ for (unsigned i = left; i < sz - right; ++i)
+ if (src_is_poisoned)
+ EXPECT_POISONED_O(dst[i], src_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
+
+ free(dst);
+ free(src);
+}
+
+TEST(MemorySanitizer, memcpy_unaligned) {
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ for (int aligned = 0; aligned < 2; ++aligned)
+ for (int srcp = 0; srcp < 2; ++srcp)
+ for (int dstp = 0; dstp < 2; ++dstp)
+ TestUnalignedMemcpy(i, j, aligned, srcp, dstp);
+}
+
+TEST(MemorySanitizer, memmove) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ memmove(y, x, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
+TEST(MemorySanitizer, memccpy_nomatch) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ memccpy(y, x, 'd', 4);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_NOT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_match) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ memccpy(y, x, 'b', 4);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_NOT_POISONED(y[1]);
+ EXPECT_POISONED(y[2]);
+ EXPECT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_nomatch_positive) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ EXPECT_UMR(memccpy(y, x, 'd', 5));
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_match_positive) {
+ char* x = new char[5];
+ char* y = new char[5];
+ x[0] = 'a';
+ x[2] = 'b';
+ EXPECT_UMR(memccpy(y, x, 'b', 5));
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, bcopy) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ bcopy(x, y, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
+TEST(MemorySanitizer, strdup) {
+ char buf[4] = "abc";
+ __msan_poison(buf + 2, sizeof(*buf));
+ char *x = strdup(buf);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[1]);
+ EXPECT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+ free(x);
+}
+
+TEST(MemorySanitizer, strndup) {
+ char buf[4] = "abc";
+ __msan_poison(buf + 2, sizeof(*buf));
+ char *x = strndup(buf, 3);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[1]);
+ EXPECT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+ free(x);
+}
+
+TEST(MemorySanitizer, strndup_short) {
+ char buf[4] = "abc";
+ __msan_poison(buf + 1, sizeof(*buf));
+ __msan_poison(buf + 2, sizeof(*buf));
+ char *x = strndup(buf, 2);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_POISONED(x[1]);
+ EXPECT_NOT_POISONED(x[2]);
+ free(x);
+}
+
+
+template<class T, int size>
+void TestOverlapMemmove() {
+ T *x = new T[size];
+ ASSERT_GE(size, 3);
+ x[2] = 0;
+ memmove(x, x + 1, (size - 1) * sizeof(T));
+ EXPECT_NOT_POISONED(x[1]);
+ EXPECT_POISONED(x[0]);
+ EXPECT_POISONED(x[2]);
+ delete [] x;
+}
+
+TEST(MemorySanitizer, overlap_memmove) {
+ TestOverlapMemmove<U1, 10>();
+ TestOverlapMemmove<U1, 1000>();
+ TestOverlapMemmove<U8, 4>();
+ TestOverlapMemmove<U8, 1000>();
+}
+
+TEST(MemorySanitizer, strcpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[3];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = 0;
+ strcpy(y, x); // NOLINT
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+}
+
+TEST(MemorySanitizer, strncpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[5];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = '\0';
+ strncpy(y, x, 4); // NOLINT
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+}
+
+TEST(MemorySanitizer, stpcpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[3];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = 0;
+ char *res = stpcpy(y, x); // NOLINT
+ ASSERT_EQ(res, y + 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+}
+
+TEST(MemorySanitizer, strcat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strcat(a, b);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 5);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat_overflow) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 2);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+#define TEST_STRTO_INT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_EQ(1U, func_name(str_prefix##"1", &e, 10)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
+
+#define TEST_STRTO_FLOAT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
+
+#define TEST_STRTO_FLOAT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+#define TEST_STRTO_INT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ ASSERT_EQ(1U, func_name(str_prefix##"1", &e, 10, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+TEST_STRTO_INT(strtol, char, )
+TEST_STRTO_INT(strtoll, char, )
+TEST_STRTO_INT(strtoul, char, )
+TEST_STRTO_INT(strtoull, char, )
+
+TEST_STRTO_FLOAT(strtof, char, )
+TEST_STRTO_FLOAT(strtod, char, )
+TEST_STRTO_FLOAT(strtold, char, )
+
+TEST_STRTO_FLOAT_LOC(strtof_l, char, )
+TEST_STRTO_FLOAT_LOC(strtod_l, char, )
+TEST_STRTO_FLOAT_LOC(strtold_l, char, )
+
+TEST_STRTO_INT_LOC(strtol_l, char, )
+TEST_STRTO_INT_LOC(strtoll_l, char, )
+TEST_STRTO_INT_LOC(strtoul_l, char, )
+TEST_STRTO_INT_LOC(strtoull_l, char, )
+
+TEST_STRTO_INT(wcstol, wchar_t, L)
+TEST_STRTO_INT(wcstoll, wchar_t, L)
+TEST_STRTO_INT(wcstoul, wchar_t, L)
+TEST_STRTO_INT(wcstoull, wchar_t, L)
+
+TEST_STRTO_FLOAT(wcstof, wchar_t, L)
+TEST_STRTO_FLOAT(wcstod, wchar_t, L)
+TEST_STRTO_FLOAT(wcstold, wchar_t, L)
+
+TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L)
+
+TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L)
+
+
+TEST(MemorySanitizer, strtoimax) {
+ char *e;
+ ASSERT_EQ(1, strtoimax("1", &e, 10));
+ EXPECT_NOT_POISONED((S8) e);
+}
+
+TEST(MemorySanitizer, strtoumax) {
+ char *e;
+ ASSERT_EQ(1U, strtoumax("1", &e, 10));
+ EXPECT_NOT_POISONED((S8) e);
+}
+
+#ifdef __GLIBC__
+extern "C" float __strtof_l(const char *nptr, char **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtof_l, char, )
+extern "C" double __strtod_l(const char *nptr, char **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtod_l, char, )
+extern "C" long double __strtold_l(const char *nptr, char **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtold_l, char, )
+
+extern "C" float __wcstof_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstof_l, wchar_t, L)
+extern "C" double __wcstod_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstod_l, wchar_t, L)
+extern "C" long double __wcstold_l(const wchar_t *nptr, wchar_t **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstold_l, wchar_t, L)
+#endif // __GLIBC__
+
+TEST(MemorySanitizer, modf) {
+ double x, y;
+ x = modf(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modff) {
+ float x, y;
+ x = modff(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modfl) {
+ long double x, y;
+ x = modfl(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+// There's no sincos() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sincos) {
+ double s, c;
+ sincos(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+#endif
+
+// There's no sincosf() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sincosf) {
+ float s, c;
+ sincosf(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+#endif
+
+// There's no sincosl() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sincosl) {
+ long double s, c;
+ sincosl(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+#endif
+
+TEST(MemorySanitizer, remquo) {
+ int quo;
+ double res = remquo(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, remquof) {
+ int quo;
+ float res = remquof(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, remquol) {
+ int quo;
+ long double res = remquof(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, lgamma) {
+ double res = lgamma(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgammaf) {
+ float res = lgammaf(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgammal) {
+ long double res = lgammal(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgamma_r) {
+ int sgn;
+ double res = lgamma_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+TEST(MemorySanitizer, lgammaf_r) {
+ int sgn;
+ float res = lgammaf_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+// There's no lgammal_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, lgammal_r) {
+ int sgn;
+ long double res = lgammal_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+#endif
+
+// There's no drand48_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, drand48_r) {
+ struct drand48_data buf;
+ srand48_r(0, &buf);
+ double d;
+ drand48_r(&buf, &d);
+ EXPECT_NOT_POISONED(d);
+}
+#endif
+
+// There's no lrand48_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, lrand48_r) {
+ struct drand48_data buf;
+ srand48_r(0, &buf);
+ long d;
+ lrand48_r(&buf, &d);
+ EXPECT_NOT_POISONED(d);
+}
+#endif
+
+TEST(MemorySanitizer, sprintf) { // NOLINT
+ char buff[10];
+ break_optimization(buff);
+ EXPECT_POISONED(buff[0]);
+ int res = sprintf(buff, "%d", 1234567); // NOLINT
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
+ EXPECT_POISONED(buff[8]);
+}
+
+TEST(MemorySanitizer, snprintf) {
+ char buff[10];
+ break_optimization(buff);
+ EXPECT_POISONED(buff[0]);
+ int res = snprintf(buff, sizeof(buff), "%d", 1234567);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
+ EXPECT_POISONED(buff[8]);
+}
+
+TEST(MemorySanitizer, swprintf) {
+ wchar_t buff[10];
+ ASSERT_EQ(4U, sizeof(wchar_t));
+ break_optimization(buff);
+ EXPECT_POISONED(buff[0]);
+ int res = swprintf(buff, 9, L"%d", 1234567);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
+ EXPECT_POISONED(buff[8]);
+}
+
+TEST(MemorySanitizer, asprintf) { // NOLINT
+ char *pbuf;
+ EXPECT_POISONED(pbuf);
+ int res = asprintf(&pbuf, "%d", 1234567); // NOLINT
+ ASSERT_EQ(res, 7);
+ EXPECT_NOT_POISONED(pbuf);
+ ASSERT_EQ(pbuf[0], '1');
+ ASSERT_EQ(pbuf[1], '2');
+ ASSERT_EQ(pbuf[2], '3');
+ ASSERT_EQ(pbuf[6], '7');
+ ASSERT_EQ(pbuf[7], 0);
+ free(pbuf);
+}
+
+TEST(MemorySanitizer, mbstowcs) {
+ const char *x = "abc";
+ wchar_t buff[10];
+ int res = mbstowcs(buff, x, 2);
+ EXPECT_EQ(2, res);
+ EXPECT_EQ(L'a', buff[0]);
+ EXPECT_EQ(L'b', buff[1]);
+ EXPECT_POISONED(buff[2]);
+ res = mbstowcs(buff, x, 10);
+ EXPECT_EQ(3, res);
+ EXPECT_NOT_POISONED(buff[3]);
+}
+
+TEST(MemorySanitizer, wcstombs) {
+ const wchar_t *x = L"abc";
+ char buff[10];
+ int res = wcstombs(buff, x, 4);
+ EXPECT_EQ(res, 3);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_EQ(buff[2], 'c');
+}
+
+TEST(MemorySanitizer, wcsrtombs) {
+ const wchar_t *x = L"abc";
+ const wchar_t *p = x;
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = wcsrtombs(buff, &p, 4, &mbs);
+ EXPECT_EQ(res, 3);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_EQ(buff[2], 'c');
+ EXPECT_EQ(buff[3], '\0');
+ EXPECT_POISONED(buff[4]);
+}
+
+TEST(MemorySanitizer, wcsnrtombs) {
+ const wchar_t *x = L"abc";
+ const wchar_t *p = x;
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = wcsnrtombs(buff, &p, 2, 4, &mbs);
+ EXPECT_EQ(res, 2);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_POISONED(buff[2]);
+}
+
+TEST(MemorySanitizer, wmemset) {
+ wchar_t x[25];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ wmemset(x, L'A', 10);
+ EXPECT_EQ(x[0], L'A');
+ EXPECT_EQ(x[9], L'A');
+ EXPECT_POISONED(x[10]);
+}
+
+TEST(MemorySanitizer, mbtowc) {
+ const char *x = "abc";
+ wchar_t wx;
+ int res = mbtowc(&wx, x, 3);
+ EXPECT_GT(res, 0);
+ EXPECT_NOT_POISONED(wx);
+}
+
+TEST(MemorySanitizer, mbrtowc) {
+ const char *x = "abc";
+ wchar_t wx;
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = mbrtowc(&wx, x, 3, &mbs);
+ EXPECT_GT(res, 0);
+ EXPECT_NOT_POISONED(wx);
+}
+
+TEST(MemorySanitizer, wcsftime) {
+ wchar_t x[100];
+ time_t t = time(NULL);
+ struct tm tms;
+ struct tm *tmres = localtime_r(&t, &tms);
+ ASSERT_NE((void *)0, tmres);
+ size_t res = wcsftime(x, sizeof(x) / sizeof(x[0]), L"%Y-%m-%d", tmres);
+ EXPECT_GT(res, 0UL);
+ EXPECT_EQ(res, wcslen(x));
+}
+
+TEST(MemorySanitizer, gettimeofday) {
+ struct timeval tv;
+ struct timezone tz;
+ break_optimization(&tv);
+ break_optimization(&tz);
+ ASSERT_EQ(16U, sizeof(tv));
+ ASSERT_EQ(8U, sizeof(tz));
+ EXPECT_POISONED(tv.tv_sec);
+ EXPECT_POISONED(tv.tv_usec);
+ EXPECT_POISONED(tz.tz_minuteswest);
+ EXPECT_POISONED(tz.tz_dsttime);
+ ASSERT_EQ(0, gettimeofday(&tv, &tz));
+ EXPECT_NOT_POISONED(tv.tv_sec);
+ EXPECT_NOT_POISONED(tv.tv_usec);
+ EXPECT_NOT_POISONED(tz.tz_minuteswest);
+ EXPECT_NOT_POISONED(tz.tz_dsttime);
+}
+
+TEST(MemorySanitizer, clock_gettime) {
+ struct timespec tp;
+ EXPECT_POISONED(tp.tv_sec);
+ EXPECT_POISONED(tp.tv_nsec);
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
+ EXPECT_NOT_POISONED(tp.tv_sec);
+ EXPECT_NOT_POISONED(tp.tv_nsec);
+}
+
+TEST(MemorySanitizer, clock_getres) {
+ struct timespec tp;
+ EXPECT_POISONED(tp.tv_sec);
+ EXPECT_POISONED(tp.tv_nsec);
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, 0));
+ EXPECT_POISONED(tp.tv_sec);
+ EXPECT_POISONED(tp.tv_nsec);
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &tp));
+ EXPECT_NOT_POISONED(tp.tv_sec);
+ EXPECT_NOT_POISONED(tp.tv_nsec);
+}
+
+TEST(MemorySanitizer, getitimer) {
+ struct itimerval it1, it2;
+ int res;
+ EXPECT_POISONED(it1.it_interval.tv_sec);
+ EXPECT_POISONED(it1.it_interval.tv_usec);
+ EXPECT_POISONED(it1.it_value.tv_sec);
+ EXPECT_POISONED(it1.it_value.tv_usec);
+ res = getitimer(ITIMER_VIRTUAL, &it1);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(it1.it_interval.tv_sec);
+ EXPECT_NOT_POISONED(it1.it_interval.tv_usec);
+ EXPECT_NOT_POISONED(it1.it_value.tv_sec);
+ EXPECT_NOT_POISONED(it1.it_value.tv_usec);
+
+ it1.it_interval.tv_sec = it1.it_value.tv_sec = 10000;
+ it1.it_interval.tv_usec = it1.it_value.tv_usec = 0;
+
+ res = setitimer(ITIMER_VIRTUAL, &it1, &it2);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(it2.it_interval.tv_sec);
+ EXPECT_NOT_POISONED(it2.it_interval.tv_usec);
+ EXPECT_NOT_POISONED(it2.it_value.tv_sec);
+ EXPECT_NOT_POISONED(it2.it_value.tv_usec);
+
+ // Check that old_value can be 0, and disable the timer.
+ memset(&it1, 0, sizeof(it1));
+ res = setitimer(ITIMER_VIRTUAL, &it1, 0);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, setitimer_null) {
+ setitimer(ITIMER_VIRTUAL, 0, 0);
+ // Not testing the return value, since it the behaviour seems to differ
+ // between libc implementations and POSIX.
+ // Should never crash, though.
+}
+
+TEST(MemorySanitizer, time) {
+ time_t t;
+ EXPECT_POISONED(t);
+ time_t t2 = time(&t);
+ ASSERT_NE(t2, (time_t)-1);
+ EXPECT_NOT_POISONED(t);
+}
+
+TEST(MemorySanitizer, strptime) {
+ struct tm time;
+ char *p = strptime("11/1/2013-05:39", "%m/%d/%Y-%H:%M", &time);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(time.tm_sec);
+ EXPECT_NOT_POISONED(time.tm_hour);
+ EXPECT_NOT_POISONED(time.tm_year);
+}
+
+TEST(MemorySanitizer, localtime) {
+ time_t t = 123;
+ struct tm *time = localtime(&t);
+ ASSERT_TRUE(time != NULL);
+ EXPECT_NOT_POISONED(time->tm_sec);
+ EXPECT_NOT_POISONED(time->tm_hour);
+ EXPECT_NOT_POISONED(time->tm_year);
+ EXPECT_NOT_POISONED(time->tm_isdst);
+ EXPECT_NE(0U, strlen(time->tm_zone));
+}
+
+TEST(MemorySanitizer, localtime_r) {
+ time_t t = 123;
+ struct tm time;
+ struct tm *res = localtime_r(&t, &time);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(time.tm_sec);
+ EXPECT_NOT_POISONED(time.tm_hour);
+ EXPECT_NOT_POISONED(time.tm_year);
+ EXPECT_NOT_POISONED(time.tm_isdst);
+ EXPECT_NE(0U, strlen(time.tm_zone));
+}
+
+// There's no getmntent() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, getmntent) {
+ FILE *fp = setmntent("/etc/fstab", "r");
+ struct mntent *mnt = getmntent(fp);
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
+ EXPECT_NOT_POISONED(mnt->mnt_freq);
+ EXPECT_NOT_POISONED(mnt->mnt_passno);
+ fclose(fp);
+}
+#endif
+
+// There's no getmntent_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, getmntent_r) {
+ FILE *fp = setmntent("/etc/fstab", "r");
+ struct mntent mntbuf;
+ char buf[1000];
+ struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf));
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
+ EXPECT_NOT_POISONED(mnt->mnt_freq);
+ EXPECT_NOT_POISONED(mnt->mnt_passno);
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, ether) {
+ const char *asc = "11:22:33:44:55:66";
+ struct ether_addr *paddr = ether_aton(asc);
+ EXPECT_NOT_POISONED(*paddr);
+
+ struct ether_addr addr;
+ paddr = ether_aton_r(asc, &addr);
+ ASSERT_EQ(paddr, &addr);
+ EXPECT_NOT_POISONED(addr);
+
+ char *s = ether_ntoa(&addr);
+ ASSERT_NE(0U, strlen(s));
+
+ char buf[100];
+ s = ether_ntoa_r(&addr, buf);
+ ASSERT_EQ(s, buf);
+ ASSERT_NE(0U, strlen(buf));
+}
+
+TEST(MemorySanitizer, mmap) {
+ const int size = 4096;
+ void *p1, *p2;
+ p1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+ __msan_poison(p1, size);
+ munmap(p1, size);
+ for (int i = 0; i < 1000; i++) {
+ p2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p2 == p1)
+ break;
+ else
+ munmap(p2, size);
+ }
+ if (p1 == p2) {
+ EXPECT_NOT_POISONED(*(char*)p2);
+ munmap(p2, size);
+ }
+}
+
+// There's no fcvt() on FreeBSD.
+#if !defined(__FreeBSD__)
+// FIXME: enable and add ecvt.
+// FIXME: check why msandr does nt handle fcvt.
+TEST(MemorySanitizer, fcvt) {
+ int a, b;
+ break_optimization(&a);
+ break_optimization(&b);
+ EXPECT_POISONED(a);
+ EXPECT_POISONED(b);
+ char *str = fcvt(12345.6789, 10, &a, &b);
+ EXPECT_NOT_POISONED(a);
+ EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+#endif
+
+// There's no fcvt_long() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fcvt_long) {
+ int a, b;
+ break_optimization(&a);
+ break_optimization(&b);
+ EXPECT_POISONED(a);
+ EXPECT_POISONED(b);
+ char *str = fcvt(111111112345.6789, 10, &a, &b);
+ EXPECT_NOT_POISONED(a);
+ EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+#endif
+
+TEST(MemorySanitizer, memchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[2] = '2';
+ void *res;
+ EXPECT_UMR(res = memchr(x, '2', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memchr(x, '2', 10);
+ EXPECT_EQ(&x[2], res);
+ EXPECT_UMR(res = memchr(x, '3', 10));
+ EXPECT_NOT_POISONED(res);
+}
+
+TEST(MemorySanitizer, memrchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[9] = '9';
+ void *res;
+ EXPECT_UMR(res = memrchr(x, '9', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memrchr(x, '0', 2);
+ EXPECT_EQ(&x[0], res);
+ EXPECT_UMR(res = memrchr(x, '7', 10));
+ EXPECT_NOT_POISONED(res);
+}
+
+TEST(MemorySanitizer, frexp) {
+ int x;
+ x = *GetPoisoned<int>();
+ double r = frexp(1.1, &x);
+ EXPECT_NOT_POISONED(r);
+ EXPECT_NOT_POISONED(x);
+
+ x = *GetPoisoned<int>();
+ float rf = frexpf(1.1, &x);
+ EXPECT_NOT_POISONED(rf);
+ EXPECT_NOT_POISONED(x);
+
+ x = *GetPoisoned<int>();
+ double rl = frexpl(1.1, &x);
+ EXPECT_NOT_POISONED(rl);
+ EXPECT_NOT_POISONED(x);
+}
+
+namespace {
+
+static int cnt;
+
+void SigactionHandler(int signo, siginfo_t* si, void* uc) {
+ ASSERT_EQ(signo, SIGPROF);
+ ASSERT_TRUE(si != NULL);
+ EXPECT_NOT_POISONED(si->si_errno);
+ EXPECT_NOT_POISONED(si->si_pid);
+#if __linux__
+# if defined(__x86_64__)
+ EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]);
+# elif defined(__i386__)
+ EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]);
+# endif
+#endif
+ ++cnt;
+}
+
+TEST(MemorySanitizer, sigaction) {
+ struct sigaction act = {};
+ struct sigaction oldact = {};
+ struct sigaction origact = {};
+
+ sigaction(SIGPROF, 0, &origact);
+
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction = &SigactionHandler;
+ sigaction(SIGPROF, &act, 0);
+
+ kill(getpid(), SIGPROF);
+
+ act.sa_flags &= ~SA_SIGINFO;
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGPROF, &act, 0);
+
+ act.sa_flags &= ~SA_SIGINFO;
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPROF, &act, &oldact);
+ EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
+ EXPECT_EQ(SIG_DFL, oldact.sa_handler);
+ kill(getpid(), SIGPROF);
+
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction = &SigactionHandler;
+ sigaction(SIGPROF, &act, &oldact);
+ EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
+ EXPECT_EQ(SIG_IGN, oldact.sa_handler);
+ kill(getpid(), SIGPROF);
+
+ act.sa_flags &= ~SA_SIGINFO;
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGPROF, &act, &oldact);
+ EXPECT_TRUE(oldact.sa_flags & SA_SIGINFO);
+ EXPECT_EQ(&SigactionHandler, oldact.sa_sigaction);
+ EXPECT_EQ(2, cnt);
+
+ sigaction(SIGPROF, &origact, 0);
+}
+
+} // namespace
+
+
+TEST(MemorySanitizer, sigemptyset) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigemptyset(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigfillset) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigfillset(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigpending) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigpending(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigprocmask) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigprocmask(SIG_BLOCK, 0, &s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+struct StructWithDtor {
+ ~StructWithDtor();
+};
+
+NOINLINE StructWithDtor::~StructWithDtor() {
+ break_optimization(0);
+}
+
+TEST(MemorySanitizer, Invoke) {
+ StructWithDtor s; // Will cause the calls to become invokes.
+ EXPECT_NOT_POISONED(0);
+ EXPECT_POISONED(*GetPoisoned<int>());
+ EXPECT_NOT_POISONED(0);
+ EXPECT_POISONED(*GetPoisoned<int>());
+ EXPECT_POISONED(ReturnPoisoned<S4>());
+}
+
+TEST(MemorySanitizer, ptrtoint) {
+ // Test that shadow is propagated through pointer-to-integer conversion.
+ void* p = (void*)0xABCD;
+ __msan_poison(((char*)&p) + 1, sizeof(p));
+ EXPECT_NOT_POISONED((((uintptr_t)p) & 0xFF) == 0);
+
+ void* q = (void*)0xABCD;
+ __msan_poison(&q, sizeof(q) - 1);
+ EXPECT_POISONED((((uintptr_t)q) & 0xFF) == 0);
+}
+
+static void vaargsfn2(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, double));
+ va_end(vl);
+}
+
+static void vaargsfn(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ // The following call will overwrite __msan_param_tls.
+ // Checks after it test that arg shadow was somehow saved across the call.
+ vaargsfn2(1, 2, 3, 4, *GetPoisoned<double>());
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgTest) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn(1, 13, *x, 42, *y);
+}
+
+static void vaargsfn_many(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgManyTest) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn_many(1, 2, *x, 3, 4, 5, 6, 7, 8, 9, *y);
+}
+
+static void vaargsfn_pass2(va_list vl) {
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+}
+
+static void vaargsfn_pass(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_POISONED(va_arg(vl, int));
+ vaargsfn_pass2(vl);
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgPass) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn_pass(1, *x, 2, 3, *y);
+}
+
+static void vaargsfn_copy2(va_list vl) {
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+}
+
+static void vaargsfn_copy(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_list vl2;
+ va_copy(vl2, vl);
+ vaargsfn_copy2(vl2);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgCopy) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn_copy(1, 2, *x, 3, *y);
+}
+
+static void vaargsfn_ptr(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int*));
+ EXPECT_POISONED(va_arg(vl, int*));
+ EXPECT_NOT_POISONED(va_arg(vl, int*));
+ EXPECT_POISONED(va_arg(vl, double*));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgPtr) {
+ int** x = GetPoisoned<int*>();
+ double** y = GetPoisoned<double*>(8);
+ int z;
+ vaargsfn_ptr(1, &z, *x, &z, *y);
+}
+
+static void vaargsfn_overflow(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, int*));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, int*));
+
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, int*));
+
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, int*));
+
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgOverflow) {
+ int* x = GetPoisoned<int>();
+ double* y = GetPoisoned<double>(8);
+ int** p = GetPoisoned<int*>(16);
+ int z;
+ vaargsfn_overflow(1,
+ 1, 2, *x, 4, 5, 6,
+ 1.1, 2.2, 3.3, *y, 5.5, *p, 7.7, 8.8,
+ // the following args will overflow for sure
+ *x, *y, *p,
+ 7, 9.9, &z,
+ *x, *y, *p);
+}
+
+static void vaargsfn_tlsoverwrite2(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ for (int i = 0; i < 20; ++i)
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+static void vaargsfn_tlsoverwrite(int guard, ...) {
+ // This call will overwrite TLS contents unless it's backed up somewhere.
+ vaargsfn_tlsoverwrite2(2,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42); // 20x
+ va_list vl;
+ va_start(vl, guard);
+ for (int i = 0; i < 20; ++i)
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgTLSOverwrite) {
+ int* x = GetPoisoned<int>();
+ vaargsfn_tlsoverwrite(1,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x); // 20x
+
+}
+
+struct StructByVal {
+ int a, b, c, d, e, f;
+};
+
+static void vaargsfn_structbyval(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgStructByVal) {
+ StructByVal s;
+ s.a = 1;
+ s.b = *GetPoisoned<int>();
+ s.c = 2;
+ s.d = *GetPoisoned<int>();
+ s.e = 3;
+ s.f = *GetPoisoned<int>();
+ vaargsfn_structbyval(0, s, s);
+}
+
+NOINLINE void StructByValTestFunc(struct StructByVal s) {
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+}
+
+NOINLINE void StructByValTestFunc1(struct StructByVal s) {
+ StructByValTestFunc(s);
+}
+
+NOINLINE void StructByValTestFunc2(int z, struct StructByVal s) {
+ StructByValTestFunc(s);
+}
+
+TEST(MemorySanitizer, StructByVal) {
+ // Large aggregates are passed as "byval" pointer argument in LLVM.
+ struct StructByVal s;
+ s.a = 1;
+ s.b = *GetPoisoned<int>();
+ s.c = 2;
+ s.d = *GetPoisoned<int>();
+ s.e = 3;
+ s.f = *GetPoisoned<int>();
+ StructByValTestFunc(s);
+ StructByValTestFunc1(s);
+ StructByValTestFunc2(0, s);
+}
+
+
+#if MSAN_HAS_M128
+NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return _mm_cmpeq_epi16(*a, *b); }
+NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return _mm_cmplt_epi16(*a, *b); }
+TEST(MemorySanitizer, m128) {
+ __m128i a = _mm_set1_epi16(0x1234);
+ __m128i b = _mm_set1_epi16(0x7890);
+ EXPECT_NOT_POISONED(m128Eq(&a, &b));
+ EXPECT_NOT_POISONED(m128Lt(&a, &b));
+}
+// FIXME: add more tests for __m128i.
+#endif // MSAN_HAS_M128
+
+// We should not complain when copying this poisoned hole.
+struct StructWithHole {
+ U4 a;
+ // 4-byte hole.
+ U8 b;
+};
+
+NOINLINE StructWithHole ReturnStructWithHole() {
+ StructWithHole res;
+ __msan_poison(&res, sizeof(res));
+ res.a = 1;
+ res.b = 2;
+ return res;
+}
+
+TEST(MemorySanitizer, StructWithHole) {
+ StructWithHole a = ReturnStructWithHole();
+ break_optimization(&a);
+}
+
+template <class T>
+NOINLINE T ReturnStruct() {
+ T res;
+ __msan_poison(&res, sizeof(res));
+ res.a = 1;
+ return res;
+}
+
+template <class T>
+NOINLINE void TestReturnStruct() {
+ T s1 = ReturnStruct<T>();
+ EXPECT_NOT_POISONED(s1.a);
+ EXPECT_POISONED(s1.b);
+}
+
+struct SSS1 {
+ int a, b, c;
+};
+struct SSS2 {
+ int b, a, c;
+};
+struct SSS3 {
+ int b, c, a;
+};
+struct SSS4 {
+ int c, b, a;
+};
+
+struct SSS5 {
+ int a;
+ float b;
+};
+struct SSS6 {
+ int a;
+ double b;
+};
+struct SSS7 {
+ S8 b;
+ int a;
+};
+struct SSS8 {
+ S2 b;
+ S8 a;
+};
+
+TEST(MemorySanitizer, IntStruct3) {
+ TestReturnStruct<SSS1>();
+ TestReturnStruct<SSS2>();
+ TestReturnStruct<SSS3>();
+ TestReturnStruct<SSS4>();
+ TestReturnStruct<SSS5>();
+ TestReturnStruct<SSS6>();
+ TestReturnStruct<SSS7>();
+ TestReturnStruct<SSS8>();
+}
+
+struct LongStruct {
+ U1 a1, b1;
+ U2 a2, b2;
+ U4 a4, b4;
+ U8 a8, b8;
+};
+
+NOINLINE LongStruct ReturnLongStruct1() {
+ LongStruct res;
+ __msan_poison(&res, sizeof(res));
+ res.a1 = res.a2 = res.a4 = res.a8 = 111;
+ // leaves b1, .., b8 poisoned.
+ return res;
+}
+
+NOINLINE LongStruct ReturnLongStruct2() {
+ LongStruct res;
+ __msan_poison(&res, sizeof(res));
+ res.b1 = res.b2 = res.b4 = res.b8 = 111;
+ // leaves a1, .., a8 poisoned.
+ return res;
+}
+
+TEST(MemorySanitizer, LongStruct) {
+ LongStruct s1 = ReturnLongStruct1();
+ __msan_print_shadow(&s1, sizeof(s1));
+ EXPECT_NOT_POISONED(s1.a1);
+ EXPECT_NOT_POISONED(s1.a2);
+ EXPECT_NOT_POISONED(s1.a4);
+ EXPECT_NOT_POISONED(s1.a8);
+
+ EXPECT_POISONED(s1.b1);
+ EXPECT_POISONED(s1.b2);
+ EXPECT_POISONED(s1.b4);
+ EXPECT_POISONED(s1.b8);
+
+ LongStruct s2 = ReturnLongStruct2();
+ __msan_print_shadow(&s2, sizeof(s2));
+ EXPECT_NOT_POISONED(s2.b1);
+ EXPECT_NOT_POISONED(s2.b2);
+ EXPECT_NOT_POISONED(s2.b4);
+ EXPECT_NOT_POISONED(s2.b8);
+
+ EXPECT_POISONED(s2.a1);
+ EXPECT_POISONED(s2.a2);
+ EXPECT_POISONED(s2.a4);
+ EXPECT_POISONED(s2.a8);
+}
+
+TEST(MemorySanitizer, getrlimit) {
+ struct rlimit limit;
+ __msan_poison(&limit, sizeof(limit));
+ int result = getrlimit(RLIMIT_DATA, &limit);
+ ASSERT_EQ(result, 0);
+ EXPECT_NOT_POISONED(limit.rlim_cur);
+ EXPECT_NOT_POISONED(limit.rlim_max);
+}
+
+TEST(MemorySanitizer, getrusage) {
+ struct rusage usage;
+ __msan_poison(&usage, sizeof(usage));
+ int result = getrusage(RUSAGE_SELF, &usage);
+ ASSERT_EQ(result, 0);
+ EXPECT_NOT_POISONED(usage.ru_utime.tv_sec);
+ EXPECT_NOT_POISONED(usage.ru_utime.tv_usec);
+ EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
+ EXPECT_NOT_POISONED(usage.ru_stime.tv_usec);
+ EXPECT_NOT_POISONED(usage.ru_maxrss);
+ EXPECT_NOT_POISONED(usage.ru_minflt);
+ EXPECT_NOT_POISONED(usage.ru_majflt);
+ EXPECT_NOT_POISONED(usage.ru_inblock);
+ EXPECT_NOT_POISONED(usage.ru_oublock);
+ EXPECT_NOT_POISONED(usage.ru_nvcsw);
+ EXPECT_NOT_POISONED(usage.ru_nivcsw);
+}
+
+#if defined(__FreeBSD__)
+static void GetProgramPath(char *buf, size_t sz) {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ int res = sysctl(mib, 4, buf, &sz, NULL, 0);
+ ASSERT_EQ(0, res);
+}
+#elif defined(__GLIBC__)
+static void GetProgramPath(char *buf, size_t sz) {
+ extern char *program_invocation_name;
+ int res = snprintf(buf, sz, "%s", program_invocation_name);
+ ASSERT_GE(res, 0);
+ ASSERT_LT((size_t)res, sz);
+}
+#else
+# error "TODO: port this"
+#endif
+
+static void dladdr_testfn() {}
+
+TEST(MemorySanitizer, dladdr) {
+ Dl_info info;
+ __msan_poison(&info, sizeof(info));
+ int result = dladdr((const void*)dladdr_testfn, &info);
+ ASSERT_NE(result, 0);
+ EXPECT_NOT_POISONED((unsigned long)info.dli_fname);
+ if (info.dli_fname)
+ EXPECT_NOT_POISONED(strlen(info.dli_fname));
+ EXPECT_NOT_POISONED((unsigned long)info.dli_fbase);
+ EXPECT_NOT_POISONED((unsigned long)info.dli_sname);
+ if (info.dli_sname)
+ EXPECT_NOT_POISONED(strlen(info.dli_sname));
+ EXPECT_NOT_POISONED((unsigned long)info.dli_saddr);
+}
+
+#ifndef MSAN_TEST_DISABLE_DLOPEN
+
+static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
+ (*(int *)data)++;
+ EXPECT_NOT_POISONED(info->dlpi_addr);
+ EXPECT_NOT_POISONED(strlen(info->dlpi_name));
+ EXPECT_NOT_POISONED(info->dlpi_phnum);
+ for (int i = 0; i < info->dlpi_phnum; ++i)
+ EXPECT_NOT_POISONED(info->dlpi_phdr[i]);
+ return 0;
+}
+
+// Compute the path to our loadable DSO. We assume it's in the same
+// directory. Only use string routines that we intercept so far to do this.
+static void GetPathToLoadable(char *buf, size_t sz) {
+ char program_path[kMaxPathLength];
+ GetProgramPath(program_path, sizeof(program_path));
+
+ const char *last_slash = strrchr(program_path, '/');
+ ASSERT_NE(nullptr, last_slash);
+ size_t dir_len = (size_t)(last_slash - program_path);
+#if defined(__x86_64__)
+ static const char basename[] = "libmsan_loadable.x86_64.so";
+#elif defined(__MIPSEB__) || defined(MIPSEB)
+ static const char basename[] = "libmsan_loadable.mips64.so";
+#elif defined(__mips64)
+ static const char basename[] = "libmsan_loadable.mips64el.so";
+#endif
+ int res = snprintf(buf, sz, "%.*s/%s",
+ (int)dir_len, program_path, basename);
+ ASSERT_GE(res, 0);
+ ASSERT_LT((size_t)res, sz);
+}
+
+TEST(MemorySanitizer, dl_iterate_phdr) {
+ char path[kMaxPathLength];
+ GetPathToLoadable(path, sizeof(path));
+
+ // Having at least one dlopen'ed library in the process makes this more
+ // entertaining.
+ void *lib = dlopen(path, RTLD_LAZY);
+ ASSERT_NE((void*)0, lib);
+
+ int count = 0;
+ int result = dl_iterate_phdr(dl_phdr_callback, &count);
+ ASSERT_GT(count, 0);
+
+ dlclose(lib);
+}
+
+TEST(MemorySanitizer, dlopen) {
+ char path[kMaxPathLength];
+ GetPathToLoadable(path, sizeof(path));
+
+ // We need to clear shadow for globals when doing dlopen. In order to test
+ // this, we have to poison the shadow for the DSO before we load it. In
+ // general this is difficult, but the loader tends to reload things in the
+ // same place, so we open, close, and then reopen. The global should always
+ // start out clean after dlopen.
+ for (int i = 0; i < 2; i++) {
+ void *lib = dlopen(path, RTLD_LAZY);
+ if (lib == NULL) {
+ printf("dlerror: %s\n", dlerror());
+ ASSERT_TRUE(lib != NULL);
+ }
+ void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global");
+ ASSERT_TRUE(get_dso_global != NULL);
+ void **dso_global = get_dso_global();
+ EXPECT_NOT_POISONED(*dso_global);
+ __msan_poison(dso_global, sizeof(*dso_global));
+ EXPECT_POISONED(*dso_global);
+ dlclose(lib);
+ }
+}
+
+// Regression test for a crash in dlopen() interceptor.
+TEST(MemorySanitizer, dlopenFailed) {
+ const char *path = "/libmsan_loadable_does_not_exist.so";
+ void *lib = dlopen(path, RTLD_LAZY);
+ ASSERT_TRUE(lib == NULL);
+}
+
+#endif // MSAN_TEST_DISABLE_DLOPEN
+
+// There's no sched_getaffinity() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sched_getaffinity) {
+ cpu_set_t mask;
+ int res = sched_getaffinity(getpid(), sizeof(mask), &mask);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(mask);
+}
+#endif
+
+TEST(MemorySanitizer, scanf) {
+ const char *input = "42 hello";
+ int* d = new int;
+ char* s = new char[7];
+ int res = sscanf(input, "%d %5s", d, s);
+ printf("res %d\n", res);
+ ASSERT_EQ(res, 2);
+ EXPECT_NOT_POISONED(*d);
+ EXPECT_NOT_POISONED(s[0]);
+ EXPECT_NOT_POISONED(s[1]);
+ EXPECT_NOT_POISONED(s[2]);
+ EXPECT_NOT_POISONED(s[3]);
+ EXPECT_NOT_POISONED(s[4]);
+ EXPECT_NOT_POISONED(s[5]);
+ EXPECT_POISONED(s[6]);
+ delete[] s;
+ delete d;
+}
+
+static void *SimpleThread_threadfn(void* data) {
+ return new int;
+}
+
+TEST(MemorySanitizer, SimpleThread) {
+ pthread_t t;
+ void *p;
+ int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(t);
+ res = pthread_join(t, &p);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(p);
+ delete (int*)p;
+}
+
+static void *SmallStackThread_threadfn(void* data) {
+ return 0;
+}
+
+TEST(MemorySanitizer, SmallStackThread) {
+ pthread_attr_t attr;
+ pthread_t t;
+ void *p;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_setstacksize(&attr, 64 * 1024);
+ ASSERT_EQ(0, res);
+ res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
+ ASSERT_EQ(0, res);
+ res = pthread_join(t, &p);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, SmallPreAllocatedStackThread) {
+ pthread_attr_t attr;
+ pthread_t t;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ void *stack;
+ const size_t kStackSize = 16 * 1024;
+ res = posix_memalign(&stack, 4096, kStackSize);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_setstack(&attr, stack, kStackSize);
+ ASSERT_EQ(0, res);
+ res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
+ EXPECT_EQ(0, res);
+ res = pthread_join(t, NULL);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, pthread_attr_get) {
+ pthread_attr_t attr;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ {
+ int v;
+ res = pthread_attr_getdetachstate(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ size_t v;
+ res = pthread_attr_getguardsize(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ struct sched_param v;
+ res = pthread_attr_getschedparam(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getschedpolicy(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getinheritsched(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getscope(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ size_t v;
+ res = pthread_attr_getstacksize(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ void *v;
+ size_t w;
+ res = pthread_attr_getstack(&attr, &v, &w);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ EXPECT_NOT_POISONED(w);
+ }
+ {
+ cpu_set_t v;
+ res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, pthread_getschedparam) {
+ int policy;
+ struct sched_param param;
+ int res = pthread_getschedparam(pthread_self(), &policy, &param);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(policy);
+ EXPECT_NOT_POISONED(param.sched_priority);
+}
+
+TEST(MemorySanitizer, pthread_key_create) {
+ pthread_key_t key;
+ int res = pthread_key_create(&key, NULL);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(key);
+ res = pthread_key_delete(key);
+ ASSERT_EQ(0, res);
+}
+
+namespace {
+struct SignalCondArg {
+ pthread_cond_t* cond;
+ pthread_mutex_t* mu;
+ bool broadcast;
+};
+
+void *SignalCond(void *param) {
+ SignalCondArg *arg = reinterpret_cast<SignalCondArg *>(param);
+ pthread_mutex_lock(arg->mu);
+ if (arg->broadcast)
+ pthread_cond_broadcast(arg->cond);
+ else
+ pthread_cond_signal(arg->cond);
+ pthread_mutex_unlock(arg->mu);
+ return 0;
+}
+} // namespace
+
+TEST(MemorySanitizer, pthread_cond_wait) {
+ pthread_cond_t cond;
+ pthread_mutex_t mu;
+ SignalCondArg args = {&cond, &mu, false};
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&mu, 0);
+ pthread_mutex_lock(&mu);
+
+ // signal
+ pthread_t thr;
+ pthread_create(&thr, 0, SignalCond, &args);
+ int res = pthread_cond_wait(&cond, &mu);
+ ASSERT_EQ(0, res);
+ pthread_join(thr, 0);
+
+ // broadcast
+ args.broadcast = true;
+ pthread_create(&thr, 0, SignalCond, &args);
+ res = pthread_cond_wait(&cond, &mu);
+ ASSERT_EQ(0, res);
+ pthread_join(thr, 0);
+
+ pthread_mutex_unlock(&mu);
+ pthread_mutex_destroy(&mu);
+ pthread_cond_destroy(&cond);
+}
+
+TEST(MemorySanitizer, tmpnam) {
+ char s[L_tmpnam];
+ char *res = tmpnam(s);
+ ASSERT_EQ(s, res);
+ EXPECT_NOT_POISONED(strlen(res));
+}
+
+TEST(MemorySanitizer, tempnam) {
+ char *res = tempnam(NULL, "zzz");
+ EXPECT_NOT_POISONED(strlen(res));
+ free(res);
+}
+
+TEST(MemorySanitizer, posix_memalign) {
+ void *p;
+ EXPECT_POISONED(p);
+ int res = posix_memalign(&p, 4096, 13);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(p);
+ EXPECT_EQ(0U, (uintptr_t)p % 4096);
+ free(p);
+}
+
+// There's no memalign() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, memalign) {
+ void *p = memalign(4096, 13);
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ free(p);
+}
+#endif
+
+TEST(MemorySanitizer, valloc) {
+ void *a = valloc(100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ free(a);
+}
+
+// There's no pvalloc() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, pvalloc) {
+ void *p = pvalloc(kPageSize + 100);
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ EXPECT_EQ(2 * kPageSize, __sanitizer_get_allocated_size(p));
+ free(p);
+
+ p = pvalloc(0); // pvalloc(0) should allocate at least one page.
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ EXPECT_EQ(kPageSize, __sanitizer_get_allocated_size(p));
+ free(p);
+}
+#endif
+
+TEST(MemorySanitizer, inet_pton) {
+ const char *s = "1:0:0:0:0:0:0:8";
+ unsigned char buf[sizeof(struct in6_addr)];
+ int res = inet_pton(AF_INET6, s, buf);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[sizeof(struct in6_addr) - 1]);
+
+ char s_out[INET6_ADDRSTRLEN];
+ EXPECT_POISONED(s_out[3]);
+ const char *q = inet_ntop(AF_INET6, buf, s_out, INET6_ADDRSTRLEN);
+ ASSERT_NE((void*)0, q);
+ EXPECT_NOT_POISONED(s_out[3]);
+}
+
+TEST(MemorySanitizer, inet_aton) {
+ const char *s = "127.0.0.1";
+ struct in_addr in[2];
+ int res = inet_aton(s, in);
+ ASSERT_NE(0, res);
+ EXPECT_NOT_POISONED(in[0]);
+ EXPECT_POISONED(*(char *)(in + 1));
+}
+
+TEST(MemorySanitizer, uname) {
+ struct utsname u;
+ int res = uname(&u);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(strlen(u.sysname));
+ EXPECT_NOT_POISONED(strlen(u.nodename));
+ EXPECT_NOT_POISONED(strlen(u.release));
+ EXPECT_NOT_POISONED(strlen(u.version));
+ EXPECT_NOT_POISONED(strlen(u.machine));
+}
+
+TEST(MemorySanitizer, gethostname) {
+ char buf[100];
+ int res = gethostname(buf, 100);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(strlen(buf));
+}
+
+// There's no sysinfo() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sysinfo) {
+ struct sysinfo info;
+ int res = sysinfo(&info);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(info);
+}
+#endif
+
+TEST(MemorySanitizer, getpwuid) {
+ struct passwd *p = getpwuid(0); // root
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+ ASSERT_EQ(0U, p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwuid_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwuid_r(0, &pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+TEST(MemorySanitizer, getpwnam_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+TEST(MemorySanitizer, getpwnam_r_positive) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char s[5];
+ strncpy(s, "abcd", 5);
+ __msan_poison(s, 5);
+ char buf[10000];
+ int res;
+ EXPECT_UMR(res = getpwnam_r(s, &pwd, buf, sizeof(buf), &pwdres));
+}
+
+TEST(MemorySanitizer, getgrnam_r) {
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ int res = getgrnam_r(SUPERUSER_GROUP, &grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ // Note that getgrnam_r() returns 0 if the matching group is not found.
+ ASSERT_NE(nullptr, grpres);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+TEST(MemorySanitizer, getpwent) {
+ setpwent();
+ struct passwd *p = getpwent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwent_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ setpwent();
+ int res = getpwent_r(&pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+// There's no fgetpwent() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fgetpwent) {
+ FILE *fp = fopen("/etc/passwd", "r");
+ struct passwd *p = fgetpwent(fp);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, getgrent) {
+ setgrent();
+ struct group *p = getgrent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->gr_name);
+ ASSERT_TRUE(p->gr_name != NULL);
+ EXPECT_NOT_POISONED(p->gr_name[0]);
+ EXPECT_NOT_POISONED(p->gr_gid);
+}
+
+// There's no fgetgrent() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fgetgrent) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group *grp = fgetgrent(fp);
+ ASSERT_TRUE(grp != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name);
+ ASSERT_TRUE(grp->gr_name != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name[0]);
+ EXPECT_NOT_POISONED(grp->gr_gid);
+ for (char **p = grp->gr_mem; *p; ++p) {
+ EXPECT_NOT_POISONED((*p)[0]);
+ EXPECT_TRUE(strlen(*p) > 0);
+ }
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, getgrent_r) {
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = getgrent_r(&grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+// There's no fgetgrent_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fgetgrent_r) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, getgroups) {
+ int n = getgroups(0, 0);
+ gid_t *gids = new gid_t[n];
+ int res = getgroups(n, gids);
+ ASSERT_EQ(n, res);
+ for (int i = 0; i < n; ++i)
+ EXPECT_NOT_POISONED(gids[i]);
+}
+
+TEST(MemorySanitizer, wordexp) {
+ wordexp_t w;
+ int res = wordexp("a b c", &w, 0);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(3U, w.we_wordc);
+ ASSERT_STREQ("a", w.we_wordv[0]);
+ ASSERT_STREQ("b", w.we_wordv[1]);
+ ASSERT_STREQ("c", w.we_wordv[2]);
+}
+
+template<class T>
+static bool applySlt(T value, T shadow) {
+ __msan_partial_poison(&value, &shadow, sizeof(T));
+ volatile bool zzz = true;
+ // This "|| zzz" trick somehow makes LLVM emit "icmp slt" instead of
+ // a shift-and-trunc to get at the highest bit.
+ volatile bool v = value < 0 || zzz;
+ return v;
+}
+
+TEST(MemorySanitizer, SignedCompareWithZero) {
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xF));
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFF));
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFFFFFF));
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0x7FFFFFF));
+ EXPECT_UMR(applySlt<S4>(0xF, 0x80FFFFFF));
+ EXPECT_UMR(applySlt<S4>(0xF, 0xFFFFFFFF));
+}
+
+template <class T, class S>
+static T poisoned(T Va, S Sa) {
+ char SIZE_CHECK1[(ssize_t)sizeof(T) - (ssize_t)sizeof(S)];
+ char SIZE_CHECK2[(ssize_t)sizeof(S) - (ssize_t)sizeof(T)];
+ T a;
+ a = Va;
+ __msan_partial_poison(&a, &Sa, sizeof(T));
+ return a;
+}
+
+TEST(MemorySanitizer, ICmpRelational) {
+ EXPECT_NOT_POISONED(poisoned(0, 0) < poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) < poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) < poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) < poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) < poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_NOT_POISONED(poisoned(0, 0) <= poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) <= poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) <= poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) <= poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) <= poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <=
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <=
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_NOT_POISONED(poisoned(0, 0) > poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) > poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) > poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) > poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) > poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_NOT_POISONED(poisoned(0, 0) >= poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) >= poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) >= poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) >= poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) >= poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >=
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >=
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_POISONED(poisoned(6, 0xF) > poisoned(7, 0));
+ EXPECT_POISONED(poisoned(0xF, 0xF) > poisoned(7, 0));
+
+ EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U));
+}
+
+#if MSAN_HAS_M128
+TEST(MemorySanitizer, ICmpVectorRelational) {
+ EXPECT_NOT_POISONED(
+ _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)),
+ poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0))));
+ EXPECT_NOT_POISONED(
+ _mm_cmplt_epi16(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)),
+ poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0))));
+ EXPECT_POISONED(
+ _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)),
+ poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF))));
+ EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)),
+ poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0))));
+}
+#endif
+
+// Volatile bitfield store is implemented as load-mask-store
+// Test that we don't warn on the store of (uninitialized) padding.
+struct VolatileBitfieldStruct {
+ volatile unsigned x : 1;
+ unsigned y : 1;
+};
+
+TEST(MemorySanitizer, VolatileBitfield) {
+ VolatileBitfieldStruct *S = new VolatileBitfieldStruct;
+ S->x = 1;
+ EXPECT_NOT_POISONED((unsigned)S->x);
+ EXPECT_POISONED((unsigned)S->y);
+}
+
+TEST(MemorySanitizer, UnalignedLoad) {
+ char x[32] __attribute__((aligned(8)));
+ U4 origin = __LINE__;
+ for (unsigned i = 0; i < sizeof(x) / 4; ++i)
+ __msan_set_origin(x + 4 * i, 4, origin + i);
+
+ memset(x + 8, 0, 16);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 6), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 22));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 23), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 4), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 20));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 1), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 16));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 17), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 24), origin + 6);
+}
+
+TEST(MemorySanitizer, UnalignedStore16) {
+ char x[5] __attribute__((aligned(4)));
+ U2 y2 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y2, 1);
+ __msan_set_origin(&y2, 1, origin);
+
+ __sanitizer_unaligned_store16(x + 1, y2);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED_O(x[3], origin);
+}
+
+TEST(MemorySanitizer, UnalignedStore32) {
+ char x[8] __attribute__((aligned(4)));
+ U4 y4 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y4, 2);
+ __msan_set_origin(&y4, 2, origin);
+
+ __sanitizer_unaligned_store32(x + 3, y4);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_POISONED_O(x[7], origin);
+}
+
+TEST(MemorySanitizer, UnalignedStore64) {
+ char x[16] __attribute__((aligned(8)));
+ U8 y8 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y8, 3);
+ __msan_poison(((char *)&y8) + sizeof(y8) - 2, 1);
+ __msan_set_origin(&y8, 8, origin);
+
+ __sanitizer_unaligned_store64(x + 3, y8);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
+ EXPECT_POISONED_O(x[5], origin);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED_O(x[9], origin);
+ EXPECT_NOT_POISONED(x[10]);
+ EXPECT_POISONED_O(x[11], origin);
+}
+
+TEST(MemorySanitizer, UnalignedStore16_precise) {
+ char x[8] __attribute__((aligned(4)));
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_POISONED_O(x[2], originx1);
+ EXPECT_NOT_POISONED(x[3]);
+ EXPECT_POISONED_O(x[4], originy);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
+}
+
+TEST(MemorySanitizer, UnalignedStore16_precise2) {
+ char x[8] __attribute__((aligned(4)));
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y), 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_POISONED_O(x[2], originy);
+ EXPECT_POISONED_O(x[3], originy);
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originx2);
+ EXPECT_POISONED_O(x[6], originx2);
+ EXPECT_POISONED_O(x[7], originx2);
+}
+
+TEST(MemorySanitizer, UnalignedStore64_precise) {
+ char x[12] __attribute__((aligned(8)));
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_poison(((char *)&y) + 7, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED_O(x[3], originy);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
+
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED_O(x[9], originy);
+ EXPECT_POISONED_O(x[10], originy);
+ EXPECT_POISONED_O(x[11], originy);
+}
+
+TEST(MemorySanitizer, UnalignedStore64_precise2) {
+ char x[12] __attribute__((aligned(8)));
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 3, 3);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
+
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_NOT_POISONED(x[9]);
+ EXPECT_POISONED_O(x[10], originx3);
+ EXPECT_POISONED_O(x[11], originx3);
+}
+
+#if (defined(__x86_64__) && defined(__clang__))
+namespace {
+typedef U1 V16x8 __attribute__((__vector_size__(16)));
+typedef U2 V8x16 __attribute__((__vector_size__(16)));
+typedef U4 V4x32 __attribute__((__vector_size__(16)));
+typedef U8 V2x64 __attribute__((__vector_size__(16)));
+typedef U4 V8x32 __attribute__((__vector_size__(32)));
+typedef U8 V4x64 __attribute__((__vector_size__(32)));
+typedef U4 V2x32 __attribute__((__vector_size__(8)));
+typedef U2 V4x16 __attribute__((__vector_size__(8)));
+typedef U1 V8x8 __attribute__((__vector_size__(8)));
+
+
+V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) {
+ return _mm_slli_epi16(x, y);
+}
+
+V8x16 shift_sse2_left(V8x16 x, V8x16 y) {
+ return _mm_sll_epi16(x, y);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, 2);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar_by_uninit) {
+ V8x16 v = {0, 1, 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, Poisoned<U4>());
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+TEST(VectorShiftTest, sse2_left) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ // Top 64 bits of shift count don't affect the result.
+ V2x64 s = {2, Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_by_uninit) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V2x64 s = {Poisoned<U8>(), Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+#ifdef __AVX2__
+V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+ return _mm_sllv_epi32(x, y);
+}
+// This is variable vector shift that's only available starting with AVX2.
+// V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+TEST(VectorShiftTest, avx2_left) {
+ V4x32 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3};
+ V4x32 s = {2, Poisoned<U4>(), 3, Poisoned<U4>()};
+ V4x32 u = shift_avx2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_NOT_POISONED(u[0] | (~7U));
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[1] | (~31U));
+ EXPECT_NOT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[3] | (~31U));
+}
+#endif // __AVX2__
+} // namespace
+
+TEST(VectorPackTest, sse2_packssdw_128) {
+ const unsigned S2_max = (1 << 15) - 1;
+ V4x32 a = {Poisoned<U4>(0, 0xFF0000), Poisoned<U4>(0, 0xFFFF0000),
+ S2_max + 100, 4};
+ V4x32 b = {Poisoned<U4>(0, 0xFF), S2_max + 10000, Poisoned<U4>(0, 0xFF00),
+ S2_max};
+
+ V8x16 c = _mm_packs_epi32(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], S2_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], S2_max);
+ EXPECT_EQ(c[7], S2_max);
+}
+
+TEST(VectorPackTest, mmx_packuswb) {
+ const unsigned U1_max = (1 << 8) - 1;
+ V4x16 a = {Poisoned<U2>(0, 0xFF00), Poisoned<U2>(0, 0xF000U), U1_max + 100,
+ 4};
+ V4x16 b = {Poisoned<U2>(0, 0xFF), U1_max - 1, Poisoned<U2>(0, 0xF), U1_max};
+ V8x8 c = _mm_packs_pu16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], U1_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], U1_max - 1);
+ EXPECT_EQ(c[7], U1_max);
+}
+
+TEST(VectorSadTest, sse2_psad_bw) {
+ V16x8 a = {Poisoned<U1>(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ V16x8 b = {100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115};
+ V2x64 c = _mm_sad_epu8(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ(800U, c[1]);
+}
+
+TEST(VectorMaddTest, mmx_pmadd_wd) {
+ V4x16 a = {Poisoned<U2>(), 1, 2, 3};
+ V4x16 b = {100, 101, 102, 103};
+ V2x32 c = _mm_madd_pi16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ((unsigned)(2 * 102 + 3 * 103), c[1]);
+}
+#endif // defined(__clang__)
+
+TEST(MemorySanitizerOrigins, SetGet) {
+ EXPECT_EQ(TrackingOrigins(), __msan_get_track_origins());
+ if (!TrackingOrigins()) return;
+ int x;
+ __msan_set_origin(&x, sizeof(x), 1234);
+ EXPECT_EQ(1234U, __msan_get_origin(&x));
+ __msan_set_origin(&x, sizeof(x), 5678);
+ EXPECT_EQ(5678U, __msan_get_origin(&x));
+ __msan_set_origin(&x, sizeof(x), 0);
+ EXPECT_EQ(0U, __msan_get_origin(&x));
+}
+
+namespace {
+struct S {
+ U4 dummy;
+ U2 a;
+ U2 b;
+};
+
+TEST(MemorySanitizerOrigins, InitializedStoreDoesNotChangeOrigin) {
+ if (!TrackingOrigins()) return;
+
+ S s;
+ U4 origin = rand(); // NOLINT
+ s.a = *GetPoisonedO<U2>(0, origin);
+ EXPECT_EQ(origin, __msan_get_origin(&s.a));
+ EXPECT_EQ(origin, __msan_get_origin(&s.b));
+
+ s.b = 42;
+ EXPECT_EQ(origin, __msan_get_origin(&s.a));
+ EXPECT_EQ(origin, __msan_get_origin(&s.b));
+}
+} // namespace
+
+template<class T, class BinaryOp>
+INLINE
+void BinaryOpOriginTest(BinaryOp op) {
+ U4 ox = rand(); //NOLINT
+ U4 oy = rand(); //NOLINT
+ T *x = GetPoisonedO<T>(0, ox, 0);
+ T *y = GetPoisonedO<T>(1, oy, 0);
+ T *z = GetPoisonedO<T>(2, 0, 0);
+
+ *z = op(*x, *y);
+ U4 origin = __msan_get_origin(z);
+ EXPECT_POISONED_O(*z, origin);
+ EXPECT_EQ(true, origin == ox || origin == oy);
+
+ // y is poisoned, x is not.
+ *x = 10101;
+ *y = *GetPoisonedO<T>(1, oy);
+ break_optimization(x);
+ __msan_set_origin(z, sizeof(*z), 0);
+ *z = op(*x, *y);
+ EXPECT_POISONED_O(*z, oy);
+ EXPECT_EQ(__msan_get_origin(z), oy);
+
+ // x is poisoned, y is not.
+ *x = *GetPoisonedO<T>(0, ox);
+ *y = 10101010;
+ break_optimization(y);
+ __msan_set_origin(z, sizeof(*z), 0);
+ *z = op(*x, *y);
+ EXPECT_POISONED_O(*z, ox);
+ EXPECT_EQ(__msan_get_origin(z), ox);
+}
+
+template<class T> INLINE T XOR(const T &a, const T&b) { return a ^ b; }
+template<class T> INLINE T ADD(const T &a, const T&b) { return a + b; }
+template<class T> INLINE T SUB(const T &a, const T&b) { return a - b; }
+template<class T> INLINE T MUL(const T &a, const T&b) { return a * b; }
+template<class T> INLINE T AND(const T &a, const T&b) { return a & b; }
+template<class T> INLINE T OR (const T &a, const T&b) { return a | b; }
+
+TEST(MemorySanitizerOrigins, BinaryOp) {
+ if (!TrackingOrigins()) return;
+ BinaryOpOriginTest<S8>(XOR<S8>);
+ BinaryOpOriginTest<U8>(ADD<U8>);
+ BinaryOpOriginTest<S4>(SUB<S4>);
+ BinaryOpOriginTest<S4>(MUL<S4>);
+ BinaryOpOriginTest<U4>(OR<U4>);
+ BinaryOpOriginTest<U4>(AND<U4>);
+ BinaryOpOriginTest<double>(ADD<U4>);
+ BinaryOpOriginTest<float>(ADD<S4>);
+ BinaryOpOriginTest<double>(ADD<double>);
+ BinaryOpOriginTest<float>(ADD<double>);
+}
+
+TEST(MemorySanitizerOrigins, Unary) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O((void*)*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O((U8)*GetPoisonedO<void*>(0, __LINE__), __LINE__);
+}
+
+TEST(MemorySanitizerOrigins, EQ) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) <= 11, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) == 11, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<float>(0, __LINE__) == 1.1, __LINE__);
+}
+
+TEST(MemorySanitizerOrigins, DIV) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) / 100, __LINE__);
+ unsigned o = __LINE__;
+ EXPECT_UMR_O(volatile unsigned y = 100 / *GetPoisonedO<S4>(0, o, 1), o);
+}
+
+TEST(MemorySanitizerOrigins, SHIFT) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) >> 10, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) >> 10, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) << 10, __LINE__);
+ EXPECT_POISONED_O(10U << *GetPoisonedO<U8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(-10 >> *GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(-10 << *GetPoisonedO<S8>(0, __LINE__), __LINE__);
+}
+
+template<class T, int N>
+void MemCpyTest() {
+ int ox = __LINE__;
+ T *x = new T[N];
+ T *y = new T[N];
+ T *z = new T[N];
+ T *q = new T[N];
+ __msan_poison(x, N * sizeof(T));
+ __msan_set_origin(x, N * sizeof(T), ox);
+ __msan_set_origin(y, N * sizeof(T), 777777);
+ __msan_set_origin(z, N * sizeof(T), 888888);
+ EXPECT_NOT_POISONED(x);
+ memcpy(y, x, N * sizeof(T));
+ EXPECT_POISONED_O(y[0], ox);
+ EXPECT_POISONED_O(y[N/2], ox);
+ EXPECT_POISONED_O(y[N-1], ox);
+ EXPECT_NOT_POISONED(x);
+ void *res = mempcpy(q, x, N * sizeof(T));
+ ASSERT_EQ(q + N, res);
+ EXPECT_POISONED_O(q[0], ox);
+ EXPECT_POISONED_O(q[N/2], ox);
+ EXPECT_POISONED_O(q[N-1], ox);
+ EXPECT_NOT_POISONED(x);
+ memmove(z, x, N * sizeof(T));
+ EXPECT_POISONED_O(z[0], ox);
+ EXPECT_POISONED_O(z[N/2], ox);
+ EXPECT_POISONED_O(z[N-1], ox);
+}
+
+TEST(MemorySanitizerOrigins, LargeMemCpy) {
+ if (!TrackingOrigins()) return;
+ MemCpyTest<U1, 10000>();
+ MemCpyTest<U8, 10000>();
+}
+
+TEST(MemorySanitizerOrigins, SmallMemCpy) {
+ if (!TrackingOrigins()) return;
+ MemCpyTest<U8, 1>();
+ MemCpyTest<U8, 2>();
+ MemCpyTest<U8, 3>();
+}
+
+TEST(MemorySanitizerOrigins, Select) {
+ if (!TrackingOrigins()) return;
+ EXPECT_NOT_POISONED(g_one ? 1 : *GetPoisonedO<S4>(0, __LINE__));
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ S4 x;
+ break_optimization(&x);
+ x = g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 0;
+
+ EXPECT_POISONED_O(g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 1, __LINE__);
+ EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__);
+}
+
+NOINLINE int RetvalOriginTest(U4 origin) {
+ int *a = new int;
+ break_optimization(a);
+ __msan_set_origin(a, sizeof(*a), origin);
+ int res = *a;
+ delete a;
+ return res;
+}
+
+TEST(MemorySanitizerOrigins, Retval) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__);
+}
+
+NOINLINE void ParamOriginTest(int param, U4 origin) {
+ EXPECT_POISONED_O(param, origin);
+}
+
+TEST(MemorySanitizerOrigins, Param) {
+ if (!TrackingOrigins()) return;
+ int *a = new int;
+ U4 origin = __LINE__;
+ break_optimization(a);
+ __msan_set_origin(a, sizeof(*a), origin);
+ ParamOriginTest(*a, origin);
+ delete a;
+}
+
+TEST(MemorySanitizerOrigins, Invoke) {
+ if (!TrackingOrigins()) return;
+ StructWithDtor s; // Will cause the calls to become invokes.
+ EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__);
+}
+
+TEST(MemorySanitizerOrigins, strlen) {
+ S8 alignment;
+ break_optimization(&alignment);
+ char x[4] = {'a', 'b', 0, 0};
+ __msan_poison(&x[2], 1);
+ U4 origin = __LINE__;
+ __msan_set_origin(x, sizeof(x), origin);
+ EXPECT_UMR_O(volatile unsigned y = strlen(x), origin);
+}
+
+TEST(MemorySanitizerOrigins, wcslen) {
+ wchar_t w[3] = {'a', 'b', 0};
+ U4 origin = __LINE__;
+ __msan_set_origin(w, sizeof(w), origin);
+ __msan_poison(&w[2], sizeof(wchar_t));
+ EXPECT_UMR_O(volatile unsigned y = wcslen(w), origin);
+}
+
+#if MSAN_HAS_M128
+TEST(MemorySanitizerOrigins, StoreIntrinsic) {
+ __m128 x, y;
+ U4 origin = __LINE__;
+ __msan_set_origin(&x, sizeof(x), origin);
+ __msan_poison(&x, sizeof(x));
+ __builtin_ia32_storeups((float*)&y, x);
+ EXPECT_POISONED_O(y, origin);
+}
+#endif
+
+NOINLINE void RecursiveMalloc(int depth) {
+ static int count;
+ count++;
+ if ((count % (1024 * 1024)) == 0)
+ printf("RecursiveMalloc: %d\n", count);
+ int *x1 = new int;
+ int *x2 = new int;
+ break_optimization(x1);
+ break_optimization(x2);
+ if (depth > 0) {
+ RecursiveMalloc(depth-1);
+ RecursiveMalloc(depth-1);
+ }
+ delete x1;
+ delete x2;
+}
+
+TEST(MemorySanitizer, Select) {
+ int x;
+ int volatile* p = &x;
+ int z = *p ? 1 : 0;
+ EXPECT_POISONED(z);
+}
+
+TEST(MemorySanitizer, SelectPartial) {
+ // Precise instrumentation of select.
+ // Some bits of the result do not depend on select condition, and must stay
+ // initialized even if select condition is not. These are the bits that are
+ // equal and initialized in both left and right select arguments.
+ U4 x = 0xFFFFABCDU;
+ U4 x_s = 0xFFFF0000U;
+ __msan_partial_poison(&x, &x_s, sizeof(x));
+ U4 y = 0xAB00U;
+ U1 cond = true;
+ __msan_poison(&cond, sizeof(cond));
+ U4 z = cond ? x : y;
+ __msan_print_shadow(&z, sizeof(z));
+ EXPECT_POISONED(z & 0xFFU);
+ EXPECT_NOT_POISONED(z & 0xFF00U);
+ EXPECT_POISONED(z & 0xFF0000U);
+ EXPECT_POISONED(z & 0xFF000000U);
+ EXPECT_EQ(0xAB00U, z & 0xFF00U);
+}
+
+TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
+ RecursiveMalloc(22);
+}
+
+TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
+ size_t sizes[] = {0, 20, 5000, 1<<20};
+ for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
+ size_t alloc_size = __sanitizer_get_estimated_allocated_size(sizes[i]);
+ EXPECT_EQ(alloc_size, sizes[i]);
+ }
+}
+
+TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
+ char *array = reinterpret_cast<char*>(malloc(100));
+ int *int_ptr = new int;
+
+ EXPECT_TRUE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(100U, __sanitizer_get_allocated_size(array));
+
+ EXPECT_TRUE(__sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(*int_ptr), __sanitizer_get_allocated_size(int_ptr));
+
+ void *wild_addr = reinterpret_cast<void*>(0x1);
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(wild_addr));
+
+ EXPECT_FALSE(__sanitizer_get_ownership(array + 50));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array + 50));
+
+ // NULL is a valid argument for GetAllocatedSize but is not owned.
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
+
+ free(array);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array));
+
+ delete int_ptr;
+}
+
+TEST(MemorySanitizer, MlockTest) {
+ EXPECT_EQ(0, mlockall(MCL_CURRENT));
+ EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+ EXPECT_EQ(0, munlockall());
+ EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+
+// Test that LargeAllocator unpoisons memory before releasing it to the OS.
+TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) {
+ void *p = malloc(1024 * 1024);
+ free(p);
+
+ typedef void *(*mmap_fn)(void *, size_t, int, int, int, off_t);
+ mmap_fn real_mmap = (mmap_fn)dlsym(RTLD_NEXT, "mmap");
+
+ // Allocate the page that was released to the OS in free() with the real mmap,
+ // bypassing the interceptor.
+ char *q = (char *)real_mmap(p, 4096, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE((char *)0, q);
+
+ ASSERT_TRUE(q <= p);
+ ASSERT_TRUE(q + 4096 > p);
+
+ EXPECT_NOT_POISONED(q[0]);
+ EXPECT_NOT_POISONED(q[10]);
+ EXPECT_NOT_POISONED(q[100]);
+
+ munmap(q, 4096);
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+TEST(MemorySanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ free(array);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test_config.h b/contrib/compiler-rt/lib/msan/tests/msan_test_config.h
new file mode 100644
index 000000000000..5404c434d09f
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/tests/msan_test_config.h
@@ -0,0 +1,20 @@
+//===-- msan_test_config.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 MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_TEST_CONFIG_H
+#define MSAN_TEST_CONFIG_H
+
+#include "gtest/gtest.h"
+
+#endif // MSAN_TEST_CONFIG_H
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc b/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc
new file mode 100644
index 000000000000..c8c5fefb19f5
--- /dev/null
+++ b/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc
@@ -0,0 +1,21 @@
+//===-- msan_test_main.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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_EXTERNAL_TEST_CONFIG
+#include "msan_test_config.h"
+#endif // MSAN_EXTERNAL_TEST_CONFIG
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/compiler-rt/lib/mulsf3.c b/contrib/compiler-rt/lib/mulsf3.c
deleted file mode 100644
index 861a9ba5f90d..000000000000
--- a/contrib/compiler-rt/lib/mulsf3.c
+++ /dev/null
@@ -1,112 +0,0 @@
-//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements single-precision soft-float multiplication
-// with the IEEE-754 default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(fmul, mulsf3)
-
-COMPILER_RT_ABI fp_t
-__mulsf3(fp_t a, fp_t b) {
-
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN * anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything * NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity * non-zero = +/- infinity
- if (bAbs) return fromRep(aAbs | productSign);
- // infinity * zero = NaN
- else return fromRep(qnanRep);
- }
-
- if (bAbs == infRep) {
- // non-zero * infinity = +/- infinity
- if (aAbs) return fromRep(bAbs | productSign);
- // zero * infinity = NaN
- else return fromRep(qnanRep);
- }
-
- // zero * anything = +/- zero
- if (!aAbs) return fromRep(productSign);
- // anything * zero = +/- zero
- if (!bAbs) return fromRep(productSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale += normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
-
- // Get the significand of a*b. Before multiplying the significands, shift
- // one of them left to left-align it in the field. Thus, the product will
- // have (exponentBits + 2) integral digits, all but two of which must be
- // zero. Normalizing this result is just a conditional left-shift by one
- // and bumping the exponent accordingly.
- rep_t productHi, productLo;
- wideMultiply(aSignificand, bSignificand << exponentBits,
- &productHi, &productLo);
-
- int productExponent = aExponent + bExponent - exponentBias + scale;
-
- // Normalize the significand, adjust exponent if needed.
- if (productHi & implicitBit) productExponent++;
- else wideLeftShift(&productHi, &productLo, 1);
-
- // If we have overflowed the type, return +/- infinity.
- if (productExponent >= maxExponent) return fromRep(infRep | productSign);
-
- if (productExponent <= 0) {
- // Result is denormal before rounding, the exponent is zero and we
- // need to shift the significand.
- wideRightShiftWithSticky(&productHi, &productLo, 1U - (unsigned)productExponent);
- }
-
- else {
- // Result is normal before rounding; insert the exponent.
- productHi &= significandMask;
- productHi |= (rep_t)productExponent << significandBits;
- }
-
- // Insert the sign of the result:
- productHi |= productSign;
-
- // Final rounding. The final result may overflow to infinity, or underflow
- // to zero, but those are the correct results in those cases.
- if (productLo > signBit) productHi++;
- if (productLo == signBit) productHi += productHi & 1;
- return fromRep(productHi);
-}
diff --git a/contrib/compiler-rt/lib/profile/GCDAProfiling.c b/contrib/compiler-rt/lib/profile/GCDAProfiling.c
new file mode 100644
index 000000000000..45fbd07e544b
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/GCDAProfiling.c
@@ -0,0 +1,587 @@
+/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the gcov profiling
+|* instrumentation pass. Link against this library when running code through
+|* the -insert-gcov-profiling LLVM pass.
+|*
+|* We emit files in a corrupt version of GCOV's "gcda" file format. These files
+|* are only close enough that LCOV will happily parse them. Anything that lcov
+|* ignores is missing.
+|*
+|* TODO: gcov is multi-process safe by having each exit open the existing file
+|* and append to it. We'd like to achieve that and be thread-safe too.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
+#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
+
+#if !I386_FREEBSD
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+#if !defined(_MSC_VER) && !I386_FREEBSD
+#include <stdint.h>
+#endif
+
+#if defined(_MSC_VER)
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#elif I386_FREEBSD
+/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
+ * FreeBSD 10, r232261) when compiled in 32-bit mode.
+ */
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+int mkdir(const char*, unsigned short);
+#endif
+
+/* #define DEBUG_GCDAPROFILING */
+
+/*
+ * --- GCOV file format I/O primitives ---
+ */
+
+/*
+ * The current file name we're outputting. Used primarily for error logging.
+ */
+static char *filename = NULL;
+
+/*
+ * The current file we're outputting.
+ */
+static FILE *output_file = NULL;
+
+/*
+ * Buffer that we write things into.
+ */
+#define WRITE_BUFFER_SIZE (128 * 1024)
+static char *write_buffer = NULL;
+static uint64_t cur_buffer_size = 0;
+static uint64_t cur_pos = 0;
+static uint64_t file_size = 0;
+static int new_file = 0;
+static int fd = -1;
+
+/*
+ * A list of functions to write out the data.
+ */
+typedef void (*writeout_fn)();
+
+struct writeout_fn_node {
+ writeout_fn fn;
+ struct writeout_fn_node *next;
+};
+
+static struct writeout_fn_node *writeout_fn_head = NULL;
+static struct writeout_fn_node *writeout_fn_tail = NULL;
+
+/*
+ * A list of flush functions that our __gcov_flush() function should call.
+ */
+typedef void (*flush_fn)();
+
+struct flush_fn_node {
+ flush_fn fn;
+ struct flush_fn_node *next;
+};
+
+static struct flush_fn_node *flush_fn_head = NULL;
+static struct flush_fn_node *flush_fn_tail = NULL;
+
+static void resize_write_buffer(uint64_t size) {
+ if (!new_file) return;
+ size += cur_pos;
+ if (size <= cur_buffer_size) return;
+ size = (size - 1) / WRITE_BUFFER_SIZE + 1;
+ size *= WRITE_BUFFER_SIZE;
+ write_buffer = realloc(write_buffer, size);
+ cur_buffer_size = size;
+}
+
+static void write_bytes(const char *s, size_t len) {
+ resize_write_buffer(len);
+ memcpy(&write_buffer[cur_pos], s, len);
+ cur_pos += len;
+}
+
+static void write_32bit_value(uint32_t i) {
+ write_bytes((char*)&i, 4);
+}
+
+static void write_64bit_value(uint64_t i) {
+ write_bytes((char*)&i, 8);
+}
+
+static uint32_t length_of_string(const char *s) {
+ return (strlen(s) / 4) + 1;
+}
+
+static void write_string(const char *s) {
+ uint32_t len = length_of_string(s);
+ write_32bit_value(len);
+ write_bytes(s, strlen(s));
+ write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
+}
+
+static uint32_t read_32bit_value() {
+ uint32_t val;
+
+ if (new_file)
+ return (uint32_t)-1;
+
+ val = *(uint32_t*)&write_buffer[cur_pos];
+ cur_pos += 4;
+ return val;
+}
+
+static uint64_t read_64bit_value() {
+ uint64_t val;
+
+ if (new_file)
+ return (uint64_t)-1;
+
+ val = *(uint64_t*)&write_buffer[cur_pos];
+ cur_pos += 8;
+ return val;
+}
+
+static char *mangle_filename(const char *orig_filename) {
+ char *new_filename;
+ size_t filename_len, prefix_len;
+ int prefix_strip;
+ int level = 0;
+ const char *fname, *ptr;
+ const char *prefix = getenv("GCOV_PREFIX");
+ const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP");
+
+ if (prefix == NULL || prefix[0] == '\0')
+ return strdup(orig_filename);
+
+ if (prefix_strip_str) {
+ prefix_strip = atoi(prefix_strip_str);
+
+ /* Negative GCOV_PREFIX_STRIP values are ignored */
+ if (prefix_strip < 0)
+ prefix_strip = 0;
+ } else {
+ prefix_strip = 0;
+ }
+
+ fname = orig_filename;
+ for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) {
+ if (*ptr == '\0')
+ break;
+ if (*ptr != '/')
+ continue;
+ fname = ptr;
+ ++level;
+ }
+
+ filename_len = strlen(fname);
+ prefix_len = strlen(prefix);
+ new_filename = malloc(prefix_len + 1 + filename_len + 1);
+ memcpy(new_filename, prefix, prefix_len);
+
+ if (prefix[prefix_len - 1] != '/')
+ new_filename[prefix_len++] = '/';
+ memcpy(new_filename + prefix_len, fname, filename_len + 1);
+
+ return new_filename;
+}
+
+static void recursive_mkdir(char *path) {
+ int i;
+
+ for (i = 1; path[i] != '\0'; ++i) {
+ if (path[i] != '/') continue;
+ path[i] = '\0';
+#ifdef _WIN32
+ _mkdir(path);
+#else
+ mkdir(path, 0755); /* Some of these will fail, ignore it. */
+#endif
+ path[i] = '/';
+ }
+}
+
+static int map_file() {
+ fseek(output_file, 0L, SEEK_END);
+ file_size = ftell(output_file);
+
+ /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an
+ * error message because it should "just work" for the user. */
+ if (file_size == 0)
+ return -1;
+
+ write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fd, 0);
+ if (write_buffer == (void *)-1) {
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot map: %s\n", filename,
+ strerror(errnum));
+ return -1;
+ }
+ return 0;
+}
+
+static void unmap_file() {
+ if (msync(write_buffer, file_size, MS_SYNC) == -1) {
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename,
+ strerror(errnum));
+ }
+
+ /* We explicitly ignore errors from unmapping because at this point the data
+ * is written and we don't care.
+ */
+ (void)munmap(write_buffer, file_size);
+ write_buffer = NULL;
+ file_size = 0;
+}
+
+/*
+ * --- LLVM line counter API ---
+ */
+
+/* A file in this case is a translation unit. Each .o file built with line
+ * profiling enabled will emit to a different file. Only one file may be
+ * started at a time.
+ */
+void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+ uint32_t checksum) {
+ const char *mode = "r+b";
+ filename = mangle_filename(orig_filename);
+
+ /* Try just opening the file. */
+ new_file = 0;
+ fd = open(filename, O_RDWR);
+
+ if (fd == -1) {
+ /* Try opening the file, creating it if necessary. */
+ new_file = 1;
+ mode = "w+b";
+ fd = open(filename, O_RDWR | O_CREAT, 0644);
+ if (fd == -1) {
+ /* Try creating the directories first then opening the file. */
+ recursive_mkdir(filename);
+ fd = open(filename, O_RDWR | O_CREAT, 0644);
+ if (fd == -1) {
+ /* Bah! It's hopeless. */
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
+ strerror(errnum));
+ return;
+ }
+ }
+ }
+
+ output_file = fdopen(fd, mode);
+
+ /* Initialize the write buffer. */
+ write_buffer = NULL;
+ cur_buffer_size = 0;
+ cur_pos = 0;
+
+ if (new_file) {
+ resize_write_buffer(WRITE_BUFFER_SIZE);
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ } else {
+ if (map_file() == -1) {
+ /* mmap failed, try to recover by clobbering */
+ new_file = 1;
+ write_buffer = NULL;
+ cur_buffer_size = 0;
+ resize_write_buffer(WRITE_BUFFER_SIZE);
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ }
+ }
+
+ /* gcda file, version, stamp checksum. */
+ write_bytes("adcg", 4);
+ write_bytes(version, 4);
+ write_32bit_value(checksum);
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
+#endif
+}
+
+/* Given an array of pointers to counters (counters), increment the n-th one,
+ * where we're also given a pointer to n (predecessor).
+ */
+void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
+ uint64_t **counters) {
+ uint64_t *counter;
+ uint32_t pred;
+
+ pred = *predecessor;
+ if (pred == 0xffffffff)
+ return;
+ counter = counters[pred];
+
+ /* Don't crash if the pred# is out of sync. This can happen due to threads,
+ or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */
+ if (counter)
+ ++*counter;
+#ifdef DEBUG_GCDAPROFILING
+ else
+ fprintf(stderr,
+ "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n",
+ *counter, *predecessor);
+#endif
+}
+
+void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
+ uint32_t func_checksum, uint8_t use_extra_checksum,
+ uint32_t cfg_checksum) {
+ uint32_t len = 2;
+
+ if (use_extra_checksum)
+ len++;
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident,
+ function_name ? function_name : "NULL");
+#endif
+ if (!output_file) return;
+
+ /* function tag */
+ write_bytes("\0\0\0\1", 4);
+ if (function_name)
+ len += 1 + length_of_string(function_name);
+ write_32bit_value(len);
+ write_32bit_value(ident);
+ write_32bit_value(func_checksum);
+ if (use_extra_checksum)
+ write_32bit_value(cfg_checksum);
+ if (function_name)
+ write_string(function_name);
+}
+
+void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
+ uint32_t i;
+ uint64_t *old_ctrs = NULL;
+ uint32_t val = 0;
+ uint64_t save_cur_pos = cur_pos;
+
+ if (!output_file) return;
+
+ val = read_32bit_value();
+
+ if (val != (uint32_t)-1) {
+ /* There are counters present in the file. Merge them. */
+ if (val != 0x01a10000) {
+ fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+ "corrupt arc tag (0x%08x)\n",
+ filename, val);
+ return;
+ }
+
+ val = read_32bit_value();
+ if (val == (uint32_t)-1 || val / 2 != num_counters) {
+ fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+ "mismatched number of counters (%d)\n",
+ filename, val);
+ return;
+ }
+
+ old_ctrs = malloc(sizeof(uint64_t) * num_counters);
+ for (i = 0; i < num_counters; ++i)
+ old_ctrs[i] = read_64bit_value();
+ }
+
+ cur_pos = save_cur_pos;
+
+ /* Counter #1 (arcs) tag */
+ write_bytes("\0\0\xa1\1", 4);
+ write_32bit_value(num_counters * 2);
+ for (i = 0; i < num_counters; ++i) {
+ counters[i] += (old_ctrs ? old_ctrs[i] : 0);
+ write_64bit_value(counters[i]);
+ }
+
+ free(old_ctrs);
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: %u arcs\n", num_counters);
+ for (i = 0; i < num_counters; ++i)
+ fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]);
+#endif
+}
+
+void llvm_gcda_summary_info() {
+ const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
+ uint32_t i;
+ uint32_t runs = 1;
+ uint32_t val = 0;
+ uint64_t save_cur_pos = cur_pos;
+
+ if (!output_file) return;
+
+ val = read_32bit_value();
+
+ if (val != (uint32_t)-1) {
+ /* There are counters present in the file. Merge them. */
+ if (val != 0xa1000000) {
+ fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+ "corrupt object tag (0x%08x)\n",
+ filename, val);
+ return;
+ }
+
+ val = read_32bit_value(); /* length */
+ if (val != obj_summary_len) {
+ fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+ "mismatched object length (%d)\n",
+ filename, val);
+ return;
+ }
+
+ read_32bit_value(); /* checksum, unused */
+ read_32bit_value(); /* num, unused */
+ runs += read_32bit_value(); /* Add previous run count to new counter. */
+ }
+
+ cur_pos = save_cur_pos;
+
+ /* Object summary tag */
+ write_bytes("\0\0\0\xa1", 4);
+ write_32bit_value(obj_summary_len);
+ write_32bit_value(0); /* checksum, unused */
+ write_32bit_value(0); /* num, unused */
+ write_32bit_value(runs);
+ for (i = 3; i < obj_summary_len; ++i)
+ write_32bit_value(0);
+
+ /* Program summary tag */
+ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */
+ write_32bit_value(0); /* 0 length */
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: %u runs\n", runs);
+#endif
+}
+
+void llvm_gcda_end_file() {
+ /* Write out EOF record. */
+ if (output_file) {
+ write_bytes("\0\0\0\0\0\0\0\0", 8);
+
+ if (new_file) {
+ fwrite(write_buffer, cur_pos, 1, output_file);
+ free(write_buffer);
+ } else {
+ unmap_file();
+ }
+
+ fclose(output_file);
+ output_file = NULL;
+ write_buffer = NULL;
+ }
+ free(filename);
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: -----\n");
+#endif
+}
+
+void llvm_register_writeout_function(writeout_fn fn) {
+ struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node));
+ new_node->fn = fn;
+ new_node->next = NULL;
+
+ if (!writeout_fn_head) {
+ writeout_fn_head = writeout_fn_tail = new_node;
+ } else {
+ writeout_fn_tail->next = new_node;
+ writeout_fn_tail = new_node;
+ }
+}
+
+void llvm_writeout_files() {
+ struct writeout_fn_node *curr = writeout_fn_head;
+
+ while (curr) {
+ curr->fn();
+ curr = curr->next;
+ }
+}
+
+void llvm_delete_writeout_function_list() {
+ while (writeout_fn_head) {
+ struct writeout_fn_node *node = writeout_fn_head;
+ writeout_fn_head = writeout_fn_head->next;
+ free(node);
+ }
+
+ writeout_fn_head = writeout_fn_tail = NULL;
+}
+
+void llvm_register_flush_function(flush_fn fn) {
+ struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node));
+ new_node->fn = fn;
+ new_node->next = NULL;
+
+ if (!flush_fn_head) {
+ flush_fn_head = flush_fn_tail = new_node;
+ } else {
+ flush_fn_tail->next = new_node;
+ flush_fn_tail = new_node;
+ }
+}
+
+void __gcov_flush() {
+ struct flush_fn_node *curr = flush_fn_head;
+
+ while (curr) {
+ curr->fn();
+ curr = curr->next;
+ }
+}
+
+void llvm_delete_flush_function_list() {
+ while (flush_fn_head) {
+ struct flush_fn_node *node = flush_fn_head;
+ flush_fn_head = flush_fn_head->next;
+ free(node);
+ }
+
+ flush_fn_head = flush_fn_tail = NULL;
+}
+
+void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) {
+ static int atexit_ran = 0;
+
+ if (wfn)
+ llvm_register_writeout_function(wfn);
+
+ if (ffn)
+ llvm_register_flush_function(ffn);
+
+ if (atexit_ran == 0) {
+ atexit_ran = 1;
+
+ /* Make sure we write out the data and delete the data structures. */
+ atexit(llvm_delete_flush_function_list);
+ atexit(llvm_delete_writeout_function_list);
+ atexit(llvm_writeout_files);
+ }
+}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfiling.c b/contrib/compiler-rt/lib/profile/InstrProfiling.c
new file mode 100644
index 000000000000..8d010df28f18
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfiling.c
@@ -0,0 +1,48 @@
+/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include <string.h>
+
+__attribute__((visibility("hidden")))
+uint64_t __llvm_profile_get_magic(void) {
+ /* Magic number to detect file format and endianness.
+ *
+ * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0,
+ * so that utilities, like strings, don't grab it as a string. 129 is also
+ * invalid UTF-8, and high enough to be interesting.
+ *
+ * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR"
+ * for 32-bit platforms.
+ */
+ unsigned char R = sizeof(void *) == sizeof(uint64_t) ? 'r' : 'R';
+ return
+ (uint64_t)255 << 56 |
+ (uint64_t)'l' << 48 |
+ (uint64_t)'p' << 40 |
+ (uint64_t)'r' << 32 |
+ (uint64_t)'o' << 24 |
+ (uint64_t)'f' << 16 |
+ (uint64_t) R << 8 |
+ (uint64_t)129;
+}
+
+__attribute__((visibility("hidden")))
+uint64_t __llvm_profile_get_version(void) {
+ /* This should be bumped any time the output format changes. */
+ return 1;
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_reset_counters(void) {
+ uint64_t *I = __llvm_profile_begin_counters();
+ uint64_t *E = __llvm_profile_end_counters();
+
+ memset(I, 0, sizeof(uint64_t)*(E - I));
+}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfiling.h b/contrib/compiler-rt/lib/profile/InstrProfiling.h
new file mode 100644
index 000000000000..2b1bd003668e
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfiling.h
@@ -0,0 +1,92 @@
+/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_H_
+#define PROFILE_INSTRPROFILING_H_
+
+#if defined(__FreeBSD__) && defined(__i386__)
+
+/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
+ * FreeBSD 10, r232261) when compiled in 32-bit mode.
+ */
+#define PRIu64 "llu"
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef uint32_t uintptr_t;
+
+#else /* defined(__FreeBSD__) && defined(__i386__) */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#endif /* defined(__FreeBSD__) && defined(__i386__) */
+
+#define PROFILE_HEADER_SIZE 7
+
+typedef struct __llvm_profile_data {
+ const uint32_t NameSize;
+ const uint32_t NumCounters;
+ const uint64_t FuncHash;
+ const char *const Name;
+ uint64_t *const Counters;
+} __llvm_profile_data;
+
+/*!
+ * \brief Get required size for profile buffer.
+ */
+uint64_t __llvm_profile_get_size_for_buffer(void);
+
+/*!
+ * \brief Write instrumentation data to the given buffer.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer().
+ */
+int __llvm_profile_write_buffer(char *Buffer);
+
+const __llvm_profile_data *__llvm_profile_begin_data(void);
+const __llvm_profile_data *__llvm_profile_end_data(void);
+const char *__llvm_profile_begin_names(void);
+const char *__llvm_profile_end_names(void);
+uint64_t *__llvm_profile_begin_counters(void);
+uint64_t *__llvm_profile_end_counters(void);
+
+/*!
+ * \brief Write instrumentation data to the current file.
+ *
+ * Writes to the file with the last name given to \a __llvm_profile_set_filename(),
+ * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
+ * or if that's not set, \c "default.profdata".
+ */
+int __llvm_profile_write_file(void);
+
+/*!
+ * \brief Set the filename for writing instrumentation data.
+ *
+ * Sets the filename to be used for subsequent calls to
+ * \a __llvm_profile_write_file().
+ *
+ * \c Name is not copied, so it must remain valid. Passing NULL resets the
+ * filename logic to the default behaviour.
+ */
+void __llvm_profile_set_filename(const char *Name);
+
+/*! \brief Register to write instrumentation data to file at exit. */
+int __llvm_profile_register_write_file_atexit(void);
+
+/*! \brief Initialize file handling. */
+void __llvm_profile_initialize_file(void);
+
+/*! \brief Get the magic token for the file format. */
+uint64_t __llvm_profile_get_magic(void);
+
+/*! \brief Get the version of the file format. */
+uint64_t __llvm_profile_get_version(void);
+
+#endif /* PROFILE_INSTRPROFILING_H_ */
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c b/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c
new file mode 100644
index 000000000000..3c429c8a85ea
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -0,0 +1,104 @@
+/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+
+#include <string.h>
+
+__attribute__((visibility("hidden")))
+uint64_t __llvm_profile_get_size_for_buffer(void) {
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+
+ return __llvm_profile_get_size_for_buffer_internal(
+ DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
+}
+
+#define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin)
+
+__attribute__((visibility("hidden")))
+uint64_t __llvm_profile_get_size_for_buffer_internal(
+ const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd, const char *NamesBegin,
+ const char *NamesEnd) {
+ /* Match logic in __llvm_profile_write_buffer(). */
+ const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char);
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+ return sizeof(uint64_t) * PROFILE_HEADER_SIZE +
+ PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
+ PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) +
+ NamesSize + Padding;
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_write_buffer(char *Buffer) {
+ /* Match logic in __llvm_profile_get_size_for_buffer().
+ * Match logic in __llvm_profile_write_file().
+ */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+
+ return __llvm_profile_write_buffer_internal(Buffer, DataBegin, DataEnd,
+ CountersBegin, CountersEnd,
+ NamesBegin, NamesEnd);
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_write_buffer_internal(
+ char *Buffer, const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
+ /* Match logic in __llvm_profile_get_size_for_buffer().
+ * Match logic in __llvm_profile_write_file().
+ */
+
+ /* Calculate size of sections. */
+ const uint64_t DataSize = DataEnd - DataBegin;
+ const uint64_t CountersSize = CountersEnd - CountersBegin;
+ const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
+
+ /* Create the header. */
+ uint64_t Header[PROFILE_HEADER_SIZE];
+ Header[0] = __llvm_profile_get_magic();
+ Header[1] = __llvm_profile_get_version();
+ Header[2] = DataSize;
+ Header[3] = CountersSize;
+ Header[4] = NamesSize;
+ Header[5] = (uintptr_t)CountersBegin;
+ Header[6] = (uintptr_t)NamesBegin;
+
+ /* Write the data. */
+#define UPDATE_memcpy(Data, Size) \
+ do { \
+ memcpy(Buffer, Data, Size); \
+ Buffer += Size; \
+ } while (0)
+ UPDATE_memcpy(Header, PROFILE_HEADER_SIZE * sizeof(uint64_t));
+ UPDATE_memcpy(DataBegin, DataSize * sizeof(__llvm_profile_data));
+ UPDATE_memcpy(CountersBegin, CountersSize * sizeof(uint64_t));
+ UPDATE_memcpy(NamesBegin, NamesSize * sizeof(char));
+ UPDATE_memcpy(Zeroes, Padding * sizeof(char));
+#undef UPDATE_memcpy
+
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingFile.c b/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
new file mode 100644
index 000000000000..346665fd5b3e
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -0,0 +1,199 @@
+/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
+
+static int writeFile(FILE *File) {
+ /* Match logic in __llvm_profile_write_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+
+ /* Calculate size of sections. */
+ const uint64_t DataSize = DataEnd - DataBegin;
+ const uint64_t CountersSize = CountersEnd - CountersBegin;
+ const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
+
+ /* Create the header. */
+ uint64_t Header[PROFILE_HEADER_SIZE];
+ Header[0] = __llvm_profile_get_magic();
+ Header[1] = __llvm_profile_get_version();
+ Header[2] = DataSize;
+ Header[3] = CountersSize;
+ Header[4] = NamesSize;
+ Header[5] = (uintptr_t)CountersBegin;
+ Header[6] = (uintptr_t)NamesBegin;
+
+ /* Write the data. */
+#define CHECK_fwrite(Data, Size, Length, File) \
+ do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
+ CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
+ CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
+ CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
+ CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
+ CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
+#undef CHECK_fwrite
+
+ return 0;
+}
+
+static int writeFileWithName(const char *OutputName) {
+ int RetVal;
+ FILE *OutputFile;
+ if (!OutputName || !OutputName[0])
+ return -1;
+
+ /* Append to the file to support profiling multiple shared objects. */
+ OutputFile = fopen(OutputName, "a");
+ if (!OutputFile)
+ return -1;
+
+ RetVal = writeFile(OutputFile);
+
+ fclose(OutputFile);
+ return RetVal;
+}
+
+__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
+__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
+
+static void setFilename(const char *Filename, int OwnsFilename) {
+ if (__llvm_profile_OwnsFilename)
+ free(UNCONST(__llvm_profile_CurrentFilename));
+
+ __llvm_profile_CurrentFilename = Filename;
+ __llvm_profile_OwnsFilename = OwnsFilename;
+}
+
+static void truncateCurrentFile(void) {
+ const char *Filename = __llvm_profile_CurrentFilename;
+ if (!Filename || !Filename[0])
+ return;
+
+ /* Truncate the file. Later we'll reopen and append. */
+ FILE *File = fopen(Filename, "w");
+ if (!File)
+ return;
+ fclose(File);
+}
+
+static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
+
+int getpid(void);
+static int setFilenameFromEnvironment(void) {
+ const char *Filename = getenv("LLVM_PROFILE_FILE");
+ if (!Filename || !Filename[0])
+ return -1;
+
+ /* Check the filename for "%p", which indicates a pid-substitution. */
+#define MAX_PID_SIZE 16
+ char PidChars[MAX_PID_SIZE] = {0};
+ int NumPids = 0;
+ int PidLength = 0;
+ int I;
+ for (I = 0; Filename[I]; ++I)
+ if (Filename[I] == '%' && Filename[++I] == 'p')
+ if (!NumPids++) {
+ PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
+ if (PidLength <= 0)
+ return -1;
+ }
+ if (!NumPids) {
+ setFilename(Filename, 0);
+ return 0;
+ }
+
+ /* Allocate enough space for the substituted filename. */
+ char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
+ if (!Allocated)
+ return -1;
+
+ /* Construct the new filename. */
+ int J;
+ for (I = 0, J = 0; Filename[I]; ++I)
+ if (Filename[I] == '%') {
+ if (Filename[++I] == 'p') {
+ memcpy(Allocated + J, PidChars, PidLength);
+ J += PidLength;
+ }
+ /* Drop any unknown substitutions. */
+ } else
+ Allocated[J++] = Filename[I];
+ Allocated[J] = 0;
+
+ /* Use the computed name. */
+ setFilename(Allocated, 1);
+ return 0;
+}
+
+static void setFilenameAutomatically(void) {
+ if (!setFilenameFromEnvironment())
+ return;
+
+ setDefaultFilename();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_initialize_file(void) {
+ /* Check if the filename has been initialized. */
+ if (__llvm_profile_CurrentFilename)
+ return;
+
+ /* Detect the filename and truncate. */
+ setFilenameAutomatically();
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_set_filename(const char *Filename) {
+ setFilename(Filename, 0);
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_write_file(void) {
+ /* Check the filename. */
+ if (!__llvm_profile_CurrentFilename)
+ return -1;
+
+ /* Write the file. */
+ int rc = writeFileWithName(__llvm_profile_CurrentFilename);
+ if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
+ fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
+ __llvm_profile_CurrentFilename, strerror(errno));
+ return rc;
+}
+
+static void writeFileWithoutReturn(void) {
+ __llvm_profile_write_file();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_register_write_file_atexit(void) {
+ static int HasBeenRegistered = 0;
+
+ if (HasBeenRegistered)
+ return 0;
+
+ HasBeenRegistered = 1;
+ return atexit(writeFileWithoutReturn);
+}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h b/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h
new file mode 100644
index 000000000000..ede39cd9d713
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h
@@ -0,0 +1,40 @@
+/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_INTERNALH_
+#define PROFILE_INSTRPROFILING_INTERNALH_
+
+#include "InstrProfiling.h"
+
+/*!
+ * \brief Write instrumentation data to the given buffer, given explicit
+ * pointers to the live data in memory. This function is probably not what you
+ * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if
+ * your program has a custom memory layout.
+ */
+uint64_t __llvm_profile_get_size_for_buffer_internal(
+ const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin, const uint64_t *CountersEnd,
+ const char *NamesBegin, const char *NamesEnd);
+
+/*!
+ * \brief Write instrumentation data to the given buffer, given explicit
+ * pointers to the live data in memory. This function is probably not what you
+ * want. Use __llvm_profile_write_buffer instead. Use this function if your
+ * program has a custom memory layout.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer_internal().
+ */
+int __llvm_profile_write_buffer_internal(
+ char *Buffer, const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd);
+
+#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
new file mode 100644
index 000000000000..02299cc4630c
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
@@ -0,0 +1,43 @@
+/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+#if defined(__APPLE__)
+/* Use linker magic to find the bounds of the Data section. */
+__attribute__((visibility("hidden")))
+extern __llvm_profile_data DataStart __asm("section$start$__DATA$__llvm_prf_data");
+__attribute__((visibility("hidden")))
+extern __llvm_profile_data DataEnd __asm("section$end$__DATA$__llvm_prf_data");
+__attribute__((visibility("hidden")))
+extern char NamesStart __asm("section$start$__DATA$__llvm_prf_names");
+__attribute__((visibility("hidden")))
+extern char NamesEnd __asm("section$end$__DATA$__llvm_prf_names");
+__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");
+
+__attribute__((visibility("hidden")))
+const __llvm_profile_data *__llvm_profile_begin_data(void) {
+ return &DataStart;
+}
+__attribute__((visibility("hidden")))
+const __llvm_profile_data *__llvm_profile_end_data(void) {
+ return &DataEnd;
+}
+__attribute__((visibility("hidden")))
+const char *__llvm_profile_begin_names(void) { return &NamesStart; }
+__attribute__((visibility("hidden")))
+const char *__llvm_profile_end_names(void) { return &NamesEnd; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
+#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
new file mode 100644
index 000000000000..548d6a396b76
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
@@ -0,0 +1,74 @@
+/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+#if !defined(__APPLE__)
+#include <stdlib.h>
+
+static const __llvm_profile_data *DataFirst = NULL;
+static const __llvm_profile_data *DataLast = NULL;
+static const char *NamesFirst = NULL;
+static const char *NamesLast = NULL;
+static uint64_t *CountersFirst = NULL;
+static uint64_t *CountersLast = NULL;
+
+/*!
+ * \brief Register an instrumented function.
+ *
+ * Calls to this are emitted by clang with -fprofile-instr-generate. Such
+ * calls are only required (and only emitted) on targets where we haven't
+ * implemented linker magic to find the bounds of the sections.
+ */
+__attribute__((visibility("hidden")))
+void __llvm_profile_register_function(void *Data_) {
+ /* TODO: Only emit this function if we can't use linker magic. */
+ const __llvm_profile_data *Data = (__llvm_profile_data*)Data_;
+ if (!DataFirst) {
+ DataFirst = Data;
+ DataLast = Data + 1;
+ NamesFirst = Data->Name;
+ NamesLast = Data->Name + Data->NameSize;
+ CountersFirst = Data->Counters;
+ CountersLast = Data->Counters + Data->NumCounters;
+ return;
+ }
+
+#define UPDATE_FIRST(First, New) \
+ First = New < First ? New : First
+ UPDATE_FIRST(DataFirst, Data);
+ UPDATE_FIRST(NamesFirst, Data->Name);
+ UPDATE_FIRST(CountersFirst, Data->Counters);
+#undef UPDATE_FIRST
+
+#define UPDATE_LAST(Last, New) \
+ Last = New > Last ? New : Last
+ UPDATE_LAST(DataLast, Data + 1);
+ UPDATE_LAST(NamesLast, Data->Name + Data->NameSize);
+ UPDATE_LAST(CountersLast, Data->Counters + Data->NumCounters);
+#undef UPDATE_LAST
+}
+
+__attribute__((visibility("hidden")))
+const __llvm_profile_data *__llvm_profile_begin_data(void) {
+ return DataFirst;
+}
+__attribute__((visibility("hidden")))
+const __llvm_profile_data *__llvm_profile_end_data(void) {
+ return DataLast;
+}
+__attribute__((visibility("hidden")))
+const char *__llvm_profile_begin_names(void) { return NamesFirst; }
+__attribute__((visibility("hidden")))
+const char *__llvm_profile_end_names(void) { return NamesLast; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
+#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc b/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc
new file mode 100644
index 000000000000..081ecb29e987
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc
@@ -0,0 +1,30 @@
+//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+#include "InstrProfiling.h"
+
+__attribute__((visibility("hidden"))) int __llvm_profile_runtime;
+
+}
+
+namespace {
+
+class RegisterRuntime {
+public:
+ RegisterRuntime() {
+ __llvm_profile_register_write_file_atexit();
+ __llvm_profile_initialize_file();
+ }
+};
+
+RegisterRuntime Registration;
+
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
new file mode 100644
index 000000000000..acf4ff020939
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
@@ -0,0 +1,342 @@
+//===-- sanitizer_addrhashmap.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Concurrent uptr->T hashmap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ADDRHASHMAP_H
+#define SANITIZER_ADDRHASHMAP_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_allocator_internal.h"
+
+namespace __sanitizer {
+
+// Concurrent uptr->T hashmap.
+// T must be a POD type, kSize is preferably a prime but can be any number.
+// Usage example:
+//
+// typedef AddrHashMap<uptr, 11> Map;
+// Map m;
+// {
+// Map::Handle h(&m, addr);
+// use h.operator->() to access the data
+// if h.created() then the element was just created, and the current thread
+// has exclusive access to it
+// otherwise the current thread has only read access to the data
+// }
+// {
+// Map::Handle h(&m, addr, true);
+// this will remove the data from the map in Handle dtor
+// the current thread has exclusive access to the data
+// if !h.exists() then the element never existed
+// }
+template<typename T, uptr kSize>
+class AddrHashMap {
+ private:
+ struct Cell {
+ atomic_uintptr_t addr;
+ T val;
+ };
+
+ struct AddBucket {
+ uptr cap;
+ uptr size;
+ Cell cells[1]; // variable len
+ };
+
+ static const uptr kBucketSize = 3;
+
+ struct Bucket {
+ RWMutex mtx;
+ atomic_uintptr_t add;
+ Cell cells[kBucketSize];
+ };
+
+ public:
+ AddrHashMap();
+
+ class Handle {
+ public:
+ Handle(AddrHashMap<T, kSize> *map, uptr addr);
+ Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove);
+ Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create);
+
+ ~Handle();
+ T *operator->();
+ bool created() const;
+ bool exists() const;
+
+ private:
+ friend AddrHashMap<T, kSize>;
+ AddrHashMap<T, kSize> *map_;
+ Bucket *bucket_;
+ Cell *cell_;
+ uptr addr_;
+ uptr addidx_;
+ bool created_;
+ bool remove_;
+ bool create_;
+ };
+
+ private:
+ friend class Handle;
+ Bucket *table_;
+
+ void acquire(Handle *h);
+ void release(Handle *h);
+ uptr calcHash(uptr addr);
+};
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = false;
+ create_ = true;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+ bool remove) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = remove;
+ create_ = true;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+ bool remove, bool create) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = remove;
+ create_ = create;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::~Handle() {
+ map_->release(this);
+}
+
+template <typename T, uptr kSize>
+T *AddrHashMap<T, kSize>::Handle::operator->() {
+ return &cell_->val;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::created() const {
+ return created_;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::exists() const {
+ return cell_ != 0;
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::AddrHashMap() {
+ table_ = (Bucket*)MmapOrDie(kSize * sizeof(table_[0]), "AddrHashMap");
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::acquire(Handle *h) {
+ uptr addr = h->addr_;
+ uptr hash = calcHash(addr);
+ Bucket *b = &table_[hash];
+
+ h->created_ = false;
+ h->addidx_ = -1U;
+ h->bucket_ = b;
+ h->cell_ = 0;
+
+ // If we want to remove the element, we need exclusive access to the bucket,
+ // so skip the lock-free phase.
+ if (h->remove_)
+ goto locked;
+
+ retry:
+ // First try to find an existing element w/o read mutex.
+ CHECK(!h->remove_);
+ // Check the embed cells.
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_acquire);
+ if (addr1 == addr) {
+ h->cell_ = c;
+ return;
+ }
+ }
+
+ // Check the add cells with read lock.
+ if (atomic_load(&b->add, memory_order_relaxed)) {
+ b->mtx.ReadLock();
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ h->addidx_ = i;
+ h->cell_ = c;
+ return;
+ }
+ }
+ b->mtx.ReadUnlock();
+ }
+
+ locked:
+ // Re-check existence under write lock.
+ // Embed cells.
+ b->mtx.Lock();
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ if (h->remove_) {
+ h->cell_ = c;
+ return;
+ }
+ b->mtx.Unlock();
+ goto retry;
+ }
+ }
+
+ // Add cells.
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ if (add) {
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ if (h->remove_) {
+ h->addidx_ = i;
+ h->cell_ = c;
+ return;
+ }
+ b->mtx.Unlock();
+ goto retry;
+ }
+ }
+ }
+
+ // The element does not exist, no need to create it if we want to remove.
+ if (h->remove_ || !h->create_) {
+ b->mtx.Unlock();
+ return;
+ }
+
+ // Now try to create it under the mutex.
+ h->created_ = true;
+ // See if we have a free embed cell.
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == 0) {
+ h->cell_ = c;
+ return;
+ }
+ }
+
+ // Store in the add cells.
+ if (add == 0) {
+ // Allocate a new add array.
+ const uptr kInitSize = 64;
+ add = (AddBucket*)InternalAlloc(kInitSize);
+ internal_memset(add, 0, kInitSize);
+ add->cap = (kInitSize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+ add->size = 0;
+ atomic_store(&b->add, (uptr)add, memory_order_relaxed);
+ }
+ if (add->size == add->cap) {
+ // Grow existing add array.
+ uptr oldsize = sizeof(*add) + (add->cap - 1) * sizeof(add->cells[0]);
+ uptr newsize = oldsize * 2;
+ AddBucket *add1 = (AddBucket*)InternalAlloc(newsize);
+ internal_memset(add1, 0, newsize);
+ add1->cap = (newsize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+ add1->size = add->size;
+ internal_memcpy(add1->cells, add->cells, add->size * sizeof(add->cells[0]));
+ InternalFree(add);
+ atomic_store(&b->add, (uptr)add1, memory_order_relaxed);
+ add = add1;
+ }
+ // Store.
+ uptr i = add->size++;
+ Cell *c = &add->cells[i];
+ CHECK_EQ(atomic_load(&c->addr, memory_order_relaxed), 0);
+ h->addidx_ = i;
+ h->cell_ = c;
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::release(Handle *h) {
+ if (h->cell_ == 0)
+ return;
+ Bucket *b = h->bucket_;
+ Cell *c = h->cell_;
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (h->created_) {
+ // Denote completion of insertion.
+ CHECK_EQ(addr1, 0);
+ // After the following store, the element becomes available
+ // for lock-free reads.
+ atomic_store(&c->addr, h->addr_, memory_order_release);
+ b->mtx.Unlock();
+ } else if (h->remove_) {
+ // Denote that the cell is empty now.
+ CHECK_EQ(addr1, h->addr_);
+ atomic_store(&c->addr, 0, memory_order_release);
+ // See if we need to compact the bucket.
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ if (h->addidx_ == -1U) {
+ // Removed from embed array, move an add element into the freed cell.
+ if (add && add->size != 0) {
+ uptr last = --add->size;
+ Cell *c1 = &add->cells[last];
+ c->val = c1->val;
+ uptr addr1 = atomic_load(&c1->addr, memory_order_relaxed);
+ atomic_store(&c->addr, addr1, memory_order_release);
+ atomic_store(&c1->addr, 0, memory_order_release);
+ }
+ } else {
+ // Removed from add array, compact it.
+ uptr last = --add->size;
+ Cell *c1 = &add->cells[last];
+ if (c != c1) {
+ *c = *c1;
+ atomic_store(&c1->addr, 0, memory_order_relaxed);
+ }
+ }
+ if (add && add->size == 0) {
+ // FIXME(dvyukov): free add?
+ }
+ b->mtx.Unlock();
+ } else {
+ CHECK_EQ(addr1, h->addr_);
+ if (h->addidx_ != -1U)
+ b->mtx.ReadUnlock();
+ }
+}
+
+template<typename T, uptr kSize>
+uptr AddrHashMap<T, kSize>::calcHash(uptr addr) {
+ addr += addr << 10;
+ addr ^= addr >> 6;
+ return addr % kSize;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ADDRHASHMAP_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
new file mode 100644
index 000000000000..03b3e83153de
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
@@ -0,0 +1,150 @@
+//===-- sanitizer_allocator.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// This allocator is used inside run-times.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_allocator.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// ThreadSanitizer for Go uses libc malloc/free.
+#if defined(SANITIZER_GO) || defined(SANITIZER_USE_MALLOC)
+# if SANITIZER_LINUX && !SANITIZER_ANDROID
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void __libc_free(void *ptr);
+# define LIBC_MALLOC __libc_malloc
+# define LIBC_FREE __libc_free
+# else
+# include <stdlib.h>
+# define LIBC_MALLOC malloc
+# define LIBC_FREE free
+# endif
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ (void)cache;
+ return LIBC_MALLOC(size);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+ (void)cache;
+ LIBC_FREE(ptr);
+}
+
+InternalAllocator *internal_allocator() {
+ return 0;
+}
+
+#else // SANITIZER_GO
+
+static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
+static atomic_uint8_t internal_allocator_initialized;
+static StaticSpinMutex internal_alloc_init_mu;
+
+static InternalAllocatorCache internal_allocator_cache;
+static StaticSpinMutex internal_allocator_cache_mu;
+
+InternalAllocator *internal_allocator() {
+ InternalAllocator *internal_allocator_instance =
+ reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder);
+ if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) {
+ SpinMutexLock l(&internal_alloc_init_mu);
+ if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
+ 0) {
+ internal_allocator_instance->Init(/* may_return_null*/ false);
+ atomic_store(&internal_allocator_initialized, 1, memory_order_release);
+ }
+ }
+ return internal_allocator_instance;
+}
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ if (cache == 0) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Allocate(&internal_allocator_cache, size, 8,
+ false);
+ }
+ return internal_allocator()->Allocate(cache, size, 8, false);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+ if (cache == 0) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Deallocate(&internal_allocator_cache, ptr);
+ }
+ internal_allocator()->Deallocate(cache, ptr);
+}
+
+#endif // SANITIZER_GO
+
+const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ if (size + sizeof(u64) < size)
+ return 0;
+ void *p = RawInternalAlloc(size + sizeof(u64), cache);
+ if (p == 0)
+ return 0;
+ ((u64*)p)[0] = kBlockMagic;
+ return (char*)p + sizeof(u64);
+}
+
+void InternalFree(void *addr, InternalAllocatorCache *cache) {
+ if (addr == 0)
+ return;
+ addr = (char*)addr - sizeof(u64);
+ CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
+ ((u64*)addr)[0] = 0;
+ RawInternalFree(addr, cache);
+}
+
+// LowLevelAllocator
+static LowLevelAllocateCallback low_level_alloc_callback;
+
+void *LowLevelAllocator::Allocate(uptr size) {
+ // Align allocation size.
+ size = RoundUpTo(size, 8);
+ if (allocated_end_ - allocated_current_ < (sptr)size) {
+ uptr size_to_allocate = Max(size, GetPageSizeCached());
+ allocated_current_ =
+ (char*)MmapOrDie(size_to_allocate, __func__);
+ allocated_end_ = allocated_current_ + size_to_allocate;
+ if (low_level_alloc_callback) {
+ low_level_alloc_callback((uptr)allocated_current_,
+ size_to_allocate);
+ }
+ }
+ CHECK(allocated_end_ - allocated_current_ >= (sptr)size);
+ void *res = allocated_current_;
+ allocated_current_ += size;
+ return res;
+}
+
+void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
+ low_level_alloc_callback = callback;
+}
+
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
+ if (!size) return false;
+ uptr max = (uptr)-1L;
+ return (max / size) < n;
+}
+
+void NORETURN ReportAllocatorCannotReturnNull() {
+ Report("%s's allocator is terminating the process instead of returning 0\n",
+ SanitizerToolName);
+ Report("If you don't like this behavior set allocator_may_return_null=1\n");
+ CHECK(0);
+ Die();
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
new file mode 100644
index 000000000000..b5105f8c2555
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
@@ -0,0 +1,1451 @@
+//===-- sanitizer_allocator.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specialized memory allocator for ThreadSanitizer, MemorySanitizer, etc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_H
+#define SANITIZER_ALLOCATOR_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_lfstack.h"
+
+namespace __sanitizer {
+
+// Prints error message and kills the program.
+void NORETURN ReportAllocatorCannotReturnNull();
+
+// SizeClassMap maps allocation sizes into size classes and back.
+// Class 0 corresponds to size 0.
+// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
+// Next 4 classes: 256 + i * 64 (i = 1 to 4).
+// Next 4 classes: 512 + i * 128 (i = 1 to 4).
+// ...
+// Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4).
+// Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
+//
+// This structure of the size class map gives us:
+// - Efficient table-free class-to-size and size-to-class functions.
+// - Difference between two consequent size classes is betweed 14% and 25%
+//
+// This class also gives a hint to a thread-caching allocator about the amount
+// of chunks that need to be cached per-thread:
+// - kMaxNumCached is the maximal number of chunks per size class.
+// - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
+//
+// Part of output of SizeClassMap::Print():
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
+// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
+// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
+// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
+// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
+// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
+// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
+//
+// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
+// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
+// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
+// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
+// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
+// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
+// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
+// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
+//
+// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
+// c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17
+// c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18
+// c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19
+//
+// c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20
+// c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21
+// c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22
+// c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23
+//
+// c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24
+// c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25
+// c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26
+// c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27
+//
+// ...
+//
+// c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48
+// c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49
+// c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50
+// c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51
+//
+// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52
+
+template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog>
+class SizeClassMap {
+ static const uptr kMinSizeLog = 4;
+ static const uptr kMidSizeLog = kMinSizeLog + 4;
+ static const uptr kMinSize = 1 << kMinSizeLog;
+ static const uptr kMidSize = 1 << kMidSizeLog;
+ static const uptr kMidClass = kMidSize / kMinSize;
+ static const uptr S = 2;
+ static const uptr M = (1 << S) - 1;
+
+ public:
+ static const uptr kMaxNumCached = kMaxNumCachedT;
+ // We transfer chunks between central and thread-local free lists in batches.
+ // For small size classes we allocate batches separately.
+ // For large size classes we use one of the chunks to store the batch.
+ struct TransferBatch {
+ TransferBatch *next;
+ uptr count;
+ void *batch[kMaxNumCached];
+ };
+
+ static const uptr kMaxSize = 1UL << kMaxSizeLog;
+ static const uptr kNumClasses =
+ kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
+ COMPILER_CHECK(kNumClasses >= 32 && kNumClasses <= 256);
+ static const uptr kNumClassesRounded =
+ kNumClasses == 32 ? 32 :
+ kNumClasses <= 64 ? 64 :
+ kNumClasses <= 128 ? 128 : 256;
+
+ static uptr Size(uptr class_id) {
+ if (class_id <= kMidClass)
+ return kMinSize * class_id;
+ class_id -= kMidClass;
+ uptr t = kMidSize << (class_id >> S);
+ return t + (t >> S) * (class_id & M);
+ }
+
+ static uptr ClassID(uptr size) {
+ if (size <= kMidSize)
+ return (size + kMinSize - 1) >> kMinSizeLog;
+ if (size > kMaxSize) return 0;
+ uptr l = MostSignificantSetBitIndex(size);
+ uptr hbits = (size >> (l - S)) & M;
+ uptr lbits = size & ((1 << (l - S)) - 1);
+ uptr l1 = l - kMidSizeLog;
+ return kMidClass + (l1 << S) + hbits + (lbits > 0);
+ }
+
+ static uptr MaxCached(uptr class_id) {
+ if (class_id == 0) return 0;
+ uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
+ return Max<uptr>(1, Min(kMaxNumCached, n));
+ }
+
+ static void Print() {
+ uptr prev_s = 0;
+ uptr total_cached = 0;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ uptr s = Size(i);
+ if (s >= kMidSize / 2 && (s & (s - 1)) == 0)
+ Printf("\n");
+ uptr d = s - prev_s;
+ uptr p = prev_s ? (d * 100 / prev_s) : 0;
+ uptr l = s ? MostSignificantSetBitIndex(s) : 0;
+ uptr cached = MaxCached(i) * s;
+ Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
+ "cached: %zd %zd; id %zd\n",
+ i, Size(i), d, p, l, MaxCached(i), cached, ClassID(s));
+ total_cached += cached;
+ prev_s = s;
+ }
+ Printf("Total cached: %zd\n", total_cached);
+ }
+
+ static bool SizeClassRequiresSeparateTransferBatch(uptr class_id) {
+ return Size(class_id) < sizeof(TransferBatch) -
+ sizeof(uptr) * (kMaxNumCached - MaxCached(class_id));
+ }
+
+ static void Validate() {
+ for (uptr c = 1; c < kNumClasses; c++) {
+ // Printf("Validate: c%zd\n", c);
+ uptr s = Size(c);
+ CHECK_NE(s, 0U);
+ CHECK_EQ(ClassID(s), c);
+ if (c != kNumClasses - 1)
+ CHECK_EQ(ClassID(s + 1), c + 1);
+ CHECK_EQ(ClassID(s - 1), c);
+ if (c)
+ CHECK_GT(Size(c), Size(c-1));
+ }
+ CHECK_EQ(ClassID(kMaxSize + 1), 0);
+
+ for (uptr s = 1; s <= kMaxSize; s++) {
+ uptr c = ClassID(s);
+ // Printf("s%zd => c%zd\n", s, c);
+ CHECK_LT(c, kNumClasses);
+ CHECK_GE(Size(c), s);
+ if (c > 0)
+ CHECK_LT(Size(c-1), s);
+ }
+ }
+};
+
+typedef SizeClassMap<17, 128, 16> DefaultSizeClassMap;
+typedef SizeClassMap<17, 64, 14> CompactSizeClassMap;
+template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
+
+// Memory allocator statistics
+enum AllocatorStat {
+ AllocatorStatAllocated,
+ AllocatorStatMapped,
+ AllocatorStatCount
+};
+
+typedef uptr AllocatorStatCounters[AllocatorStatCount];
+
+// Per-thread stats, live in per-thread cache.
+class AllocatorStats {
+ public:
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ }
+ void InitLinkerInitialized() {}
+
+ void Add(AllocatorStat i, uptr v) {
+ v += atomic_load(&stats_[i], memory_order_relaxed);
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Sub(AllocatorStat i, uptr v) {
+ v = atomic_load(&stats_[i], memory_order_relaxed) - v;
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Set(AllocatorStat i, uptr v) {
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ uptr Get(AllocatorStat i) const {
+ return atomic_load(&stats_[i], memory_order_relaxed);
+ }
+
+ private:
+ friend class AllocatorGlobalStats;
+ AllocatorStats *next_;
+ AllocatorStats *prev_;
+ atomic_uintptr_t stats_[AllocatorStatCount];
+};
+
+// Global stats, used for aggregation and querying.
+class AllocatorGlobalStats : public AllocatorStats {
+ public:
+ void InitLinkerInitialized() {
+ next_ = this;
+ prev_ = this;
+ }
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ InitLinkerInitialized();
+ }
+
+ void Register(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->next_ = next_;
+ s->prev_ = this;
+ next_->prev_ = s;
+ next_ = s;
+ }
+
+ void Unregister(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->prev_->next_ = s->next_;
+ s->next_->prev_ = s->prev_;
+ for (int i = 0; i < AllocatorStatCount; i++)
+ Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
+ }
+
+ void Get(AllocatorStatCounters s) const {
+ internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
+ SpinMutexLock l(&mu_);
+ const AllocatorStats *stats = this;
+ for (;;) {
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] += stats->Get(AllocatorStat(i));
+ stats = stats->next_;
+ if (stats == this)
+ break;
+ }
+ // All stats must be non-negative.
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
+ }
+
+ private:
+ mutable SpinMutex mu_;
+};
+
+// Allocators call these callbacks on mmap/munmap.
+struct NoOpMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const { }
+ void OnUnmap(uptr p, uptr size) const { }
+};
+
+// Callback type for iterating over chunks.
+typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
+
+// SizeClassAllocator64 -- allocator for 64-bit address space.
+//
+// Space: a portion of address space of kSpaceSize bytes starting at
+// a fixed address (kSpaceBeg). Both constants are powers of two and
+// kSpaceBeg is kSpaceSize-aligned.
+// At the beginning the entire space is mprotect-ed, then small parts of it
+// are mapped on demand.
+//
+// Region: a part of Space dedicated to a single size class.
+// There are kNumClasses Regions of equal size.
+//
+// UserChunk: a piece of memory returned to user.
+// MetaChunk: kMetadataSize bytes of metadata associated with a UserChunk.
+//
+// A Region looks like this:
+// UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1
+template <const uptr kSpaceBeg, const uptr kSpaceSize,
+ const uptr kMetadataSize, class SizeClassMap,
+ class MapUnmapCallback = NoOpMapUnmapCallback>
+class SizeClassAllocator64 {
+ public:
+ typedef typename SizeClassMap::TransferBatch Batch;
+ typedef SizeClassAllocator64<kSpaceBeg, kSpaceSize, kMetadataSize,
+ SizeClassMap, MapUnmapCallback> ThisT;
+ typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
+
+ void Init() {
+ CHECK_EQ(kSpaceBeg,
+ reinterpret_cast<uptr>(Mprotect(kSpaceBeg, kSpaceSize)));
+ MapWithCallback(kSpaceEnd, AdditionalSize());
+ }
+
+ void MapWithCallback(uptr beg, uptr size) {
+ CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
+ MapUnmapCallback().OnMap(beg, size);
+ }
+
+ void UnmapWithCallback(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ static bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *region = GetRegionInfo(class_id);
+ Batch *b = region->free_list.Pop();
+ if (b == 0)
+ b = PopulateFreeList(stat, c, class_id, region);
+ region->n_allocated += b->count;
+ return b;
+ }
+
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ CHECK_GT(b->count, 0);
+ region->free_list.Push(b);
+ region->n_freed += b->count;
+ }
+
+ static bool PointerIsMine(const void *p) {
+ return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
+ }
+
+ static uptr GetSizeClass(const void *p) {
+ return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClassesRounded;
+ }
+
+ void *GetBlockBegin(const void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr size = SizeClassMap::Size(class_id);
+ if (!size) return 0;
+ uptr chunk_idx = GetChunkIdx((uptr)p, size);
+ uptr reg_beg = (uptr)p & ~(kRegionSize - 1);
+ uptr beg = chunk_idx * size;
+ uptr next_beg = beg + size;
+ if (class_id >= kNumClasses) return 0;
+ RegionInfo *region = GetRegionInfo(class_id);
+ if (region->mapped_user >= next_beg)
+ return reinterpret_cast<void*>(reg_beg + beg);
+ return 0;
+ }
+
+ static uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return SizeClassMap::Size(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ void *GetMetaData(const void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr size = SizeClassMap::Size(class_id);
+ uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
+ return reinterpret_cast<void*>(kSpaceBeg + (kRegionSize * (class_id + 1)) -
+ (1 + chunk_idx) * kMetadataSize);
+ }
+
+ uptr TotalMemoryUsed() {
+ uptr res = 0;
+ for (uptr i = 0; i < kNumClasses; i++)
+ res += GetRegionInfo(i)->allocated_user;
+ return res;
+ }
+
+ // Test-only.
+ void TestOnlyUnmap() {
+ UnmapWithCallback(kSpaceBeg, kSpaceSize + AdditionalSize());
+ }
+
+ void PrintStats() {
+ uptr total_mapped = 0;
+ uptr n_allocated = 0;
+ uptr n_freed = 0;
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ total_mapped += region->mapped_user;
+ n_allocated += region->n_allocated;
+ n_freed += region->n_freed;
+ }
+ Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; "
+ "remains %zd\n",
+ total_mapped >> 20, n_allocated, n_allocated - n_freed);
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ if (region->mapped_user == 0) continue;
+ Printf(" %02zd (%zd): total: %zd K allocs: %zd remains: %zd\n",
+ class_id,
+ SizeClassMap::Size(class_id),
+ region->mapped_user >> 10,
+ region->n_allocated,
+ region->n_allocated - region->n_freed);
+ }
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetRegionInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = (int)kNumClasses - 1; i >= 0; i--) {
+ GetRegionInfo(i)->mutex.Unlock();
+ }
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ uptr chunk_size = SizeClassMap::Size(class_id);
+ uptr region_beg = kSpaceBeg + class_id * kRegionSize;
+ for (uptr chunk = region_beg;
+ chunk < region_beg + region->allocated_user;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
+ }
+ }
+ }
+
+ static uptr AdditionalSize() {
+ return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
+ GetPageSizeCached());
+ }
+
+ typedef SizeClassMap SizeClassMapT;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+ static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
+
+ private:
+ static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;
+ static const uptr kSpaceEnd = kSpaceBeg + kSpaceSize;
+ COMPILER_CHECK(kSpaceBeg % kSpaceSize == 0);
+ // kRegionSize must be >= 2^32.
+ COMPILER_CHECK((kRegionSize) >= (1ULL << (SANITIZER_WORDSIZE / 2)));
+ // Populate the free list with at most this number of bytes at once
+ // or with one element if its size is greater.
+ static const uptr kPopulateSize = 1 << 14;
+ // Call mmap for user memory with at least this size.
+ static const uptr kUserMapSize = 1 << 16;
+ // Call mmap for metadata memory with at least this size.
+ static const uptr kMetaMapSize = 1 << 16;
+
+ struct RegionInfo {
+ BlockingMutex mutex;
+ LFStack<Batch> free_list;
+ uptr allocated_user; // Bytes allocated for user memory.
+ uptr allocated_meta; // Bytes allocated for metadata.
+ uptr mapped_user; // Bytes mapped for user memory.
+ uptr mapped_meta; // Bytes mapped for metadata.
+ uptr n_allocated, n_freed; // Just stats.
+ };
+ COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
+
+ RegionInfo *GetRegionInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
+ return &regions[class_id];
+ }
+
+ static uptr GetChunkIdx(uptr chunk, uptr size) {
+ uptr offset = chunk % kRegionSize;
+ // Here we divide by a non-constant. This is costly.
+ // size always fits into 32-bits. If the offset fits too, use 32-bit div.
+ if (offset >> (SANITIZER_WORDSIZE / 2))
+ return offset / size;
+ return (u32)offset / (u32)size;
+ }
+
+ NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id, RegionInfo *region) {
+ BlockingMutexLock l(&region->mutex);
+ Batch *b = region->free_list.Pop();
+ if (b)
+ return b;
+ uptr size = SizeClassMap::Size(class_id);
+ uptr count = size < kPopulateSize ? SizeClassMap::MaxCached(class_id) : 1;
+ uptr beg_idx = region->allocated_user;
+ uptr end_idx = beg_idx + count * size;
+ uptr region_beg = kSpaceBeg + kRegionSize * class_id;
+ if (end_idx + size > region->mapped_user) {
+ // Do the mmap for the user memory.
+ uptr map_size = kUserMapSize;
+ while (end_idx + size > region->mapped_user + map_size)
+ map_size += kUserMapSize;
+ CHECK_GE(region->mapped_user + map_size, end_idx);
+ MapWithCallback(region_beg + region->mapped_user, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
+ region->mapped_user += map_size;
+ }
+ uptr total_count = (region->mapped_user - beg_idx - size)
+ / size / count * count;
+ region->allocated_meta += total_count * kMetadataSize;
+ if (region->allocated_meta > region->mapped_meta) {
+ uptr map_size = kMetaMapSize;
+ while (region->allocated_meta > region->mapped_meta + map_size)
+ map_size += kMetaMapSize;
+ // Do the mmap for the metadata.
+ CHECK_GE(region->mapped_meta + map_size, region->allocated_meta);
+ MapWithCallback(region_beg + kRegionSize -
+ region->mapped_meta - map_size, map_size);
+ region->mapped_meta += map_size;
+ }
+ CHECK_LE(region->allocated_meta, region->mapped_meta);
+ if (region->mapped_user + region->mapped_meta > kRegionSize) {
+ Printf("%s: Out of memory. Dying. ", SanitizerToolName);
+ Printf("The process has exhausted %zuMB for size class %zu.\n",
+ kRegionSize / 1024 / 1024, size);
+ Die();
+ }
+ for (;;) {
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
+ else
+ b = (Batch*)(region_beg + beg_idx);
+ b->count = count;
+ for (uptr i = 0; i < count; i++)
+ b->batch[i] = (void*)(region_beg + beg_idx + i * size);
+ region->allocated_user += count * size;
+ CHECK_LE(region->allocated_user, region->mapped_user);
+ beg_idx += count * size;
+ if (beg_idx + count * size + size > region->mapped_user)
+ break;
+ CHECK_GT(b->count, 0);
+ region->free_list.Push(b);
+ }
+ return b;
+ }
+};
+
+// Maps integers in rage [0, kSize) to u8 values.
+template<u64 kSize>
+class FlatByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map_, 0, sizeof(map_));
+ }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize);
+ CHECK_EQ(0U, map_[idx]);
+ map_[idx] = val;
+ }
+ u8 operator[] (uptr idx) {
+ CHECK_LT(idx, kSize);
+ // FIXME: CHECK may be too expensive here.
+ return map_[idx];
+ }
+ private:
+ u8 map_[kSize];
+};
+
+// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
+// It is implemented as a two-dimensional array: array of kSize1 pointers
+// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
+// Each value is initially zero and can be set to something else only once.
+// Setting and getting values from multiple threads is safe w/o extra locking.
+template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+class TwoLevelByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map1_, 0, sizeof(map1_));
+ mu_.Init();
+ }
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kSize1; i++) {
+ u8 *p = Get(i);
+ if (!p) continue;
+ MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
+ UnmapOrDie(p, kSize2);
+ }
+ }
+
+ uptr size() const { return kSize1 * kSize2; }
+ uptr size1() const { return kSize1; }
+ uptr size2() const { return kSize2; }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = GetOrCreate(idx / kSize2);
+ CHECK_EQ(0U, map2[idx % kSize2]);
+ map2[idx % kSize2] = val;
+ }
+
+ u8 operator[] (uptr idx) const {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = Get(idx / kSize2);
+ if (!map2) return 0;
+ return map2[idx % kSize2];
+ }
+
+ private:
+ u8 *Get(uptr idx) const {
+ CHECK_LT(idx, kSize1);
+ return reinterpret_cast<u8 *>(
+ atomic_load(&map1_[idx], memory_order_acquire));
+ }
+
+ u8 *GetOrCreate(uptr idx) {
+ u8 *res = Get(idx);
+ if (!res) {
+ SpinMutexLock l(&mu_);
+ if (!(res = Get(idx))) {
+ res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
+ MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
+ atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
+ memory_order_release);
+ }
+ }
+ return res;
+ }
+
+ atomic_uintptr_t map1_[kSize1];
+ StaticSpinMutex mu_;
+};
+
+// SizeClassAllocator32 -- allocator for 32-bit address space.
+// This allocator can theoretically be used on 64-bit arch, but there it is less
+// efficient than SizeClassAllocator64.
+//
+// [kSpaceBeg, kSpaceBeg + kSpaceSize) is the range of addresses which can
+// be returned by MmapOrDie().
+//
+// Region:
+// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
+// Since the regions are aligned by kRegionSize, there are exactly
+// kNumPossibleRegions possible regions in the address space and so we keep
+// a ByteMap possible_regions to store the size classes of each Region.
+// 0 size class means the region is not used by the allocator.
+//
+// One Region is used to allocate chunks of a single size class.
+// A Region looks like this:
+// UserChunk1 .. UserChunkN <gap> MetaChunkN .. MetaChunk1
+//
+// In order to avoid false sharing the objects of this class should be
+// chache-line aligned.
+template <const uptr kSpaceBeg, const u64 kSpaceSize,
+ const uptr kMetadataSize, class SizeClassMap,
+ const uptr kRegionSizeLog,
+ class ByteMap,
+ class MapUnmapCallback = NoOpMapUnmapCallback>
+class SizeClassAllocator32 {
+ public:
+ typedef typename SizeClassMap::TransferBatch Batch;
+ typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
+ SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
+ typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
+
+ void Init() {
+ possible_regions.TestOnlyInit();
+ internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
+ }
+
+ void *MapWithCallback(uptr size) {
+ size = RoundUpTo(size, GetPageSizeCached());
+ void *res = MmapOrDie(size, "SizeClassAllocator32");
+ MapUnmapCallback().OnMap((uptr)res, size);
+ return res;
+ }
+
+ void UnmapWithCallback(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ static bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ void *GetMetaData(const void *p) {
+ CHECK(PointerIsMine(p));
+ uptr mem = reinterpret_cast<uptr>(p);
+ uptr beg = ComputeRegionBeg(mem);
+ uptr size = SizeClassMap::Size(GetSizeClass(p));
+ u32 offset = mem - beg;
+ uptr n = offset / (u32)size; // 32-bit division
+ uptr meta = (beg + kRegionSize) - (n + 1) * kMetadataSize;
+ return reinterpret_cast<void*>(meta);
+ }
+
+ NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ SizeClassInfo *sci = GetSizeClassInfo(class_id);
+ SpinMutexLock l(&sci->mutex);
+ if (sci->free_list.empty())
+ PopulateFreeList(stat, c, sci, class_id);
+ CHECK(!sci->free_list.empty());
+ Batch *b = sci->free_list.front();
+ sci->free_list.pop_front();
+ return b;
+ }
+
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
+ CHECK_LT(class_id, kNumClasses);
+ SizeClassInfo *sci = GetSizeClassInfo(class_id);
+ SpinMutexLock l(&sci->mutex);
+ CHECK_GT(b->count, 0);
+ sci->free_list.push_front(b);
+ }
+
+ bool PointerIsMine(const void *p) {
+ return GetSizeClass(p) != 0;
+ }
+
+ uptr GetSizeClass(const void *p) {
+ return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
+ }
+
+ void *GetBlockBegin(const void *p) {
+ CHECK(PointerIsMine(p));
+ uptr mem = reinterpret_cast<uptr>(p);
+ uptr beg = ComputeRegionBeg(mem);
+ uptr size = SizeClassMap::Size(GetSizeClass(p));
+ u32 offset = mem - beg;
+ u32 n = offset / (u32)size; // 32-bit division
+ uptr res = beg + (n * (u32)size);
+ return reinterpret_cast<void*>(res);
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return SizeClassMap::Size(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ uptr TotalMemoryUsed() {
+ // No need to lock here.
+ uptr res = 0;
+ for (uptr i = 0; i < kNumPossibleRegions; i++)
+ if (possible_regions[i])
+ res += kRegionSize;
+ return res;
+ }
+
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kNumPossibleRegions; i++)
+ if (possible_regions[i])
+ UnmapWithCallback((i * kRegionSize), kRegionSize);
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetSizeClassInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = kNumClasses - 1; i >= 0; i--) {
+ GetSizeClassInfo(i)->mutex.Unlock();
+ }
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr region = 0; region < kNumPossibleRegions; region++)
+ if (possible_regions[region]) {
+ uptr chunk_size = SizeClassMap::Size(possible_regions[region]);
+ uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
+ uptr region_beg = region * kRegionSize;
+ for (uptr chunk = region_beg;
+ chunk < region_beg + max_chunks_in_region * chunk_size;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
+ }
+ }
+ }
+
+ void PrintStats() {
+ }
+
+ typedef SizeClassMap SizeClassMapT;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+
+ private:
+ static const uptr kRegionSize = 1 << kRegionSizeLog;
+ static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
+
+ struct SizeClassInfo {
+ SpinMutex mutex;
+ IntrusiveList<Batch> free_list;
+ char padding[kCacheLineSize - sizeof(uptr) - sizeof(IntrusiveList<Batch>)];
+ };
+ COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize);
+
+ uptr ComputeRegionId(uptr mem) {
+ uptr res = mem >> kRegionSizeLog;
+ CHECK_LT(res, kNumPossibleRegions);
+ return res;
+ }
+
+ uptr ComputeRegionBeg(uptr mem) {
+ return mem & ~(kRegionSize - 1);
+ }
+
+ uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
+ "SizeClassAllocator32"));
+ MapUnmapCallback().OnMap(res, kRegionSize);
+ stat->Add(AllocatorStatMapped, kRegionSize);
+ CHECK_EQ(0U, (res & (kRegionSize - 1)));
+ possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
+ return res;
+ }
+
+ SizeClassInfo *GetSizeClassInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ return &size_class_info_array[class_id];
+ }
+
+ void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ SizeClassInfo *sci, uptr class_id) {
+ uptr size = SizeClassMap::Size(class_id);
+ uptr reg = AllocateRegion(stat, class_id);
+ uptr n_chunks = kRegionSize / (size + kMetadataSize);
+ uptr max_count = SizeClassMap::MaxCached(class_id);
+ Batch *b = 0;
+ for (uptr i = reg; i < reg + n_chunks * size; i += size) {
+ if (b == 0) {
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
+ else
+ b = (Batch*)i;
+ b->count = 0;
+ }
+ b->batch[b->count++] = (void*)i;
+ if (b->count == max_count) {
+ CHECK_GT(b->count, 0);
+ sci->free_list.push_back(b);
+ b = 0;
+ }
+ }
+ if (b) {
+ CHECK_GT(b->count, 0);
+ sci->free_list.push_back(b);
+ }
+ }
+
+ ByteMap possible_regions;
+ SizeClassInfo size_class_info_array[kNumClasses];
+};
+
+// Objects of this type should be used as local caches for SizeClassAllocator64
+// or SizeClassAllocator32. Since the typical use of this class is to have one
+// object per thread in TLS, is has to be POD.
+template<class SizeClassAllocator>
+struct SizeClassAllocatorLocalCache {
+ typedef SizeClassAllocator Allocator;
+ static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
+
+ void Init(AllocatorGlobalStats *s) {
+ stats_.Init();
+ if (s)
+ s->Register(&stats_);
+ }
+
+ void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+ Drain(allocator);
+ if (s)
+ s->Unregister(&stats_);
+ }
+
+ void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ stats_.Add(AllocatorStatAllocated, SizeClassMap::Size(class_id));
+ PerClass *c = &per_class_[class_id];
+ if (UNLIKELY(c->count == 0))
+ Refill(allocator, class_id);
+ void *res = c->batch[--c->count];
+ PREFETCH(c->batch[c->count - 1]);
+ return res;
+ }
+
+ void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ // If the first allocator call on a new thread is a deallocation, then
+ // max_count will be zero, leading to check failure.
+ InitCache();
+ stats_.Sub(AllocatorStatAllocated, SizeClassMap::Size(class_id));
+ PerClass *c = &per_class_[class_id];
+ CHECK_NE(c->max_count, 0UL);
+ if (UNLIKELY(c->count == c->max_count))
+ Drain(allocator, class_id);
+ c->batch[c->count++] = p;
+ }
+
+ void Drain(SizeClassAllocator *allocator) {
+ for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
+ PerClass *c = &per_class_[class_id];
+ while (c->count > 0)
+ Drain(allocator, class_id);
+ }
+ }
+
+ // private:
+ typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap;
+ typedef typename SizeClassMap::TransferBatch Batch;
+ struct PerClass {
+ uptr count;
+ uptr max_count;
+ void *batch[2 * SizeClassMap::kMaxNumCached];
+ };
+ PerClass per_class_[kNumClasses];
+ AllocatorStats stats_;
+
+ void InitCache() {
+ if (per_class_[1].max_count)
+ return;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ PerClass *c = &per_class_[i];
+ c->max_count = 2 * SizeClassMap::MaxCached(i);
+ }
+ }
+
+ NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
+ InitCache();
+ PerClass *c = &per_class_[class_id];
+ Batch *b = allocator->AllocateBatch(&stats_, this, class_id);
+ CHECK_GT(b->count, 0);
+ for (uptr i = 0; i < b->count; i++)
+ c->batch[i] = b->batch[i];
+ c->count = b->count;
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
+ }
+
+ NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
+ InitCache();
+ PerClass *c = &per_class_[class_id];
+ Batch *b;
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ b = (Batch*)Allocate(allocator, SizeClassMap::ClassID(sizeof(Batch)));
+ else
+ b = (Batch*)c->batch[0];
+ uptr cnt = Min(c->max_count / 2, c->count);
+ for (uptr i = 0; i < cnt; i++) {
+ b->batch[i] = c->batch[i];
+ c->batch[i] = c->batch[i + c->max_count / 2];
+ }
+ b->count = cnt;
+ c->count -= cnt;
+ CHECK_GT(b->count, 0);
+ allocator->DeallocateBatch(&stats_, class_id, b);
+ }
+};
+
+// This class can (de)allocate only large chunks of memory using mmap/unmap.
+// The main purpose of this allocator is to cover large and rare allocation
+// sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
+template <class MapUnmapCallback = NoOpMapUnmapCallback>
+class LargeMmapAllocator {
+ public:
+ void InitLinkerInitialized(bool may_return_null) {
+ page_size_ = GetPageSizeCached();
+ atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
+ }
+
+ void Init(bool may_return_null) {
+ internal_memset(this, 0, sizeof(*this));
+ InitLinkerInitialized(may_return_null);
+ }
+
+ void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
+ CHECK(IsPowerOfTwo(alignment));
+ uptr map_size = RoundUpMapSize(size);
+ if (alignment > page_size_)
+ map_size += alignment;
+ // Overflow.
+ if (map_size < size)
+ return ReturnNullOrDie();
+ uptr map_beg = reinterpret_cast<uptr>(
+ MmapOrDie(map_size, "LargeMmapAllocator"));
+ CHECK(IsAligned(map_beg, page_size_));
+ MapUnmapCallback().OnMap(map_beg, map_size);
+ uptr map_end = map_beg + map_size;
+ uptr res = map_beg + page_size_;
+ if (res & (alignment - 1)) // Align.
+ res += alignment - (res & (alignment - 1));
+ CHECK(IsAligned(res, alignment));
+ CHECK(IsAligned(res, page_size_));
+ CHECK_GE(res + size, map_beg);
+ CHECK_LE(res + size, map_end);
+ Header *h = GetHeader(res);
+ h->size = size;
+ h->map_beg = map_beg;
+ h->map_size = map_size;
+ uptr size_log = MostSignificantSetBitIndex(map_size);
+ CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
+ {
+ SpinMutexLock l(&mutex_);
+ uptr idx = n_chunks_++;
+ chunks_sorted_ = false;
+ CHECK_LT(idx, kMaxNumChunks);
+ h->chunk_idx = idx;
+ chunks_[idx] = h;
+ stats.n_allocs++;
+ stats.currently_allocated += map_size;
+ stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
+ stats.by_size_log[size_log]++;
+ stat->Add(AllocatorStatAllocated, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
+ }
+ return reinterpret_cast<void*>(res);
+ }
+
+ void *ReturnNullOrDie() {
+ if (atomic_load(&may_return_null_, memory_order_acquire))
+ return 0;
+ ReportAllocatorCannotReturnNull();
+ }
+
+ void SetMayReturnNull(bool may_return_null) {
+ atomic_store(&may_return_null_, may_return_null, memory_order_release);
+ }
+
+ void Deallocate(AllocatorStats *stat, void *p) {
+ Header *h = GetHeader(p);
+ {
+ SpinMutexLock l(&mutex_);
+ uptr idx = h->chunk_idx;
+ CHECK_EQ(chunks_[idx], h);
+ CHECK_LT(idx, n_chunks_);
+ chunks_[idx] = chunks_[n_chunks_ - 1];
+ chunks_[idx]->chunk_idx = idx;
+ n_chunks_--;
+ chunks_sorted_ = false;
+ stats.n_frees++;
+ stats.currently_allocated -= h->map_size;
+ stat->Sub(AllocatorStatAllocated, h->map_size);
+ stat->Sub(AllocatorStatMapped, h->map_size);
+ }
+ MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
+ UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
+ }
+
+ uptr TotalMemoryUsed() {
+ SpinMutexLock l(&mutex_);
+ uptr res = 0;
+ for (uptr i = 0; i < n_chunks_; i++) {
+ Header *h = chunks_[i];
+ CHECK_EQ(h->chunk_idx, i);
+ res += RoundUpMapSize(h->size);
+ }
+ return res;
+ }
+
+ bool PointerIsMine(const void *p) {
+ return GetBlockBegin(p) != 0;
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ return RoundUpTo(GetHeader(p)->size, page_size_);
+ }
+
+ // At least page_size_/2 metadata bytes is available.
+ void *GetMetaData(const void *p) {
+ // Too slow: CHECK_EQ(p, GetBlockBegin(p));
+ if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) {
+ Printf("%s: bad pointer %p\n", SanitizerToolName, p);
+ CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
+ }
+ return GetHeader(p) + 1;
+ }
+
+ void *GetBlockBegin(const void *ptr) {
+ uptr p = reinterpret_cast<uptr>(ptr);
+ SpinMutexLock l(&mutex_);
+ uptr nearest_chunk = 0;
+ // Cache-friendly linear search.
+ for (uptr i = 0; i < n_chunks_; i++) {
+ uptr ch = reinterpret_cast<uptr>(chunks_[i]);
+ if (p < ch) continue; // p is at left to this chunk, skip it.
+ if (p - ch < p - nearest_chunk)
+ nearest_chunk = ch;
+ }
+ if (!nearest_chunk)
+ return 0;
+ Header *h = reinterpret_cast<Header *>(nearest_chunk);
+ CHECK_GE(nearest_chunk, h->map_beg);
+ CHECK_LT(nearest_chunk, h->map_beg + h->map_size);
+ CHECK_LE(nearest_chunk, p);
+ if (h->map_beg + h->map_size <= p)
+ return 0;
+ return GetUser(h);
+ }
+
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *ptr) {
+ mutex_.CheckLocked();
+ uptr p = reinterpret_cast<uptr>(ptr);
+ uptr n = n_chunks_;
+ if (!n) return 0;
+ if (!chunks_sorted_) {
+ // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
+ SortArray(reinterpret_cast<uptr*>(chunks_), n);
+ for (uptr i = 0; i < n; i++)
+ chunks_[i]->chunk_idx = i;
+ chunks_sorted_ = true;
+ min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
+ max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
+ chunks_[n - 1]->map_size;
+ }
+ if (p < min_mmap_ || p >= max_mmap_)
+ return 0;
+ uptr beg = 0, end = n - 1;
+ // This loop is a log(n) lower_bound. It does not check for the exact match
+ // to avoid expensive cache-thrashing loads.
+ while (end - beg >= 2) {
+ uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1
+ if (p < reinterpret_cast<uptr>(chunks_[mid]))
+ end = mid - 1; // We are not interested in chunks_[mid].
+ else
+ beg = mid; // chunks_[mid] may still be what we want.
+ }
+
+ if (beg < end) {
+ CHECK_EQ(beg + 1, end);
+ // There are 2 chunks left, choose one.
+ if (p >= reinterpret_cast<uptr>(chunks_[end]))
+ beg = end;
+ }
+
+ Header *h = chunks_[beg];
+ if (h->map_beg + h->map_size <= p || p < h->map_beg)
+ return 0;
+ return GetUser(h);
+ }
+
+ void PrintStats() {
+ Printf("Stats: LargeMmapAllocator: allocated %zd times, "
+ "remains %zd (%zd K) max %zd M; by size logs: ",
+ stats.n_allocs, stats.n_allocs - stats.n_frees,
+ stats.currently_allocated >> 10, stats.max_allocated >> 20);
+ for (uptr i = 0; i < ARRAY_SIZE(stats.by_size_log); i++) {
+ uptr c = stats.by_size_log[i];
+ if (!c) continue;
+ Printf("%zd:%zd; ", i, c);
+ }
+ Printf("\n");
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ mutex_.Lock();
+ }
+
+ void ForceUnlock() {
+ mutex_.Unlock();
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr i = 0; i < n_chunks_; i++)
+ callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
+ }
+
+ private:
+ static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
+ struct Header {
+ uptr map_beg;
+ uptr map_size;
+ uptr size;
+ uptr chunk_idx;
+ };
+
+ Header *GetHeader(uptr p) {
+ CHECK(IsAligned(p, page_size_));
+ return reinterpret_cast<Header*>(p - page_size_);
+ }
+ Header *GetHeader(const void *p) {
+ return GetHeader(reinterpret_cast<uptr>(p));
+ }
+
+ void *GetUser(Header *h) {
+ CHECK(IsAligned((uptr)h, page_size_));
+ return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
+ }
+
+ uptr RoundUpMapSize(uptr size) {
+ return RoundUpTo(size, page_size_) + page_size_;
+ }
+
+ uptr page_size_;
+ Header *chunks_[kMaxNumChunks];
+ uptr n_chunks_;
+ uptr min_mmap_, max_mmap_;
+ bool chunks_sorted_;
+ struct Stats {
+ uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
+ } stats;
+ atomic_uint8_t may_return_null_;
+ SpinMutex mutex_;
+};
+
+// This class implements a complete memory allocator by using two
+// internal allocators:
+// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
+// When allocating 2^x bytes it should return 2^x aligned chunk.
+// PrimaryAllocator is used via a local AllocatorCache.
+// SecondaryAllocator can allocate anything, but is not efficient.
+template <class PrimaryAllocator, class AllocatorCache,
+ class SecondaryAllocator> // NOLINT
+class CombinedAllocator {
+ public:
+ void InitCommon(bool may_return_null) {
+ primary_.Init();
+ atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
+ }
+
+ void InitLinkerInitialized(bool may_return_null) {
+ secondary_.InitLinkerInitialized(may_return_null);
+ stats_.InitLinkerInitialized();
+ InitCommon(may_return_null);
+ }
+
+ void Init(bool may_return_null) {
+ secondary_.Init(may_return_null);
+ stats_.Init();
+ InitCommon(may_return_null);
+ }
+
+ void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
+ bool cleared = false, bool check_rss_limit = false) {
+ // Returning 0 on malloc(0) may break a lot of code.
+ if (size == 0)
+ size = 1;
+ if (size + alignment < size)
+ return ReturnNullOrDie();
+ if (check_rss_limit && RssLimitIsExceeded())
+ return ReturnNullOrDie();
+ if (alignment > 8)
+ size = RoundUpTo(size, alignment);
+ void *res;
+ bool from_primary = primary_.CanAllocate(size, alignment);
+ if (from_primary)
+ res = cache->Allocate(&primary_, primary_.ClassID(size));
+ else
+ res = secondary_.Allocate(&stats_, size, alignment);
+ if (alignment > 8)
+ CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
+ if (cleared && res && from_primary)
+ internal_bzero_aligned16(res, RoundUpTo(size, 16));
+ return res;
+ }
+
+ bool MayReturnNull() const {
+ return atomic_load(&may_return_null_, memory_order_acquire);
+ }
+
+ void *ReturnNullOrDie() {
+ if (MayReturnNull())
+ return 0;
+ ReportAllocatorCannotReturnNull();
+ }
+
+ void SetMayReturnNull(bool may_return_null) {
+ secondary_.SetMayReturnNull(may_return_null);
+ atomic_store(&may_return_null_, may_return_null, memory_order_release);
+ }
+
+ bool RssLimitIsExceeded() {
+ return atomic_load(&rss_limit_is_exceeded_, memory_order_acquire);
+ }
+
+ void SetRssLimitIsExceeded(bool rss_limit_is_exceeded) {
+ atomic_store(&rss_limit_is_exceeded_, rss_limit_is_exceeded,
+ memory_order_release);
+ }
+
+ void Deallocate(AllocatorCache *cache, void *p) {
+ if (!p) return;
+ if (primary_.PointerIsMine(p))
+ cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
+ else
+ secondary_.Deallocate(&stats_, p);
+ }
+
+ void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
+ uptr alignment) {
+ if (!p)
+ return Allocate(cache, new_size, alignment);
+ if (!new_size) {
+ Deallocate(cache, p);
+ return 0;
+ }
+ CHECK(PointerIsMine(p));
+ uptr old_size = GetActuallyAllocatedSize(p);
+ uptr memcpy_size = Min(new_size, old_size);
+ void *new_p = Allocate(cache, new_size, alignment);
+ if (new_p)
+ internal_memcpy(new_p, p, memcpy_size);
+ Deallocate(cache, p);
+ return new_p;
+ }
+
+ bool PointerIsMine(void *p) {
+ if (primary_.PointerIsMine(p))
+ return true;
+ return secondary_.PointerIsMine(p);
+ }
+
+ bool FromPrimary(void *p) {
+ return primary_.PointerIsMine(p);
+ }
+
+ void *GetMetaData(const void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetMetaData(p);
+ return secondary_.GetMetaData(p);
+ }
+
+ void *GetBlockBegin(const void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBegin(p);
+ }
+
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBeginFastLocked(p);
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetActuallyAllocatedSize(p);
+ return secondary_.GetActuallyAllocatedSize(p);
+ }
+
+ uptr TotalMemoryUsed() {
+ return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
+ }
+
+ void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
+
+ void InitCache(AllocatorCache *cache) {
+ cache->Init(&stats_);
+ }
+
+ void DestroyCache(AllocatorCache *cache) {
+ cache->Destroy(&primary_, &stats_);
+ }
+
+ void SwallowCache(AllocatorCache *cache) {
+ cache->Drain(&primary_);
+ }
+
+ void GetStats(AllocatorStatCounters s) const {
+ stats_.Get(s);
+ }
+
+ void PrintStats() {
+ primary_.PrintStats();
+ secondary_.PrintStats();
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ primary_.ForceLock();
+ secondary_.ForceLock();
+ }
+
+ void ForceUnlock() {
+ secondary_.ForceUnlock();
+ primary_.ForceUnlock();
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ primary_.ForEachChunk(callback, arg);
+ secondary_.ForEachChunk(callback, arg);
+ }
+
+ private:
+ PrimaryAllocator primary_;
+ SecondaryAllocator secondary_;
+ AllocatorGlobalStats stats_;
+ atomic_uint8_t may_return_null_;
+ atomic_uint8_t rss_limit_is_exceeded_;
+};
+
+// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ALLOCATOR_H
+
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
new file mode 100644
index 000000000000..2cd924c99781
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
@@ -0,0 +1,38 @@
+//===-- sanitizer_allocator_interface.h ------------------------- C++ -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Re-declaration of functions from public sanitizer allocator interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
+#define SANITIZER_ALLOCATOR_INTERFACE_H
+
+#include "sanitizer_internal_defs.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_estimated_allocated_size(uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE uptr
+__sanitizer_get_allocated_size(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
+} // extern "C"
+
+#endif // SANITIZER_ALLOCATOR_INTERFACE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
new file mode 100644
index 000000000000..9b9cfd0b5931
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -0,0 +1,63 @@
+//===-- sanitizer_allocator_internal.h -------------------------- C++ -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This allocator is used inside run-times.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERNAL_H
+#define SANITIZER_ALLOCATOR_INTERNAL_H
+
+#include "sanitizer_allocator.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// FIXME: Check if we may use even more compact size class map for internal
+// purposes.
+typedef CompactSizeClassMap InternalSizeClassMap;
+
+static const uptr kInternalAllocatorSpace = 0;
+static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
+static const uptr kInternalAllocatorRegionSizeLog = 20;
+#if SANITIZER_WORDSIZE == 32
+static const uptr kInternalAllocatorNumRegions =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
+#else
+static const uptr kInternalAllocatorNumRegions =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
+#endif
+typedef SizeClassAllocator32<
+ kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap,
+ kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
+
+typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
+ InternalAllocatorCache;
+
+typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
+ LargeMmapAllocator<> > InternalAllocator;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
+void InternalFree(void *p, InternalAllocatorCache *cache = 0);
+InternalAllocator *internal_allocator();
+
+enum InternalAllocEnum {
+ INTERNAL_ALLOC
+};
+
+} // namespace __sanitizer
+
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ InternalAllocEnum) {
+ return InternalAlloc(size);
+}
+
+#endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
new file mode 100644
index 000000000000..906012a96f11
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
@@ -0,0 +1,40 @@
+//===-- sanitizer_asm.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various support for assemebler.
+//
+//===----------------------------------------------------------------------===//
+
+// Some toolchains do not support .cfi asm directives, so we have to hide
+// them inside macros.
+#if defined(__clang__) || \
+ (defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM))
+ // GCC defined __GCC_HAVE_DWARF2_CFI_ASM if it supports CFI.
+ // Clang seems to support CFI by default (or not?).
+ // We need two versions of macros: for inline asm and standalone asm files.
+# define CFI_INL_ADJUST_CFA_OFFSET(n) ".cfi_adjust_cfa_offset " #n ";"
+
+# define CFI_STARTPROC .cfi_startproc
+# define CFI_ENDPROC .cfi_endproc
+# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
+# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
+# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
+# define CFI_RESTORE(reg) .cfi_restore reg
+
+#else // No CFI
+# define CFI_INL_ADJUST_CFA_OFFSET(n)
+# define CFI_STARTPROC
+# define CFI_ENDPROC
+# define CFI_ADJUST_CFA_OFFSET(n)
+# define CFI_REL_OFFSET(reg, n)
+# define CFI_DEF_CFA_REGISTER(reg)
+# define CFI_RESTORE(reg)
+#endif
+
+
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
new file mode 100644
index 000000000000..6643c5494393
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
@@ -0,0 +1,66 @@
+//===-- sanitizer_atomic.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_H
+#define SANITIZER_ATOMIC_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+enum memory_order {
+ memory_order_relaxed = 1 << 0,
+ memory_order_consume = 1 << 1,
+ memory_order_acquire = 1 << 2,
+ memory_order_release = 1 << 3,
+ memory_order_acq_rel = 1 << 4,
+ memory_order_seq_cst = 1 << 5
+};
+
+struct atomic_uint8_t {
+ typedef u8 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint16_t {
+ typedef u16 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint32_t {
+ typedef u32 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint64_t {
+ typedef u64 Type;
+ // On 32-bit platforms u64 is not necessary aligned on 8 bytes.
+ volatile ALIGNED(8) Type val_dont_use;
+};
+
+struct atomic_uintptr_t {
+ typedef uptr Type;
+ volatile Type val_dont_use;
+};
+
+} // namespace __sanitizer
+
+#if defined(__GNUC__)
+# include "sanitizer_atomic_clang.h"
+#elif defined(_MSC_VER)
+# include "sanitizer_atomic_msvc.h"
+#else
+# error "Unsupported compiler"
+#endif
+
+#endif // SANITIZER_ATOMIC_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
new file mode 100644
index 000000000000..38363e875560
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -0,0 +1,100 @@
+//===-- sanitizer_atomic_clang.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 ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_H
+#define SANITIZER_ATOMIC_CLANG_H
+
+#if defined(__i386__) || defined(__x86_64__)
+# include "sanitizer_atomic_clang_x86.h"
+#else
+# include "sanitizer_atomic_clang_other.h"
+#endif
+
+namespace __sanitizer {
+
+// We would like to just use compiler builtin atomic operations
+// for loads and stores, but they are mostly broken in clang:
+// - they lead to vastly inefficient code generation
+// (http://llvm.org/bugs/show_bug.cgi?id=17281)
+// - 64-bit atomic operations are not implemented on x86_32
+// (http://llvm.org/bugs/show_bug.cgi?id=15034)
+// - they are not implemented on ARM
+// error: undefined reference to '__atomic_load_4'
+
+// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
+// for mappings of the memory model to different processors.
+
+INLINE void atomic_signal_fence(memory_order) {
+ __asm__ __volatile__("" ::: "memory");
+}
+
+INLINE void atomic_thread_fence(memory_order) {
+ __sync_synchronize();
+}
+
+template<typename T>
+INLINE typename T::Type atomic_fetch_add(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return __sync_fetch_and_add(&a->val_dont_use, v);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_fetch_sub(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return __sync_fetch_and_add(&a->val_dont_use, -v);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_exchange(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ DCHECK(!((uptr)a % sizeof(*a)));
+ if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
+ __sync_synchronize();
+ v = __sync_lock_test_and_set(&a->val_dont_use, v);
+ if (mo == memory_order_seq_cst)
+ __sync_synchronize();
+ return v;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_strong(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ typedef typename T::Type Type;
+ Type cmpv = *cmp;
+ Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_weak(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ return atomic_compare_exchange_strong(a, cmp, xchg, mo);
+}
+
+} // namespace __sanitizer
+
+#undef ATOMIC_ORDER
+
+#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
new file mode 100644
index 000000000000..099b9f7ec8c6
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
@@ -0,0 +1,97 @@
+//===-- sanitizer_atomic_clang_other.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 ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
+#define SANITIZER_ATOMIC_CLANG_OTHER_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else if (mo == memory_order_consume) {
+ // Assume that processor respects data dependencies
+ // (and that compiler won't break them).
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ } else if (mo == memory_order_acquire) {
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __sync_synchronize();
+ } else { // seq_cst
+ // E.g. on POWER we need a hw fence even before the store.
+ __sync_synchronize();
+ v = a->val_dont_use;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit load on 32-bit platform.
+ // Gross, but simple and reliable.
+ // Assume that it is not in read-only memory.
+ v = __sync_fetch_and_add(
+ const_cast<typename T::Type volatile *>(&a->val_dont_use), 0);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else if (mo == memory_order_release) {
+ __sync_synchronize();
+ a->val_dont_use = v;
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ __sync_synchronize();
+ a->val_dont_use = v;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit store on 32-bit platform.
+ // Gross, but simple and reliable.
+ typename T::Type cmp = a->val_dont_use;
+ typename T::Type cur;
+ for (;;) {
+ cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v);
+ if (cmp == v)
+ break;
+ cmp = cur;
+ }
+ }
+}
+
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
new file mode 100644
index 000000000000..38feb29287f1
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
@@ -0,0 +1,116 @@
+//===-- sanitizer_atomic_clang_x86.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 ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_X86_H
+#define SANITIZER_ATOMIC_CLANG_X86_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+ for (int i = 0; i < cnt; i++)
+ __asm__ __volatile__("pause");
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else if (mo == memory_order_consume) {
+ // Assume that processor respects data dependencies
+ // (and that compiler won't break them).
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ } else if (mo == memory_order_acquire) {
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ // On x86 loads are implicitly acquire.
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ // On x86 plain MOV is enough for seq_cst store.
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ }
+ } else {
+ // 64-bit load on 32-bit platform.
+ __asm__ __volatile__(
+ "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves
+ "movq %%mm0, %0;" // (ptr could be read-only)
+ "emms;" // Empty mmx state/Reset FP regs
+ : "=m" (v)
+ : "m" (a->val_dont_use)
+ : // mark the FP stack and mmx registers as clobbered
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif // #ifdef __MMX__
+ "memory");
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else if (mo == memory_order_release) {
+ // On x86 stores are implicitly release.
+ __asm__ __volatile__("" ::: "memory");
+ a->val_dont_use = v;
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ // On x86 stores are implicitly release.
+ __asm__ __volatile__("" ::: "memory");
+ a->val_dont_use = v;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit store on 32-bit platform.
+ __asm__ __volatile__(
+ "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves
+ "movq %%mm0, %0;"
+ "emms;" // Empty mmx state/Reset FP regs
+ : "=m" (a->val_dont_use)
+ : "m" (v)
+ : // mark the FP stack and mmx registers as clobbered
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif // #ifdef __MMX__
+ "memory");
+ if (mo == memory_order_seq_cst)
+ __sync_synchronize();
+ }
+}
+
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_ATOMIC_CLANG_X86_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
new file mode 100644
index 000000000000..12ffef3ba105
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -0,0 +1,253 @@
+//===-- sanitizer_atomic_msvc.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 ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_MSVC_H
+#define SANITIZER_ATOMIC_MSVC_H
+
+extern "C" void _ReadWriteBarrier();
+#pragma intrinsic(_ReadWriteBarrier)
+extern "C" void _mm_mfence();
+#pragma intrinsic(_mm_mfence)
+extern "C" void _mm_pause();
+#pragma intrinsic(_mm_pause)
+extern "C" long _InterlockedExchangeAdd( // NOLINT
+ long volatile * Addend, long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd)
+extern "C" short _InterlockedCompareExchange16( // NOLINT
+ short volatile *Destination, // NOLINT
+ short Exchange, short Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange16)
+extern "C"
+long long _InterlockedCompareExchange64( // NOLINT
+ long long volatile *Destination, // NOLINT
+ long long Exchange, long long Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange64)
+extern "C" void *_InterlockedCompareExchangePointer(
+ void *volatile *Destination,
+ void *Exchange, void *Comparand);
+#pragma intrinsic(_InterlockedCompareExchangePointer)
+extern "C"
+long __cdecl _InterlockedCompareExchange( // NOLINT
+ long volatile *Destination, // NOLINT
+ long Exchange, long Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange)
+
+#ifdef _WIN64
+extern "C" long long _InterlockedExchangeAdd64( // NOLINT
+ long long volatile * Addend, long long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd64)
+#endif
+
+namespace __sanitizer {
+
+INLINE void atomic_signal_fence(memory_order) {
+ _ReadWriteBarrier();
+}
+
+INLINE void atomic_thread_fence(memory_order) {
+ _mm_mfence();
+}
+
+INLINE void proc_yield(int cnt) {
+ for (int i = 0; i < cnt; i++)
+ _mm_pause();
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+ // FIXME(dvyukov): 64-bit load is not atomic on 32-bits.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ v = a->val_dont_use;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ // FIXME(dvyukov): 64-bit store is not atomic on 32-bits.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ a->val_dont_use = v;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ if (mo == memory_order_seq_cst)
+ atomic_thread_fence(memory_order_seq_cst);
+}
+
+INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, (long)v); // NOLINT
+}
+
+INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
+ uptr v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+ return (uptr)_InterlockedExchangeAdd64(
+ (volatile long long*)&a->val_dont_use, (long long)v); // NOLINT
+#else
+ return (uptr)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, (long)v); // NOLINT
+#endif
+}
+
+INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, -(long)v); // NOLINT
+}
+
+INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
+ uptr v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+ return (uptr)_InterlockedExchangeAdd64(
+ (volatile long long*)&a->val_dont_use, -(long long)v); // NOLINT
+#else
+ return (uptr)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, -(long)v); // NOLINT
+#endif
+}
+
+INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
+ u8 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ __asm {
+ mov eax, a
+ mov cl, v
+ xchg [eax], cl // NOLINT
+ mov v, cl
+ }
+ return v;
+}
+
+INLINE u16 atomic_exchange(volatile atomic_uint16_t *a,
+ u16 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ __asm {
+ mov eax, a
+ mov cx, v
+ xchg [eax], cx // NOLINT
+ mov v, cx
+ }
+ return v;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
+ u8 *cmp,
+ u8 xchgv,
+ memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ u8 cmpv = *cmp;
+ u8 prev;
+ __asm {
+ mov al, cmpv
+ mov ecx, a
+ mov dl, xchgv
+ lock cmpxchg [ecx], dl
+ mov prev, al
+ }
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
+ uptr *cmp,
+ uptr xchg,
+ memory_order mo) {
+ uptr cmpv = *cmp;
+ uptr prev = (uptr)_InterlockedCompareExchangePointer(
+ (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
+ u16 *cmp,
+ u16 xchg,
+ memory_order mo) {
+ u16 cmpv = *cmp;
+ u16 prev = (u16)_InterlockedCompareExchange16(
+ (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
+ u32 *cmp,
+ u32 xchg,
+ memory_order mo) {
+ u32 cmpv = *cmp;
+ u32 prev = (u32)_InterlockedCompareExchange(
+ (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
+ u64 *cmp,
+ u64 xchg,
+ memory_order mo) {
+ u64 cmpv = *cmp;
+ u64 prev = (u64)_InterlockedCompareExchange64(
+ (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_weak(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ return atomic_compare_exchange_strong(a, cmp, xchg, mo);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h
new file mode 100644
index 000000000000..d8472732ff21
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h
@@ -0,0 +1,351 @@
+//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specializer BitVector implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BITVECTOR_H
+#define SANITIZER_BITVECTOR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// Fixed size bit vector based on a single basic integer.
+template <class basic_int_t = uptr>
+class BasicBitVector {
+ public:
+ enum SizeEnum { kSize = sizeof(basic_int_t) * 8 };
+
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() { bits_ = 0; }
+ void setAll() { bits_ = ~(basic_int_t)0; }
+ bool empty() const { return bits_ == 0; }
+
+ // Returns true if the bit has changed from 0 to 1.
+ bool setBit(uptr idx) {
+ basic_int_t old = bits_;
+ bits_ |= mask(idx);
+ return bits_ != old;
+ }
+
+ // Returns true if the bit has changed from 1 to 0.
+ bool clearBit(uptr idx) {
+ basic_int_t old = bits_;
+ bits_ &= ~mask(idx);
+ return bits_ != old;
+ }
+
+ bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }
+
+ uptr getAndClearFirstOne() {
+ CHECK(!empty());
+ uptr idx = LeastSignificantSetBitIndex(bits_);
+ clearBit(idx);
+ return idx;
+ }
+
+ // Do "this |= v" and return whether new bits have been added.
+ bool setUnion(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ |= v.bits_;
+ return bits_ != old;
+ }
+
+ // Do "this &= v" and return whether any bits have been removed.
+ bool setIntersection(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ &= v.bits_;
+ return bits_ != old;
+ }
+
+ // Do "this &= ~v" and return whether any bits have been removed.
+ bool setDifference(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ &= ~v.bits_;
+ return bits_ != old;
+ }
+
+ void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }
+
+ // Returns true if 'this' intersects with 'v'.
+ bool intersectsWith(const BasicBitVector &v) const {
+ return (bits_ & v.bits_) != 0;
+ }
+
+ // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
+ // uptr idx = it.next();
+ // use(idx);
+ // }
+ class Iterator {
+ public:
+ Iterator() { }
+ explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}
+ bool hasNext() const { return !bv_.empty(); }
+ uptr next() { return bv_.getAndClearFirstOne(); }
+ void clear() { bv_.clear(); }
+ private:
+ BasicBitVector bv_;
+ };
+
+ private:
+ basic_int_t mask(uptr idx) const {
+ CHECK_LT(idx, size());
+ return (basic_int_t)1UL << idx;
+ }
+ basic_int_t bits_;
+};
+
+// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
+// The implementation is optimized for better performance on
+// sparse bit vectors, i.e. the those with few set bits.
+template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
+class TwoLevelBitVector {
+ // This is essentially a 2-level bit vector.
+ // Set bit in the first level BV indicates that there are set bits
+ // in the corresponding BV of the second level.
+ // This structure allows O(kLevel1Size) time for clear() and empty(),
+ // as well fast handling of sparse BVs.
+ public:
+ enum SizeEnum { kSize = BV::kSize * BV::kSize * kLevel1Size };
+ // No CTOR.
+
+ uptr size() const { return kSize; }
+
+ void clear() {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ l1_[i].clear();
+ }
+
+ void setAll() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ l1_[i0].setAll();
+ for (uptr i1 = 0; i1 < BV::kSize; i1++)
+ l2_[i0][i1].setAll();
+ }
+ }
+
+ bool empty() const {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ if (!l1_[i].empty())
+ return false;
+ return true;
+ }
+
+ // Returns true if the bit has changed from 0 to 1.
+ bool setBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ if (!l1_[i0].getBit(i1)) {
+ l1_[i0].setBit(i1);
+ l2_[i0][i1].clear();
+ }
+ bool res = l2_[i0][i1].setBit(i2);
+ // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
+ // idx, i0, i1, i2, res);
+ return res;
+ }
+
+ bool clearBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ bool res = false;
+ if (l1_[i0].getBit(i1)) {
+ res = l2_[i0][i1].clearBit(i2);
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ return res;
+ }
+
+ bool getBit(uptr idx) const {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
+ return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
+ }
+
+ uptr getAndClearFirstOne() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].empty()) continue;
+ uptr i1 = l1_[i0].getAndClearFirstOne();
+ uptr i2 = l2_[i0][i1].getAndClearFirstOne();
+ if (!l2_[i0][i1].empty())
+ l1_[i0].setBit(i1);
+ uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
+ // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
+ return res;
+ }
+ CHECK(0);
+ return 0;
+ }
+
+ // Do "this |= v" and return whether new bits have been added.
+ bool setUnion(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = v.l1_[i0];
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l1_[i0].setBit(i1))
+ l2_[i0][i1].clear();
+ if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))
+ res = true;
+ }
+ }
+ return res;
+ }
+
+ // Do "this &= v" and return whether any bits have been removed.
+ bool setIntersection(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].setIntersection(v.l1_[i0]))
+ res = true;
+ if (!l1_[i0].empty()) {
+ BV t = l1_[i0];
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))
+ res = true;
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ }
+ return res;
+ }
+
+ // Do "this &= ~v" and return whether any bits have been removed.
+ bool setDifference(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = l1_[i0];
+ t.setIntersection(v.l1_[i0]);
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))
+ res = true;
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ return res;
+ }
+
+ void copyFrom(const TwoLevelBitVector &v) {
+ clear();
+ setUnion(v);
+ }
+
+ // Returns true if 'this' intersects with 'v'.
+ bool intersectsWith(const TwoLevelBitVector &v) const {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = l1_[i0];
+ t.setIntersection(v.l1_[i0]);
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (!v.l1_[i0].getBit(i1)) continue;
+ if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
+ // uptr idx = it.next();
+ // use(idx);
+ // }
+ class Iterator {
+ public:
+ Iterator() { }
+ explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {
+ it1_.clear();
+ it2_.clear();
+ }
+
+ bool hasNext() const {
+ if (it1_.hasNext()) return true;
+ for (uptr i = i0_; i < kLevel1Size; i++)
+ if (!bv_.l1_[i].empty()) return true;
+ return false;
+ }
+
+ uptr next() {
+ // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ if (!it1_.hasNext() && !it2_.hasNext()) {
+ for (; i0_ < kLevel1Size; i0_++) {
+ if (bv_.l1_[i0_].empty()) continue;
+ it1_ = typename BV::Iterator(bv_.l1_[i0_]);
+ // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ break;
+ }
+ }
+ if (!it2_.hasNext()) {
+ CHECK(it1_.hasNext());
+ i1_ = it1_.next();
+ it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);
+ // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ }
+ CHECK(it2_.hasNext());
+ uptr i2 = it2_.next();
+ uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;
+ // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,
+ // it1_.hasNext(), it2_.hasNext(), kSize, res);
+ if (!it1_.hasNext() && !it2_.hasNext())
+ i0_++;
+ return res;
+ }
+
+ private:
+ const TwoLevelBitVector &bv_;
+ uptr i0_, i1_;
+ typename BV::Iterator it1_, it2_;
+ };
+
+ private:
+ void check(uptr idx) const { CHECK_LE(idx, size()); }
+
+ uptr idx0(uptr idx) const {
+ uptr res = idx / (BV::kSize * BV::kSize);
+ CHECK_LE(res, kLevel1Size);
+ return res;
+ }
+
+ uptr idx1(uptr idx) const {
+ uptr res = (idx / BV::kSize) % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ uptr idx2(uptr idx) const {
+ uptr res = idx % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ BV l1_[kLevel1Size];
+ BV l2_[kLevel1Size][BV::kSize];
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BITVECTOR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h
new file mode 100644
index 000000000000..df72f1c2d471
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h
@@ -0,0 +1,165 @@
+//===-- sanitizer_bvgraph.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 Sanitizer runtime.
+// BVGraph -- a directed graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BVGRAPH_H
+#define SANITIZER_BVGRAPH_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bitvector.h"
+
+namespace __sanitizer {
+
+// Directed graph of fixed size implemented as an array of bit vectors.
+// Not thread-safe, all accesses should be protected by an external lock.
+template<class BV>
+class BVGraph {
+ public:
+ enum SizeEnum { kSize = BV::kSize };
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() {
+ for (uptr i = 0; i < size(); i++)
+ v[i].clear();
+ }
+
+ bool empty() const {
+ for (uptr i = 0; i < size(); i++)
+ if (!v[i].empty())
+ return false;
+ return true;
+ }
+
+ // Returns true if a new edge was added.
+ bool addEdge(uptr from, uptr to) {
+ check(from, to);
+ return v[from].setBit(to);
+ }
+
+ // Returns true if at least one new edge was added.
+ uptr addEdges(const BV &from, uptr to, uptr added_edges[],
+ uptr max_added_edges) {
+ uptr res = 0;
+ t1.copyFrom(from);
+ while (!t1.empty()) {
+ uptr node = t1.getAndClearFirstOne();
+ if (v[node].setBit(to))
+ if (res < max_added_edges)
+ added_edges[res++] = node;
+ }
+ return res;
+ }
+
+ // *EXPERIMENTAL*
+ // Returns true if an edge from=>to exist.
+ // This function does not use any global state except for 'this' itself,
+ // and thus can be called from different threads w/o locking.
+ // This would be racy.
+ // FIXME: investigate how much we can prove about this race being "benign".
+ bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); }
+
+ // Returns true if the edge from=>to was removed.
+ bool removeEdge(uptr from, uptr to) {
+ return v[from].clearBit(to);
+ }
+
+ // Returns true if at least one edge *=>to was removed.
+ bool removeEdgesTo(const BV &to) {
+ bool res = 0;
+ for (uptr from = 0; from < size(); from++) {
+ if (v[from].setDifference(to))
+ res = true;
+ }
+ return res;
+ }
+
+ // Returns true if at least one edge from=>* was removed.
+ bool removeEdgesFrom(const BV &from) {
+ bool res = false;
+ t1.copyFrom(from);
+ while (!t1.empty()) {
+ uptr idx = t1.getAndClearFirstOne();
+ if (!v[idx].empty()) {
+ v[idx].clear();
+ res = true;
+ }
+ }
+ return res;
+ }
+
+ void removeEdgesFrom(uptr from) {
+ return v[from].clear();
+ }
+
+ bool hasEdge(uptr from, uptr to) const {
+ check(from, to);
+ return v[from].getBit(to);
+ }
+
+ // Returns true if there is a path from the node 'from'
+ // to any of the nodes in 'targets'.
+ bool isReachable(uptr from, const BV &targets) {
+ BV &to_visit = t1,
+ &visited = t2;
+ to_visit.copyFrom(v[from]);
+ visited.clear();
+ visited.setBit(from);
+ while (!to_visit.empty()) {
+ uptr idx = to_visit.getAndClearFirstOne();
+ if (visited.setBit(idx))
+ to_visit.setUnion(v[idx]);
+ }
+ return targets.intersectsWith(visited);
+ }
+
+ // Finds a path from 'from' to one of the nodes in 'target',
+ // stores up to 'path_size' items of the path into 'path',
+ // returns the path length, or 0 if there is no path of size 'path_size'.
+ uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) {
+ if (path_size == 0)
+ return 0;
+ path[0] = from;
+ if (targets.getBit(from))
+ return 1;
+ // The function is recursive, so we don't want to create BV on stack.
+ // Instead of a getAndClearFirstOne loop we use the slower iterator.
+ for (typename BV::Iterator it(v[from]); it.hasNext(); ) {
+ uptr idx = it.next();
+ if (uptr res = findPath(idx, targets, path + 1, path_size - 1))
+ return res + 1;
+ }
+ return 0;
+ }
+
+ // Same as findPath, but finds a shortest path.
+ uptr findShortestPath(uptr from, const BV &targets, uptr *path,
+ uptr path_size) {
+ for (uptr p = 1; p <= path_size; p++)
+ if (findPath(from, targets, path, p) == p)
+ return p;
+ return 0;
+ }
+
+ private:
+ void check(uptr idx1, uptr idx2) const {
+ CHECK_LT(idx1, size());
+ CHECK_LT(idx2, size());
+ }
+ BV v[kSize];
+ // Keep temporary vectors here since we can not create large objects on stack.
+ BV t1, t2;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BVGRAPH_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
new file mode 100644
index 000000000000..4be3c7abf756
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
@@ -0,0 +1,350 @@
+//===-- sanitizer_common.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
+
+namespace __sanitizer {
+
+const char *SanitizerToolName = "SanitizerTool";
+
+atomic_uint32_t current_verbosity;
+
+uptr GetPageSizeCached() {
+ static uptr PageSize;
+ if (!PageSize)
+ PageSize = GetPageSize();
+ return PageSize;
+}
+
+StaticSpinMutex report_file_mu;
+ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
+
+void RawWrite(const char *buffer) {
+ report_file.Write(buffer, internal_strlen(buffer));
+}
+
+void ReportFile::ReopenIfNecessary() {
+ mu->CheckLocked();
+ if (fd == kStdoutFd || fd == kStderrFd) return;
+
+ uptr pid = internal_getpid();
+ // If in tracer, use the parent's file.
+ if (pid == stoptheworld_tracer_pid)
+ pid = stoptheworld_tracer_ppid;
+ if (fd != kInvalidFd) {
+ // If the report file is already opened by the current process,
+ // do nothing. Otherwise the report file was opened by the parent
+ // process, close it now.
+ if (fd_pid == pid)
+ return;
+ else
+ internal_close(fd);
+ }
+
+ internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
+ uptr openrv = OpenFile(full_path, true);
+ if (internal_iserror(openrv)) {
+ const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
+ internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
+ internal_write(kStderrFd, full_path, internal_strlen(full_path));
+ Die();
+ }
+ fd = openrv;
+ fd_pid = pid;
+}
+
+void ReportFile::SetReportPath(const char *path) {
+ if (!path)
+ return;
+ uptr len = internal_strlen(path);
+ if (len > sizeof(path_prefix) - 100) {
+ Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
+ path[0], path[1], path[2], path[3],
+ path[4], path[5], path[6], path[7]);
+ Die();
+ }
+
+ SpinMutexLock l(mu);
+ if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
+ internal_close(fd);
+ fd = kInvalidFd;
+ if (internal_strcmp(path, "stdout") == 0) {
+ fd = kStdoutFd;
+ } else if (internal_strcmp(path, "stderr") == 0) {
+ fd = kStderrFd;
+ } else {
+ internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
+ }
+}
+
+// PID of the tracer task in StopTheWorld. It shares the address space with the
+// main process, but has a different PID and thus requires special handling.
+uptr stoptheworld_tracer_pid = 0;
+// Cached pid of parent process - if the parent process dies, we want to keep
+// writing to the same log file.
+uptr stoptheworld_tracer_ppid = 0;
+
+static DieCallbackType InternalDieCallback, UserDieCallback;
+void SetDieCallback(DieCallbackType callback) {
+ InternalDieCallback = callback;
+}
+void SetUserDieCallback(DieCallbackType callback) {
+ UserDieCallback = callback;
+}
+
+DieCallbackType GetDieCallback() {
+ return InternalDieCallback;
+}
+
+void NORETURN Die() {
+ if (UserDieCallback)
+ UserDieCallback();
+ if (InternalDieCallback)
+ InternalDieCallback();
+ internal__exit(1);
+}
+
+static CheckFailedCallbackType CheckFailedCallback;
+void SetCheckFailedCallback(CheckFailedCallbackType callback) {
+ CheckFailedCallback = callback;
+}
+
+void NORETURN CheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ if (CheckFailedCallback) {
+ CheckFailedCallback(file, line, cond, v1, v2);
+ }
+ Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
+ v1, v2);
+ Die();
+}
+
+uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr max_len, int *errno_p) {
+ uptr PageSize = GetPageSizeCached();
+ uptr kMinFileLen = PageSize;
+ uptr read_len = 0;
+ *buff = 0;
+ *buff_size = 0;
+ // The files we usually open are not seekable, so try different buffer sizes.
+ for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
+ uptr openrv = OpenFile(file_name, /*write*/ false);
+ if (internal_iserror(openrv, errno_p)) return 0;
+ fd_t fd = openrv;
+ UnmapOrDie(*buff, *buff_size);
+ *buff = (char*)MmapOrDie(size, __func__);
+ *buff_size = size;
+ // Read up to one page at a time.
+ read_len = 0;
+ bool reached_eof = false;
+ while (read_len + PageSize <= size) {
+ uptr just_read = internal_read(fd, *buff + read_len, PageSize);
+ if (internal_iserror(just_read, errno_p)) {
+ UnmapOrDie(*buff, *buff_size);
+ return 0;
+ }
+ if (just_read == 0) {
+ reached_eof = true;
+ break;
+ }
+ read_len += just_read;
+ }
+ internal_close(fd);
+ if (reached_eof) // We've read the whole file.
+ break;
+ }
+ return read_len;
+}
+
+typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
+
+template<class T>
+static inline bool CompareLess(const T &a, const T &b) {
+ return a < b;
+}
+
+void SortArray(uptr *array, uptr size) {
+ InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
+}
+
+// We want to map a chunk of address space aligned to 'alignment'.
+// We do it by maping a bit more and then unmaping redundant pieces.
+// We probably can do it with fewer syscalls in some OS-dependent way.
+void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
+// uptr PageSize = GetPageSizeCached();
+ CHECK(IsPowerOfTwo(size));
+ CHECK(IsPowerOfTwo(alignment));
+ uptr map_size = size + alignment;
+ uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
+ uptr map_end = map_res + map_size;
+ uptr res = map_res;
+ if (res & (alignment - 1)) // Not aligned.
+ res = (map_res + alignment) & ~(alignment - 1);
+ uptr end = res + size;
+ if (res != map_res)
+ UnmapOrDie((void*)map_res, res - map_res);
+ if (end != map_end)
+ UnmapOrDie((void*)end, map_end - end);
+ return (void*)res;
+}
+
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_path_prefix) {
+ if (filepath == 0) return 0;
+ if (strip_path_prefix == 0) return filepath;
+ const char *pos = internal_strstr(filepath, strip_path_prefix);
+ if (pos == 0) return filepath;
+ pos += internal_strlen(strip_path_prefix);
+ if (pos[0] == '.' && pos[1] == '/')
+ pos += 2;
+ return pos;
+}
+
+const char *StripModuleName(const char *module) {
+ if (module == 0)
+ return 0;
+ if (const char *slash_pos = internal_strrchr(module, '/'))
+ return slash_pos + 1;
+ return module;
+}
+
+void ReportErrorSummary(const char *error_message) {
+ if (!common_flags()->print_summary)
+ return;
+ InternalScopedString buff(kMaxSummaryLength);
+ buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
+ __sanitizer_report_error_summary(buff.data());
+}
+
+void ReportErrorSummary(const char *error_type, const char *file,
+ int line, const char *function) {
+ if (!common_flags()->print_summary)
+ return;
+ InternalScopedString buff(kMaxSummaryLength);
+ buff.append("%s %s:%d %s", error_type,
+ file ? StripPathPrefix(file, common_flags()->strip_path_prefix)
+ : "??",
+ line, function ? function : "??");
+ ReportErrorSummary(buff.data());
+}
+
+LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
+ full_name_ = internal_strdup(module_name);
+ base_address_ = base_address;
+ ranges_.clear();
+}
+
+void LoadedModule::clear() {
+ InternalFree(full_name_);
+ while (!ranges_.empty()) {
+ AddressRange *r = ranges_.front();
+ ranges_.pop_front();
+ InternalFree(r);
+ }
+}
+
+void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
+ void *mem = InternalAlloc(sizeof(AddressRange));
+ AddressRange *r = new(mem) AddressRange(beg, end, executable);
+ ranges_.push_back(r);
+}
+
+bool LoadedModule::containsAddress(uptr address) const {
+ for (Iterator iter = ranges(); iter.hasNext();) {
+ const AddressRange *r = iter.next();
+ if (r->beg <= address && address < r->end)
+ return true;
+ }
+ return false;
+}
+
+static atomic_uintptr_t g_total_mmaped;
+
+void IncreaseTotalMmap(uptr size) {
+ if (!common_flags()->mmap_limit_mb) return;
+ uptr total_mmaped =
+ atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
+ // Since for now mmap_limit_mb is not a user-facing flag, just kill
+ // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
+ RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
+}
+
+void DecreaseTotalMmap(uptr size) {
+ if (!common_flags()->mmap_limit_mb) return;
+ atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
+}
+
+bool TemplateMatch(const char *templ, const char *str) {
+ if (str == 0 || str[0] == 0)
+ return false;
+ bool start = false;
+ if (templ && templ[0] == '^') {
+ start = true;
+ templ++;
+ }
+ bool asterisk = false;
+ while (templ && templ[0]) {
+ if (templ[0] == '*') {
+ templ++;
+ start = false;
+ asterisk = true;
+ continue;
+ }
+ if (templ[0] == '$')
+ return str[0] == 0 || asterisk;
+ if (str[0] == 0)
+ return false;
+ char *tpos = (char*)internal_strchr(templ, '*');
+ char *tpos1 = (char*)internal_strchr(templ, '$');
+ if (tpos == 0 || (tpos1 && tpos1 < tpos))
+ tpos = tpos1;
+ if (tpos != 0)
+ tpos[0] = 0;
+ const char *str0 = str;
+ const char *spos = internal_strstr(str, templ);
+ str = spos + internal_strlen(templ);
+ templ = tpos;
+ if (tpos)
+ tpos[0] = tpos == tpos1 ? '$' : '*';
+ if (spos == 0)
+ return false;
+ if (start && spos != str0)
+ return false;
+ start = false;
+ asterisk = false;
+ }
+ return true;
+}
+
+} // namespace __sanitizer
+
+using namespace __sanitizer; // NOLINT
+
+extern "C" {
+void __sanitizer_set_report_path(const char *path) {
+ report_file.SetReportPath(path);
+}
+
+void __sanitizer_report_error_summary(const char *error_summary) {
+ Printf("%s\n", error_summary);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_set_death_callback(void (*callback)(void)) {
+ SetUserDieCallback(callback);
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
new file mode 100644
index 000000000000..ff13ef164045
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -0,0 +1,622 @@
+//===-- sanitizer_common.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 shared between run-time libraries of sanitizers.
+//
+// It declares common functions and classes that are used in both runtimes.
+// Implementation of some functions are provided in sanitizer_common, while
+// others must be defined by run-time library itself.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_COMMON_H
+#define SANITIZER_COMMON_H
+
+#include "sanitizer_flags.h"
+#include "sanitizer_interface_internal.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+struct StackTrace;
+
+// Constants.
+const uptr kWordSize = SANITIZER_WORDSIZE / 8;
+const uptr kWordSizeInBits = 8 * kWordSize;
+
+#if defined(__powerpc__) || defined(__powerpc64__)
+ const uptr kCacheLineSize = 128;
+#else
+ const uptr kCacheLineSize = 64;
+#endif
+
+const uptr kMaxPathLength = 4096;
+
+const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
+
+extern const char *SanitizerToolName; // Can be changed by the tool.
+
+extern atomic_uint32_t current_verbosity;
+INLINE void SetVerbosity(int verbosity) {
+ atomic_store(&current_verbosity, verbosity, memory_order_relaxed);
+}
+INLINE int Verbosity() {
+ return atomic_load(&current_verbosity, memory_order_relaxed);
+}
+
+uptr GetPageSize();
+uptr GetPageSizeCached();
+uptr GetMmapGranularity();
+uptr GetMaxVirtualAddress();
+// Threads
+uptr GetTid();
+uptr GetThreadSelf();
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom);
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size);
+
+// Memory management
+void *MmapOrDie(uptr size, const char *mem_type);
+void UnmapOrDie(void *addr, uptr size);
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
+void *MmapNoReserveOrDie(uptr size, const char *mem_type);
+void *MmapFixedOrDie(uptr fixed_addr, uptr size);
+void *Mprotect(uptr fixed_addr, uptr size);
+// Map aligned chunk of address space; size and alignment are powers of two.
+void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
+// Used to check if we can map shadow memory to a fixed location.
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
+void FlushUnneededShadowMemory(uptr addr, uptr size);
+void IncreaseTotalMmap(uptr size);
+void DecreaseTotalMmap(uptr size);
+uptr GetRSS();
+void NoHugePagesInRegion(uptr addr, uptr length);
+void DontDumpShadowMemory(uptr addr, uptr length);
+
+// InternalScopedBuffer can be used instead of large stack arrays to
+// keep frame size low.
+// FIXME: use InternalAlloc instead of MmapOrDie once
+// InternalAlloc is made libc-free.
+template<typename T>
+class InternalScopedBuffer {
+ public:
+ explicit InternalScopedBuffer(uptr cnt) {
+ cnt_ = cnt;
+ ptr_ = (T*)MmapOrDie(cnt * sizeof(T), "InternalScopedBuffer");
+ }
+ ~InternalScopedBuffer() {
+ UnmapOrDie(ptr_, cnt_ * sizeof(T));
+ }
+ T &operator[](uptr i) { return ptr_[i]; }
+ T *data() { return ptr_; }
+ uptr size() { return cnt_ * sizeof(T); }
+
+ private:
+ T *ptr_;
+ uptr cnt_;
+ // Disallow evil constructors.
+ InternalScopedBuffer(const InternalScopedBuffer&);
+ void operator=(const InternalScopedBuffer&);
+};
+
+class InternalScopedString : public InternalScopedBuffer<char> {
+ public:
+ explicit InternalScopedString(uptr max_length)
+ : InternalScopedBuffer<char>(max_length), length_(0) {
+ (*this)[0] = '\0';
+ }
+ uptr length() { return length_; }
+ void clear() {
+ (*this)[0] = '\0';
+ length_ = 0;
+ }
+ void append(const char *format, ...);
+
+ private:
+ uptr length_;
+};
+
+// Simple low-level (mmap-based) allocator for internal use. Doesn't have
+// constructor, so all instances of LowLevelAllocator should be
+// linker initialized.
+class LowLevelAllocator {
+ public:
+ // Requires an external lock.
+ void *Allocate(uptr size);
+ private:
+ char *allocated_end_;
+ char *allocated_current_;
+};
+typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size);
+// Allows to register tool-specific callbacks for LowLevelAllocator.
+// Passing NULL removes the callback.
+void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
+
+// IO
+void RawWrite(const char *buffer);
+bool ColorizeReports();
+void Printf(const char *format, ...);
+void Report(const char *format, ...);
+void SetPrintfAndReportCallback(void (*callback)(const char *));
+#define VReport(level, ...) \
+ do { \
+ if ((uptr)Verbosity() >= (level)) Report(__VA_ARGS__); \
+ } while (0)
+#define VPrintf(level, ...) \
+ do { \
+ if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \
+ } while (0)
+
+// Can be used to prevent mixing error reports from different sanitizers.
+extern StaticSpinMutex CommonSanitizerReportMutex;
+
+struct ReportFile {
+ void Write(const char *buffer, uptr length);
+ bool PrintsToTty();
+ void SetReportPath(const char *path);
+
+ // Don't use fields directly. They are only declared public to allow
+ // aggregate initialization.
+
+ // Protects fields below.
+ StaticSpinMutex *mu;
+ // Opened file descriptor. Defaults to stderr. It may be equal to
+ // kInvalidFd, in which case new file will be opened when necessary.
+ fd_t fd;
+ // Path prefix of report file, set via __sanitizer_set_report_path.
+ char path_prefix[kMaxPathLength];
+ // Full path to report, obtained as <path_prefix>.PID
+ char full_path[kMaxPathLength];
+ // PID of the process that opened fd. If a fork() occurs,
+ // the PID of child will be different from fd_pid.
+ uptr fd_pid;
+
+ private:
+ void ReopenIfNecessary();
+};
+extern ReportFile report_file;
+
+extern uptr stoptheworld_tracer_pid;
+extern uptr stoptheworld_tracer_ppid;
+
+uptr OpenFile(const char *filename, bool write);
+// Opens the file 'file_name" and reads up to 'max_len' bytes.
+// The resulting buffer is mmaped and stored in '*buff'.
+// The size of the mmaped region is stored in '*buff_size',
+// Returns the number of read bytes or 0 if file can not be opened.
+uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr max_len, int *errno_p = nullptr);
+// Maps given file to virtual memory, and returns pointer to it
+// (or NULL if the mapping failes). Stores the size of mmaped region
+// in '*buff_size'.
+void *MapFileToMemory(const char *file_name, uptr *buff_size);
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size);
+
+// Error report formatting.
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_file_prefix);
+// Strip the directories from the module name.
+const char *StripModuleName(const char *module);
+
+// OS
+void DisableCoreDumperIfNecessary();
+void DumpProcessMap();
+bool FileExists(const char *filename);
+const char *GetEnv(const char *name);
+bool SetEnv(const char *name, const char *value);
+const char *GetPwd();
+char *FindPathToBinary(const char *name);
+u32 GetUid();
+void ReExec();
+bool StackSizeIsUnlimited();
+void SetStackSizeLimitInBytes(uptr limit);
+bool AddressSpaceIsUnlimited();
+void SetAddressSpaceUnlimited();
+void AdjustStackSize(void *attr);
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void SetSandboxingCallback(void (*f)());
+
+void CoverageUpdateMapping();
+void CovBeforeFork();
+void CovAfterFork(int child_pid);
+
+void InitializeCoverage(bool enabled, const char *coverage_dir);
+void ReInitializeCoverage(bool enabled, const char *coverage_dir);
+
+void InitTlsSize();
+uptr GetTlsSize();
+
+// Other
+void SleepForSeconds(int seconds);
+void SleepForMillis(int millis);
+u64 NanoTime();
+int Atexit(void (*function)(void));
+void SortArray(uptr *array, uptr size);
+bool TemplateMatch(const char *templ, const char *str);
+
+// Exit
+void NORETURN Abort();
+void NORETURN Die();
+void NORETURN
+CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
+
+// Set the name of the current thread to 'name', return true on succees.
+// The name may be truncated to a system-dependent limit.
+bool SanitizerSetThreadName(const char *name);
+// Get the name of the current thread (no more than max_len bytes),
+// return true on succees. name should have space for at least max_len+1 bytes.
+bool SanitizerGetThreadName(char *name, int max_len);
+
+// Specific tools may override behavior of "Die" and "CheckFailed" functions
+// to do tool-specific job.
+typedef void (*DieCallbackType)(void);
+void SetDieCallback(DieCallbackType);
+void SetUserDieCallback(DieCallbackType);
+DieCallbackType GetDieCallback();
+typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
+ u64, u64);
+void SetCheckFailedCallback(CheckFailedCallbackType callback);
+
+// Callback will be called if soft_rss_limit_mb is given and the limit is
+// exceeded (exceeded==true) or if rss went down below the limit
+// (exceeded==false).
+// The callback should be registered once at the tool init time.
+void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded));
+
+// Functions related to signal handling.
+typedef void (*SignalHandlerType)(int, void *, void *);
+bool IsDeadlySignal(int signum);
+void InstallDeadlySignalHandlers(SignalHandlerType handler);
+// Alternative signal stack (POSIX-only).
+void SetAlternateSignalStack();
+void UnsetAlternateSignalStack();
+
+// We don't want a summary too long.
+const int kMaxSummaryLength = 1024;
+// Construct a one-line string:
+// SUMMARY: SanitizerToolName: error_message
+// and pass it to __sanitizer_report_error_summary.
+void ReportErrorSummary(const char *error_message);
+// Same as above, but construct error_message as:
+// error_type file:line function
+void ReportErrorSummary(const char *error_type, const char *file,
+ int line, const char *function);
+void ReportErrorSummary(const char *error_type, StackTrace *trace);
+
+// Math
+#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
+extern "C" {
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT
+#if defined(_WIN64)
+unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT
+unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT
+#endif
+}
+#endif
+
+INLINE uptr MostSignificantSetBitIndex(uptr x) {
+ CHECK_NE(x, 0U);
+ unsigned long up; // NOLINT
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+ up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
+#elif defined(_WIN64)
+ _BitScanReverse64(&up, x);
+#else
+ _BitScanReverse(&up, x);
+#endif
+ return up;
+}
+
+INLINE uptr LeastSignificantSetBitIndex(uptr x) {
+ CHECK_NE(x, 0U);
+ unsigned long up; // NOLINT
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+ up = __builtin_ctzl(x);
+#elif defined(_WIN64)
+ _BitScanForward64(&up, x);
+#else
+ _BitScanForward(&up, x);
+#endif
+ return up;
+}
+
+INLINE bool IsPowerOfTwo(uptr x) {
+ return (x & (x - 1)) == 0;
+}
+
+INLINE uptr RoundUpToPowerOfTwo(uptr size) {
+ CHECK(size);
+ if (IsPowerOfTwo(size)) return size;
+
+ uptr up = MostSignificantSetBitIndex(size);
+ CHECK(size < (1ULL << (up + 1)));
+ CHECK(size > (1ULL << up));
+ return 1UL << (up + 1);
+}
+
+INLINE uptr RoundUpTo(uptr size, uptr boundary) {
+ CHECK(IsPowerOfTwo(boundary));
+ return (size + boundary - 1) & ~(boundary - 1);
+}
+
+INLINE uptr RoundDownTo(uptr x, uptr boundary) {
+ return x & ~(boundary - 1);
+}
+
+INLINE bool IsAligned(uptr a, uptr alignment) {
+ return (a & (alignment - 1)) == 0;
+}
+
+INLINE uptr Log2(uptr x) {
+ CHECK(IsPowerOfTwo(x));
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+ return __builtin_ctzl(x);
+#elif defined(_WIN64)
+ unsigned long ret; // NOLINT
+ _BitScanForward64(&ret, x);
+ return ret;
+#else
+ unsigned long ret; // NOLINT
+ _BitScanForward(&ret, x);
+ return ret;
+#endif
+}
+
+// Don't use std::min, std::max or std::swap, to minimize dependency
+// on libstdc++.
+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; }
+template<class T> void Swap(T& a, T& b) {
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+// Char handling
+INLINE bool IsSpace(int c) {
+ return (c == ' ') || (c == '\n') || (c == '\t') ||
+ (c == '\f') || (c == '\r') || (c == '\v');
+}
+INLINE bool IsDigit(int c) {
+ return (c >= '0') && (c <= '9');
+}
+INLINE int ToLower(int c) {
+ return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
+}
+
+// A low-level vector based on mmap. May incur a significant memory overhead for
+// small vectors.
+// WARNING: The current implementation supports only POD types.
+template<typename T>
+class InternalMmapVectorNoCtor {
+ public:
+ void Initialize(uptr initial_capacity) {
+ capacity_ = Max(initial_capacity, (uptr)1);
+ size_ = 0;
+ data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVectorNoCtor");
+ }
+ void Destroy() {
+ UnmapOrDie(data_, capacity_ * sizeof(T));
+ }
+ T &operator[](uptr i) {
+ CHECK_LT(i, size_);
+ return data_[i];
+ }
+ const T &operator[](uptr i) const {
+ CHECK_LT(i, size_);
+ return data_[i];
+ }
+ void push_back(const T &element) {
+ CHECK_LE(size_, capacity_);
+ if (size_ == capacity_) {
+ uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1);
+ Resize(new_capacity);
+ }
+ data_[size_++] = element;
+ }
+ T &back() {
+ CHECK_GT(size_, 0);
+ return data_[size_ - 1];
+ }
+ void pop_back() {
+ CHECK_GT(size_, 0);
+ size_--;
+ }
+ uptr size() const {
+ return size_;
+ }
+ const T *data() const {
+ return data_;
+ }
+ uptr capacity() const {
+ return capacity_;
+ }
+
+ void clear() { size_ = 0; }
+
+ private:
+ void Resize(uptr new_capacity) {
+ CHECK_GT(new_capacity, 0);
+ CHECK_LE(size_, new_capacity);
+ T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T),
+ "InternalMmapVector");
+ internal_memcpy(new_data, data_, size_ * sizeof(T));
+ T *old_data = data_;
+ data_ = new_data;
+ UnmapOrDie(old_data, capacity_ * sizeof(T));
+ capacity_ = new_capacity;
+ }
+
+ T *data_;
+ uptr capacity_;
+ uptr size_;
+};
+
+template<typename T>
+class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
+ public:
+ explicit InternalMmapVector(uptr initial_capacity) {
+ InternalMmapVectorNoCtor<T>::Initialize(initial_capacity);
+ }
+ ~InternalMmapVector() { InternalMmapVectorNoCtor<T>::Destroy(); }
+ // Disallow evil constructors.
+ InternalMmapVector(const InternalMmapVector&);
+ void operator=(const InternalMmapVector&);
+};
+
+// HeapSort for arrays and InternalMmapVector.
+template<class Container, class Compare>
+void InternalSort(Container *v, uptr size, Compare comp) {
+ if (size < 2)
+ return;
+ // Stage 1: insert elements to the heap.
+ for (uptr i = 1; i < size; i++) {
+ uptr j, p;
+ for (j = i; j > 0; j = p) {
+ p = (j - 1) / 2;
+ if (comp((*v)[p], (*v)[j]))
+ Swap((*v)[j], (*v)[p]);
+ else
+ break;
+ }
+ }
+ // Stage 2: swap largest element with the last one,
+ // and sink the new top.
+ for (uptr i = size - 1; i > 0; i--) {
+ Swap((*v)[0], (*v)[i]);
+ uptr j, max_ind;
+ for (j = 0; j < i; j = max_ind) {
+ uptr left = 2 * j + 1;
+ uptr right = 2 * j + 2;
+ max_ind = j;
+ if (left < i && comp((*v)[max_ind], (*v)[left]))
+ max_ind = left;
+ if (right < i && comp((*v)[max_ind], (*v)[right]))
+ max_ind = right;
+ if (max_ind != j)
+ Swap((*v)[j], (*v)[max_ind]);
+ else
+ break;
+ }
+ }
+}
+
+template<class Container, class Value, class Compare>
+uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
+ const Value &val, Compare comp) {
+ uptr not_found = last + 1;
+ while (last >= first) {
+ uptr mid = (first + last) / 2;
+ if (comp(v[mid], val))
+ first = mid + 1;
+ else if (comp(val, v[mid]))
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return not_found;
+}
+
+// Represents a binary loaded into virtual memory (e.g. this can be an
+// executable or a shared object).
+class LoadedModule {
+ public:
+ LoadedModule(const char *module_name, uptr base_address);
+ void clear();
+ void addAddressRange(uptr beg, uptr end, bool executable);
+ bool containsAddress(uptr address) const;
+
+ const char *full_name() const { return full_name_; }
+ uptr base_address() const { return base_address_; }
+
+ struct AddressRange {
+ AddressRange *next;
+ uptr beg;
+ uptr end;
+ bool executable;
+
+ AddressRange(uptr beg, uptr end, bool executable)
+ : next(nullptr), beg(beg), end(end), executable(executable) {}
+ };
+
+ typedef IntrusiveList<AddressRange>::ConstIterator Iterator;
+ Iterator ranges() const { return Iterator(&ranges_); }
+
+ private:
+ char *full_name_; // Owned.
+ uptr base_address_;
+ IntrusiveList<AddressRange> ranges_;
+};
+
+// OS-dependent function that fills array with descriptions of at most
+// "max_modules" currently loaded modules. Returns the number of
+// initialized modules. If filter is nonzero, ignores modules for which
+// filter(full_name) is false.
+typedef bool (*string_predicate_t)(const char *);
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter);
+
+#if SANITIZER_POSIX
+const uptr kPthreadDestructorIterations = 4;
+#else
+// Unused on Windows.
+const uptr kPthreadDestructorIterations = 0;
+#endif
+
+// Callback type for iterating over a set of memory ranges.
+typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
+
+#if SANITIZER_ANDROID
+// Initialize Android logging. Any writes before this are silently lost.
+void AndroidLogInit();
+void AndroidLogWrite(const char *buffer);
+void GetExtraActivationFlags(char *buf, uptr size);
+void SanitizerInitializeUnwinder();
+#else
+INLINE void AndroidLogInit() {}
+INLINE void AndroidLogWrite(const char *buffer_unused) {}
+INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
+INLINE void SanitizerInitializeUnwinder() {}
+#endif
+
+void *internal_start_thread(void(*func)(void*), void *arg);
+void internal_join_thread(void *th);
+void MaybeStartBackgroudThread();
+
+// Make the compiler think that something is going on there.
+// Use this inside a loop that looks like memset/memcpy/etc to prevent the
+// compiler from recognising it and turning it into an actual call to
+// memset/memcpy/etc.
+static inline void SanitizerBreakOptimization(void *arg) {
+#if _MSC_VER
+ // FIXME: make sure this is actually enough.
+ __asm;
+#else
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
+}
+
+} // namespace __sanitizer
+
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ __sanitizer::LowLevelAllocator &alloc) {
+ return alloc.Allocate(size);
+}
+
+struct StackDepotStats {
+ uptr n_uniq_ids;
+ uptr allocated;
+};
+
+#endif // SANITIZER_COMMON_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
new file mode 100644
index 000000000000..87c33e186320
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -0,0 +1,4958 @@
+//===-- sanitizer_common_interceptors.inc -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common function interceptors for tools like AddressSanitizer,
+// ThreadSanitizer, MemorySanitizer, etc.
+//
+// This file should be included into the tool's interceptor file,
+// which has to define it's own macros:
+// COMMON_INTERCEPTOR_ENTER
+// COMMON_INTERCEPTOR_ENTER_NOIGNORE
+// COMMON_INTERCEPTOR_READ_RANGE
+// COMMON_INTERCEPTOR_WRITE_RANGE
+// COMMON_INTERCEPTOR_INITIALIZE_RANGE
+// COMMON_INTERCEPTOR_DIR_ACQUIRE
+// COMMON_INTERCEPTOR_FD_ACQUIRE
+// COMMON_INTERCEPTOR_FD_RELEASE
+// COMMON_INTERCEPTOR_FD_ACCESS
+// COMMON_INTERCEPTOR_SET_THREAD_NAME
+// COMMON_INTERCEPTOR_ON_EXIT
+// COMMON_INTERCEPTOR_MUTEX_LOCK
+// COMMON_INTERCEPTOR_MUTEX_UNLOCK
+// COMMON_INTERCEPTOR_MUTEX_REPAIR
+// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
+// COMMON_INTERCEPTOR_HANDLE_RECVMSG
+// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+//===----------------------------------------------------------------------===//
+#include "interception/interception.h"
+#include "sanitizer_addrhashmap.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_platform_interceptors.h"
+#include "sanitizer_tls_get_addr.h"
+
+#include <stdarg.h>
+
+#if SANITIZER_WINDOWS && !defined(va_copy)
+#define va_copy(dst, src) ((dst) = (src))
+#endif // _WIN32
+
+#if SANITIZER_FREEBSD
+#define pthread_setname_np pthread_set_name_np
+#define inet_aton __inet_aton
+#define inet_pton __inet_pton
+#endif
+
+#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_UNPOISON_PARAM
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FD_ACCESS
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_OPEN
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_CLOSE
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \
+ COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__)
+#endif
+
+#ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
+#endif
+
+struct FileMetadata {
+ // For open_memstream().
+ char **addr;
+ SIZE_T *size;
+};
+
+struct CommonInterceptorMetadata {
+ enum {
+ CIMT_INVALID = 0,
+ CIMT_FILE
+ } type;
+ union {
+ FileMetadata file;
+ };
+};
+
+typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap;
+
+static MetadataHashMap *interceptor_metadata_map;
+
+#if SI_NOT_WINDOWS
+UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr,
+ const FileMetadata &file) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr);
+ CHECK(h.created());
+ h->type = CommonInterceptorMetadata::CIMT_FILE;
+ h->file = file;
+}
+
+UNUSED static const FileMetadata *GetInterceptorMetadata(
+ __sanitizer_FILE *addr) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr,
+ /* remove */ false,
+ /* create */ false);
+ if (h.exists()) {
+ CHECK(!h.created());
+ CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE);
+ return &h->file;
+ } else {
+ return 0;
+ }
+}
+
+UNUSED static void DeleteInterceptorMetadata(void *addr) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true);
+ CHECK(h.exists());
+}
+#endif // SI_NOT_WINDOWS
+
+#if SANITIZER_INTERCEPT_TEXTDOMAIN
+INTERCEPTOR(char*, textdomain, const char *domainname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
+ char* domain = REAL(textdomain)(domainname);
+ if (domain) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
+ }
+ return domain;
+}
+#define INIT_TEXTDOMAIN COMMON_INTERCEPT_FUNCTION(textdomain)
+#else
+#define INIT_TEXTDOMAIN
+#endif
+
+#if SANITIZER_INTERCEPT_STRCMP
+static inline int CharCmpX(unsigned char c1, unsigned char c2) {
+ return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
+
+INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
+ unsigned char c1, c2;
+ uptr i;
+ for (i = 0;; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+ return CharCmpX(c1, c2);
+}
+
+INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_strncmp(s1, s2, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
+ return CharCmpX(c1, c2);
+}
+
+#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp)
+#define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp)
+#else
+#define INIT_STRCMP
+#define INIT_STRNCMP
+#endif
+
+#if SANITIZER_INTERCEPT_STRCASECMP
+static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
+ int c1_low = ToLower(c1);
+ int c2_low = ToLower(c2);
+ return c1_low - c2_low;
+}
+
+INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0;; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+ return CharCaseCmp(c1, c2);
+}
+
+INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0; i < n; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
+ return CharCaseCmp(c1, c2);
+}
+
+#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp)
+#define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp)
+#else
+#define INIT_STRCASECMP
+#define INIT_STRNCASECMP
+#endif
+
+#if SANITIZER_INTERCEPT_MEMCHR
+INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
+ void *res = REAL(memchr)(s, c, n);
+ uptr len = res ? (char *)res - (const char *)s + 1 : n;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len);
+ return res;
+}
+
+#define INIT_MEMCHR COMMON_INTERCEPT_FUNCTION(memchr)
+#else
+#define INIT_MEMCHR
+#endif
+
+#if SANITIZER_INTERCEPT_MEMRCHR
+INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memrchr, s, c, n);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, n);
+ return REAL(memrchr)(s, c, n);
+}
+
+#define INIT_MEMRCHR COMMON_INTERCEPT_FUNCTION(memrchr)
+#else
+#define INIT_MEMRCHR
+#endif
+
+#if SANITIZER_INTERCEPT_FREXP
+INTERCEPTOR(double, frexp, double x, int *exp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp);
+ // Assuming frexp() always writes to |exp|.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ double res = REAL(frexp)(x, exp);
+ return res;
+}
+
+#define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp);
+#else
+#define INIT_FREXP
+#endif // SANITIZER_INTERCEPT_FREXP
+
+#if SANITIZER_INTERCEPT_FREXPF_FREXPL
+INTERCEPTOR(float, frexpf, float x, int *exp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ float res = REAL(frexpf)(x, exp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ return res;
+}
+
+INTERCEPTOR(long double, frexpl, long double x, int *exp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ long double res = REAL(frexpl)(x, exp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ return res;
+}
+
+#define INIT_FREXPF_FREXPL \
+ COMMON_INTERCEPT_FUNCTION(frexpf); \
+ COMMON_INTERCEPT_FUNCTION(frexpl)
+#else
+#define INIT_FREXPF_FREXPL
+#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
+
+#if SI_NOT_WINDOWS
+static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen);
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+#endif
+
+#if SANITIZER_INTERCEPT_READ
+INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(read)(fd, ptr, count);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_READ COMMON_INTERCEPT_FUNCTION(read)
+#else
+#define INIT_READ
+#endif
+
+#if SANITIZER_INTERCEPT_PREAD
+INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread)
+#else
+#define INIT_PREAD
+#endif
+
+#if SANITIZER_INTERCEPT_PREAD64
+INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64)
+#else
+#define INIT_PREAD64
+#endif
+
+#if SANITIZER_INTERCEPT_READV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
+ int iovcnt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(readv)(fd, iov, iovcnt);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_READV COMMON_INTERCEPT_FUNCTION(readv)
+#else
+#define INIT_READV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV
+INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv)
+#else
+#define INIT_PREADV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV64
+INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64)
+#else
+#define INIT_PREADV64
+#endif
+
+#if SANITIZER_INTERCEPT_WRITE
+INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(write)(fd, ptr, count);
+ // FIXME: this check should be _before_ the call to REAL(write), not after
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ return res;
+}
+#define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write)
+#else
+#define INIT_WRITE
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITE
+INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ return res;
+}
+#define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite)
+#else
+#define INIT_PWRITE
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITE64
+INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ return res;
+}
+#define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64)
+#else
+#define INIT_PWRITE64
+#endif
+
+#if SANITIZER_INTERCEPT_WRITEV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov,
+ int iovcnt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(writev)(fd, iov, iovcnt);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev)
+#else
+#define INIT_WRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV
+INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev)
+#else
+#define INIT_PWRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV64
+INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64)
+#else
+#define INIT_PWRITEV64
+#endif
+
+#if SANITIZER_INTERCEPT_PRCTL
+INTERCEPTOR(int, prctl, int option, unsigned long arg2,
+ unsigned long arg3, // NOLINT
+ unsigned long arg4, unsigned long arg5) { // NOLINT
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
+ static const int PR_SET_NAME = 15;
+ int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
+ if (option == PR_SET_NAME) {
+ char buff[16];
+ internal_strncpy(buff, (char *)arg2, 15);
+ buff[15] = 0;
+ COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
+ }
+ return res;
+}
+#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl)
+#else
+#define INIT_PRCTL
+#endif // SANITIZER_INTERCEPT_PRCTL
+
+#if SANITIZER_INTERCEPT_TIME
+INTERCEPTOR(unsigned long, time, unsigned long *t) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, time, t);
+ unsigned long local_t;
+ unsigned long res = REAL(time)(&local_t);
+ if (t && res != (unsigned long)-1) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t));
+ *t = local_t;
+ }
+ return res;
+}
+#define INIT_TIME COMMON_INTERCEPT_FUNCTION(time);
+#else
+#define INIT_TIME
+#endif // SANITIZER_INTERCEPT_TIME
+
+#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ if (tm->tm_zone) {
+ // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
+ // can point to shared memory and tsan would report a data race.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone,
+ REAL(strlen(tm->tm_zone)) + 1);
+ }
+}
+INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
+ __sanitizer_tm *res = REAL(localtime)(timep);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
+ __sanitizer_tm *res = REAL(localtime_r)(timep, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
+ __sanitizer_tm *res = REAL(gmtime)(timep);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
+ __sanitizer_tm *res = REAL(gmtime_r)(timep, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(char *, ctime, unsigned long *timep) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(ctime)(timep);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(ctime_r)(timep, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(asctime)(tm);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(asctime_r)(tm, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(long, mktime, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mktime, tm);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_sec, sizeof(tm->tm_sec));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_min, sizeof(tm->tm_min));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_hour, sizeof(tm->tm_hour));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mday, sizeof(tm->tm_mday));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mon, sizeof(tm->tm_mon));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_year, sizeof(tm->tm_year));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_isdst, sizeof(tm->tm_isdst));
+ long res = REAL(mktime)(tm);
+ if (res != -1) unpoison_tm(ctx, tm);
+ return res;
+}
+#define INIT_LOCALTIME_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(localtime); \
+ COMMON_INTERCEPT_FUNCTION(localtime_r); \
+ COMMON_INTERCEPT_FUNCTION(gmtime); \
+ COMMON_INTERCEPT_FUNCTION(gmtime_r); \
+ COMMON_INTERCEPT_FUNCTION(ctime); \
+ COMMON_INTERCEPT_FUNCTION(ctime_r); \
+ COMMON_INTERCEPT_FUNCTION(asctime); \
+ COMMON_INTERCEPT_FUNCTION(asctime_r); \
+ COMMON_INTERCEPT_FUNCTION(mktime);
+#else
+#define INIT_LOCALTIME_AND_FRIENDS
+#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+
+#if SANITIZER_INTERCEPT_STRPTIME
+INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm);
+ if (format)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(strptime)(s, format, tm);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
+ // Do not call unpoison_tm here, because strptime does not, in fact,
+ // initialize the entire struct tm. For example, tm_zone pointer is left
+ // uninitialized.
+ if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ }
+ return res;
+}
+#define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime);
+#else
+#define INIT_STRPTIME
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF
+#include "sanitizer_common_interceptors_format.inc"
+
+#define FORMAT_INTERCEPTOR_IMPL(name, vname, ...) \
+ { \
+ void *ctx; \
+ va_list ap; \
+ va_start(ap, format); \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \
+ int res = WRAP(vname)(__VA_ARGS__, ap); \
+ va_end(ap); \
+ return res; \
+ }
+
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF
+
+#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
+ va_list aq; \
+ va_copy(aq, ap); \
+ int res = REAL(vname)(__VA_ARGS__); \
+ if (res > 0) \
+ scanf_common(ctx, res, allowGnuMalloc, format, aq); \
+ va_end(aq); \
+ return res; \
+ }
+
+INTERCEPTOR(int, vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap)
+
+INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
+
+INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
+
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format,
+ va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
+#endif // SANITIZER_INTERCEPT_ISOC99_SCANF
+
+INTERCEPTOR(int, scanf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format)
+
+INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+
+INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+
+INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
+#endif
+
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF
+#define INIT_SCANF \
+ COMMON_INTERCEPT_FUNCTION(scanf); \
+ COMMON_INTERCEPT_FUNCTION(sscanf); \
+ COMMON_INTERCEPT_FUNCTION(fscanf); \
+ COMMON_INTERCEPT_FUNCTION(vscanf); \
+ COMMON_INTERCEPT_FUNCTION(vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(vfscanf);
+#else
+#define INIT_SCANF
+#endif
+
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+#define INIT_ISOC99_SCANF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#else
+#define INIT_ISOC99_SCANF
+#endif
+
+#if SANITIZER_INTERCEPT_PRINTF
+
+#define VPRINTF_INTERCEPTOR_ENTER(vname, ...) \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
+ va_list aq; \
+ va_copy(aq, ap);
+
+#define VPRINTF_INTERCEPTOR_RETURN() \
+ va_end(aq);
+
+#define VPRINTF_INTERCEPTOR_IMPL(vname, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__); \
+ if (common_flags()->check_printf) \
+ printf_common(ctx, format, aq); \
+ int res = REAL(vname)(__VA_ARGS__); \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// FIXME: under ASan the REAL() call below may write to freed memory and
+// corrupt its metadata. See
+// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(str, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// FIXME: under ASan the REAL() call below may write to freed memory and
+// corrupt its metadata. See
+// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(str, size, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, Min(size, (SIZE_T)(res + 1))); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// FIXME: under ASan the REAL() call below may write to freed memory and
+// corrupt its metadata. See
+// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *)); \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(strp, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+INTERCEPTOR(int, vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap)
+
+INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format,
+ va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format,
+ va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap)
+
+#if SANITIZER_INTERCEPT_PRINTF_L
+INTERCEPTOR(int, vsnprintf_l, char *str, SIZE_T size, void *loc,
+ const char *format, va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf_l, str, size, loc, format, ap)
+
+INTERCEPTOR(int, snprintf_l, char *str, SIZE_T size, void *loc,
+ const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(snprintf_l, vsnprintf_l, str, size, loc, format)
+#endif // SANITIZER_INTERCEPT_PRINTF_L
+
+INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
+
+INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
+VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream,
+ const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format,
+ va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format,
+ va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format,
+ ap)
+
+#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+INTERCEPTOR(int, printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format)
+
+INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format)
+
+INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT
+FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT
+
+INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format)
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format)
+
+INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format,
+ ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format)
+
+INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size,
+ const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
+ format)
+
+#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+#endif // SANITIZER_INTERCEPT_PRINTF
+
+#if SANITIZER_INTERCEPT_PRINTF
+#define INIT_PRINTF \
+ COMMON_INTERCEPT_FUNCTION(printf); \
+ COMMON_INTERCEPT_FUNCTION(sprintf); \
+ COMMON_INTERCEPT_FUNCTION(snprintf); \
+ COMMON_INTERCEPT_FUNCTION(asprintf); \
+ COMMON_INTERCEPT_FUNCTION(fprintf); \
+ COMMON_INTERCEPT_FUNCTION(vprintf); \
+ COMMON_INTERCEPT_FUNCTION(vsprintf); \
+ COMMON_INTERCEPT_FUNCTION(vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION(vasprintf); \
+ COMMON_INTERCEPT_FUNCTION(vfprintf);
+#else
+#define INIT_PRINTF
+#endif
+
+#if SANITIZER_INTERCEPT_PRINTF_L
+#define INIT_PRINTF_L \
+ COMMON_INTERCEPT_FUNCTION(snprintf_l); \
+ COMMON_INTERCEPT_FUNCTION(vsnprintf_l);
+#else
+#define INIT_PRINTF_L
+#endif
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+#define INIT_ISOC99_PRINTF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_printf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf);
+#else
+#define INIT_ISOC99_PRINTF
+#endif
+
+#if SANITIZER_INTERCEPT_IOCTL
+#include "sanitizer_common_interceptors_ioctl.inc"
+INTERCEPTOR(int, ioctl, int d, unsigned long request, ...) {
+ void *ctx;
+ va_list ap;
+ va_start(ap, request);
+ void *arg = va_arg(ap, void *);
+ va_end(ap);
+ COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg);
+
+ CHECK(ioctl_initialized);
+
+ // Note: TSan does not use common flags, and they are zero-initialized.
+ // This effectively disables ioctl handling in TSan.
+ if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg);
+
+ // Although request is unsigned long, the rest of the interceptor uses it
+ // as just "unsigned" to save space, because we know that all values fit in
+ // "unsigned" - they are compile-time constants.
+
+ const ioctl_desc *desc = ioctl_lookup(request);
+ ioctl_desc decoded_desc;
+ if (!desc) {
+ VPrintf(2, "Decoding unknown ioctl 0x%x\n", request);
+ if (!ioctl_decode(request, &decoded_desc))
+ Printf("WARNING: failed decoding unknown ioctl 0x%x\n", request);
+ else
+ desc = &decoded_desc;
+ }
+
+ if (desc) ioctl_common_pre(ctx, desc, d, request, arg);
+ int res = REAL(ioctl)(d, request, arg);
+ // FIXME: some ioctls have different return values for success and failure.
+ if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg);
+ return res;
+}
+#define INIT_IOCTL \
+ ioctl_init(); \
+ COMMON_INTERCEPT_FUNCTION(ioctl);
+#else
+#define INIT_IOCTL
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
+ SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || \
+ SANITIZER_INTERCEPT_GETPWENT_R || SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
+ if (pwd) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
+ if (pwd->pw_name)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_name,
+ REAL(strlen)(pwd->pw_name) + 1);
+ if (pwd->pw_passwd)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_passwd,
+ REAL(strlen)(pwd->pw_passwd) + 1);
+#if !SANITIZER_ANDROID
+ if (pwd->pw_gecos)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_gecos,
+ REAL(strlen)(pwd->pw_gecos) + 1);
+#endif
+#if SANITIZER_MAC
+ if (pwd->pw_class)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_class,
+ REAL(strlen)(pwd->pw_class) + 1);
+#endif
+ if (pwd->pw_dir)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_dir,
+ REAL(strlen)(pwd->pw_dir) + 1);
+ if (pwd->pw_shell)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_shell,
+ REAL(strlen)(pwd->pw_shell) + 1);
+ }
+}
+
+static void unpoison_group(void *ctx, __sanitizer_group *grp) {
+ if (grp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp));
+ if (grp->gr_name)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_name,
+ REAL(strlen)(grp->gr_name) + 1);
+ if (grp->gr_passwd)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_passwd,
+ REAL(strlen)(grp->gr_passwd) + 1);
+ char **p = grp->gr_mem;
+ for (; *p; ++p) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*p, REAL(strlen)(*p) + 1);
+ }
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_mem,
+ (p - grp->gr_mem + 1) * sizeof(*p));
+ }
+}
+#endif // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS ||
+ // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT ||
+ // SANITIZER_INTERCEPT_GETPWENT_R ||
+ // SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ __sanitizer_passwd *res = REAL(getpwnam)(name);
+ if (res != 0) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
+ __sanitizer_passwd *res = REAL(getpwuid)(uid);
+ if (res != 0) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ __sanitizer_group *res = REAL(getgrnam)(name);
+ if (res != 0) unpoison_group(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
+ __sanitizer_group *res = REAL(getgrgid)(gid);
+ if (res != 0) unpoison_group(ctx, res);
+ return res;
+}
+#define INIT_GETPWNAM_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid);
+#else
+#define INIT_GETPWNAM_AND_FRIENDS
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
+ char *buf, SIZE_T buflen, __sanitizer_passwd **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_passwd(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_passwd(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
+ char *buf, SIZE_T buflen, __sanitizer_group **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_group(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
+ SIZE_T buflen, __sanitizer_group **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_group(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_GETPWNAM_R_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid_r);
+#else
+#define INIT_GETPWNAM_R_AND_FRIENDS
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWENT
+INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy);
+ __sanitizer_passwd *res = REAL(getpwent)(dummy);
+ if (res != 0) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy);
+ __sanitizer_group *res = REAL(getgrent)(dummy);
+ if (res != 0) unpoison_group(ctx, res);;
+ return res;
+}
+#define INIT_GETPWENT \
+ COMMON_INTERCEPT_FUNCTION(getpwent); \
+ COMMON_INTERCEPT_FUNCTION(getgrent);
+#else
+#define INIT_GETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_FGETPWENT
+INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp);
+ __sanitizer_passwd *res = REAL(fgetpwent)(fp);
+ if (res != 0) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp);
+ __sanitizer_group *res = REAL(fgetgrent)(fp);
+ if (res != 0) unpoison_group(ctx, res);
+ return res;
+}
+#define INIT_FGETPWENT \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent); \
+ COMMON_INTERCEPT_FUNCTION(fgetgrent);
+#else
+#define INIT_FGETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWENT_R
+INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
+ __sanitizer_group **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_group **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+#define INIT_GETPWENT_R \
+ COMMON_INTERCEPT_FUNCTION(getpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrent_r); \
+ COMMON_INTERCEPT_FUNCTION(fgetgrent_r);
+#else
+#define INIT_GETPWENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_SETPWENT
+// The only thing these interceptors do is disable any nested interceptors.
+// These functions may open nss modules and call uninstrumented functions from
+// them, and we don't want things like strlen() to trigger.
+INTERCEPTOR(void, setpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setpwent, dummy);
+ REAL(setpwent)(dummy);
+}
+INTERCEPTOR(void, endpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, endpwent, dummy);
+ REAL(endpwent)(dummy);
+}
+INTERCEPTOR(void, setgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setgrent, dummy);
+ REAL(setgrent)(dummy);
+}
+INTERCEPTOR(void, endgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, endgrent, dummy);
+ REAL(endgrent)(dummy);
+}
+#define INIT_SETPWENT \
+ COMMON_INTERCEPT_FUNCTION(setpwent); \
+ COMMON_INTERCEPT_FUNCTION(endpwent); \
+ COMMON_INTERCEPT_FUNCTION(setgrent); \
+ COMMON_INTERCEPT_FUNCTION(endgrent);
+#else
+#define INIT_SETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_CLOCK_GETTIME
+INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(clock_getres)(clk_id, tp);
+ if (!res && tp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(clock_gettime)(clk_id, tp);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz);
+ return REAL(clock_settime)(clk_id, tp);
+}
+#define INIT_CLOCK_GETTIME \
+ COMMON_INTERCEPT_FUNCTION(clock_getres); \
+ COMMON_INTERCEPT_FUNCTION(clock_gettime); \
+ COMMON_INTERCEPT_FUNCTION(clock_settime);
+#else
+#define INIT_CLOCK_GETTIME
+#endif
+
+#if SANITIZER_INTERCEPT_GETITIMER
+INTERCEPTOR(int, getitimer, int which, void *curr_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getitimer)(which, curr_value);
+ if (!res && curr_value) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value);
+ if (new_value)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(setitimer)(which, new_value, old_value);
+ if (!res && old_value) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
+ }
+ return res;
+}
+#define INIT_GETITIMER \
+ COMMON_INTERCEPT_FUNCTION(getitimer); \
+ COMMON_INTERCEPT_FUNCTION(setitimer);
+#else
+#define INIT_GETITIMER
+#endif
+
+#if SANITIZER_INTERCEPT_GLOB
+static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob));
+ // +1 for NULL pointer at the end.
+ if (pglob->gl_pathv)
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv));
+ for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) {
+ char *p = pglob->gl_pathv[i];
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1);
+ }
+}
+
+static THREADLOCAL __sanitizer_glob_t *pglob_copy;
+
+static void wrapped_gl_closedir(void *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ pglob_copy->gl_closedir(dir);
+}
+
+static void *wrapped_gl_readdir(void *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ return pglob_copy->gl_readdir(dir);
+}
+
+static void *wrapped_gl_opendir(const char *s) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+ return pglob_copy->gl_opendir(s);
+}
+
+static int wrapped_gl_lstat(const char *s, void *st) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+ return pglob_copy->gl_lstat(s, st);
+}
+
+static int wrapped_gl_stat(const char *s, void *st) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+ return pglob_copy->gl_stat(s, st);
+}
+
+INTERCEPTOR(int, glob, const char *pattern, int flags,
+ int (*errfunc)(const char *epath, int eerrno),
+ __sanitizer_glob_t *pglob) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+ __sanitizer_glob_t glob_copy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ pglob_copy = &glob_copy;
+ }
+ int res = REAL(glob)(pattern, flags, errfunc, pglob);
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ }
+ pglob_copy = 0;
+ if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+ return res;
+}
+
+INTERCEPTOR(int, glob64, const char *pattern, int flags,
+ int (*errfunc)(const char *epath, int eerrno),
+ __sanitizer_glob_t *pglob) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+ __sanitizer_glob_t glob_copy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ pglob_copy = &glob_copy;
+ }
+ int res = REAL(glob64)(pattern, flags, errfunc, pglob);
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ }
+ pglob_copy = 0;
+ if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+ return res;
+}
+#define INIT_GLOB \
+ COMMON_INTERCEPT_FUNCTION(glob); \
+ COMMON_INTERCEPT_FUNCTION(glob64);
+#else // SANITIZER_INTERCEPT_GLOB
+#define INIT_GLOB
+#endif // SANITIZER_INTERCEPT_GLOB
+
+#if SANITIZER_INTERCEPT_WAIT
+// According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version
+// suffixes on Darwin. See the declaration of INTERCEPTOR_WITH_SUFFIX for
+// details.
+INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wait, status);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(wait)(status);
+ if (res != -1 && status)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ return res;
+}
+// On FreeBSD id_t is always 64-bit wide.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop,
+ int options) {
+#else
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
+ int options) {
+#endif
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(waitid)(idtype, id, infop, options);
+ if (res != -1 && infop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
+ return res;
+}
+INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(waitpid)(pid, status, options);
+ if (res != -1 && status)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ return res;
+}
+INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(wait3)(status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#if SANITIZER_ANDROID
+INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(__wait4)(pid, status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(__wait4);
+#else
+INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(wait4)(pid, status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(wait4);
+#endif // SANITIZER_ANDROID
+#define INIT_WAIT \
+ COMMON_INTERCEPT_FUNCTION(wait); \
+ COMMON_INTERCEPT_FUNCTION(waitid); \
+ COMMON_INTERCEPT_FUNCTION(waitpid); \
+ COMMON_INTERCEPT_FUNCTION(wait3);
+#else
+#define INIT_WAIT
+#define INIT_WAIT4
+#endif
+
+#if SANITIZER_INTERCEPT_INET
+INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, inet_ntop, af, src, dst, size);
+ uptr sz = __sanitizer_in_addr_sz(af);
+ if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz);
+ // FIXME: figure out read size based on the address family.
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(inet_ntop)(af, src, dst, size);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst);
+ // FIXME: figure out read size based on the address family.
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(inet_pton)(af, src, dst);
+ if (res == 1) {
+ uptr sz = __sanitizer_in_addr_sz(af);
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+ }
+ return res;
+}
+#define INIT_INET \
+ COMMON_INTERCEPT_FUNCTION(inet_ntop); \
+ COMMON_INTERCEPT_FUNCTION(inet_pton);
+#else
+#define INIT_INET
+#endif
+
+#if SANITIZER_INTERCEPT_INET
+INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, dst);
+ if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(inet_aton)(cp, dst);
+ if (res != 0) {
+ uptr sz = __sanitizer_in_addr_sz(af_inet);
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+ }
+ return res;
+}
+#define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton);
+#else
+#define INIT_INET_ATON
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM
+INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(pthread_getschedparam)(thread, policy, param);
+ if (res == 0) {
+ if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy));
+ if (param) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, sizeof(*param));
+ }
+ return res;
+}
+#define INIT_PTHREAD_GETSCHEDPARAM \
+ COMMON_INTERCEPT_FUNCTION(pthread_getschedparam);
+#else
+#define INIT_PTHREAD_GETSCHEDPARAM
+#endif
+
+#if SANITIZER_INTERCEPT_GETADDRINFO
+INTERCEPTOR(int, getaddrinfo, char *node, char *service,
+ struct __sanitizer_addrinfo *hints,
+ struct __sanitizer_addrinfo **out) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getaddrinfo, node, service, hints, out);
+ if (node) COMMON_INTERCEPTOR_READ_RANGE(ctx, node, REAL(strlen)(node) + 1);
+ if (service)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1);
+ if (hints)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getaddrinfo)(node, service, hints, out);
+ if (res == 0 && out) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
+ struct __sanitizer_addrinfo *p = *out;
+ while (p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (p->ai_addr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen);
+ if (p->ai_canonname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname,
+ REAL(strlen)(p->ai_canonname) + 1);
+ p = p->ai_next;
+ }
+ }
+ return res;
+}
+#define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo);
+#else
+#define INIT_GETADDRINFO
+#endif
+
+#if SANITIZER_INTERCEPT_GETNAMEINFO
+INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
+ unsigned hostlen, char *serv, unsigned servlen, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen,
+ serv, servlen, flags);
+ // FIXME: consider adding READ_RANGE(sockaddr, salen)
+ // There is padding in in_addr that may make this too noisy
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res =
+ REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
+ if (res == 0) {
+ if (host && hostlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, REAL(strlen)(host) + 1);
+ if (serv && servlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, REAL(strlen)(serv) + 1);
+ }
+ return res;
+}
+#define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo);
+#else
+#define INIT_GETNAMEINFO
+#endif
+
+#if SANITIZER_INTERCEPT_GETSOCKNAME
+INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ int addrlen_in = *addrlen;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getsockname)(sock_fd, addr, addrlen);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen));
+ }
+ return res;
+}
+#define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname);
+#else
+#define INIT_GETSOCKNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME || SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+static void write_hostent(void *ctx, struct __sanitizer_hostent *h) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h, sizeof(__sanitizer_hostent));
+ if (h->h_name)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h->h_name, REAL(strlen)(h->h_name) + 1);
+ char **p = h->h_aliases;
+ while (*p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+ ++p;
+ }
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, h->h_aliases, (p - h->h_aliases + 1) * sizeof(*h->h_aliases));
+ p = h->h_addr_list;
+ while (*p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, h->h_length);
+ ++p;
+ }
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, h->h_addr_list, (p - h->h_addr_list + 1) * sizeof(*h->h_addr_list));
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname, char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname, name);
+ struct __sanitizer_hostent *res = REAL(gethostbyname)(name);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len,
+ int type) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr, addr, len, type);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
+ struct __sanitizer_hostent *res = REAL(gethostbyaddr)(addr, len, type);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake);
+ struct __sanitizer_hostent *res = REAL(gethostent)(fake);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2, name, af);
+ struct __sanitizer_hostent *res = REAL(gethostbyname2)(name, af);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+#define INIT_GETHOSTBYNAME \
+ COMMON_INTERCEPT_FUNCTION(gethostent); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2);
+#else
+#define INIT_GETHOSTBYNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
+ char *buf, SIZE_T buflen, __sanitizer_hostent **result,
+ int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result,
+ h_errnop);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYNAME_R COMMON_INTERCEPT_FUNCTION(gethostbyname_r);
+#else
+#define INIT_GETHOSTBYNAME_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTENT_R
+INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf,
+ SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, result,
+ h_errnop);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTENT_R \
+ COMMON_INTERCEPT_FUNCTION(gethostent_r);
+#else
+#define INIT_GETHOSTENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYADDR_R
+INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
+ struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
+ __sanitizer_hostent **result, int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf,
+ buflen, result, h_errnop);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
+ h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYADDR_R \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r);
+#else
+#define INIT_GETHOSTBYADDR_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME2_R
+INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
+ struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
+ __sanitizer_hostent **result, int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen,
+ result, h_errnop);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res =
+ REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYNAME2_R \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2_r);
+#else
+#define INIT_GETHOSTBYNAME2_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETSOCKOPT
+INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
+ int *optlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval,
+ optlen);
+ if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen);
+ if (res == 0)
+ if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
+ return res;
+}
+#define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt);
+#else
+#define INIT_GETSOCKOPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT
+INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen);
+ unsigned addrlen0 = 0;
+ if (addrlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ addrlen0 = *addrlen;
+ }
+ int fd2 = REAL(accept)(fd, addr, addrlen);
+ if (fd2 >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+ }
+ return fd2;
+}
+#define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept);
+#else
+#define INIT_ACCEPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT4
+INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f);
+ unsigned addrlen0 = 0;
+ if (addrlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ addrlen0 = *addrlen;
+ }
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int fd2 = REAL(accept4)(fd, addr, addrlen, f);
+ if (fd2 >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+ }
+ return fd2;
+}
+#define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4);
+#else
+#define INIT_ACCEPT4
+#endif
+
+#if SANITIZER_INTERCEPT_MODF
+INTERCEPTOR(double, modf, double x, double *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ double res = REAL(modf)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+INTERCEPTOR(float, modff, float x, float *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ float res = REAL(modff)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ long double res = REAL(modfl)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+#define INIT_MODF \
+ COMMON_INTERCEPT_FUNCTION(modf); \
+ COMMON_INTERCEPT_FUNCTION(modff); \
+ COMMON_INTERCEPT_FUNCTION(modfl);
+#else
+#define INIT_MODF
+#endif
+
+#if SANITIZER_INTERCEPT_RECVMSG
+static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,
+ SSIZE_T maxlen) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg));
+ if (msg->msg_name && msg->msg_namelen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen);
+ if (msg->msg_iov && msg->msg_iovlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov,
+ sizeof(*msg->msg_iov) * msg->msg_iovlen);
+ write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen);
+ if (msg->msg_control && msg->msg_controllen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen);
+}
+
+INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
+ int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
+ if (res >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ if (msg) {
+ write_msghdr(ctx, msg, res);
+ COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg);
+ }
+ }
+ return res;
+}
+#define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg);
+#else
+#define INIT_RECVMSG
+#endif
+
+#if SANITIZER_INTERCEPT_GETPEERNAME
+INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen);
+ unsigned addr_sz;
+ if (addrlen) addr_sz = *addrlen;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getpeername)(sockfd, addr, addrlen);
+ if (!res && addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
+ return res;
+}
+#define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername);
+#else
+#define INIT_GETPEERNAME
+#endif
+
+#if SANITIZER_INTERCEPT_SYSINFO
+INTERCEPTOR(int, sysinfo, void *info) {
+ void *ctx;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
+ int res = REAL(sysinfo)(info);
+ if (!res && info)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz);
+ return res;
+}
+#define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo);
+#else
+#define INIT_SYSINFO
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR
+INTERCEPTOR(__sanitizer_dirent *, opendir, const char *path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, opendir, path);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ __sanitizer_dirent *res = REAL(opendir)(path);
+ if (res != 0)
+ COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path);
+ return res;
+}
+
+INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_dirent *res = REAL(readdir)(dirp);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ return res;
+}
+
+INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
+ __sanitizer_dirent **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(readdir_r)(dirp, entry, result);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (*result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+ }
+ return res;
+}
+
+#define INIT_READDIR \
+ COMMON_INTERCEPT_FUNCTION(opendir); \
+ COMMON_INTERCEPT_FUNCTION(readdir); \
+ COMMON_INTERCEPT_FUNCTION(readdir_r);
+#else
+#define INIT_READDIR
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR64
+INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_dirent64 *res = REAL(readdir64)(dirp);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ return res;
+}
+
+INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
+ __sanitizer_dirent64 **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(readdir64_r)(dirp, entry, result);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (*result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+ }
+ return res;
+}
+#define INIT_READDIR64 \
+ COMMON_INTERCEPT_FUNCTION(readdir64); \
+ COMMON_INTERCEPT_FUNCTION(readdir64_r);
+#else
+#define INIT_READDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_PTRACE
+INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
+
+ if (data) {
+ if (request == ptrace_setregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz);
+ else if (request == ptrace_setfpregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+ else if (request == ptrace_setfpxregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_setsiginfo)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
+ else if (request == ptrace_setregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len);
+ }
+ }
+
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ uptr res = REAL(ptrace)(request, pid, addr, data);
+
+ if (!res && data) {
+ // Note that PEEK* requests assign different meaning to the return value.
+ // This function does not handle them (nor does it need to).
+ if (request == ptrace_getregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz);
+ else if (request == ptrace_getfpregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+ else if (request == ptrace_getfpxregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_getsiginfo)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
+ else if (request == ptrace_geteventmsg)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long));
+ else if (request == ptrace_getregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len);
+ }
+ }
+ return res;
+}
+
+#define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace);
+#else
+#define INIT_PTRACE
+#endif
+
+#if SANITIZER_INTERCEPT_SETLOCALE
+INTERCEPTOR(char *, setlocale, int category, char *locale) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale);
+ if (locale)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);
+ char *res = REAL(setlocale)(category, locale);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+#define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale);
+#else
+#define INIT_SETLOCALE
+#endif
+
+#if SANITIZER_INTERCEPT_GETCWD
+INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(getcwd)(buf, size);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd);
+#else
+#define INIT_GETCWD
+#endif
+
+#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
+INTERCEPTOR(char *, get_current_dir_name, int fake) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(get_current_dir_name)(fake);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+#define INIT_GET_CURRENT_DIR_NAME \
+ COMMON_INTERCEPT_FUNCTION(get_current_dir_name);
+#else
+#define INIT_GET_CURRENT_DIR_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_STRTOIMAX
+INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
+ if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ return res;
+}
+
+INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
+ if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ return res;
+}
+
+#define INIT_STRTOIMAX \
+ COMMON_INTERCEPT_FUNCTION(strtoimax); \
+ COMMON_INTERCEPT_FUNCTION(strtoumax);
+#else
+#define INIT_STRTOIMAX
+#endif
+
+#if SANITIZER_INTERCEPT_MBSTOWCS
+INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(mbstowcs)(dest, src, len);
+ if (res != (SIZE_T) - 1 && dest) {
+ SIZE_T write_cnt = res + (res < len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
+ void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps);
+ if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
+ if (res != (SIZE_T)(-1) && dest && src) {
+ // This function, and several others, may or may not write the terminating
+ // \0 character. They write it iff they clear *src.
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+#define INIT_MBSTOWCS \
+ COMMON_INTERCEPT_FUNCTION(mbstowcs); \
+ COMMON_INTERCEPT_FUNCTION(mbsrtowcs);
+#else
+#define INIT_MBSTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_MBSNRTOWCS
+INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
+ SIZE_T len, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps);
+ if (src) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+ }
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
+ if (res != (SIZE_T)(-1) && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+#define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs);
+#else
+#define INIT_MBSNRTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSTOMBS
+INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(wcstombs)(dest, src, len);
+ if (res != (SIZE_T) - 1 && dest) {
+ SIZE_T write_cnt = res + (res < len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
+ void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps);
+ if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
+ if (res != (SIZE_T) - 1 && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCSTOMBS \
+ COMMON_INTERCEPT_FUNCTION(wcstombs); \
+ COMMON_INTERCEPT_FUNCTION(wcsrtombs);
+#else
+#define INIT_WCSTOMBS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSNRTOMBS
+INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
+ SIZE_T len, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps);
+ if (src) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+ }
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
+ if (res != (SIZE_T) - 1 && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs);
+#else
+#define INIT_WCSNRTOMBS
+#endif
+
+#if SANITIZER_INTERCEPT_TCGETATTR
+INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(tcgetattr)(fd, termios_p);
+ if (!res && termios_p)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
+ return res;
+}
+
+#define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr);
+#else
+#define INIT_TCGETATTR
+#endif
+
+#if SANITIZER_INTERCEPT_REALPATH
+INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+
+ // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest
+ // version of a versioned symbol. For realpath(), this gives us something
+ // (called __old_realpath) that does not handle NULL in the second argument.
+ // Handle it as part of the interceptor.
+ char *allocated_path = 0;
+ if (!resolved_path)
+ allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
+
+ char *res = REAL(realpath)(path, resolved_path);
+ if (allocated_path && !res) WRAP(free)(allocated_path);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath);
+#else
+#define INIT_REALPATH
+#endif
+
+#if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME
+INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ char *res = REAL(canonicalize_file_name)(path);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_CANONICALIZE_FILE_NAME \
+ COMMON_INTERCEPT_FUNCTION(canonicalize_file_name);
+#else
+#define INIT_CANONICALIZE_FILE_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_CONFSTR
+INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(confstr)(name, buf, len);
+ if (buf && res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
+ return res;
+}
+#define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr);
+#else
+#define INIT_CONFSTR
+#endif
+
+#if SANITIZER_INTERCEPT_SCHED_GETAFFINITY
+INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
+ if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
+ return res;
+}
+#define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity);
+#else
+#define INIT_SCHED_GETAFFINITY
+#endif
+
+#if SANITIZER_INTERCEPT_SCHED_GETPARAM
+INTERCEPTOR(int, sched_getparam, int pid, void *param) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sched_getparam, pid, param);
+ int res = REAL(sched_getparam)(pid, param);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, struct_sched_param_sz);
+ return res;
+}
+#define INIT_SCHED_GETPARAM COMMON_INTERCEPT_FUNCTION(sched_getparam);
+#else
+#define INIT_SCHED_GETPARAM
+#endif
+
+#if SANITIZER_INTERCEPT_STRERROR
+INTERCEPTOR(char *, strerror, int errnum) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum);
+ char *res = REAL(strerror)(errnum);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror);
+#else
+#define INIT_STRERROR
+#endif
+
+#if SANITIZER_INTERCEPT_STRERROR_R
+INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(strerror_r)(errnum, buf, buflen);
+ // There are 2 versions of strerror_r:
+ // * POSIX version returns 0 on success, negative error code on failure,
+ // writes message to buf.
+ // * GNU version returns message pointer, which points to either buf or some
+ // static storage.
+ SIZE_T posix_res = (SIZE_T)res;
+ if (posix_res < 1024 || posix_res > (SIZE_T) - 1024) {
+ // POSIX version. Spec is not clear on whether buf is NULL-terminated.
+ // At least on OSX, buf contents are valid even when the call fails.
+ SIZE_T sz = internal_strnlen(buf, buflen);
+ if (sz < buflen) ++sz;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ } else {
+ // GNU version.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r);
+#else
+#define INIT_STRERROR_R
+#endif
+
+#if SANITIZER_INTERCEPT_XPG_STRERROR_R
+INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
+ // This version always returns a null-terminated string.
+ if (buf && buflen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ return res;
+}
+#define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r);
+#else
+#define INIT_XPG_STRERROR_R
+#endif
+
+#if SANITIZER_INTERCEPT_SCANDIR
+typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *);
+typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **,
+ const struct __sanitizer_dirent **);
+
+static THREADLOCAL scandir_filter_f scandir_filter;
+static THREADLOCAL scandir_compar_f scandir_compar;
+
+static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
+ return scandir_filter(dir);
+}
+
+static int wrapped_scandir_compar(const struct __sanitizer_dirent **a,
+ const struct __sanitizer_dirent **b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
+ return scandir_compar(a, b);
+}
+
+INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
+ scandir_filter_f filter, scandir_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar);
+ if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
+ scandir_filter = filter;
+ scandir_compar = compar;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(scandir)(dirp, namelist, filter ? wrapped_scandir_filter : 0,
+ compar ? wrapped_scandir_compar : 0);
+ scandir_filter = 0;
+ scandir_compar = 0;
+ if (namelist && res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ (*namelist)[i]->d_reclen);
+ }
+ return res;
+}
+#define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir);
+#else
+#define INIT_SCANDIR
+#endif
+
+#if SANITIZER_INTERCEPT_SCANDIR64
+typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *);
+typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **,
+ const struct __sanitizer_dirent64 **);
+
+static THREADLOCAL scandir64_filter_f scandir64_filter;
+static THREADLOCAL scandir64_compar_f scandir64_compar;
+
+static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
+ return scandir64_filter(dir);
+}
+
+static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a,
+ const struct __sanitizer_dirent64 **b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
+ return scandir64_compar(a, b);
+}
+
+INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
+ scandir64_filter_f filter, scandir64_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar);
+ if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
+ scandir64_filter = filter;
+ scandir64_compar = compar;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res =
+ REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0,
+ compar ? wrapped_scandir64_compar : 0);
+ scandir64_filter = 0;
+ scandir64_compar = 0;
+ if (namelist && res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ (*namelist)[i]->d_reclen);
+ }
+ return res;
+}
+#define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64);
+#else
+#define INIT_SCANDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_GETGROUPS
+INTERCEPTOR(int, getgroups, int size, u32 *lst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getgroups)(size, lst);
+ if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
+ return res;
+}
+#define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups);
+#else
+#define INIT_GETGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_POLL
+static void read_pollfd(void *ctx, __sanitizer_pollfd *fds,
+ __sanitizer_nfds_t nfds) {
+ for (unsigned i = 0; i < nfds; ++i) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].fd, sizeof(fds[i].fd));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].events, sizeof(fds[i].events));
+ }
+}
+
+static void write_pollfd(void *ctx, __sanitizer_pollfd *fds,
+ __sanitizer_nfds_t nfds) {
+ for (unsigned i = 0; i < nfds; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &fds[i].revents,
+ sizeof(fds[i].revents));
+}
+
+INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+ int timeout) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, poll, fds, nfds, timeout);
+ if (fds && nfds) read_pollfd(ctx, fds, nfds);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout);
+ if (fds && nfds) write_pollfd(ctx, fds, nfds);
+ return res;
+}
+#define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll);
+#else
+#define INIT_POLL
+#endif
+
+#if SANITIZER_INTERCEPT_PPOLL
+INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+ void *timeout_ts, __sanitizer_sigset_t *sigmask) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ppoll, fds, nfds, timeout_ts, sigmask);
+ if (fds && nfds) read_pollfd(ctx, fds, nfds);
+ if (timeout_ts)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz);
+ // FIXME: read sigmask when all of sigemptyset, etc are intercepted.
+ int res =
+ COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask);
+ if (fds && nfds) write_pollfd(ctx, fds, nfds);
+ return res;
+}
+#define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll);
+#else
+#define INIT_PPOLL
+#endif
+
+#if SANITIZER_INTERCEPT_WORDEXP
+INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, flags);
+ if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(wordexp)(s, p, flags);
+ if (!res && p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (p->we_wordc)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->we_wordv,
+ sizeof(*p->we_wordv) * p->we_wordc);
+ for (uptr i = 0; i < p->we_wordc; ++i) {
+ char *w = p->we_wordv[i];
+ if (w) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, w, REAL(strlen)(w) + 1);
+ }
+ }
+ return res;
+}
+#define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp);
+#else
+#define INIT_WORDEXP
+#endif
+
+#if SANITIZER_INTERCEPT_SIGWAIT
+INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigwait)(set, sig);
+ if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
+ return res;
+}
+#define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait);
+#else
+#define INIT_SIGWAIT
+#endif
+
+#if SANITIZER_INTERCEPT_SIGWAITINFO
+INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigwaitinfo)(set, info);
+ if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+ return res;
+}
+#define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo);
+#else
+#define INIT_SIGWAITINFO
+#endif
+
+#if SANITIZER_INTERCEPT_SIGTIMEDWAIT
+INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
+ void *timeout) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout);
+ if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigtimedwait)(set, info, timeout);
+ if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+ return res;
+}
+#define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait);
+#else
+#define INIT_SIGTIMEDWAIT
+#endif
+
+#if SANITIZER_INTERCEPT_SIGSETOPS
+INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigemptyset)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+
+INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigfillset)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+#define INIT_SIGSETOPS \
+ COMMON_INTERCEPT_FUNCTION(sigemptyset); \
+ COMMON_INTERCEPT_FUNCTION(sigfillset);
+#else
+#define INIT_SIGSETOPS
+#endif
+
+#if SANITIZER_INTERCEPT_SIGPENDING
+INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigpending)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+#define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending);
+#else
+#define INIT_SIGPENDING
+#endif
+
+#if SANITIZER_INTERCEPT_SIGPROCMASK
+INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(sigprocmask)(how, set, oldset);
+ if (!res && oldset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+ return res;
+}
+#define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask);
+#else
+#define INIT_SIGPROCMASK
+#endif
+
+#if SANITIZER_INTERCEPT_BACKTRACE
+INTERCEPTOR(int, backtrace, void **buffer, int size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(backtrace)(buffer, size);
+ if (res && buffer)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
+ return res;
+}
+
+INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size);
+ if (buffer && size)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char **res = REAL(backtrace_symbols)(buffer, size);
+ if (res && size) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
+ for (int i = 0; i < size; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res[i], REAL(strlen(res[i])) + 1);
+ }
+ return res;
+}
+#define INIT_BACKTRACE \
+ COMMON_INTERCEPT_FUNCTION(backtrace); \
+ COMMON_INTERCEPT_FUNCTION(backtrace_symbols);
+#else
+#define INIT_BACKTRACE
+#endif
+
+#if SANITIZER_INTERCEPT__EXIT
+INTERCEPTOR(void, _exit, int status) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _exit, status);
+ int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx);
+ if (status == 0) status = status1;
+ REAL(_exit)(status);
+}
+#define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit);
+#else
+#define INIT__EXIT
+#endif
+
+#if SANITIZER_INTERCEPT_PHTREAD_MUTEX
+INTERCEPTOR(int, pthread_mutex_lock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
+ int res = REAL(pthread_mutex_lock)(m);
+ if (res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
+ if (res == 0 || res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m);
+ COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
+ return REAL(pthread_mutex_unlock)(m);
+}
+
+#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock)
+#define INIT_PTHREAD_MUTEX_UNLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock)
+#else
+#define INIT_PTHREAD_MUTEX_LOCK
+#define INIT_PTHREAD_MUTEX_UNLOCK
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R
+static void write_mntent(void *ctx, __sanitizer_mntent *mnt) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt));
+ if (mnt->mnt_fsname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname,
+ REAL(strlen)(mnt->mnt_fsname) + 1);
+ if (mnt->mnt_dir)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir,
+ REAL(strlen)(mnt->mnt_dir) + 1);
+ if (mnt->mnt_type)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type,
+ REAL(strlen)(mnt->mnt_type) + 1);
+ if (mnt->mnt_opts)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts,
+ REAL(strlen)(mnt->mnt_opts) + 1);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT
+INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp);
+ __sanitizer_mntent *res = REAL(getmntent)(fp);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent);
+#else
+#define INIT_GETMNTENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT_R
+INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp,
+ __sanitizer_mntent *mntbuf, char *buf, int buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen);
+ __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r);
+#else
+#define INIT_GETMNTENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS
+INTERCEPTOR(int, statfs, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(statfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(fstatfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+#define INIT_STATFS \
+ COMMON_INTERCEPT_FUNCTION(statfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs);
+#else
+#define INIT_STATFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS64
+INTERCEPTOR(int, statfs64, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(statfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(fstatfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+#define INIT_STATFS64 \
+ COMMON_INTERCEPT_FUNCTION(statfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs64);
+#else
+#define INIT_STATFS64
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS
+INTERCEPTOR(int, statvfs, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(statvfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(fstatvfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+#define INIT_STATVFS \
+ COMMON_INTERCEPT_FUNCTION(statvfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs);
+#else
+#define INIT_STATVFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS64
+INTERCEPTOR(int, statvfs64, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(statvfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(fstatvfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+#define INIT_STATVFS64 \
+ COMMON_INTERCEPT_FUNCTION(statvfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs64);
+#else
+#define INIT_STATVFS64
+#endif
+
+#if SANITIZER_INTERCEPT_INITGROUPS
+INTERCEPTOR(int, initgroups, char *user, u32 group) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group);
+ if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, REAL(strlen)(user) + 1);
+ int res = REAL(initgroups)(user, group);
+ return res;
+}
+#define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups);
+#else
+#define INIT_INITGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_NTOA_ATON
+INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ char *res = REAL(ether_ntoa)(addr);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ __sanitizer_ether_addr *res = REAL(ether_aton)(buf);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res));
+ return res;
+}
+#define INIT_ETHER_NTOA_ATON \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton);
+#else
+#define INIT_ETHER_NTOA_ATON
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_HOST
+INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, addr);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(ether_ntohost)(hostname, addr);
+ if (!res && hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ return res;
+}
+INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr);
+ if (hostname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(ether_hostton)(hostname, addr);
+ if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ return res;
+}
+INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
+ char *hostname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname);
+ if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(ether_line)(line, addr, hostname);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ }
+ return res;
+}
+#define INIT_ETHER_HOST \
+ COMMON_INTERCEPT_FUNCTION(ether_ntohost); \
+ COMMON_INTERCEPT_FUNCTION(ether_hostton); \
+ COMMON_INTERCEPT_FUNCTION(ether_line);
+#else
+#define INIT_ETHER_HOST
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_R
+INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, buf);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(ether_ntoa_r)(addr, buf);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
+ __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
+ return res;
+}
+#define INIT_ETHER_R \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton_r);
+#else
+#define INIT_ETHER_R
+#endif
+
+#if SANITIZER_INTERCEPT_SHMCTL
+INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(shmctl)(shmid, cmd, buf);
+ if (res >= 0) {
+ unsigned sz = 0;
+ if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat)
+ sz = sizeof(__sanitizer_shmid_ds);
+ else if (cmd == shmctl_ipc_info)
+ sz = struct_shminfo_sz;
+ else if (cmd == shmctl_shm_info)
+ sz = struct_shm_info_sz;
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ }
+ return res;
+}
+#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl);
+#else
+#define INIT_SHMCTL
+#endif
+
+#if SANITIZER_INTERCEPT_RANDOM_R
+INTERCEPTOR(int, random_r, void *buf, u32 *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(random_r)(buf, result);
+ if (!res && result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r);
+#else
+#define INIT_RANDOM_R
+#endif
+
+// FIXME: under ASan the REAL() call below may write to freed memory and corrupt
+// its metadata. See
+// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \
+ SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GET
+#define INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(fn, sz) \
+ INTERCEPTOR(int, fn, void *attr, void *r) { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, fn, attr, r); \
+ int res = REAL(fn)(attr, r); \
+ if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \
+ return res; \
+ }
+#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_attr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_MUTEXATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_mutexattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_rwlockattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_CONDATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_condattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_BARRIERATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_barrierattr_get##what, sz)
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET
+INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T))
+INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz)
+INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T))
+INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(pthread_attr_getstack)(attr, addr, size);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size));
+ }
+ return res;
+}
+
+// We may need to call the real pthread_attr_getstack from the run-time
+// in sanitizer_common, but we don't want to include the interception headers
+// there. So, just define this function here.
+namespace __sanitizer {
+extern "C" {
+int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {
+ return REAL(pthread_attr_getstack)(attr, addr, size);
+}
+} // extern "C"
+} // namespace __sanitizer
+
+#define INIT_PTHREAD_ATTR_GET \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack);
+#else
+#define INIT_PTHREAD_ATTR_GET
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED
+INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int))
+
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched);
+#else
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP
+INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
+ void *cpuset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize,
+ cpuset);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
+ if (!res && cpusetsize && cpuset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
+ return res;
+}
+
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np);
+#else
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getpshared);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(type, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETTYPE \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_gettype);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETTYPE
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(protocol, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprotocol);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(prioceiling, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprioceiling);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust_np, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust_np);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getpshared);
+#else
+#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP
+INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(kind_np, sizeof(int))
+#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getkind_np);
+#else
+#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_CONDATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_CONDATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_condattr_getpshared);
+#else
+#define INIT_PTHREAD_CONDATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK
+INTERCEPTOR_PTHREAD_CONDATTR_GET(clock, sizeof(int))
+#define INIT_PTHREAD_CONDATTR_GETCLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_condattr_getclock);
+#else
+#define INIT_PTHREAD_CONDATTR_GETCLOCK
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_BARRIERATTR_GET(pshared, sizeof(int)) // !mac !android
+#define INIT_PTHREAD_BARRIERATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_barrierattr_getpshared);
+#else
+#define INIT_PTHREAD_BARRIERATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM
+INTERCEPTOR(char *, tmpnam, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s);
+ char *res = REAL(tmpnam)(s);
+ if (res) {
+ if (s)
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ else
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam);
+#else
+#define INIT_TMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM_R
+INTERCEPTOR(char *, tmpnam_r, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(tmpnam_r)(s);
+ if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ return res;
+}
+#define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r);
+#else
+#define INIT_TMPNAM_R
+#endif
+
+#if SANITIZER_INTERCEPT_TEMPNAM
+INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, pfx);
+ if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1);
+ if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1);
+ char *res = REAL(tempnam)(dir, pfx);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam);
+#else
+#define INIT_TEMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP
+INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+ COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
+ return REAL(pthread_setname_np)(thread, name);
+}
+#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np);
+#else
+#define INIT_PTHREAD_SETNAME_NP
+#endif
+
+#if SANITIZER_INTERCEPT_SINCOS
+INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ REAL(sincos)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ REAL(sincosf)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ REAL(sincosl)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+#define INIT_SINCOS \
+ COMMON_INTERCEPT_FUNCTION(sincos); \
+ COMMON_INTERCEPT_FUNCTION(sincosf); \
+ COMMON_INTERCEPT_FUNCTION(sincosl);
+#else
+#define INIT_SINCOS
+#endif
+
+#if SANITIZER_INTERCEPT_REMQUO
+INTERCEPTOR(double, remquo, double x, double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ double res = REAL(remquo)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(float, remquof, float x, float y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ float res = REAL(remquof)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ long double res = REAL(remquol)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+#define INIT_REMQUO \
+ COMMON_INTERCEPT_FUNCTION(remquo); \
+ COMMON_INTERCEPT_FUNCTION(remquof); \
+ COMMON_INTERCEPT_FUNCTION(remquol);
+#else
+#define INIT_REMQUO
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA
+extern int signgam;
+INTERCEPTOR(double, lgamma, double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x);
+ double res = REAL(lgamma)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(float, lgammaf, float x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x);
+ float res = REAL(lgammaf)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(long double, lgammal, long double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x);
+ long double res = REAL(lgammal)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+#define INIT_LGAMMA \
+ COMMON_INTERCEPT_FUNCTION(lgamma); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf); \
+ COMMON_INTERCEPT_FUNCTION(lgammal);
+#else
+#define INIT_LGAMMA
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA_R
+INTERCEPTOR(double, lgamma_r, double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ double res = REAL(lgamma_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ float res = REAL(lgammaf_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+#define INIT_LGAMMA_R \
+ COMMON_INTERCEPT_FUNCTION(lgamma_r); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf_r);
+#else
+#define INIT_LGAMMA_R
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMAL_R
+INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ long double res = REAL(lgammal_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION(lgammal_r);
+#else
+#define INIT_LGAMMAL_R
+#endif
+
+#if SANITIZER_INTERCEPT_DRAND48_R
+INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(drand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(lrand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_DRAND48_R \
+ COMMON_INTERCEPT_FUNCTION(drand48_r); \
+ COMMON_INTERCEPT_FUNCTION(lrand48_r);
+#else
+#define INIT_DRAND48_R
+#endif
+
+#if SANITIZER_INTERCEPT_RAND_R
+INTERCEPTOR(int, rand_r, unsigned *seedp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, rand_r, seedp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, seedp, sizeof(*seedp));
+ return REAL(rand_r)(seedp);
+}
+#define INIT_RAND_R COMMON_INTERCEPT_FUNCTION(rand_r);
+#else
+#define INIT_RAND_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETLINE
+INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(getline)(lineptr, n, stream);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+INTERCEPTOR(SSIZE_T, __getdelim, char **lineptr, SIZE_T *n, int delim,
+ void *stream) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __getdelim, lineptr, n, delim, stream);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(__getdelim)(lineptr, n, delim, stream);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim,
+ void *stream) {
+ return __getdelim(lineptr, n, delim, stream);
+}
+#define INIT_GETLINE \
+ COMMON_INTERCEPT_FUNCTION(getline); \
+ COMMON_INTERCEPT_FUNCTION(__getdelim); \
+ COMMON_INTERCEPT_FUNCTION(getdelim);
+#else
+#define INIT_GETLINE
+#endif
+
+#if SANITIZER_INTERCEPT_ICONV
+INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
+ char **outbuf, SIZE_T *outbytesleft) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf,
+ outbytesleft);
+ if (inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft));
+ if (inbuf && inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft);
+ if (outbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft));
+ void *outbuf_orig = outbuf ? *outbuf : 0;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
+ if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
+ SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz);
+ }
+ return res;
+}
+#define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv);
+#else
+#define INIT_ICONV
+#endif
+
+#if SANITIZER_INTERCEPT_TIMES
+INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, times, tms);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_clock_t res = REAL(times)(tms);
+ if (res != (__sanitizer_clock_t)-1 && tms)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
+ return res;
+}
+#define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times);
+#else
+#define INIT_TIMES
+#endif
+
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr)
+// If you see any crashes around this functions, there are 2 known issues with
+// it: 1. __tls_get_addr can be called with mis-aligned stack due to:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
+// 2. It can be called recursively if sanitizer code uses __tls_get_addr
+// to access thread local variables (it should not happen normally,
+// because sanitizers use initial-exec tls model).
+INTERCEPTOR(void *, __tls_get_addr, void *arg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg);
+ void *res = REAL(__tls_get_addr)(arg);
+ DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res);
+ if (dtv) {
+ // New DTLS block has been allocated.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size);
+ }
+ return res;
+}
+#else
+#define INIT_TLS_GET_ADDR
+#endif
+
+#if SANITIZER_INTERCEPT_LISTXATTR
+INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, size);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(listxattr)(path, list, size);
+ // Here and below, size == 0 is a special case where nothing is written to the
+ // buffer, and res contains the desired buffer size.
+ if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, size);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(llistxattr)(path, list, size);
+ if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(flistxattr)(fd, list, size);
+ if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+ return res;
+}
+#define INIT_LISTXATTR \
+ COMMON_INTERCEPT_FUNCTION(listxattr); \
+ COMMON_INTERCEPT_FUNCTION(llistxattr); \
+ COMMON_INTERCEPT_FUNCTION(flistxattr);
+#else
+#define INIT_LISTXATTR
+#endif
+
+#if SANITIZER_INTERCEPT_GETXATTR
+INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(getxattr)(path, name, value, size);
+ if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(lgetxattr)(path, name, value, size);
+ if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size);
+ if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ SSIZE_T res = REAL(fgetxattr)(fd, name, value, size);
+ if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+ return res;
+}
+#define INIT_GETXATTR \
+ COMMON_INTERCEPT_FUNCTION(getxattr); \
+ COMMON_INTERCEPT_FUNCTION(lgetxattr); \
+ COMMON_INTERCEPT_FUNCTION(fgetxattr);
+#else
+#define INIT_GETXATTR
+#endif
+
+#if SANITIZER_INTERCEPT_GETRESID
+INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getresuid)(ruid, euid, suid);
+ if (res >= 0) {
+ if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz);
+ if (euid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, euid, uid_t_sz);
+ if (suid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, suid, uid_t_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getresgid)(rgid, egid, sgid);
+ if (res >= 0) {
+ if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz);
+ if (egid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, egid, gid_t_sz);
+ if (sgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sgid, gid_t_sz);
+ }
+ return res;
+}
+#define INIT_GETRESID \
+ COMMON_INTERCEPT_FUNCTION(getresuid); \
+ COMMON_INTERCEPT_FUNCTION(getresgid);
+#else
+#define INIT_GETRESID
+#endif
+
+#if SANITIZER_INTERCEPT_GETIFADDRS
+// As long as getifaddrs()/freeifaddrs() use calloc()/free(), we don't need to
+// intercept freeifaddrs(). If that ceases to be the case, we might need to
+// intercept it to poison the memory again.
+INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(getifaddrs)(ifap);
+ if (res == 0 && ifap) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *));
+ __sanitizer_ifaddrs *p = *ifap;
+ while (p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_ifaddrs));
+ if (p->ifa_name)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_name,
+ REAL(strlen)(p->ifa_name) + 1);
+ if (p->ifa_addr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_addr, struct_sockaddr_sz);
+ if (p->ifa_netmask)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_netmask, struct_sockaddr_sz);
+ // On Linux this is a union, but the other member also points to a
+ // struct sockaddr, so the following is sufficient.
+ if (p->ifa_dstaddr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_dstaddr, struct_sockaddr_sz);
+ // FIXME(smatveev): Unpoison p->ifa_data as well.
+ p = p->ifa_next;
+ }
+ }
+ return res;
+}
+#define INIT_GETIFADDRS \
+ COMMON_INTERCEPT_FUNCTION(getifaddrs);
+#else
+#define INIT_GETIFADDRS
+#endif
+
+#if SANITIZER_INTERCEPT_IF_INDEXTONAME
+INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ char *res = REAL(if_indextoname)(ifindex, ifname);
+ if (res && ifname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
+ return res;
+}
+INTERCEPTOR(unsigned int, if_nametoindex, const char* ifname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, if_nametoindex, ifname);
+ if (ifname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
+ return REAL(if_nametoindex)(ifname);
+}
+#define INIT_IF_INDEXTONAME \
+ COMMON_INTERCEPT_FUNCTION(if_indextoname); \
+ COMMON_INTERCEPT_FUNCTION(if_nametoindex);
+#else
+#define INIT_IF_INDEXTONAME
+#endif
+
+#if SANITIZER_INTERCEPT_CAPGET
+INTERCEPTOR(int, capget, void *hdrp, void *datap) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, capget, hdrp, datap);
+ if (hdrp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(capget)(hdrp, datap);
+ if (res == 0 && datap)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz);
+ // We can also return -1 and write to hdrp->version if the version passed in
+ // hdrp->version is unsupported. But that's not a trivial condition to check,
+ // and anyway COMMON_INTERCEPTOR_READ_RANGE protects us to some extent.
+ return res;
+}
+INTERCEPTOR(int, capset, void *hdrp, const void *datap) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, capset, hdrp, datap);
+ if (hdrp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
+ if (datap)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, __user_cap_data_struct_sz);
+ return REAL(capset)(hdrp, datap);
+}
+#define INIT_CAPGET \
+ COMMON_INTERCEPT_FUNCTION(capget); \
+ COMMON_INTERCEPT_FUNCTION(capset);
+#else
+#define INIT_CAPGET
+#endif
+
+#if SANITIZER_INTERCEPT_AEABI_MEM
+DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr);
+DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr);
+DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
+
+INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) {
+ return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) {
+ return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) {
+ return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) {
+ return WRAP(memcpy)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) {
+ return WRAP(memcpy)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) {
+ return WRAP(memcpy)(to, from, size);
+}
+// Note the argument order.
+INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) {
+ return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) {
+ return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) {
+ return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+#define INIT_AEABI_MEM \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memmove); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memmove8); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy8); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memset); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memset4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memset8); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memclr); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memclr4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memclr8);
+#else
+#define INIT_AEABI_MEM
+#endif // SANITIZER_INTERCEPT_AEABI_MEM
+
+#if SANITIZER_INTERCEPT___BZERO
+DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
+
+INTERCEPTOR(void *, __bzero, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+#define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero);
+#else
+#define INIT___BZERO
+#endif // SANITIZER_INTERCEPT___BZERO
+
+#if SANITIZER_INTERCEPT_FTIME
+INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(ftime)(tp);
+ if (tp)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp));
+ return res;
+}
+#define INIT_FTIME COMMON_INTERCEPT_FUNCTION(ftime);
+#else
+#define INIT_FTIME
+#endif // SANITIZER_INTERCEPT_FTIME
+
+#if SANITIZER_INTERCEPT_XDR
+INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr,
+ unsigned size, int op) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ REAL(xdrmem_create)(xdrs, addr, size, op);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
+ if (op == __sanitizer_XDR_ENCODE) {
+ // It's not obvious how much data individual xdr_ routines write.
+ // Simply unpoison the entire target buffer in advance.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (void *)addr, size);
+ }
+}
+
+INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ REAL(xdrstdio_create)(xdrs, file, op);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
+}
+
+// FIXME: under ASan the call below may write to freed memory and corrupt
+// its metadata. See
+// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+#define XDR_INTERCEPTOR(F, T) \
+ INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, F, xdrs, p); \
+ if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); \
+ int res = REAL(F)(xdrs, p); \
+ if (res && p && xdrs->x_op == __sanitizer_XDR_DECODE) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); \
+ return res; \
+ }
+
+XDR_INTERCEPTOR(xdr_short, short)
+XDR_INTERCEPTOR(xdr_u_short, unsigned short)
+XDR_INTERCEPTOR(xdr_int, int)
+XDR_INTERCEPTOR(xdr_u_int, unsigned)
+XDR_INTERCEPTOR(xdr_long, long)
+XDR_INTERCEPTOR(xdr_u_long, unsigned long)
+XDR_INTERCEPTOR(xdr_hyper, long long)
+XDR_INTERCEPTOR(xdr_u_hyper, unsigned long long)
+XDR_INTERCEPTOR(xdr_longlong_t, long long)
+XDR_INTERCEPTOR(xdr_u_longlong_t, unsigned long long)
+XDR_INTERCEPTOR(xdr_int8_t, u8)
+XDR_INTERCEPTOR(xdr_uint8_t, u8)
+XDR_INTERCEPTOR(xdr_int16_t, u16)
+XDR_INTERCEPTOR(xdr_uint16_t, u16)
+XDR_INTERCEPTOR(xdr_int32_t, u32)
+XDR_INTERCEPTOR(xdr_uint32_t, u32)
+XDR_INTERCEPTOR(xdr_int64_t, u64)
+XDR_INTERCEPTOR(xdr_uint64_t, u64)
+XDR_INTERCEPTOR(xdr_quad_t, long long)
+XDR_INTERCEPTOR(xdr_u_quad_t, unsigned long long)
+XDR_INTERCEPTOR(xdr_bool, bool)
+XDR_INTERCEPTOR(xdr_enum, int)
+XDR_INTERCEPTOR(xdr_char, char)
+XDR_INTERCEPTOR(xdr_u_char, unsigned char)
+XDR_INTERCEPTOR(xdr_float, float)
+XDR_INTERCEPTOR(xdr_double, double)
+
+// FIXME: intercept xdr_array, opaque, union, vector, reference, pointer,
+// wrapstring, sizeof
+
+INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep,
+ unsigned maxsize) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, xdr_bytes, xdrs, p, sizep, maxsize);
+ if (p && sizep && xdrs->x_op == __sanitizer_XDR_ENCODE) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *sizep);
+ }
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize);
+ if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizep, sizeof(*sizep));
+ if (res && *p && *sizep) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, *sizep);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
+ unsigned maxsize) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, xdr_string, xdrs, p, maxsize);
+ if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+ }
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ int res = REAL(xdr_string)(xdrs, p, maxsize);
+ if (p && xdrs->x_op == __sanitizer_XDR_DECODE) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (res && *p)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+ }
+ return res;
+}
+
+#define INIT_XDR \
+ COMMON_INTERCEPT_FUNCTION(xdrmem_create); \
+ COMMON_INTERCEPT_FUNCTION(xdrstdio_create); \
+ COMMON_INTERCEPT_FUNCTION(xdr_short); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_short); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_int); \
+ COMMON_INTERCEPT_FUNCTION(xdr_long); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_long); \
+ COMMON_INTERCEPT_FUNCTION(xdr_hyper); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_hyper); \
+ COMMON_INTERCEPT_FUNCTION(xdr_longlong_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_longlong_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int8_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint8_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int16_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint16_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int32_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint32_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int64_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint64_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_quad_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_quad_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_bool); \
+ COMMON_INTERCEPT_FUNCTION(xdr_enum); \
+ COMMON_INTERCEPT_FUNCTION(xdr_char); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_char); \
+ COMMON_INTERCEPT_FUNCTION(xdr_float); \
+ COMMON_INTERCEPT_FUNCTION(xdr_double); \
+ COMMON_INTERCEPT_FUNCTION(xdr_bytes); \
+ COMMON_INTERCEPT_FUNCTION(xdr_string);
+#else
+#define INIT_XDR
+#endif // SANITIZER_INTERCEPT_XDR
+
+#if SANITIZER_INTERCEPT_TSEARCH
+INTERCEPTOR(void *, tsearch, void *key, void **rootp,
+ int (*compar)(const void *, const void *)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ void *res = REAL(tsearch)(key, rootp, compar);
+ if (res && *(void **)res == key)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *));
+ return res;
+}
+#define INIT_TSEARCH COMMON_INTERCEPT_FUNCTION(tsearch);
+#else
+#define INIT_TSEARCH
+#endif
+
+#if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \
+ SANITIZER_INTERCEPT_OPEN_MEMSTREAM
+void unpoison_file(__sanitizer_FILE *fp) {
+#if SANITIZER_HAS_STRUCT_FILE
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp));
+ if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
+ fp->_IO_read_end - fp->_IO_read_base);
+#endif // SANITIZER_HAS_STRUCT_FILE
+}
+#endif
+
+#if SANITIZER_INTERCEPT_LIBIO_INTERNALS
+// These guys are called when a .c source is built with -O2.
+INTERCEPTOR(int, __uflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __uflow, fp);
+ int res = REAL(__uflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __underflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __underflow, fp);
+ int res = REAL(__underflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __overflow, __sanitizer_FILE *fp, int ch) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __overflow, fp, ch);
+ int res = REAL(__overflow)(fp, ch);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __wuflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __wuflow, fp);
+ int res = REAL(__wuflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __wunderflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __wunderflow, fp);
+ int res = REAL(__wunderflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __woverflow, fp, ch);
+ int res = REAL(__woverflow)(fp, ch);
+ unpoison_file(fp);
+ return res;
+}
+#define INIT_LIBIO_INTERNALS \
+ COMMON_INTERCEPT_FUNCTION(__uflow); \
+ COMMON_INTERCEPT_FUNCTION(__underflow); \
+ COMMON_INTERCEPT_FUNCTION(__overflow); \
+ COMMON_INTERCEPT_FUNCTION(__wuflow); \
+ COMMON_INTERCEPT_FUNCTION(__wunderflow); \
+ COMMON_INTERCEPT_FUNCTION(__woverflow);
+#else
+#define INIT_LIBIO_INTERNALS
+#endif
+
+#if SANITIZER_INTERCEPT_FOPEN
+INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ __sanitizer_FILE *res = REAL(fopen)(path, mode);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, fdopen, int fd, const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fdopen, fd, mode);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ __sanitizer_FILE *res = REAL(fdopen)(fd, mode);
+ if (res) unpoison_file(res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode,
+ __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ __sanitizer_FILE *res = REAL(freopen)(path, mode, fp);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+#define INIT_FOPEN \
+ COMMON_INTERCEPT_FUNCTION(fopen); \
+ COMMON_INTERCEPT_FUNCTION(fdopen); \
+ COMMON_INTERCEPT_FUNCTION(freopen);
+#else
+#define INIT_FOPEN
+#endif
+
+#if SANITIZER_INTERCEPT_FOPEN64
+INTERCEPTOR(__sanitizer_FILE *, fopen64, const char *path, const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fopen64, path, mode);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ __sanitizer_FILE *res = REAL(fopen64)(path, mode);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode,
+ __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+#define INIT_FOPEN64 \
+ COMMON_INTERCEPT_FUNCTION(fopen64); \
+ COMMON_INTERCEPT_FUNCTION(freopen64);
+#else
+#define INIT_FOPEN64
+#endif
+
+#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM
+INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc);
+ if (res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc));
+ unpoison_file(res);
+ FileMetadata file = {ptr, sizeloc};
+ SetInterceptorMetadata(res, file);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr,
+ SIZE_T *sizeloc) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, open_wmemstream, ptr, sizeloc);
+ __sanitizer_FILE *res = REAL(open_wmemstream)(ptr, sizeloc);
+ if (res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc));
+ unpoison_file(res);
+ FileMetadata file = {(char **)ptr, sizeloc};
+ SetInterceptorMetadata(res, file);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size,
+ const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode);
+ if (res) unpoison_file(res);
+ return res;
+}
+#define INIT_OPEN_MEMSTREAM \
+ COMMON_INTERCEPT_FUNCTION(open_memstream); \
+ COMMON_INTERCEPT_FUNCTION(open_wmemstream); \
+ COMMON_INTERCEPT_FUNCTION(fmemopen);
+#else
+#define INIT_OPEN_MEMSTREAM
+#endif
+
+#if SANITIZER_INTERCEPT_OBSTACK
+static void initialize_obstack(__sanitizer_obstack *obstack) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack, sizeof(*obstack));
+ if (obstack->chunk)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack->chunk,
+ sizeof(*obstack->chunk));
+}
+
+INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack, int sz,
+ int align, void *(*alloc_fn)(uptr arg, uptr sz),
+ void (*free_fn)(uptr arg, void *p)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin_1, obstack, sz, align, alloc_fn,
+ free_fn);
+ int res = REAL(_obstack_begin_1)(obstack, sz, align, alloc_fn, free_fn);
+ if (res) initialize_obstack(obstack);
+ return res;
+}
+INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack, int sz,
+ int align, void *(*alloc_fn)(uptr sz), void (*free_fn)(void *p)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin, obstack, sz, align, alloc_fn,
+ free_fn);
+ int res = REAL(_obstack_begin)(obstack, sz, align, alloc_fn, free_fn);
+ if (res) initialize_obstack(obstack);
+ return res;
+}
+INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _obstack_newchunk, obstack, length);
+ REAL(_obstack_newchunk)(obstack, length);
+ if (obstack->chunk)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(
+ obstack->chunk, obstack->next_free - (char *)obstack->chunk);
+}
+#define INIT_OBSTACK \
+ COMMON_INTERCEPT_FUNCTION(_obstack_begin_1); \
+ COMMON_INTERCEPT_FUNCTION(_obstack_begin); \
+ COMMON_INTERCEPT_FUNCTION(_obstack_newchunk);
+#else
+#define INIT_OBSTACK
+#endif
+
+#if SANITIZER_INTERCEPT_FFLUSH
+INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
+ int res = REAL(fflush)(fp);
+ // FIXME: handle fp == NULL
+ if (fp) {
+ const FileMetadata *m = GetInterceptorMetadata(fp);
+ if (m) COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+ }
+ return res;
+}
+#define INIT_FFLUSH COMMON_INTERCEPT_FUNCTION(fflush);
+#else
+#define INIT_FFLUSH
+#endif
+
+#if SANITIZER_INTERCEPT_FCLOSE
+INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
+ if (fp) {
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ const FileMetadata *m = GetInterceptorMetadata(fp);
+ if (m) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+ DeleteInterceptorMetadata(fp);
+ }
+ }
+ return REAL(fclose)(fp);
+}
+#define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose);
+#else
+#define INIT_FCLOSE
+#endif
+
+#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
+INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
+ void *res = REAL(dlopen)(filename, flag);
+ COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
+ return res;
+}
+
+INTERCEPTOR(int, dlclose, void *handle) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle);
+ int res = REAL(dlclose)(handle);
+ COMMON_INTERCEPTOR_LIBRARY_UNLOADED();
+ return res;
+}
+#define INIT_DLOPEN_DLCLOSE \
+ COMMON_INTERCEPT_FUNCTION(dlopen); \
+ COMMON_INTERCEPT_FUNCTION(dlclose);
+#else
+#define INIT_DLOPEN_DLCLOSE
+#endif
+
+#if SANITIZER_INTERCEPT_GETPASS
+INTERCEPTOR(char *, getpass, const char *prompt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpass, prompt);
+ if (prompt)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, prompt, REAL(strlen)(prompt)+1);
+ char *res = REAL(getpass)(prompt);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res)+1);
+ return res;
+}
+
+#define INIT_GETPASS COMMON_INTERCEPT_FUNCTION(getpass);
+#else
+#define INIT_GETPASS
+#endif
+
+#if SANITIZER_INTERCEPT_TIMERFD
+INTERCEPTOR(int, timerfd_settime, int fd, int flags, void *new_value,
+ void *old_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, timerfd_settime, fd, flags, new_value,
+ old_value);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerspec_sz);
+ int res = REAL(timerfd_settime)(fd, flags, new_value, old_value);
+ if (res != -1 && old_value)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerspec_sz);
+ return res;
+}
+
+INTERCEPTOR(int, timerfd_gettime, int fd, void *curr_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, timerfd_gettime, fd, curr_value);
+ int res = REAL(timerfd_gettime)(fd, curr_value);
+ if (res != -1 && curr_value)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerspec_sz);
+ return res;
+}
+#define INIT_TIMERFD \
+ COMMON_INTERCEPT_FUNCTION(timerfd_settime); \
+ COMMON_INTERCEPT_FUNCTION(timerfd_gettime);
+#else
+#define INIT_TIMERFD
+#endif
+
+#if SANITIZER_INTERCEPT_MLOCKX
+// Linux kernel has a bug that leads to kernel deadlock if a process
+// maps TBs of memory and then calls mlock().
+static void MlockIsUnsupported() {
+ static atomic_uint8_t printed;
+ if (atomic_exchange(&printed, 1, memory_order_relaxed))
+ return;
+ VPrintf(1, "INFO: %s ignores mlock/mlockall/munlock/munlockall\n",
+ SanitizerToolName);
+}
+
+INTERCEPTOR(int, mlock, const void *addr, uptr len) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlock, const void *addr, uptr len) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, mlockall, int flags) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlockall, void) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+#define INIT_MLOCKX \
+ COMMON_INTERCEPT_FUNCTION(mlock); \
+ COMMON_INTERCEPT_FUNCTION(munlock); \
+ COMMON_INTERCEPT_FUNCTION(mlockall); \
+ COMMON_INTERCEPT_FUNCTION(munlockall);
+
+#else
+#define INIT_MLOCKX
+#endif // SANITIZER_INTERCEPT_MLOCKX
+
+static void InitializeCommonInterceptors() {
+ static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
+ interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
+
+ INIT_TEXTDOMAIN;
+ INIT_STRCMP;
+ INIT_STRNCMP;
+ INIT_STRCASECMP;
+ INIT_STRNCASECMP;
+ INIT_MEMCHR;
+ INIT_MEMRCHR;
+ INIT_READ;
+ INIT_PREAD;
+ INIT_PREAD64;
+ INIT_READV;
+ INIT_PREADV;
+ INIT_PREADV64;
+ INIT_WRITE;
+ INIT_PWRITE;
+ INIT_PWRITE64;
+ INIT_WRITEV;
+ INIT_PWRITEV;
+ INIT_PWRITEV64;
+ INIT_PRCTL;
+ INIT_LOCALTIME_AND_FRIENDS;
+ INIT_STRPTIME;
+ INIT_SCANF;
+ INIT_ISOC99_SCANF;
+ INIT_PRINTF;
+ INIT_PRINTF_L;
+ INIT_ISOC99_PRINTF;
+ INIT_FREXP;
+ INIT_FREXPF_FREXPL;
+ INIT_GETPWNAM_AND_FRIENDS;
+ INIT_GETPWNAM_R_AND_FRIENDS;
+ INIT_GETPWENT;
+ INIT_FGETPWENT;
+ INIT_GETPWENT_R;
+ INIT_SETPWENT;
+ INIT_CLOCK_GETTIME;
+ INIT_GETITIMER;
+ INIT_TIME;
+ INIT_GLOB;
+ INIT_WAIT;
+ INIT_WAIT4;
+ INIT_INET;
+ INIT_PTHREAD_GETSCHEDPARAM;
+ INIT_GETADDRINFO;
+ INIT_GETNAMEINFO;
+ INIT_GETSOCKNAME;
+ INIT_GETHOSTBYNAME;
+ INIT_GETHOSTBYNAME_R;
+ INIT_GETHOSTBYNAME2_R;
+ INIT_GETHOSTBYADDR_R;
+ INIT_GETHOSTENT_R;
+ INIT_GETSOCKOPT;
+ INIT_ACCEPT;
+ INIT_ACCEPT4;
+ INIT_MODF;
+ INIT_RECVMSG;
+ INIT_GETPEERNAME;
+ INIT_IOCTL;
+ INIT_INET_ATON;
+ INIT_SYSINFO;
+ INIT_READDIR;
+ INIT_READDIR64;
+ INIT_PTRACE;
+ INIT_SETLOCALE;
+ INIT_GETCWD;
+ INIT_GET_CURRENT_DIR_NAME;
+ INIT_STRTOIMAX;
+ INIT_MBSTOWCS;
+ INIT_MBSNRTOWCS;
+ INIT_WCSTOMBS;
+ INIT_WCSNRTOMBS;
+ INIT_TCGETATTR;
+ INIT_REALPATH;
+ INIT_CANONICALIZE_FILE_NAME;
+ INIT_CONFSTR;
+ INIT_SCHED_GETAFFINITY;
+ INIT_SCHED_GETPARAM;
+ INIT_STRERROR;
+ INIT_STRERROR_R;
+ INIT_XPG_STRERROR_R;
+ INIT_SCANDIR;
+ INIT_SCANDIR64;
+ INIT_GETGROUPS;
+ INIT_POLL;
+ INIT_PPOLL;
+ INIT_WORDEXP;
+ INIT_SIGWAIT;
+ INIT_SIGWAITINFO;
+ INIT_SIGTIMEDWAIT;
+ INIT_SIGSETOPS;
+ INIT_SIGPENDING;
+ INIT_SIGPROCMASK;
+ INIT_BACKTRACE;
+ INIT__EXIT;
+ INIT_PTHREAD_MUTEX_LOCK;
+ INIT_PTHREAD_MUTEX_UNLOCK;
+ INIT_GETMNTENT;
+ INIT_GETMNTENT_R;
+ INIT_STATFS;
+ INIT_STATFS64;
+ INIT_STATVFS;
+ INIT_STATVFS64;
+ INIT_INITGROUPS;
+ INIT_ETHER_NTOA_ATON;
+ INIT_ETHER_HOST;
+ INIT_ETHER_R;
+ INIT_SHMCTL;
+ INIT_RANDOM_R;
+ INIT_PTHREAD_ATTR_GET;
+ INIT_PTHREAD_ATTR_GETINHERITSCHED;
+ INIT_PTHREAD_ATTR_GETAFFINITY_NP;
+ INIT_PTHREAD_MUTEXATTR_GETPSHARED;
+ INIT_PTHREAD_MUTEXATTR_GETTYPE;
+ INIT_PTHREAD_MUTEXATTR_GETPROTOCOL;
+ INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING;
+ INIT_PTHREAD_MUTEXATTR_GETROBUST;
+ INIT_PTHREAD_MUTEXATTR_GETROBUST_NP;
+ INIT_PTHREAD_RWLOCKATTR_GETPSHARED;
+ INIT_PTHREAD_RWLOCKATTR_GETKIND_NP;
+ INIT_PTHREAD_CONDATTR_GETPSHARED;
+ INIT_PTHREAD_CONDATTR_GETCLOCK;
+ INIT_PTHREAD_BARRIERATTR_GETPSHARED;
+ INIT_TMPNAM;
+ INIT_TMPNAM_R;
+ INIT_TEMPNAM;
+ INIT_PTHREAD_SETNAME_NP;
+ INIT_SINCOS;
+ INIT_REMQUO;
+ INIT_LGAMMA;
+ INIT_LGAMMA_R;
+ INIT_LGAMMAL_R;
+ INIT_DRAND48_R;
+ INIT_RAND_R;
+ INIT_GETLINE;
+ INIT_ICONV;
+ INIT_TIMES;
+ INIT_TLS_GET_ADDR;
+ INIT_LISTXATTR;
+ INIT_GETXATTR;
+ INIT_GETRESID;
+ INIT_GETIFADDRS;
+ INIT_IF_INDEXTONAME;
+ INIT_CAPGET;
+ INIT_AEABI_MEM;
+ INIT___BZERO;
+ INIT_FTIME;
+ INIT_XDR;
+ INIT_TSEARCH;
+ INIT_LIBIO_INTERNALS;
+ INIT_FOPEN;
+ INIT_FOPEN64;
+ INIT_OPEN_MEMSTREAM;
+ INIT_OBSTACK;
+ INIT_FFLUSH;
+ INIT_FCLOSE;
+ INIT_DLOPEN_DLCLOSE;
+ INIT_GETPASS;
+ INIT_TIMERFD;
+ INIT_MLOCKX;
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
new file mode 100644
index 000000000000..8f94802aeae8
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -0,0 +1,559 @@
+//===-- sanitizer_common_interceptors_format.inc ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Scanf/printf implementation for use in *Sanitizer interceptors.
+// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
+// and http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html
+// with a few common GNU extensions.
+//
+//===----------------------------------------------------------------------===//
+#include <stdarg.h>
+
+static const char *parse_number(const char *p, int *out) {
+ *out = internal_atoll(p);
+ while (*p >= '0' && *p <= '9')
+ ++p;
+ return p;
+}
+
+static const char *maybe_parse_param_index(const char *p, int *out) {
+ // n$
+ if (*p >= '0' && *p <= '9') {
+ int number;
+ const char *q = parse_number(p, &number);
+ CHECK(q);
+ if (*q == '$') {
+ *out = number;
+ p = q + 1;
+ }
+ }
+
+ // Otherwise, do not change p. This will be re-parsed later as the field
+ // width.
+ return p;
+}
+
+static bool char_is_one_of(char c, const char *s) {
+ return !!internal_strchr(s, c);
+}
+
+static const char *maybe_parse_length_modifier(const char *p, char ll[2]) {
+ if (char_is_one_of(*p, "jztLq")) {
+ ll[0] = *p;
+ ++p;
+ } else if (*p == 'h') {
+ ll[0] = 'h';
+ ++p;
+ if (*p == 'h') {
+ ll[1] = 'h';
+ ++p;
+ }
+ } else if (*p == 'l') {
+ ll[0] = 'l';
+ ++p;
+ if (*p == 'l') {
+ ll[1] = 'l';
+ ++p;
+ }
+ }
+ return p;
+}
+
+// Returns true if the character is an integer conversion specifier.
+static bool format_is_integer_conv(char c) {
+ return char_is_one_of(c, "diouxXn");
+}
+
+// Returns true if the character is an floating point conversion specifier.
+static bool format_is_float_conv(char c) {
+ return char_is_one_of(c, "aAeEfFgG");
+}
+
+// Returns string output character size for string-like conversions,
+// or 0 if the conversion is invalid.
+static int format_get_char_size(char convSpecifier,
+ const char lengthModifier[2]) {
+ if (char_is_one_of(convSpecifier, "CS")) {
+ return sizeof(wchar_t);
+ }
+
+ if (char_is_one_of(convSpecifier, "cs[")) {
+ if (lengthModifier[0] == 'l' && lengthModifier[1] == '\0')
+ return sizeof(wchar_t);
+ else if (lengthModifier[0] == '\0')
+ return sizeof(char);
+ }
+
+ return 0;
+}
+
+enum FormatStoreSize {
+ // Store size not known in advance; can be calculated as wcslen() of the
+ // destination buffer.
+ FSS_WCSLEN = -2,
+ // Store size not known in advance; can be calculated as strlen() of the
+ // destination buffer.
+ FSS_STRLEN = -1,
+ // Invalid conversion specifier.
+ FSS_INVALID = 0
+};
+
+// Returns the memory size of a format directive (if >0), or a value of
+// FormatStoreSize.
+static int format_get_value_size(char convSpecifier,
+ const char lengthModifier[2],
+ bool promote_float) {
+ if (format_is_integer_conv(convSpecifier)) {
+ switch (lengthModifier[0]) {
+ case 'h':
+ return lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
+ case 'l':
+ return lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
+ case 'q':
+ return sizeof(long long);
+ case 'L':
+ return sizeof(long long);
+ case 'j':
+ return sizeof(INTMAX_T);
+ case 'z':
+ return sizeof(SIZE_T);
+ case 't':
+ return sizeof(PTRDIFF_T);
+ case 0:
+ return sizeof(int);
+ default:
+ return FSS_INVALID;
+ }
+ }
+
+ if (format_is_float_conv(convSpecifier)) {
+ switch (lengthModifier[0]) {
+ case 'L':
+ case 'q':
+ return sizeof(long double);
+ case 'l':
+ return lengthModifier[1] == 'l' ? sizeof(long double)
+ : sizeof(double);
+ case 0:
+ // Printf promotes floats to doubles but scanf does not
+ return promote_float ? sizeof(double) : sizeof(float);
+ default:
+ return FSS_INVALID;
+ }
+ }
+
+ if (convSpecifier == 'p') {
+ if (lengthModifier[0] != 0)
+ return FSS_INVALID;
+ return sizeof(void *);
+ }
+
+ return FSS_INVALID;
+}
+
+struct ScanfDirective {
+ int argIdx; // argument index, or -1 if not specified ("%n$")
+ int fieldWidth;
+ const char *begin;
+ const char *end;
+ bool suppressed; // suppress assignment ("*")
+ bool allocate; // allocate space ("m")
+ char lengthModifier[2];
+ char convSpecifier;
+ bool maybeGnuMalloc;
+};
+
+// Parse scanf format string. If a valid directive in encountered, it is
+// returned in dir. This function returns the pointer to the first
+// unprocessed character, or 0 in case of error.
+// In case of the end-of-string, a pointer to the closing \0 is returned.
+static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
+ ScanfDirective *dir) {
+ internal_memset(dir, 0, sizeof(*dir));
+ dir->argIdx = -1;
+
+ while (*p) {
+ if (*p != '%') {
+ ++p;
+ continue;
+ }
+ dir->begin = p;
+ ++p;
+ // %%
+ if (*p == '%') {
+ ++p;
+ continue;
+ }
+ if (*p == '\0') {
+ return 0;
+ }
+ // %n$
+ p = maybe_parse_param_index(p, &dir->argIdx);
+ CHECK(p);
+ // *
+ if (*p == '*') {
+ dir->suppressed = true;
+ ++p;
+ }
+ // Field width
+ if (*p >= '0' && *p <= '9') {
+ p = parse_number(p, &dir->fieldWidth);
+ CHECK(p);
+ if (dir->fieldWidth <= 0) // Width if at all must be non-zero
+ return 0;
+ }
+ // m
+ if (*p == 'm') {
+ dir->allocate = true;
+ ++p;
+ }
+ // Length modifier.
+ p = maybe_parse_length_modifier(p, dir->lengthModifier);
+ // Conversion specifier.
+ dir->convSpecifier = *p++;
+ // Consume %[...] expression.
+ if (dir->convSpecifier == '[') {
+ if (*p == '^')
+ ++p;
+ if (*p == ']')
+ ++p;
+ while (*p && *p != ']')
+ ++p;
+ if (*p == 0)
+ return 0; // unexpected end of string
+ // Consume the closing ']'.
+ ++p;
+ }
+ // This is unfortunately ambiguous between old GNU extension
+ // of %as, %aS and %a[...] and newer POSIX %a followed by
+ // letters s, S or [.
+ if (allowGnuMalloc && dir->convSpecifier == 'a' &&
+ !dir->lengthModifier[0]) {
+ if (*p == 's' || *p == 'S') {
+ dir->maybeGnuMalloc = true;
+ ++p;
+ } else if (*p == '[') {
+ // Watch for %a[h-j%d], if % appears in the
+ // [...] range, then we need to give up, we don't know
+ // if scanf will parse it as POSIX %a [h-j %d ] or
+ // GNU allocation of string with range dh-j plus %.
+ const char *q = p + 1;
+ if (*q == '^')
+ ++q;
+ if (*q == ']')
+ ++q;
+ while (*q && *q != ']' && *q != '%')
+ ++q;
+ if (*q == 0 || *q == '%')
+ return 0;
+ p = q + 1; // Consume the closing ']'.
+ dir->maybeGnuMalloc = true;
+ }
+ }
+ dir->end = p;
+ break;
+ }
+ return p;
+}
+
+static int scanf_get_value_size(ScanfDirective *dir) {
+ if (dir->allocate) {
+ if (!char_is_one_of(dir->convSpecifier, "cCsS["))
+ return FSS_INVALID;
+ return sizeof(char *);
+ }
+
+ if (dir->maybeGnuMalloc) {
+ if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
+ return FSS_INVALID;
+ // This is ambiguous, so check the smaller size of char * (if it is
+ // a GNU extension of %as, %aS or %a[...]) and float (if it is
+ // POSIX %a followed by s, S or [ letters).
+ return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "cCsS[")) {
+ bool needsTerminator = char_is_one_of(dir->convSpecifier, "sS[");
+ unsigned charSize =
+ format_get_char_size(dir->convSpecifier, dir->lengthModifier);
+ if (charSize == 0)
+ return FSS_INVALID;
+ if (dir->fieldWidth == 0) {
+ if (!needsTerminator)
+ return charSize;
+ return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+ }
+ return (dir->fieldWidth + needsTerminator) * charSize;
+ }
+
+ return format_get_value_size(dir->convSpecifier, dir->lengthModifier, false);
+}
+
+// Common part of *scanf interceptors.
+// Process format string and va_list, and report all store ranges.
+// Stops when "consuming" n_inputs input items.
+static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
+ const char *format, va_list aq) {
+ CHECK_GT(n_inputs, 0);
+ const char *p = format;
+
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1);
+
+ while (*p) {
+ ScanfDirective dir;
+ p = scanf_parse_next(p, allowGnuMalloc, &dir);
+ if (!p)
+ break;
+ if (dir.convSpecifier == 0) {
+ // This can only happen at the end of the format string.
+ CHECK_EQ(*p, 0);
+ break;
+ }
+ // Here the directive is valid. Do what it says.
+ if (dir.argIdx != -1) {
+ // Unsupported.
+ break;
+ }
+ if (dir.suppressed)
+ continue;
+ int size = scanf_get_value_size(&dir);
+ if (size == FSS_INVALID) {
+ Report("WARNING: unexpected format specifier in scanf interceptor: "
+ "%.*s\n", dir.end - dir.begin, dir.begin);
+ break;
+ }
+ void *argp = va_arg(aq, void *);
+ if (dir.convSpecifier != 'n')
+ --n_inputs;
+ if (n_inputs < 0)
+ break;
+ if (size == FSS_STRLEN) {
+ size = internal_strlen((const char *)argp) + 1;
+ } else if (size == FSS_WCSLEN) {
+ // FIXME: actually use wcslen() to calculate it.
+ size = 0;
+ }
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+ }
+}
+
+#if SANITIZER_INTERCEPT_PRINTF
+
+struct PrintfDirective {
+ int fieldWidth;
+ int fieldPrecision;
+ int argIdx; // width argument index, or -1 if not specified ("%*n$")
+ int precisionIdx; // precision argument index, or -1 if not specified (".*n$")
+ const char *begin;
+ const char *end;
+ bool starredWidth;
+ bool starredPrecision;
+ char lengthModifier[2];
+ char convSpecifier;
+};
+
+static const char *maybe_parse_number(const char *p, int *out) {
+ if (*p >= '0' && *p <= '9')
+ p = parse_number(p, out);
+ return p;
+}
+
+static const char *maybe_parse_number_or_star(const char *p, int *out,
+ bool *star) {
+ if (*p == '*') {
+ *star = true;
+ ++p;
+ } else {
+ *star = false;
+ p = maybe_parse_number(p, out);
+ }
+ return p;
+}
+
+// Parse printf format string. Same as scanf_parse_next.
+static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
+ internal_memset(dir, 0, sizeof(*dir));
+ dir->argIdx = -1;
+ dir->precisionIdx = -1;
+
+ while (*p) {
+ if (*p != '%') {
+ ++p;
+ continue;
+ }
+ dir->begin = p;
+ ++p;
+ // %%
+ if (*p == '%') {
+ ++p;
+ continue;
+ }
+ if (*p == '\0') {
+ return 0;
+ }
+ // %n$
+ p = maybe_parse_param_index(p, &dir->precisionIdx);
+ CHECK(p);
+ // Flags
+ while (char_is_one_of(*p, "'-+ #0")) {
+ ++p;
+ }
+ // Field width
+ p = maybe_parse_number_or_star(p, &dir->fieldWidth,
+ &dir->starredWidth);
+ if (!p)
+ return 0;
+ // Precision
+ if (*p == '.') {
+ ++p;
+ // Actual precision is optional (surprise!)
+ p = maybe_parse_number_or_star(p, &dir->fieldPrecision,
+ &dir->starredPrecision);
+ if (!p)
+ return 0;
+ // m$
+ if (dir->starredPrecision) {
+ p = maybe_parse_param_index(p, &dir->precisionIdx);
+ CHECK(p);
+ }
+ }
+ // Length modifier.
+ p = maybe_parse_length_modifier(p, dir->lengthModifier);
+ // Conversion specifier.
+ dir->convSpecifier = *p++;
+ dir->end = p;
+ break;
+ }
+ return p;
+}
+
+static int printf_get_value_size(PrintfDirective *dir) {
+ if (dir->convSpecifier == 'm') {
+ return sizeof(char *);
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "cCsS")) {
+ unsigned charSize =
+ format_get_char_size(dir->convSpecifier, dir->lengthModifier);
+ if (charSize == 0)
+ return FSS_INVALID;
+ if (char_is_one_of(dir->convSpecifier, "sS")) {
+ return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+ }
+ return charSize;
+ }
+
+ return format_get_value_size(dir->convSpecifier, dir->lengthModifier, true);
+}
+
+#define SKIP_SCALAR_ARG(aq, convSpecifier, size) \
+ do { \
+ if (format_is_float_conv(convSpecifier)) { \
+ switch (size) { \
+ case 8: \
+ va_arg(*aq, double); \
+ break; \
+ case 12: \
+ va_arg(*aq, long double); \
+ break; \
+ case 16: \
+ va_arg(*aq, long double); \
+ break; \
+ default: \
+ Report("WARNING: unexpected floating-point arg size" \
+ " in printf interceptor: %d\n", size); \
+ return; \
+ } \
+ } else { \
+ switch (size) { \
+ case 1: \
+ case 2: \
+ case 4: \
+ va_arg(*aq, u32); \
+ break; \
+ case 8: \
+ va_arg(*aq, u64); \
+ break; \
+ default: \
+ Report("WARNING: unexpected arg size" \
+ " in printf interceptor: %d\n", size); \
+ return; \
+ } \
+ } \
+ } while (0)
+
+// Common part of *printf interceptors.
+// Process format string and va_list, and report all load ranges.
+static void printf_common(void *ctx, const char *format, va_list aq) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1);
+
+ const char *p = format;
+
+ while (*p) {
+ PrintfDirective dir;
+ p = printf_parse_next(p, &dir);
+ if (!p)
+ break;
+ if (dir.convSpecifier == 0) {
+ // This can only happen at the end of the format string.
+ CHECK_EQ(*p, 0);
+ break;
+ }
+ // Here the directive is valid. Do what it says.
+ if (dir.argIdx != -1 || dir.precisionIdx != -1) {
+ // Unsupported.
+ break;
+ }
+ if (dir.starredWidth) {
+ // Dynamic width
+ SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
+ }
+ if (dir.starredPrecision) {
+ // Dynamic precision
+ SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
+ }
+ int size = printf_get_value_size(&dir);
+ if (size == FSS_INVALID) {
+ Report("WARNING: unexpected format specifier in printf "
+ "interceptor: %.*s\n", dir.end - dir.begin, dir.begin);
+ break;
+ }
+ if (dir.convSpecifier == 'n') {
+ void *argp = va_arg(aq, void *);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+ continue;
+ } else if (size == FSS_STRLEN) {
+ if (void *argp = va_arg(aq, void *)) {
+ if (dir.starredPrecision) {
+ // FIXME: properly support starred precision for strings.
+ size = 0;
+ } else if (dir.fieldPrecision > 0) {
+ // Won't read more than "precision" symbols.
+ size = internal_strnlen((const char *)argp, dir.fieldPrecision);
+ if (size < dir.fieldPrecision) size++;
+ } else {
+ // Whole string will be accessed.
+ size = internal_strlen((const char *)argp) + 1;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+ }
+ } else if (size == FSS_WCSLEN) {
+ if (void *argp = va_arg(aq, void *)) {
+ // FIXME: Properly support wide-character strings (via wcsrtombs).
+ size = 0;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+ }
+ } else {
+ // Skip non-pointer args
+ SKIP_SCALAR_ARG(&aq, dir.convSpecifier, size);
+ }
+ }
+}
+
+#endif // SANITIZER_INTERCEPT_PRINTF
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
new file mode 100755
index 000000000000..69b7ca9eaa2e
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -0,0 +1,608 @@
+//===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Ioctl handling in common sanitizer interceptors.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_flags.h"
+
+struct ioctl_desc {
+ unsigned req;
+ // FIXME: support read+write arguments. Currently READWRITE and WRITE do the
+ // same thing.
+ // XXX: The declarations below may use WRITE instead of READWRITE, unless
+ // explicitly noted.
+ enum {
+ NONE,
+ READ,
+ WRITE,
+ READWRITE,
+ CUSTOM
+ } type : 3;
+ unsigned size : 29;
+ const char* name;
+};
+
+const unsigned ioctl_table_max = 500;
+static ioctl_desc ioctl_table[ioctl_table_max];
+static unsigned ioctl_table_size = 0;
+
+// This can not be declared as a global, because references to struct_*_sz
+// require a global initializer. And this table must be available before global
+// initializers are run.
+static void ioctl_table_fill() {
+#define _(rq, tp, sz) \
+ if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \
+ CHECK(ioctl_table_size < ioctl_table_max); \
+ ioctl_table[ioctl_table_size].req = IOCTL_##rq; \
+ ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \
+ ioctl_table[ioctl_table_size].size = sz; \
+ ioctl_table[ioctl_table_size].name = #rq; \
+ ++ioctl_table_size; \
+ }
+
+ _(FIOASYNC, READ, sizeof(int));
+ _(FIOCLEX, NONE, 0);
+ _(FIOGETOWN, WRITE, sizeof(int));
+ _(FIONBIO, READ, sizeof(int));
+ _(FIONCLEX, NONE, 0);
+ _(FIOSETOWN, READ, sizeof(int));
+ _(SIOCADDMULTI, READ, struct_ifreq_sz);
+ _(SIOCATMARK, WRITE, sizeof(int));
+ _(SIOCDELMULTI, READ, struct_ifreq_sz);
+ _(SIOCGIFADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFCONF, CUSTOM, 0);
+ _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMTU, WRITE, struct_ifreq_sz);
+ _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz);
+ _(SIOCGPGRP, WRITE, sizeof(int));
+ _(SIOCSIFADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFBRDADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFDSTADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFFLAGS, READ, struct_ifreq_sz);
+ _(SIOCSIFMETRIC, READ, struct_ifreq_sz);
+ _(SIOCSIFMTU, READ, struct_ifreq_sz);
+ _(SIOCSIFNETMASK, READ, struct_ifreq_sz);
+ _(SIOCSPGRP, READ, sizeof(int));
+ _(TIOCCONS, NONE, 0);
+ _(TIOCEXCL, NONE, 0);
+ _(TIOCGETD, WRITE, sizeof(int));
+ _(TIOCGPGRP, WRITE, pid_t_sz);
+ _(TIOCGWINSZ, WRITE, struct_winsize_sz);
+ _(TIOCMBIC, READ, sizeof(int));
+ _(TIOCMBIS, READ, sizeof(int));
+ _(TIOCMGET, WRITE, sizeof(int));
+ _(TIOCMSET, READ, sizeof(int));
+ _(TIOCNOTTY, NONE, 0);
+ _(TIOCNXCL, NONE, 0);
+ _(TIOCOUTQ, WRITE, sizeof(int));
+ _(TIOCPKT, READ, sizeof(int));
+ _(TIOCSCTTY, NONE, 0);
+ _(TIOCSETD, READ, sizeof(int));
+ _(TIOCSPGRP, READ, pid_t_sz);
+ _(TIOCSTI, READ, sizeof(char));
+ _(TIOCSWINSZ, READ, struct_winsize_sz);
+
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+ _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz);
+ _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz);
+#endif
+
+#if SANITIZER_LINUX
+ // Conflicting request ids.
+ // _(CDROMAUDIOBUFSIZ, NONE, 0);
+ // _(SNDCTL_TMR_CONTINUE, NONE, 0);
+ // _(SNDCTL_TMR_START, NONE, 0);
+ // _(SNDCTL_TMR_STOP, NONE, 0);
+ // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE
+ // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE
+ // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
+ // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
+ _(BLKFLSBUF, NONE, 0);
+ _(BLKGETSIZE, WRITE, sizeof(uptr));
+ _(BLKRAGET, WRITE, sizeof(int));
+ _(BLKRASET, NONE, 0);
+ _(BLKROGET, WRITE, sizeof(int));
+ _(BLKROSET, READ, sizeof(int));
+ _(BLKRRPART, NONE, 0);
+ _(CDROMEJECT, NONE, 0);
+ _(CDROMEJECT_SW, NONE, 0);
+ _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz);
+ _(CDROMPAUSE, NONE, 0);
+ _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz);
+ _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz);
+ _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz);
+ _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz);
+ _(CDROMREADMODE1, READ, struct_cdrom_msf_sz);
+ _(CDROMREADMODE2, READ, struct_cdrom_msf_sz);
+ _(CDROMREADRAW, READ, struct_cdrom_msf_sz);
+ _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz);
+ _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz);
+ _(CDROMRESET, NONE, 0);
+ _(CDROMRESUME, NONE, 0);
+ _(CDROMSEEK, READ, struct_cdrom_msf_sz);
+ _(CDROMSTART, NONE, 0);
+ _(CDROMSTOP, NONE, 0);
+ _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz);
+ _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz);
+ _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz);
+ _(CDROM_GET_UPC, WRITE, 8);
+ _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup
+ _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup
+ _(EVIOCGEFFECTS, WRITE, sizeof(int));
+ _(EVIOCGID, WRITE, struct_input_id_sz);
+ _(EVIOCGKEY, WRITE, 0);
+ _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2);
+ _(EVIOCGLED, WRITE, 0);
+ _(EVIOCGNAME, WRITE, 0);
+ _(EVIOCGPHYS, WRITE, 0);
+ _(EVIOCGRAB, READ, sizeof(int));
+ _(EVIOCGREP, WRITE, sizeof(int) * 2);
+ _(EVIOCGSND, WRITE, 0);
+ _(EVIOCGSW, WRITE, 0);
+ _(EVIOCGUNIQ, WRITE, 0);
+ _(EVIOCGVERSION, WRITE, sizeof(int));
+ _(EVIOCRMFF, READ, sizeof(int));
+ _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup
+ _(EVIOCSFF, READ, struct_ff_effect_sz);
+ _(EVIOCSKEYCODE, READ, sizeof(int) * 2);
+ _(EVIOCSREP, READ, sizeof(int) * 2);
+ _(FDCLRPRM, NONE, 0);
+ _(FDDEFPRM, READ, struct_floppy_struct_sz);
+ _(FDFLUSH, NONE, 0);
+ _(FDFMTBEG, NONE, 0);
+ _(FDFMTEND, NONE, 0);
+ _(FDFMTTRK, READ, struct_format_descr_sz);
+ _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz);
+ _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
+ _(FDGETDRVTYP, WRITE, 16);
+ _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz);
+ _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz);
+ _(FDGETPRM, WRITE, struct_floppy_struct_sz);
+ _(FDMSGOFF, NONE, 0);
+ _(FDMSGON, NONE, 0);
+ _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
+ _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz);
+ _(FDRESET, NONE, 0);
+ _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz);
+ _(FDSETEMSGTRESH, NONE, 0);
+ _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz);
+ _(FDSETPRM, READ, struct_floppy_struct_sz);
+ _(FDTWADDLE, NONE, 0);
+ _(FDWERRORCLR, NONE, 0);
+ _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz);
+ _(HDIO_DRIVE_CMD, WRITE, sizeof(int));
+ _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz);
+ _(HDIO_GET_32BIT, WRITE, sizeof(int));
+ _(HDIO_GET_DMA, WRITE, sizeof(int));
+ _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz);
+ _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int));
+ _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int));
+ _(HDIO_GET_NOWERR, WRITE, sizeof(int));
+ _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int));
+ _(HDIO_SET_32BIT, NONE, 0);
+ _(HDIO_SET_DMA, NONE, 0);
+ _(HDIO_SET_KEEPSETTINGS, NONE, 0);
+ _(HDIO_SET_MULTCOUNT, NONE, 0);
+ _(HDIO_SET_NOWERR, NONE, 0);
+ _(HDIO_SET_UNMASKINTR, NONE, 0);
+ _(MTIOCGET, WRITE, struct_mtget_sz);
+ _(MTIOCPOS, WRITE, struct_mtpos_sz);
+ _(MTIOCTOP, READ, struct_mtop_sz);
+ _(PPPIOCGASYNCMAP, WRITE, sizeof(int));
+ _(PPPIOCGDEBUG, WRITE, sizeof(int));
+ _(PPPIOCGFLAGS, WRITE, sizeof(int));
+ _(PPPIOCGUNIT, WRITE, sizeof(int));
+ _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8);
+ _(PPPIOCSASYNCMAP, READ, sizeof(int));
+ _(PPPIOCSDEBUG, READ, sizeof(int));
+ _(PPPIOCSFLAGS, READ, sizeof(int));
+ _(PPPIOCSMAXCID, READ, sizeof(int));
+ _(PPPIOCSMRU, READ, sizeof(int));
+ _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8);
+ _(SIOCADDRT, READ, struct_rtentry_sz);
+ _(SIOCDARP, READ, struct_arpreq_sz);
+ _(SIOCDELRT, READ, struct_rtentry_sz);
+ _(SIOCDRARP, READ, struct_arpreq_sz);
+ _(SIOCGARP, WRITE, struct_arpreq_sz);
+ _(SIOCGIFENCAP, WRITE, sizeof(int));
+ _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMAP, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMEM, WRITE, struct_ifreq_sz);
+ _(SIOCGIFNAME, NONE, 0);
+ _(SIOCGIFSLAVE, NONE, 0);
+ _(SIOCGRARP, WRITE, struct_arpreq_sz);
+ _(SIOCGSTAMP, WRITE, timeval_sz);
+ _(SIOCSARP, READ, struct_arpreq_sz);
+ _(SIOCSIFENCAP, READ, sizeof(int));
+ _(SIOCSIFHWADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFLINK, NONE, 0);
+ _(SIOCSIFMAP, READ, struct_ifreq_sz);
+ _(SIOCSIFMEM, READ, struct_ifreq_sz);
+ _(SIOCSIFSLAVE, NONE, 0);
+ _(SIOCSRARP, READ, struct_arpreq_sz);
+ _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz);
+ _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz);
+ _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_RESET, NONE, 0);
+ _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz);
+ _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz);
+ _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int));
+ _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int));
+ _(SNDCTL_DSP_NONBLOCK, NONE, 0);
+ _(SNDCTL_DSP_POST, NONE, 0);
+ _(SNDCTL_DSP_RESET, NONE, 0);
+ _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SPEED, WRITE, sizeof(int));
+ _(SNDCTL_DSP_STEREO, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SYNC, NONE, 0);
+ _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int));
+ _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz);
+ _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz);
+ _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz);
+ _(SNDCTL_SEQ_PANIC, NONE, 0);
+ _(SNDCTL_SEQ_PERCMODE, NONE, 0);
+ _(SNDCTL_SEQ_RESET, NONE, 0);
+ _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int));
+ _(SNDCTL_SEQ_SYNC, NONE, 0);
+ _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int));
+ _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int));
+ _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz);
+ _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int));
+ _(SNDCTL_TMR_METRONOME, READ, sizeof(int));
+ _(SNDCTL_TMR_SELECT, WRITE, sizeof(int));
+ _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int));
+ _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int));
+ _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_CD, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_BITS, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_RATE, WRITE, sizeof(int));
+ _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
+ _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
+ _(TCFLSH, NONE, 0);
+ _(TCGETA, WRITE, struct_termio_sz);
+ _(TCGETS, WRITE, struct_termios_sz);
+ _(TCSBRK, NONE, 0);
+ _(TCSBRKP, NONE, 0);
+ _(TCSETA, READ, struct_termio_sz);
+ _(TCSETAF, READ, struct_termio_sz);
+ _(TCSETAW, READ, struct_termio_sz);
+ _(TCSETS, READ, struct_termios_sz);
+ _(TCSETSF, READ, struct_termios_sz);
+ _(TCSETSW, READ, struct_termios_sz);
+ _(TCXONC, NONE, 0);
+ _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz);
+ _(TIOCGSOFTCAR, WRITE, sizeof(int));
+ _(TIOCINQ, WRITE, sizeof(int));
+ _(TIOCLINUX, READ, sizeof(char));
+ _(TIOCSERCONFIG, NONE, 0);
+ _(TIOCSERGETLSR, WRITE, sizeof(int));
+ _(TIOCSERGWILD, WRITE, sizeof(int));
+ _(TIOCSERSWILD, READ, sizeof(int));
+ _(TIOCSLCKTRMIOS, READ, struct_termios_sz);
+ _(TIOCSSOFTCAR, READ, sizeof(int));
+ _(VT_ACTIVATE, NONE, 0);
+ _(VT_DISALLOCATE, NONE, 0);
+ _(VT_GETMODE, WRITE, struct_vt_mode_sz);
+ _(VT_GETSTATE, WRITE, struct_vt_stat_sz);
+ _(VT_OPENQRY, WRITE, sizeof(int));
+ _(VT_RELDISP, NONE, 0);
+ _(VT_RESIZE, READ, struct_vt_sizes_sz);
+ _(VT_RESIZEX, READ, struct_vt_consize_sz);
+ _(VT_SENDSIG, NONE, 0);
+ _(VT_SETMODE, READ, struct_vt_mode_sz);
+ _(VT_WAITACTIVE, NONE, 0);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
+ _(CYGETDEFTHRESH, WRITE, sizeof(int));
+ _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
+ _(CYGETMON, WRITE, struct_cyclades_monitor_sz);
+ _(CYGETTHRESH, WRITE, sizeof(int));
+ _(CYGETTIMEOUT, WRITE, sizeof(int));
+ _(CYSETDEFTHRESH, NONE, 0);
+ _(CYSETDEFTIMEOUT, NONE, 0);
+ _(CYSETTHRESH, NONE, 0);
+ _(CYSETTIMEOUT, NONE, 0);
+ _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz);
+ _(EQL_ENSLAVE, WRITE, struct_ifreq_sz);
+ _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz);
+ _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz);
+ _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz);
+ _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz);
+ _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz);
+ _(EVIOCGPROP, WRITE, 0);
+ _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz);
+ _(FS_IOC_GETFLAGS, WRITE, sizeof(int));
+ _(FS_IOC_GETVERSION, WRITE, sizeof(int));
+ _(FS_IOC_SETFLAGS, READ, sizeof(int));
+ _(FS_IOC_SETVERSION, READ, sizeof(int));
+ _(GIO_CMAP, WRITE, 48);
+ _(GIO_FONT, WRITE, 8192);
+ _(GIO_SCRNMAP, WRITE, e_tabsz);
+ _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz);
+ _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz);
+ _(KDADDIO, NONE, 0);
+ _(KDDELIO, NONE, 0);
+ _(KDDISABIO, NONE, 0);
+ _(KDENABIO, NONE, 0);
+ _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz);
+ _(KDGETLED, WRITE, 1);
+ _(KDGETMODE, WRITE, sizeof(int));
+ _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz);
+ _(KDGKBENT, WRITE, struct_kbentry_sz);
+ _(KDGKBLED, WRITE, sizeof(int));
+ _(KDGKBMETA, WRITE, sizeof(int));
+ _(KDGKBMODE, WRITE, sizeof(int));
+ _(KDGKBSENT, WRITE, struct_kbsentry_sz);
+ _(KDGKBTYPE, WRITE, 1);
+ _(KDMAPDISP, NONE, 0);
+ _(KDMKTONE, NONE, 0);
+ _(KDSETKEYCODE, READ, struct_kbkeycode_sz);
+ _(KDSETLED, NONE, 0);
+ _(KDSETMODE, NONE, 0);
+ _(KDSIGACCEPT, NONE, 0);
+ _(KDSKBDIACR, READ, struct_kbdiacrs_sz);
+ _(KDSKBENT, READ, struct_kbentry_sz);
+ _(KDSKBLED, NONE, 0);
+ _(KDSKBMETA, NONE, 0);
+ _(KDSKBMODE, NONE, 0);
+ _(KDSKBSENT, READ, struct_kbsentry_sz);
+ _(KDUNMAPDISP, NONE, 0);
+ _(KIOCSOUND, NONE, 0);
+ _(LPABORT, NONE, 0);
+ _(LPABORTOPEN, NONE, 0);
+ _(LPCAREFUL, NONE, 0);
+ _(LPCHAR, NONE, 0);
+ _(LPGETIRQ, WRITE, sizeof(int));
+ _(LPGETSTATUS, WRITE, sizeof(int));
+ _(LPRESET, NONE, 0);
+ _(LPSETIRQ, NONE, 0);
+ _(LPTIME, NONE, 0);
+ _(LPWAIT, NONE, 0);
+ _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz);
+ _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz);
+ _(PIO_CMAP, NONE, 0);
+ _(PIO_FONT, READ, 8192);
+ _(PIO_SCRNMAP, READ, e_tabsz);
+ _(PIO_UNIMAP, READ, struct_unimapdesc_sz);
+ _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz);
+ _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz);
+ _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int));
+ _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0);
+ _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0);
+ _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz);
+ _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz);
+ _(TIOCGSERIAL, WRITE, struct_serial_struct_sz);
+ _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz);
+ _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz);
+ _(TIOCSSERIAL, READ, struct_serial_struct_sz);
+
+ // The following ioctl requests are shared between AX25, IPX, netrom and
+ // mrouted.
+ // _(SIOCAIPXITFCRT, READ, sizeof(char));
+ // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz);
+ // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz);
+ // _(SIOCAIPXPRISLT, READ, sizeof(char));
+ // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz);
+ // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz);
+ // _(SIOCNRDECOBS, NONE, 0);
+ // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz);
+ // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz);
+ // _(SIOCAX25NOUID, READ, sizeof(int));
+ // _(SIOCNRRTCTL, READ, sizeof(int));
+ // _(SIOCAX25DIGCTL, READ, sizeof(int));
+ // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz);
+ // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz);
+#endif
+#undef _
+}
+
+static bool ioctl_initialized = false;
+
+struct ioctl_desc_compare {
+ bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {
+ return left.req < right.req;
+ }
+};
+
+static void ioctl_init() {
+ ioctl_table_fill();
+ InternalSort(&ioctl_table, ioctl_table_size, ioctl_desc_compare());
+
+ bool bad = false;
+ for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {
+ if (ioctl_table[i].req >= ioctl_table[i + 1].req) {
+ Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n",
+ ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,
+ ioctl_table[i + 1].name);
+ bad = true;
+ }
+ }
+
+ if (bad) Die();
+
+ ioctl_initialized = true;
+}
+
+// Handle the most evil ioctls that encode argument value as part of request id.
+static unsigned ioctl_request_fixup(unsigned req) {
+#if SANITIZER_LINUX
+ // Strip size and event number.
+ const unsigned kEviocgbitMask =
+ (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX;
+ if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT)
+ return IOCTL_EVIOCGBIT;
+ // Strip absolute axis number.
+ if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS)
+ return IOCTL_EVIOCGABS;
+ if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS)
+ return IOCTL_EVIOCSABS;
+#endif
+ return req;
+}
+
+static const ioctl_desc *ioctl_table_lookup(unsigned req) {
+ int left = 0;
+ int right = ioctl_table_size;
+ while (left < right) {
+ int mid = (left + right) / 2;
+ if (ioctl_table[mid].req < req)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left == right && ioctl_table[left].req == req)
+ return ioctl_table + left;
+ else
+ return 0;
+}
+
+static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
+ CHECK(desc);
+ desc->req = req;
+ desc->name = "<DECODED_IOCTL>";
+ desc->size = IOC_SIZE(req);
+ // Sanity check.
+ if (desc->size > 0xFFFF) return false;
+ unsigned dir = IOC_DIR(req);
+ switch (dir) {
+ case IOC_NONE:
+ desc->type = ioctl_desc::NONE;
+ break;
+ case IOC_READ | IOC_WRITE:
+ desc->type = ioctl_desc::READWRITE;
+ break;
+ case IOC_READ:
+ desc->type = ioctl_desc::WRITE;
+ break;
+ case IOC_WRITE:
+ desc->type = ioctl_desc::READ;
+ break;
+ default:
+ return false;
+ }
+ // Size can be 0 iff type is NONE.
+ if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;
+ // Sanity check.
+ if (IOC_TYPE(req) == 0) return false;
+ return true;
+}
+
+static const ioctl_desc *ioctl_lookup(unsigned req) {
+ req = ioctl_request_fixup(req);
+ const ioctl_desc *desc = ioctl_table_lookup(req);
+ if (desc) return desc;
+
+ // Try stripping access size from the request id.
+ desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));
+ // Sanity check: requests that encode access size are either read or write and
+ // have size of 0 in the table.
+ if (desc && desc->size == 0 &&
+ (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||
+ desc->type == ioctl_desc::READ))
+ return desc;
+ return 0;
+}
+
+static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
+ unsigned request, void *arg) {
+ if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {
+ unsigned size = desc->size ? desc->size : IOC_SIZE(request);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);
+ }
+ if (desc->type != ioctl_desc::CUSTOM)
+ return;
+ switch (request) {
+ case 0x00008912: { // SIOCGIFCONF
+ struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &ifc->ifc_len, sizeof(ifc->ifc_len));
+ break;
+ }
+ }
+ return;
+}
+
+static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,
+ unsigned request, void *arg) {
+ if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {
+ // FIXME: add verbose output
+ unsigned size = desc->size ? desc->size : IOC_SIZE(request);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);
+ }
+ if (desc->type != ioctl_desc::CUSTOM)
+ return;
+ switch (request) {
+ case 0x00008912: { // SIOCGIFCONF
+ struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);
+ break;
+ }
+ }
+ return;
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc
new file mode 100644
index 000000000000..17ef6897ba26
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -0,0 +1,135 @@
+//===-- sanitizer_common_libcdep.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_stackdepot.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+bool ReportFile::PrintsToTty() {
+ SpinMutexLock l(mu);
+ ReopenIfNecessary();
+ return internal_isatty(fd) != 0;
+}
+
+bool ColorizeReports() {
+ // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
+ // printing on Windows.
+ if (SANITIZER_WINDOWS)
+ return false;
+
+ const char *flag = common_flags()->color;
+ return internal_strcmp(flag, "always") == 0 ||
+ (internal_strcmp(flag, "auto") == 0 && report_file.PrintsToTty());
+}
+
+static void (*sandboxing_callback)();
+void SetSandboxingCallback(void (*f)()) {
+ sandboxing_callback = f;
+}
+
+void ReportErrorSummary(const char *error_type, StackTrace *stack) {
+ if (!common_flags()->print_summary)
+ return;
+#if !SANITIZER_GO
+ if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) {
+ // Currently, we include the first stack frame into the report summary.
+ // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
+ uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+ SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+ const AddressInfo &ai = frame->info;
+ ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
+ frame->ClearAll();
+ }
+#else
+ AddressInfo ai;
+ ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
+#endif
+}
+
+static void (*SoftRssLimitExceededCallback)(bool exceeded);
+void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
+ CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
+ SoftRssLimitExceededCallback = Callback;
+}
+
+void BackgroundThread(void *arg) {
+ uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
+ uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
+ uptr prev_reported_rss = 0;
+ uptr prev_reported_stack_depot_size = 0;
+ bool reached_soft_rss_limit = false;
+ while (true) {
+ SleepForMillis(100);
+ uptr current_rss_mb = GetRSS() >> 20;
+ if (Verbosity()) {
+ // If RSS has grown 10% since last time, print some information.
+ if (prev_reported_rss * 11 / 10 < current_rss_mb) {
+ Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
+ prev_reported_rss = current_rss_mb;
+ }
+ // If stack depot has grown 10% since last time, print it too.
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ if (prev_reported_stack_depot_size * 11 / 10 <
+ stack_depot_stats->allocated) {
+ Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
+ SanitizerToolName,
+ stack_depot_stats->n_uniq_ids,
+ stack_depot_stats->allocated >> 20);
+ prev_reported_stack_depot_size = stack_depot_stats->allocated;
+ }
+ }
+ // Check RSS against the limit.
+ if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
+ Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
+ SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
+ DumpProcessMap();
+ Die();
+ }
+ if (soft_rss_limit_mb) {
+ if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
+ reached_soft_rss_limit = true;
+ Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
+ SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
+ if (SoftRssLimitExceededCallback)
+ SoftRssLimitExceededCallback(true);
+ } else if (soft_rss_limit_mb >= current_rss_mb &&
+ reached_soft_rss_limit) {
+ reached_soft_rss_limit = false;
+ if (SoftRssLimitExceededCallback)
+ SoftRssLimitExceededCallback(false);
+ }
+ }
+ }
+}
+
+void MaybeStartBackgroudThread() {
+ if (!SANITIZER_LINUX) return; // Need to implement/test on other platforms.
+ // Start the background thread if one of the rss limits is given.
+ if (!common_flags()->hard_rss_limit_mb &&
+ !common_flags()->soft_rss_limit_mb) return;
+ if (!&real_pthread_create) return; // Can't spawn the thread anyway.
+ internal_start_thread(BackgroundThread, nullptr);
+}
+
+} // namespace __sanitizer
+
+void NOINLINE
+__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
+ PrepareForSandboxing(args);
+ if (sandboxing_callback)
+ sandboxing_callback();
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
new file mode 100644
index 000000000000..7e15d51ff35b
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -0,0 +1,2852 @@
+//===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common syscalls handlers for tools like AddressSanitizer,
+// ThreadSanitizer, MemorySanitizer, etc.
+//
+// This file should be included into the tool's interceptor file,
+// which has to define it's own macros:
+// COMMON_SYSCALL_PRE_READ_RANGE
+// Called in prehook for regions that will be read by the kernel and
+// must be initialized.
+// COMMON_SYSCALL_PRE_WRITE_RANGE
+// Called in prehook for regions that will be written to by the kernel
+// and must be addressable. The actual write range may be smaller than
+// reported in the prehook. See POST_WRITE_RANGE.
+// COMMON_SYSCALL_POST_READ_RANGE
+// Called in posthook for regions that were read by the kernel. Does
+// not make much sense.
+// COMMON_SYSCALL_POST_WRITE_RANGE
+// Called in posthook for regions that were written to by the kernel
+// and are now initialized.
+// COMMON_SYSCALL_ACQUIRE(addr)
+// Acquire memory visibility from addr.
+// COMMON_SYSCALL_RELEASE(addr)
+// Release memory visibility to addr.
+// COMMON_SYSCALL_FD_CLOSE(fd)
+// Called before closing file descriptor fd.
+// COMMON_SYSCALL_FD_ACQUIRE(fd)
+// Acquire memory visibility from fd.
+// COMMON_SYSCALL_FD_RELEASE(fd)
+// Release memory visibility to fd.
+// COMMON_SYSCALL_PRE_FORK()
+// Called before fork syscall.
+// COMMON_SYSCALL_POST_FORK(long res)
+// Called after fork syscall.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_libc.h"
+
+#define PRE_SYSCALL(name) \
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name
+#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)
+#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
+
+#define POST_SYSCALL(name) \
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name
+#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
+#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+
+#ifndef COMMON_SYSCALL_ACQUIRE
+# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))
+#endif
+
+#ifndef COMMON_SYSCALL_RELEASE
+# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_CLOSE
+# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_ACQUIRE
+# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_RELEASE
+# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_PRE_FORK
+# define COMMON_SYSCALL_PRE_FORK() {}
+#endif
+
+#ifndef COMMON_SYSCALL_POST_FORK
+# define COMMON_SYSCALL_POST_FORK(res) {}
+#endif
+
+// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
+
+extern "C" {
+struct sanitizer_kernel_iovec {
+ void *iov_base;
+ unsigned long iov_len;
+};
+
+struct sanitizer_kernel_msghdr {
+ void *msg_name;
+ int msg_namelen;
+ struct sanitizer_kernel_iovec *msg_iov;
+ unsigned long msg_iovlen;
+ void *msg_control;
+ unsigned long msg_controllen;
+ unsigned msg_flags;
+};
+
+struct sanitizer_kernel_mmsghdr {
+ struct sanitizer_kernel_msghdr msg_hdr;
+ unsigned msg_len;
+};
+
+struct sanitizer_kernel_timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+
+struct sanitizer_kernel_timeval {
+ long tv_sec;
+ long tv_usec;
+};
+
+struct sanitizer_kernel_rusage {
+ struct sanitizer_kernel_timeval ru_timeval[2];
+ long ru_long[14];
+};
+
+struct sanitizer_kernel_sockaddr {
+ unsigned short sa_family;
+ char sa_data[14];
+};
+
+// Real sigset size is always passed as a syscall argument.
+// Declare it "void" to catch sizeof(kernel_sigset_t).
+typedef void kernel_sigset_t;
+
+static void kernel_write_iovec(const __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ POST_WRITE(iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+// This functions uses POST_READ, because it needs to run after syscall to know
+// the real read range.
+static void kernel_read_iovec(const __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ POST_READ(iovec, sizeof(*iovec) * iovlen);
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ POST_READ(iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+PRE_SYSCALL(recvmsg)(long sockfd, sanitizer_kernel_msghdr *msg, long flags) {
+ PRE_READ(msg, sizeof(*msg));
+}
+
+POST_SYSCALL(recvmsg)(long res, long sockfd, sanitizer_kernel_msghdr *msg,
+ long flags) {
+ if (res >= 0) {
+ if (msg) {
+ for (unsigned long i = 0; i < msg->msg_iovlen; ++i) {
+ POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
+ }
+ POST_WRITE(msg->msg_control, msg->msg_controllen);
+ }
+ }
+}
+
+PRE_SYSCALL(recvmmsg)(long fd, sanitizer_kernel_mmsghdr *msg, long vlen,
+ long flags, void *timeout) {
+ PRE_READ(msg, vlen * sizeof(*msg));
+}
+
+POST_SYSCALL(recvmmsg)(long res, long fd, sanitizer_kernel_mmsghdr *msg,
+ long vlen, long flags, void *timeout) {
+ if (res >= 0) {
+ if (msg) {
+ for (unsigned long i = 0; i < msg->msg_hdr.msg_iovlen; ++i) {
+ POST_WRITE(msg->msg_hdr.msg_iov[i].iov_base,
+ msg->msg_hdr.msg_iov[i].iov_len);
+ }
+ POST_WRITE(msg->msg_hdr.msg_control, msg->msg_hdr.msg_controllen);
+ POST_WRITE(&msg->msg_len, sizeof(msg->msg_len));
+ }
+ if (timeout) POST_WRITE(timeout, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(read)(long fd, void *buf, uptr count) {
+ if (buf) {
+ PRE_WRITE(buf, count);
+ }
+}
+
+POST_SYSCALL(read)(long res, long fd, void *buf, uptr count) {
+ if (res > 0 && buf) {
+ POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(time)(void *tloc) {}
+
+POST_SYSCALL(time)(long res, void *tloc) {
+ if (res >= 0) {
+ if (tloc) POST_WRITE(tloc, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(stime)(void *tptr) {}
+
+POST_SYSCALL(stime)(long res, void *tptr) {
+ if (res >= 0) {
+ if (tptr) POST_WRITE(tptr, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(gettimeofday)(void *tv, void *tz) {}
+
+POST_SYSCALL(gettimeofday)(long res, void *tv, void *tz) {
+ if (res >= 0) {
+ if (tv) POST_WRITE(tv, timeval_sz);
+ if (tz) POST_WRITE(tz, struct_timezone_sz);
+ }
+}
+
+PRE_SYSCALL(settimeofday)(void *tv, void *tz) {}
+
+POST_SYSCALL(settimeofday)(long res, void *tv, void *tz) {
+ if (res >= 0) {
+ if (tv) POST_WRITE(tv, timeval_sz);
+ if (tz) POST_WRITE(tz, struct_timezone_sz);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(adjtimex)(void *txc_p) {}
+
+POST_SYSCALL(adjtimex)(long res, void *txc_p) {
+ if (res >= 0) {
+ if (txc_p) POST_WRITE(txc_p, struct_timex_sz);
+ }
+}
+#endif
+
+PRE_SYSCALL(times)(void *tbuf) {}
+
+POST_SYSCALL(times)(long res, void *tbuf) {
+ if (res >= 0) {
+ if (tbuf) POST_WRITE(tbuf, struct_tms_sz);
+ }
+}
+
+PRE_SYSCALL(gettid)() {}
+
+POST_SYSCALL(gettid)(long res) {}
+
+PRE_SYSCALL(nanosleep)(void *rqtp, void *rmtp) {}
+
+POST_SYSCALL(nanosleep)(long res, void *rqtp, void *rmtp) {
+ if (res >= 0) {
+ if (rqtp) POST_WRITE(rqtp, struct_timespec_sz);
+ if (rmtp) POST_WRITE(rmtp, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(alarm)(long seconds) {}
+
+POST_SYSCALL(alarm)(long res, long seconds) {}
+
+PRE_SYSCALL(getpid)() {}
+
+POST_SYSCALL(getpid)(long res) {}
+
+PRE_SYSCALL(getppid)() {}
+
+POST_SYSCALL(getppid)(long res) {}
+
+PRE_SYSCALL(getuid)() {}
+
+POST_SYSCALL(getuid)(long res) {}
+
+PRE_SYSCALL(geteuid)() {}
+
+POST_SYSCALL(geteuid)(long res) {}
+
+PRE_SYSCALL(getgid)() {}
+
+POST_SYSCALL(getgid)(long res) {}
+
+PRE_SYSCALL(getegid)() {}
+
+POST_SYSCALL(getegid)(long res) {}
+
+PRE_SYSCALL(getresuid)(void *ruid, void *euid, void *suid) {}
+
+POST_SYSCALL(getresuid)(long res, void *ruid, void *euid, void *suid) {
+ if (res >= 0) {
+ if (ruid) POST_WRITE(ruid, sizeof(unsigned));
+ if (euid) POST_WRITE(euid, sizeof(unsigned));
+ if (suid) POST_WRITE(suid, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getresgid)(void *rgid, void *egid, void *sgid) {}
+
+POST_SYSCALL(getresgid)(long res, void *rgid, void *egid, void *sgid) {
+ if (res >= 0) {
+ if (rgid) POST_WRITE(rgid, sizeof(unsigned));
+ if (egid) POST_WRITE(egid, sizeof(unsigned));
+ if (sgid) POST_WRITE(sgid, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getpgid)(long pid) {}
+
+POST_SYSCALL(getpgid)(long res, long pid) {}
+
+PRE_SYSCALL(getpgrp)() {}
+
+POST_SYSCALL(getpgrp)(long res) {}
+
+PRE_SYSCALL(getsid)(long pid) {}
+
+POST_SYSCALL(getsid)(long res, long pid) {}
+
+PRE_SYSCALL(getgroups)(long gidsetsize, void *grouplist) {}
+
+POST_SYSCALL(getgroups)(long res, long gidsetsize,
+ __sanitizer___kernel_gid_t *grouplist) {
+ if (res >= 0) {
+ if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist));
+ }
+}
+
+PRE_SYSCALL(setregid)(long rgid, long egid) {}
+
+POST_SYSCALL(setregid)(long res, long rgid, long egid) {}
+
+PRE_SYSCALL(setgid)(long gid) {}
+
+POST_SYSCALL(setgid)(long res, long gid) {}
+
+PRE_SYSCALL(setreuid)(long ruid, long euid) {}
+
+POST_SYSCALL(setreuid)(long res, long ruid, long euid) {}
+
+PRE_SYSCALL(setuid)(long uid) {}
+
+POST_SYSCALL(setuid)(long res, long uid) {}
+
+PRE_SYSCALL(setresuid)(long ruid, long euid, long suid) {}
+
+POST_SYSCALL(setresuid)(long res, long ruid, long euid, long suid) {}
+
+PRE_SYSCALL(setresgid)(long rgid, long egid, long sgid) {}
+
+POST_SYSCALL(setresgid)(long res, long rgid, long egid, long sgid) {}
+
+PRE_SYSCALL(setfsuid)(long uid) {}
+
+POST_SYSCALL(setfsuid)(long res, long uid) {}
+
+PRE_SYSCALL(setfsgid)(long gid) {}
+
+POST_SYSCALL(setfsgid)(long res, long gid) {}
+
+PRE_SYSCALL(setpgid)(long pid, long pgid) {}
+
+POST_SYSCALL(setpgid)(long res, long pid, long pgid) {}
+
+PRE_SYSCALL(setsid)() {}
+
+POST_SYSCALL(setsid)(long res) {}
+
+PRE_SYSCALL(setgroups)(long gidsetsize, __sanitizer___kernel_gid_t *grouplist) {
+ if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist));
+}
+
+POST_SYSCALL(setgroups)(long res, long gidsetsize,
+ __sanitizer___kernel_gid_t *grouplist) {}
+
+PRE_SYSCALL(acct)(const void *name) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(acct)(long res, const void *name) {}
+
+PRE_SYSCALL(capget)(void *header, void *dataptr) {
+ if (header) PRE_READ(header, __user_cap_header_struct_sz);
+}
+
+POST_SYSCALL(capget)(long res, void *header, void *dataptr) {
+ if (res >= 0)
+ if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz);
+}
+
+PRE_SYSCALL(capset)(void *header, const void *data) {
+ if (header) PRE_READ(header, __user_cap_header_struct_sz);
+ if (data) PRE_READ(data, __user_cap_data_struct_sz);
+}
+
+POST_SYSCALL(capset)(long res, void *header, const void *data) {}
+
+PRE_SYSCALL(personality)(long personality) {}
+
+POST_SYSCALL(personality)(long res, long personality) {}
+
+PRE_SYSCALL(sigpending)(void *set) {}
+
+POST_SYSCALL(sigpending)(long res, void *set) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, old_sigset_t_sz);
+ }
+}
+
+PRE_SYSCALL(sigprocmask)(long how, void *set, void *oset) {}
+
+POST_SYSCALL(sigprocmask)(long res, long how, void *set, void *oset) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, old_sigset_t_sz);
+ if (oset) POST_WRITE(oset, old_sigset_t_sz);
+ }
+}
+
+PRE_SYSCALL(getitimer)(long which, void *value) {}
+
+POST_SYSCALL(getitimer)(long res, long which, void *value) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, struct_itimerval_sz);
+ }
+}
+
+PRE_SYSCALL(setitimer)(long which, void *value, void *ovalue) {}
+
+POST_SYSCALL(setitimer)(long res, long which, void *value, void *ovalue) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, struct_itimerval_sz);
+ if (ovalue) POST_WRITE(ovalue, struct_itimerval_sz);
+ }
+}
+
+PRE_SYSCALL(timer_create)(long which_clock, void *timer_event_spec,
+ void *created_timer_id) {}
+
+POST_SYSCALL(timer_create)(long res, long which_clock, void *timer_event_spec,
+ void *created_timer_id) {
+ if (res >= 0) {
+ if (timer_event_spec) POST_WRITE(timer_event_spec, struct_sigevent_sz);
+ if (created_timer_id) POST_WRITE(created_timer_id, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(timer_gettime)(long timer_id, void *setting) {}
+
+POST_SYSCALL(timer_gettime)(long res, long timer_id, void *setting) {
+ if (res >= 0) {
+ if (setting) POST_WRITE(setting, struct_itimerspec_sz);
+ }
+}
+
+PRE_SYSCALL(timer_getoverrun)(long timer_id) {}
+
+POST_SYSCALL(timer_getoverrun)(long res, long timer_id) {}
+
+PRE_SYSCALL(timer_settime)(long timer_id, long flags, const void *new_setting,
+ void *old_setting) {
+ if (new_setting) PRE_READ(new_setting, struct_itimerspec_sz);
+}
+
+POST_SYSCALL(timer_settime)(long res, long timer_id, long flags,
+ const void *new_setting, void *old_setting) {
+ if (res >= 0) {
+ if (old_setting) POST_WRITE(old_setting, struct_itimerspec_sz);
+ }
+}
+
+PRE_SYSCALL(timer_delete)(long timer_id) {}
+
+POST_SYSCALL(timer_delete)(long res, long timer_id) {}
+
+PRE_SYSCALL(clock_settime)(long which_clock, const void *tp) {
+ if (tp) PRE_READ(tp, struct_timespec_sz);
+}
+
+POST_SYSCALL(clock_settime)(long res, long which_clock, const void *tp) {}
+
+PRE_SYSCALL(clock_gettime)(long which_clock, void *tp) {}
+
+POST_SYSCALL(clock_gettime)(long res, long which_clock, void *tp) {
+ if (res >= 0) {
+ if (tp) POST_WRITE(tp, struct_timespec_sz);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(clock_adjtime)(long which_clock, void *tx) {}
+
+POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) {
+ if (res >= 0) {
+ if (tx) POST_WRITE(tx, struct_timex_sz);
+ }
+}
+#endif
+
+PRE_SYSCALL(clock_getres)(long which_clock, void *tp) {}
+
+POST_SYSCALL(clock_getres)(long res, long which_clock, void *tp) {
+ if (res >= 0) {
+ if (tp) POST_WRITE(tp, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(clock_nanosleep)(long which_clock, long flags, const void *rqtp,
+ void *rmtp) {
+ if (rqtp) PRE_READ(rqtp, struct_timespec_sz);
+}
+
+POST_SYSCALL(clock_nanosleep)(long res, long which_clock, long flags,
+ const void *rqtp, void *rmtp) {
+ if (res >= 0) {
+ if (rmtp) POST_WRITE(rmtp, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(nice)(long increment) {}
+
+POST_SYSCALL(nice)(long res, long increment) {}
+
+PRE_SYSCALL(sched_setscheduler)(long pid, long policy, void *param) {}
+
+POST_SYSCALL(sched_setscheduler)(long res, long pid, long policy, void *param) {
+ if (res >= 0) {
+ if (param) POST_WRITE(param, struct_sched_param_sz);
+ }
+}
+
+PRE_SYSCALL(sched_setparam)(long pid, void *param) {
+ if (param) PRE_READ(param, struct_sched_param_sz);
+}
+
+POST_SYSCALL(sched_setparam)(long res, long pid, void *param) {}
+
+PRE_SYSCALL(sched_getscheduler)(long pid) {}
+
+POST_SYSCALL(sched_getscheduler)(long res, long pid) {}
+
+PRE_SYSCALL(sched_getparam)(long pid, void *param) {}
+
+POST_SYSCALL(sched_getparam)(long res, long pid, void *param) {
+ if (res >= 0) {
+ if (param) POST_WRITE(param, struct_sched_param_sz);
+ }
+}
+
+PRE_SYSCALL(sched_setaffinity)(long pid, long len, void *user_mask_ptr) {
+ if (user_mask_ptr) PRE_READ(user_mask_ptr, len);
+}
+
+POST_SYSCALL(sched_setaffinity)(long res, long pid, long len,
+ void *user_mask_ptr) {}
+
+PRE_SYSCALL(sched_getaffinity)(long pid, long len, void *user_mask_ptr) {}
+
+POST_SYSCALL(sched_getaffinity)(long res, long pid, long len,
+ void *user_mask_ptr) {
+ if (res >= 0) {
+ if (user_mask_ptr) POST_WRITE(user_mask_ptr, len);
+ }
+}
+
+PRE_SYSCALL(sched_yield)() {}
+
+POST_SYSCALL(sched_yield)(long res) {}
+
+PRE_SYSCALL(sched_get_priority_max)(long policy) {}
+
+POST_SYSCALL(sched_get_priority_max)(long res, long policy) {}
+
+PRE_SYSCALL(sched_get_priority_min)(long policy) {}
+
+POST_SYSCALL(sched_get_priority_min)(long res, long policy) {}
+
+PRE_SYSCALL(sched_rr_get_interval)(long pid, void *interval) {}
+
+POST_SYSCALL(sched_rr_get_interval)(long res, long pid, void *interval) {
+ if (res >= 0) {
+ if (interval) POST_WRITE(interval, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(setpriority)(long which, long who, long niceval) {}
+
+POST_SYSCALL(setpriority)(long res, long which, long who, long niceval) {}
+
+PRE_SYSCALL(getpriority)(long which, long who) {}
+
+POST_SYSCALL(getpriority)(long res, long which, long who) {}
+
+PRE_SYSCALL(shutdown)(long arg0, long arg1) {}
+
+POST_SYSCALL(shutdown)(long res, long arg0, long arg1) {}
+
+PRE_SYSCALL(reboot)(long magic1, long magic2, long cmd, void *arg) {}
+
+POST_SYSCALL(reboot)(long res, long magic1, long magic2, long cmd, void *arg) {}
+
+PRE_SYSCALL(restart_syscall)() {}
+
+POST_SYSCALL(restart_syscall)(long res) {}
+
+PRE_SYSCALL(kexec_load)(long entry, long nr_segments, void *segments,
+ long flags) {}
+
+POST_SYSCALL(kexec_load)(long res, long entry, long nr_segments, void *segments,
+ long flags) {
+ if (res >= 0) {
+ if (segments) POST_WRITE(segments, struct_kexec_segment_sz);
+ }
+}
+
+PRE_SYSCALL(exit)(long error_code) {}
+
+POST_SYSCALL(exit)(long res, long error_code) {}
+
+PRE_SYSCALL(exit_group)(long error_code) {}
+
+POST_SYSCALL(exit_group)(long res, long error_code) {}
+
+PRE_SYSCALL(wait4)(long pid, void *stat_addr, long options, void *ru) {}
+
+POST_SYSCALL(wait4)(long res, long pid, void *stat_addr, long options,
+ void *ru) {
+ if (res >= 0) {
+ if (stat_addr) POST_WRITE(stat_addr, sizeof(int));
+ if (ru) POST_WRITE(ru, struct_rusage_sz);
+ }
+}
+
+PRE_SYSCALL(waitid)(long which, long pid, void *infop, long options, void *ru) {
+}
+
+POST_SYSCALL(waitid)(long res, long which, long pid, void *infop, long options,
+ void *ru) {
+ if (res >= 0) {
+ if (infop) POST_WRITE(infop, siginfo_t_sz);
+ if (ru) POST_WRITE(ru, struct_rusage_sz);
+ }
+}
+
+PRE_SYSCALL(waitpid)(long pid, void *stat_addr, long options) {}
+
+POST_SYSCALL(waitpid)(long res, long pid, void *stat_addr, long options) {
+ if (res >= 0) {
+ if (stat_addr) POST_WRITE(stat_addr, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(set_tid_address)(void *tidptr) {}
+
+POST_SYSCALL(set_tid_address)(long res, void *tidptr) {
+ if (res >= 0) {
+ if (tidptr) POST_WRITE(tidptr, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(init_module)(void *umod, long len, const void *uargs) {
+ if (uargs)
+ PRE_READ(uargs, __sanitizer::internal_strlen((const char *)uargs) + 1);
+}
+
+POST_SYSCALL(init_module)(long res, void *umod, long len, const void *uargs) {}
+
+PRE_SYSCALL(delete_module)(const void *name_user, long flags) {
+ if (name_user)
+ PRE_READ(name_user,
+ __sanitizer::internal_strlen((const char *)name_user) + 1);
+}
+
+POST_SYSCALL(delete_module)(long res, const void *name_user, long flags) {}
+
+PRE_SYSCALL(rt_sigprocmask)(long how, void *set, void *oset, long sigsetsize) {}
+
+POST_SYSCALL(rt_sigprocmask)(long res, long how, kernel_sigset_t *set,
+ kernel_sigset_t *oset, long sigsetsize) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, sigsetsize);
+ if (oset) POST_WRITE(oset, sigsetsize);
+ }
+}
+
+PRE_SYSCALL(rt_sigpending)(void *set, long sigsetsize) {}
+
+POST_SYSCALL(rt_sigpending)(long res, kernel_sigset_t *set, long sigsetsize) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, sigsetsize);
+ }
+}
+
+PRE_SYSCALL(rt_sigtimedwait)(const kernel_sigset_t *uthese, void *uinfo,
+ const void *uts, long sigsetsize) {
+ if (uthese) PRE_READ(uthese, sigsetsize);
+ if (uts) PRE_READ(uts, struct_timespec_sz);
+}
+
+POST_SYSCALL(rt_sigtimedwait)(long res, const void *uthese, void *uinfo,
+ const void *uts, long sigsetsize) {
+ if (res >= 0) {
+ if (uinfo) POST_WRITE(uinfo, siginfo_t_sz);
+ }
+}
+
+PRE_SYSCALL(rt_tgsigqueueinfo)(long tgid, long pid, long sig, void *uinfo) {}
+
+POST_SYSCALL(rt_tgsigqueueinfo)(long res, long tgid, long pid, long sig,
+ void *uinfo) {
+ if (res >= 0) {
+ if (uinfo) POST_WRITE(uinfo, siginfo_t_sz);
+ }
+}
+
+PRE_SYSCALL(kill)(long pid, long sig) {}
+
+POST_SYSCALL(kill)(long res, long pid, long sig) {}
+
+PRE_SYSCALL(tgkill)(long tgid, long pid, long sig) {}
+
+POST_SYSCALL(tgkill)(long res, long tgid, long pid, long sig) {}
+
+PRE_SYSCALL(tkill)(long pid, long sig) {}
+
+POST_SYSCALL(tkill)(long res, long pid, long sig) {}
+
+PRE_SYSCALL(rt_sigqueueinfo)(long pid, long sig, void *uinfo) {}
+
+POST_SYSCALL(rt_sigqueueinfo)(long res, long pid, long sig, void *uinfo) {
+ if (res >= 0) {
+ if (uinfo) POST_WRITE(uinfo, siginfo_t_sz);
+ }
+}
+
+PRE_SYSCALL(sgetmask)() {}
+
+POST_SYSCALL(sgetmask)(long res) {}
+
+PRE_SYSCALL(ssetmask)(long newmask) {}
+
+POST_SYSCALL(ssetmask)(long res, long newmask) {}
+
+PRE_SYSCALL(signal)(long sig, long handler) {}
+
+POST_SYSCALL(signal)(long res, long sig, long handler) {}
+
+PRE_SYSCALL(pause)() {}
+
+POST_SYSCALL(pause)(long res) {}
+
+PRE_SYSCALL(sync)() {}
+
+POST_SYSCALL(sync)(long res) {}
+
+PRE_SYSCALL(fsync)(long fd) {}
+
+POST_SYSCALL(fsync)(long res, long fd) {}
+
+PRE_SYSCALL(fdatasync)(long fd) {}
+
+POST_SYSCALL(fdatasync)(long res, long fd) {}
+
+PRE_SYSCALL(bdflush)(long func, long data) {}
+
+POST_SYSCALL(bdflush)(long res, long func, long data) {}
+
+PRE_SYSCALL(mount)(void *dev_name, void *dir_name, void *type, long flags,
+ void *data) {}
+
+POST_SYSCALL(mount)(long res, void *dev_name, void *dir_name, void *type,
+ long flags, void *data) {
+ if (res >= 0) {
+ if (dev_name)
+ POST_WRITE(dev_name,
+ __sanitizer::internal_strlen((const char *)dev_name) + 1);
+ if (dir_name)
+ POST_WRITE(dir_name,
+ __sanitizer::internal_strlen((const char *)dir_name) + 1);
+ if (type)
+ POST_WRITE(type, __sanitizer::internal_strlen((const char *)type) + 1);
+ }
+}
+
+PRE_SYSCALL(umount)(void *name, long flags) {}
+
+POST_SYSCALL(umount)(long res, void *name, long flags) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(oldumount)(void *name) {}
+
+POST_SYSCALL(oldumount)(long res, void *name) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(truncate)(const void *path, long length) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(truncate)(long res, const void *path, long length) {}
+
+PRE_SYSCALL(ftruncate)(long fd, long length) {}
+
+POST_SYSCALL(ftruncate)(long res, long fd, long length) {}
+
+PRE_SYSCALL(stat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(statfs)(const void *path, void *buf) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(statfs)(long res, const void *path, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs_sz);
+ }
+}
+
+PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs64_sz);
+ }
+}
+
+PRE_SYSCALL(fstatfs)(long fd, void *buf) {}
+
+POST_SYSCALL(fstatfs)(long res, long fd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs_sz);
+ }
+}
+
+PRE_SYSCALL(fstatfs64)(long fd, long sz, void *buf) {}
+
+POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs64_sz);
+ }
+}
+#endif // !SANITIZER_ANDROID
+
+PRE_SYSCALL(lstat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lstat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(fstat)(long fd, void *statbuf) {}
+
+POST_SYSCALL(fstat)(long res, long fd, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(newstat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(newstat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(newlstat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(newlstat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(newfstat)(long fd, void *statbuf) {}
+
+POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(ustat)(long dev, void *ubuf) {}
+
+POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
+ if (res >= 0) {
+ if (ubuf) POST_WRITE(ubuf, struct_ustat_sz);
+ }
+}
+#endif // !SANITIZER_ANDROID
+
+PRE_SYSCALL(stat64)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(stat64)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(fstat64)(long fd, void *statbuf) {}
+
+POST_SYSCALL(fstat64)(long res, long fd, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(lstat64)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lstat64)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(setxattr)(const void *path, const void *name, const void *value,
+ long size, long flags) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ if (value) PRE_READ(value, size);
+}
+
+POST_SYSCALL(setxattr)(long res, const void *path, const void *name,
+ const void *value, long size, long flags) {}
+
+PRE_SYSCALL(lsetxattr)(const void *path, const void *name, const void *value,
+ long size, long flags) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ if (value) PRE_READ(value, size);
+}
+
+POST_SYSCALL(lsetxattr)(long res, const void *path, const void *name,
+ const void *value, long size, long flags) {}
+
+PRE_SYSCALL(fsetxattr)(long fd, const void *name, const void *value, long size,
+ long flags) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ if (value) PRE_READ(value, size);
+}
+
+POST_SYSCALL(fsetxattr)(long res, long fd, const void *name, const void *value,
+ long size, long flags) {}
+
+PRE_SYSCALL(getxattr)(const void *path, const void *name, void *value,
+ long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(getxattr)(long res, const void *path, const void *name,
+ void *value, long size) {
+ if (size && res > 0) {
+ if (value) POST_WRITE(value, res);
+ }
+}
+
+PRE_SYSCALL(lgetxattr)(const void *path, const void *name, void *value,
+ long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name,
+ void *value, long size) {
+ if (size && res > 0) {
+ if (value) POST_WRITE(value, res);
+ }
+}
+
+PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value,
+ long size) {
+ if (size && res > 0) {
+ if (value) POST_WRITE(value, res);
+ }
+}
+
+PRE_SYSCALL(listxattr)(const void *path, void *list, long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) {
+ if (size && res > 0) {
+ if (list) POST_WRITE(list, res);
+ }
+}
+
+PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) {
+ if (size && res > 0) {
+ if (list) POST_WRITE(list, res);
+ }
+}
+
+PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {}
+
+POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) {
+ if (size && res > 0) {
+ if (list) POST_WRITE(list, res);
+ }
+}
+
+PRE_SYSCALL(removexattr)(const void *path, const void *name) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(removexattr)(long res, const void *path, const void *name) {}
+
+PRE_SYSCALL(lremovexattr)(const void *path, const void *name) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(lremovexattr)(long res, const void *path, const void *name) {}
+
+PRE_SYSCALL(fremovexattr)(long fd, const void *name) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(fremovexattr)(long res, long fd, const void *name) {}
+
+PRE_SYSCALL(brk)(long brk) {}
+
+POST_SYSCALL(brk)(long res, long brk) {}
+
+PRE_SYSCALL(mprotect)(long start, long len, long prot) {}
+
+POST_SYSCALL(mprotect)(long res, long start, long len, long prot) {}
+
+PRE_SYSCALL(mremap)(long addr, long old_len, long new_len, long flags,
+ long new_addr) {}
+
+POST_SYSCALL(mremap)(long res, long addr, long old_len, long new_len,
+ long flags, long new_addr) {}
+
+PRE_SYSCALL(remap_file_pages)(long start, long size, long prot, long pgoff,
+ long flags) {}
+
+POST_SYSCALL(remap_file_pages)(long res, long start, long size, long prot,
+ long pgoff, long flags) {}
+
+PRE_SYSCALL(msync)(long start, long len, long flags) {}
+
+POST_SYSCALL(msync)(long res, long start, long len, long flags) {}
+
+PRE_SYSCALL(munmap)(long addr, long len) {}
+
+POST_SYSCALL(munmap)(long res, long addr, long len) {}
+
+PRE_SYSCALL(mlock)(long start, long len) {}
+
+POST_SYSCALL(mlock)(long res, long start, long len) {}
+
+PRE_SYSCALL(munlock)(long start, long len) {}
+
+POST_SYSCALL(munlock)(long res, long start, long len) {}
+
+PRE_SYSCALL(mlockall)(long flags) {}
+
+POST_SYSCALL(mlockall)(long res, long flags) {}
+
+PRE_SYSCALL(munlockall)() {}
+
+POST_SYSCALL(munlockall)(long res) {}
+
+PRE_SYSCALL(madvise)(long start, long len, long behavior) {}
+
+POST_SYSCALL(madvise)(long res, long start, long len, long behavior) {}
+
+PRE_SYSCALL(mincore)(long start, long len, void *vec) {}
+
+POST_SYSCALL(mincore)(long res, long start, long len, void *vec) {
+ if (res >= 0) {
+ if (vec) {
+ POST_WRITE(vec, (len + GetPageSizeCached() - 1) / GetPageSizeCached());
+ }
+ }
+}
+
+PRE_SYSCALL(pivot_root)(const void *new_root, const void *put_old) {
+ if (new_root)
+ PRE_READ(new_root,
+ __sanitizer::internal_strlen((const char *)new_root) + 1);
+ if (put_old)
+ PRE_READ(put_old, __sanitizer::internal_strlen((const char *)put_old) + 1);
+}
+
+POST_SYSCALL(pivot_root)(long res, const void *new_root, const void *put_old) {}
+
+PRE_SYSCALL(chroot)(const void *filename) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chroot)(long res, const void *filename) {}
+
+PRE_SYSCALL(mknod)(const void *filename, long mode, long dev) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(mknod)(long res, const void *filename, long mode, long dev) {}
+
+PRE_SYSCALL(link)(const void *oldname, const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(link)(long res, const void *oldname, const void *newname) {}
+
+PRE_SYSCALL(symlink)(const void *old, const void *new_) {
+ if (old) PRE_READ(old, __sanitizer::internal_strlen((const char *)old) + 1);
+ if (new_)
+ PRE_READ(new_, __sanitizer::internal_strlen((const char *)new_) + 1);
+}
+
+POST_SYSCALL(symlink)(long res, const void *old, const void *new_) {}
+
+PRE_SYSCALL(unlink)(const void *pathname) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(unlink)(long res, const void *pathname) {}
+
+PRE_SYSCALL(rename)(const void *oldname, const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(rename)(long res, const void *oldname, const void *newname) {}
+
+PRE_SYSCALL(chmod)(const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chmod)(long res, const void *filename, long mode) {}
+
+PRE_SYSCALL(fchmod)(long fd, long mode) {}
+
+POST_SYSCALL(fchmod)(long res, long fd, long mode) {}
+
+PRE_SYSCALL(fcntl)(long fd, long cmd, long arg) {}
+
+POST_SYSCALL(fcntl)(long res, long fd, long cmd, long arg) {}
+
+PRE_SYSCALL(fcntl64)(long fd, long cmd, long arg) {}
+
+POST_SYSCALL(fcntl64)(long res, long fd, long cmd, long arg) {}
+
+PRE_SYSCALL(pipe)(void *fildes) {}
+
+POST_SYSCALL(pipe)(long res, void *fildes) {
+ if (res >= 0) {
+ if (fildes) POST_WRITE(fildes, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(pipe2)(void *fildes, long flags) {}
+
+POST_SYSCALL(pipe2)(long res, void *fildes, long flags) {
+ if (res >= 0) {
+ if (fildes) POST_WRITE(fildes, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(dup)(long fildes) {}
+
+POST_SYSCALL(dup)(long res, long fildes) {}
+
+PRE_SYSCALL(dup2)(long oldfd, long newfd) {}
+
+POST_SYSCALL(dup2)(long res, long oldfd, long newfd) {}
+
+PRE_SYSCALL(dup3)(long oldfd, long newfd, long flags) {}
+
+POST_SYSCALL(dup3)(long res, long oldfd, long newfd, long flags) {}
+
+PRE_SYSCALL(ioperm)(long from, long num, long on) {}
+
+POST_SYSCALL(ioperm)(long res, long from, long num, long on) {}
+
+PRE_SYSCALL(ioctl)(long fd, long cmd, long arg) {}
+
+POST_SYSCALL(ioctl)(long res, long fd, long cmd, long arg) {}
+
+PRE_SYSCALL(flock)(long fd, long cmd) {}
+
+POST_SYSCALL(flock)(long res, long fd, long cmd) {}
+
+PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) {
+ if (ctx) PRE_WRITE(ctx, sizeof(*ctx));
+}
+
+POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) {
+ if (res >= 0) {
+ if (ctx) POST_WRITE(ctx, sizeof(*ctx));
+ // (*ctx) is actually a pointer to a kernel mapped page, and there are
+ // people out there who are crazy enough to peek into that page's 32-byte
+ // header.
+ if (*ctx) POST_WRITE(*ctx, 32);
+ }
+}
+
+PRE_SYSCALL(io_destroy)(long ctx) {}
+
+POST_SYSCALL(io_destroy)(long res, long ctx) {}
+
+PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr,
+ __sanitizer_io_event *ioevpp, void *timeout) {
+ if (timeout) PRE_READ(timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
+ __sanitizer_io_event *ioevpp, void *timeout) {
+ if (res >= 0) {
+ if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp));
+ if (timeout) POST_WRITE(timeout, struct_timespec_sz);
+ }
+ for (long i = 0; i < res; i++) {
+ // We synchronize io_submit -> io_getevents/io_cancel using the
+ // user-provided data context. Data is not necessary a pointer, it can be
+ // an int, 0 or whatever; acquire/release will correctly handle this.
+ // This scheme can lead to false negatives, e.g. when all operations
+ // synchronize on 0. But there does not seem to be a better solution
+ // (except wrapping all operations in own context, which is unreliable).
+ // We can not reliably extract fildes in io_getevents.
+ COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data);
+ }
+}
+
+PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
+ for (long i = 0; i < nr; ++i) {
+ uptr op = iocbpp[i]->aio_lio_opcode;
+ void *data = (void*)iocbpp[i]->aio_data;
+ void *buf = (void*)iocbpp[i]->aio_buf;
+ uptr len = (uptr)iocbpp[i]->aio_nbytes;
+ if (op == iocb_cmd_pwrite && buf && len) {
+ PRE_READ(buf, len);
+ } else if (op == iocb_cmd_pread && buf && len) {
+ POST_WRITE(buf, len);
+ } else if (op == iocb_cmd_pwritev) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
+ for (uptr v = 0; v < len; v++)
+ PRE_READ(iovec[v].iov_base, iovec[v].iov_len);
+ } else if (op == iocb_cmd_preadv) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
+ for (uptr v = 0; v < len; v++)
+ POST_WRITE(iovec[v].iov_base, iovec[v].iov_len);
+ }
+ // See comment in io_getevents.
+ COMMON_SYSCALL_RELEASE(data);
+ }
+}
+
+POST_SYSCALL(io_submit)(long res, long ctx_id, long nr,
+ __sanitizer_iocb **iocbpp) {}
+
+PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb,
+ __sanitizer_io_event *result) {
+}
+
+POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb,
+ __sanitizer_io_event *result) {
+ if (res == 0) {
+ if (result) {
+ // See comment in io_getevents.
+ COMMON_SYSCALL_ACQUIRE((void*)result->data);
+ POST_WRITE(result, sizeof(*result));
+ }
+ if (iocb)
+ POST_WRITE(iocb, sizeof(*iocb));
+ }
+}
+
+PRE_SYSCALL(sendfile)(long out_fd, long in_fd, void *offset, long count) {}
+
+POST_SYSCALL(sendfile)(long res, long out_fd, long in_fd,
+ __sanitizer___kernel_off_t *offset, long count) {
+ if (res >= 0) {
+ if (offset) POST_WRITE(offset, sizeof(*offset));
+ }
+}
+
+PRE_SYSCALL(sendfile64)(long out_fd, long in_fd, void *offset, long count) {}
+
+POST_SYSCALL(sendfile64)(long res, long out_fd, long in_fd,
+ __sanitizer___kernel_loff_t *offset, long count) {
+ if (res >= 0) {
+ if (offset) POST_WRITE(offset, sizeof(*offset));
+ }
+}
+
+PRE_SYSCALL(readlink)(const void *path, void *buf, long bufsiz) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(readlink)(long res, const void *path, void *buf, long bufsiz) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(creat)(const void *pathname, long mode) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(creat)(long res, const void *pathname, long mode) {}
+
+PRE_SYSCALL(open)(const void *filename, long flags, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(open)(long res, const void *filename, long flags, long mode) {}
+
+PRE_SYSCALL(close)(long fd) {
+ COMMON_SYSCALL_FD_CLOSE((int)fd);
+}
+
+POST_SYSCALL(close)(long res, long fd) {}
+
+PRE_SYSCALL(access)(const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(access)(long res, const void *filename, long mode) {}
+
+PRE_SYSCALL(vhangup)() {}
+
+POST_SYSCALL(vhangup)(long res) {}
+
+PRE_SYSCALL(chown)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chown)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(lchown)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lchown)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(fchown)(long fd, long user, long group) {}
+
+POST_SYSCALL(fchown)(long res, long fd, long user, long group) {}
+
+PRE_SYSCALL(chown16)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chown16)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(lchown16)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lchown16)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(fchown16)(long fd, long user, long group) {}
+
+POST_SYSCALL(fchown16)(long res, long fd, long user, long group) {}
+
+PRE_SYSCALL(setregid16)(long rgid, long egid) {}
+
+POST_SYSCALL(setregid16)(long res, long rgid, long egid) {}
+
+PRE_SYSCALL(setgid16)(long gid) {}
+
+POST_SYSCALL(setgid16)(long res, long gid) {}
+
+PRE_SYSCALL(setreuid16)(long ruid, long euid) {}
+
+POST_SYSCALL(setreuid16)(long res, long ruid, long euid) {}
+
+PRE_SYSCALL(setuid16)(long uid) {}
+
+POST_SYSCALL(setuid16)(long res, long uid) {}
+
+PRE_SYSCALL(setresuid16)(long ruid, long euid, long suid) {}
+
+POST_SYSCALL(setresuid16)(long res, long ruid, long euid, long suid) {}
+
+PRE_SYSCALL(getresuid16)(void *ruid, void *euid, void *suid) {}
+
+POST_SYSCALL(getresuid16)(long res, __sanitizer___kernel_old_uid_t *ruid,
+ __sanitizer___kernel_old_uid_t *euid,
+ __sanitizer___kernel_old_uid_t *suid) {
+ if (res >= 0) {
+ if (ruid) POST_WRITE(ruid, sizeof(*ruid));
+ if (euid) POST_WRITE(euid, sizeof(*euid));
+ if (suid) POST_WRITE(suid, sizeof(*suid));
+ }
+}
+
+PRE_SYSCALL(setresgid16)(long rgid, long egid, long sgid) {}
+
+POST_SYSCALL(setresgid16)(long res, long rgid, long egid, long sgid) {}
+
+PRE_SYSCALL(getresgid16)(void *rgid, void *egid, void *sgid) {}
+
+POST_SYSCALL(getresgid16)(long res, __sanitizer___kernel_old_gid_t *rgid,
+ __sanitizer___kernel_old_gid_t *egid,
+ __sanitizer___kernel_old_gid_t *sgid) {
+ if (res >= 0) {
+ if (rgid) POST_WRITE(rgid, sizeof(*rgid));
+ if (egid) POST_WRITE(egid, sizeof(*egid));
+ if (sgid) POST_WRITE(sgid, sizeof(*sgid));
+ }
+}
+
+PRE_SYSCALL(setfsuid16)(long uid) {}
+
+POST_SYSCALL(setfsuid16)(long res, long uid) {}
+
+PRE_SYSCALL(setfsgid16)(long gid) {}
+
+POST_SYSCALL(setfsgid16)(long res, long gid) {}
+
+PRE_SYSCALL(getgroups16)(long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {}
+
+POST_SYSCALL(getgroups16)(long res, long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {
+ if (res >= 0) {
+ if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist));
+ }
+}
+
+PRE_SYSCALL(setgroups16)(long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {
+ if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist));
+}
+
+POST_SYSCALL(setgroups16)(long res, long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {}
+
+PRE_SYSCALL(getuid16)() {}
+
+POST_SYSCALL(getuid16)(long res) {}
+
+PRE_SYSCALL(geteuid16)() {}
+
+POST_SYSCALL(geteuid16)(long res) {}
+
+PRE_SYSCALL(getgid16)() {}
+
+POST_SYSCALL(getgid16)(long res) {}
+
+PRE_SYSCALL(getegid16)() {}
+
+POST_SYSCALL(getegid16)(long res) {}
+
+PRE_SYSCALL(utime)(void *filename, void *times) {}
+
+POST_SYSCALL(utime)(long res, void *filename, void *times) {
+ if (res >= 0) {
+ if (filename)
+ POST_WRITE(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+ if (times) POST_WRITE(times, struct_utimbuf_sz);
+ }
+}
+
+PRE_SYSCALL(utimes)(void *filename, void *utimes) {}
+
+POST_SYSCALL(utimes)(long res, void *filename, void *utimes) {
+ if (res >= 0) {
+ if (filename)
+ POST_WRITE(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+ if (utimes) POST_WRITE(utimes, timeval_sz);
+ }
+}
+
+PRE_SYSCALL(lseek)(long fd, long offset, long origin) {}
+
+POST_SYSCALL(lseek)(long res, long fd, long offset, long origin) {}
+
+PRE_SYSCALL(llseek)(long fd, long offset_high, long offset_low, void *result,
+ long origin) {}
+
+POST_SYSCALL(llseek)(long res, long fd, long offset_high, long offset_low,
+ void *result, long origin) {
+ if (res >= 0) {
+ if (result) POST_WRITE(result, sizeof(long long));
+ }
+}
+
+PRE_SYSCALL(readv)(long fd, const __sanitizer_iovec *vec, long vlen) {}
+
+POST_SYSCALL(readv)(long res, long fd, const __sanitizer_iovec *vec,
+ long vlen) {
+ if (res >= 0) {
+ if (vec) kernel_write_iovec(vec, vlen, res);
+ }
+}
+
+PRE_SYSCALL(write)(long fd, const void *buf, long count) {
+ if (buf) PRE_READ(buf, count);
+}
+
+POST_SYSCALL(write)(long res, long fd, const void *buf, long count) {}
+
+PRE_SYSCALL(writev)(long fd, const __sanitizer_iovec *vec, long vlen) {}
+
+POST_SYSCALL(writev)(long res, long fd, const __sanitizer_iovec *vec,
+ long vlen) {
+ if (res >= 0) {
+ if (vec) kernel_read_iovec(vec, vlen, res);
+ }
+}
+
+#ifdef _LP64
+PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos) {}
+
+POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos) {
+ if (buf) PRE_READ(buf, count);
+}
+
+POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count,
+ long pos) {}
+#else
+PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos0, long pos1) {}
+
+POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos0,
+ long pos1) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos0,
+ long pos1) {
+ if (buf) PRE_READ(buf, count);
+}
+
+POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count,
+ long pos0, long pos1) {}
+#endif
+
+PRE_SYSCALL(preadv)(long fd, const __sanitizer_iovec *vec, long vlen,
+ long pos_l, long pos_h) {}
+
+POST_SYSCALL(preadv)(long res, long fd, const __sanitizer_iovec *vec, long vlen,
+ long pos_l, long pos_h) {
+ if (res >= 0) {
+ if (vec) kernel_write_iovec(vec, vlen, res);
+ }
+}
+
+PRE_SYSCALL(pwritev)(long fd, const __sanitizer_iovec *vec, long vlen,
+ long pos_l, long pos_h) {}
+
+POST_SYSCALL(pwritev)(long res, long fd, const __sanitizer_iovec *vec,
+ long vlen, long pos_l, long pos_h) {
+ if (res >= 0) {
+ if (vec) kernel_read_iovec(vec, vlen, res);
+ }
+}
+
+PRE_SYSCALL(getcwd)(void *buf, long size) {}
+
+POST_SYSCALL(getcwd)(long res, void *buf, long size) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(mkdir)(const void *pathname, long mode) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(mkdir)(long res, const void *pathname, long mode) {}
+
+PRE_SYSCALL(chdir)(const void *filename) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chdir)(long res, const void *filename) {}
+
+PRE_SYSCALL(fchdir)(long fd) {}
+
+POST_SYSCALL(fchdir)(long res, long fd) {}
+
+PRE_SYSCALL(rmdir)(const void *pathname) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(rmdir)(long res, const void *pathname) {}
+
+PRE_SYSCALL(lookup_dcookie)(u64 cookie64, void *buf, long len) {}
+
+POST_SYSCALL(lookup_dcookie)(long res, u64 cookie64, void *buf, long len) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(quotactl)(long cmd, const void *special, long id, void *addr) {
+ if (special)
+ PRE_READ(special, __sanitizer::internal_strlen((const char *)special) + 1);
+}
+
+POST_SYSCALL(quotactl)(long res, long cmd, const void *special, long id,
+ void *addr) {}
+
+PRE_SYSCALL(getdents)(long fd, void *dirent, long count) {}
+
+POST_SYSCALL(getdents)(long res, long fd, void *dirent, long count) {
+ if (res >= 0) {
+ if (dirent) POST_WRITE(dirent, res);
+ }
+}
+
+PRE_SYSCALL(getdents64)(long fd, void *dirent, long count) {}
+
+POST_SYSCALL(getdents64)(long res, long fd, void *dirent, long count) {
+ if (res >= 0) {
+ if (dirent) POST_WRITE(dirent, res);
+ }
+}
+
+PRE_SYSCALL(setsockopt)(long fd, long level, long optname, void *optval,
+ long optlen) {}
+
+POST_SYSCALL(setsockopt)(long res, long fd, long level, long optname,
+ void *optval, long optlen) {
+ if (res >= 0) {
+ if (optval)
+ POST_WRITE(optval,
+ __sanitizer::internal_strlen((const char *)optval) + 1);
+ }
+}
+
+PRE_SYSCALL(getsockopt)(long fd, long level, long optname, void *optval,
+ void *optlen) {}
+
+POST_SYSCALL(getsockopt)(long res, long fd, long level, long optname,
+ void *optval, void *optlen) {
+ if (res >= 0) {
+ if (optval)
+ POST_WRITE(optval,
+ __sanitizer::internal_strlen((const char *)optval) + 1);
+ if (optlen) POST_WRITE(optlen, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(bind)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {}
+
+POST_SYSCALL(bind)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ long arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ }
+}
+
+PRE_SYSCALL(connect)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {}
+
+POST_SYSCALL(connect)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ long arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ }
+}
+
+PRE_SYSCALL(accept)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {}
+
+POST_SYSCALL(accept)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(accept4)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2,
+ long arg3) {}
+
+POST_SYSCALL(accept4)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2, long arg3) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getsockname)(long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {}
+
+POST_SYSCALL(getsockname)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getpeername)(long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {}
+
+POST_SYSCALL(getpeername)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(send)(long arg0, void *arg1, long arg2, long arg3) {}
+
+POST_SYSCALL(send)(long res, long arg0, void *arg1, long arg2, long arg3) {
+ if (res) {
+ if (arg1) POST_READ(arg1, res);
+ }
+}
+
+PRE_SYSCALL(sendto)(long arg0, void *arg1, long arg2, long arg3,
+ sanitizer_kernel_sockaddr *arg4, long arg5) {}
+
+POST_SYSCALL(sendto)(long res, long arg0, void *arg1, long arg2, long arg3,
+ sanitizer_kernel_sockaddr *arg4, long arg5) {
+ if (res >= 0) {
+ if (arg1) POST_READ(arg1, res);
+ if (arg4) POST_WRITE(arg4, sizeof(*arg4));
+ }
+}
+
+PRE_SYSCALL(sendmsg)(long fd, void *msg, long flags) {}
+
+POST_SYSCALL(sendmsg)(long res, long fd, void *msg, long flags) {
+ // FIXME: POST_READ
+}
+
+PRE_SYSCALL(sendmmsg)(long fd, void *msg, long vlen, long flags) {}
+
+POST_SYSCALL(sendmmsg)(long res, long fd, void *msg, long vlen, long flags) {
+ // FIXME: POST_READ
+}
+
+PRE_SYSCALL(recv)(long arg0, void *buf, long len, long flags) {}
+
+POST_SYSCALL(recv)(long res, void *buf, long len, long flags) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(recvfrom)(long arg0, void *buf, long len, long flags,
+ sanitizer_kernel_sockaddr *arg4, void *arg5) {}
+
+POST_SYSCALL(recvfrom)(long res, long arg0, void *buf, long len, long flags,
+ sanitizer_kernel_sockaddr *arg4, void *arg5) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ if (arg4) POST_WRITE(arg4, sizeof(*arg4));
+ if (arg5) POST_WRITE(arg5, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(socket)(long arg0, long arg1, long arg2) {}
+
+POST_SYSCALL(socket)(long res, long arg0, long arg1, long arg2) {}
+
+PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, void *arg3) {}
+
+POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2,
+ void *arg3) {
+ if (res >= 0) {
+ if (arg3) POST_WRITE(arg3, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(socketcall)(long call, void *args) {}
+
+POST_SYSCALL(socketcall)(long res, long call, void *args) {
+ if (res >= 0) {
+ if (args) POST_WRITE(args, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(listen)(long arg0, long arg1) {}
+
+POST_SYSCALL(listen)(long res, long arg0, long arg1) {}
+
+PRE_SYSCALL(poll)(void *ufds, long nfds, long timeout) {}
+
+POST_SYSCALL(poll)(long res, __sanitizer_pollfd *ufds, long nfds,
+ long timeout) {
+ if (res >= 0) {
+ if (ufds) POST_WRITE(ufds, nfds * sizeof(*ufds));
+ }
+}
+
+PRE_SYSCALL(select)(long n, __sanitizer___kernel_fd_set *inp,
+ __sanitizer___kernel_fd_set *outp,
+ __sanitizer___kernel_fd_set *exp, void *tvp) {}
+
+POST_SYSCALL(select)(long res, long n, __sanitizer___kernel_fd_set *inp,
+ __sanitizer___kernel_fd_set *outp,
+ __sanitizer___kernel_fd_set *exp, void *tvp) {
+ if (res >= 0) {
+ if (inp) POST_WRITE(inp, sizeof(*inp));
+ if (outp) POST_WRITE(outp, sizeof(*outp));
+ if (exp) POST_WRITE(exp, sizeof(*exp));
+ if (tvp) POST_WRITE(tvp, timeval_sz);
+ }
+}
+
+PRE_SYSCALL(old_select)(void *arg) {}
+
+POST_SYSCALL(old_select)(long res, void *arg) {}
+
+PRE_SYSCALL(epoll_create)(long size) {}
+
+POST_SYSCALL(epoll_create)(long res, long size) {}
+
+PRE_SYSCALL(epoll_create1)(long flags) {}
+
+POST_SYSCALL(epoll_create1)(long res, long flags) {}
+
+PRE_SYSCALL(epoll_ctl)(long epfd, long op, long fd, void *event) {}
+
+POST_SYSCALL(epoll_ctl)(long res, long epfd, long op, long fd, void *event) {
+ if (res >= 0) {
+ if (event) POST_WRITE(event, struct_epoll_event_sz);
+ }
+}
+
+PRE_SYSCALL(epoll_wait)(long epfd, void *events, long maxevents, long timeout) {
+}
+
+POST_SYSCALL(epoll_wait)(long res, long epfd, void *events, long maxevents,
+ long timeout) {
+ if (res >= 0) {
+ if (events) POST_WRITE(events, struct_epoll_event_sz);
+ }
+}
+
+PRE_SYSCALL(epoll_pwait)(long epfd, void *events, long maxevents, long timeout,
+ const kernel_sigset_t *sigmask, long sigsetsize) {
+ if (sigmask) PRE_READ(sigmask, sigsetsize);
+}
+
+POST_SYSCALL(epoll_pwait)(long res, long epfd, void *events, long maxevents,
+ long timeout, const void *sigmask, long sigsetsize) {
+ if (res >= 0) {
+ if (events) POST_WRITE(events, struct_epoll_event_sz);
+ }
+}
+
+PRE_SYSCALL(gethostname)(void *name, long len) {}
+
+POST_SYSCALL(gethostname)(long res, void *name, long len) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(sethostname)(void *name, long len) {}
+
+POST_SYSCALL(sethostname)(long res, void *name, long len) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(setdomainname)(void *name, long len) {}
+
+POST_SYSCALL(setdomainname)(long res, void *name, long len) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(newuname)(void *name) {}
+
+POST_SYSCALL(newuname)(long res, void *name) {
+ if (res >= 0) {
+ if (name) POST_WRITE(name, struct_new_utsname_sz);
+ }
+}
+
+PRE_SYSCALL(uname)(void *arg0) {}
+
+POST_SYSCALL(uname)(long res, void *arg0) {
+ if (res >= 0) {
+ if (arg0) POST_WRITE(arg0, struct_old_utsname_sz);
+ }
+}
+
+PRE_SYSCALL(olduname)(void *arg0) {}
+
+POST_SYSCALL(olduname)(long res, void *arg0) {
+ if (res >= 0) {
+ if (arg0) POST_WRITE(arg0, struct_oldold_utsname_sz);
+ }
+}
+
+PRE_SYSCALL(getrlimit)(long resource, void *rlim) {}
+
+POST_SYSCALL(getrlimit)(long res, long resource, void *rlim) {
+ if (res >= 0) {
+ if (rlim) POST_WRITE(rlim, struct_rlimit_sz);
+ }
+}
+
+PRE_SYSCALL(old_getrlimit)(long resource, void *rlim) {}
+
+POST_SYSCALL(old_getrlimit)(long res, long resource, void *rlim) {
+ if (res >= 0) {
+ if (rlim) POST_WRITE(rlim, struct_rlimit_sz);
+ }
+}
+
+PRE_SYSCALL(setrlimit)(long resource, void *rlim) {}
+
+POST_SYSCALL(setrlimit)(long res, long resource, void *rlim) {
+ if (res >= 0) {
+ if (rlim) POST_WRITE(rlim, struct_rlimit_sz);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(prlimit64)(long pid, long resource, const void *new_rlim,
+ void *old_rlim) {
+ if (new_rlim) PRE_READ(new_rlim, struct_rlimit64_sz);
+}
+
+POST_SYSCALL(prlimit64)(long res, long pid, long resource, const void *new_rlim,
+ void *old_rlim) {
+ if (res >= 0) {
+ if (old_rlim) POST_WRITE(old_rlim, struct_rlimit64_sz);
+ }
+}
+#endif
+
+PRE_SYSCALL(getrusage)(long who, void *ru) {}
+
+POST_SYSCALL(getrusage)(long res, long who, void *ru) {
+ if (res >= 0) {
+ if (ru) POST_WRITE(ru, struct_rusage_sz);
+ }
+}
+
+PRE_SYSCALL(umask)(long mask) {}
+
+POST_SYSCALL(umask)(long res, long mask) {}
+
+PRE_SYSCALL(msgget)(long key, long msgflg) {}
+
+POST_SYSCALL(msgget)(long res, long key, long msgflg) {}
+
+PRE_SYSCALL(msgsnd)(long msqid, void *msgp, long msgsz, long msgflg) {
+ if (msgp) PRE_READ(msgp, msgsz);
+}
+
+POST_SYSCALL(msgsnd)(long res, long msqid, void *msgp, long msgsz,
+ long msgflg) {}
+
+PRE_SYSCALL(msgrcv)(long msqid, void *msgp, long msgsz, long msgtyp,
+ long msgflg) {}
+
+POST_SYSCALL(msgrcv)(long res, long msqid, void *msgp, long msgsz, long msgtyp,
+ long msgflg) {
+ if (res >= 0) {
+ if (msgp) POST_WRITE(msgp, res);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(msgctl)(long msqid, long cmd, void *buf) {}
+
+POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_msqid_ds_sz);
+ }
+}
+#endif
+
+PRE_SYSCALL(semget)(long key, long nsems, long semflg) {}
+
+POST_SYSCALL(semget)(long res, long key, long nsems, long semflg) {}
+
+PRE_SYSCALL(semop)(long semid, void *sops, long nsops) {}
+
+POST_SYSCALL(semop)(long res, long semid, void *sops, long nsops) {}
+
+PRE_SYSCALL(semctl)(long semid, long semnum, long cmd, void *arg) {}
+
+POST_SYSCALL(semctl)(long res, long semid, long semnum, long cmd, void *arg) {}
+
+PRE_SYSCALL(semtimedop)(long semid, void *sops, long nsops,
+ const void *timeout) {
+ if (timeout) PRE_READ(timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(semtimedop)(long res, long semid, void *sops, long nsops,
+ const void *timeout) {}
+
+PRE_SYSCALL(shmat)(long shmid, void *shmaddr, long shmflg) {}
+
+POST_SYSCALL(shmat)(long res, long shmid, void *shmaddr, long shmflg) {
+ if (res >= 0) {
+ if (shmaddr)
+ POST_WRITE(shmaddr,
+ __sanitizer::internal_strlen((const char *)shmaddr) + 1);
+ }
+}
+
+PRE_SYSCALL(shmget)(long key, long size, long flag) {}
+
+POST_SYSCALL(shmget)(long res, long key, long size, long flag) {}
+
+PRE_SYSCALL(shmdt)(void *shmaddr) {}
+
+POST_SYSCALL(shmdt)(long res, void *shmaddr) {
+ if (res >= 0) {
+ if (shmaddr)
+ POST_WRITE(shmaddr,
+ __sanitizer::internal_strlen((const char *)shmaddr) + 1);
+ }
+}
+
+PRE_SYSCALL(ipc)(long call, long first, long second, long third, void *ptr,
+ long fifth) {}
+
+POST_SYSCALL(ipc)(long res, long call, long first, long second, long third,
+ void *ptr, long fifth) {}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {}
+
+POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, sizeof(__sanitizer_shmid_ds));
+ }
+}
+
+PRE_SYSCALL(mq_open)(const void *name, long oflag, long mode, void *attr) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(mq_open)(long res, const void *name, long oflag, long mode,
+ void *attr) {
+ if (res >= 0) {
+ if (attr) POST_WRITE(attr, struct_mq_attr_sz);
+ }
+}
+
+PRE_SYSCALL(mq_unlink)(const void *name) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(mq_unlink)(long res, const void *name) {}
+
+PRE_SYSCALL(mq_timedsend)(long mqdes, const void *msg_ptr, long msg_len,
+ long msg_prio, const void *abs_timeout) {
+ if (msg_ptr) PRE_READ(msg_ptr, msg_len);
+ if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(mq_timedsend)(long res, long mqdes, const void *msg_ptr,
+ long msg_len, long msg_prio,
+ const void *abs_timeout) {}
+
+PRE_SYSCALL(mq_timedreceive)(long mqdes, void *msg_ptr, long msg_len,
+ void *msg_prio, const void *abs_timeout) {
+ if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(mq_timedreceive)(long res, long mqdes, void *msg_ptr, long msg_len,
+ int *msg_prio, const void *abs_timeout) {
+ if (res >= 0) {
+ if (msg_ptr) POST_WRITE(msg_ptr, res);
+ if (msg_prio) POST_WRITE(msg_prio, sizeof(*msg_prio));
+ }
+}
+
+PRE_SYSCALL(mq_notify)(long mqdes, const void *notification) {
+ if (notification) PRE_READ(notification, struct_sigevent_sz);
+}
+
+POST_SYSCALL(mq_notify)(long res, long mqdes, const void *notification) {}
+
+PRE_SYSCALL(mq_getsetattr)(long mqdes, const void *mqstat, void *omqstat) {
+ if (mqstat) PRE_READ(mqstat, struct_mq_attr_sz);
+}
+
+POST_SYSCALL(mq_getsetattr)(long res, long mqdes, const void *mqstat,
+ void *omqstat) {
+ if (res >= 0) {
+ if (omqstat) POST_WRITE(omqstat, struct_mq_attr_sz);
+ }
+}
+#endif // SANITIZER_ANDROID
+
+PRE_SYSCALL(pciconfig_iobase)(long which, long bus, long devfn) {}
+
+POST_SYSCALL(pciconfig_iobase)(long res, long which, long bus, long devfn) {}
+
+PRE_SYSCALL(pciconfig_read)(long bus, long dfn, long off, long len, void *buf) {
+}
+
+POST_SYSCALL(pciconfig_read)(long res, long bus, long dfn, long off, long len,
+ void *buf) {}
+
+PRE_SYSCALL(pciconfig_write)(long bus, long dfn, long off, long len,
+ void *buf) {}
+
+POST_SYSCALL(pciconfig_write)(long res, long bus, long dfn, long off, long len,
+ void *buf) {}
+
+PRE_SYSCALL(swapon)(const void *specialfile, long swap_flags) {
+ if (specialfile)
+ PRE_READ(specialfile,
+ __sanitizer::internal_strlen((const char *)specialfile) + 1);
+}
+
+POST_SYSCALL(swapon)(long res, const void *specialfile, long swap_flags) {}
+
+PRE_SYSCALL(swapoff)(const void *specialfile) {
+ if (specialfile)
+ PRE_READ(specialfile,
+ __sanitizer::internal_strlen((const char *)specialfile) + 1);
+}
+
+POST_SYSCALL(swapoff)(long res, const void *specialfile) {}
+
+PRE_SYSCALL(sysctl)(__sanitizer___sysctl_args *args) {
+ if (args) {
+ if (args->name) PRE_READ(args->name, args->nlen * sizeof(*args->name));
+ if (args->newval) PRE_READ(args->name, args->newlen);
+ }
+}
+
+POST_SYSCALL(sysctl)(long res, __sanitizer___sysctl_args *args) {
+ if (res >= 0) {
+ if (args && args->oldval && args->oldlenp) {
+ POST_WRITE(args->oldlenp, sizeof(*args->oldlenp));
+ POST_WRITE(args->oldval, *args->oldlenp);
+ }
+ }
+}
+
+PRE_SYSCALL(sysinfo)(void *info) {}
+
+POST_SYSCALL(sysinfo)(long res, void *info) {
+ if (res >= 0) {
+ if (info) POST_WRITE(info, struct_sysinfo_sz);
+ }
+}
+
+PRE_SYSCALL(sysfs)(long option, long arg1, long arg2) {}
+
+POST_SYSCALL(sysfs)(long res, long option, long arg1, long arg2) {}
+
+PRE_SYSCALL(syslog)(long type, void *buf, long len) {}
+
+POST_SYSCALL(syslog)(long res, long type, void *buf, long len) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(uselib)(const void *library) {
+ if (library)
+ PRE_READ(library, __sanitizer::internal_strlen((const char *)library) + 1);
+}
+
+POST_SYSCALL(uselib)(long res, const void *library) {}
+
+PRE_SYSCALL(ni_syscall)() {}
+
+POST_SYSCALL(ni_syscall)(long res) {}
+
+PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
+#if !SANITIZER_ANDROID && \
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
+ if (data) {
+ if (request == ptrace_setregs) {
+ PRE_READ((void *)data, struct_user_regs_struct_sz);
+ } else if (request == ptrace_setfpregs) {
+ PRE_READ((void *)data, struct_user_fpregs_struct_sz);
+ } else if (request == ptrace_setfpxregs) {
+ PRE_READ((void *)data, struct_user_fpxregs_struct_sz);
+ } else if (request == ptrace_setsiginfo) {
+ PRE_READ((void *)data, siginfo_t_sz);
+ } else if (request == ptrace_setregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ PRE_READ(iov->iov_base, iov->iov_len);
+ }
+ }
+#endif
+}
+
+POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
+#if !SANITIZER_ANDROID && \
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
+ if (res >= 0 && data) {
+ // Note that this is different from the interceptor in
+ // sanitizer_common_interceptors.inc.
+ // PEEK* requests return resulting values through data pointer.
+ if (request == ptrace_getregs) {
+ POST_WRITE((void *)data, struct_user_regs_struct_sz);
+ } else if (request == ptrace_getfpregs) {
+ POST_WRITE((void *)data, struct_user_fpregs_struct_sz);
+ } else if (request == ptrace_getfpxregs) {
+ POST_WRITE((void *)data, struct_user_fpxregs_struct_sz);
+ } else if (request == ptrace_getsiginfo) {
+ POST_WRITE((void *)data, siginfo_t_sz);
+ } else if (request == ptrace_getregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ POST_WRITE(iov->iov_base, iov->iov_len);
+ } else if (request == ptrace_peekdata || request == ptrace_peektext ||
+ request == ptrace_peekuser) {
+ POST_WRITE((void *)data, sizeof(void *));
+ }
+ }
+#endif
+}
+
+PRE_SYSCALL(add_key)(const void *_type, const void *_description,
+ const void *_payload, long plen, long destringid) {
+ if (_type)
+ PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1);
+ if (_description)
+ PRE_READ(_description,
+ __sanitizer::internal_strlen((const char *)_description) + 1);
+}
+
+POST_SYSCALL(add_key)(long res, const void *_type, const void *_description,
+ const void *_payload, long plen, long destringid) {}
+
+PRE_SYSCALL(request_key)(const void *_type, const void *_description,
+ const void *_callout_info, long destringid) {
+ if (_type)
+ PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1);
+ if (_description)
+ PRE_READ(_description,
+ __sanitizer::internal_strlen((const char *)_description) + 1);
+ if (_callout_info)
+ PRE_READ(_callout_info,
+ __sanitizer::internal_strlen((const char *)_callout_info) + 1);
+}
+
+POST_SYSCALL(request_key)(long res, const void *_type, const void *_description,
+ const void *_callout_info, long destringid) {}
+
+PRE_SYSCALL(keyctl)(long cmd, long arg2, long arg3, long arg4, long arg5) {}
+
+POST_SYSCALL(keyctl)(long res, long cmd, long arg2, long arg3, long arg4,
+ long arg5) {}
+
+PRE_SYSCALL(ioprio_set)(long which, long who, long ioprio) {}
+
+POST_SYSCALL(ioprio_set)(long res, long which, long who, long ioprio) {}
+
+PRE_SYSCALL(ioprio_get)(long which, long who) {}
+
+POST_SYSCALL(ioprio_get)(long res, long which, long who) {}
+
+PRE_SYSCALL(set_mempolicy)(long mode, void *nmask, long maxnode) {}
+
+POST_SYSCALL(set_mempolicy)(long res, long mode, void *nmask, long maxnode) {
+ if (res >= 0) {
+ if (nmask) POST_WRITE(nmask, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(migrate_pages)(long pid, long maxnode, const void *from,
+ const void *to) {
+ if (from) PRE_READ(from, sizeof(long));
+ if (to) PRE_READ(to, sizeof(long));
+}
+
+POST_SYSCALL(migrate_pages)(long res, long pid, long maxnode, const void *from,
+ const void *to) {}
+
+PRE_SYSCALL(move_pages)(long pid, long nr_pages, const void **pages,
+ const int *nodes, int *status, long flags) {
+ if (pages) PRE_READ(pages, nr_pages * sizeof(*pages));
+ if (nodes) PRE_READ(nodes, nr_pages * sizeof(*nodes));
+}
+
+POST_SYSCALL(move_pages)(long res, long pid, long nr_pages, const void **pages,
+ const int *nodes, int *status, long flags) {
+ if (res >= 0) {
+ if (status) POST_WRITE(status, nr_pages * sizeof(*status));
+ }
+}
+
+PRE_SYSCALL(mbind)(long start, long len, long mode, void *nmask, long maxnode,
+ long flags) {}
+
+POST_SYSCALL(mbind)(long res, long start, long len, long mode, void *nmask,
+ long maxnode, long flags) {
+ if (res >= 0) {
+ if (nmask) POST_WRITE(nmask, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(get_mempolicy)(void *policy, void *nmask, long maxnode, long addr,
+ long flags) {}
+
+POST_SYSCALL(get_mempolicy)(long res, void *policy, void *nmask, long maxnode,
+ long addr, long flags) {
+ if (res >= 0) {
+ if (policy) POST_WRITE(policy, sizeof(int));
+ if (nmask) POST_WRITE(nmask, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(inotify_init)() {}
+
+POST_SYSCALL(inotify_init)(long res) {}
+
+PRE_SYSCALL(inotify_init1)(long flags) {}
+
+POST_SYSCALL(inotify_init1)(long res, long flags) {}
+
+PRE_SYSCALL(inotify_add_watch)(long fd, const void *path, long mask) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(inotify_add_watch)(long res, long fd, const void *path,
+ long mask) {}
+
+PRE_SYSCALL(inotify_rm_watch)(long fd, long wd) {}
+
+POST_SYSCALL(inotify_rm_watch)(long res, long fd, long wd) {}
+
+PRE_SYSCALL(spu_run)(long fd, void *unpc, void *ustatus) {}
+
+POST_SYSCALL(spu_run)(long res, long fd, unsigned *unpc, unsigned *ustatus) {
+ if (res >= 0) {
+ if (unpc) POST_WRITE(unpc, sizeof(*unpc));
+ if (ustatus) POST_WRITE(ustatus, sizeof(*ustatus));
+ }
+}
+
+PRE_SYSCALL(spu_create)(const void *name, long flags, long mode, long fd) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(spu_create)(long res, const void *name, long flags, long mode,
+ long fd) {}
+
+PRE_SYSCALL(mknodat)(long dfd, const void *filename, long mode, long dev) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(mknodat)(long res, long dfd, const void *filename, long mode,
+ long dev) {}
+
+PRE_SYSCALL(mkdirat)(long dfd, const void *pathname, long mode) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(mkdirat)(long res, long dfd, const void *pathname, long mode) {}
+
+PRE_SYSCALL(unlinkat)(long dfd, const void *pathname, long flag) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(unlinkat)(long res, long dfd, const void *pathname, long flag) {}
+
+PRE_SYSCALL(symlinkat)(const void *oldname, long newdfd, const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(symlinkat)(long res, const void *oldname, long newdfd,
+ const void *newname) {}
+
+PRE_SYSCALL(linkat)(long olddfd, const void *oldname, long newdfd,
+ const void *newname, long flags) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(linkat)(long res, long olddfd, const void *oldname, long newdfd,
+ const void *newname, long flags) {}
+
+PRE_SYSCALL(renameat)(long olddfd, const void *oldname, long newdfd,
+ const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(renameat)(long res, long olddfd, const void *oldname, long newdfd,
+ const void *newname) {}
+
+PRE_SYSCALL(futimesat)(long dfd, const void *filename, void *utimes) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(futimesat)(long res, long dfd, const void *filename,
+ void *utimes) {
+ if (res >= 0) {
+ if (utimes) POST_WRITE(utimes, timeval_sz);
+ }
+}
+
+PRE_SYSCALL(faccessat)(long dfd, const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(faccessat)(long res, long dfd, const void *filename, long mode) {}
+
+PRE_SYSCALL(fchmodat)(long dfd, const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fchmodat)(long res, long dfd, const void *filename, long mode) {}
+
+PRE_SYSCALL(fchownat)(long dfd, const void *filename, long user, long group,
+ long flag) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fchownat)(long res, long dfd, const void *filename, long user,
+ long group, long flag) {}
+
+PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(openat)(long res, long dfd, const void *filename, long flags,
+ long mode) {}
+
+PRE_SYSCALL(newfstatat)(long dfd, const void *filename, void *statbuf,
+ long flag) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(newfstatat)(long res, long dfd, const void *filename,
+ void *statbuf, long flag) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(fstatat64)(long dfd, const void *filename, void *statbuf,
+ long flag) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fstatat64)(long res, long dfd, const void *filename, void *statbuf,
+ long flag) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(readlinkat)(long dfd, const void *path, void *buf, long bufsiz) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(readlinkat)(long res, long dfd, const void *path, void *buf,
+ long bufsiz) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(utimensat)(long dfd, const void *filename, void *utimes,
+ long flags) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(utimensat)(long res, long dfd, const void *filename, void *utimes,
+ long flags) {
+ if (res >= 0) {
+ if (utimes) POST_WRITE(utimes, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(unshare)(long unshare_flags) {}
+
+POST_SYSCALL(unshare)(long res, long unshare_flags) {}
+
+PRE_SYSCALL(splice)(long fd_in, void *off_in, long fd_out, void *off_out,
+ long len, long flags) {}
+
+POST_SYSCALL(splice)(long res, long fd_in, void *off_in, long fd_out,
+ void *off_out, long len, long flags) {
+ if (res >= 0) {
+ if (off_in) POST_WRITE(off_in, sizeof(long long));
+ if (off_out) POST_WRITE(off_out, sizeof(long long));
+ }
+}
+
+PRE_SYSCALL(vmsplice)(long fd, const __sanitizer_iovec *iov, long nr_segs,
+ long flags) {}
+
+POST_SYSCALL(vmsplice)(long res, long fd, const __sanitizer_iovec *iov,
+ long nr_segs, long flags) {
+ if (res >= 0) {
+ if (iov) kernel_read_iovec(iov, nr_segs, res);
+ }
+}
+
+PRE_SYSCALL(tee)(long fdin, long fdout, long len, long flags) {}
+
+POST_SYSCALL(tee)(long res, long fdin, long fdout, long len, long flags) {}
+
+PRE_SYSCALL(get_robust_list)(long pid, void *head_ptr, void *len_ptr) {}
+
+POST_SYSCALL(get_robust_list)(long res, long pid, void *head_ptr,
+ void *len_ptr) {}
+
+PRE_SYSCALL(set_robust_list)(void *head, long len) {}
+
+POST_SYSCALL(set_robust_list)(long res, void *head, long len) {}
+
+PRE_SYSCALL(getcpu)(void *cpu, void *node, void *cache) {}
+
+POST_SYSCALL(getcpu)(long res, void *cpu, void *node, void *cache) {
+ if (res >= 0) {
+ if (cpu) POST_WRITE(cpu, sizeof(unsigned));
+ if (node) POST_WRITE(node, sizeof(unsigned));
+ // The third argument to this system call is nowadays unused.
+ }
+}
+
+PRE_SYSCALL(signalfd)(long ufd, void *user_mask, long sizemask) {}
+
+POST_SYSCALL(signalfd)(long res, long ufd, kernel_sigset_t *user_mask,
+ long sizemask) {
+ if (res >= 0) {
+ if (user_mask) POST_WRITE(user_mask, sizemask);
+ }
+}
+
+PRE_SYSCALL(signalfd4)(long ufd, void *user_mask, long sizemask, long flags) {}
+
+POST_SYSCALL(signalfd4)(long res, long ufd, kernel_sigset_t *user_mask,
+ long sizemask, long flags) {
+ if (res >= 0) {
+ if (user_mask) POST_WRITE(user_mask, sizemask);
+ }
+}
+
+PRE_SYSCALL(timerfd_create)(long clockid, long flags) {}
+
+POST_SYSCALL(timerfd_create)(long res, long clockid, long flags) {}
+
+PRE_SYSCALL(timerfd_settime)(long ufd, long flags, const void *utmr,
+ void *otmr) {
+ if (utmr) PRE_READ(utmr, struct_itimerspec_sz);
+}
+
+POST_SYSCALL(timerfd_settime)(long res, long ufd, long flags, const void *utmr,
+ void *otmr) {
+ if (res >= 0) {
+ if (otmr) POST_WRITE(otmr, struct_itimerspec_sz);
+ }
+}
+
+PRE_SYSCALL(timerfd_gettime)(long ufd, void *otmr) {}
+
+POST_SYSCALL(timerfd_gettime)(long res, long ufd, void *otmr) {
+ if (res >= 0) {
+ if (otmr) POST_WRITE(otmr, struct_itimerspec_sz);
+ }
+}
+
+PRE_SYSCALL(eventfd)(long count) {}
+
+POST_SYSCALL(eventfd)(long res, long count) {}
+
+PRE_SYSCALL(eventfd2)(long count, long flags) {}
+
+POST_SYSCALL(eventfd2)(long res, long count, long flags) {}
+
+PRE_SYSCALL(old_readdir)(long arg0, void *arg1, long arg2) {}
+
+POST_SYSCALL(old_readdir)(long res, long arg0, void *arg1, long arg2) {
+ // Missing definition of 'struct old_linux_dirent'.
+}
+
+PRE_SYSCALL(pselect6)(long arg0, __sanitizer___kernel_fd_set *arg1,
+ __sanitizer___kernel_fd_set *arg2,
+ __sanitizer___kernel_fd_set *arg3, void *arg4,
+ void *arg5) {}
+
+POST_SYSCALL(pselect6)(long res, long arg0, __sanitizer___kernel_fd_set *arg1,
+ __sanitizer___kernel_fd_set *arg2,
+ __sanitizer___kernel_fd_set *arg3, void *arg4,
+ void *arg5) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(*arg2));
+ if (arg3) POST_WRITE(arg3, sizeof(*arg3));
+ if (arg4) POST_WRITE(arg4, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(ppoll)(__sanitizer_pollfd *arg0, long arg1, void *arg2,
+ const kernel_sigset_t *arg3, long arg4) {
+ if (arg3) PRE_READ(arg3, arg4);
+}
+
+POST_SYSCALL(ppoll)(long res, __sanitizer_pollfd *arg0, long arg1, void *arg2,
+ const void *arg3, long arg4) {
+ if (res >= 0) {
+ if (arg0) POST_WRITE(arg0, sizeof(*arg0));
+ if (arg2) POST_WRITE(arg2, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(syncfs)(long fd) {}
+
+POST_SYSCALL(syncfs)(long res, long fd) {}
+
+PRE_SYSCALL(perf_event_open)(__sanitizer_perf_event_attr *attr_uptr, long pid,
+ long cpu, long group_fd, long flags) {
+ if (attr_uptr) PRE_READ(attr_uptr, attr_uptr->size);
+}
+
+POST_SYSCALL(perf_event_open)(long res, __sanitizer_perf_event_attr *attr_uptr,
+ long pid, long cpu, long group_fd, long flags) {}
+
+PRE_SYSCALL(mmap_pgoff)(long addr, long len, long prot, long flags, long fd,
+ long pgoff) {}
+
+POST_SYSCALL(mmap_pgoff)(long res, long addr, long len, long prot, long flags,
+ long fd, long pgoff) {}
+
+PRE_SYSCALL(old_mmap)(void *arg) {}
+
+POST_SYSCALL(old_mmap)(long res, void *arg) {}
+
+PRE_SYSCALL(name_to_handle_at)(long dfd, const void *name, void *handle,
+ void *mnt_id, long flag) {}
+
+POST_SYSCALL(name_to_handle_at)(long res, long dfd, const void *name,
+ void *handle, void *mnt_id, long flag) {}
+
+PRE_SYSCALL(open_by_handle_at)(long mountdirfd, void *handle, long flags) {}
+
+POST_SYSCALL(open_by_handle_at)(long res, long mountdirfd, void *handle,
+ long flags) {}
+
+PRE_SYSCALL(setns)(long fd, long nstype) {}
+
+POST_SYSCALL(setns)(long res, long fd, long nstype) {}
+
+PRE_SYSCALL(process_vm_readv)(long pid, const __sanitizer_iovec *lvec,
+ long liovcnt, const void *rvec, long riovcnt,
+ long flags) {}
+
+POST_SYSCALL(process_vm_readv)(long res, long pid,
+ const __sanitizer_iovec *lvec, long liovcnt,
+ const void *rvec, long riovcnt, long flags) {
+ if (res >= 0) {
+ if (lvec) kernel_write_iovec(lvec, liovcnt, res);
+ }
+}
+
+PRE_SYSCALL(process_vm_writev)(long pid, const __sanitizer_iovec *lvec,
+ long liovcnt, const void *rvec, long riovcnt,
+ long flags) {}
+
+POST_SYSCALL(process_vm_writev)(long res, long pid,
+ const __sanitizer_iovec *lvec, long liovcnt,
+ const void *rvec, long riovcnt, long flags) {
+ if (res >= 0) {
+ if (lvec) kernel_read_iovec(lvec, liovcnt, res);
+ }
+}
+
+PRE_SYSCALL(fork)() {
+ COMMON_SYSCALL_PRE_FORK();
+}
+
+POST_SYSCALL(fork)(long res) {
+ COMMON_SYSCALL_POST_FORK(res);
+}
+
+PRE_SYSCALL(vfork)() {
+ COMMON_SYSCALL_PRE_FORK();
+}
+
+POST_SYSCALL(vfork)(long res) {
+ COMMON_SYSCALL_POST_FORK(res);
+}
+} // extern "C"
+
+#undef PRE_SYSCALL
+#undef PRE_READ
+#undef PRE_WRITE
+#undef POST_SYSCALL
+#undef POST_READ
+#undef POST_WRITE
+
+#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
new file mode 100644
index 000000000000..49887b1e91a9
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -0,0 +1,731 @@
+//===-- sanitizer_coverage.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage.
+// This file implements run-time support for a poor man's coverage tool.
+//
+// Compiler instrumentation:
+// For every interesting basic block the compiler injects the following code:
+// if (Guard < 0) {
+// __sanitizer_cov(&Guard);
+// }
+// At the module start up time __sanitizer_cov_module_init sets the guards
+// to consecutive negative numbers (-1, -2, -3, ...).
+// It's fine to call __sanitizer_cov more than once for a given block.
+//
+// Run-time:
+// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
+// and atomically set Guard to -Guard.
+// - __sanitizer_cov_dump: dump the coverage data to disk.
+// For every module of the current process that has coverage data
+// this will create a file module_name.PID.sancov. The file format is simple:
+// it's just a sorted sequence of 4-byte offsets in the module.
+//
+// Eventually, this coverage implementation should be obsoleted by a more
+// powerful general purpose Clang/LLVM coverage instrumentation.
+// Consider this implementation as prototype.
+//
+// FIXME: support (or at least test with) dlclose.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_flags.h"
+
+static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
+
+static atomic_uintptr_t coverage_counter;
+
+// pc_array is the array containing the covered PCs.
+// To make the pc_array thread- and async-signal-safe it has to be large enough.
+// 128M counters "ought to be enough for anybody" (4M on 32-bit).
+
+// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file.
+// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping()
+// dump current memory layout to another file.
+
+static bool cov_sandboxed = false;
+static int cov_fd = kInvalidFd;
+static unsigned int cov_max_block_size = 0;
+static bool coverage_enabled = false;
+static const char *coverage_dir;
+
+namespace __sanitizer {
+
+class CoverageData {
+ public:
+ void Init();
+ void Enable();
+ void Disable();
+ void ReInit();
+ void BeforeFork();
+ void AfterFork(int child_pid);
+ void Extend(uptr npcs);
+ void Add(uptr pc, u32 *guard);
+ void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+ uptr cache_size);
+ void DumpCallerCalleePairs();
+ void DumpTrace();
+
+ ALWAYS_INLINE
+ void TraceBasicBlock(s32 *id);
+
+ void InitializeGuardArray(s32 *guards);
+ void InitializeGuards(s32 *guards, uptr n, const char *module_name);
+ void ReinitializeGuards();
+
+ uptr *data();
+ uptr size();
+
+ private:
+ // Maximal size pc array may ever grow.
+ // We MmapNoReserve this space to ensure that the array is contiguous.
+ static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 24, 1 << 27);
+ // The amount file mapping for the pc array is grown by.
+ static const uptr kPcArrayMmapSize = 64 * 1024;
+
+ // pc_array is allocated with MmapNoReserveOrDie and so it uses only as
+ // much RAM as it really needs.
+ uptr *pc_array;
+ // Index of the first available pc_array slot.
+ atomic_uintptr_t pc_array_index;
+ // Array size.
+ atomic_uintptr_t pc_array_size;
+ // Current file mapped size of the pc array.
+ uptr pc_array_mapped_size;
+ // Descriptor of the file mapped pc array.
+ int pc_fd;
+
+ // Vector of coverage guard arrays, protected by mu.
+ InternalMmapVectorNoCtor<s32*> guard_array_vec;
+
+ // Vector of module (compilation unit) names.
+ InternalMmapVectorNoCtor<const char*> comp_unit_name_vec;
+
+ // Caller-Callee (cc) array, size and current index.
+ static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
+ uptr **cc_array;
+ atomic_uintptr_t cc_array_index;
+ atomic_uintptr_t cc_array_size;
+
+ // Tracing event array, size and current pointer.
+ // We record all events (basic block entries) in a global buffer of u32
+ // values. Each such value is the index in pc_array.
+ // So far the tracing is highly experimental:
+ // - not thread-safe;
+ // - does not support long traces;
+ // - not tuned for performance.
+ static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30);
+ u32 *tr_event_array;
+ uptr tr_event_array_size;
+ u32 *tr_event_pointer;
+ static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27);
+
+ StaticSpinMutex mu;
+
+ void DirectOpen();
+};
+
+static CoverageData coverage_data;
+
+void CovUpdateMapping(const char *path, uptr caller_pc = 0);
+
+void CoverageData::DirectOpen() {
+ InternalScopedString path(kMaxPathLength);
+ internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
+ coverage_dir, internal_getpid());
+ pc_fd = OpenFile(path.data(), true);
+ if (internal_iserror(pc_fd)) {
+ Report(" Coverage: failed to open %s for writing\n", path.data());
+ Die();
+ }
+
+ pc_array_mapped_size = 0;
+ CovUpdateMapping(coverage_dir);
+}
+
+void CoverageData::Init() {
+ pc_fd = kInvalidFd;
+}
+
+void CoverageData::Enable() {
+ if (pc_array)
+ return;
+ pc_array = reinterpret_cast<uptr *>(
+ MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
+ atomic_store(&pc_array_index, 0, memory_order_relaxed);
+ if (common_flags()->coverage_direct) {
+ atomic_store(&pc_array_size, 0, memory_order_relaxed);
+ } else {
+ atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
+ }
+
+ cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
+ sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
+ atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
+ atomic_store(&cc_array_index, 0, memory_order_relaxed);
+
+ // Allocate tr_event_array with a guard page at the end.
+ tr_event_array = reinterpret_cast<u32 *>(MmapNoReserveOrDie(
+ sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(),
+ "CovInit::tr_event_array"));
+ Mprotect(reinterpret_cast<uptr>(&tr_event_array[kTrEventArrayMaxSize]),
+ GetMmapGranularity());
+ tr_event_array_size = kTrEventArrayMaxSize;
+ tr_event_pointer = tr_event_array;
+}
+
+void CoverageData::InitializeGuardArray(s32 *guards) {
+ Enable(); // Make sure coverage is enabled at this point.
+ s32 n = guards[0];
+ for (s32 j = 1; j <= n; j++) {
+ uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
+ guards[j] = -static_cast<s32>(idx + 1);
+ }
+}
+
+void CoverageData::Disable() {
+ if (pc_array) {
+ internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize);
+ pc_array = nullptr;
+ }
+ if (cc_array) {
+ internal_munmap(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
+ cc_array = nullptr;
+ }
+ if (tr_event_array) {
+ internal_munmap(tr_event_array,
+ sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
+ GetMmapGranularity());
+ tr_event_array = nullptr;
+ tr_event_pointer = nullptr;
+ }
+ if (pc_fd != kInvalidFd) {
+ internal_close(pc_fd);
+ pc_fd = kInvalidFd;
+ }
+}
+
+void CoverageData::ReinitializeGuards() {
+ // Assuming single thread.
+ atomic_store(&pc_array_index, 0, memory_order_relaxed);
+ for (uptr i = 0; i < guard_array_vec.size(); i++)
+ InitializeGuardArray(guard_array_vec[i]);
+}
+
+void CoverageData::ReInit() {
+ Disable();
+ if (coverage_enabled) {
+ if (common_flags()->coverage_direct) {
+ // In memory-mapped mode we must extend the new file to the known array
+ // size.
+ uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
+ Enable();
+ if (size) Extend(size);
+ if (coverage_enabled) CovUpdateMapping(coverage_dir);
+ } else {
+ Enable();
+ }
+ }
+ // Re-initialize the guards.
+ // We are single-threaded now, no need to grab any lock.
+ CHECK_EQ(atomic_load(&pc_array_index, memory_order_relaxed), 0);
+ ReinitializeGuards();
+}
+
+void CoverageData::BeforeFork() {
+ mu.Lock();
+}
+
+void CoverageData::AfterFork(int child_pid) {
+ // We are single-threaded so it's OK to release the lock early.
+ mu.Unlock();
+ if (child_pid == 0) ReInit();
+}
+
+// Extend coverage PC array to fit additional npcs elements.
+void CoverageData::Extend(uptr npcs) {
+ if (!common_flags()->coverage_direct) return;
+ SpinMutexLock l(&mu);
+
+ uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
+ size += npcs * sizeof(uptr);
+
+ if (coverage_enabled && size > pc_array_mapped_size) {
+ if (pc_fd == kInvalidFd) DirectOpen();
+ CHECK_NE(pc_fd, kInvalidFd);
+
+ uptr new_mapped_size = pc_array_mapped_size;
+ while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize;
+ CHECK_LE(new_mapped_size, sizeof(uptr) * kPcArrayMaxSize);
+
+ // Extend the file and map the new space at the end of pc_array.
+ uptr res = internal_ftruncate(pc_fd, new_mapped_size);
+ int err;
+ if (internal_iserror(res, &err)) {
+ Printf("failed to extend raw coverage file: %d\n", err);
+ Die();
+ }
+
+ uptr next_map_base = ((uptr)pc_array) + pc_array_mapped_size;
+ void *p = MapWritableFileToMemory((void *)next_map_base,
+ new_mapped_size - pc_array_mapped_size,
+ pc_fd, pc_array_mapped_size);
+ CHECK_EQ((uptr)p, next_map_base);
+ pc_array_mapped_size = new_mapped_size;
+ }
+
+ atomic_store(&pc_array_size, size, memory_order_release);
+}
+
+void CoverageData::InitializeGuards(s32 *guards, uptr n,
+ const char *module_name) {
+ // The array 'guards' has n+1 elements, we use the element zero
+ // to store 'n'.
+ CHECK_LT(n, 1 << 30);
+ guards[0] = static_cast<s32>(n);
+ InitializeGuardArray(guards);
+ SpinMutexLock l(&mu);
+ comp_unit_name_vec.push_back(module_name);
+ guard_array_vec.push_back(guards);
+}
+
+// If guard is negative, atomically set it to -guard and store the PC in
+// pc_array.
+void CoverageData::Add(uptr pc, u32 *guard) {
+ atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
+ s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed);
+ if (guard_value >= 0) return;
+
+ atomic_store(atomic_guard, -guard_value, memory_order_relaxed);
+ if (!pc_array) return;
+
+ uptr idx = -guard_value - 1;
+ if (idx >= atomic_load(&pc_array_index, memory_order_acquire))
+ return; // May happen after fork when pc_array_index becomes 0.
+ CHECK_LT(idx * sizeof(uptr),
+ atomic_load(&pc_array_size, memory_order_acquire));
+ pc_array[idx] = pc;
+ atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+}
+
+// Registers a pair caller=>callee.
+// When a given caller is seen for the first time, the callee_cache is added
+// to the global array cc_array, callee_cache[0] is set to caller and
+// callee_cache[1] is set to cache_size.
+// Then we are trying to add callee to callee_cache [2,cache_size) if it is
+// not there yet.
+// If the cache is full we drop the callee (may want to fix this later).
+void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+ uptr cache_size) {
+ if (!cc_array) return;
+ atomic_uintptr_t *atomic_callee_cache =
+ reinterpret_cast<atomic_uintptr_t *>(callee_cache);
+ uptr zero = 0;
+ if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller,
+ memory_order_seq_cst)) {
+ uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed);
+ CHECK_LT(idx * sizeof(uptr),
+ atomic_load(&cc_array_size, memory_order_acquire));
+ callee_cache[1] = cache_size;
+ cc_array[idx] = callee_cache;
+ }
+ CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller);
+ for (uptr i = 2; i < cache_size; i++) {
+ uptr was = 0;
+ if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
+ memory_order_seq_cst)) {
+ atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+ return;
+ }
+ if (was == callee) // Already have this callee.
+ return;
+ }
+}
+
+uptr *CoverageData::data() {
+ return pc_array;
+}
+
+uptr CoverageData::size() {
+ return atomic_load(&pc_array_index, memory_order_relaxed);
+}
+
+// Block layout for packed file format: header, followed by module name (no
+// trailing zero), followed by data blob.
+struct CovHeader {
+ int pid;
+ unsigned int module_name_length;
+ unsigned int data_length;
+};
+
+static void CovWritePacked(int pid, const char *module, const void *blob,
+ unsigned int blob_size) {
+ if (cov_fd < 0) return;
+ unsigned module_name_length = internal_strlen(module);
+ CovHeader header = {pid, module_name_length, blob_size};
+
+ if (cov_max_block_size == 0) {
+ // Writing to a file. Just go ahead.
+ internal_write(cov_fd, &header, sizeof(header));
+ internal_write(cov_fd, module, module_name_length);
+ internal_write(cov_fd, blob, blob_size);
+ } else {
+ // Writing to a socket. We want to split the data into appropriately sized
+ // blocks.
+ InternalScopedBuffer<char> block(cov_max_block_size);
+ CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data());
+ uptr header_size_with_module = sizeof(header) + module_name_length;
+ CHECK_LT(header_size_with_module, cov_max_block_size);
+ unsigned int max_payload_size =
+ cov_max_block_size - header_size_with_module;
+ char *block_pos = block.data();
+ internal_memcpy(block_pos, &header, sizeof(header));
+ block_pos += sizeof(header);
+ internal_memcpy(block_pos, module, module_name_length);
+ block_pos += module_name_length;
+ char *block_data_begin = block_pos;
+ const char *blob_pos = (const char *)blob;
+ while (blob_size > 0) {
+ unsigned int payload_size = Min(blob_size, max_payload_size);
+ blob_size -= payload_size;
+ internal_memcpy(block_data_begin, blob_pos, payload_size);
+ blob_pos += payload_size;
+ ((CovHeader *)block.data())->data_length = payload_size;
+ internal_write(cov_fd, block.data(),
+ header_size_with_module + payload_size);
+ }
+ }
+}
+
+// If packed = false: <name>.<pid>.<sancov> (name = module name).
+// If packed = true and name == 0: <pid>.<sancov>.<packed>.
+// If packed = true and name != 0: <name>.<sancov>.<packed> (name is
+// user-supplied).
+static int CovOpenFile(bool packed, const char *name,
+ const char *extension = "sancov") {
+ InternalScopedString path(kMaxPathLength);
+ if (!packed) {
+ CHECK(name);
+ path.append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(),
+ extension);
+ } else {
+ if (!name)
+ path.append("%s/%zd.%s.packed", coverage_dir, internal_getpid(),
+ extension);
+ else
+ path.append("%s/%s.%s.packed", coverage_dir, name, extension);
+ }
+ uptr fd = OpenFile(path.data(), true);
+ if (internal_iserror(fd)) {
+ Report(" SanitizerCoverage: failed to open %s for writing\n", path.data());
+ return -1;
+ }
+ return fd;
+}
+
+// Dump trace PCs and trace events into two separate files.
+void CoverageData::DumpTrace() {
+ uptr max_idx = tr_event_pointer - tr_event_array;
+ if (!max_idx) return;
+ auto sym = Symbolizer::GetOrInit();
+ if (!sym)
+ return;
+ InternalScopedString out(32 << 20);
+ for (uptr i = 0, n = size(); i < n; i++) {
+ const char *module_name = "<unknown>";
+ uptr module_address = 0;
+ sym->GetModuleNameAndOffsetForPC(pc_array[i], &module_name,
+ &module_address);
+ out.append("%s 0x%zx\n", module_name, module_address);
+ }
+ int fd = CovOpenFile(false, "trace-points");
+ if (fd < 0) return;
+ internal_write(fd, out.data(), out.length());
+ internal_close(fd);
+
+ fd = CovOpenFile(false, "trace-compunits");
+ if (fd < 0) return;
+ out.clear();
+ for (uptr i = 0; i < comp_unit_name_vec.size(); i++)
+ out.append("%s\n", comp_unit_name_vec[i]);
+ internal_write(fd, out.data(), out.length());
+ internal_close(fd);
+
+ fd = CovOpenFile(false, "trace-events");
+ if (fd < 0) return;
+ uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]);
+ u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array);
+ // The trace file could be huge, and may not be written with a single syscall.
+ while (bytes_to_write) {
+ uptr actually_written = internal_write(fd, event_bytes, bytes_to_write);
+ if (actually_written <= bytes_to_write) {
+ bytes_to_write -= actually_written;
+ event_bytes += actually_written;
+ } else {
+ break;
+ }
+ }
+ internal_close(fd);
+ VReport(1, " CovDump: Trace: %zd PCs written\n", size());
+ VReport(1, " CovDump: Trace: %zd Events written\n", max_idx);
+}
+
+// This function dumps the caller=>callee pairs into a file as a sequence of
+// lines like "module_name offset".
+void CoverageData::DumpCallerCalleePairs() {
+ uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed);
+ if (!max_idx) return;
+ auto sym = Symbolizer::GetOrInit();
+ if (!sym)
+ return;
+ InternalScopedString out(32 << 20);
+ uptr total = 0;
+ for (uptr i = 0; i < max_idx; i++) {
+ uptr *cc_cache = cc_array[i];
+ CHECK(cc_cache);
+ uptr caller = cc_cache[0];
+ uptr n_callees = cc_cache[1];
+ const char *caller_module_name = "<unknown>";
+ uptr caller_module_address = 0;
+ sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name,
+ &caller_module_address);
+ for (uptr j = 2; j < n_callees; j++) {
+ uptr callee = cc_cache[j];
+ if (!callee) break;
+ total++;
+ const char *callee_module_name = "<unknown>";
+ uptr callee_module_address = 0;
+ sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name,
+ &callee_module_address);
+ out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name,
+ caller_module_address, callee_module_name,
+ callee_module_address);
+ }
+ }
+ int fd = CovOpenFile(false, "caller-callee");
+ if (fd < 0) return;
+ internal_write(fd, out.data(), out.length());
+ internal_close(fd);
+ VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
+}
+
+// Record the current PC into the event buffer.
+// Every event is a u32 value (index in tr_pc_array_index) so we compute
+// it once and then cache in the provided 'cache' storage.
+//
+// This function will eventually be inlined by the compiler.
+void CoverageData::TraceBasicBlock(s32 *id) {
+ // Will trap here if
+ // 1. coverage is not enabled at run-time.
+ // 2. The array tr_event_array is full.
+ *tr_event_pointer = static_cast<u32>(*id - 1);
+ tr_event_pointer++;
+}
+
+static void CovDumpAsBitSet() {
+ if (!common_flags()->coverage_bitset) return;
+ if (!coverage_data.size()) return;
+ int fd = CovOpenFile(/* packed */false, "combined", "bitset-sancov");
+ if (fd < 0) return;
+ uptr n = coverage_data.size();
+ uptr n_set_bits = 0;
+ InternalScopedBuffer<char> out(n);
+ for (uptr i = 0; i < n; i++) {
+ uptr pc = coverage_data.data()[i];
+ out[i] = pc ? '1' : '0';
+ if (pc)
+ n_set_bits++;
+ }
+ internal_write(fd, out.data(), n);
+ internal_close(fd);
+ VReport(1, " CovDump: bitset of %zd bits written, %zd bits are set\n", n,
+ n_set_bits);
+}
+
+// Dump the coverage on disk.
+static void CovDump() {
+ if (!coverage_enabled || common_flags()->coverage_direct) return;
+#if !SANITIZER_WINDOWS
+ if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
+ return;
+ CovDumpAsBitSet();
+ coverage_data.DumpTrace();
+ if (!common_flags()->coverage_pcs) return;
+ uptr size = coverage_data.size();
+ InternalMmapVector<u32> offsets(size);
+ uptr *vb = coverage_data.data();
+ uptr *ve = vb + size;
+ SortArray(vb, size);
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr mb, me, off, prot;
+ InternalScopedString module(kMaxPathLength);
+ InternalScopedString path(kMaxPathLength);
+ for (int i = 0;
+ proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
+ i++) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+ continue;
+ while (vb < ve && *vb < mb) vb++;
+ if (vb >= ve) break;
+ if (*vb < me) {
+ offsets.clear();
+ const uptr *old_vb = vb;
+ CHECK_LE(off, *vb);
+ for (; vb < ve && *vb < me; vb++) {
+ uptr diff = *vb - (i ? mb : 0) + off;
+ CHECK_LE(diff, 0xffffffffU);
+ offsets.push_back(static_cast<u32>(diff));
+ }
+ const char *module_name = StripModuleName(module.data());
+ if (cov_sandboxed) {
+ if (cov_fd >= 0) {
+ CovWritePacked(internal_getpid(), module_name, offsets.data(),
+ offsets.size() * sizeof(u32));
+ VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb);
+ }
+ } else {
+ // One file per module per process.
+ path.clear();
+ path.append("%s/%s.%zd.sancov", coverage_dir, module_name,
+ internal_getpid());
+ int fd = CovOpenFile(false /* packed */, module_name);
+ if (fd > 0) {
+ internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
+ internal_close(fd);
+ VReport(1, " CovDump: %s: %zd PCs written\n", path.data(),
+ vb - old_vb);
+ }
+ }
+ }
+ }
+ if (cov_fd >= 0)
+ internal_close(cov_fd);
+ coverage_data.DumpCallerCalleePairs();
+#endif // !SANITIZER_WINDOWS
+}
+
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ if (!args) return;
+ if (!coverage_enabled) return;
+ cov_sandboxed = args->coverage_sandboxed;
+ if (!cov_sandboxed) return;
+ cov_fd = args->coverage_fd;
+ cov_max_block_size = args->coverage_max_block_size;
+ if (cov_fd < 0)
+ // Pre-open the file now. The sandbox won't allow us to do it later.
+ cov_fd = CovOpenFile(true /* packed */, 0);
+}
+
+int MaybeOpenCovFile(const char *name) {
+ CHECK(name);
+ if (!coverage_enabled) return -1;
+ return CovOpenFile(true /* packed */, name);
+}
+
+void CovBeforeFork() {
+ coverage_data.BeforeFork();
+}
+
+void CovAfterFork(int child_pid) {
+ coverage_data.AfterFork(child_pid);
+}
+
+void InitializeCoverage(bool enabled, const char *dir) {
+ if (coverage_enabled)
+ return; // May happen if two sanitizer enable coverage in the same process.
+ coverage_enabled = enabled;
+ coverage_dir = dir;
+ coverage_data.Init();
+ if (enabled) coverage_data.Enable();
+#if !SANITIZER_WINDOWS
+ if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump);
+#endif
+}
+
+void ReInitializeCoverage(bool enabled, const char *dir) {
+ coverage_enabled = enabled;
+ coverage_dir = dir;
+ coverage_data.ReInit();
+}
+
+void CoverageUpdateMapping() {
+ if (coverage_enabled)
+ CovUpdateMapping(coverage_dir);
+}
+
+} // namespace __sanitizer
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) {
+ coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+ guard);
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) {
+ atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
+ if (__sanitizer::atomic_load(atomic_guard, memory_order_relaxed))
+ __sanitizer_cov(guard);
+}
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) {
+ coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+ callee, callee_cache16, 16);
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
+ coverage_enabled = true;
+ coverage_dir = common_flags()->coverage_dir;
+ coverage_data.Init();
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_module_init(s32 *guards, uptr npcs, const char *module_name) {
+ coverage_data.InitializeGuards(guards, npcs, module_name);
+ if (!common_flags()->coverage_direct) return;
+ if (SANITIZER_ANDROID && coverage_enabled) {
+ // dlopen/dlclose interceptors do not work on Android, so we rely on
+ // Extend() calls to update .sancov.map.
+ CovUpdateMapping(coverage_dir, GET_CALLER_PC());
+ }
+ coverage_data.Extend(npcs);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+sptr __sanitizer_maybe_open_cov_file(const char *name) {
+ return MaybeOpenCovFile(name);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_total_unique_coverage() {
+ return atomic_load(&coverage_counter, memory_order_relaxed);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_func_enter(s32 *id) {
+ coverage_data.TraceBasicBlock(id);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_basic_block(s32 *id) {
+ coverage_data.TraceBasicBlock(id);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_reset_coverage() {
+ coverage_data.ReinitializeGuards();
+ internal_bzero_aligned16(
+ coverage_data.data(),
+ RoundUpTo(coverage_data.size() * sizeof(coverage_data.data()[0]), 16));
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_coverage_guards(uptr **data) {
+ *data = coverage_data.data();
+ return coverage_data.size();
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
new file mode 100644
index 000000000000..6b5e91fbc018
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -0,0 +1,130 @@
+//===-- sanitizer_coverage_mapping.cc -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Mmap-based implementation of sanitizer coverage.
+//
+// This is part of the implementation of code coverage that does not require
+// __sanitizer_cov_dump() call. Data is stored in 2 files per process.
+//
+// $pid.sancov.map describes process memory layout in the following text-based
+// format:
+// <pointer size in bits> // 1 line, 32 or 64
+// <mapping start> <mapping end> <base address> <dso name> // repeated
+// ...
+// Mapping lines are NOT sorted. This file is updated every time memory layout
+// is changed (i.e. in dlopen() and dlclose() interceptors).
+//
+// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not
+// sorted. This file is extended by 64Kb at a time and mapped into memory. It
+// contains one or more 0 words at the end, up to the next 64Kb aligned offset.
+//
+// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack
+// $pid.sancov.raw.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+static const uptr kMaxNumberOfModules = 1 << 14;
+static const uptr kMaxTextSize = 64 * 1024;
+
+struct CachedMapping {
+ public:
+ bool NeedsUpdate(uptr pc) {
+ int new_pid = internal_getpid();
+ if (last_pid == new_pid && pc && pc >= last_range_start &&
+ pc < last_range_end)
+ return false;
+ last_pid = new_pid;
+ return true;
+ }
+
+ void SetModuleRange(uptr start, uptr end) {
+ last_range_start = start;
+ last_range_end = end;
+ }
+
+ private:
+ uptr last_range_start, last_range_end;
+ int last_pid;
+};
+
+static CachedMapping cached_mapping;
+static StaticSpinMutex mapping_mu;
+
+void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) {
+ if (!common_flags()->coverage_direct) return;
+
+ SpinMutexLock l(&mapping_mu);
+
+ if (!cached_mapping.NeedsUpdate(caller_pc))
+ return;
+
+ InternalScopedString text(kMaxTextSize);
+
+ {
+ InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
+ CHECK(modules.data());
+ int n_modules = GetListOfModules(modules.data(), kMaxNumberOfModules,
+ /* filter */ 0);
+
+ text.append("%d\n", sizeof(uptr) * 8);
+ for (int i = 0; i < n_modules; ++i) {
+ const char *module_name = StripModuleName(modules[i].full_name());
+ uptr base = modules[i].base_address();
+ for (auto iter = modules[i].ranges(); iter.hasNext();) {
+ const auto *range = iter.next();
+ if (range->executable) {
+ uptr start = range->beg;
+ uptr end = range->end;
+ text.append("%zx %zx %zx %s\n", start, end, base, module_name);
+ if (caller_pc && caller_pc >= start && caller_pc < end)
+ cached_mapping.SetModuleRange(start, end);
+ }
+ }
+ modules[i].clear();
+ }
+ }
+
+ int err;
+ InternalScopedString tmp_path(64 + internal_strlen(coverage_dir));
+ uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
+ "%s/%zd.sancov.map.tmp", coverage_dir,
+ internal_getpid());
+ CHECK_LE(res, tmp_path.size());
+ uptr map_fd = OpenFile(tmp_path.data(), true);
+ if (internal_iserror(map_fd, &err)) {
+ Report(" Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
+ err);
+ Die();
+ }
+
+ res = internal_write(map_fd, text.data(), text.length());
+ if (internal_iserror(res, &err)) {
+ Printf("sancov.map write failed: %d\n", err);
+ Die();
+ }
+ internal_close(map_fd);
+
+ InternalScopedString path(64 + internal_strlen(coverage_dir));
+ res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
+ coverage_dir, internal_getpid());
+ CHECK_LE(res, path.size());
+ res = internal_rename(tmp_path.data(), path.data());
+ if (internal_iserror(res, &err)) {
+ Printf("sancov.map rename failed: %d\n", err);
+ Die();
+ }
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h
new file mode 100644
index 000000000000..86d5743e9794
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h
@@ -0,0 +1,416 @@
+//===-- sanitizer_deadlock_detector.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 Sanitizer runtime.
+// The deadlock detector maintains a directed graph of lock acquisitions.
+// When a lock event happens, the detector checks if the locks already held by
+// the current thread are reachable from the newly acquired lock.
+//
+// The detector can handle only a fixed amount of simultaneously live locks
+// (a lock is alive if it has been locked at least once and has not been
+// destroyed). When the maximal number of locks is reached the entire graph
+// is flushed and the new lock epoch is started. The node ids from the old
+// epochs can not be used with any of the detector methods except for
+// nodeBelongsToCurrentEpoch().
+//
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_H
+#define SANITIZER_DEADLOCK_DETECTOR_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bvgraph.h"
+
+namespace __sanitizer {
+
+// Thread-local state for DeadlockDetector.
+// It contains the locks currently held by the owning thread.
+template <class BV>
+class DeadlockDetectorTLS {
+ public:
+ // No CTOR.
+ void clear() {
+ bv_.clear();
+ epoch_ = 0;
+ n_recursive_locks = 0;
+ n_all_locks_ = 0;
+ }
+
+ bool empty() const { return bv_.empty(); }
+
+ void ensureCurrentEpoch(uptr current_epoch) {
+ if (epoch_ == current_epoch) return;
+ bv_.clear();
+ epoch_ = current_epoch;
+ n_recursive_locks = 0;
+ n_all_locks_ = 0;
+ }
+
+ uptr getEpoch() const { return epoch_; }
+
+ // Returns true if this is the first (non-recursive) acquisition of this lock.
+ bool addLock(uptr lock_id, uptr current_epoch, u32 stk) {
+ // Printf("addLock: %zx %zx stk %u\n", lock_id, current_epoch, stk);
+ CHECK_EQ(epoch_, current_epoch);
+ if (!bv_.setBit(lock_id)) {
+ // The lock is already held by this thread, it must be recursive.
+ CHECK_LT(n_recursive_locks, ARRAY_SIZE(recursive_locks));
+ recursive_locks[n_recursive_locks++] = lock_id;
+ return false;
+ }
+ CHECK_LT(n_all_locks_, ARRAY_SIZE(all_locks_with_contexts_));
+ // lock_id < BV::kSize, can cast to a smaller int.
+ u32 lock_id_short = static_cast<u32>(lock_id);
+ LockWithContext l = {lock_id_short, stk};
+ all_locks_with_contexts_[n_all_locks_++] = l;
+ return true;
+ }
+
+ void removeLock(uptr lock_id) {
+ if (n_recursive_locks) {
+ for (sptr i = n_recursive_locks - 1; i >= 0; i--) {
+ if (recursive_locks[i] == lock_id) {
+ n_recursive_locks--;
+ Swap(recursive_locks[i], recursive_locks[n_recursive_locks]);
+ return;
+ }
+ }
+ }
+ // Printf("remLock: %zx %zx\n", lock_id, epoch_);
+ if (!bv_.clearBit(lock_id))
+ return; // probably addLock happened before flush
+ if (n_all_locks_) {
+ for (sptr i = n_all_locks_ - 1; i >= 0; i--) {
+ if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) {
+ Swap(all_locks_with_contexts_[i],
+ all_locks_with_contexts_[n_all_locks_ - 1]);
+ n_all_locks_--;
+ break;
+ }
+ }
+ }
+ }
+
+ u32 findLockContext(uptr lock_id) {
+ for (uptr i = 0; i < n_all_locks_; i++)
+ if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id))
+ return all_locks_with_contexts_[i].stk;
+ return 0;
+ }
+
+ const BV &getLocks(uptr current_epoch) const {
+ CHECK_EQ(epoch_, current_epoch);
+ return bv_;
+ }
+
+ uptr getNumLocks() const { return n_all_locks_; }
+ uptr getLock(uptr idx) const { return all_locks_with_contexts_[idx].lock; }
+
+ private:
+ BV bv_;
+ uptr epoch_;
+ uptr recursive_locks[64];
+ uptr n_recursive_locks;
+ struct LockWithContext {
+ u32 lock;
+ u32 stk;
+ };
+ LockWithContext all_locks_with_contexts_[64];
+ uptr n_all_locks_;
+};
+
+// DeadlockDetector.
+// For deadlock detection to work we need one global DeadlockDetector object
+// and one DeadlockDetectorTLS object per evey thread.
+// This class is not thread safe, all concurrent accesses should be guarded
+// by an external lock.
+// Most of the methods of this class are not thread-safe (i.e. should
+// be protected by an external lock) unless explicitly told otherwise.
+template <class BV>
+class DeadlockDetector {
+ public:
+ typedef BV BitVector;
+
+ uptr size() const { return g_.size(); }
+
+ // No CTOR.
+ void clear() {
+ current_epoch_ = 0;
+ available_nodes_.clear();
+ recycled_nodes_.clear();
+ g_.clear();
+ n_edges_ = 0;
+ }
+
+ // Allocate new deadlock detector node.
+ // If we are out of available nodes first try to recycle some.
+ // If there is nothing to recycle, flush the graph and increment the epoch.
+ // Associate 'data' (opaque user's object) with the new node.
+ uptr newNode(uptr data) {
+ if (!available_nodes_.empty())
+ return getAvailableNode(data);
+ if (!recycled_nodes_.empty()) {
+ // Printf("recycling: n_edges_ %zd\n", n_edges_);
+ for (sptr i = n_edges_ - 1; i >= 0; i--) {
+ if (recycled_nodes_.getBit(edges_[i].from) ||
+ recycled_nodes_.getBit(edges_[i].to)) {
+ Swap(edges_[i], edges_[n_edges_ - 1]);
+ n_edges_--;
+ }
+ }
+ CHECK(available_nodes_.empty());
+ // removeEdgesFrom was called in removeNode.
+ g_.removeEdgesTo(recycled_nodes_);
+ available_nodes_.setUnion(recycled_nodes_);
+ recycled_nodes_.clear();
+ return getAvailableNode(data);
+ }
+ // We are out of vacant nodes. Flush and increment the current_epoch_.
+ current_epoch_ += size();
+ recycled_nodes_.clear();
+ available_nodes_.setAll();
+ g_.clear();
+ n_edges_ = 0;
+ return getAvailableNode(data);
+ }
+
+ // Get data associated with the node created by newNode().
+ uptr getData(uptr node) const { return data_[nodeToIndex(node)]; }
+
+ bool nodeBelongsToCurrentEpoch(uptr node) {
+ return node && (node / size() * size()) == current_epoch_;
+ }
+
+ void removeNode(uptr node) {
+ uptr idx = nodeToIndex(node);
+ CHECK(!available_nodes_.getBit(idx));
+ CHECK(recycled_nodes_.setBit(idx));
+ g_.removeEdgesFrom(idx);
+ }
+
+ void ensureCurrentEpoch(DeadlockDetectorTLS<BV> *dtls) {
+ dtls->ensureCurrentEpoch(current_epoch_);
+ }
+
+ // Returns true if there is a cycle in the graph after this lock event.
+ // Ideally should be called before the lock is acquired so that we can
+ // report a deadlock before a real deadlock happens.
+ bool onLockBefore(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_));
+ }
+
+ u32 findLockContext(DeadlockDetectorTLS<BV> *dtls, uptr node) {
+ return dtls->findLockContext(nodeToIndex(node));
+ }
+
+ // Add cur_node to the set of locks held currently by dtls.
+ void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ dtls->addLock(cur_idx, current_epoch_, stk);
+ }
+
+ // Experimental *racy* fast path function.
+ // Returns true if all edges from the currently held locks to cur_node exist.
+ bool hasAllEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+ uptr local_epoch = dtls->getEpoch();
+ // Read from current_epoch_ is racy.
+ if (cur_node && local_epoch == current_epoch_ &&
+ local_epoch == nodeToEpoch(cur_node)) {
+ uptr cur_idx = nodeToIndexUnchecked(cur_node);
+ for (uptr i = 0, n = dtls->getNumLocks(); i < n; i++) {
+ if (!g_.hasEdge(dtls->getLock(i), cur_idx))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // Adds edges from currently held locks to cur_node,
+ // returns the number of added edges, and puts the sources of added edges
+ // into added_edges[].
+ // Should be called before onLockAfter.
+ uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk,
+ int unique_tid) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ uptr added_edges[40];
+ uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx,
+ added_edges, ARRAY_SIZE(added_edges));
+ for (uptr i = 0; i < n_added_edges; i++) {
+ if (n_edges_ < ARRAY_SIZE(edges_)) {
+ Edge e = {(u16)added_edges[i], (u16)cur_idx,
+ dtls->findLockContext(added_edges[i]), stk,
+ unique_tid};
+ edges_[n_edges_++] = e;
+ }
+ // Printf("Edge%zd: %u %zd=>%zd in T%d\n",
+ // n_edges_, stk, added_edges[i], cur_idx, unique_tid);
+ }
+ return n_added_edges;
+ }
+
+ bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to,
+ int *unique_tid) {
+ uptr from_idx = nodeToIndex(from_node);
+ uptr to_idx = nodeToIndex(to_node);
+ for (uptr i = 0; i < n_edges_; i++) {
+ if (edges_[i].from == from_idx && edges_[i].to == to_idx) {
+ *stk_from = edges_[i].stk_from;
+ *stk_to = edges_[i].stk_to;
+ *unique_tid = edges_[i].unique_tid;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Test-only function. Handles the before/after lock events,
+ // returns true if there is a cycle.
+ bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+ ensureCurrentEpoch(dtls);
+ bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node);
+ addEdges(dtls, cur_node, stk, 0);
+ onLockAfter(dtls, cur_node, stk);
+ return is_reachable;
+ }
+
+ // Handles the try_lock event, returns false.
+ // When a try_lock event happens (i.e. a try_lock call succeeds) we need
+ // to add this lock to the currently held locks, but we should not try to
+ // change the lock graph or to detect a cycle. We may want to investigate
+ // whether a more aggressive strategy is possible for try_lock.
+ bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ dtls->addLock(cur_idx, current_epoch_, stk);
+ return false;
+ }
+
+ // Returns true iff dtls is empty (no locks are currently held) and we can
+ // add the node to the currently held locks w/o chanding the global state.
+ // This operation is thread-safe as it only touches the dtls.
+ bool onFirstLock(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
+ if (!dtls->empty()) return false;
+ if (dtls->getEpoch() && dtls->getEpoch() == nodeToEpoch(node)) {
+ dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
+ return true;
+ }
+ return false;
+ }
+
+ // Finds a path between the lock 'cur_node' (currently not held in dtls)
+ // and some currently held lock, returns the length of the path
+ // or 0 on failure.
+ uptr findPathToLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, uptr *path,
+ uptr path_size) {
+ tmp_bv_.copyFrom(dtls->getLocks(current_epoch_));
+ uptr idx = nodeToIndex(cur_node);
+ CHECK(!tmp_bv_.getBit(idx));
+ uptr res = g_.findShortestPath(idx, tmp_bv_, path, path_size);
+ for (uptr i = 0; i < res; i++)
+ path[i] = indexToNode(path[i]);
+ if (res)
+ CHECK_EQ(path[0], cur_node);
+ return res;
+ }
+
+ // Handle the unlock event.
+ // This operation is thread-safe as it only touches the dtls.
+ void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
+ if (dtls->getEpoch() == nodeToEpoch(node))
+ dtls->removeLock(nodeToIndexUnchecked(node));
+ }
+
+ // Tries to handle the lock event w/o writing to global state.
+ // Returns true on success.
+ // This operation is thread-safe as it only touches the dtls
+ // (modulo racy nature of hasAllEdges).
+ bool onLockFast(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
+ if (hasAllEdges(dtls, node)) {
+ dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
+ return true;
+ }
+ return false;
+ }
+
+ bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
+ return dtls->getLocks(current_epoch_).getBit(nodeToIndex(node));
+ }
+
+ uptr testOnlyGetEpoch() const { return current_epoch_; }
+ bool testOnlyHasEdge(uptr l1, uptr l2) {
+ return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2));
+ }
+ // idx1 and idx2 are raw indices to g_, not lock IDs.
+ bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) {
+ return g_.hasEdge(idx1, idx2);
+ }
+
+ void Print() {
+ for (uptr from = 0; from < size(); from++)
+ for (uptr to = 0; to < size(); to++)
+ if (g_.hasEdge(from, to))
+ Printf(" %zx => %zx\n", from, to);
+ }
+
+ private:
+ void check_idx(uptr idx) const { CHECK_LT(idx, size()); }
+
+ void check_node(uptr node) const {
+ CHECK_GE(node, size());
+ CHECK_EQ(current_epoch_, nodeToEpoch(node));
+ }
+
+ uptr indexToNode(uptr idx) const {
+ check_idx(idx);
+ return idx + current_epoch_;
+ }
+
+ uptr nodeToIndexUnchecked(uptr node) const { return node % size(); }
+
+ uptr nodeToIndex(uptr node) const {
+ check_node(node);
+ return nodeToIndexUnchecked(node);
+ }
+
+ uptr nodeToEpoch(uptr node) const { return node / size() * size(); }
+
+ uptr getAvailableNode(uptr data) {
+ uptr idx = available_nodes_.getAndClearFirstOne();
+ data_[idx] = data;
+ return indexToNode(idx);
+ }
+
+ struct Edge {
+ u16 from;
+ u16 to;
+ u32 stk_from;
+ u32 stk_to;
+ int unique_tid;
+ };
+
+ uptr current_epoch_;
+ BV available_nodes_;
+ BV recycled_nodes_;
+ BV tmp_bv_;
+ BVGraph<BV> g_;
+ uptr data_[BV::kSize];
+ Edge edges_[BV::kSize * 32];
+ uptr n_edges_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
new file mode 100644
index 000000000000..b931edc7eae5
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -0,0 +1,189 @@
+//===-- sanitizer_deadlock_detector1.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on NxN adjacency bit matrix.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_deadlock_detector.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+
+namespace __sanitizer {
+
+typedef TwoLevelBitVector<> DDBV; // DeadlockDetector's bit vector.
+
+struct DDPhysicalThread {
+};
+
+struct DDLogicalThread {
+ u64 ctx;
+ DeadlockDetectorTLS<DDBV> dd;
+ DDReport rep;
+ bool report_pending;
+};
+
+struct DD : public DDetector {
+ SpinMutex mtx;
+ DeadlockDetector<DDBV> dd;
+ DDFlags flags;
+
+ explicit DD(const DDFlags *flags);
+
+ DDPhysicalThread* CreatePhysicalThread();
+ void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+ DDLogicalThread* CreateLogicalThread(u64 ctx);
+ void DestroyLogicalThread(DDLogicalThread *lt);
+
+ void MutexInit(DDCallback *cb, DDMutex *m);
+ void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock);
+ void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+ DDReport *GetReport(DDCallback *cb);
+
+ void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
+ void ReportDeadlock(DDCallback *cb, DDMutex *m);
+};
+
+DDetector *DDetector::Create(const DDFlags *flags) {
+ (void)flags;
+ void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+ return new(mem) DD(flags);
+}
+
+DD::DD(const DDFlags *flags)
+ : flags(*flags) {
+ dd.clear();
+}
+
+DDPhysicalThread* DD::CreatePhysicalThread() {
+ return 0;
+}
+
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
+}
+
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+ DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt));
+ lt->ctx = ctx;
+ lt->dd.clear();
+ lt->report_pending = false;
+ return lt;
+}
+
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
+ lt->~DDLogicalThread();
+ InternalFree(lt);
+}
+
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
+ m->id = 0;
+ m->stk = cb->Unwind();
+}
+
+void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) {
+ if (!dd.nodeBelongsToCurrentEpoch(m->id))
+ m->id = dd.newNode(reinterpret_cast<uptr>(m));
+ dd.ensureCurrentEpoch(&lt->dd);
+}
+
+void DD::MutexBeforeLock(DDCallback *cb,
+ DDMutex *m, bool wlock) {
+ DDLogicalThread *lt = cb->lt;
+ if (lt->dd.empty()) return; // This will be the first lock held by lt.
+ if (dd.hasAllEdges(&lt->dd, m->id)) return; // We already have all edges.
+ SpinMutexLock lk(&mtx);
+ MutexEnsureID(lt, m);
+ if (dd.isHeld(&lt->dd, m->id))
+ return; // FIXME: allow this only for recursive locks.
+ if (dd.onLockBefore(&lt->dd, m->id)) {
+ // Actually add this edge now so that we have all the stack traces.
+ dd.addEdges(&lt->dd, m->id, cb->Unwind(), cb->UniqueTid());
+ ReportDeadlock(cb, m);
+ }
+}
+
+void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) {
+ DDLogicalThread *lt = cb->lt;
+ uptr path[10];
+ uptr len = dd.findPathToLock(&lt->dd, m->id, path, ARRAY_SIZE(path));
+ CHECK_GT(len, 0U); // Hm.. cycle of 10 locks? I'd like to see that.
+ CHECK_EQ(m->id, path[0]);
+ lt->report_pending = true;
+ DDReport *rep = &lt->rep;
+ rep->n = len;
+ for (uptr i = 0; i < len; i++) {
+ uptr from = path[i];
+ uptr to = path[(i + 1) % len];
+ DDMutex *m0 = (DDMutex*)dd.getData(from);
+ DDMutex *m1 = (DDMutex*)dd.getData(to);
+
+ u32 stk_from = -1U, stk_to = -1U;
+ int unique_tid = 0;
+ dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid);
+ // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to,
+ // unique_tid);
+ rep->loop[i].thr_ctx = unique_tid;
+ rep->loop[i].mtx_ctx0 = m0->ctx;
+ rep->loop[i].mtx_ctx1 = m1->ctx;
+ rep->loop[i].stk[0] = stk_to;
+ rep->loop[i].stk[1] = stk_from;
+ }
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) {
+ DDLogicalThread *lt = cb->lt;
+ u32 stk = 0;
+ if (flags.second_deadlock_stack)
+ stk = cb->Unwind();
+ // Printf("T%p MutexLock: %zx stk %u\n", lt, m->id, stk);
+ if (dd.onFirstLock(&lt->dd, m->id, stk))
+ return;
+ if (dd.onLockFast(&lt->dd, m->id, stk))
+ return;
+
+ SpinMutexLock lk(&mtx);
+ MutexEnsureID(lt, m);
+ if (wlock) // Only a recursive rlock may be held.
+ CHECK(!dd.isHeld(&lt->dd, m->id));
+ if (!trylock)
+ dd.addEdges(&lt->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid());
+ dd.onLockAfter(&lt->dd, m->id, stk);
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+ // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id);
+ dd.onUnlock(&cb->lt->dd, m->id);
+}
+
+void DD::MutexDestroy(DDCallback *cb,
+ DDMutex *m) {
+ if (!m->id) return;
+ SpinMutexLock lk(&mtx);
+ if (dd.nodeBelongsToCurrentEpoch(m->id))
+ dd.removeNode(m->id);
+ m->id = 0;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+ if (!cb->lt->report_pending)
+ return 0;
+ cb->lt->report_pending = false;
+ return &cb->lt->rep;
+}
+
+} // namespace __sanitizer
+#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
new file mode 100644
index 000000000000..87d4a4d9a838
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
@@ -0,0 +1,428 @@
+//===-- sanitizer_deadlock_detector2.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on adjacency lists.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+
+namespace __sanitizer {
+
+const int kMaxNesting = 64;
+const u32 kNoId = -1;
+const u32 kEndId = -2;
+const int kMaxLink = 8;
+const int kL1Size = 1024;
+const int kL2Size = 1024;
+const int kMaxMutex = kL1Size * kL2Size;
+
+struct Id {
+ u32 id;
+ u32 seq;
+
+ explicit Id(u32 id = 0, u32 seq = 0)
+ : id(id)
+ , seq(seq) {
+ }
+};
+
+struct Link {
+ u32 id;
+ u32 seq;
+ u32 tid;
+ u32 stk0;
+ u32 stk1;
+
+ explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0)
+ : id(id)
+ , seq(seq)
+ , tid(tid)
+ , stk0(s0)
+ , stk1(s1) {
+ }
+};
+
+struct DDPhysicalThread {
+ DDReport rep;
+ bool report_pending;
+ bool visited[kMaxMutex];
+ Link pending[kMaxMutex];
+ Link path[kMaxMutex];
+};
+
+struct ThreadMutex {
+ u32 id;
+ u32 stk;
+};
+
+struct DDLogicalThread {
+ u64 ctx;
+ ThreadMutex locked[kMaxNesting];
+ int nlocked;
+};
+
+struct Mutex {
+ StaticSpinMutex mtx;
+ u32 seq;
+ int nlink;
+ Link link[kMaxLink];
+};
+
+struct DD : public DDetector {
+ explicit DD(const DDFlags *flags);
+
+ DDPhysicalThread* CreatePhysicalThread();
+ void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+ DDLogicalThread* CreateLogicalThread(u64 ctx);
+ void DestroyLogicalThread(DDLogicalThread *lt);
+
+ void MutexInit(DDCallback *cb, DDMutex *m);
+ void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock);
+ void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+ DDReport *GetReport(DDCallback *cb);
+
+ void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx);
+ void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath);
+ u32 allocateId(DDCallback *cb);
+ Mutex *getMutex(u32 id);
+ u32 getMutexId(Mutex *m);
+
+ DDFlags flags;
+
+ Mutex* mutex[kL1Size];
+
+ SpinMutex mtx;
+ InternalMmapVector<u32> free_id;
+ int id_gen;
+};
+
+DDetector *DDetector::Create(const DDFlags *flags) {
+ (void)flags;
+ void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+ return new(mem) DD(flags);
+}
+
+DD::DD(const DDFlags *flags)
+ : flags(*flags)
+ , free_id(1024) {
+ id_gen = 0;
+}
+
+DDPhysicalThread* DD::CreatePhysicalThread() {
+ DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread),
+ "deadlock detector (physical thread)");
+ return pt;
+}
+
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
+ pt->~DDPhysicalThread();
+ UnmapOrDie(pt, sizeof(DDPhysicalThread));
+}
+
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+ DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(
+ sizeof(DDLogicalThread));
+ lt->ctx = ctx;
+ lt->nlocked = 0;
+ return lt;
+}
+
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
+ lt->~DDLogicalThread();
+ InternalFree(lt);
+}
+
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
+ VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m);
+ m->id = kNoId;
+ m->recursion = 0;
+ atomic_store(&m->owner, 0, memory_order_relaxed);
+}
+
+Mutex *DD::getMutex(u32 id) {
+ return &mutex[id / kL2Size][id % kL2Size];
+}
+
+u32 DD::getMutexId(Mutex *m) {
+ for (int i = 0; i < kL1Size; i++) {
+ Mutex *tab = mutex[i];
+ if (tab == 0)
+ break;
+ if (m >= tab && m < tab + kL2Size)
+ return i * kL2Size + (m - tab);
+ }
+ return -1;
+}
+
+u32 DD::allocateId(DDCallback *cb) {
+ u32 id = -1;
+ SpinMutexLock l(&mtx);
+ if (free_id.size() > 0) {
+ id = free_id.back();
+ free_id.pop_back();
+ } else {
+ CHECK_LT(id_gen, kMaxMutex);
+ if ((id_gen % kL2Size) == 0) {
+ mutex[id_gen / kL2Size] = (Mutex*)MmapOrDie(kL2Size * sizeof(Mutex),
+ "deadlock detector (mutex table)");
+ }
+ id = id_gen++;
+ }
+ CHECK_LE(id, kMaxMutex);
+ VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id);
+ return id;
+}
+
+void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
+ VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n",
+ cb->lt->ctx, m, wlock, cb->lt->nlocked);
+ DDPhysicalThread *pt = cb->pt;
+ DDLogicalThread *lt = cb->lt;
+
+ uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+ if (owner == (uptr)cb->lt) {
+ VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n",
+ cb->lt->ctx);
+ return;
+ }
+
+ CHECK_LE(lt->nlocked, kMaxNesting);
+
+ // FIXME(dvyukov): don't allocate id if lt->nlocked == 0?
+ if (m->id == kNoId)
+ m->id = allocateId(cb);
+
+ ThreadMutex *tm = &lt->locked[lt->nlocked++];
+ tm->id = m->id;
+ if (flags.second_deadlock_stack)
+ tm->stk = cb->Unwind();
+ if (lt->nlocked == 1) {
+ VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n",
+ cb->lt->ctx);
+ return;
+ }
+
+ bool added = false;
+ Mutex *mtx = getMutex(m->id);
+ for (int i = 0; i < lt->nlocked - 1; i++) {
+ u32 id1 = lt->locked[i].id;
+ u32 stk1 = lt->locked[i].stk;
+ Mutex *mtx1 = getMutex(id1);
+ SpinMutexLock l(&mtx1->mtx);
+ if (mtx1->nlink == kMaxLink) {
+ // FIXME(dvyukov): check stale links
+ continue;
+ }
+ int li = 0;
+ for (; li < mtx1->nlink; li++) {
+ Link *link = &mtx1->link[li];
+ if (link->id == m->id) {
+ if (link->seq != mtx->seq) {
+ link->seq = mtx->seq;
+ link->tid = lt->ctx;
+ link->stk0 = stk1;
+ link->stk1 = cb->Unwind();
+ added = true;
+ VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+ cb->lt->ctx, getMutexId(mtx1), m->id);
+ }
+ break;
+ }
+ }
+ if (li == mtx1->nlink) {
+ // FIXME(dvyukov): check stale links
+ Link *link = &mtx1->link[mtx1->nlink++];
+ link->id = m->id;
+ link->seq = mtx->seq;
+ link->tid = lt->ctx;
+ link->stk0 = stk1;
+ link->stk1 = cb->Unwind();
+ added = true;
+ VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+ cb->lt->ctx, getMutexId(mtx1), m->id);
+ }
+ }
+
+ if (!added || mtx->nlink == 0) {
+ VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n",
+ cb->lt->ctx);
+ return;
+ }
+
+ CycleCheck(pt, lt, m);
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock) {
+ VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n",
+ cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked);
+ DDLogicalThread *lt = cb->lt;
+
+ uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+ if (owner == (uptr)cb->lt) {
+ VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx);
+ CHECK(wlock);
+ m->recursion++;
+ return;
+ }
+ CHECK_EQ(owner, 0);
+ if (wlock) {
+ VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx);
+ CHECK_EQ(m->recursion, 0);
+ m->recursion = 1;
+ atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed);
+ }
+
+ if (!trylock)
+ return;
+
+ CHECK_LE(lt->nlocked, kMaxNesting);
+ if (m->id == kNoId)
+ m->id = allocateId(cb);
+ ThreadMutex *tm = &lt->locked[lt->nlocked++];
+ tm->id = m->id;
+ if (flags.second_deadlock_stack)
+ tm->stk = cb->Unwind();
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+ VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n",
+ cb->lt->ctx, m, wlock, cb->lt->nlocked);
+ DDLogicalThread *lt = cb->lt;
+
+ uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+ if (owner == (uptr)cb->lt) {
+ VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx);
+ if (--m->recursion > 0)
+ return;
+ VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx);
+ atomic_store(&m->owner, 0, memory_order_relaxed);
+ }
+ CHECK_NE(m->id, kNoId);
+ int last = lt->nlocked - 1;
+ for (int i = last; i >= 0; i--) {
+ if (cb->lt->locked[i].id == m->id) {
+ lt->locked[i] = lt->locked[last];
+ lt->nlocked--;
+ break;
+ }
+ }
+}
+
+void DD::MutexDestroy(DDCallback *cb, DDMutex *m) {
+ VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n",
+ cb->lt->ctx, m);
+ DDLogicalThread *lt = cb->lt;
+
+ if (m->id == kNoId)
+ return;
+
+ // Remove the mutex from lt->locked if there.
+ int last = lt->nlocked - 1;
+ for (int i = last; i >= 0; i--) {
+ if (lt->locked[i].id == m->id) {
+ lt->locked[i] = lt->locked[last];
+ lt->nlocked--;
+ break;
+ }
+ }
+
+ // Clear and invalidate the mutex descriptor.
+ {
+ Mutex *mtx = getMutex(m->id);
+ SpinMutexLock l(&mtx->mtx);
+ mtx->seq++;
+ mtx->nlink = 0;
+ }
+
+ // Return id to cache.
+ {
+ SpinMutexLock l(&mtx);
+ free_id.push_back(m->id);
+ }
+}
+
+void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt,
+ DDMutex *m) {
+ internal_memset(pt->visited, 0, sizeof(pt->visited));
+ int npath = 0;
+ int npending = 0;
+ {
+ Mutex *mtx = getMutex(m->id);
+ SpinMutexLock l(&mtx->mtx);
+ for (int li = 0; li < mtx->nlink; li++)
+ pt->pending[npending++] = mtx->link[li];
+ }
+ while (npending > 0) {
+ Link link = pt->pending[--npending];
+ if (link.id == kEndId) {
+ npath--;
+ continue;
+ }
+ if (pt->visited[link.id])
+ continue;
+ Mutex *mtx1 = getMutex(link.id);
+ SpinMutexLock l(&mtx1->mtx);
+ if (mtx1->seq != link.seq)
+ continue;
+ pt->visited[link.id] = true;
+ if (mtx1->nlink == 0)
+ continue;
+ pt->path[npath++] = link;
+ pt->pending[npending++] = Link(kEndId);
+ if (link.id == m->id)
+ return Report(pt, lt, npath); // Bingo!
+ for (int li = 0; li < mtx1->nlink; li++) {
+ Link *link1 = &mtx1->link[li];
+ // Mutex *mtx2 = getMutex(link->id);
+ // FIXME(dvyukov): fast seq check
+ // FIXME(dvyukov): fast nlink != 0 check
+ // FIXME(dvyukov): fast pending check?
+ // FIXME(dvyukov): npending can be larger than kMaxMutex
+ pt->pending[npending++] = *link1;
+ }
+ }
+}
+
+void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) {
+ DDReport *rep = &pt->rep;
+ rep->n = npath;
+ for (int i = 0; i < npath; i++) {
+ Link *link = &pt->path[i];
+ Link *link0 = &pt->path[i ? i - 1 : npath - 1];
+ rep->loop[i].thr_ctx = link->tid;
+ rep->loop[i].mtx_ctx0 = link0->id;
+ rep->loop[i].mtx_ctx1 = link->id;
+ rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0;
+ rep->loop[i].stk[1] = link->stk1;
+ }
+ pt->report_pending = true;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+ if (!cb->pt->report_pending)
+ return 0;
+ cb->pt->report_pending = false;
+ return &cb->pt->rep;
+}
+
+} // namespace __sanitizer
+#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
new file mode 100644
index 000000000000..8cf26e0d5528
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
@@ -0,0 +1,93 @@
+//===-- sanitizer_deadlock_detector_interface.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 Sanitizer runtime.
+// Abstract deadlock detector interface.
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+#define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_VERSION
+# define SANITIZER_DEADLOCK_DETECTOR_VERSION 1
+#endif
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_atomic.h"
+
+namespace __sanitizer {
+
+// dd - deadlock detector.
+// lt - logical (user) thread.
+// pt - physical (OS) thread.
+
+struct DDPhysicalThread;
+struct DDLogicalThread;
+
+struct DDMutex {
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+ uptr id;
+ u32 stk; // creation stack
+#elif SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+ u32 id;
+ u32 recursion;
+ atomic_uintptr_t owner;
+#else
+# error "BAD SANITIZER_DEADLOCK_DETECTOR_VERSION"
+#endif
+ u64 ctx;
+};
+
+struct DDFlags {
+ bool second_deadlock_stack;
+};
+
+struct DDReport {
+ enum { kMaxLoopSize = 8 };
+ int n; // number of entries in loop
+ struct {
+ u64 thr_ctx; // user thread context
+ u64 mtx_ctx0; // user mutex context, start of the edge
+ u64 mtx_ctx1; // user mutex context, end of the edge
+ u32 stk[2]; // stack ids for the edge
+ } loop[kMaxLoopSize];
+};
+
+struct DDCallback {
+ DDPhysicalThread *pt;
+ DDLogicalThread *lt;
+
+ virtual u32 Unwind() { return 0; }
+ virtual int UniqueTid() { return 0; }
+};
+
+struct DDetector {
+ static DDetector *Create(const DDFlags *flags);
+
+ virtual DDPhysicalThread* CreatePhysicalThread() { return 0; }
+ virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {}
+
+ virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return 0; }
+ virtual void DestroyLogicalThread(DDLogicalThread *lt) {}
+
+ virtual void MutexInit(DDCallback *cb, DDMutex *m) {}
+ virtual void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {}
+ virtual void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock) {}
+ virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {}
+ virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {}
+
+ virtual DDReport *GetReport(DDCallback *cb) { return 0; }
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc
new file mode 100644
index 000000000000..d125002daf4c
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc
@@ -0,0 +1,153 @@
+//===-- sanitizer_flag_parser.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_flag_parser.h"
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_flag_parser.h"
+
+namespace __sanitizer {
+
+LowLevelAllocator FlagParser::Alloc;
+
+class UnknownFlags {
+ static const int kMaxUnknownFlags = 20;
+ const char *unknown_flags_[kMaxUnknownFlags];
+ int n_unknown_flags_;
+
+ public:
+ void Add(const char *name) {
+ CHECK_LT(n_unknown_flags_, kMaxUnknownFlags);
+ unknown_flags_[n_unknown_flags_++] = name;
+ }
+
+ void Report() {
+ if (!n_unknown_flags_) return;
+ Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_);
+ for (int i = 0; i < n_unknown_flags_; ++i)
+ Printf(" %s\n", unknown_flags_[i]);
+ n_unknown_flags_ = 0;
+ }
+};
+
+UnknownFlags unknown_flags;
+
+void ReportUnrecognizedFlags() {
+ unknown_flags.Report();
+}
+
+char *FlagParser::ll_strndup(const char *s, uptr n) {
+ uptr len = internal_strnlen(s, n);
+ char *s2 = (char*)Alloc.Allocate(len + 1);
+ internal_memcpy(s2, s, len);
+ s2[len] = 0;
+ return s2;
+}
+
+void FlagParser::PrintFlagDescriptions() {
+ Printf("Available flags for %s:\n", SanitizerToolName);
+ for (int i = 0; i < n_flags_; ++i)
+ Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc);
+}
+
+void FlagParser::fatal_error(const char *err) {
+ Printf("ERROR: %s\n", err);
+ Die();
+}
+
+bool FlagParser::is_space(char c) {
+ return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' ||
+ c == '\r';
+}
+
+void FlagParser::skip_whitespace() {
+ while (is_space(buf_[pos_])) ++pos_;
+}
+
+void FlagParser::parse_flag() {
+ uptr name_start = pos_;
+ while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_;
+ if (buf_[pos_] != '=') fatal_error("expected '='");
+ char *name = ll_strndup(buf_ + name_start, pos_ - name_start);
+
+ uptr value_start = ++pos_;
+ char *value;
+ if (buf_[pos_] == '\'' || buf_[pos_] == '"') {
+ char quote = buf_[pos_++];
+ while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_;
+ if (buf_[pos_] == 0) fatal_error("unterminated string");
+ value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1);
+ ++pos_; // consume the closing quote
+ } else {
+ while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_;
+ if (buf_[pos_] != 0 && !is_space(buf_[pos_]))
+ fatal_error("expected separator or eol");
+ value = ll_strndup(buf_ + value_start, pos_ - value_start);
+ }
+
+ bool res = run_handler(name, value);
+ if (!res) fatal_error("Flag parsing failed.");
+}
+
+void FlagParser::parse_flags() {
+ while (true) {
+ skip_whitespace();
+ if (buf_[pos_] == 0) break;
+ parse_flag();
+ }
+
+ // Do a sanity check for certain flags.
+ if (common_flags_dont_use.malloc_context_size < 1)
+ common_flags_dont_use.malloc_context_size = 1;
+}
+
+void FlagParser::ParseString(const char *s) {
+ if (!s) return;
+ // Backup current parser state to allow nested ParseString() calls.
+ const char *old_buf_ = buf_;
+ uptr old_pos_ = pos_;
+ buf_ = s;
+ pos_ = 0;
+
+ parse_flags();
+
+ buf_ = old_buf_;
+ pos_ = old_pos_;
+}
+
+bool FlagParser::run_handler(const char *name, const char *value) {
+ for (int i = 0; i < n_flags_; ++i) {
+ if (internal_strcmp(name, flags_[i].name) == 0)
+ return flags_[i].handler->Parse(value);
+ }
+ // Unrecognized flag. This is not a fatal error, we may print a warning later.
+ unknown_flags.Add(name);
+ return true;
+}
+
+void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler,
+ const char *desc) {
+ CHECK_LT(n_flags_, kMaxFlags);
+ flags_[n_flags_].name = name;
+ flags_[n_flags_].desc = desc;
+ flags_[n_flags_].handler = handler;
+ ++n_flags_;
+}
+
+FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
+ flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
new file mode 100644
index 000000000000..0ac7634cb876
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
@@ -0,0 +1,121 @@
+//===-- sanitizer_flag_parser.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_FLAG_REGISTRY_H
+#define SANITIZER_FLAG_REGISTRY_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+class FlagHandlerBase {
+ public:
+ virtual bool Parse(const char *value) { return false; }
+};
+
+template <typename T>
+class FlagHandler : public FlagHandlerBase {
+ T *t_;
+
+ public:
+ explicit FlagHandler(T *t) : t_(t) {}
+ bool Parse(const char *value) final;
+};
+
+template <>
+inline bool FlagHandler<bool>::Parse(const char *value) {
+ if (internal_strcmp(value, "0") == 0 ||
+ internal_strcmp(value, "no") == 0 ||
+ internal_strcmp(value, "false") == 0) {
+ *t_ = false;
+ return true;
+ }
+ if (internal_strcmp(value, "1") == 0 ||
+ internal_strcmp(value, "yes") == 0 ||
+ internal_strcmp(value, "true") == 0) {
+ *t_ = true;
+ return true;
+ }
+ Printf("ERROR: Invalid value for bool option: '%s'\n", value);
+ return false;
+}
+
+template <>
+inline bool FlagHandler<const char *>::Parse(const char *value) {
+ *t_ = internal_strdup(value);
+ return true;
+}
+
+template <>
+inline bool FlagHandler<int>::Parse(const char *value) {
+ char *value_end;
+ *t_ = internal_simple_strtoll(value, &value_end, 10);
+ bool ok = *value_end == 0;
+ if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
+ return ok;
+}
+
+template <>
+inline bool FlagHandler<uptr>::Parse(const char *value) {
+ char *value_end;
+ *t_ = internal_simple_strtoll(value, &value_end, 10);
+ bool ok = *value_end == 0;
+ if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
+ return ok;
+}
+
+class FlagParser {
+ static const int kMaxFlags = 200;
+ struct Flag {
+ const char *name;
+ const char *desc;
+ FlagHandlerBase *handler;
+ } *flags_;
+ int n_flags_;
+
+ const char *buf_;
+ uptr pos_;
+
+ public:
+ FlagParser();
+ void RegisterHandler(const char *name, FlagHandlerBase *handler,
+ const char *desc);
+ void ParseString(const char *s);
+ void PrintFlagDescriptions();
+
+ static LowLevelAllocator Alloc;
+
+ private:
+ void fatal_error(const char *err);
+ bool is_space(char c);
+ void skip_whitespace();
+ void parse_flags();
+ void parse_flag();
+ bool run_handler(const char *name, const char *value);
+ char *ll_strndup(const char *s, uptr n);
+};
+
+template <typename T>
+static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
+ T *var) {
+ FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var); // NOLINT
+ parser->RegisterHandler(name, fh, desc);
+}
+
+void ReportUnrecognizedFlags();
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FLAG_REGISTRY_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc
new file mode 100644
index 000000000000..e835b46a24fc
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc
@@ -0,0 +1,87 @@
+//===-- sanitizer_flags.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_flags.h"
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
+#include "sanitizer_flag_parser.h"
+
+namespace __sanitizer {
+
+CommonFlags common_flags_dont_use;
+
+struct FlagDescription {
+ const char *name;
+ const char *description;
+ FlagDescription *next;
+};
+
+IntrusiveList<FlagDescription> flag_descriptions;
+
+// If set, the tool will install its own SEGV signal handler by default.
+#ifndef SANITIZER_NEEDS_SEGV
+# define SANITIZER_NEEDS_SEGV 1
+#endif
+
+void CommonFlags::SetDefaults() {
+#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "sanitizer_flags.inc"
+#undef COMMON_FLAG
+}
+
+void CommonFlags::CopyFrom(const CommonFlags &other) {
+ internal_memcpy(this, &other, sizeof(*this));
+}
+
+class FlagHandlerInclude : public FlagHandlerBase {
+ static const uptr kMaxIncludeSize = 1 << 15;
+ FlagParser *parser_;
+
+ public:
+ explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {}
+ bool Parse(const char *value) final {
+ char *data;
+ uptr data_mapped_size;
+ int err;
+ uptr len =
+ ReadFileToBuffer(value, &data, &data_mapped_size,
+ Max(kMaxIncludeSize, GetPageSizeCached()), &err);
+ if (!len) {
+ Printf("Failed to read options from '%s': error %d\n", value, err);
+ return false;
+ }
+ parser_->ParseString(data);
+ UnmapOrDie(data, data_mapped_size);
+ return true;
+ }
+};
+
+void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf) {
+ FlagHandlerInclude *fh_include =
+ new (FlagParser::Alloc) FlagHandlerInclude(parser); // NOLINT
+ parser->RegisterHandler("include", fh_include,
+ "read more options from the given file");
+}
+
+void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
+#define COMMON_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &cf->Name);
+#include "sanitizer_flags.inc"
+#undef COMMON_FLAG
+
+ RegisterIncludeFlag(parser, cf);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
new file mode 100644
index 000000000000..fda6d710757e
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
@@ -0,0 +1,55 @@
+//===-- sanitizer_flags.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_FLAGS_H
+#define SANITIZER_FLAGS_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+struct CommonFlags {
+#define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "sanitizer_flags.inc"
+#undef COMMON_FLAG
+
+ void SetDefaults();
+ void CopyFrom(const CommonFlags &other);
+};
+
+// Functions to get/set global CommonFlags shared by all sanitizer runtimes:
+extern CommonFlags common_flags_dont_use;
+inline const CommonFlags *common_flags() {
+ return &common_flags_dont_use;
+}
+
+inline void SetCommonFlagsDefaults() {
+ common_flags_dont_use.SetDefaults();
+}
+
+// This function can only be used to setup tool-specific overrides for
+// CommonFlags defaults. Generally, it should only be used right after
+// SetCommonFlagsDefaults(), but before ParseCommonFlagsFromString(), and
+// only during the flags initialization (i.e. before they are used for
+// the first time).
+inline void OverrideCommonFlags(const CommonFlags &cf) {
+ common_flags_dont_use.CopyFrom(cf);
+}
+
+class FlagParser;
+void RegisterCommonFlags(FlagParser *parser,
+ CommonFlags *cf = &common_flags_dont_use);
+void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf);
+} // namespace __sanitizer
+
+#endif // SANITIZER_FLAGS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
new file mode 100644
index 000000000000..58f7f372228f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
@@ -0,0 +1,148 @@
+//===-- sanitizer_flags.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 describes common flags available in all sanitizers.
+//
+//===----------------------------------------------------------------------===//
+#ifndef COMMON_FLAG
+#error "Define COMMON_FLAG prior to including this file!"
+#endif
+
+// COMMON_FLAG(Type, Name, DefaultValue, Description)
+// Supported types: bool, const char *, int, uptr.
+// Default value must be a compile-time constant.
+// Description must be a string literal.
+
+COMMON_FLAG(
+ bool, symbolize, true,
+ "If set, use the online symbolizer from common sanitizer runtime to turn "
+ "virtual addresses to file/line locations.")
+COMMON_FLAG(
+ const char *, external_symbolizer_path, 0,
+ "Path to external symbolizer. If empty, the tool will search $PATH for "
+ "the symbolizer.")
+COMMON_FLAG(
+ bool, allow_addr2line, false,
+ "If set, allows online symbolizer to run addr2line binary to symbolize "
+ "stack traces (addr2line will only be used if llvm-symbolizer binary is "
+ "unavailable.")
+COMMON_FLAG(const char *, strip_path_prefix, "",
+ "Strips this prefix from file paths in error reports.")
+COMMON_FLAG(bool, fast_unwind_on_check, false,
+ "If available, use the fast frame-pointer-based unwinder on "
+ "internal CHECK failures.")
+COMMON_FLAG(bool, fast_unwind_on_fatal, false,
+ "If available, use the fast frame-pointer-based unwinder on fatal "
+ "errors.")
+COMMON_FLAG(bool, fast_unwind_on_malloc, true,
+ "If available, use the fast frame-pointer-based unwinder on "
+ "malloc/free.")
+COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.")
+COMMON_FLAG(int, malloc_context_size, 1,
+ "Max number of stack frames kept for each allocation/deallocation.")
+COMMON_FLAG(
+ const char *, log_path, "stderr",
+ "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
+ "\"stderr\". The default is \"stderr\".")
+COMMON_FLAG(
+ int, verbosity, 0,
+ "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).")
+COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.")
+COMMON_FLAG(
+ bool, leak_check_at_exit, true,
+ "Invoke leak checking in an atexit handler. Has no effect if "
+ "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
+ "handler has a chance to run.")
+COMMON_FLAG(bool, allocator_may_return_null, false,
+ "If false, the allocator will crash instead of returning 0 on "
+ "out-of-memory.")
+COMMON_FLAG(bool, print_summary, true,
+ "If false, disable printing error summaries in addition to error "
+ "reports.")
+COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
+COMMON_FLAG(bool, handle_segv, SANITIZER_NEEDS_SEGV,
+ "If set, registers the tool's custom SEGV handler (both SIGBUS and "
+ "SIGSEGV on OSX).")
+COMMON_FLAG(bool, allow_user_segv_handler, false,
+ "If set, allows user to register a SEGV handler even if the tool "
+ "registers one.")
+COMMON_FLAG(bool, use_sigaltstack, true,
+ "If set, uses alternate stack for signal handling.")
+COMMON_FLAG(bool, detect_deadlocks, false,
+ "If set, deadlock detection is enabled.")
+COMMON_FLAG(
+ uptr, clear_shadow_mmap_threshold, 64 * 1024,
+ "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
+ "memset(). This is the threshold size in bytes.")
+COMMON_FLAG(const char *, color, "auto",
+ "Colorize reports: (always|never|auto).")
+COMMON_FLAG(
+ bool, legacy_pthread_cond, false,
+ "Enables support for dynamic libraries linked with libpthread 2.2.5.")
+COMMON_FLAG(bool, intercept_tls_get_addr, false, "Intercept __tls_get_addr.")
+COMMON_FLAG(bool, help, false, "Print the flag descriptions.")
+COMMON_FLAG(uptr, mmap_limit_mb, 0,
+ "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
+ "not a user-facing flag, used mosly for testing the tools")
+COMMON_FLAG(uptr, hard_rss_limit_mb, 0,
+ "Hard RSS limit in Mb."
+ " If non-zero, a background thread is spawned at startup"
+ " which periodically reads RSS and aborts the process if the"
+ " limit is reached")
+COMMON_FLAG(uptr, soft_rss_limit_mb, 0,
+ "Soft RSS limit in Mb."
+ " If non-zero, a background thread is spawned at startup"
+ " which periodically reads RSS. If the limit is reached"
+ " all subsequent malloc/new calls will fail or return NULL"
+ " (depending on the value of allocator_may_return_null)"
+ " until the RSS goes below the soft limit."
+ " This limit does not affect memory allocations other than"
+ " malloc/new.")
+COMMON_FLAG(bool, can_use_proc_maps_statm, true,
+ "If false, do not attempt to read /proc/maps/statm."
+ " Mostly useful for testing sanitizers.")
+COMMON_FLAG(
+ bool, coverage, false,
+ "If set, coverage information will be dumped at program shutdown (if the "
+ "coverage instrumentation was enabled at compile time).")
+// On by default, but works only if coverage == true.
+COMMON_FLAG(bool, coverage_pcs, true,
+ "If set (and if 'coverage' is set too), the coverage information "
+ "will be dumped as a set of PC offsets for every module.")
+COMMON_FLAG(bool, coverage_bitset, false,
+ "If set (and if 'coverage' is set too), the coverage information "
+ "will also be dumped as a bitset to a separate file.")
+COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID,
+ "If set, coverage information will be dumped directly to a memory "
+ "mapped file. This way data is not lost even if the process is "
+ "suddenly killed.")
+COMMON_FLAG(const char *, coverage_dir, ".",
+ "Target directory for coverage dumps. Defaults to the current "
+ "directory.")
+COMMON_FLAG(bool, full_address_space, false,
+ "Sanitize complete address space; "
+ "by default kernel area on 32-bit platforms will not be sanitized")
+COMMON_FLAG(bool, print_suppressions, true,
+ "Print matched suppressions at exit.")
+COMMON_FLAG(
+ bool, disable_coredump, (SANITIZER_WORDSIZE == 64),
+ "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
+ "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
+ "default and for sanitizers that don't reserve lots of virtual memory.")
+COMMON_FLAG(bool, use_madv_dontdump, true,
+ "If set, instructs kernel to not store the (huge) shadow "
+ "in core file.")
+COMMON_FLAG(bool, symbolize_inline_frames, true,
+ "Print inlined frames in stacktraces. Defaults to true.")
+COMMON_FLAG(const char *, stack_trace_format, "DEFAULT",
+ "Format string used to render stack frames. "
+ "See sanitizer_stacktrace_printer.h for the format description. "
+ "Use DEFAULT to get default format.")
+COMMON_FLAG(bool, no_huge_pages_for_shadow, true,
+ "If true, the shadow is not allowed to use huge pages. ")
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h
new file mode 100644
index 000000000000..c9bba8064af0
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h
@@ -0,0 +1,137 @@
+//===-- sanitizer_freebsd.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 Sanitizer runtime. It contains FreeBSD-specific
+// definitions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_FREEBSD_H
+#define SANITIZER_FREEBSD_H
+
+#include "sanitizer_internal_defs.h"
+
+// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
+// 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+# include <osreldate.h>
+# if __FreeBSD_version <= 902001 // v9.2
+# include <link.h>
+# include <sys/param.h>
+# include <ucontext.h>
+
+namespace __sanitizer {
+
+typedef unsigned long long __xuint64_t;
+
+typedef __int32_t __xregister_t;
+
+typedef struct __xmcontext {
+ __xregister_t mc_onstack;
+ __xregister_t mc_gs;
+ __xregister_t mc_fs;
+ __xregister_t mc_es;
+ __xregister_t mc_ds;
+ __xregister_t mc_edi;
+ __xregister_t mc_esi;
+ __xregister_t mc_ebp;
+ __xregister_t mc_isp;
+ __xregister_t mc_ebx;
+ __xregister_t mc_edx;
+ __xregister_t mc_ecx;
+ __xregister_t mc_eax;
+ __xregister_t mc_trapno;
+ __xregister_t mc_err;
+ __xregister_t mc_eip;
+ __xregister_t mc_cs;
+ __xregister_t mc_eflags;
+ __xregister_t mc_esp;
+ __xregister_t mc_ss;
+
+ int mc_len;
+ int mc_fpformat;
+ int mc_ownedfp;
+ __xregister_t mc_flags;
+
+ int mc_fpstate[128] __aligned(16);
+ __xregister_t mc_fsbase;
+ __xregister_t mc_gsbase;
+ __xregister_t mc_xfpustate;
+ __xregister_t mc_xfpustate_len;
+
+ int mc_spare2[4];
+} xmcontext_t;
+
+typedef struct __xucontext {
+ sigset_t uc_sigmask;
+ xmcontext_t uc_mcontext;
+
+ struct __ucontext *uc_link;
+ stack_t uc_stack;
+ int uc_flags;
+ int __spare__[4];
+} xucontext_t;
+
+struct xkinfo_vmentry {
+ int kve_structsize;
+ int kve_type;
+ __xuint64_t kve_start;
+ __xuint64_t kve_end;
+ __xuint64_t kve_offset;
+ __xuint64_t kve_vn_fileid;
+ __uint32_t kve_vn_fsid;
+ int kve_flags;
+ int kve_resident;
+ int kve_private_resident;
+ int kve_protection;
+ int kve_ref_count;
+ int kve_shadow_count;
+ int kve_vn_type;
+ __xuint64_t kve_vn_size;
+ __uint32_t kve_vn_rdev;
+ __uint16_t kve_vn_mode;
+ __uint16_t kve_status;
+ int _kve_ispare[12];
+ char kve_path[PATH_MAX];
+};
+
+typedef struct {
+ __uint32_t p_type;
+ __uint32_t p_offset;
+ __uint32_t p_vaddr;
+ __uint32_t p_paddr;
+ __uint32_t p_filesz;
+ __uint32_t p_memsz;
+ __uint32_t p_flags;
+ __uint32_t p_align;
+} XElf32_Phdr;
+
+struct xdl_phdr_info {
+ Elf_Addr dlpi_addr;
+ const char *dlpi_name;
+ const XElf32_Phdr *dlpi_phdr;
+ Elf_Half dlpi_phnum;
+ unsigned long long int dlpi_adds;
+ unsigned long long int dlpi_subs;
+ size_t dlpi_tls_modid;
+ void *dlpi_tls_data;
+};
+
+typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
+typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
+
+#define xdl_iterate_phdr(callback, param) \
+ (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
+
+} // namespace __sanitizer
+
+# endif // __FreeBSD_version <= 902001
+#endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+
+#endif // SANITIZER_FREEBSD_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
new file mode 100644
index 000000000000..94d9f4e9524a
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
@@ -0,0 +1,58 @@
+//===-- sanitizer_interface_internal.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 shared between run-time libraries of sanitizers.
+//
+// This header declares the sanitizer runtime interface functions.
+// The runtime library has to define these functions so the instrumented program
+// could call them.
+//
+// See also include/sanitizer/common_interface_defs.h
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_INTERFACE_INTERNAL_H
+#define SANITIZER_INTERFACE_INTERNAL_H
+
+#include "sanitizer_internal_defs.h"
+
+extern "C" {
+ // Tell the tools to write their reports to "path.<pid>" instead of stderr.
+ // The special values are "stdout" and "stderr".
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __sanitizer_set_report_path(const char *path);
+
+ typedef struct {
+ int coverage_sandboxed;
+ __sanitizer::sptr coverage_fd;
+ unsigned int coverage_max_block_size;
+ } __sanitizer_sandbox_arguments;
+
+ // Notify the tools that the sandbox is going to be turned on.
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+ __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
+
+ // This function is called by the tool when it has just finished reporting
+ // an error. 'error_summary' is a one-line string that summarizes
+ // the error message. This function can be overridden by the client.
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_report_error_summary(const char *error_summary);
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
+ const void *end);
+} // extern "C"
+
+#endif // SANITIZER_INTERFACE_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
new file mode 100644
index 000000000000..a969f305cd1a
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -0,0 +1,300 @@
+//===-- sanitizer_internal_defs.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 shared between AddressSanitizer and ThreadSanitizer.
+// It contains macro used in run-time libraries code.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_DEFS_H
+#define SANITIZER_DEFS_H
+
+#include "sanitizer_platform.h"
+
+#ifndef SANITIZER_DEBUG
+# define SANITIZER_DEBUG 0
+#endif
+
+// Only use SANITIZER_*ATTRIBUTE* before the function return type!
+#if SANITIZER_WINDOWS
+# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
+// FIXME find out what we need on Windows, if anything.
+# define SANITIZER_WEAK_ATTRIBUTE
+#elif defined(SANITIZER_GO)
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#else
+# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
+#endif
+
+#if SANITIZER_LINUX && !defined(SANITIZER_GO)
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
+#else
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
+#endif
+
+// We can use .preinit_array section on Linux to call sanitizer initialization
+// functions very early in the process startup (unless PIC macro is defined).
+// FIXME: do we have anything like this on Mac?
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC)
+# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
+#else
+# define SANITIZER_CAN_USE_PREINIT_ARRAY 0
+#endif
+
+// GCC does not understand __has_feature
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+// For portability reasons we do not include stddef.h, stdint.h or any other
+// system header, but we do need some basic types that are not defined
+// in a portable way by the language itself.
+namespace __sanitizer {
+
+#if defined(_WIN64)
+// 64-bit Windows uses LLP64 data model.
+typedef unsigned long long uptr; // NOLINT
+typedef signed long long sptr; // NOLINT
+#else
+typedef unsigned long uptr; // NOLINT
+typedef signed long sptr; // NOLINT
+#endif // defined(_WIN64)
+#if defined(__x86_64__)
+// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
+// 64-bit pointer to unwind stack frame.
+typedef unsigned long long uhwptr; // NOLINT
+#else
+typedef uptr uhwptr; // NOLINT
+#endif
+typedef unsigned char u8;
+typedef unsigned short u16; // NOLINT
+typedef unsigned int u32;
+typedef unsigned long long u64; // NOLINT
+typedef signed char s8;
+typedef signed short s16; // NOLINT
+typedef signed int s32;
+typedef signed long long s64; // NOLINT
+typedef int fd_t;
+
+// WARNING: OFF_T may be different from OS type off_t, depending on the value of
+// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
+// like pread and mmap, as opposed to pread64 and mmap64.
+// FreeBSD, Mac and Linux/x86-64 are special.
+#if SANITIZER_FREEBSD || SANITIZER_MAC || \
+ (SANITIZER_LINUX && defined(__x86_64__))
+typedef u64 OFF_T;
+#else
+typedef uptr OFF_T;
+#endif
+typedef u64 OFF64_T;
+
+#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
+typedef uptr operator_new_size_type;
+#else
+typedef u32 operator_new_size_type;
+#endif
+} // namespace __sanitizer
+
+
+using namespace __sanitizer; // NOLINT
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers to avoid portability issues.
+
+// Common defs.
+#define INLINE inline
+#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#define WEAK SANITIZER_WEAK_ATTRIBUTE
+
+// Platform-specific defs.
+#if defined(_MSC_VER)
+# define ALWAYS_INLINE __forceinline
+// FIXME(timurrrr): do we need this on Windows?
+# define ALIAS(x)
+# define ALIGNED(x) __declspec(align(x))
+# define FORMAT(f, a)
+# define NOINLINE __declspec(noinline)
+# define NORETURN __declspec(noreturn)
+# define THREADLOCAL __declspec(thread)
+# define NOTHROW
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+# define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
+#else // _MSC_VER
+# define ALWAYS_INLINE inline __attribute__((always_inline))
+# define ALIAS(x) __attribute__((alias(x)))
+// Please only use the ALIGNED macro before the type.
+// Using ALIGNED after the variable declaration is not portable!
+# define ALIGNED(x) __attribute__((aligned(x)))
+# define FORMAT(f, a) __attribute__((format(printf, f, a)))
+# define NOINLINE __attribute__((noinline))
+# define NORETURN __attribute__((noreturn))
+# define THREADLOCAL __thread
+# define NOTHROW throw()
+# define LIKELY(x) __builtin_expect(!!(x), 1)
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+# if defined(__i386__) || defined(__x86_64__)
+// __builtin_prefetch(x) generates prefetchnt0 on x86
+# define PREFETCH(x) __asm__("prefetchnta (%0)" : : "r" (x))
+# else
+# define PREFETCH(x) __builtin_prefetch(x)
+# endif
+#endif // _MSC_VER
+
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
+# define USED __attribute__((used))
+#else
+# define UNUSED
+# define USED
+#endif
+
+// Unaligned versions of basic types.
+typedef ALIGNED(1) u16 uu16;
+typedef ALIGNED(1) u32 uu32;
+typedef ALIGNED(1) u64 uu64;
+typedef ALIGNED(1) s16 us16;
+typedef ALIGNED(1) s32 us32;
+typedef ALIGNED(1) s64 us64;
+
+#if SANITIZER_WINDOWS
+typedef unsigned long DWORD; // NOLINT
+typedef DWORD thread_return_t;
+# define THREAD_CALLING_CONV __stdcall
+#else // _WIN32
+typedef void* thread_return_t;
+# define THREAD_CALLING_CONV
+#endif // _WIN32
+typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
+
+// NOTE: Functions below must be defined in each run-time.
+namespace __sanitizer {
+void NORETURN Die();
+
+// FIXME: No, this shouldn't be in the sanitizer interface.
+SANITIZER_INTERFACE_ATTRIBUTE
+void NORETURN CheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2);
+} // namespace __sanitizer
+
+// Check macro
+#define RAW_CHECK_MSG(expr, msg) do { \
+ if (UNLIKELY(!(expr))) { \
+ RawWrite(msg); \
+ Die(); \
+ } \
+} while (0)
+
+#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr)
+
+#define CHECK_IMPL(c1, op, c2) \
+ do { \
+ __sanitizer::u64 v1 = (u64)(c1); \
+ __sanitizer::u64 v2 = (u64)(c2); \
+ if (UNLIKELY(!(v1 op v2))) \
+ __sanitizer::CheckFailed(__FILE__, __LINE__, \
+ "(" #c1 ") " #op " (" #c2 ")", v1, v2); \
+ } while (false) \
+/**/
+
+#define CHECK(a) CHECK_IMPL((a), !=, 0)
+#define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b))
+#define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b))
+#define CHECK_LT(a, b) CHECK_IMPL((a), <, (b))
+#define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b))
+#define CHECK_GT(a, b) CHECK_IMPL((a), >, (b))
+#define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b))
+
+#if SANITIZER_DEBUG
+#define DCHECK(a) CHECK(a)
+#define DCHECK_EQ(a, b) CHECK_EQ(a, b)
+#define DCHECK_NE(a, b) CHECK_NE(a, b)
+#define DCHECK_LT(a, b) CHECK_LT(a, b)
+#define DCHECK_LE(a, b) CHECK_LE(a, b)
+#define DCHECK_GT(a, b) CHECK_GT(a, b)
+#define DCHECK_GE(a, b) CHECK_GE(a, b)
+#else
+#define DCHECK(a)
+#define DCHECK_EQ(a, b)
+#define DCHECK_NE(a, b)
+#define DCHECK_LT(a, b)
+#define DCHECK_LE(a, b)
+#define DCHECK_GT(a, b)
+#define DCHECK_GE(a, b)
+#endif
+
+#define UNREACHABLE(msg) do { \
+ CHECK(0 && msg); \
+ Die(); \
+} while (0)
+
+#define UNIMPLEMENTED() UNREACHABLE("unimplemented")
+
+#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+#define IMPL_PASTE(a, b) a##b
+#define IMPL_COMPILER_ASSERT(pred, line) \
+ typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1]
+
+// Limits for integral types. We have to redefine it in case we don't
+// have stdint.h (like in Visual Studio 9).
+#undef __INT64_C
+#undef __UINT64_C
+#if SANITIZER_WORDSIZE == 64
+# define __INT64_C(c) c ## L
+# define __UINT64_C(c) c ## UL
+#else
+# define __INT64_C(c) c ## LL
+# define __UINT64_C(c) c ## ULL
+#endif // SANITIZER_WORDSIZE == 64
+#undef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#undef INT32_MAX
+#define INT32_MAX (2147483647)
+#undef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#undef INT64_MIN
+#define INT64_MIN (-__INT64_C(9223372036854775807)-1)
+#undef INT64_MAX
+#define INT64_MAX (__INT64_C(9223372036854775807))
+#undef UINT64_MAX
+#define UINT64_MAX (__UINT64_C(18446744073709551615))
+
+enum LinkerInitialized { LINKER_INITIALIZED = 0 };
+
+#if !defined(_MSC_VER) || defined(__clang__)
+# define GET_CALLER_PC() (uptr)__builtin_return_address(0)
+# define GET_CURRENT_FRAME() (uptr)__builtin_frame_address(0)
+#else
+extern "C" void* _ReturnAddress(void);
+# pragma intrinsic(_ReturnAddress)
+# define GET_CALLER_PC() (uptr)_ReturnAddress()
+// CaptureStackBackTrace doesn't need to know BP on Windows.
+// FIXME: This macro is still used when printing error reports though it's not
+// clear if the BP value is needed in the ASan reports on Windows.
+# define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
+#endif
+
+#define HANDLE_EINTR(res, f) \
+ { \
+ int rverrno; \
+ do { \
+ res = (f); \
+ } while (internal_iserror(res, &rverrno) && rverrno == EINTR); \
+ }
+
+// Forces the compiler to generate a frame pointer in the function.
+#define ENABLE_FRAME_POINTER \
+ do { \
+ volatile uptr enable_fp; \
+ enable_fp = GET_CURRENT_FRAME(); \
+ } while (0)
+
+#endif // SANITIZER_DEFS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h
new file mode 100644
index 000000000000..088413908087
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h
@@ -0,0 +1,73 @@
+//===-- sanitizer_lfstack.h -=-----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Lock-free stack.
+// Uses 32/17 bits as ABA-counter on 32/64-bit platforms.
+// The memory passed to Push() must not be ever munmap'ed.
+// The type T must contain T *next field.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LFSTACK_H
+#define SANITIZER_LFSTACK_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_atomic.h"
+
+namespace __sanitizer {
+
+template<typename T>
+struct LFStack {
+ void Clear() {
+ atomic_store(&head_, 0, memory_order_relaxed);
+ }
+
+ bool Empty() const {
+ return (atomic_load(&head_, memory_order_relaxed) & kPtrMask) == 0;
+ }
+
+ void Push(T *p) {
+ u64 cmp = atomic_load(&head_, memory_order_relaxed);
+ for (;;) {
+ u64 cnt = (cmp & kCounterMask) + kCounterInc;
+ u64 xch = (u64)(uptr)p | cnt;
+ p->next = (T*)(uptr)(cmp & kPtrMask);
+ if (atomic_compare_exchange_weak(&head_, &cmp, xch,
+ memory_order_release))
+ break;
+ }
+ }
+
+ T *Pop() {
+ u64 cmp = atomic_load(&head_, memory_order_acquire);
+ for (;;) {
+ T *cur = (T*)(uptr)(cmp & kPtrMask);
+ if (cur == 0)
+ return 0;
+ T *nxt = cur->next;
+ u64 cnt = (cmp & kCounterMask);
+ u64 xch = (u64)(uptr)nxt | cnt;
+ if (atomic_compare_exchange_weak(&head_, &cmp, xch,
+ memory_order_acquire))
+ return cur;
+ }
+ }
+
+ // private:
+ static const int kCounterBits = FIRST_32_SECOND_64(32, 17);
+ static const u64 kPtrMask = ((u64)-1) >> kCounterBits;
+ static const u64 kCounterMask = ~kPtrMask;
+ static const u64 kCounterInc = kPtrMask + 1;
+
+ atomic_uint64_t head_;
+};
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_LFSTACK_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc
new file mode 100644
index 000000000000..cb162a4c4984
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc
@@ -0,0 +1,261 @@
+//===-- sanitizer_libc.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries. See sanitizer_libc.h for details.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+s64 internal_atoll(const char *nptr) {
+ return internal_simple_strtoll(nptr, (char**)0, 10);
+}
+
+void *internal_memchr(const void *s, int c, uptr n) {
+ const char *t = (const char *)s;
+ for (uptr i = 0; i < n; ++i, ++t)
+ if (*t == c)
+ return reinterpret_cast<void *>(const_cast<char *>(t));
+ return 0;
+}
+
+void *internal_memrchr(const void *s, int c, uptr n) {
+ const char *t = (const char *)s;
+ void *res = nullptr;
+ for (uptr i = 0; i < n; ++i, ++t) {
+ if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t));
+ }
+ return res;
+}
+
+int internal_memcmp(const void* s1, const void* s2, uptr n) {
+ const char *t1 = (const char *)s1;
+ const char *t2 = (const char *)s2;
+ for (uptr i = 0; i < n; ++i, ++t1, ++t2)
+ if (*t1 != *t2)
+ return *t1 < *t2 ? -1 : 1;
+ return 0;
+}
+
+void *internal_memcpy(void *dest, const void *src, uptr n) {
+ char *d = (char*)dest;
+ const char *s = (const char *)src;
+ for (uptr i = 0; i < n; ++i)
+ d[i] = s[i];
+ return dest;
+}
+
+void *internal_memmove(void *dest, const void *src, uptr n) {
+ char *d = (char*)dest;
+ const char *s = (const char *)src;
+ sptr i, signed_n = (sptr)n;
+ CHECK_GE(signed_n, 0);
+ if (d < s) {
+ for (i = 0; i < signed_n; ++i)
+ d[i] = s[i];
+ } else {
+ if (d > s && signed_n > 0)
+ for (i = signed_n - 1; i >= 0 ; --i) {
+ d[i] = s[i];
+ }
+ }
+ return dest;
+}
+
+// Semi-fast bzero for 16-aligned data. Still far from peak performance.
+void internal_bzero_aligned16(void *s, uptr n) {
+ struct S16 { u64 a, b; } ALIGNED(16);
+ CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0);
+ for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) {
+ p->a = p->b = 0;
+ SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ }
+}
+
+void *internal_memset(void* s, int c, uptr n) {
+ // The next line prevents Clang from making a call to memset() instead of the
+ // loop below.
+ // FIXME: building the runtime with -ffreestanding is a better idea. However
+ // there currently are linktime problems due to PR12396.
+ char volatile *t = (char*)s;
+ for (uptr i = 0; i < n; ++i, ++t) {
+ *t = c;
+ }
+ return s;
+}
+
+uptr internal_strcspn(const char *s, const char *reject) {
+ uptr i;
+ for (i = 0; s[i]; i++) {
+ if (internal_strchr(reject, s[i]) != 0)
+ return i;
+ }
+ return i;
+}
+
+char* internal_strdup(const char *s) {
+ uptr len = internal_strlen(s);
+ char *s2 = (char*)InternalAlloc(len + 1);
+ internal_memcpy(s2, s, len);
+ s2[len] = 0;
+ return s2;
+}
+
+char* internal_strndup(const char *s, uptr n) {
+ uptr len = internal_strnlen(s, n);
+ char *s2 = (char*)InternalAlloc(len + 1);
+ internal_memcpy(s2, s, len);
+ s2[len] = 0;
+ return s2;
+}
+
+int internal_strcmp(const char *s1, const char *s2) {
+ while (true) {
+ unsigned c1 = *s1;
+ unsigned c2 = *s2;
+ if (c1 != c2) return (c1 < c2) ? -1 : 1;
+ if (c1 == 0) break;
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+
+int internal_strncmp(const char *s1, const char *s2, uptr n) {
+ for (uptr i = 0; i < n; i++) {
+ unsigned c1 = *s1;
+ unsigned c2 = *s2;
+ if (c1 != c2) return (c1 < c2) ? -1 : 1;
+ if (c1 == 0) break;
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+
+char* internal_strchr(const char *s, int c) {
+ while (true) {
+ if (*s == (char)c)
+ return const_cast<char *>(s);
+ if (*s == 0)
+ return 0;
+ s++;
+ }
+}
+
+char *internal_strchrnul(const char *s, int c) {
+ char *res = internal_strchr(s, c);
+ if (!res)
+ res = const_cast<char *>(s) + internal_strlen(s);
+ return res;
+}
+
+char *internal_strrchr(const char *s, int c) {
+ const char *res = 0;
+ for (uptr i = 0; s[i]; i++) {
+ if (s[i] == c) res = s + i;
+ }
+ return const_cast<char *>(res);
+}
+
+uptr internal_strlen(const char *s) {
+ uptr i = 0;
+ while (s[i]) i++;
+ return i;
+}
+
+char *internal_strncat(char *dst, const char *src, uptr n) {
+ uptr len = internal_strlen(dst);
+ uptr i;
+ for (i = 0; i < n && src[i]; i++)
+ dst[len + i] = src[i];
+ dst[len + i] = 0;
+ return dst;
+}
+
+char *internal_strncpy(char *dst, const char *src, uptr n) {
+ uptr i;
+ for (i = 0; i < n && src[i]; i++)
+ dst[i] = src[i];
+ internal_memset(dst + i, '\0', n - i);
+ return dst;
+}
+
+uptr internal_strnlen(const char *s, uptr maxlen) {
+ uptr i = 0;
+ while (i < maxlen && s[i]) i++;
+ return i;
+}
+
+char *internal_strstr(const char *haystack, const char *needle) {
+ // This is O(N^2), but we are not using it in hot places.
+ uptr len1 = internal_strlen(haystack);
+ uptr len2 = internal_strlen(needle);
+ if (len1 < len2) return 0;
+ for (uptr pos = 0; pos <= len1 - len2; pos++) {
+ if (internal_memcmp(haystack + pos, needle, len2) == 0)
+ return const_cast<char *>(haystack) + pos;
+ }
+ return 0;
+}
+
+s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
+ CHECK_EQ(base, 10);
+ while (IsSpace(*nptr)) nptr++;
+ int sgn = 1;
+ u64 res = 0;
+ bool have_digits = false;
+ char *old_nptr = const_cast<char *>(nptr);
+ if (*nptr == '+') {
+ sgn = 1;
+ nptr++;
+ } else if (*nptr == '-') {
+ sgn = -1;
+ nptr++;
+ }
+ while (IsDigit(*nptr)) {
+ res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX;
+ int digit = ((*nptr) - '0');
+ res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX;
+ have_digits = true;
+ nptr++;
+ }
+ if (endptr != 0) {
+ *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
+ }
+ if (sgn > 0) {
+ return (s64)(Min((u64)INT64_MAX, res));
+ } else {
+ return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1);
+ }
+}
+
+bool mem_is_zero(const char *beg, uptr size) {
+ CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check.
+ const char *end = beg + size;
+ uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
+ uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
+ uptr all = 0;
+ // Prologue.
+ for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++)
+ all |= *mem;
+ // Aligned loop.
+ for (; aligned_beg < aligned_end; aligned_beg++)
+ all |= *aligned_beg;
+ // Epilogue.
+ if ((char*)aligned_end >= beg)
+ for (const char *mem = (char*)aligned_end; mem < end; mem++)
+ all |= *mem;
+ return all == 0;
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
new file mode 100644
index 000000000000..c086b8a9139e
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
@@ -0,0 +1,129 @@
+//===-- sanitizer_libc.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// These tools can not use some of the libc functions directly because those
+// functions are intercepted. Instead, we implement a tiny subset of libc here.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LIBC_H
+#define SANITIZER_LIBC_H
+
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers from sanitizer runtime.
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// internal_X() is a custom implementation of X() for use in RTL.
+
+// String functions
+s64 internal_atoll(const char *nptr);
+void *internal_memchr(const void *s, int c, uptr n);
+void *internal_memrchr(const void *s, int c, uptr n);
+int internal_memcmp(const void* s1, const void* s2, uptr n);
+void *internal_memcpy(void *dest, const void *src, uptr n);
+void *internal_memmove(void *dest, const void *src, uptr n);
+// Set [s, s + n) to 0. Both s and n should be 16-aligned.
+void internal_bzero_aligned16(void *s, uptr n);
+// Should not be used in performance-critical places.
+void *internal_memset(void *s, int c, uptr n);
+char* internal_strchr(const char *s, int c);
+char *internal_strchrnul(const char *s, int c);
+int internal_strcmp(const char *s1, const char *s2);
+uptr internal_strcspn(const char *s, const char *reject);
+char *internal_strdup(const char *s);
+char *internal_strndup(const char *s, uptr n);
+uptr internal_strlen(const char *s);
+char *internal_strncat(char *dst, const char *src, uptr n);
+int internal_strncmp(const char *s1, const char *s2, uptr n);
+char *internal_strncpy(char *dst, const char *src, uptr n);
+uptr internal_strnlen(const char *s, uptr maxlen);
+char *internal_strrchr(const char *s, int c);
+// This is O(N^2), but we are not using it in hot places.
+char *internal_strstr(const char *haystack, const char *needle);
+// Works only for base=10 and doesn't set errno.
+s64 internal_simple_strtoll(const char *nptr, char **endptr, int base);
+int internal_snprintf(char *buffer, uptr length, const char *format, ...);
+
+// Return true if all bytes in [mem, mem+size) are zero.
+// Optimized for the case when the result is true.
+bool mem_is_zero(const char *mem, uptr size);
+
+
+// Memory
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+ int fd, u64 offset);
+uptr internal_munmap(void *addr, uptr length);
+
+// I/O
+const fd_t kInvalidFd = -1;
+const fd_t kStdinFd = 0;
+const fd_t kStdoutFd = 1;
+const fd_t kStderrFd = 2;
+uptr internal_close(fd_t fd);
+int internal_isatty(fd_t fd);
+
+// Use __sanitizer::OpenFile() instead.
+uptr internal_open(const char *filename, int flags);
+uptr internal_open(const char *filename, int flags, u32 mode);
+
+uptr internal_read(fd_t fd, void *buf, uptr count);
+uptr internal_write(fd_t fd, const void *buf, uptr count);
+uptr internal_ftruncate(fd_t fd, uptr size);
+
+// OS
+uptr internal_filesize(fd_t fd); // -1 on error.
+uptr internal_stat(const char *path, void *buf);
+uptr internal_lstat(const char *path, void *buf);
+uptr internal_fstat(fd_t fd, void *buf);
+uptr internal_dup2(int oldfd, int newfd);
+uptr internal_readlink(const char *path, char *buf, uptr bufsize);
+uptr internal_unlink(const char *path);
+uptr internal_rename(const char *oldpath, const char *newpath);
+void NORETURN internal__exit(int exitcode);
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
+
+uptr internal_ptrace(int request, int pid, void *addr, void *data);
+uptr internal_waitpid(int pid, int *status, int options);
+uptr internal_getpid();
+uptr internal_getppid();
+
+int internal_fork();
+
+// Threading
+uptr internal_sched_yield();
+
+// These functions call appropriate pthread_ functions directly, bypassing
+// the interceptor. They are weak and may not be present in some tools.
+SANITIZER_WEAK_ATTRIBUTE
+int real_pthread_create(void *th, void *attr, void *(*callback)(void *),
+ void *param);
+SANITIZER_WEAK_ATTRIBUTE
+int real_pthread_join(void *th, void **ret);
+
+#define DEFINE_REAL_PTHREAD_FUNCTIONS \
+ namespace __sanitizer { \
+ int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \
+ void *param) { \
+ return REAL(pthread_create)(th, attr, callback, param); \
+ } \
+ int real_pthread_join(void *th, void **ret) { \
+ return REAL(pthread_join(th, ret)); \
+ } \
+ } // namespace __sanitizer
+
+// Error handling
+bool internal_iserror(uptr retval, int *rverrno = 0);
+
+int internal_sigaction(int signum, const void *act, void *oldact);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBC_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
new file mode 100644
index 000000000000..cefb1dc97a17
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
@@ -0,0 +1,100 @@
+//===-- sanitizer_libignore.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "sanitizer_libignore.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+LibIgnore::LibIgnore(LinkerInitialized) {
+}
+
+void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
+ BlockingMutexLock lock(&mutex_);
+ if (count_ >= kMaxLibs) {
+ Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName,
+ kMaxLibs);
+ Die();
+ }
+ Lib *lib = &libs_[count_++];
+ lib->templ = internal_strdup(name_templ);
+ lib->name = nullptr;
+ lib->real_name = nullptr;
+ lib->loaded = false;
+}
+
+void LibIgnore::OnLibraryLoaded(const char *name) {
+ BlockingMutexLock lock(&mutex_);
+ // Try to match suppressions with symlink target.
+ InternalScopedString buf(kMaxPathLength);
+ if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
+ buf[0]) {
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ if (!lib->loaded && lib->real_name == 0 &&
+ TemplateMatch(lib->templ, name))
+ lib->real_name = internal_strdup(buf.data());
+ }
+ }
+
+ // Scan suppressions list and find newly loaded and unloaded libraries.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ InternalScopedString module(kMaxPathLength);
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ bool loaded = false;
+ proc_maps.Reset();
+ uptr b, e, off, prot;
+ while (proc_maps.Next(&b, &e, &off, module.data(), module.size(), &prot)) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+ continue;
+ if (TemplateMatch(lib->templ, module.data()) ||
+ (lib->real_name != 0 &&
+ internal_strcmp(lib->real_name, module.data()) == 0)) {
+ if (loaded) {
+ Report("%s: called_from_lib suppression '%s' is matched against"
+ " 2 libraries: '%s' and '%s'\n",
+ SanitizerToolName, lib->templ, lib->name, module.data());
+ Die();
+ }
+ loaded = true;
+ if (lib->loaded)
+ continue;
+ VReport(1,
+ "Matched called_from_lib suppression '%s' against library"
+ " '%s'\n",
+ lib->templ, module.data());
+ lib->loaded = true;
+ lib->name = internal_strdup(module.data());
+ const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
+ code_ranges_[idx].begin = b;
+ code_ranges_[idx].end = e;
+ atomic_store(&loaded_count_, idx + 1, memory_order_release);
+ }
+ }
+ if (lib->loaded && !loaded) {
+ Report("%s: library '%s' that was matched against called_from_lib"
+ " suppression '%s' is unloaded\n",
+ SanitizerToolName, lib->name, lib->templ);
+ Die();
+ }
+ }
+}
+
+void LibIgnore::OnLibraryUnloaded() {
+ OnLibraryLoaded(0);
+}
+
+} // namespace __sanitizer
+
+#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
new file mode 100644
index 000000000000..cd56c36c1c0e
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
@@ -0,0 +1,83 @@
+//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LibIgnore allows to ignore all interceptors called from a particular set
+// of dynamic libraries. LibIgnore can be initialized with several templates
+// of names of libraries to be ignored. It finds code ranges for the libraries;
+// and checks whether the provided PC value belongs to the code ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LIBIGNORE_H
+#define SANITIZER_LIBIGNORE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+class LibIgnore {
+ public:
+ explicit LibIgnore(LinkerInitialized);
+
+ // Must be called during initialization.
+ void AddIgnoredLibrary(const char *name_templ);
+
+ // Must be called after a new dynamic library is loaded.
+ void OnLibraryLoaded(const char *name);
+
+ // Must be called after a dynamic library is unloaded.
+ void OnLibraryUnloaded();
+
+ // Checks whether the provided PC belongs to one of the ignored libraries.
+ bool IsIgnored(uptr pc) const;
+
+ private:
+ struct Lib {
+ char *templ;
+ char *name;
+ char *real_name; // target of symlink
+ bool loaded;
+ };
+
+ struct LibCodeRange {
+ uptr begin;
+ uptr end;
+ };
+
+ static const uptr kMaxLibs = 128;
+
+ // Hot part:
+ atomic_uintptr_t loaded_count_;
+ LibCodeRange code_ranges_[kMaxLibs];
+
+ // Cold part:
+ BlockingMutex mutex_;
+ uptr count_;
+ Lib libs_[kMaxLibs];
+
+ // Disallow copying of LibIgnore objects.
+ LibIgnore(const LibIgnore&); // not implemented
+ void operator = (const LibIgnore&); // not implemented
+};
+
+inline bool LibIgnore::IsIgnored(uptr pc) const {
+ const uptr n = atomic_load(&loaded_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end)
+ return true;
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBIGNORE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
new file mode 100644
index 000000000000..8029181a5173
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
@@ -0,0 +1,933 @@
+//===-- sanitizer_linux.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements linux-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
+
+#if !SANITIZER_FREEBSD
+#include <asm/param.h>
+#endif
+
+// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
+// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
+// access stat from asm/stat.h, without conflicting with definition in
+// sys/stat.h, we use this trick.
+#if defined(__mips64)
+#include <sys/types.h>
+#define stat kernel_stat
+#include <asm/stat.h>
+#undef stat
+#endif
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#if !SANITIZER_ANDROID
+#include <link.h>
+#endif
+#include <pthread.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if SANITIZER_FREEBSD
+#include <sys/sysctl.h>
+#include <machine/atomic.h>
+extern "C" {
+// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
+// FreeBSD 9.2 and 10.0.
+#include <sys/umtx.h>
+}
+extern char **environ; // provided by crt1
+#endif // SANITIZER_FREEBSD
+
+#if !SANITIZER_ANDROID
+#include <sys/signal.h>
+#endif
+
+#if SANITIZER_ANDROID
+#include <android/log.h>
+#include <sys/system_properties.h>
+#endif
+
+#if SANITIZER_LINUX
+// <linux/time.h>
+struct kernel_timeval {
+ long tv_sec;
+ long tv_usec;
+};
+
+// <linux/futex.h> is broken on some linux distributions.
+const int FUTEX_WAIT = 0;
+const int FUTEX_WAKE = 1;
+#endif // SANITIZER_LINUX
+
+// Are we using 32-bit or 64-bit Linux syscalls?
+// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
+// but it still needs to use 64-bit syscalls.
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64)
+# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
+#else
+# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
+#endif
+
+namespace __sanitizer {
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+#include "sanitizer_syscall_linux_x86_64.inc"
+#else
+#include "sanitizer_syscall_generic.inc"
+#endif
+
+// --------------- sanitizer_libc.h
+uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
+ u64 offset) {
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
+ offset);
+#else
+ // mmap2 specifies file offset in 4096-byte units.
+ CHECK(IsAligned(offset, 4096));
+ return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
+ offset / 4096);
+#endif
+}
+
+uptr internal_munmap(void *addr, uptr length) {
+ return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
+}
+
+uptr internal_close(fd_t fd) {
+ return internal_syscall(SYSCALL(close), fd);
+}
+
+uptr internal_open(const char *filename, int flags) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
+#else
+ return internal_syscall(SYSCALL(open), (uptr)filename, flags);
+#endif
+}
+
+uptr internal_open(const char *filename, int flags, u32 mode) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
+ mode);
+#else
+ return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
+#endif
+}
+
+uptr OpenFile(const char *filename, bool write) {
+ return internal_open(filename,
+ write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
+}
+
+uptr internal_read(fd_t fd, void *buf, uptr count) {
+ sptr res;
+ HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
+ count));
+ return res;
+}
+
+uptr internal_write(fd_t fd, const void *buf, uptr count) {
+ sptr res;
+ HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf,
+ count));
+ return res;
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+ sptr res;
+ HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size));
+ return res;
+}
+
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD
+static void stat64_to_stat(struct stat64 *in, struct stat *out) {
+ internal_memset(out, 0, sizeof(*out));
+ out->st_dev = in->st_dev;
+ out->st_ino = in->st_ino;
+ out->st_mode = in->st_mode;
+ out->st_nlink = in->st_nlink;
+ out->st_uid = in->st_uid;
+ out->st_gid = in->st_gid;
+ out->st_rdev = in->st_rdev;
+ out->st_size = in->st_size;
+ out->st_blksize = in->st_blksize;
+ out->st_blocks = in->st_blocks;
+ out->st_atime = in->st_atime;
+ out->st_mtime = in->st_mtime;
+ out->st_ctime = in->st_ctime;
+ out->st_ino = in->st_ino;
+}
+#endif
+
+#if defined(__mips64)
+static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
+ internal_memset(out, 0, sizeof(*out));
+ out->st_dev = in->st_dev;
+ out->st_ino = in->st_ino;
+ out->st_mode = in->st_mode;
+ out->st_nlink = in->st_nlink;
+ out->st_uid = in->st_uid;
+ out->st_gid = in->st_gid;
+ out->st_rdev = in->st_rdev;
+ out->st_size = in->st_size;
+ out->st_blksize = in->st_blksize;
+ out->st_blocks = in->st_blocks;
+ out->st_atime = in->st_atime_nsec;
+ out->st_mtime = in->st_mtime_nsec;
+ out->st_ctime = in->st_ctime_nsec;
+ out->st_ino = in->st_ino;
+}
+#endif
+
+uptr internal_stat(const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(stat), path, buf);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, 0);
+#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+# if defined(__mips64)
+ // For mips64, stat syscall fills buffer in the format of kernel_stat
+ struct kernel_stat kbuf;
+ int res = internal_syscall(SYSCALL(stat), path, &kbuf);
+ kernel_stat_to_stat(&kbuf, (struct stat *)buf);
+ return res;
+# else
+ return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf);
+# endif
+#else
+ struct stat64 buf64;
+ int res = internal_syscall(SYSCALL(stat64), path, &buf64);
+ stat64_to_stat(&buf64, (struct stat *)buf);
+ return res;
+#endif
+}
+
+uptr internal_lstat(const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(lstat), path, buf);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, AT_SYMLINK_NOFOLLOW);
+#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf);
+#else
+ struct stat64 buf64;
+ int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
+ stat64_to_stat(&buf64, (struct stat *)buf);
+ return res;
+#endif
+}
+
+uptr internal_fstat(fd_t fd, void *buf) {
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
+#else
+ struct stat64 buf64;
+ int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
+ stat64_to_stat(&buf64, (struct stat *)buf);
+ return res;
+#endif
+}
+
+uptr internal_filesize(fd_t fd) {
+ struct stat st;
+ if (internal_fstat(fd, &st))
+ return -1;
+ return (uptr)st.st_size;
+}
+
+uptr internal_dup2(int oldfd, int newfd) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
+#else
+ return internal_syscall(SYSCALL(dup2), oldfd, newfd);
+#endif
+}
+
+uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(readlinkat), AT_FDCWD,
+ (uptr)path, (uptr)buf, bufsize);
+#else
+ return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
+#endif
+}
+
+uptr internal_unlink(const char *path) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
+#else
+ return internal_syscall(SYSCALL(unlink), (uptr)path);
+#endif
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
+ (uptr)newpath);
+#else
+ return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
+#endif
+}
+
+uptr internal_sched_yield() {
+ return internal_syscall(SYSCALL(sched_yield));
+}
+
+void internal__exit(int exitcode) {
+#if SANITIZER_FREEBSD
+ internal_syscall(SYSCALL(exit), exitcode);
+#else
+ internal_syscall(SYSCALL(exit_group), exitcode);
+#endif
+ Die(); // Unreachable.
+}
+
+uptr internal_execve(const char *filename, char *const argv[],
+ char *const envp[]) {
+ return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
+ (uptr)envp);
+}
+
+// ----------------- sanitizer_common.h
+bool FileExists(const char *filename) {
+ struct stat st;
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0))
+#else
+ if (internal_stat(filename, &st))
+#endif
+ return false;
+ // Sanity check: filename is a regular file.
+ return S_ISREG(st.st_mode);
+}
+
+uptr GetTid() {
+#if SANITIZER_FREEBSD
+ return (uptr)pthread_self();
+#else
+ return internal_syscall(SYSCALL(gettid));
+#endif
+}
+
+u64 NanoTime() {
+#if SANITIZER_FREEBSD
+ timeval tv;
+#else
+ kernel_timeval tv;
+#endif
+ internal_memset(&tv, 0, sizeof(tv));
+ internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0);
+ return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
+}
+
+// Like getenv, but reads env directly from /proc (on Linux) or parses the
+// 'environ' array (on FreeBSD) and does not use libc. This function should be
+// called first inside __asan_init.
+const char *GetEnv(const char *name) {
+#if SANITIZER_FREEBSD
+ if (::environ != 0) {
+ uptr NameLen = internal_strlen(name);
+ for (char **Env = ::environ; *Env != 0; Env++) {
+ if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
+ return (*Env) + NameLen + 1;
+ }
+ }
+ return 0; // Not found.
+#elif SANITIZER_LINUX
+ static char *environ;
+ static uptr len;
+ static bool inited;
+ if (!inited) {
+ inited = true;
+ uptr environ_size;
+ len = ReadFileToBuffer("/proc/self/environ",
+ &environ, &environ_size, 1 << 26);
+ }
+ if (!environ || len == 0) return 0;
+ uptr namelen = internal_strlen(name);
+ const char *p = environ;
+ while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
+ // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
+ const char* endp =
+ (char*)internal_memchr(p, '\0', len - (p - environ));
+ if (endp == 0) // this entry isn't NUL terminated
+ return 0;
+ else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
+ return p + namelen + 1; // point after =
+ p = endp + 1;
+ }
+ return 0; // Not found.
+#else
+#error "Unsupported platform"
+#endif
+}
+
+extern "C" {
+ SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
+}
+
+#if !SANITIZER_GO
+static void ReadNullSepFileToArray(const char *path, char ***arr,
+ int arr_size) {
+ char *buff;
+ uptr buff_size = 0;
+ *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
+ ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024);
+ (*arr)[0] = buff;
+ int count, i;
+ for (count = 1, i = 1; ; i++) {
+ if (buff[i] == 0) {
+ if (buff[i+1] == 0) break;
+ (*arr)[count] = &buff[i+1];
+ CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible.
+ count++;
+ }
+ }
+ (*arr)[count] = 0;
+}
+#endif
+
+static void GetArgsAndEnv(char*** argv, char*** envp) {
+#if !SANITIZER_GO
+ if (&__libc_stack_end) {
+#endif
+ uptr* stack_end = (uptr*)__libc_stack_end;
+ int argc = *stack_end;
+ *argv = (char**)(stack_end + 1);
+ *envp = (char**)(stack_end + argc + 2);
+#if !SANITIZER_GO
+ } else {
+ static const int kMaxArgv = 2000, kMaxEnvp = 2000;
+ ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
+ ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
+ }
+#endif
+}
+
+void ReExec() {
+ char **argv, **envp;
+ GetArgsAndEnv(&argv, &envp);
+ uptr rv = internal_execve("/proc/self/exe", argv, envp);
+ int rverrno;
+ CHECK_EQ(internal_iserror(rv, &rverrno), true);
+ Printf("execve failed, errno %d\n", rverrno);
+ Die();
+}
+
+enum MutexState {
+ MtxUnlocked = 0,
+ MtxLocked = 1,
+ MtxSleeping = 2
+};
+
+BlockingMutex::BlockingMutex() {
+ internal_memset(this, 0, sizeof(*this));
+}
+
+void BlockingMutex::Lock() {
+ CHECK_EQ(owner_, 0);
+ atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
+ if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
+ return;
+ while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
+#if SANITIZER_FREEBSD
+ _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
+#else
+ internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+#endif
+ }
+}
+
+void BlockingMutex::Unlock() {
+ atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
+ u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
+ CHECK_NE(v, MtxUnlocked);
+ if (v == MtxSleeping) {
+#if SANITIZER_FREEBSD
+ _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
+#else
+ internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
+#endif
+ }
+}
+
+void BlockingMutex::CheckLocked() {
+ atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
+ CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
+}
+
+// ----------------- sanitizer_linux.h
+// The actual size of this structure is specified by d_reclen.
+// Note that getdents64 uses a different structure format. We only provide the
+// 32-bit syscall here.
+struct linux_dirent {
+#if SANITIZER_X32
+ u64 d_ino;
+ u64 d_off;
+#else
+ unsigned long d_ino;
+ unsigned long d_off;
+#endif
+ unsigned short d_reclen;
+ char d_name[256];
+};
+
+// Syscall wrappers.
+uptr internal_ptrace(int request, int pid, void *addr, void *data) {
+ return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
+ (uptr)data);
+}
+
+uptr internal_waitpid(int pid, int *status, int options) {
+ return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
+ 0 /* rusage */);
+}
+
+uptr internal_getpid() {
+ return internal_syscall(SYSCALL(getpid));
+}
+
+uptr internal_getppid() {
+ return internal_syscall(SYSCALL(getppid));
+}
+
+uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
+#else
+ return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
+#endif
+}
+
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
+ return internal_syscall(SYSCALL(lseek), fd, offset, whence);
+}
+
+#if SANITIZER_LINUX
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
+ return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
+}
+#endif
+
+uptr internal_sigaltstack(const struct sigaltstack *ss,
+ struct sigaltstack *oss) {
+ return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
+}
+
+int internal_fork() {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
+#else
+ return internal_syscall(SYSCALL(fork));
+#endif
+}
+
+#if SANITIZER_LINUX
+// Doesn't set sa_restorer, use with caution (see below).
+int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
+ __sanitizer_kernel_sigaction_t k_act, k_oldact;
+ internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
+ internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t));
+ const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act;
+ __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact;
+ if (u_act) {
+ k_act.handler = u_act->handler;
+ k_act.sigaction = u_act->sigaction;
+ internal_memcpy(&k_act.sa_mask, &u_act->sa_mask,
+ sizeof(__sanitizer_kernel_sigset_t));
+ k_act.sa_flags = u_act->sa_flags;
+ // FIXME: most often sa_restorer is unset, however the kernel requires it
+ // to point to a valid signal restorer that calls the rt_sigreturn syscall.
+ // If sa_restorer passed to the kernel is NULL, the program may crash upon
+ // signal delivery or fail to unwind the stack in the signal handler.
+ // libc implementation of sigaction() passes its own restorer to
+ // rt_sigaction, so we need to do the same (we'll need to reimplement the
+ // restorers; for x86_64 the restorer address can be obtained from
+ // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
+ k_act.sa_restorer = u_act->sa_restorer;
+ }
+
+ uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
+ (uptr)(u_act ? &k_act : NULL),
+ (uptr)(u_oldact ? &k_oldact : NULL),
+ (uptr)sizeof(__sanitizer_kernel_sigset_t));
+
+ if ((result == 0) && u_oldact) {
+ u_oldact->handler = k_oldact.handler;
+ u_oldact->sigaction = k_oldact.sigaction;
+ internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
+ sizeof(__sanitizer_kernel_sigset_t));
+ u_oldact->sa_flags = k_oldact.sa_flags;
+ u_oldact->sa_restorer = k_oldact.sa_restorer;
+ }
+ return result;
+}
+#endif // SANITIZER_LINUX
+
+uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset) {
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
+#else
+ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+ __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
+ return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how,
+ (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0],
+ sizeof(__sanitizer_kernel_sigset_t));
+#endif
+}
+
+void internal_sigfillset(__sanitizer_sigset_t *set) {
+ internal_memset(set, 0xff, sizeof(*set));
+}
+
+#if SANITIZER_LINUX
+void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
+ signum -= 1;
+ CHECK_GE(signum, 0);
+ CHECK_LT(signum, sizeof(*set) * 8);
+ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+ const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
+ const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
+ k_set->sig[idx] &= ~(1 << bit);
+}
+#endif // SANITIZER_LINUX
+
+// ThreadLister implementation.
+ThreadLister::ThreadLister(int pid)
+ : pid_(pid),
+ descriptor_(-1),
+ buffer_(4096),
+ error_(true),
+ entry_((struct linux_dirent *)buffer_.data()),
+ bytes_read_(0) {
+ char task_directory_path[80];
+ internal_snprintf(task_directory_path, sizeof(task_directory_path),
+ "/proc/%d/task/", pid);
+ uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
+ if (internal_iserror(openrv)) {
+ error_ = true;
+ Report("Can't open /proc/%d/task for reading.\n", pid);
+ } else {
+ error_ = false;
+ descriptor_ = openrv;
+ }
+}
+
+int ThreadLister::GetNextTID() {
+ int tid = -1;
+ do {
+ if (error_)
+ return -1;
+ if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries())
+ return -1;
+ if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' &&
+ entry_->d_name[0] <= '9') {
+ // Found a valid tid.
+ tid = (int)internal_atoll(entry_->d_name);
+ }
+ entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen);
+ } while (tid < 0);
+ return tid;
+}
+
+void ThreadLister::Reset() {
+ if (error_ || descriptor_ < 0)
+ return;
+ internal_lseek(descriptor_, 0, SEEK_SET);
+}
+
+ThreadLister::~ThreadLister() {
+ if (descriptor_ >= 0)
+ internal_close(descriptor_);
+}
+
+bool ThreadLister::error() { return error_; }
+
+bool ThreadLister::GetDirectoryEntries() {
+ CHECK_GE(descriptor_, 0);
+ CHECK_NE(error_, true);
+ bytes_read_ = internal_getdents(descriptor_,
+ (struct linux_dirent *)buffer_.data(),
+ buffer_.size());
+ if (internal_iserror(bytes_read_)) {
+ Report("Can't read directory entries from /proc/%d/task.\n", pid_);
+ error_ = true;
+ return false;
+ } else if (bytes_read_ == 0) {
+ return false;
+ }
+ entry_ = (struct linux_dirent *)buffer_.data();
+ return true;
+}
+
+uptr GetPageSize() {
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
+ return EXEC_PAGESIZE;
+#else
+ return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
+#endif
+}
+
+static char proc_self_exe_cache_str[kMaxPathLength];
+static uptr proc_self_exe_cache_len = 0;
+
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+ if (proc_self_exe_cache_len > 0) {
+ // If available, use the cached module name.
+ uptr module_name_len =
+ internal_snprintf(buf, buf_len, "%s", proc_self_exe_cache_str);
+ CHECK_LT(module_name_len, buf_len);
+ return module_name_len;
+ }
+#if SANITIZER_FREEBSD
+ const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ size_t Size = buf_len;
+ bool IsErr = (sysctl(Mib, 4, buf, &Size, NULL, 0) != 0);
+ int readlink_error = IsErr ? errno : 0;
+ uptr module_name_len = Size;
+#else
+ uptr module_name_len = internal_readlink(
+ "/proc/self/exe", buf, buf_len);
+ int readlink_error;
+ bool IsErr = internal_iserror(module_name_len, &readlink_error);
+#endif
+ if (IsErr) {
+ // We can't read /proc/self/exe for some reason, assume the name of the
+ // binary is unknown.
+ Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
+ "some stack frames may not be symbolized\n", readlink_error);
+ module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
+ CHECK_LT(module_name_len, buf_len);
+ }
+ return module_name_len;
+}
+
+void CacheBinaryName() {
+ if (!proc_self_exe_cache_len) {
+ proc_self_exe_cache_len =
+ ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
+ }
+}
+
+// Match full names of the form /path/to/base_name{-,.}*
+bool LibraryNameIs(const char *full_name, const char *base_name) {
+ const char *name = full_name;
+ // Strip path.
+ while (*name != '\0') name++;
+ while (name > full_name && *name != '/') name--;
+ if (*name == '/') name++;
+ uptr base_name_length = internal_strlen(base_name);
+ if (internal_strncmp(name, base_name, base_name_length)) return false;
+ return (name[base_name_length] == '-' || name[base_name_length] == '.');
+}
+
+#if !SANITIZER_ANDROID
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+ CHECK_NE(map, nullptr);
+#if !SANITIZER_FREEBSD
+ typedef ElfW(Phdr) Elf_Phdr;
+ typedef ElfW(Ehdr) Elf_Ehdr;
+#endif // !SANITIZER_FREEBSD
+ char *base = (char *)map->l_addr;
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
+ char *phdrs = base + ehdr->e_phoff;
+ char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
+
+ // Find the segment with the minimum base so we can "relocate" the p_vaddr
+ // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
+ // objects have a non-zero base.
+ uptr preferred_base = (uptr)-1;
+ for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+ Elf_Phdr *phdr = (Elf_Phdr *)iter;
+ if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
+ preferred_base = (uptr)phdr->p_vaddr;
+ }
+
+ // Compute the delta from the real base to get a relocation delta.
+ sptr delta = (uptr)base - preferred_base;
+ // Now we can figure out what the loader really mapped.
+ for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+ Elf_Phdr *phdr = (Elf_Phdr *)iter;
+ if (phdr->p_type == PT_LOAD) {
+ uptr seg_start = phdr->p_vaddr + delta;
+ uptr seg_end = seg_start + phdr->p_memsz;
+ // None of these values are aligned. We consider the ragged edges of the
+ // load command as defined, since they are mapped from the file.
+ seg_start = RoundDownTo(seg_start, GetPageSizeCached());
+ seg_end = RoundUpTo(seg_end, GetPageSizeCached());
+ cb((void *)seg_start, seg_end - seg_start);
+ }
+ }
+}
+#endif
+
+#if defined(__x86_64__) && SANITIZER_LINUX
+// We cannot use glibc's clone wrapper, because it messes with the child
+// task's TLS. It writes the PID and TID of the child task to its thread
+// descriptor, but in our case the child task shares the thread descriptor with
+// the parent (because we don't know how to allocate a new thread
+// descriptor to keep glibc happy). So the stock version of clone(), when
+// used with CLONE_VM, would end up corrupting the parent's thread descriptor.
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ long long res;
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+ ((unsigned long long *)child_stack)[0] = (uptr)fn;
+ ((unsigned long long *)child_stack)[1] = (uptr)arg;
+ register void *r8 __asm__("r8") = newtls;
+ register int *r10 __asm__("r10") = child_tidptr;
+ __asm__ __volatile__(
+ /* %rax = syscall(%rax = SYSCALL(clone),
+ * %rdi = flags,
+ * %rsi = child_stack,
+ * %rdx = parent_tidptr,
+ * %r8 = new_tls,
+ * %r10 = child_tidptr)
+ */
+ "syscall\n"
+
+ /* if (%rax != 0)
+ * return;
+ */
+ "testq %%rax,%%rax\n"
+ "jnz 1f\n"
+
+ /* In the child. Terminate unwind chain. */
+ // XXX: We should also terminate the CFI unwind chain
+ // here. Unfortunately clang 3.2 doesn't support the
+ // necessary CFI directives, so we skip that part.
+ "xorq %%rbp,%%rbp\n"
+
+ /* Call "fn(arg)". */
+ "popq %%rax\n"
+ "popq %%rdi\n"
+ "call *%%rax\n"
+
+ /* Call _exit(%rax). */
+ "movq %%rax,%%rdi\n"
+ "movq %2,%%rax\n"
+ "syscall\n"
+
+ /* Return to parent. */
+ "1:\n"
+ : "=a" (res)
+ : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
+ "S"(child_stack),
+ "D"(flags),
+ "d"(parent_tidptr),
+ "r"(r8),
+ "r"(r10)
+ : "rsp", "memory", "r11", "rcx");
+ return res;
+}
+#elif defined(__mips__)
+// TODO(sagarthakur): clone function is to be rewritten in assembly.
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ return clone(fn, child_stack, flags, arg, parent_tidptr,
+ newtls, child_tidptr);
+}
+#endif // defined(__x86_64__) && SANITIZER_LINUX
+
+#if SANITIZER_ANDROID
+static atomic_uint8_t android_log_initialized;
+
+void AndroidLogInit() {
+ atomic_store(&android_log_initialized, 1, memory_order_release);
+}
+// This thing is not, strictly speaking, async signal safe, but it does not seem
+// to cause any issues. Alternative is writing to log devices directly, but
+// their location and message format might change in the future, so we'd really
+// like to avoid that.
+void AndroidLogWrite(const char *buffer) {
+ if (!atomic_load(&android_log_initialized, memory_order_acquire))
+ return;
+
+ char *copy = internal_strdup(buffer);
+ char *p = copy;
+ char *q;
+ // __android_log_write has an implicit message length limit.
+ // Print one line at a time.
+ do {
+ q = internal_strchr(p, '\n');
+ if (q) *q = '\0';
+ __android_log_write(ANDROID_LOG_INFO, NULL, p);
+ if (q) p = q + 1;
+ } while (q);
+ InternalFree(copy);
+}
+
+void GetExtraActivationFlags(char *buf, uptr size) {
+ CHECK(size > PROP_VALUE_MAX);
+ __system_property_get("asan.options", buf);
+}
+#endif
+
+bool IsDeadlySignal(int signum) {
+ return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
+}
+
+#ifndef SANITIZER_GO
+void *internal_start_thread(void(*func)(void *arg), void *arg) {
+ // Start the thread with signals blocked, otherwise it can steal user signals.
+ __sanitizer_sigset_t set, old;
+ internal_sigfillset(&set);
+ internal_sigprocmask(SIG_SETMASK, &set, &old);
+ void *th;
+ real_pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
+ internal_sigprocmask(SIG_SETMASK, &old, 0);
+ return th;
+}
+
+void internal_join_thread(void *th) {
+ real_pthread_join(th, 0);
+}
+#else
+void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
+
+void internal_join_thread(void *th) {}
+#endif
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
new file mode 100644
index 000000000000..b2e603d3a23e
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
@@ -0,0 +1,93 @@
+//===-- sanitizer_linux.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Linux-specific syscall wrappers and classes.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LINUX_H
+#define SANITIZER_LINUX_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
+struct link_map; // Opaque type returned by dlopen().
+struct sigaltstack;
+
+namespace __sanitizer {
+// Dirent structure for getdents(). Note that this structure is different from
+// the one in <dirent.h>, which is used by readdir().
+struct linux_dirent;
+
+// Syscall wrappers.
+uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
+uptr internal_sigaltstack(const struct sigaltstack* ss,
+ struct sigaltstack* oss);
+uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset);
+void internal_sigfillset(__sanitizer_sigset_t *set);
+
+// Linux-only syscalls.
+#if SANITIZER_LINUX
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
+// Used only by sanitizer_stoptheworld. Signal handlers that are actually used
+// (like the process-wide error reporting SEGV handler) must use
+// internal_sigaction instead.
+int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
+void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
+#if defined(__x86_64__) || defined(__mips__)
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr);
+#endif
+#endif // SANITIZER_LINUX
+
+// This class reads thread IDs from /proc/<pid>/task using only syscalls.
+class ThreadLister {
+ public:
+ explicit ThreadLister(int pid);
+ ~ThreadLister();
+ // GetNextTID returns -1 if the list of threads is exhausted, or if there has
+ // been an error.
+ int GetNextTID();
+ void Reset();
+ bool error();
+
+ private:
+ bool GetDirectoryEntries();
+
+ int pid_;
+ int descriptor_;
+ InternalScopedBuffer<char> buffer_;
+ bool error_;
+ struct linux_dirent* entry_;
+ int bytes_read_;
+};
+
+// Exposed for testing.
+uptr ThreadDescriptorSize();
+uptr ThreadSelf();
+uptr ThreadSelfOffset();
+
+// Matches a library's file name against a base name (stripping path and version
+// information).
+bool LibraryNameIs(const char *full_name, const char *base_name);
+
+// Read the name of the current binary from /proc/self/exe.
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
+// Cache the value of /proc/self/exe.
+void CacheBinaryName();
+
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_LINUX_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
new file mode 100644
index 000000000000..c71b6257ebc3
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -0,0 +1,519 @@
+//===-- sanitizer_linux_libcdep.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements linux-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_freebsd.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_symbolizer.h"
+
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <dlfcn.h> // for dlsym()
+#endif
+
+#include <pthread.h>
+#include <signal.h>
+#include <sys/resource.h>
+
+#if SANITIZER_FREEBSD
+#include <pthread_np.h>
+#include <osreldate.h>
+#define pthread_getattr_np pthread_attr_get_np
+#endif
+
+#if SANITIZER_LINUX
+#include <sys/prctl.h>
+#endif
+
+#if !SANITIZER_ANDROID
+#include <elf.h>
+#include <link.h>
+#include <unistd.h>
+#endif
+
+namespace __sanitizer {
+
+// This function is defined elsewhere if we intercepted pthread_attr_getstack.
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE int
+real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
+} // extern "C"
+
+static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) {
+#if !SANITIZER_GO
+ if (&real_pthread_attr_getstack)
+ return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
+#endif
+ return pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
+}
+
+SANITIZER_WEAK_ATTRIBUTE int
+real_sigaction(int signum, const void *act, void *oldact);
+
+int internal_sigaction(int signum, const void *act, void *oldact) {
+#if !SANITIZER_GO
+ if (&real_sigaction)
+ return real_sigaction(signum, act, oldact);
+#endif
+ return sigaction(signum, (const struct sigaction *)act,
+ (struct sigaction *)oldact);
+}
+
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom) {
+ CHECK(stack_top);
+ CHECK(stack_bottom);
+ if (at_initialization) {
+ // This is the main thread. Libpthread may not be initialized yet.
+ struct rlimit rl;
+ CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
+
+ // Find the mapping that contains a stack variable.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr start, end, offset;
+ uptr prev_end = 0;
+ while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) {
+ if ((uptr)&rl < end)
+ break;
+ prev_end = end;
+ }
+ CHECK((uptr)&rl >= start && (uptr)&rl < end);
+
+ // Get stacksize from rlimit, but clip it so that it does not overlap
+ // with other mappings.
+ uptr stacksize = rl.rlim_cur;
+ if (stacksize > end - prev_end)
+ stacksize = end - prev_end;
+ // When running with unlimited stack size, we still want to set some limit.
+ // The unlimited stack size is caused by 'ulimit -s unlimited'.
+ // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
+ if (stacksize > kMaxThreadStackSize)
+ stacksize = kMaxThreadStackSize;
+ *stack_top = end;
+ *stack_bottom = end - stacksize;
+ return;
+ }
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
+ uptr stacksize = 0;
+ void *stackaddr = 0;
+ my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+ pthread_attr_destroy(&attr);
+
+ CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
+ *stack_top = (uptr)stackaddr + stacksize;
+ *stack_bottom = (uptr)stackaddr;
+}
+
+#if !SANITIZER_GO
+bool SetEnv(const char *name, const char *value) {
+ void *f = dlsym(RTLD_NEXT, "setenv");
+ if (f == 0)
+ return false;
+ typedef int(*setenv_ft)(const char *name, const char *value, int overwrite);
+ setenv_ft setenv_f;
+ CHECK_EQ(sizeof(setenv_f), sizeof(f));
+ internal_memcpy(&setenv_f, &f, sizeof(f));
+ return setenv_f(name, value, 1) == 0;
+}
+#endif
+
+bool SanitizerSetThreadName(const char *name) {
+#ifdef PR_SET_NAME
+ return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); // NOLINT
+#else
+ return false;
+#endif
+}
+
+bool SanitizerGetThreadName(char *name, int max_len) {
+#ifdef PR_GET_NAME
+ char buff[17];
+ if (prctl(PR_GET_NAME, (unsigned long)buff, 0, 0, 0)) // NOLINT
+ return false;
+ internal_strncpy(name, buff, max_len);
+ name[max_len] = 0;
+ return true;
+#else
+ return false;
+#endif
+}
+
+#if !SANITIZER_FREEBSD
+static uptr g_tls_size;
+#endif
+
+#ifdef __i386__
+# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
+#else
+# define DL_INTERNAL_FUNCTION
+#endif
+
+#if defined(__mips__)
+// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
+// head structure. It lies before the static tls blocks.
+static uptr TlsPreTcbSize() {
+ const uptr kTcbHead = 16;
+ const uptr kTlsAlign = 16;
+ const uptr kTlsPreTcbSize =
+ (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
+ InitTlsSize();
+ g_tls_size = (g_tls_size + kTlsPreTcbSize + kTlsAlign -1) & ~(kTlsAlign - 1);
+ return kTlsPreTcbSize;
+}
+#endif
+
+void InitTlsSize() {
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
+ typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
+ get_tls_func get_tls;
+ void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
+ CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr));
+ internal_memcpy(&get_tls, &get_tls_static_info_ptr,
+ sizeof(get_tls_static_info_ptr));
+ CHECK_NE(get_tls, 0);
+ size_t tls_size = 0;
+ size_t tls_align = 0;
+ get_tls(&tls_size, &tls_align);
+ g_tls_size = tls_size;
+#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID
+}
+
+#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__)) \
+ && SANITIZER_LINUX
+// sizeof(struct thread) from glibc.
+static atomic_uintptr_t kThreadDescriptorSize;
+
+uptr ThreadDescriptorSize() {
+ uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
+ if (val)
+ return val;
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef _CS_GNU_LIBC_VERSION
+ char buf[64];
+ uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
+ if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) {
+ char *end;
+ int minor = internal_simple_strtoll(buf + 8, &end, 10);
+ if (end != buf + 8 && (*end == '\0' || *end == '.')) {
+ /* sizeof(struct thread) values from various glibc versions. */
+ if (SANITIZER_X32)
+ val = 1728; // Assume only one particular version for x32.
+ else if (minor <= 3)
+ val = FIRST_32_SECOND_64(1104, 1696);
+ else if (minor == 4)
+ val = FIRST_32_SECOND_64(1120, 1728);
+ else if (minor == 5)
+ val = FIRST_32_SECOND_64(1136, 1728);
+ else if (minor <= 9)
+ val = FIRST_32_SECOND_64(1136, 1712);
+ else if (minor == 10)
+ val = FIRST_32_SECOND_64(1168, 1776);
+ else if (minor <= 12)
+ val = FIRST_32_SECOND_64(1168, 2288);
+ else if (minor == 13)
+ val = FIRST_32_SECOND_64(1168, 2304);
+ else
+ val = FIRST_32_SECOND_64(1216, 2304);
+ }
+ if (val)
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+ return val;
+ }
+#endif
+#elif defined(__mips__)
+ // TODO(sagarthakur): add more values as per different glibc versions.
+ val = FIRST_32_SECOND_64(1152, 1776);
+ if (val)
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+ return val;
+#endif
+ return 0;
+}
+
+// The offset at which pointer to self is located in the thread descriptor.
+const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
+
+uptr ThreadSelfOffset() {
+ return kThreadSelfOffset;
+}
+
+uptr ThreadSelf() {
+ uptr descr_addr;
+# if defined(__i386__)
+ asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+# elif defined(__x86_64__)
+ asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+# elif defined(__mips__)
+ // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
+ // points to the end of the TCB + 0x7000. The pthread_descr structure is
+ // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
+ // TCB and the size of pthread_descr.
+ const uptr kTlsTcbOffset = 0x7000;
+ uptr thread_pointer;
+ asm volatile(".set push;\
+ .set mips64r2;\
+ rdhwr %0,$29;\
+ .set pop" : "=r" (thread_pointer));
+ descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
+# else
+# error "unsupported CPU arch"
+# endif
+ return descr_addr;
+}
+#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
+
+#if SANITIZER_FREEBSD
+static void **ThreadSelfSegbase() {
+ void **segbase = 0;
+# if defined(__i386__)
+ // sysarch(I386_GET_GSBASE, segbase);
+ __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
+# elif defined(__x86_64__)
+ // sysarch(AMD64_GET_FSBASE, segbase);
+ __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
+# else
+# error "unsupported CPU arch for FreeBSD platform"
+# endif
+ return segbase;
+}
+
+uptr ThreadSelf() {
+ return (uptr)ThreadSelfSegbase()[2];
+}
+#endif // SANITIZER_FREEBSD
+
+#if !SANITIZER_GO
+static void GetTls(uptr *addr, uptr *size) {
+#if SANITIZER_LINUX
+# if defined(__x86_64__) || defined(__i386__)
+ *addr = ThreadSelf();
+ *size = GetTlsSize();
+ *addr -= *size;
+ *addr += ThreadDescriptorSize();
+# elif defined(__mips__)
+ *addr = ThreadSelf();
+ *size = GetTlsSize();
+# else
+ *addr = 0;
+ *size = 0;
+# endif
+#elif SANITIZER_FREEBSD
+ void** segbase = ThreadSelfSegbase();
+ *addr = 0;
+ *size = 0;
+ if (segbase != 0) {
+ // tcbalign = 16
+ // tls_size = round(tls_static_space, tcbalign);
+ // dtv = segbase[1];
+ // dtv[2] = segbase - tls_static_space;
+ void **dtv = (void**) segbase[1];
+ *addr = (uptr) dtv[2];
+ *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
+ }
+#else
+# error "Unknown OS"
+#endif
+}
+#endif
+
+#if !SANITIZER_GO
+uptr GetTlsSize() {
+#if SANITIZER_FREEBSD
+ uptr addr, size;
+ GetTls(&addr, &size);
+ return size;
+#else
+ return g_tls_size;
+#endif
+}
+#endif
+
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size) {
+#if SANITIZER_GO
+ // Stub implementation for Go.
+ *stk_addr = *stk_size = *tls_addr = *tls_size = 0;
+#else
+ GetTls(tls_addr, tls_size);
+
+ uptr stack_top, stack_bottom;
+ GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
+ *stk_addr = stack_bottom;
+ *stk_size = stack_top - stack_bottom;
+
+ if (!main) {
+ // If stack and tls intersect, make them non-intersecting.
+ if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
+ CHECK_GT(*tls_addr + *tls_size, *stk_addr);
+ CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
+ *stk_size -= *tls_size;
+ *tls_addr = *stk_addr + *stk_size;
+ }
+ }
+#endif
+}
+
+void AdjustStackSize(void *attr_) {
+ pthread_attr_t *attr = (pthread_attr_t *)attr_;
+ uptr stackaddr = 0;
+ size_t stacksize = 0;
+ my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+ // GLibC will return (0 - stacksize) as the stack address in the case when
+ // stacksize is set, but stackaddr is not.
+ bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
+ // We place a lot of tool data into TLS, account for that.
+ const uptr minstacksize = GetTlsSize() + 128*1024;
+ if (stacksize < minstacksize) {
+ if (!stack_set) {
+ if (stacksize != 0) {
+ VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
+ minstacksize);
+ pthread_attr_setstacksize(attr, minstacksize);
+ }
+ } else {
+ Printf("Sanitizer: pre-allocated stack size is insufficient: "
+ "%zu < %zu\n", stacksize, minstacksize);
+ Printf("Sanitizer: pthread_create is likely to fail.\n");
+ }
+ }
+}
+
+#if SANITIZER_ANDROID
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ MemoryMappingLayout memory_mapping(false);
+ return memory_mapping.DumpListOfModules(modules, max_modules, filter);
+}
+#else // SANITIZER_ANDROID
+# if !SANITIZER_FREEBSD
+typedef ElfW(Phdr) Elf_Phdr;
+# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
+# define Elf_Phdr XElf32_Phdr
+# define dl_phdr_info xdl_phdr_info
+# define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
+# endif
+
+struct DlIteratePhdrData {
+ LoadedModule *modules;
+ uptr current_n;
+ bool first;
+ uptr max_n;
+ string_predicate_t filter;
+};
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+ DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
+ if (data->current_n == data->max_n)
+ return 0;
+ InternalScopedString module_name(kMaxPathLength);
+ if (data->first) {
+ data->first = false;
+ // First module is the binary itself.
+ ReadBinaryName(module_name.data(), module_name.size());
+ } else if (info->dlpi_name) {
+ module_name.append("%s", info->dlpi_name);
+ }
+ if (module_name[0] == '\0')
+ return 0;
+ if (data->filter && !data->filter(module_name.data()))
+ return 0;
+ void *mem = &data->modules[data->current_n];
+ LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
+ info->dlpi_addr);
+ data->current_n++;
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr cur_end = cur_beg + phdr->p_memsz;
+ bool executable = phdr->p_flags & PF_X;
+ cur_module->addAddressRange(cur_beg, cur_end, executable);
+ }
+ }
+ return 0;
+}
+
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ CHECK(modules);
+ DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
+ dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+ return data.current_n;
+}
+#endif // SANITIZER_ANDROID
+
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ // Some kinds of sandboxes may forbid filesystem access, so we won't be able
+ // to read the file mappings from /proc/self/maps. Luckily, neither the
+ // process will be able to load additional libraries, so it's fine to use the
+ // cached mappings.
+ MemoryMappingLayout::CacheMemoryMappings();
+ // Same for /proc/self/exe in the symbolizer.
+#if !SANITIZER_GO
+ Symbolizer::GetOrInit()->PrepareForSandboxing();
+ CovPrepareForSandboxing(args);
+#endif
+}
+
+// getrusage does not give us the current RSS, only the max RSS.
+// Still, this is better than nothing if /proc/self/statm is not available
+// for some reason, e.g. due to a sandbox.
+static uptr GetRSSFromGetrusage() {
+ struct rusage usage;
+ if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox.
+ return 0;
+ return usage.ru_maxrss << 10; // ru_maxrss is in Kb.
+}
+
+uptr GetRSS() {
+ if (!common_flags()->can_use_proc_maps_statm)
+ return GetRSSFromGetrusage();
+ uptr fd = OpenFile("/proc/self/statm", false);
+ if ((sptr)fd < 0)
+ return GetRSSFromGetrusage();
+ char buf[64];
+ uptr len = internal_read(fd, buf, sizeof(buf) - 1);
+ internal_close(fd);
+ if ((sptr)len <= 0)
+ return 0;
+ buf[len] = 0;
+ // The format of the file is:
+ // 1084 89 69 11 0 79 0
+ // We need the second number which is RSS in pages.
+ char *pos = buf;
+ // Skip the first number.
+ while (*pos >= '0' && *pos <= '9')
+ pos++;
+ // Skip whitespaces.
+ while (!(*pos >= '0' && *pos <= '9') && *pos != 0)
+ pos++;
+ // Read the number.
+ uptr rss = 0;
+ while (*pos >= '0' && *pos <= '9')
+ rss = rss * 10 + *pos++ - '0';
+ return rss * GetPageSizeCached();
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h
new file mode 100644
index 000000000000..6dd9c8f7bca1
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h
@@ -0,0 +1,145 @@
+//===-- sanitizer_list.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 contains implementation of a list class to be used by
+// ThreadSanitizer, etc run-times.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LIST_H
+#define SANITIZER_LIST_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// Intrusive singly-linked list with size(), push_back(), push_front()
+// pop_front(), append_front() and append_back().
+// This class should be a POD (so that it can be put into TLS)
+// and an object with all zero fields should represent a valid empty list.
+// This class does not have a CTOR, so clear() should be called on all
+// non-zero-initialized objects before using.
+template<class Item>
+struct IntrusiveList {
+ friend class Iterator;
+
+ void clear() {
+ first_ = last_ = 0;
+ size_ = 0;
+ }
+
+ bool empty() const { return size_ == 0; }
+ uptr size() const { return size_; }
+
+ void push_back(Item *x) {
+ if (empty()) {
+ x->next = 0;
+ first_ = last_ = x;
+ size_ = 1;
+ } else {
+ x->next = 0;
+ last_->next = x;
+ last_ = x;
+ size_++;
+ }
+ }
+
+ void push_front(Item *x) {
+ if (empty()) {
+ x->next = 0;
+ first_ = last_ = x;
+ size_ = 1;
+ } else {
+ x->next = first_;
+ first_ = x;
+ size_++;
+ }
+ }
+
+ void pop_front() {
+ CHECK(!empty());
+ first_ = first_->next;
+ if (first_ == 0)
+ last_ = 0;
+ size_--;
+ }
+
+ Item *front() { return first_; }
+ Item *back() { return last_; }
+
+ void append_front(IntrusiveList<Item> *l) {
+ CHECK_NE(this, l);
+ if (l->empty())
+ return;
+ if (empty()) {
+ *this = *l;
+ } else if (!l->empty()) {
+ l->last_->next = first_;
+ first_ = l->first_;
+ size_ += l->size();
+ }
+ l->clear();
+ }
+
+ void append_back(IntrusiveList<Item> *l) {
+ CHECK_NE(this, l);
+ if (l->empty())
+ return;
+ if (empty()) {
+ *this = *l;
+ } else {
+ last_->next = l->first_;
+ last_ = l->last_;
+ size_ += l->size();
+ }
+ l->clear();
+ }
+
+ void CheckConsistency() {
+ if (size_ == 0) {
+ CHECK_EQ(first_, 0);
+ CHECK_EQ(last_, 0);
+ } else {
+ uptr count = 0;
+ for (Item *i = first_; ; i = i->next) {
+ count++;
+ if (i == last_) break;
+ }
+ CHECK_EQ(size(), count);
+ CHECK_EQ(last_->next, 0);
+ }
+ }
+
+ template<class ListTy, class ItemTy>
+ class IteratorBase {
+ public:
+ explicit IteratorBase(ListTy *list)
+ : list_(list), current_(list->first_) { }
+ ItemTy *next() {
+ ItemTy *ret = current_;
+ if (current_) current_ = current_->next;
+ return ret;
+ }
+ bool hasNext() const { return current_ != 0; }
+ private:
+ ListTy *list_;
+ ItemTy *current_;
+ };
+
+ typedef IteratorBase<IntrusiveList<Item>, Item> Iterator;
+ typedef IteratorBase<const IntrusiveList<Item>, const Item> ConstIterator;
+
+// private, don't use directly.
+ uptr size_;
+ Item *first_;
+ Item *last_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIST_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
new file mode 100644
index 000000000000..39a5c7e8d24f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
@@ -0,0 +1,333 @@
+//===-- sanitizer_mac.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 shared between various sanitizers' runtime libraries and
+// implements OSX-specific functions.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
+// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
+// the clients will most certainly use 64-bit ones as well.
+#ifndef _DARWIN_USE_64_BIT_INODE
+#define _DARWIN_USE_64_BIT_INODE 1
+#endif
+#include <stdio.h>
+
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mac.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+#include <crt_externs.h> // for _NSGetEnviron
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libkern/OSAtomic.h>
+#include <errno.h>
+
+namespace __sanitizer {
+
+#include "sanitizer_syscall_generic.inc"
+
+// ---------------------- sanitizer_libc.h
+uptr internal_mmap(void *addr, size_t length, int prot, int flags,
+ int fd, u64 offset) {
+ return (uptr)mmap(addr, length, prot, flags, fd, offset);
+}
+
+uptr internal_munmap(void *addr, uptr length) {
+ return munmap(addr, length);
+}
+
+uptr internal_close(fd_t fd) {
+ return close(fd);
+}
+
+uptr internal_open(const char *filename, int flags) {
+ return open(filename, flags);
+}
+
+uptr internal_open(const char *filename, int flags, u32 mode) {
+ return open(filename, flags, mode);
+}
+
+uptr OpenFile(const char *filename, bool write) {
+ return internal_open(filename,
+ write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+}
+
+uptr internal_read(fd_t fd, void *buf, uptr count) {
+ return read(fd, buf, count);
+}
+
+uptr internal_write(fd_t fd, const void *buf, uptr count) {
+ return write(fd, buf, count);
+}
+
+uptr internal_stat(const char *path, void *buf) {
+ return stat(path, (struct stat *)buf);
+}
+
+uptr internal_lstat(const char *path, void *buf) {
+ return lstat(path, (struct stat *)buf);
+}
+
+uptr internal_fstat(fd_t fd, void *buf) {
+ return fstat(fd, (struct stat *)buf);
+}
+
+uptr internal_filesize(fd_t fd) {
+ struct stat st;
+ if (internal_fstat(fd, &st))
+ return -1;
+ return (uptr)st.st_size;
+}
+
+uptr internal_dup2(int oldfd, int newfd) {
+ return dup2(oldfd, newfd);
+}
+
+uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
+ return readlink(path, buf, bufsize);
+}
+
+uptr internal_unlink(const char *path) {
+ return unlink(path);
+}
+
+uptr internal_sched_yield() {
+ return sched_yield();
+}
+
+void internal__exit(int exitcode) {
+ _exit(exitcode);
+}
+
+uptr internal_getpid() {
+ return getpid();
+}
+
+int internal_sigaction(int signum, const void *act, void *oldact) {
+ return sigaction(signum,
+ (struct sigaction *)act, (struct sigaction *)oldact);
+}
+
+int internal_fork() {
+ // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
+ return fork();
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+ return rename(oldpath, newpath);
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+ return ftruncate(fd, size);
+}
+
+// ----------------- sanitizer_common.h
+bool FileExists(const char *filename) {
+ struct stat st;
+ if (stat(filename, &st))
+ return false;
+ // Sanity check: filename is a regular file.
+ return S_ISREG(st.st_mode);
+}
+
+uptr GetTid() {
+ return reinterpret_cast<uptr>(pthread_self());
+}
+
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom) {
+ CHECK(stack_top);
+ CHECK(stack_bottom);
+ uptr stacksize = pthread_get_stacksize_np(pthread_self());
+ // pthread_get_stacksize_np() returns an incorrect stack size for the main
+ // thread on Mavericks. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=261
+ if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
+ stacksize == (1 << 19)) {
+ struct rlimit rl;
+ CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
+ // Most often rl.rlim_cur will be the desired 8M.
+ if (rl.rlim_cur < kMaxThreadStackSize) {
+ stacksize = rl.rlim_cur;
+ } else {
+ stacksize = kMaxThreadStackSize;
+ }
+ }
+ void *stackaddr = pthread_get_stackaddr_np(pthread_self());
+ *stack_top = (uptr)stackaddr;
+ *stack_bottom = *stack_top - stacksize;
+}
+
+const char *GetEnv(const char *name) {
+ char ***env_ptr = _NSGetEnviron();
+ if (!env_ptr) {
+ Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
+ "called after libSystem_initializer().\n");
+ CHECK(env_ptr);
+ }
+ char **environ = *env_ptr;
+ CHECK(environ);
+ uptr name_len = internal_strlen(name);
+ while (*environ != 0) {
+ uptr len = internal_strlen(*environ);
+ if (len > name_len) {
+ const char *p = *environ;
+ if (!internal_memcmp(p, name, name_len) &&
+ p[name_len] == '=') { // Match.
+ return *environ + name_len + 1; // String starting after =.
+ }
+ }
+ environ++;
+ }
+ return 0;
+}
+
+void ReExec() {
+ UNIMPLEMENTED();
+}
+
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ (void)args;
+ // Nothing here for now.
+}
+
+uptr GetPageSize() {
+ return sysconf(_SC_PAGESIZE);
+}
+
+BlockingMutex::BlockingMutex() {
+ internal_memset(this, 0, sizeof(*this));
+}
+
+void BlockingMutex::Lock() {
+ CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
+ CHECK_EQ(OS_SPINLOCK_INIT, 0);
+ CHECK_NE(owner_, (uptr)pthread_self());
+ OSSpinLockLock((OSSpinLock*)&opaque_storage_);
+ CHECK(!owner_);
+ owner_ = (uptr)pthread_self();
+}
+
+void BlockingMutex::Unlock() {
+ CHECK(owner_ == (uptr)pthread_self());
+ owner_ = 0;
+ OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
+}
+
+void BlockingMutex::CheckLocked() {
+ CHECK_EQ((uptr)pthread_self(), owner_);
+}
+
+u64 NanoTime() {
+ return 0;
+}
+
+uptr GetTlsSize() {
+ return 0;
+}
+
+void InitTlsSize() {
+}
+
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size) {
+#ifndef SANITIZER_GO
+ uptr stack_top, stack_bottom;
+ GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
+ *stk_addr = stack_bottom;
+ *stk_size = stack_top - stack_bottom;
+ *tls_addr = 0;
+ *tls_size = 0;
+#else
+ *stk_addr = 0;
+ *stk_size = 0;
+ *tls_addr = 0;
+ *tls_size = 0;
+#endif
+}
+
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ MemoryMappingLayout memory_mapping(false);
+ return memory_mapping.DumpListOfModules(modules, max_modules, filter);
+}
+
+bool IsDeadlySignal(int signum) {
+ return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
+}
+
+MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
+
+MacosVersion GetMacosVersionInternal() {
+ int mib[2] = { CTL_KERN, KERN_OSRELEASE };
+ char version[100];
+ uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
+ for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
+ // Get the version length.
+ CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
+ CHECK_LT(len, maxlen);
+ CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
+ switch (version[0]) {
+ case '9': return MACOS_VERSION_LEOPARD;
+ case '1': {
+ switch (version[1]) {
+ case '0': return MACOS_VERSION_SNOW_LEOPARD;
+ case '1': return MACOS_VERSION_LION;
+ case '2': return MACOS_VERSION_MOUNTAIN_LION;
+ case '3': return MACOS_VERSION_MAVERICKS;
+ case '4': return MACOS_VERSION_YOSEMITE;
+ default:
+ if (IsDigit(version[1]))
+ return MACOS_VERSION_UNKNOWN_NEWER;
+ else
+ return MACOS_VERSION_UNKNOWN;
+ }
+ }
+ default: return MACOS_VERSION_UNKNOWN;
+ }
+}
+
+MacosVersion GetMacosVersion() {
+ atomic_uint32_t *cache =
+ reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
+ MacosVersion result =
+ static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
+ if (result == MACOS_VERSION_UNINITIALIZED) {
+ result = GetMacosVersionInternal();
+ atomic_store(cache, result, memory_order_release);
+ }
+ return result;
+}
+
+uptr GetRSS() {
+ return 0;
+}
+
+void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
+void internal_join_thread(void *th) { }
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
new file mode 100644
index 000000000000..9eed905187ec
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
@@ -0,0 +1,38 @@
+//===-- sanitizer_mac.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 shared between various sanitizers' runtime libraries and
+// provides definitions for OSX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_MAC_H
+#define SANITIZER_MAC_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
+namespace __sanitizer {
+
+enum MacosVersion {
+ MACOS_VERSION_UNINITIALIZED = 0,
+ MACOS_VERSION_UNKNOWN,
+ MACOS_VERSION_LEOPARD,
+ MACOS_VERSION_SNOW_LEOPARD,
+ MACOS_VERSION_LION,
+ MACOS_VERSION_MOUNTAIN_LION,
+ MACOS_VERSION_MAVERICKS,
+ MACOS_VERSION_YOSEMITE,
+ MACOS_VERSION_UNKNOWN_NEWER
+};
+
+MacosVersion GetMacosVersion();
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
+#endif // SANITIZER_MAC_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mutex.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mutex.h
new file mode 100644
index 000000000000..d06fc45ff931
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mutex.h
@@ -0,0 +1,219 @@
+//===-- sanitizer_mutex.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_MUTEX_H
+#define SANITIZER_MUTEX_H
+
+#include "sanitizer_atomic.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+class StaticSpinMutex {
+ public:
+ void Init() {
+ atomic_store(&state_, 0, memory_order_relaxed);
+ }
+
+ void Lock() {
+ if (TryLock())
+ return;
+ LockSlow();
+ }
+
+ bool TryLock() {
+ return atomic_exchange(&state_, 1, memory_order_acquire) == 0;
+ }
+
+ void Unlock() {
+ atomic_store(&state_, 0, memory_order_release);
+ }
+
+ void CheckLocked() {
+ CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1);
+ }
+
+ private:
+ atomic_uint8_t state_;
+
+ void NOINLINE LockSlow() {
+ for (int i = 0;; i++) {
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ if (atomic_load(&state_, memory_order_relaxed) == 0
+ && atomic_exchange(&state_, 1, memory_order_acquire) == 0)
+ return;
+ }
+ }
+};
+
+class SpinMutex : public StaticSpinMutex {
+ public:
+ SpinMutex() {
+ Init();
+ }
+
+ private:
+ SpinMutex(const SpinMutex&);
+ void operator=(const SpinMutex&);
+};
+
+class BlockingMutex {
+ public:
+#if SANITIZER_WINDOWS
+ // Windows does not currently support LinkerInitialized
+ explicit BlockingMutex(LinkerInitialized);
+#else
+ explicit constexpr BlockingMutex(LinkerInitialized)
+ : opaque_storage_ {0, }, owner_(0) {}
+#endif
+ BlockingMutex();
+ void Lock();
+ void Unlock();
+ void CheckLocked();
+ private:
+ uptr opaque_storage_[10];
+ uptr owner_; // for debugging
+};
+
+// Reader-writer spin mutex.
+class RWMutex {
+ public:
+ RWMutex() {
+ atomic_store(&state_, kUnlocked, memory_order_relaxed);
+ }
+
+ ~RWMutex() {
+ CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+ }
+
+ void Lock() {
+ u32 cmp = kUnlocked;
+ if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
+ memory_order_acquire))
+ return;
+ LockSlow();
+ }
+
+ void Unlock() {
+ u32 prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
+ DCHECK_NE(prev & kWriteLock, 0);
+ (void)prev;
+ }
+
+ void ReadLock() {
+ u32 prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
+ if ((prev & kWriteLock) == 0)
+ return;
+ ReadLockSlow();
+ }
+
+ void ReadUnlock() {
+ u32 prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
+ DCHECK_EQ(prev & kWriteLock, 0);
+ DCHECK_GT(prev & ~kWriteLock, 0);
+ (void)prev;
+ }
+
+ void CheckLocked() {
+ CHECK_NE(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+ }
+
+ private:
+ atomic_uint32_t state_;
+
+ enum {
+ kUnlocked = 0,
+ kWriteLock = 1,
+ kReadLock = 2
+ };
+
+ void NOINLINE LockSlow() {
+ for (int i = 0;; i++) {
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ u32 cmp = atomic_load(&state_, memory_order_relaxed);
+ if (cmp == kUnlocked &&
+ atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
+ memory_order_acquire))
+ return;
+ }
+ }
+
+ void NOINLINE ReadLockSlow() {
+ for (int i = 0;; i++) {
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ u32 prev = atomic_load(&state_, memory_order_acquire);
+ if ((prev & kWriteLock) == 0)
+ return;
+ }
+ }
+
+ RWMutex(const RWMutex&);
+ void operator = (const RWMutex&);
+};
+
+template<typename MutexType>
+class GenericScopedLock {
+ public:
+ explicit GenericScopedLock(MutexType *mu)
+ : mu_(mu) {
+ mu_->Lock();
+ }
+
+ ~GenericScopedLock() {
+ mu_->Unlock();
+ }
+
+ private:
+ MutexType *mu_;
+
+ GenericScopedLock(const GenericScopedLock&);
+ void operator=(const GenericScopedLock&);
+};
+
+template<typename MutexType>
+class GenericScopedReadLock {
+ public:
+ explicit GenericScopedReadLock(MutexType *mu)
+ : mu_(mu) {
+ mu_->ReadLock();
+ }
+
+ ~GenericScopedReadLock() {
+ mu_->ReadUnlock();
+ }
+
+ private:
+ MutexType *mu_;
+
+ GenericScopedReadLock(const GenericScopedReadLock&);
+ void operator=(const GenericScopedReadLock&);
+};
+
+typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock;
+typedef GenericScopedLock<BlockingMutex> BlockingMutexLock;
+typedef GenericScopedLock<RWMutex> RWMutexLock;
+typedef GenericScopedReadLock<RWMutex> RWMutexReadLock;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MUTEX_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.cc
new file mode 100644
index 000000000000..5fa533a70861
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_persistent_allocator.cc -----------------------*- 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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_persistent_allocator.h"
+
+namespace __sanitizer {
+
+PersistentAllocator thePersistentAllocator;
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h
new file mode 100644
index 000000000000..326406b12bfb
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h
@@ -0,0 +1,71 @@
+//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A fast memory allocator that does not support free() nor realloc().
+// All allocations are forever.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
+#define SANITIZER_PERSISTENT_ALLOCATOR_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+class PersistentAllocator {
+ public:
+ void *alloc(uptr size);
+
+ private:
+ void *tryAlloc(uptr size);
+ StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator.
+ atomic_uintptr_t region_pos; // Region allocator for Node's.
+ atomic_uintptr_t region_end;
+};
+
+inline void *PersistentAllocator::tryAlloc(uptr size) {
+ // Optimisic lock-free allocation, essentially try to bump the region ptr.
+ for (;;) {
+ uptr cmp = atomic_load(&region_pos, memory_order_acquire);
+ uptr end = atomic_load(&region_end, memory_order_acquire);
+ if (cmp == 0 || cmp + size > end) return 0;
+ if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size,
+ memory_order_acquire))
+ return (void *)cmp;
+ }
+}
+
+inline void *PersistentAllocator::alloc(uptr size) {
+ // First, try to allocate optimisitically.
+ void *s = tryAlloc(size);
+ if (s) return s;
+ // If failed, lock, retry and alloc new superblock.
+ SpinMutexLock l(&mtx);
+ for (;;) {
+ s = tryAlloc(size);
+ if (s) return s;
+ atomic_store(&region_pos, 0, memory_order_relaxed);
+ uptr allocsz = 64 * 1024;
+ if (allocsz < size) allocsz = size;
+ uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
+ atomic_store(&region_end, mem + allocsz, memory_order_release);
+ atomic_store(&region_pos, mem, memory_order_release);
+ }
+}
+
+extern PersistentAllocator thePersistentAllocator;
+inline void *PersistentAlloc(uptr sz) {
+ return thePersistentAllocator.alloc(sz);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_placement_new.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_placement_new.h
new file mode 100644
index 000000000000..8904d1040ea7
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_placement_new.h
@@ -0,0 +1,25 @@
+//===-- sanitizer_placement_new.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//
+// The file provides 'placement new'.
+// Do not include it into header files, only into source files.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PLACEMENT_NEW_H
+#define SANITIZER_PLACEMENT_NEW_H
+
+#include "sanitizer_internal_defs.h"
+
+inline void *operator new(__sanitizer::operator_new_size_type sz, void *p) {
+ return p;
+}
+
+#endif // SANITIZER_PLACEMENT_NEW_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
new file mode 100644
index 000000000000..6f8cd30bf4d9
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
@@ -0,0 +1,120 @@
+//===-- sanitizer_platform.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common platform macros.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PLATFORM_H
+#define SANITIZER_PLATFORM_H
+
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+ !defined(__APPLE__) && !defined(_WIN32)
+# error "This operating system is not supported"
+#endif
+
+#if defined(__linux__)
+# define SANITIZER_LINUX 1
+#else
+# define SANITIZER_LINUX 0
+#endif
+
+#if defined(__FreeBSD__)
+# define SANITIZER_FREEBSD 1
+#else
+# define SANITIZER_FREEBSD 0
+#endif
+
+#if defined(__APPLE__)
+# define SANITIZER_MAC 1
+# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+# define SANITIZER_IOS 1
+# else
+# define SANITIZER_IOS 0
+# endif
+#else
+# define SANITIZER_MAC 0
+# define SANITIZER_IOS 0
+#endif
+
+#if defined(_WIN32)
+# define SANITIZER_WINDOWS 1
+#else
+# define SANITIZER_WINDOWS 0
+#endif
+
+#if defined(__ANDROID__)
+# define SANITIZER_ANDROID 1
+#else
+# define SANITIZER_ANDROID 0
+#endif
+
+#define SANITIZER_POSIX (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC)
+
+#if __LP64__ || defined(_WIN64)
+# define SANITIZER_WORDSIZE 64
+#else
+# define SANITIZER_WORDSIZE 32
+#endif
+
+#if SANITIZER_WORDSIZE == 64
+# define FIRST_32_SECOND_64(a, b) (b)
+#else
+# define FIRST_32_SECOND_64(a, b) (a)
+#endif
+
+#if defined(__x86_64__) && !defined(_LP64)
+# define SANITIZER_X32 1
+#else
+# define SANITIZER_X32 0
+#endif
+
+// By default we allow to use SizeClassAllocator64 on 64-bit platform.
+// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
+// does not work well and we need to fallback to SizeClassAllocator32.
+// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
+// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
+#ifndef SANITIZER_CAN_USE_ALLOCATOR64
+# if defined(__aarch64__) || defined(__mips64)
+# define SANITIZER_CAN_USE_ALLOCATOR64 0
+# else
+# define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
+# endif
+#endif
+
+// The range of addresses which can be returned my mmap.
+// FIXME: this value should be different on different platforms,
+// e.g. on AArch64 it is most likely (1ULL << 39). Larger values will still work
+// but will consume more memory for TwoLevelByteMap.
+#if defined(__aarch64__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39)
+#elif defined(__mips__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
+#else
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
+#endif
+
+// The AArch64 linux port uses the canonical syscall set as mandated by
+// the upstream linux community for all new ports. Other ports may still
+// use legacy syscalls.
+#ifndef SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+# if defined(__aarch64__) && SANITIZER_LINUX
+# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1
+# else
+# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 0
+# endif
+#endif
+
+#ifdef __mips__
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10)
+#else
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
+#endif
+
+#endif // SANITIZER_PLATFORM_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
new file mode 100644
index 000000000000..438ecbaa2ec8
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -0,0 +1,247 @@
+//===-- sanitizer_platform_interceptors.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 defines macro telling whether sanitizer tools can/should intercept
+// given library functions on a given platform.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
+#define SANITIZER_PLATFORM_INTERCEPTORS_H
+
+#include "sanitizer_internal_defs.h"
+
+#if !SANITIZER_WINDOWS
+# define SI_NOT_WINDOWS 1
+# include "sanitizer_platform_limits_posix.h"
+#else
+# define SI_NOT_WINDOWS 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define SI_LINUX_NOT_ANDROID 1
+#else
+# define SI_LINUX_NOT_ANDROID 0
+#endif
+
+#if SANITIZER_FREEBSD
+# define SI_FREEBSD 1
+#else
+# define SI_FREEBSD 0
+#endif
+
+#if SANITIZER_LINUX
+# define SI_LINUX 1
+#else
+# define SI_LINUX 0
+#endif
+
+#if SANITIZER_MAC
+# define SI_MAC 1
+#else
+# define SI_MAC 0
+#endif
+
+#if SANITIZER_IOS
+# define SI_IOS 1
+#else
+# define SI_IOS 0
+#endif
+
+#define SANITIZER_INTERCEPT_STRCMP 1
+#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MEMCHR 1
+#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX
+
+#define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_PREADV SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_PRCTL SI_LINUX
+
+#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
+
+#ifndef SANITIZER_INTERCEPT_PRINTF
+# define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_PRINTF_L SI_FREEBSD
+# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
+#endif
+
+#define SANITIZER_INTERCEPT_FREXP 1
+#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWENT \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_FREEBSD || SI_LINUX
+#define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_FREEBSD || SI_LINUX
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETHOSTENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
+#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
+ (defined(__i386) || defined (__x86_64) || defined (__mips64)) // NOLINT
+#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WCSNRTOMBS \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_CONFSTR \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WORDEXP \
+ SI_FREEBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGSETOPS \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
+#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATFS SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATFS64 \
+ (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ETHER_HOST \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ETHER_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SHMCTL \
+ ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64)
+#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SINCOS SI_LINUX
+#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LGAMMA_R SI_FREEBSD || SI_LINUX
+#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_RAND_R SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS
+
+// FIXME: getline seems to be available on OSX 10.7
+#define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
+
+#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
+ SI_FREEBSD || SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_TLS_GET_ADDR \
+ SI_FREEBSD || SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX
+#define SANITIZER_INTERCEPT_GETXATTR SI_LINUX
+#define SANITIZER_INTERCEPT_GETRESID SI_LINUX
+#define SANITIZER_INTERCEPT_GETIFADDRS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_IF_INDEXTONAME SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_AEABI_MEM SI_LINUX && defined(__arm__)
+#define SANITIZER_INTERCEPT___BZERO SI_MAC
+#define SANITIZER_INTERCEPT_FTIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
+ SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS
+
+#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
new file mode 100644
index 000000000000..92353e42d984
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
@@ -0,0 +1,105 @@
+//===-- sanitizer_platform_limits_linux.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 Sanitizer common code.
+//
+// Sizes and layouts of linux kernel data structures.
+//===----------------------------------------------------------------------===//
+
+// This is a separate compilation unit for linux headers that conflict with
+// userspace headers.
+// Most "normal" includes go in sanitizer_platform_limits_posix.cc
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
+// For offsetof -> __builtin_offsetof definition.
+#include <stddef.h>
+
+// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that
+// are not defined anywhere in userspace headers. Fake them. This seems to work
+// fine with newer headers, too.
+#include <asm/posix_types.h>
+#if defined(__x86_64__) || defined(__mips__)
+#include <sys/stat.h>
+#else
+#define ino_t __kernel_ino_t
+#define mode_t __kernel_mode_t
+#define nlink_t __kernel_nlink_t
+#define uid_t __kernel_uid_t
+#define gid_t __kernel_gid_t
+#define off_t __kernel_off_t
+// This header seems to contain the definitions of _kernel_ stat* structs.
+#include <asm/stat.h>
+#undef ino_t
+#undef mode_t
+#undef nlink_t
+#undef uid_t
+#undef gid_t
+#undef off_t
+#endif
+
+#include <linux/aio_abi.h>
+
+#if !SANITIZER_ANDROID
+#include <sys/statfs.h>
+#include <linux/perf_event.h>
+#endif
+
+namespace __sanitizer {
+#if !SANITIZER_ANDROID
+ unsigned struct_statfs64_sz = sizeof(struct statfs64);
+#endif
+} // namespace __sanitizer
+
+#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\
+ && !defined(__mips__)
+COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
+#endif
+
+COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));
+
+#if defined(__i386__)
+COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
+#endif
+
+CHECK_TYPE_SIZE(io_event);
+CHECK_SIZE_AND_OFFSET(io_event, data);
+CHECK_SIZE_AND_OFFSET(io_event, obj);
+CHECK_SIZE_AND_OFFSET(io_event, res);
+CHECK_SIZE_AND_OFFSET(io_event, res2);
+
+#if !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
+ sizeof(struct perf_event_attr));
+CHECK_SIZE_AND_OFFSET(perf_event_attr, type);
+CHECK_SIZE_AND_OFFSET(perf_event_attr, size);
+#endif
+
+COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
+COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
+#if !SANITIZER_ANDROID
+COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV);
+COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV);
+#endif
+
+CHECK_TYPE_SIZE(iocb);
+CHECK_SIZE_AND_OFFSET(iocb, aio_data);
+// Skip aio_key, it's weird.
+CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode);
+CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio);
+CHECK_SIZE_AND_OFFSET(iocb, aio_fildes);
+CHECK_SIZE_AND_OFFSET(iocb, aio_buf);
+CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes);
+CHECK_SIZE_AND_OFFSET(iocb, aio_offset);
+
+#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
new file mode 100644
index 000000000000..8824c8088f2d
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -0,0 +1,1205 @@
+//===-- sanitizer_platform_limits_posix.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 Sanitizer common code.
+//
+// Sizes and layouts of platform-specific POSIX data structures.
+//===----------------------------------------------------------------------===//
+
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
+// Tests in this file assume that off_t-dependent data structures match the
+// libc ABI. For example, struct dirent here is what readdir() function (as
+// exported from libc) returns, and not the user-facing "dirent", which
+// depends on _FILE_OFFSET_BITS setting.
+// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
+#ifdef _FILE_OFFSET_BITS
+#undef _FILE_OFFSET_BITS
+#endif
+#if SANITIZER_FREEBSD
+#define _WANT_RTENTRY
+#include <sys/param.h>
+#include <sys/socketvar.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netdb.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <termios.h>
+#include <time.h>
+#include <wchar.h>
+
+#if !SANITIZER_ANDROID
+#include <sys/mount.h>
+#include <sys/timeb.h>
+#endif
+
+#if SANITIZER_LINUX
+#include <malloc.h>
+#include <mntent.h>
+#include <netinet/ether.h>
+#include <sys/sysinfo.h>
+#include <sys/vt.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/input.h>
+#include <linux/ioctl.h>
+#include <linux/soundcard.h>
+#include <linux/sysctl.h>
+#include <linux/utsname.h>
+#include <linux/posix_types.h>
+#endif
+
+#if SANITIZER_FREEBSD
+# include <sys/mount.h>
+# include <sys/sockio.h>
+# include <sys/socket.h>
+# include <sys/filio.h>
+# include <sys/signal.h>
+# include <sys/timespec.h>
+# include <sys/timex.h>
+# include <sys/mqueue.h>
+# include <sys/msg.h>
+# include <sys/ipc.h>
+# include <sys/msg.h>
+# include <sys/statvfs.h>
+# include <sys/soundcard.h>
+# include <sys/mtio.h>
+# include <sys/consio.h>
+# include <sys/kbio.h>
+# include <sys/link_elf.h>
+# include <netinet/ip_mroute.h>
+# include <netinet/in.h>
+# include <net/ethernet.h>
+# include <net/ppp_defs.h>
+# include <glob.h>
+# include <term.h>
+
+#define _KERNEL // to declare 'shminfo' structure
+# include <sys/shm.h>
+#undef _KERNEL
+
+#undef INLINE // to avoid clashes with sanitizers' definitions
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_IOS
+#undef IOC_DIRMASK
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+# include <utime.h>
+# include <sys/ptrace.h>
+# if defined(__mips64)
+# include <asm/ptrace.h>
+# endif
+#endif
+
+#if !SANITIZER_ANDROID
+#include <ifaddrs.h>
+#include <sys/ucontext.h>
+#include <wordexp.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <glob.h>
+#include <obstack.h>
+#include <mqueue.h>
+#include <net/if_ppp.h>
+#include <netax25/ax25.h>
+#include <netipx/ipx.h>
+#include <netrom/netrom.h>
+#include <rpc/xdr.h>
+#include <scsi/scsi.h>
+#include <sys/mtio.h>
+#include <sys/kd.h>
+#include <sys/shm.h>
+#include <sys/statvfs.h>
+#include <sys/timex.h>
+#if defined(__mips64)
+# include <sys/procfs.h>
+#endif
+#include <sys/user.h>
+#include <sys/ustat.h>
+#include <linux/cyclades.h>
+#include <linux/if_eql.h>
+#include <linux/if_plip.h>
+#include <linux/lp.h>
+#include <linux/mroute.h>
+#include <linux/mroute6.h>
+#include <linux/scc.h>
+#include <linux/serial.h>
+#include <sys/msg.h>
+#include <sys/ipc.h>
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if SANITIZER_ANDROID
+#include <linux/kd.h>
+#include <linux/mtio.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#endif
+
+#if SANITIZER_LINUX
+#include <link.h>
+#include <sys/vfs.h>
+#include <sys/epoll.h>
+#include <linux/capability.h>
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_MAC
+#include <net/ethernet.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#endif
+
+// Include these after system headers to avoid name clashes and ambiguities.
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
+namespace __sanitizer {
+ unsigned struct_utsname_sz = sizeof(struct utsname);
+ unsigned struct_stat_sz = sizeof(struct stat);
+#if !SANITIZER_IOS && !SANITIZER_FREEBSD
+ unsigned struct_stat64_sz = sizeof(struct stat64);
+#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD
+ unsigned struct_rusage_sz = sizeof(struct rusage);
+ unsigned struct_tm_sz = sizeof(struct tm);
+ unsigned struct_passwd_sz = sizeof(struct passwd);
+ unsigned struct_group_sz = sizeof(struct group);
+ unsigned siginfo_t_sz = sizeof(siginfo_t);
+ unsigned struct_sigaction_sz = sizeof(struct sigaction);
+ unsigned struct_itimerval_sz = sizeof(struct itimerval);
+ unsigned pthread_t_sz = sizeof(pthread_t);
+ unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
+ unsigned pid_t_sz = sizeof(pid_t);
+ unsigned timeval_sz = sizeof(timeval);
+ unsigned uid_t_sz = sizeof(uid_t);
+ unsigned gid_t_sz = sizeof(gid_t);
+ unsigned mbstate_t_sz = sizeof(mbstate_t);
+ unsigned sigset_t_sz = sizeof(sigset_t);
+ unsigned struct_timezone_sz = sizeof(struct timezone);
+ unsigned struct_tms_sz = sizeof(struct tms);
+ unsigned struct_sigevent_sz = sizeof(struct sigevent);
+ unsigned struct_sched_param_sz = sizeof(struct sched_param);
+
+
+#if SANITIZER_MAC && !SANITIZER_IOS
+ unsigned struct_statfs64_sz = sizeof(struct statfs64);
+#endif // SANITIZER_MAC && !SANITIZER_IOS
+
+#if !SANITIZER_ANDROID
+ unsigned struct_statfs_sz = sizeof(struct statfs);
+ unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
+ unsigned ucontext_t_sz = sizeof(ucontext_t);
+#endif // !SANITIZER_ANDROID
+
+#if SANITIZER_LINUX
+ unsigned struct_epoll_event_sz = sizeof(struct epoll_event);
+ unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
+ unsigned __user_cap_header_struct_sz =
+ sizeof(struct __user_cap_header_struct);
+ unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct);
+ unsigned struct_new_utsname_sz = sizeof(struct new_utsname);
+ unsigned struct_old_utsname_sz = sizeof(struct old_utsname);
+ unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname);
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ unsigned struct_rlimit_sz = sizeof(struct rlimit);
+ unsigned struct_timespec_sz = sizeof(struct timespec);
+ unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
+ unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ unsigned struct_ustat_sz = sizeof(struct ustat);
+ unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
+ unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ unsigned struct_timex_sz = sizeof(struct timex);
+ unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
+ unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+ unsigned struct_statvfs_sz = sizeof(struct statvfs);
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+ uptr sig_ign = (uptr)SIG_IGN;
+ uptr sig_dfl = (uptr)SIG_DFL;
+ uptr sa_siginfo = (uptr)SA_SIGINFO;
+
+#if SANITIZER_LINUX
+ int e_tabsz = (int)E_TABSZ;
+#endif
+
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ unsigned struct_shminfo_sz = sizeof(struct shminfo);
+ unsigned struct_shm_info_sz = sizeof(struct shm_info);
+ int shmctl_ipc_stat = (int)IPC_STAT;
+ int shmctl_ipc_info = (int)IPC_INFO;
+ int shmctl_shm_info = (int)SHM_INFO;
+ int shmctl_shm_stat = (int)SHM_STAT;
+#endif
+
+ int map_fixed = MAP_FIXED;
+
+ int af_inet = (int)AF_INET;
+ int af_inet6 = (int)AF_INET6;
+
+ uptr __sanitizer_in_addr_sz(int af) {
+ if (af == AF_INET)
+ return sizeof(struct in_addr);
+ else if (af == AF_INET6)
+ return sizeof(struct in6_addr);
+ else
+ return 0;
+ }
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ int glob_nomatch = GLOB_NOMATCH;
+ int glob_altdirfunc = GLOB_ALTDIRFUNC;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
+#if defined(__mips64)
+ unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
+ unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
+#else
+ unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
+ unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
+#endif // __mips64
+#if (defined(__x86_64) || defined(__mips64))
+ unsigned struct_user_fpxregs_struct_sz = 0;
+#else
+ unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
+#endif // __x86_64 || __mips64
+
+ int ptrace_peektext = PTRACE_PEEKTEXT;
+ int ptrace_peekdata = PTRACE_PEEKDATA;
+ int ptrace_peekuser = PTRACE_PEEKUSER;
+ int ptrace_getregs = PTRACE_GETREGS;
+ int ptrace_setregs = PTRACE_SETREGS;
+ int ptrace_getfpregs = PTRACE_GETFPREGS;
+ int ptrace_setfpregs = PTRACE_SETFPREGS;
+ int ptrace_getfpxregs = PTRACE_GETFPXREGS;
+ int ptrace_setfpxregs = PTRACE_SETFPXREGS;
+ int ptrace_geteventmsg = PTRACE_GETEVENTMSG;
+#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \
+ (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO))
+ int ptrace_getsiginfo = PTRACE_GETSIGINFO;
+ int ptrace_setsiginfo = PTRACE_SETSIGINFO;
+#else
+ int ptrace_getsiginfo = -1;
+ int ptrace_setsiginfo = -1;
+#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO
+#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
+ int ptrace_getregset = PTRACE_GETREGSET;
+ int ptrace_setregset = PTRACE_SETREGSET;
+#else
+ int ptrace_getregset = -1;
+ int ptrace_setregset = -1;
+#endif // PTRACE_GETREGSET/PTRACE_SETREGSET
+#endif
+
+ unsigned path_max = PATH_MAX;
+
+ // ioctl arguments
+ unsigned struct_arpreq_sz = sizeof(struct arpreq);
+ unsigned struct_ifreq_sz = sizeof(struct ifreq);
+ unsigned struct_termios_sz = sizeof(struct termios);
+ unsigned struct_winsize_sz = sizeof(struct winsize);
+
+#if SANITIZER_LINUX
+ unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf);
+ unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession);
+ unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio);
+ unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl);
+ unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti);
+ unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry);
+ unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr);
+ unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl);
+ unsigned struct_ff_effect_sz = sizeof(struct ff_effect);
+ unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params);
+ unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct);
+ unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state);
+ unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors);
+ unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd);
+ unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct);
+ unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors);
+ unsigned struct_format_descr_sz = sizeof(struct format_descr);
+ unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid);
+ unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry);
+ unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo);
+ unsigned struct_input_id_sz = sizeof(struct input_id);
+ unsigned struct_mtpos_sz = sizeof(struct mtpos);
+ unsigned struct_termio_sz = sizeof(struct termio);
+ unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
+ unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
+ unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SOUND_VERSION >= 0x040000
+ unsigned struct_copr_buffer_sz = 0;
+ unsigned struct_copr_debug_buf_sz = 0;
+ unsigned struct_copr_msg_sz = 0;
+#else
+ unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+ unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+ unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+#endif
+ unsigned struct_midi_info_sz = sizeof(struct midi_info);
+ unsigned struct_mtget_sz = sizeof(struct mtget);
+ unsigned struct_mtop_sz = sizeof(struct mtop);
+ unsigned struct_rtentry_sz = sizeof(struct rtentry);
+ unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
+ unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
+ unsigned struct_synth_info_sz = sizeof(struct synth_info);
+ unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
+ unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
+#if EV_VERSION > (0x010000)
+ unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry);
+#else
+ unsigned struct_input_keymap_entry_sz = 0;
+#endif
+ unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data);
+ unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs);
+ unsigned struct_kbentry_sz = sizeof(struct kbentry);
+ unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode);
+ unsigned struct_kbsentry_sz = sizeof(struct kbsentry);
+ unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo);
+ unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct);
+ unsigned struct_scc_modem_sz = sizeof(struct scc_modem);
+ unsigned struct_scc_stat_sz = sizeof(struct scc_stat);
+ unsigned struct_serial_multiport_struct_sz
+ = sizeof(struct serial_multiport_struct);
+ unsigned struct_serial_struct_sz = sizeof(struct serial_struct);
+ unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
+ unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
+ unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+ unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+#if !SANITIZER_ANDROID && !SANITIZER_MAC
+ unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+ unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+#endif
+
+ const unsigned IOCTL_NOT_PRESENT = 0;
+
+ unsigned IOCTL_FIOASYNC = FIOASYNC;
+ unsigned IOCTL_FIOCLEX = FIOCLEX;
+ unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+ unsigned IOCTL_FIONBIO = FIONBIO;
+ unsigned IOCTL_FIONCLEX = FIONCLEX;
+ unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+ unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+ unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+ unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+ unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+ unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+ unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+ unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+ unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+ unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+ unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+ unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+ unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+ unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+ unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+ unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+ unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+ unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+ unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+ unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+ unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+ unsigned IOCTL_TIOCCONS = TIOCCONS;
+ unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+ unsigned IOCTL_TIOCGETD = TIOCGETD;
+ unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+ unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+ unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+ unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+ unsigned IOCTL_TIOCMGET = TIOCMGET;
+ unsigned IOCTL_TIOCMSET = TIOCMSET;
+ unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+ unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+ unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+ unsigned IOCTL_TIOCPKT = TIOCPKT;
+ unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+ unsigned IOCTL_TIOCSETD = TIOCSETD;
+ unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+ unsigned IOCTL_TIOCSTI = TIOCSTI;
+ unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+#if ((SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID)
+ unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
+ unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
+#endif
+
+#if SANITIZER_LINUX
+ unsigned IOCTL_EVIOCGABS = EVIOCGABS(0);
+ unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0);
+ unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS;
+ unsigned IOCTL_EVIOCGID = EVIOCGID;
+ unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0);
+ unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE;
+ unsigned IOCTL_EVIOCGLED = EVIOCGLED(0);
+ unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0);
+ unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0);
+ unsigned IOCTL_EVIOCGRAB = EVIOCGRAB;
+ unsigned IOCTL_EVIOCGREP = EVIOCGREP;
+ unsigned IOCTL_EVIOCGSND = EVIOCGSND(0);
+ unsigned IOCTL_EVIOCGSW = EVIOCGSW(0);
+ unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0);
+ unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION;
+ unsigned IOCTL_EVIOCRMFF = EVIOCRMFF;
+ unsigned IOCTL_EVIOCSABS = EVIOCSABS(0);
+ unsigned IOCTL_EVIOCSFF = EVIOCSFF;
+ unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE;
+ unsigned IOCTL_EVIOCSREP = EVIOCSREP;
+ unsigned IOCTL_BLKFLSBUF = BLKFLSBUF;
+ unsigned IOCTL_BLKGETSIZE = BLKGETSIZE;
+ unsigned IOCTL_BLKRAGET = BLKRAGET;
+ unsigned IOCTL_BLKRASET = BLKRASET;
+ unsigned IOCTL_BLKROGET = BLKROGET;
+ unsigned IOCTL_BLKROSET = BLKROSET;
+ unsigned IOCTL_BLKRRPART = BLKRRPART;
+ unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ;
+ unsigned IOCTL_CDROMEJECT = CDROMEJECT;
+ unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW;
+ unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION;
+ unsigned IOCTL_CDROMPAUSE = CDROMPAUSE;
+ unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF;
+ unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND;
+ unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO;
+ unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED;
+ unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1;
+ unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2;
+ unsigned IOCTL_CDROMREADRAW = CDROMREADRAW;
+ unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY;
+ unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR;
+ unsigned IOCTL_CDROMRESET = CDROMRESET;
+ unsigned IOCTL_CDROMRESUME = CDROMRESUME;
+ unsigned IOCTL_CDROMSEEK = CDROMSEEK;
+ unsigned IOCTL_CDROMSTART = CDROMSTART;
+ unsigned IOCTL_CDROMSTOP = CDROMSTOP;
+ unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL;
+ unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL;
+ unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD;
+ unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC;
+ unsigned IOCTL_FDCLRPRM = FDCLRPRM;
+ unsigned IOCTL_FDDEFPRM = FDDEFPRM;
+ unsigned IOCTL_FDFLUSH = FDFLUSH;
+ unsigned IOCTL_FDFMTBEG = FDFMTBEG;
+ unsigned IOCTL_FDFMTEND = FDFMTEND;
+ unsigned IOCTL_FDFMTTRK = FDFMTTRK;
+ unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM;
+ unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT;
+ unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP;
+ unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT;
+ unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS;
+ unsigned IOCTL_FDGETPRM = FDGETPRM;
+ unsigned IOCTL_FDMSGOFF = FDMSGOFF;
+ unsigned IOCTL_FDMSGON = FDMSGON;
+ unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT;
+ unsigned IOCTL_FDRAWCMD = FDRAWCMD;
+ unsigned IOCTL_FDRESET = FDRESET;
+ unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM;
+ unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH;
+ unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS;
+ unsigned IOCTL_FDSETPRM = FDSETPRM;
+ unsigned IOCTL_FDTWADDLE = FDTWADDLE;
+ unsigned IOCTL_FDWERRORCLR = FDWERRORCLR;
+ unsigned IOCTL_FDWERRORGET = FDWERRORGET;
+ unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD;
+ unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO;
+ unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT;
+ unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA;
+ unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY;
+ unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS;
+ unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT;
+ unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR;
+ unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR;
+ unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT;
+ unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA;
+ unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS;
+ unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT;
+ unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR;
+ unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR;
+ unsigned IOCTL_MTIOCPOS = MTIOCPOS;
+ unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP;
+ unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG;
+ unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS;
+ unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT;
+ unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP;
+ unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP;
+ unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG;
+ unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS;
+ unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID;
+ unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU;
+ unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP;
+ unsigned IOCTL_SIOCADDRT = SIOCADDRT;
+ unsigned IOCTL_SIOCDARP = SIOCDARP;
+ unsigned IOCTL_SIOCDELRT = SIOCDELRT;
+ unsigned IOCTL_SIOCDRARP = SIOCDRARP;
+ unsigned IOCTL_SIOCGARP = SIOCGARP;
+ unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP;
+ unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR;
+ unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP;
+ unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM;
+ unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME;
+ unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE;
+ unsigned IOCTL_SIOCGRARP = SIOCGRARP;
+ unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP;
+ unsigned IOCTL_SIOCSARP = SIOCSARP;
+ unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP;
+ unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR;
+ unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK;
+ unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP;
+ unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM;
+ unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE;
+ unsigned IOCTL_SIOCSRARP = SIOCSRARP;
+# if SOUND_VERSION >= 0x040000
+ unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT;
+# else // SOUND_VERSION
+ unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT;
+ unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD;
+ unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE;
+ unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG;
+ unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA;
+ unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET;
+ unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN;
+ unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG;
+ unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE;
+ unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA;
+ unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS;
+ unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS;
+ unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER;
+ unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE;
+ unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS;
+ unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER;
+#endif // SOUND_VERSION
+ unsigned IOCTL_TCFLSH = TCFLSH;
+ unsigned IOCTL_TCGETA = TCGETA;
+ unsigned IOCTL_TCGETS = TCGETS;
+ unsigned IOCTL_TCSBRK = TCSBRK;
+ unsigned IOCTL_TCSBRKP = TCSBRKP;
+ unsigned IOCTL_TCSETA = TCSETA;
+ unsigned IOCTL_TCSETAF = TCSETAF;
+ unsigned IOCTL_TCSETAW = TCSETAW;
+ unsigned IOCTL_TCSETS = TCSETS;
+ unsigned IOCTL_TCSETSF = TCSETSF;
+ unsigned IOCTL_TCSETSW = TCSETSW;
+ unsigned IOCTL_TCXONC = TCXONC;
+ unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS;
+ unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR;
+ unsigned IOCTL_TIOCINQ = TIOCINQ;
+ unsigned IOCTL_TIOCLINUX = TIOCLINUX;
+ unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG;
+ unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR;
+ unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD;
+ unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD;
+ unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS;
+ unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR;
+ unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
+ unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
+ unsigned IOCTL_VT_RESIZE = VT_RESIZE;
+ unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
+ unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ unsigned IOCTL_MTIOCGET = MTIOCGET;
+ unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+ unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
+ unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
+ unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
+ unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
+ unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
+ unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
+ unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
+ unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
+ unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
+ unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
+ unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
+ unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
+ unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
+ unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
+ unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
+ unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
+ unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
+ unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
+ unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
+ unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
+ unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
+ unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
+ unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
+ unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
+ unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
+ unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
+ unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
+ unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
+ unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
+ unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
+ unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
+ unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
+ unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
+ unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
+ unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
+ unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
+ unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
+ unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
+ unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
+ unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
+ unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
+ unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
+ unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
+ unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
+ unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
+ unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
+ unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
+ unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
+ unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
+ unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
+ unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
+ unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
+ unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
+ unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
+ unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
+ unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
+ unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
+ unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
+ unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
+ unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
+ unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
+ unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
+ unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
+ unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
+ unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
+ unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
+ unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
+ unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
+ unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
+ unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
+ unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
+ unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
+ unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
+ unsigned IOCTL_VT_GETMODE = VT_GETMODE;
+ unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
+ unsigned IOCTL_VT_RELDISP = VT_RELDISP;
+ unsigned IOCTL_VT_SETMODE = VT_SETMODE;
+ unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
+ unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT;
+ unsigned IOCTL_CYGETMON = CYGETMON;
+ unsigned IOCTL_CYGETTHRESH = CYGETTHRESH;
+ unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT;
+ unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH;
+ unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT;
+ unsigned IOCTL_CYSETTHRESH = CYSETTHRESH;
+ unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT;
+ unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE;
+ unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE;
+ unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG;
+ unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG;
+ unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG;
+ unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG;
+#if EV_VERSION > (0x010000)
+ unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2;
+ unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0);
+ unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2;
+#else
+ unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT;
+#endif
+ unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS;
+ unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION;
+ unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS;
+ unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION;
+ unsigned IOCTL_GIO_CMAP = GIO_CMAP;
+ unsigned IOCTL_GIO_FONT = GIO_FONT;
+ unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP;
+ unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP;
+ unsigned IOCTL_KDADDIO = KDADDIO;
+ unsigned IOCTL_KDDELIO = KDDELIO;
+ unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE;
+ unsigned IOCTL_KDGKBDIACR = KDGKBDIACR;
+ unsigned IOCTL_KDGKBENT = KDGKBENT;
+ unsigned IOCTL_KDGKBLED = KDGKBLED;
+ unsigned IOCTL_KDGKBMETA = KDGKBMETA;
+ unsigned IOCTL_KDGKBSENT = KDGKBSENT;
+ unsigned IOCTL_KDMAPDISP = KDMAPDISP;
+ unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE;
+ unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT;
+ unsigned IOCTL_KDSKBDIACR = KDSKBDIACR;
+ unsigned IOCTL_KDSKBENT = KDSKBENT;
+ unsigned IOCTL_KDSKBLED = KDSKBLED;
+ unsigned IOCTL_KDSKBMETA = KDSKBMETA;
+ unsigned IOCTL_KDSKBSENT = KDSKBSENT;
+ unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP;
+ unsigned IOCTL_LPABORT = LPABORT;
+ unsigned IOCTL_LPABORTOPEN = LPABORTOPEN;
+ unsigned IOCTL_LPCAREFUL = LPCAREFUL;
+ unsigned IOCTL_LPCHAR = LPCHAR;
+ unsigned IOCTL_LPGETIRQ = LPGETIRQ;
+ unsigned IOCTL_LPGETSTATUS = LPGETSTATUS;
+ unsigned IOCTL_LPRESET = LPRESET;
+ unsigned IOCTL_LPSETIRQ = LPSETIRQ;
+ unsigned IOCTL_LPTIME = LPTIME;
+ unsigned IOCTL_LPWAIT = LPWAIT;
+ unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG;
+ unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG;
+ unsigned IOCTL_PIO_CMAP = PIO_CMAP;
+ unsigned IOCTL_PIO_FONT = PIO_FONT;
+ unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
+ unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
+ unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
+ unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
+ unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
+ unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
+ unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE;
+ unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT;
+ unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT;
+ unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID;
+ unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID;
+ unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS;
+ unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID;
+ unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID;
+ unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS;
+ unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP;
+ unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA;
+ unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS;
+ unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
+ unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
+ unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
+ unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
+ unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
+ unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
+ unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+ unsigned IOCTL_KDDISABIO = KDDISABIO;
+ unsigned IOCTL_KDENABIO = KDENABIO;
+ unsigned IOCTL_KDGETLED = KDGETLED;
+ unsigned IOCTL_KDGETMODE = KDGETMODE;
+ unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+ unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+ unsigned IOCTL_KDMKTONE = KDMKTONE;
+ unsigned IOCTL_KDSETLED = KDSETLED;
+ unsigned IOCTL_KDSETMODE = KDSETMODE;
+ unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+ unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+ unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+ unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+ unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+ const int errno_EINVAL = EINVAL;
+// EOWNERDEAD is not present in some older platforms.
+#if defined(EOWNERDEAD)
+ const int errno_EOWNERDEAD = EOWNERDEAD;
+#else
+ const int errno_EOWNERDEAD = -1;
+#endif
+
+ const int si_SEGV_MAPERR = SEGV_MAPERR;
+ const int si_SEGV_ACCERR = SEGV_ACCERR;
+} // namespace __sanitizer
+
+COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
+
+COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
+CHECK_TYPE_SIZE(pthread_key_t);
+
+#if SANITIZER_LINUX
+// FIXME: We define those on Linux and Mac, but only check on Linux.
+COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS);
+COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS);
+COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS);
+COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS);
+COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK);
+COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK);
+COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK);
+COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK);
+COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT);
+COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT);
+COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT);
+COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT);
+COMPILER_CHECK(IOC_NONE == _IOC_NONE);
+COMPILER_CHECK(IOC_WRITE == _IOC_WRITE);
+COMPILER_CHECK(IOC_READ == _IOC_READ);
+COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX);
+COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX);
+COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
+COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678));
+COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678));
+COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678));
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+// There are more undocumented fields in dl_phdr_info that we are not interested
+// in.
+COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(glob_t);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
+#endif
+
+CHECK_TYPE_SIZE(addrinfo);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
+
+CHECK_TYPE_SIZE(hostent);
+CHECK_SIZE_AND_OFFSET(hostent, h_name);
+CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
+CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
+CHECK_SIZE_AND_OFFSET(hostent, h_length);
+CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
+
+CHECK_TYPE_SIZE(iovec);
+CHECK_SIZE_AND_OFFSET(iovec, iov_base);
+CHECK_SIZE_AND_OFFSET(iovec, iov_len);
+
+CHECK_TYPE_SIZE(msghdr);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
+
+CHECK_TYPE_SIZE(cmsghdr);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
+
+COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
+CHECK_SIZE_AND_OFFSET(dirent, d_ino);
+#if SANITIZER_MAC
+CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
+#elif SANITIZER_FREEBSD
+// There is no 'd_off' field on FreeBSD.
+#else
+CHECK_SIZE_AND_OFFSET(dirent, d_off);
+#endif
+CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64));
+CHECK_SIZE_AND_OFFSET(dirent64, d_ino);
+CHECK_SIZE_AND_OFFSET(dirent64, d_off);
+CHECK_SIZE_AND_OFFSET(dirent64, d_reclen);
+#endif
+
+CHECK_TYPE_SIZE(ifconf);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
+
+CHECK_TYPE_SIZE(pollfd);
+CHECK_SIZE_AND_OFFSET(pollfd, fd);
+CHECK_SIZE_AND_OFFSET(pollfd, events);
+CHECK_SIZE_AND_OFFSET(pollfd, revents);
+
+CHECK_TYPE_SIZE(nfds_t);
+
+CHECK_TYPE_SIZE(sigset_t);
+
+COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
+// Can't write checks for sa_handler and sa_sigaction due to them being
+// preprocessor macros.
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
+#if SANITIZER_LINUX
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
+#endif
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(__sysctl_args);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, name);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, newval);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen);
+
+CHECK_TYPE_SIZE(__kernel_uid_t);
+CHECK_TYPE_SIZE(__kernel_gid_t);
+
+#if !defined(__aarch64__)
+CHECK_TYPE_SIZE(__kernel_old_uid_t);
+CHECK_TYPE_SIZE(__kernel_old_gid_t);
+#endif
+
+CHECK_TYPE_SIZE(__kernel_off_t);
+CHECK_TYPE_SIZE(__kernel_loff_t);
+CHECK_TYPE_SIZE(__kernel_fd_set);
+#endif
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(wordexp_t);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
+#endif
+
+CHECK_TYPE_SIZE(tm);
+CHECK_SIZE_AND_OFFSET(tm, tm_sec);
+CHECK_SIZE_AND_OFFSET(tm, tm_min);
+CHECK_SIZE_AND_OFFSET(tm, tm_hour);
+CHECK_SIZE_AND_OFFSET(tm, tm_mday);
+CHECK_SIZE_AND_OFFSET(tm, tm_mon);
+CHECK_SIZE_AND_OFFSET(tm, tm_year);
+CHECK_SIZE_AND_OFFSET(tm, tm_wday);
+CHECK_SIZE_AND_OFFSET(tm, tm_yday);
+CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
+CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
+CHECK_SIZE_AND_OFFSET(tm, tm_zone);
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(mntent);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_dir);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_type);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_opts);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_freq);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
+#endif
+
+CHECK_TYPE_SIZE(ether_addr);
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(ipc_perm);
+# if SANITIZER_FREEBSD
+CHECK_SIZE_AND_OFFSET(ipc_perm, key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, seq);
+# else
+CHECK_SIZE_AND_OFFSET(ipc_perm, __key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, __seq);
+# endif
+CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(x, y) 0
+#endif
+#if !defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21)
+/* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */
+CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
+#endif
+
+CHECK_TYPE_SIZE(shmid_ds);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
+#endif
+
+CHECK_TYPE_SIZE(clock_t);
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(clockid_t);
+#endif
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(ifaddrs);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+// Compare against the union, because we can't reach into the union in a
+// compliant way.
+#ifdef ifa_dstaddr
+#undef ifa_dstaddr
+#endif
+# if SANITIZER_FREEBSD
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+# else
+COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)NULL)->ifa_dstaddr) ==
+ sizeof(((ifaddrs *)NULL)->ifa_ifu));
+COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) ==
+ offsetof(ifaddrs, ifa_ifu));
+# endif // SANITIZER_FREEBSD
+#else
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+#endif // SANITIZER_LINUX
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
+#endif
+
+#if SANITIZER_LINUX
+COMPILER_CHECK(sizeof(__sanitizer_mallinfo) == sizeof(struct mallinfo));
+#endif
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(timeb);
+CHECK_SIZE_AND_OFFSET(timeb, time);
+CHECK_SIZE_AND_OFFSET(timeb, millitm);
+CHECK_SIZE_AND_OFFSET(timeb, timezone);
+CHECK_SIZE_AND_OFFSET(timeb, dstflag);
+#endif
+
+CHECK_TYPE_SIZE(passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_name);
+CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
+CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
+
+#if !SANITIZER_ANDROID
+CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
+#endif
+
+#if SANITIZER_MAC
+CHECK_SIZE_AND_OFFSET(passwd, pw_change);
+CHECK_SIZE_AND_OFFSET(passwd, pw_expire);
+CHECK_SIZE_AND_OFFSET(passwd, pw_class);
+#endif
+
+
+CHECK_TYPE_SIZE(group);
+CHECK_SIZE_AND_OFFSET(group, gr_name);
+CHECK_SIZE_AND_OFFSET(group, gr_passwd);
+CHECK_SIZE_AND_OFFSET(group, gr_gid);
+CHECK_SIZE_AND_OFFSET(group, gr_mem);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(XDR);
+CHECK_SIZE_AND_OFFSET(XDR, x_op);
+CHECK_SIZE_AND_OFFSET(XDR, x_ops);
+CHECK_SIZE_AND_OFFSET(XDR, x_public);
+CHECK_SIZE_AND_OFFSET(XDR, x_private);
+CHECK_SIZE_AND_OFFSET(XDR, x_base);
+CHECK_SIZE_AND_OFFSET(XDR, x_handy);
+COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE);
+COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
+COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
+CHECK_SIZE_AND_OFFSET(FILE, _flags);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
+CHECK_SIZE_AND_OFFSET(FILE, _markers);
+CHECK_SIZE_AND_OFFSET(FILE, _chain);
+CHECK_SIZE_AND_OFFSET(FILE, _fileno);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
+CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
+CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
+CHECK_TYPE_SIZE(obstack);
+CHECK_SIZE_AND_OFFSET(obstack, chunk_size);
+CHECK_SIZE_AND_OFFSET(obstack, chunk);
+CHECK_SIZE_AND_OFFSET(obstack, object_base);
+CHECK_SIZE_AND_OFFSET(obstack, next_free);
+#endif
+
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
new file mode 100644
index 000000000000..bd20bea94e93
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -0,0 +1,1316 @@
+//===-- sanitizer_platform_limits_posix.h ---------------------------------===//
+//
+// 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 Sanitizer common code.
+//
+// Sizes and layouts of platform-specific POSIX data structures.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
+#define SANITIZER_PLATFORM_LIMITS_POSIX_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FREEBSD
+// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
+// incroporates the map structure.
+# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+ ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544)))
+#else
+# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle))
+#endif // !SANITIZER_FREEBSD
+
+namespace __sanitizer {
+ extern unsigned struct_utsname_sz;
+ extern unsigned struct_stat_sz;
+#if !SANITIZER_FREEBSD && !SANITIZER_IOS
+ extern unsigned struct_stat64_sz;
+#endif
+ extern unsigned struct_rusage_sz;
+ extern unsigned siginfo_t_sz;
+ extern unsigned struct_itimerval_sz;
+ extern unsigned pthread_t_sz;
+ extern unsigned pthread_cond_t_sz;
+ extern unsigned pid_t_sz;
+ extern unsigned timeval_sz;
+ extern unsigned uid_t_sz;
+ extern unsigned gid_t_sz;
+ extern unsigned mbstate_t_sz;
+ extern unsigned struct_timezone_sz;
+ extern unsigned struct_tms_sz;
+ extern unsigned struct_itimerspec_sz;
+ extern unsigned struct_sigevent_sz;
+ extern unsigned struct_sched_param_sz;
+ extern unsigned struct_statfs64_sz;
+
+#if !SANITIZER_ANDROID
+ extern unsigned struct_statfs_sz;
+ extern unsigned struct_sockaddr_sz;
+ extern unsigned ucontext_t_sz;
+#endif // !SANITIZER_ANDROID
+
+#if SANITIZER_LINUX
+
+#if defined(__x86_64__)
+ const unsigned struct_kernel_stat_sz = 144;
+ const unsigned struct_kernel_stat64_sz = 0;
+#elif defined(__i386__)
+ const unsigned struct_kernel_stat_sz = 64;
+ const unsigned struct_kernel_stat64_sz = 96;
+#elif defined(__arm__)
+ const unsigned struct_kernel_stat_sz = 64;
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__aarch64__)
+ const unsigned struct_kernel_stat_sz = 128;
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__powerpc__) && !defined(__powerpc64__)
+ const unsigned struct_kernel_stat_sz = 72;
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__powerpc64__)
+ const unsigned struct_kernel_stat_sz = 144;
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__mips__)
+ #if SANITIZER_WORDSIZE == 64
+ const unsigned struct_kernel_stat_sz = 216;
+ #else
+ const unsigned struct_kernel_stat_sz = 144;
+ #endif
+ const unsigned struct_kernel_stat64_sz = 104;
+#endif
+ struct __sanitizer_perf_event_attr {
+ unsigned type;
+ unsigned size;
+ // More fields that vary with the kernel version.
+ };
+
+ extern unsigned struct_epoll_event_sz;
+ extern unsigned struct_sysinfo_sz;
+ extern unsigned __user_cap_header_struct_sz;
+ extern unsigned __user_cap_data_struct_sz;
+ extern unsigned struct_new_utsname_sz;
+ extern unsigned struct_old_utsname_sz;
+ extern unsigned struct_oldold_utsname_sz;
+
+ const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if defined(__powerpc64__)
+ const unsigned struct___old_kernel_stat_sz = 0;
+#else
+ const unsigned struct___old_kernel_stat_sz = 32;
+#endif
+
+ extern unsigned struct_rlimit_sz;
+ extern unsigned struct_utimbuf_sz;
+ extern unsigned struct_timespec_sz;
+
+ struct __sanitizer_iocb {
+ u64 aio_data;
+ u32 aio_key_or_aio_reserved1; // Simply crazy.
+ u32 aio_reserved1_or_aio_key; // Luckily, we don't need these.
+ u16 aio_lio_opcode;
+ s16 aio_reqprio;
+ u32 aio_fildes;
+ u64 aio_buf;
+ u64 aio_nbytes;
+ s64 aio_offset;
+ u64 aio_reserved2;
+ u64 aio_reserved3;
+ };
+
+ struct __sanitizer_io_event {
+ u64 data;
+ u64 obj;
+ u64 res;
+ u64 res2;
+ };
+
+ const unsigned iocb_cmd_pread = 0;
+ const unsigned iocb_cmd_pwrite = 1;
+ const unsigned iocb_cmd_preadv = 7;
+ const unsigned iocb_cmd_pwritev = 8;
+
+ struct __sanitizer___sysctl_args {
+ int *name;
+ int nlen;
+ void *oldval;
+ uptr *oldlenp;
+ void *newval;
+ uptr newlen;
+ unsigned long ___unused[4];
+ };
+
+ const unsigned old_sigset_t_sz = sizeof(unsigned long);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_ANDROID
+ struct __sanitizer_mallinfo {
+ uptr v[10];
+ };
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_mallinfo {
+ int v[10];
+ };
+
+ extern unsigned struct_ustat_sz;
+ extern unsigned struct_rlimit64_sz;
+ extern unsigned struct_statvfs64_sz;
+
+ struct __sanitizer_ipc_perm {
+ int __key;
+ int uid;
+ int gid;
+ int cuid;
+ int cgid;
+#ifdef __powerpc__
+ unsigned mode;
+ unsigned __seq;
+ u64 __unused1;
+ u64 __unused2;
+#elif defined(__mips__) || defined(__aarch64__)
+ unsigned int mode;
+ unsigned short __seq;
+ unsigned short __pad1;
+ unsigned long __unused1;
+ unsigned long __unused2;
+#else
+ unsigned short mode;
+ unsigned short __pad1;
+ unsigned short __seq;
+ unsigned short __pad2;
+#if defined(__x86_64__) && !defined(_LP64)
+ u64 __unused1;
+ u64 __unused2;
+#else
+ unsigned long __unused1;
+ unsigned long __unused2;
+#endif
+#endif
+ };
+
+ struct __sanitizer_shmid_ds {
+ __sanitizer_ipc_perm shm_perm;
+ #ifndef __powerpc__
+ uptr shm_segsz;
+ #elif !defined(__powerpc64__)
+ uptr __unused0;
+ #endif
+ #if defined(__x86_64__) && !defined(_LP64)
+ u64 shm_atime;
+ u64 shm_dtime;
+ u64 shm_ctime;
+ #else
+ uptr shm_atime;
+ #if !defined(_LP64) && !defined(__mips__)
+ uptr __unused1;
+ #endif
+ uptr shm_dtime;
+ #if !defined(_LP64) && !defined(__mips__)
+ uptr __unused2;
+ #endif
+ uptr shm_ctime;
+ #if !defined(_LP64) && !defined(__mips__)
+ uptr __unused3;
+ #endif
+ #endif
+ #ifdef __powerpc__
+ uptr shm_segsz;
+ #endif
+ int shm_cpid;
+ int shm_lpid;
+ #if defined(__x86_64__) && !defined(_LP64)
+ u64 shm_nattch;
+ u64 __unused4;
+ u64 __unused5;
+ #else
+ uptr shm_nattch;
+ uptr __unused4;
+ uptr __unused5;
+ #endif
+ };
+#elif SANITIZER_FREEBSD
+ struct __sanitizer_ipc_perm {
+ unsigned int cuid;
+ unsigned int cgid;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned short mode;
+ unsigned short seq;
+ long key;
+ };
+
+ struct __sanitizer_shmid_ds {
+ __sanitizer_ipc_perm shm_perm;
+ unsigned long shm_segsz;
+ unsigned int shm_lpid;
+ unsigned int shm_cpid;
+ int shm_nattch;
+ unsigned long shm_atime;
+ unsigned long shm_dtime;
+ unsigned long shm_ctime;
+ };
+#endif
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned struct_msqid_ds_sz;
+ extern unsigned struct_mq_attr_sz;
+ extern unsigned struct_timex_sz;
+ extern unsigned struct_statvfs_sz;
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+ struct __sanitizer_iovec {
+ void *iov_base;
+ uptr iov_len;
+ };
+
+#if !SANITIZER_ANDROID
+ struct __sanitizer_ifaddrs {
+ struct __sanitizer_ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ void *ifa_addr; // (struct sockaddr *)
+ void *ifa_netmask; // (struct sockaddr *)
+ // This is a union on Linux.
+# ifdef ifa_dstaddr
+# undef ifa_dstaddr
+# endif
+ void *ifa_dstaddr; // (struct sockaddr *)
+ void *ifa_data;
+ };
+#endif // !SANITIZER_ANDROID
+
+#if SANITIZER_MAC
+ typedef unsigned long __sanitizer_pthread_key_t;
+#else
+ typedef unsigned __sanitizer_pthread_key_t;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+
+ struct __sanitizer_XDR {
+ int x_op;
+ void *x_ops;
+ uptr x_public;
+ uptr x_private;
+ uptr x_base;
+ unsigned x_handy;
+ };
+
+ const int __sanitizer_XDR_ENCODE = 0;
+ const int __sanitizer_XDR_DECODE = 1;
+ const int __sanitizer_XDR_FREE = 2;
+#endif
+
+ struct __sanitizer_passwd {
+ char *pw_name;
+ char *pw_passwd;
+ int pw_uid;
+ int pw_gid;
+#if SANITIZER_MAC || SANITIZER_FREEBSD
+ long pw_change;
+ char *pw_class;
+#endif
+#if !SANITIZER_ANDROID
+ char *pw_gecos;
+#endif
+ char *pw_dir;
+ char *pw_shell;
+#if SANITIZER_MAC || SANITIZER_FREEBSD
+ long pw_expire;
+#endif
+#if SANITIZER_FREEBSD
+ int pw_fields;
+#endif
+ };
+
+ struct __sanitizer_group {
+ char *gr_name;
+ char *gr_passwd;
+ int gr_gid;
+ char **gr_mem;
+ };
+
+#if defined(__x86_64__) && !defined(_LP64)
+ typedef long long __sanitizer_time_t;
+#else
+ typedef long __sanitizer_time_t;
+#endif
+
+ struct __sanitizer_timeb {
+ __sanitizer_time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+ };
+
+ struct __sanitizer_ether_addr {
+ u8 octet[6];
+ };
+
+ struct __sanitizer_tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+ long int tm_gmtoff;
+ const char *tm_zone;
+ };
+
+#if SANITIZER_LINUX
+ struct __sanitizer_mntent {
+ char *mnt_fsname;
+ char *mnt_dir;
+ char *mnt_type;
+ char *mnt_opts;
+ int mnt_freq;
+ int mnt_passno;
+ };
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
+ struct __sanitizer_msghdr {
+ void *msg_name;
+ unsigned msg_namelen;
+ struct __sanitizer_iovec *msg_iov;
+ unsigned msg_iovlen;
+ void *msg_control;
+ unsigned msg_controllen;
+ int msg_flags;
+ };
+ struct __sanitizer_cmsghdr {
+ unsigned cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ };
+#else
+ struct __sanitizer_msghdr {
+ void *msg_name;
+ unsigned msg_namelen;
+ struct __sanitizer_iovec *msg_iov;
+ uptr msg_iovlen;
+ void *msg_control;
+ uptr msg_controllen;
+ int msg_flags;
+ };
+ struct __sanitizer_cmsghdr {
+ uptr cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ };
+#endif
+
+#if SANITIZER_MAC
+ struct __sanitizer_dirent {
+ unsigned long long d_ino;
+ unsigned long long d_seekoff;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#elif SANITIZER_FREEBSD
+ struct __sanitizer_dirent {
+ unsigned int d_fileno;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#elif SANITIZER_ANDROID || defined(__x86_64__)
+ struct __sanitizer_dirent {
+ unsigned long long d_ino;
+ unsigned long long d_off;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#else
+ struct __sanitizer_dirent {
+ uptr d_ino;
+ uptr d_off;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_dirent64 {
+ unsigned long long d_ino;
+ unsigned long long d_off;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#endif
+
+// 'clock_t' is 32 bits wide on x64 FreeBSD
+#if SANITIZER_FREEBSD
+ typedef int __sanitizer_clock_t;
+#elif defined(__x86_64__) && !defined(_LP64)
+ typedef long long __sanitizer_clock_t;
+#else
+ typedef long __sanitizer_clock_t;
+#endif
+
+#if SANITIZER_LINUX
+ typedef int __sanitizer_clockid_t;
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\
+ || defined(__mips__)
+ typedef unsigned __sanitizer___kernel_uid_t;
+ typedef unsigned __sanitizer___kernel_gid_t;
+#else
+ typedef unsigned short __sanitizer___kernel_uid_t;
+ typedef unsigned short __sanitizer___kernel_gid_t;
+#endif
+#if defined(__x86_64__) && !defined(_LP64)
+ typedef long long __sanitizer___kernel_off_t;
+#else
+ typedef long __sanitizer___kernel_off_t;
+#endif
+
+#if defined(__powerpc__) || defined(__mips__)
+ typedef unsigned int __sanitizer___kernel_old_uid_t;
+ typedef unsigned int __sanitizer___kernel_old_gid_t;
+#else
+ typedef unsigned short __sanitizer___kernel_old_uid_t;
+ typedef unsigned short __sanitizer___kernel_old_gid_t;
+#endif
+
+ typedef long long __sanitizer___kernel_loff_t;
+ typedef struct {
+ unsigned long fds_bits[1024 / (8 * sizeof(long))];
+ } __sanitizer___kernel_fd_set;
+#endif
+
+ // This thing depends on the platform. We are only interested in the upper
+ // limit. Verified with a compiler assert in .cc.
+ const int pthread_attr_t_max_sz = 128;
+ union __sanitizer_pthread_attr_t {
+ char size[pthread_attr_t_max_sz]; // NOLINT
+ void *align;
+ };
+
+#if SANITIZER_ANDROID
+ typedef unsigned long __sanitizer_sigset_t;
+#elif SANITIZER_MAC
+ typedef unsigned __sanitizer_sigset_t;
+#elif SANITIZER_LINUX
+ struct __sanitizer_sigset_t {
+ // The size is determined by looking at sizeof of real sigset_t on linux.
+ uptr val[128 / sizeof(uptr)];
+ };
+#elif SANITIZER_FREEBSD
+ struct __sanitizer_sigset_t {
+ // uint32_t * 4
+ unsigned int __bits[4];
+ };
+#endif
+
+ // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
+ struct __sanitizer_sigaction {
+#if defined(__mips__) && !SANITIZER_FREEBSD
+ unsigned int sa_flags;
+#endif
+ union {
+ void (*sigaction)(int sig, void *siginfo, void *uctx);
+ void (*handler)(int sig);
+ };
+#if SANITIZER_FREEBSD
+ int sa_flags;
+ __sanitizer_sigset_t sa_mask;
+#else
+ __sanitizer_sigset_t sa_mask;
+#ifndef __mips__
+ int sa_flags;
+#endif
+#endif
+#if SANITIZER_LINUX
+ void (*sa_restorer)();
+#endif
+#if defined(__mips__) && (SANITIZER_WORDSIZE == 32)
+ int sa_resv[1];
+#endif
+ };
+
+#if SANITIZER_FREEBSD
+ typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
+#elif defined(__mips__)
+ struct __sanitizer_kernel_sigset_t {
+ u8 sig[16];
+ };
+#else
+ struct __sanitizer_kernel_sigset_t {
+ u8 sig[8];
+ };
+#endif
+
+ // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
+ struct __sanitizer_kernel_sigaction_t {
+ union {
+ void (*handler)(int signo);
+ void (*sigaction)(int signo, void *info, void *ctx);
+ };
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ __sanitizer_kernel_sigset_t sa_mask;
+ };
+
+ extern uptr sig_ign;
+ extern uptr sig_dfl;
+ extern uptr sa_siginfo;
+
+#if SANITIZER_LINUX
+ extern int e_tabsz;
+#endif
+
+ extern int af_inet;
+ extern int af_inet6;
+ uptr __sanitizer_in_addr_sz(int af);
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ struct __sanitizer_dl_phdr_info {
+ uptr dlpi_addr;
+ const char *dlpi_name;
+ const void *dlpi_phdr;
+ short dlpi_phnum;
+ };
+#endif
+
+ struct __sanitizer_addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
+ unsigned ai_addrlen;
+ char *ai_canonname;
+ void *ai_addr;
+#else // LINUX
+ unsigned ai_addrlen;
+ void *ai_addr;
+ char *ai_canonname;
+#endif
+ struct __sanitizer_addrinfo *ai_next;
+ };
+
+ struct __sanitizer_hostent {
+ char *h_name;
+ char **h_aliases;
+ int h_addrtype;
+ int h_length;
+ char **h_addr_list;
+ };
+
+ struct __sanitizer_pollfd {
+ int fd;
+ short events;
+ short revents;
+ };
+
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
+ typedef unsigned __sanitizer_nfds_t;
+#else
+ typedef unsigned long __sanitizer_nfds_t;
+#endif
+
+#if !SANITIZER_ANDROID
+# if SANITIZER_LINUX
+ struct __sanitizer_glob_t {
+ uptr gl_pathc;
+ char **gl_pathv;
+ uptr gl_offs;
+ int gl_flags;
+
+ void (*gl_closedir)(void *dirp);
+ void *(*gl_readdir)(void *dirp);
+ void *(*gl_opendir)(const char *);
+ int (*gl_lstat)(const char *, void *);
+ int (*gl_stat)(const char *, void *);
+ };
+# elif SANITIZER_FREEBSD
+ struct __sanitizer_glob_t {
+ uptr gl_pathc;
+ uptr gl_matchc;
+ uptr gl_offs;
+ int gl_flags;
+ char **gl_pathv;
+ int (*gl_errfunc)(const char*, int);
+ void (*gl_closedir)(void *dirp);
+ struct dirent *(*gl_readdir)(void *dirp);
+ void *(*gl_opendir)(const char*);
+ int (*gl_lstat)(const char*, void* /* struct stat* */);
+ int (*gl_stat)(const char*, void* /* struct stat* */);
+ };
+# endif // SANITIZER_FREEBSD
+
+# if SANITIZER_LINUX || SANITIZER_FREEBSD
+ extern int glob_nomatch;
+ extern int glob_altdirfunc;
+# endif
+#endif // !SANITIZER_ANDROID
+
+ extern unsigned path_max;
+
+ struct __sanitizer_wordexp_t {
+ uptr we_wordc;
+ char **we_wordv;
+ uptr we_offs;
+#if SANITIZER_FREEBSD
+ char *we_strings;
+ uptr we_nbytes;
+#endif
+ };
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_FILE {
+ int _flags;
+ char *_IO_read_ptr;
+ char *_IO_read_end;
+ char *_IO_read_base;
+ char *_IO_write_base;
+ char *_IO_write_ptr;
+ char *_IO_write_end;
+ char *_IO_buf_base;
+ char *_IO_buf_end;
+ char *_IO_save_base;
+ char *_IO_backup_base;
+ char *_IO_save_end;
+ void *_markers;
+ __sanitizer_FILE *_chain;
+ int _fileno;
+ };
+# define SANITIZER_HAS_STRUCT_FILE 1
+#else
+ typedef void __sanitizer_FILE;
+# define SANITIZER_HAS_STRUCT_FILE 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
+ extern unsigned struct_user_regs_struct_sz;
+ extern unsigned struct_user_fpregs_struct_sz;
+ extern unsigned struct_user_fpxregs_struct_sz;
+
+ extern int ptrace_peektext;
+ extern int ptrace_peekdata;
+ extern int ptrace_peekuser;
+ extern int ptrace_getregs;
+ extern int ptrace_setregs;
+ extern int ptrace_getfpregs;
+ extern int ptrace_setfpregs;
+ extern int ptrace_getfpxregs;
+ extern int ptrace_setfpxregs;
+ extern int ptrace_getsiginfo;
+ extern int ptrace_setsiginfo;
+ extern int ptrace_getregset;
+ extern int ptrace_setregset;
+ extern int ptrace_geteventmsg;
+#endif
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned struct_shminfo_sz;
+ extern unsigned struct_shm_info_sz;
+ extern int shmctl_ipc_stat;
+ extern int shmctl_ipc_info;
+ extern int shmctl_shm_info;
+ extern int shmctl_shm_stat;
+#endif
+
+ extern int map_fixed;
+
+ // ioctl arguments
+ struct __sanitizer_ifconf {
+ int ifc_len;
+ union {
+ void *ifcu_req;
+ } ifc_ifcu;
+#if SANITIZER_MAC
+ } __attribute__((packed));
+#else
+ };
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+struct __sanitizer__obstack_chunk {
+ char *limit;
+ struct __sanitizer__obstack_chunk *prev;
+};
+
+struct __sanitizer_obstack {
+ long chunk_size;
+ struct __sanitizer__obstack_chunk *chunk;
+ char *object_base;
+ char *next_free;
+ uptr more_fields[7];
+};
+#endif
+
+#define IOC_NRBITS 8
+#define IOC_TYPEBITS 8
+#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__)
+#define IOC_SIZEBITS 13
+#define IOC_DIRBITS 3
+#define IOC_NONE 1U
+#define IOC_WRITE 4U
+#define IOC_READ 2U
+#else
+#define IOC_SIZEBITS 14
+#define IOC_DIRBITS 2
+#define IOC_NONE 0U
+#define IOC_WRITE 1U
+#define IOC_READ 2U
+#endif
+#define IOC_NRMASK ((1 << IOC_NRBITS) - 1)
+#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1)
+#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1)
+#if defined(IOC_DIRMASK)
+#undef IOC_DIRMASK
+#endif
+#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1)
+#define IOC_NRSHIFT 0
+#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS)
+#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS)
+#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS)
+#define EVIOC_EV_MAX 0x1f
+#define EVIOC_ABS_MAX 0x3f
+
+#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
+#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
+#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
+#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
+
+ extern unsigned struct_arpreq_sz;
+ extern unsigned struct_ifreq_sz;
+ extern unsigned struct_termios_sz;
+ extern unsigned struct_winsize_sz;
+
+#if SANITIZER_LINUX
+ extern unsigned struct_cdrom_msf_sz;
+ extern unsigned struct_cdrom_multisession_sz;
+ extern unsigned struct_cdrom_read_audio_sz;
+ extern unsigned struct_cdrom_subchnl_sz;
+ extern unsigned struct_cdrom_ti_sz;
+ extern unsigned struct_cdrom_tocentry_sz;
+ extern unsigned struct_cdrom_tochdr_sz;
+ extern unsigned struct_cdrom_volctrl_sz;
+ extern unsigned struct_ff_effect_sz;
+ extern unsigned struct_floppy_drive_params_sz;
+ extern unsigned struct_floppy_drive_struct_sz;
+ extern unsigned struct_floppy_fdc_state_sz;
+ extern unsigned struct_floppy_max_errors_sz;
+ extern unsigned struct_floppy_raw_cmd_sz;
+ extern unsigned struct_floppy_struct_sz;
+ extern unsigned struct_floppy_write_errors_sz;
+ extern unsigned struct_format_descr_sz;
+ extern unsigned struct_hd_driveid_sz;
+ extern unsigned struct_hd_geometry_sz;
+ extern unsigned struct_input_absinfo_sz;
+ extern unsigned struct_input_id_sz;
+ extern unsigned struct_mtpos_sz;
+ extern unsigned struct_termio_sz;
+ extern unsigned struct_vt_consize_sz;
+ extern unsigned struct_vt_sizes_sz;
+ extern unsigned struct_vt_stat_sz;
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ extern unsigned struct_copr_buffer_sz;
+ extern unsigned struct_copr_debug_buf_sz;
+ extern unsigned struct_copr_msg_sz;
+ extern unsigned struct_midi_info_sz;
+ extern unsigned struct_mtget_sz;
+ extern unsigned struct_mtop_sz;
+ extern unsigned struct_rtentry_sz;
+ extern unsigned struct_sbi_instrument_sz;
+ extern unsigned struct_seq_event_rec_sz;
+ extern unsigned struct_synth_info_sz;
+ extern unsigned struct_vt_mode_sz;
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned struct_ax25_parms_struct_sz;
+ extern unsigned struct_cyclades_monitor_sz;
+ extern unsigned struct_input_keymap_entry_sz;
+ extern unsigned struct_ipx_config_data_sz;
+ extern unsigned struct_kbdiacrs_sz;
+ extern unsigned struct_kbentry_sz;
+ extern unsigned struct_kbkeycode_sz;
+ extern unsigned struct_kbsentry_sz;
+ extern unsigned struct_mtconfiginfo_sz;
+ extern unsigned struct_nr_parms_struct_sz;
+ extern unsigned struct_scc_modem_sz;
+ extern unsigned struct_scc_stat_sz;
+ extern unsigned struct_serial_multiport_struct_sz;
+ extern unsigned struct_serial_struct_sz;
+ extern unsigned struct_sockaddr_ax25_sz;
+ extern unsigned struct_unimapdesc_sz;
+ extern unsigned struct_unimapinit_sz;
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned struct_audio_buf_info_sz;
+ extern unsigned struct_ppp_stats_sz;
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+#if !SANITIZER_ANDROID && !SANITIZER_MAC
+ extern unsigned struct_sioc_sg_req_sz;
+ extern unsigned struct_sioc_vif_req_sz;
+#endif
+
+ // ioctl request identifiers
+
+ // A special value to mark ioctls that are not present on the target platform,
+ // when it can not be determined without including any system headers.
+ extern const unsigned IOCTL_NOT_PRESENT;
+
+ extern unsigned IOCTL_FIOASYNC;
+ extern unsigned IOCTL_FIOCLEX;
+ extern unsigned IOCTL_FIOGETOWN;
+ extern unsigned IOCTL_FIONBIO;
+ extern unsigned IOCTL_FIONCLEX;
+ extern unsigned IOCTL_FIOSETOWN;
+ extern unsigned IOCTL_SIOCADDMULTI;
+ extern unsigned IOCTL_SIOCATMARK;
+ extern unsigned IOCTL_SIOCDELMULTI;
+ extern unsigned IOCTL_SIOCGIFADDR;
+ extern unsigned IOCTL_SIOCGIFBRDADDR;
+ extern unsigned IOCTL_SIOCGIFCONF;
+ extern unsigned IOCTL_SIOCGIFDSTADDR;
+ extern unsigned IOCTL_SIOCGIFFLAGS;
+ extern unsigned IOCTL_SIOCGIFMETRIC;
+ extern unsigned IOCTL_SIOCGIFMTU;
+ extern unsigned IOCTL_SIOCGIFNETMASK;
+ extern unsigned IOCTL_SIOCGPGRP;
+ extern unsigned IOCTL_SIOCSIFADDR;
+ extern unsigned IOCTL_SIOCSIFBRDADDR;
+ extern unsigned IOCTL_SIOCSIFDSTADDR;
+ extern unsigned IOCTL_SIOCSIFFLAGS;
+ extern unsigned IOCTL_SIOCSIFMETRIC;
+ extern unsigned IOCTL_SIOCSIFMTU;
+ extern unsigned IOCTL_SIOCSIFNETMASK;
+ extern unsigned IOCTL_SIOCSPGRP;
+ extern unsigned IOCTL_TIOCCONS;
+ extern unsigned IOCTL_TIOCEXCL;
+ extern unsigned IOCTL_TIOCGETD;
+ extern unsigned IOCTL_TIOCGPGRP;
+ extern unsigned IOCTL_TIOCGWINSZ;
+ extern unsigned IOCTL_TIOCMBIC;
+ extern unsigned IOCTL_TIOCMBIS;
+ extern unsigned IOCTL_TIOCMGET;
+ extern unsigned IOCTL_TIOCMSET;
+ extern unsigned IOCTL_TIOCNOTTY;
+ extern unsigned IOCTL_TIOCNXCL;
+ extern unsigned IOCTL_TIOCOUTQ;
+ extern unsigned IOCTL_TIOCPKT;
+ extern unsigned IOCTL_TIOCSCTTY;
+ extern unsigned IOCTL_TIOCSETD;
+ extern unsigned IOCTL_TIOCSPGRP;
+ extern unsigned IOCTL_TIOCSTI;
+ extern unsigned IOCTL_TIOCSWINSZ;
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned IOCTL_SIOCGETSGCNT;
+ extern unsigned IOCTL_SIOCGETVIFCNT;
+#endif
+#if SANITIZER_LINUX
+ extern unsigned IOCTL_EVIOCGABS;
+ extern unsigned IOCTL_EVIOCGBIT;
+ extern unsigned IOCTL_EVIOCGEFFECTS;
+ extern unsigned IOCTL_EVIOCGID;
+ extern unsigned IOCTL_EVIOCGKEY;
+ extern unsigned IOCTL_EVIOCGKEYCODE;
+ extern unsigned IOCTL_EVIOCGLED;
+ extern unsigned IOCTL_EVIOCGNAME;
+ extern unsigned IOCTL_EVIOCGPHYS;
+ extern unsigned IOCTL_EVIOCGRAB;
+ extern unsigned IOCTL_EVIOCGREP;
+ extern unsigned IOCTL_EVIOCGSND;
+ extern unsigned IOCTL_EVIOCGSW;
+ extern unsigned IOCTL_EVIOCGUNIQ;
+ extern unsigned IOCTL_EVIOCGVERSION;
+ extern unsigned IOCTL_EVIOCRMFF;
+ extern unsigned IOCTL_EVIOCSABS;
+ extern unsigned IOCTL_EVIOCSFF;
+ extern unsigned IOCTL_EVIOCSKEYCODE;
+ extern unsigned IOCTL_EVIOCSREP;
+ extern unsigned IOCTL_BLKFLSBUF;
+ extern unsigned IOCTL_BLKGETSIZE;
+ extern unsigned IOCTL_BLKRAGET;
+ extern unsigned IOCTL_BLKRASET;
+ extern unsigned IOCTL_BLKROGET;
+ extern unsigned IOCTL_BLKROSET;
+ extern unsigned IOCTL_BLKRRPART;
+ extern unsigned IOCTL_CDROMAUDIOBUFSIZ;
+ extern unsigned IOCTL_CDROMEJECT;
+ extern unsigned IOCTL_CDROMEJECT_SW;
+ extern unsigned IOCTL_CDROMMULTISESSION;
+ extern unsigned IOCTL_CDROMPAUSE;
+ extern unsigned IOCTL_CDROMPLAYMSF;
+ extern unsigned IOCTL_CDROMPLAYTRKIND;
+ extern unsigned IOCTL_CDROMREADAUDIO;
+ extern unsigned IOCTL_CDROMREADCOOKED;
+ extern unsigned IOCTL_CDROMREADMODE1;
+ extern unsigned IOCTL_CDROMREADMODE2;
+ extern unsigned IOCTL_CDROMREADRAW;
+ extern unsigned IOCTL_CDROMREADTOCENTRY;
+ extern unsigned IOCTL_CDROMREADTOCHDR;
+ extern unsigned IOCTL_CDROMRESET;
+ extern unsigned IOCTL_CDROMRESUME;
+ extern unsigned IOCTL_CDROMSEEK;
+ extern unsigned IOCTL_CDROMSTART;
+ extern unsigned IOCTL_CDROMSTOP;
+ extern unsigned IOCTL_CDROMSUBCHNL;
+ extern unsigned IOCTL_CDROMVOLCTRL;
+ extern unsigned IOCTL_CDROMVOLREAD;
+ extern unsigned IOCTL_CDROM_GET_UPC;
+ extern unsigned IOCTL_FDCLRPRM;
+ extern unsigned IOCTL_FDDEFPRM;
+ extern unsigned IOCTL_FDFLUSH;
+ extern unsigned IOCTL_FDFMTBEG;
+ extern unsigned IOCTL_FDFMTEND;
+ extern unsigned IOCTL_FDFMTTRK;
+ extern unsigned IOCTL_FDGETDRVPRM;
+ extern unsigned IOCTL_FDGETDRVSTAT;
+ extern unsigned IOCTL_FDGETDRVTYP;
+ extern unsigned IOCTL_FDGETFDCSTAT;
+ extern unsigned IOCTL_FDGETMAXERRS;
+ extern unsigned IOCTL_FDGETPRM;
+ extern unsigned IOCTL_FDMSGOFF;
+ extern unsigned IOCTL_FDMSGON;
+ extern unsigned IOCTL_FDPOLLDRVSTAT;
+ extern unsigned IOCTL_FDRAWCMD;
+ extern unsigned IOCTL_FDRESET;
+ extern unsigned IOCTL_FDSETDRVPRM;
+ extern unsigned IOCTL_FDSETEMSGTRESH;
+ extern unsigned IOCTL_FDSETMAXERRS;
+ extern unsigned IOCTL_FDSETPRM;
+ extern unsigned IOCTL_FDTWADDLE;
+ extern unsigned IOCTL_FDWERRORCLR;
+ extern unsigned IOCTL_FDWERRORGET;
+ extern unsigned IOCTL_HDIO_DRIVE_CMD;
+ extern unsigned IOCTL_HDIO_GETGEO;
+ extern unsigned IOCTL_HDIO_GET_32BIT;
+ extern unsigned IOCTL_HDIO_GET_DMA;
+ extern unsigned IOCTL_HDIO_GET_IDENTITY;
+ extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS;
+ extern unsigned IOCTL_HDIO_GET_MULTCOUNT;
+ extern unsigned IOCTL_HDIO_GET_NOWERR;
+ extern unsigned IOCTL_HDIO_GET_UNMASKINTR;
+ extern unsigned IOCTL_HDIO_SET_32BIT;
+ extern unsigned IOCTL_HDIO_SET_DMA;
+ extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS;
+ extern unsigned IOCTL_HDIO_SET_MULTCOUNT;
+ extern unsigned IOCTL_HDIO_SET_NOWERR;
+ extern unsigned IOCTL_HDIO_SET_UNMASKINTR;
+ extern unsigned IOCTL_MTIOCPOS;
+ extern unsigned IOCTL_PPPIOCGASYNCMAP;
+ extern unsigned IOCTL_PPPIOCGDEBUG;
+ extern unsigned IOCTL_PPPIOCGFLAGS;
+ extern unsigned IOCTL_PPPIOCGUNIT;
+ extern unsigned IOCTL_PPPIOCGXASYNCMAP;
+ extern unsigned IOCTL_PPPIOCSASYNCMAP;
+ extern unsigned IOCTL_PPPIOCSDEBUG;
+ extern unsigned IOCTL_PPPIOCSFLAGS;
+ extern unsigned IOCTL_PPPIOCSMAXCID;
+ extern unsigned IOCTL_PPPIOCSMRU;
+ extern unsigned IOCTL_PPPIOCSXASYNCMAP;
+ extern unsigned IOCTL_SIOCDARP;
+ extern unsigned IOCTL_SIOCDRARP;
+ extern unsigned IOCTL_SIOCGARP;
+ extern unsigned IOCTL_SIOCGIFENCAP;
+ extern unsigned IOCTL_SIOCGIFHWADDR;
+ extern unsigned IOCTL_SIOCGIFMAP;
+ extern unsigned IOCTL_SIOCGIFMEM;
+ extern unsigned IOCTL_SIOCGIFNAME;
+ extern unsigned IOCTL_SIOCGIFSLAVE;
+ extern unsigned IOCTL_SIOCGRARP;
+ extern unsigned IOCTL_SIOCGSTAMP;
+ extern unsigned IOCTL_SIOCSARP;
+ extern unsigned IOCTL_SIOCSIFENCAP;
+ extern unsigned IOCTL_SIOCSIFHWADDR;
+ extern unsigned IOCTL_SIOCSIFLINK;
+ extern unsigned IOCTL_SIOCSIFMAP;
+ extern unsigned IOCTL_SIOCSIFMEM;
+ extern unsigned IOCTL_SIOCSIFSLAVE;
+ extern unsigned IOCTL_SIOCSRARP;
+ extern unsigned IOCTL_SNDCTL_COPR_HALT;
+ extern unsigned IOCTL_SNDCTL_COPR_LOAD;
+ extern unsigned IOCTL_SNDCTL_COPR_RCODE;
+ extern unsigned IOCTL_SNDCTL_COPR_RCVMSG;
+ extern unsigned IOCTL_SNDCTL_COPR_RDATA;
+ extern unsigned IOCTL_SNDCTL_COPR_RESET;
+ extern unsigned IOCTL_SNDCTL_COPR_RUN;
+ extern unsigned IOCTL_SNDCTL_COPR_SENDMSG;
+ extern unsigned IOCTL_SNDCTL_COPR_WCODE;
+ extern unsigned IOCTL_SNDCTL_COPR_WDATA;
+ extern unsigned IOCTL_TCFLSH;
+ extern unsigned IOCTL_TCGETA;
+ extern unsigned IOCTL_TCGETS;
+ extern unsigned IOCTL_TCSBRK;
+ extern unsigned IOCTL_TCSBRKP;
+ extern unsigned IOCTL_TCSETA;
+ extern unsigned IOCTL_TCSETAF;
+ extern unsigned IOCTL_TCSETAW;
+ extern unsigned IOCTL_TCSETS;
+ extern unsigned IOCTL_TCSETSF;
+ extern unsigned IOCTL_TCSETSW;
+ extern unsigned IOCTL_TCXONC;
+ extern unsigned IOCTL_TIOCGLCKTRMIOS;
+ extern unsigned IOCTL_TIOCGSOFTCAR;
+ extern unsigned IOCTL_TIOCINQ;
+ extern unsigned IOCTL_TIOCLINUX;
+ extern unsigned IOCTL_TIOCSERCONFIG;
+ extern unsigned IOCTL_TIOCSERGETLSR;
+ extern unsigned IOCTL_TIOCSERGWILD;
+ extern unsigned IOCTL_TIOCSERSWILD;
+ extern unsigned IOCTL_TIOCSLCKTRMIOS;
+ extern unsigned IOCTL_TIOCSSOFTCAR;
+ extern unsigned IOCTL_VT_DISALLOCATE;
+ extern unsigned IOCTL_VT_GETSTATE;
+ extern unsigned IOCTL_VT_RESIZE;
+ extern unsigned IOCTL_VT_RESIZEX;
+ extern unsigned IOCTL_VT_SENDSIG;
+#endif // SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ extern unsigned IOCTL_MTIOCGET;
+ extern unsigned IOCTL_MTIOCTOP;
+ extern unsigned IOCTL_SIOCADDRT;
+ extern unsigned IOCTL_SIOCDELRT;
+ extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
+ extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
+ extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
+ extern unsigned IOCTL_SNDCTL_DSP_POST;
+ extern unsigned IOCTL_SNDCTL_DSP_RESET;
+ extern unsigned IOCTL_SNDCTL_DSP_SETFMT;
+ extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT;
+ extern unsigned IOCTL_SNDCTL_DSP_SPEED;
+ extern unsigned IOCTL_SNDCTL_DSP_STEREO;
+ extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE;
+ extern unsigned IOCTL_SNDCTL_DSP_SYNC;
+ extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE;
+ extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR;
+ extern unsigned IOCTL_SNDCTL_MIDI_INFO;
+ extern unsigned IOCTL_SNDCTL_MIDI_PRETIME;
+ extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE;
+ extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT;
+ extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT;
+ extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS;
+ extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS;
+ extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND;
+ extern unsigned IOCTL_SNDCTL_SEQ_PANIC;
+ extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE;
+ extern unsigned IOCTL_SNDCTL_SEQ_RESET;
+ extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES;
+ extern unsigned IOCTL_SNDCTL_SEQ_SYNC;
+ extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI;
+ extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD;
+ extern unsigned IOCTL_SNDCTL_SYNTH_INFO;
+ extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL;
+ extern unsigned IOCTL_SNDCTL_TMR_CONTINUE;
+ extern unsigned IOCTL_SNDCTL_TMR_METRONOME;
+ extern unsigned IOCTL_SNDCTL_TMR_SELECT;
+ extern unsigned IOCTL_SNDCTL_TMR_SOURCE;
+ extern unsigned IOCTL_SNDCTL_TMR_START;
+ extern unsigned IOCTL_SNDCTL_TMR_STOP;
+ extern unsigned IOCTL_SNDCTL_TMR_TEMPO;
+ extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM;
+ extern unsigned IOCTL_SOUND_MIXER_READ_BASS;
+ extern unsigned IOCTL_SOUND_MIXER_READ_CAPS;
+ extern unsigned IOCTL_SOUND_MIXER_READ_CD;
+ extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK;
+ extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_READ_IMIX;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE1;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE2;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE3;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LOUD;
+ extern unsigned IOCTL_SOUND_MIXER_READ_MIC;
+ extern unsigned IOCTL_SOUND_MIXER_READ_MUTE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_READ_PCM;
+ extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV;
+ extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK;
+ extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC;
+ extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER;
+ extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS;
+ extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH;
+ extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_CD;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME;
+ extern unsigned IOCTL_SOUND_PCM_READ_BITS;
+ extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS;
+ extern unsigned IOCTL_SOUND_PCM_READ_FILTER;
+ extern unsigned IOCTL_SOUND_PCM_READ_RATE;
+ extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;
+ extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER;
+ extern unsigned IOCTL_VT_ACTIVATE;
+ extern unsigned IOCTL_VT_GETMODE;
+ extern unsigned IOCTL_VT_OPENQRY;
+ extern unsigned IOCTL_VT_RELDISP;
+ extern unsigned IOCTL_VT_SETMODE;
+ extern unsigned IOCTL_VT_WAITACTIVE;
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned IOCTL_CYGETDEFTHRESH;
+ extern unsigned IOCTL_CYGETDEFTIMEOUT;
+ extern unsigned IOCTL_CYGETMON;
+ extern unsigned IOCTL_CYGETTHRESH;
+ extern unsigned IOCTL_CYGETTIMEOUT;
+ extern unsigned IOCTL_CYSETDEFTHRESH;
+ extern unsigned IOCTL_CYSETDEFTIMEOUT;
+ extern unsigned IOCTL_CYSETTHRESH;
+ extern unsigned IOCTL_CYSETTIMEOUT;
+ extern unsigned IOCTL_EQL_EMANCIPATE;
+ extern unsigned IOCTL_EQL_ENSLAVE;
+ extern unsigned IOCTL_EQL_GETMASTRCFG;
+ extern unsigned IOCTL_EQL_GETSLAVECFG;
+ extern unsigned IOCTL_EQL_SETMASTRCFG;
+ extern unsigned IOCTL_EQL_SETSLAVECFG;
+ extern unsigned IOCTL_EVIOCGKEYCODE_V2;
+ extern unsigned IOCTL_EVIOCGPROP;
+ extern unsigned IOCTL_EVIOCSKEYCODE_V2;
+ extern unsigned IOCTL_FS_IOC_GETFLAGS;
+ extern unsigned IOCTL_FS_IOC_GETVERSION;
+ extern unsigned IOCTL_FS_IOC_SETFLAGS;
+ extern unsigned IOCTL_FS_IOC_SETVERSION;
+ extern unsigned IOCTL_GIO_CMAP;
+ extern unsigned IOCTL_GIO_FONT;
+ extern unsigned IOCTL_GIO_UNIMAP;
+ extern unsigned IOCTL_GIO_UNISCRNMAP;
+ extern unsigned IOCTL_KDADDIO;
+ extern unsigned IOCTL_KDDELIO;
+ extern unsigned IOCTL_KDGETKEYCODE;
+ extern unsigned IOCTL_KDGKBDIACR;
+ extern unsigned IOCTL_KDGKBENT;
+ extern unsigned IOCTL_KDGKBLED;
+ extern unsigned IOCTL_KDGKBMETA;
+ extern unsigned IOCTL_KDGKBSENT;
+ extern unsigned IOCTL_KDMAPDISP;
+ extern unsigned IOCTL_KDSETKEYCODE;
+ extern unsigned IOCTL_KDSIGACCEPT;
+ extern unsigned IOCTL_KDSKBDIACR;
+ extern unsigned IOCTL_KDSKBENT;
+ extern unsigned IOCTL_KDSKBLED;
+ extern unsigned IOCTL_KDSKBMETA;
+ extern unsigned IOCTL_KDSKBSENT;
+ extern unsigned IOCTL_KDUNMAPDISP;
+ extern unsigned IOCTL_LPABORT;
+ extern unsigned IOCTL_LPABORTOPEN;
+ extern unsigned IOCTL_LPCAREFUL;
+ extern unsigned IOCTL_LPCHAR;
+ extern unsigned IOCTL_LPGETIRQ;
+ extern unsigned IOCTL_LPGETSTATUS;
+ extern unsigned IOCTL_LPRESET;
+ extern unsigned IOCTL_LPSETIRQ;
+ extern unsigned IOCTL_LPTIME;
+ extern unsigned IOCTL_LPWAIT;
+ extern unsigned IOCTL_MTIOCGETCONFIG;
+ extern unsigned IOCTL_MTIOCSETCONFIG;
+ extern unsigned IOCTL_PIO_CMAP;
+ extern unsigned IOCTL_PIO_FONT;
+ extern unsigned IOCTL_PIO_UNIMAP;
+ extern unsigned IOCTL_PIO_UNIMAPCLR;
+ extern unsigned IOCTL_PIO_UNISCRNMAP;
+ extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN;
+ extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST;
+ extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE;
+ extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE;
+ extern unsigned IOCTL_SIOCAIPXITFCRT;
+ extern unsigned IOCTL_SIOCAIPXPRISLT;
+ extern unsigned IOCTL_SIOCAX25ADDUID;
+ extern unsigned IOCTL_SIOCAX25DELUID;
+ extern unsigned IOCTL_SIOCAX25GETPARMS;
+ extern unsigned IOCTL_SIOCAX25GETUID;
+ extern unsigned IOCTL_SIOCAX25NOUID;
+ extern unsigned IOCTL_SIOCAX25SETPARMS;
+ extern unsigned IOCTL_SIOCDEVPLIP;
+ extern unsigned IOCTL_SIOCIPXCFGDATA;
+ extern unsigned IOCTL_SIOCNRDECOBS;
+ extern unsigned IOCTL_SIOCNRGETPARMS;
+ extern unsigned IOCTL_SIOCNRRTCTL;
+ extern unsigned IOCTL_SIOCNRSETPARMS;
+ extern unsigned IOCTL_SNDCTL_DSP_GETISPACE;
+ extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE;
+ extern unsigned IOCTL_TIOCGSERIAL;
+ extern unsigned IOCTL_TIOCSERGETMULTI;
+ extern unsigned IOCTL_TIOCSERSETMULTI;
+ extern unsigned IOCTL_TIOCSSERIAL;
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned IOCTL_GIO_SCRNMAP;
+ extern unsigned IOCTL_KDDISABIO;
+ extern unsigned IOCTL_KDENABIO;
+ extern unsigned IOCTL_KDGETLED;
+ extern unsigned IOCTL_KDGETMODE;
+ extern unsigned IOCTL_KDGKBMODE;
+ extern unsigned IOCTL_KDGKBTYPE;
+ extern unsigned IOCTL_KDMKTONE;
+ extern unsigned IOCTL_KDSETLED;
+ extern unsigned IOCTL_KDSETMODE;
+ extern unsigned IOCTL_KDSKBMODE;
+ extern unsigned IOCTL_KIOCSOUND;
+ extern unsigned IOCTL_PIO_SCRNMAP;
+#endif
+
+ extern const int errno_EINVAL;
+ extern const int errno_EOWNERDEAD;
+
+ extern const int si_SEGV_MAPERR;
+ extern const int si_SEGV_ACCERR;
+} // namespace __sanitizer
+
+#define CHECK_TYPE_SIZE(TYPE) \
+ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
+
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
+ sizeof(((CLASS *) NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \
+ offsetof(CLASS, MEMBER))
+
+// For sigaction, which is a function and struct at the same time,
+// and thus requires explicit "struct" in sizeof() expression.
+#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \
+ sizeof(((struct CLASS *) NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \
+ offsetof(struct CLASS, MEMBER))
+
+#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
new file mode 100644
index 000000000000..5bc41c2580fb
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
@@ -0,0 +1,324 @@
+//===-- sanitizer_posix.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements POSIX-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+
+#include <sys/mman.h>
+
+#if SANITIZER_LINUX
+#include <sys/utsname.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <sys/personality.h>
+#endif
+
+#if SANITIZER_FREEBSD
+// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
+// that, it was never implemented. So just define it to zero.
+#undef MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+
+namespace __sanitizer {
+
+// ------------- sanitizer_common.h
+uptr GetMmapGranularity() {
+ return GetPageSize();
+}
+
+#if SANITIZER_WORDSIZE == 32
+// Take care of unusable kernel area in top gigabyte.
+static uptr GetKernelAreaSize() {
+#if SANITIZER_LINUX
+ const uptr gbyte = 1UL << 30;
+
+ // Firstly check if there are writable segments
+ // mapped to top gigabyte (e.g. stack).
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr end, prot;
+ while (proc_maps.Next(/*start*/0, &end,
+ /*offset*/0, /*filename*/0,
+ /*filename_size*/0, &prot)) {
+ if ((end >= 3 * gbyte)
+ && (prot & MemoryMappingLayout::kProtectionWrite) != 0)
+ return 0;
+ }
+
+#if !SANITIZER_ANDROID
+ // Even if nothing is mapped, top Gb may still be accessible
+ // if we are running on 64-bit kernel.
+ // Uname may report misleading results if personality type
+ // is modified (e.g. under schroot) so check this as well.
+ struct utsname uname_info;
+ int pers = personality(0xffffffffUL);
+ if (!(pers & PER_MASK)
+ && uname(&uname_info) == 0
+ && internal_strstr(uname_info.machine, "64"))
+ return 0;
+#endif // SANITIZER_ANDROID
+
+ // Top gigabyte is reserved for kernel.
+ return gbyte;
+#else
+ return 0;
+#endif // SANITIZER_LINUX
+}
+#endif // SANITIZER_WORDSIZE == 32
+
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__powerpc64__) || defined(__aarch64__)
+ // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
+ // We somehow need to figure out which one we are using now and choose
+ // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
+ // Note that with 'ulimit -s unlimited' the stack is moved away from the top
+ // of the address space, so simply checking the stack address is not enough.
+ // This should (does) work for both PowerPC64 Endian modes.
+ // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
+ return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
+# elif defined(__mips64)
+ return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
+# else
+ return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+ uptr res = (1ULL << 32) - 1; // 0xffffffff;
+ if (!common_flags()->full_address_space)
+ res -= GetKernelAreaSize();
+ CHECK_LT(reinterpret_cast<uptr>(&res), res);
+ return res;
+#endif // SANITIZER_WORDSIZE
+}
+
+void *MmapOrDie(uptr size, const char *mem_type) {
+ size = RoundUpTo(size, GetPageSizeCached());
+ uptr res = internal_mmap(0, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ int reserrno;
+ if (internal_iserror(res, &reserrno)) {
+ static int recursion_count;
+ if (recursion_count) {
+ // The Report() and CHECK calls below may call mmap recursively and fail.
+ // If we went into recursion, just die.
+ RawWrite("ERROR: Failed to mmap\n");
+ Die();
+ }
+ recursion_count++;
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
+ SanitizerToolName, size, size, mem_type, reserrno);
+ DumpProcessMap();
+ CHECK("unable to mmap" && 0);
+ }
+ IncreaseTotalMmap(size);
+ return (void *)res;
+}
+
+void UnmapOrDie(void *addr, uptr size) {
+ if (!addr || !size) return;
+ uptr res = internal_munmap(addr, size);
+ if (internal_iserror(res)) {
+ Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+ SanitizerToolName, size, size, addr);
+ CHECK("unable to unmap" && 0);
+ }
+ DecreaseTotalMmap(size);
+}
+
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+ uptr PageSize = GetPageSizeCached();
+ uptr p = internal_mmap(0,
+ RoundUpTo(size, PageSize),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ -1, 0);
+ int reserrno;
+ if (internal_iserror(p, &reserrno)) {
+ Report("ERROR: %s failed to "
+ "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
+ SanitizerToolName, size, size, mem_type, reserrno);
+ CHECK("unable to mmap" && 0);
+ }
+ IncreaseTotalMmap(size);
+ return (void *)p;
+}
+
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
+ uptr PageSize = GetPageSizeCached();
+ uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
+ RoundUpTo(size, PageSize),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
+ -1, 0);
+ int reserrno;
+ if (internal_iserror(p, &reserrno))
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
+ SanitizerToolName, size, size, fixed_addr, reserrno);
+ IncreaseTotalMmap(size);
+ return (void *)p;
+}
+
+void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
+ uptr PageSize = GetPageSizeCached();
+ uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
+ RoundUpTo(size, PageSize),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+ -1, 0);
+ int reserrno;
+ if (internal_iserror(p, &reserrno)) {
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
+ SanitizerToolName, size, size, fixed_addr, reserrno);
+ CHECK("unable to mmap" && 0);
+ }
+ IncreaseTotalMmap(size);
+ return (void *)p;
+}
+
+void *Mprotect(uptr fixed_addr, uptr size) {
+ return (void *)internal_mmap((void*)fixed_addr, size,
+ PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED |
+ MAP_NORESERVE, -1, 0);
+}
+
+void *MapFileToMemory(const char *file_name, uptr *buff_size) {
+ uptr openrv = OpenFile(file_name, false);
+ CHECK(!internal_iserror(openrv));
+ fd_t fd = openrv;
+ uptr fsize = internal_filesize(fd);
+ CHECK_NE(fsize, (uptr)-1);
+ CHECK_GT(fsize, 0);
+ *buff_size = RoundUpTo(fsize, GetPageSizeCached());
+ uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ return internal_iserror(map) ? 0 : (void *)map;
+}
+
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+ uptr flags = MAP_SHARED;
+ if (addr) flags |= MAP_FIXED;
+ uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
+ if (internal_iserror(p)) {
+ Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset,
+ size, p);
+ return 0;
+ }
+ return (void *)p;
+}
+
+static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
+ uptr start2, uptr end2) {
+ CHECK(start1 <= end1);
+ CHECK(start2 <= end2);
+ return (end1 < start2) || (end2 < start1);
+}
+
+// FIXME: this is thread-unsafe, but should not cause problems most of the time.
+// When the shadow is mapped only a single thread usually exists (plus maybe
+// several worker threads on Mac, which aren't expected to map big chunks of
+// memory).
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr start, end;
+ while (proc_maps.Next(&start, &end,
+ /*offset*/0, /*filename*/0, /*filename_size*/0,
+ /*protection*/0)) {
+ CHECK_NE(0, end);
+ if (!IntervalsAreSeparate(start, end - 1, range_start, range_end))
+ return false;
+ }
+ return true;
+}
+
+void DumpProcessMap() {
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr start, end;
+ const sptr kBufSize = 4095;
+ char *filename = (char*)MmapOrDie(kBufSize, __func__);
+ Report("Process memory map follows:\n");
+ while (proc_maps.Next(&start, &end, /* file_offset */0,
+ filename, kBufSize, /* protection */0)) {
+ Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
+ }
+ Report("End of process memory map.\n");
+ UnmapOrDie(filename, kBufSize);
+}
+
+const char *GetPwd() {
+ return GetEnv("PWD");
+}
+
+char *FindPathToBinary(const char *name) {
+ const char *path = GetEnv("PATH");
+ if (!path)
+ return 0;
+ uptr name_len = internal_strlen(name);
+ InternalScopedBuffer<char> buffer(kMaxPathLength);
+ const char *beg = path;
+ while (true) {
+ const char *end = internal_strchrnul(beg, ':');
+ uptr prefix_len = end - beg;
+ if (prefix_len + name_len + 2 <= kMaxPathLength) {
+ internal_memcpy(buffer.data(), beg, prefix_len);
+ buffer[prefix_len] = '/';
+ internal_memcpy(&buffer[prefix_len + 1], name, name_len);
+ buffer[prefix_len + 1 + name_len] = '\0';
+ if (FileExists(buffer.data()))
+ return internal_strdup(buffer.data());
+ }
+ if (*end == '\0') break;
+ beg = end + 1;
+ }
+ return 0;
+}
+
+void ReportFile::Write(const char *buffer, uptr length) {
+ SpinMutexLock l(mu);
+ static const char *kWriteError =
+ "ReportFile::Write() can't output requested buffer!\n";
+ ReopenIfNecessary();
+ if (length != internal_write(fd, buffer, length)) {
+ internal_write(fd, kWriteError, internal_strlen(kWriteError));
+ Die();
+ }
+}
+
+bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
+ uptr s, e, off, prot;
+ InternalScopedString buff(kMaxPathLength);
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
+ && internal_strcmp(module, buff.data()) == 0) {
+ *start = s;
+ *end = e;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc
new file mode 100644
index 000000000000..11828e6cdf51
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -0,0 +1,205 @@
+//===-- sanitizer_posix_libcdep.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements libc-dependent POSIX-specific functions
+// from sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_POSIX
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_stacktrace.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+u32 GetUid() {
+ return getuid();
+}
+
+uptr GetThreadSelf() {
+ return (uptr)pthread_self();
+}
+
+void FlushUnneededShadowMemory(uptr addr, uptr size) {
+ madvise((void*)addr, size, MADV_DONTNEED);
+}
+
+void NoHugePagesInRegion(uptr addr, uptr size) {
+#ifdef MADV_NOHUGEPAGE // May not be defined on old systems.
+ madvise((void *)addr, size, MADV_NOHUGEPAGE);
+#endif // MADV_NOHUGEPAGE
+}
+
+void DontDumpShadowMemory(uptr addr, uptr length) {
+#ifdef MADV_DONTDUMP
+ madvise((void *)addr, length, MADV_DONTDUMP);
+#endif
+}
+
+static rlim_t getlim(int res) {
+ rlimit rlim;
+ CHECK_EQ(0, getrlimit(res, &rlim));
+ return rlim.rlim_cur;
+}
+
+static void setlim(int res, rlim_t lim) {
+ // The following magic is to prevent clang from replacing it with memset.
+ volatile struct rlimit rlim;
+ rlim.rlim_cur = lim;
+ rlim.rlim_max = lim;
+ if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
+ Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
+ Die();
+ }
+}
+
+void DisableCoreDumperIfNecessary() {
+ if (common_flags()->disable_coredump) {
+ setlim(RLIMIT_CORE, 0);
+ }
+}
+
+bool StackSizeIsUnlimited() {
+ rlim_t stack_size = getlim(RLIMIT_STACK);
+ return (stack_size == RLIM_INFINITY);
+}
+
+void SetStackSizeLimitInBytes(uptr limit) {
+ setlim(RLIMIT_STACK, (rlim_t)limit);
+ CHECK(!StackSizeIsUnlimited());
+}
+
+bool AddressSpaceIsUnlimited() {
+ rlim_t as_size = getlim(RLIMIT_AS);
+ return (as_size == RLIM_INFINITY);
+}
+
+void SetAddressSpaceUnlimited() {
+ setlim(RLIMIT_AS, RLIM_INFINITY);
+ CHECK(AddressSpaceIsUnlimited());
+}
+
+void SleepForSeconds(int seconds) {
+ sleep(seconds);
+}
+
+void SleepForMillis(int millis) {
+ usleep(millis * 1000);
+}
+
+void Abort() {
+ abort();
+}
+
+int Atexit(void (*function)(void)) {
+#ifndef SANITIZER_GO
+ return atexit(function);
+#else
+ return 0;
+#endif
+}
+
+int internal_isatty(fd_t fd) {
+ return isatty(fd);
+}
+
+#ifndef SANITIZER_GO
+// TODO(glider): different tools may require different altstack size.
+static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
+
+void SetAlternateSignalStack() {
+ stack_t altstack, oldstack;
+ CHECK_EQ(0, sigaltstack(0, &oldstack));
+ // If the alternate stack is already in place, do nothing.
+ // Android always sets an alternate stack, but it's too small for us.
+ if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
+ // TODO(glider): the mapped stack should have the MAP_STACK flag in the
+ // future. It is not required by man 2 sigaltstack now (they're using
+ // malloc()).
+ void* base = MmapOrDie(kAltStackSize, __func__);
+ altstack.ss_sp = (char*) base;
+ altstack.ss_flags = 0;
+ altstack.ss_size = kAltStackSize;
+ CHECK_EQ(0, sigaltstack(&altstack, 0));
+}
+
+void UnsetAlternateSignalStack() {
+ stack_t altstack, oldstack;
+ altstack.ss_sp = 0;
+ altstack.ss_flags = SS_DISABLE;
+ altstack.ss_size = kAltStackSize; // Some sane value required on Darwin.
+ CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
+ UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
+}
+
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+static void MaybeInstallSigaction(int signum,
+ SignalHandlerType handler) {
+ if (!IsDeadlySignal(signum))
+ return;
+ struct sigaction sigact;
+ internal_memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = (sa_sigaction_t)handler;
+ // Do not block the signal from being received in that signal's handler.
+ // Clients are responsible for handling this correctly.
+ sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
+ if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
+ CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
+ VReport(1, "Installed the sigaction for signal %d\n", signum);
+}
+
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {
+ // Set the alternate signal stack for the main thread.
+ // This will cause SetAlternateSignalStack to be called twice, but the stack
+ // will be actually set only once.
+ if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+ MaybeInstallSigaction(SIGSEGV, handler);
+ MaybeInstallSigaction(SIGBUS, handler);
+}
+#endif // SANITIZER_GO
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+ uptr page_size = GetPageSizeCached();
+ // Checking too large memory ranges is slow.
+ CHECK_LT(size, page_size * 10);
+ int sock_pair[2];
+ if (pipe(sock_pair))
+ return false;
+ uptr bytes_written =
+ internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
+ int write_errno;
+ bool result;
+ if (internal_iserror(bytes_written, &write_errno)) {
+ CHECK_EQ(EFAULT, write_errno);
+ result = false;
+ } else {
+ result = (bytes_written == size);
+ }
+ internal_close(sock_pair[0]);
+ internal_close(sock_pair[1]);
+ return result;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc
new file mode 100644
index 000000000000..3be6723cd660
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc
@@ -0,0 +1,325 @@
+//===-- sanitizer_printf.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 shared between AddressSanitizer and ThreadSanitizer.
+//
+// Internal printf function, used inside run-time libraries.
+// We can't use libc printf because we intercept some of the functions used
+// inside it.
+//===----------------------------------------------------------------------===//
+
+
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_libc.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \
+ !defined(va_copy)
+# define va_copy(dst, src) ((dst) = (src))
+#endif
+
+namespace __sanitizer {
+
+StaticSpinMutex CommonSanitizerReportMutex;
+
+static int AppendChar(char **buff, const char *buff_end, char c) {
+ if (*buff < buff_end) {
+ **buff = c;
+ (*buff)++;
+ }
+ return 1;
+}
+
+// Appends number in a given base to buffer. If its length is less than
+// |minimal_num_length|, it is padded with leading zeroes or spaces, depending
+// on the value of |pad_with_zero|.
+static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
+ u8 base, u8 minimal_num_length, bool pad_with_zero,
+ bool negative) {
+ uptr const kMaxLen = 30;
+ RAW_CHECK(base == 10 || base == 16);
+ RAW_CHECK(base == 10 || !negative);
+ RAW_CHECK(absolute_value || !negative);
+ RAW_CHECK(minimal_num_length < kMaxLen);
+ int result = 0;
+ if (negative && minimal_num_length)
+ --minimal_num_length;
+ if (negative && pad_with_zero)
+ result += AppendChar(buff, buff_end, '-');
+ uptr num_buffer[kMaxLen];
+ int pos = 0;
+ do {
+ RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow");
+ num_buffer[pos++] = absolute_value % base;
+ absolute_value /= base;
+ } while (absolute_value > 0);
+ if (pos < minimal_num_length) {
+ // Make sure compiler doesn't insert call to memset here.
+ internal_memset(&num_buffer[pos], 0,
+ sizeof(num_buffer[0]) * (minimal_num_length - pos));
+ pos = minimal_num_length;
+ }
+ RAW_CHECK(pos > 0);
+ pos--;
+ for (; pos >= 0 && num_buffer[pos] == 0; pos--) {
+ char c = (pad_with_zero || pos == 0) ? '0' : ' ';
+ result += AppendChar(buff, buff_end, c);
+ }
+ if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
+ for (; pos >= 0; pos--) {
+ char digit = static_cast<char>(num_buffer[pos]);
+ result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
+ : 'a' + digit - 10);
+ }
+ return result;
+}
+
+static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
+ u8 minimal_num_length, bool pad_with_zero) {
+ return AppendNumber(buff, buff_end, num, base, minimal_num_length,
+ pad_with_zero, false /* negative */);
+}
+
+static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
+ u8 minimal_num_length, bool pad_with_zero) {
+ bool negative = (num < 0);
+ return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
+ minimal_num_length, pad_with_zero, negative);
+}
+
+static int AppendString(char **buff, const char *buff_end, int precision,
+ const char *s) {
+ if (s == 0)
+ s = "<null>";
+ int result = 0;
+ for (; *s; s++) {
+ if (precision >= 0 && result >= precision)
+ break;
+ result += AppendChar(buff, buff_end, *s);
+ }
+ return result;
+}
+
+static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
+ int result = 0;
+ result += AppendString(buff, buff_end, -1, "0x");
+ result += AppendUnsigned(buff, buff_end, ptr_value, 16,
+ SANITIZER_POINTER_FORMAT_LENGTH, true);
+ return result;
+}
+
+int VSNPrintf(char *buff, int buff_length,
+ const char *format, va_list args) {
+ static const char *kPrintfFormatsHelp =
+ "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n";
+ RAW_CHECK(format);
+ RAW_CHECK(buff_length > 0);
+ const char *buff_end = &buff[buff_length - 1];
+ const char *cur = format;
+ int result = 0;
+ for (; *cur; cur++) {
+ if (*cur != '%') {
+ result += AppendChar(&buff, buff_end, *cur);
+ continue;
+ }
+ cur++;
+ bool have_width = (*cur >= '0' && *cur <= '9');
+ bool pad_with_zero = (*cur == '0');
+ int width = 0;
+ if (have_width) {
+ while (*cur >= '0' && *cur <= '9') {
+ width = width * 10 + *cur++ - '0';
+ }
+ }
+ bool have_precision = (cur[0] == '.' && cur[1] == '*');
+ int precision = -1;
+ if (have_precision) {
+ cur += 2;
+ precision = va_arg(args, int);
+ }
+ bool have_z = (*cur == 'z');
+ cur += have_z;
+ bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
+ cur += have_ll * 2;
+ s64 dval;
+ u64 uval;
+ bool have_flags = have_width | have_z | have_ll;
+ // Only %s supports precision for now
+ CHECK(!(precision >= 0 && *cur != 's'));
+ switch (*cur) {
+ case 'd': {
+ dval = have_ll ? va_arg(args, s64)
+ : have_z ? va_arg(args, sptr)
+ : va_arg(args, int);
+ result += AppendSignedDecimal(&buff, buff_end, dval, width,
+ pad_with_zero);
+ break;
+ }
+ case 'u':
+ case 'x': {
+ uval = have_ll ? va_arg(args, u64)
+ : have_z ? va_arg(args, uptr)
+ : va_arg(args, unsigned);
+ result += AppendUnsigned(&buff, buff_end, uval,
+ (*cur == 'u') ? 10 : 16, width, pad_with_zero);
+ break;
+ }
+ case 'p': {
+ RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
+ result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
+ break;
+ }
+ case 's': {
+ RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
+ result += AppendString(&buff, buff_end, precision, va_arg(args, char*));
+ break;
+ }
+ case 'c': {
+ RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
+ result += AppendChar(&buff, buff_end, va_arg(args, int));
+ break;
+ }
+ case '%' : {
+ RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
+ result += AppendChar(&buff, buff_end, '%');
+ break;
+ }
+ default: {
+ RAW_CHECK_MSG(false, kPrintfFormatsHelp);
+ }
+ }
+ }
+ RAW_CHECK(buff <= buff_end);
+ AppendChar(&buff, buff_end + 1, '\0');
+ return result;
+}
+
+static void (*PrintfAndReportCallback)(const char *);
+void SetPrintfAndReportCallback(void (*callback)(const char *)) {
+ PrintfAndReportCallback = callback;
+}
+
+// Can be overriden in frontend.
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void OnPrint(const char *str) {
+ (void)str;
+}
+#elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS)
+void OnPrint(const char *str);
+#else
+void OnPrint(const char *str) {
+ (void)str;
+}
+#endif
+
+static void CallPrintfAndReportCallback(const char *str) {
+ OnPrint(str);
+ if (PrintfAndReportCallback)
+ PrintfAndReportCallback(str);
+}
+
+static void SharedPrintfCode(bool append_pid, const char *format,
+ va_list args) {
+ va_list args2;
+ va_copy(args2, args);
+ const int kLen = 16 * 1024;
+ // |local_buffer| is small enough not to overflow the stack and/or violate
+ // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
+ // hand, the bigger the buffer is, the more the chance the error report will
+ // fit into it.
+ char local_buffer[400];
+ int needed_length;
+ char *buffer = local_buffer;
+ int buffer_size = ARRAY_SIZE(local_buffer);
+ // First try to print a message using a local buffer, and then fall back to
+ // mmaped buffer.
+ for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
+ if (use_mmap) {
+ va_end(args);
+ va_copy(args, args2);
+ buffer = (char*)MmapOrDie(kLen, "Report");
+ buffer_size = kLen;
+ }
+ needed_length = 0;
+ if (append_pid) {
+ int pid = internal_getpid();
+ needed_length += internal_snprintf(buffer, buffer_size, "==%d==", pid);
+ if (needed_length >= buffer_size) {
+ // The pid doesn't fit into the current buffer.
+ if (!use_mmap)
+ continue;
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+ }
+ }
+ needed_length += VSNPrintf(buffer + needed_length,
+ buffer_size - needed_length, format, args);
+ if (needed_length >= buffer_size) {
+ // The message doesn't fit into the current buffer.
+ if (!use_mmap)
+ continue;
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+ }
+ // If the message fit into the buffer, print it and exit.
+ break;
+ }
+ RawWrite(buffer);
+ AndroidLogWrite(buffer);
+ CallPrintfAndReportCallback(buffer);
+ // If we had mapped any memory, clean up.
+ if (buffer != local_buffer)
+ UnmapOrDie((void *)buffer, buffer_size);
+ va_end(args2);
+}
+
+FORMAT(1, 2)
+void Printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ SharedPrintfCode(false, format, args);
+ va_end(args);
+}
+
+// Like Printf, but prints the current PID before the output string.
+FORMAT(1, 2)
+void Report(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ SharedPrintfCode(true, format, args);
+ va_end(args);
+}
+
+// Writes at most "length" symbols to "buffer" (including trailing '\0').
+// Returns the number of symbols that should have been written to buffer
+// (not including trailing '\0'). Thus, the string is truncated
+// iff return value is not less than "length".
+FORMAT(3, 4)
+int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ int needed_length = VSNPrintf(buffer, length, format, args);
+ va_end(args);
+ return needed_length;
+}
+
+FORMAT(2, 3)
+void InternalScopedString::append(const char *format, ...) {
+ CHECK_LT(length_, size());
+ va_list args;
+ va_start(args, format);
+ VSNPrintf(data() + length_, size() - length_, format, args);
+ va_end(args);
+ length_ += internal_strlen(data() + length_);
+ CHECK_LT(length_, size());
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
new file mode 100644
index 000000000000..94e3871af9a2
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -0,0 +1,99 @@
+//===-- sanitizer_procmaps.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 shared between AddressSanitizer and ThreadSanitizer.
+//
+// Information about the process mappings.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PROCMAPS_H
+#define SANITIZER_PROCMAPS_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+struct ProcSelfMapsBuff {
+ char *data;
+ uptr mmaped_size;
+ uptr len;
+};
+
+// Reads process memory map in an OS-specific way.
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+
+class MemoryMappingLayout {
+ public:
+ explicit MemoryMappingLayout(bool cache_enabled);
+ ~MemoryMappingLayout();
+ bool Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size, uptr *protection);
+ void Reset();
+ // In some cases, e.g. when running under a sandbox on Linux, ASan is unable
+ // to obtain the memory mappings. It should fall back to pre-cached data
+ // instead of aborting.
+ static void CacheMemoryMappings();
+
+ // Stores the list of mapped objects into an array.
+ uptr DumpListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter);
+
+ // Memory protection masks.
+ static const uptr kProtectionRead = 1;
+ static const uptr kProtectionWrite = 2;
+ static const uptr kProtectionExecute = 4;
+ static const uptr kProtectionShared = 8;
+
+ private:
+ void LoadFromCache();
+
+ // FIXME: Hide implementation details for different platforms in
+ // platform-specific files.
+# if SANITIZER_FREEBSD || SANITIZER_LINUX
+ ProcSelfMapsBuff proc_self_maps_;
+ const char *current_;
+
+ // Static mappings cache.
+ static ProcSelfMapsBuff cached_proc_self_maps_;
+ static StaticSpinMutex cache_lock_; // protects cached_proc_self_maps_.
+# elif SANITIZER_MAC
+ template<u32 kLCSegment, typename SegmentCommand>
+ bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection);
+ int current_image_;
+ u32 current_magic_;
+ u32 current_filetype_;
+ int current_load_cmd_count_;
+ char *current_load_cmd_addr_;
+# endif
+};
+
+typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,
+ /*out*/uptr *stats, uptr stats_size);
+
+// Parse the contents of /proc/self/smaps and generate a memory profile.
+// |cb| is a tool-specific callback that fills the |stats| array containing
+// |stats_size| elements.
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size);
+
+// Returns code range for the specified module.
+bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end);
+
+bool IsDecimal(char c);
+uptr ParseDecimal(const char **p);
+bool IsHex(char c);
+uptr ParseHex(const char **p);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_PROCMAPS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc
new file mode 100644
index 000000000000..2ec08d7f127b
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -0,0 +1,178 @@
+//===-- sanitizer_procmaps_common.cc --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (common parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+// Linker initialized.
+ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
+StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
+
+static int TranslateDigit(char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+// Parse a number and promote 'p' up to the first non-digit character.
+static uptr ParseNumber(const char **p, int base) {
+ uptr n = 0;
+ int d;
+ CHECK(base >= 2 && base <= 16);
+ while ((d = TranslateDigit(**p)) >= 0 && d < base) {
+ n = n * base + d;
+ (*p)++;
+ }
+ return n;
+}
+
+bool IsDecimal(char c) {
+ int d = TranslateDigit(c);
+ return d >= 0 && d < 10;
+}
+
+uptr ParseDecimal(const char **p) {
+ return ParseNumber(p, 10);
+}
+
+bool IsHex(char c) {
+ int d = TranslateDigit(c);
+ return d >= 0 && d < 16;
+}
+
+uptr ParseHex(const char **p) {
+ return ParseNumber(p, 16);
+}
+
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
+ ReadProcMaps(&proc_self_maps_);
+ if (cache_enabled) {
+ if (proc_self_maps_.mmaped_size == 0) {
+ LoadFromCache();
+ CHECK_GT(proc_self_maps_.len, 0);
+ }
+ } else {
+ CHECK_GT(proc_self_maps_.mmaped_size, 0);
+ }
+ Reset();
+ // FIXME: in the future we may want to cache the mappings on demand only.
+ if (cache_enabled)
+ CacheMemoryMappings();
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {
+ // Only unmap the buffer if it is different from the cached one. Otherwise
+ // it will be unmapped when the cache is refreshed.
+ if (proc_self_maps_.data != cached_proc_self_maps_.data) {
+ UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
+ }
+}
+
+void MemoryMappingLayout::Reset() {
+ current_ = proc_self_maps_.data;
+}
+
+// static
+void MemoryMappingLayout::CacheMemoryMappings() {
+ SpinMutexLock l(&cache_lock_);
+ // Don't invalidate the cache if the mappings are unavailable.
+ ProcSelfMapsBuff old_proc_self_maps;
+ old_proc_self_maps = cached_proc_self_maps_;
+ ReadProcMaps(&cached_proc_self_maps_);
+ if (cached_proc_self_maps_.mmaped_size == 0) {
+ cached_proc_self_maps_ = old_proc_self_maps;
+ } else {
+ if (old_proc_self_maps.mmaped_size) {
+ UnmapOrDie(old_proc_self_maps.data,
+ old_proc_self_maps.mmaped_size);
+ }
+ }
+}
+
+void MemoryMappingLayout::LoadFromCache() {
+ SpinMutexLock l(&cache_lock_);
+ if (cached_proc_self_maps_.data) {
+ proc_self_maps_ = cached_proc_self_maps_;
+ }
+}
+
+uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
+ uptr max_modules,
+ string_predicate_t filter) {
+ Reset();
+ uptr cur_beg, cur_end, cur_offset, prot;
+ InternalScopedString module_name(kMaxPathLength);
+ uptr n_modules = 0;
+ for (uptr i = 0; n_modules < max_modules &&
+ Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
+ module_name.size(), &prot);
+ i++) {
+ const char *cur_name = module_name.data();
+ if (cur_name[0] == '\0')
+ continue;
+ if (filter && !filter(cur_name))
+ continue;
+ void *mem = &modules[n_modules];
+ // Don't subtract 'cur_beg' from the first entry:
+ // * If a binary is compiled w/o -pie, then the first entry in
+ // process maps is likely the binary itself (all dynamic libs
+ // are mapped higher in address space). For such a binary,
+ // instruction offset in binary coincides with the actual
+ // instruction address in virtual memory (as code section
+ // is mapped to a fixed memory range).
+ // * If a binary is compiled with -pie, all the modules are
+ // mapped high at address space (in particular, higher than
+ // shadow memory of the tool), so the module can't be the
+ // first entry.
+ uptr base_address = (i ? cur_beg : 0) - cur_offset;
+ LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
+ cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ n_modules++;
+ }
+ return n_modules;
+}
+
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
+ char *smaps = 0;
+ uptr smaps_cap = 0;
+ uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
+ &smaps, &smaps_cap, 64<<20);
+ uptr start = 0;
+ bool file = false;
+ const char *pos = smaps;
+ while (pos < smaps + smaps_len) {
+ if (IsHex(pos[0])) {
+ start = ParseHex(&pos);
+ for (; *pos != '/' && *pos > '\n'; pos++) {}
+ file = *pos == '/';
+ } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
+ while (!IsDecimal(*pos)) pos++;
+ uptr rss = ParseDecimal(&pos) * 1024;
+ cb(start, rss, file, stats, stats_size);
+ }
+ while (*pos++ != '\n') {}
+ }
+ UnmapOrDie(smaps, smaps_cap);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
new file mode 100644
index 000000000000..5011b1ff14b2
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
@@ -0,0 +1,88 @@
+//===-- sanitizer_procmaps_freebsd.cc -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (FreeBSD-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD
+#include "sanitizer_common.h"
+#include "sanitizer_freebsd.h"
+#include "sanitizer_procmaps.h"
+
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+# include <osreldate.h>
+# if __FreeBSD_version <= 902001 // v9.2
+# define kinfo_vmentry xkinfo_vmentry
+# endif
+#endif
+
+namespace __sanitizer {
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+ const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
+ size_t Size = 0;
+ int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0);
+ CHECK_EQ(Err, 0);
+ CHECK_GT(Size, 0);
+
+ size_t MmapedSize = Size * 4 / 3;
+ void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
+ Size = MmapedSize;
+ Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0);
+ CHECK_EQ(Err, 0);
+
+ proc_maps->data = (char*)VmMap;
+ proc_maps->mmaped_size = MmapedSize;
+ proc_maps->len = Size;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection) {
+ char *last = proc_self_maps_.data + proc_self_maps_.len;
+ if (current_ >= last) return false;
+ uptr dummy;
+ if (!start) start = &dummy;
+ if (!end) end = &dummy;
+ if (!offset) offset = &dummy;
+ if (!protection) protection = &dummy;
+ struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
+
+ *start = (uptr)VmEntry->kve_start;
+ *end = (uptr)VmEntry->kve_end;
+ *offset = (uptr)VmEntry->kve_offset;
+
+ *protection = 0;
+ if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
+ *protection |= kProtectionRead;
+ if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
+ *protection |= kProtectionWrite;
+ if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
+ *protection |= kProtectionExecute;
+
+ if (filename != NULL && filename_size > 0) {
+ internal_snprintf(filename,
+ Min(filename_size, (uptr)PATH_MAX),
+ "%s", VmEntry->kve_path);
+ }
+
+ current_ += VmEntry->kve_structsize;
+
+ return true;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc
new file mode 100644
index 000000000000..79ca4dfd8fca
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -0,0 +1,90 @@
+//===-- sanitizer_procmaps_linux.cc ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (Linux-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+ proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
+ &proc_maps->mmaped_size, 1 << 26);
+}
+
+static bool IsOneOf(char c, char c1, char c2) {
+ return c == c1 || c == c2;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection) {
+ char *last = proc_self_maps_.data + proc_self_maps_.len;
+ if (current_ >= last) return false;
+ uptr dummy;
+ if (!start) start = &dummy;
+ if (!end) end = &dummy;
+ if (!offset) offset = &dummy;
+ if (!protection) protection = &dummy;
+ char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
+ if (next_line == 0)
+ next_line = last;
+ // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
+ *start = ParseHex(&current_);
+ CHECK_EQ(*current_++, '-');
+ *end = ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ CHECK(IsOneOf(*current_, '-', 'r'));
+ *protection = 0;
+ if (*current_++ == 'r')
+ *protection |= kProtectionRead;
+ CHECK(IsOneOf(*current_, '-', 'w'));
+ if (*current_++ == 'w')
+ *protection |= kProtectionWrite;
+ CHECK(IsOneOf(*current_, '-', 'x'));
+ if (*current_++ == 'x')
+ *protection |= kProtectionExecute;
+ CHECK(IsOneOf(*current_, 's', 'p'));
+ if (*current_++ == 's')
+ *protection |= kProtectionShared;
+ CHECK_EQ(*current_++, ' ');
+ *offset = ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ ParseHex(&current_);
+ CHECK_EQ(*current_++, ':');
+ ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ while (IsDecimal(*current_))
+ current_++;
+ // Qemu may lack the trailing space.
+ // http://code.google.com/p/address-sanitizer/issues/detail?id=160
+ // CHECK_EQ(*current_++, ' ');
+ // Skip spaces.
+ while (current_ < next_line && *current_ == ' ')
+ current_++;
+ // Fill in the filename.
+ uptr i = 0;
+ while (current_ < next_line) {
+ if (filename && i < filename_size - 1)
+ filename[i++] = *current_;
+ current_++;
+ }
+ if (filename && i < filename_size)
+ filename[i] = 0;
+ current_ = next_line + 1;
+ return true;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc
new file mode 100644
index 000000000000..c0a86149788c
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -0,0 +1,190 @@
+//===-- sanitizer_procmaps_mac.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (Mac-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+
+namespace __sanitizer {
+
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
+ Reset();
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {
+}
+
+// More information about Mach-O headers can be found in mach-o/loader.h
+// Each Mach-O image has a header (mach_header or mach_header_64) starting with
+// a magic number, and a list of linker load commands directly following the
+// header.
+// A load command is at least two 32-bit words: the command type and the
+// command size in bytes. We're interested only in segment load commands
+// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
+// into the task's address space.
+// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
+// segment_command_64 correspond to the memory address, memory size and the
+// file offset of the current memory segment.
+// Because these fields are taken from the images as is, one needs to add
+// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
+
+void MemoryMappingLayout::Reset() {
+ // Count down from the top.
+ // TODO(glider): as per man 3 dyld, iterating over the headers with
+ // _dyld_image_count is thread-unsafe. We need to register callbacks for
+ // adding and removing images which will invalidate the MemoryMappingLayout
+ // state.
+ current_image_ = _dyld_image_count();
+ current_load_cmd_count_ = -1;
+ current_load_cmd_addr_ = 0;
+ current_magic_ = 0;
+ current_filetype_ = 0;
+}
+
+// static
+void MemoryMappingLayout::CacheMemoryMappings() {
+ // No-op on Mac for now.
+}
+
+void MemoryMappingLayout::LoadFromCache() {
+ // No-op on Mac for now.
+}
+
+// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
+// Google Perftools, http://code.google.com/p/google-perftools.
+
+// NextSegmentLoad scans the current image for the next segment load command
+// and returns the start and end addresses and file offset of the corresponding
+// segment.
+// Note that the segment addresses are not necessarily sorted.
+template<u32 kLCSegment, typename SegmentCommand>
+bool MemoryMappingLayout::NextSegmentLoad(
+ uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size, uptr *protection) {
+ const char* lc = current_load_cmd_addr_;
+ current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
+ if (((const load_command *)lc)->cmd == kLCSegment) {
+ const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
+ const SegmentCommand* sc = (const SegmentCommand *)lc;
+ if (start) *start = sc->vmaddr + dlloff;
+ if (protection) {
+ // Return the initial protection.
+ *protection = sc->initprot;
+ }
+ if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
+ if (offset) {
+ if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
+ *offset = sc->vmaddr;
+ } else {
+ *offset = sc->fileoff;
+ }
+ }
+ if (filename) {
+ internal_strncpy(filename, _dyld_get_image_name(current_image_),
+ filename_size);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection) {
+ for (; current_image_ >= 0; current_image_--) {
+ const mach_header* hdr = _dyld_get_image_header(current_image_);
+ if (!hdr) continue;
+ if (current_load_cmd_count_ < 0) {
+ // Set up for this image;
+ current_load_cmd_count_ = hdr->ncmds;
+ current_magic_ = hdr->magic;
+ current_filetype_ = hdr->filetype;
+ switch (current_magic_) {
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+
+ for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
+ switch (current_magic_) {
+ // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
+ start, end, offset, filename, filename_size, protection))
+ return true;
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
+ start, end, offset, filename, filename_size, protection))
+ return true;
+ break;
+ }
+ }
+ }
+ // If we get here, no more load_cmd's in this image talk about
+ // segments. Go on to the next image.
+ }
+ return false;
+}
+
+uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
+ uptr max_modules,
+ string_predicate_t filter) {
+ Reset();
+ uptr cur_beg, cur_end, prot;
+ InternalScopedString module_name(kMaxPathLength);
+ uptr n_modules = 0;
+ for (uptr i = 0; n_modules < max_modules &&
+ Next(&cur_beg, &cur_end, 0, module_name.data(),
+ module_name.size(), &prot);
+ i++) {
+ const char *cur_name = module_name.data();
+ if (cur_name[0] == '\0')
+ continue;
+ if (filter && !filter(cur_name))
+ continue;
+ LoadedModule *cur_module = 0;
+ if (n_modules > 0 &&
+ 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
+ cur_module = &modules[n_modules - 1];
+ } else {
+ void *mem = &modules[n_modules];
+ cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+ n_modules++;
+ }
+ cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ }
+ return n_modules;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h
new file mode 100644
index 000000000000..404d3753f7e9
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h
@@ -0,0 +1,185 @@
+//===-- sanitizer_quarantine.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Memory quarantine for AddressSanitizer and potentially other tools.
+// Quarantine caches some specified amount of memory in per-thread caches,
+// then evicts to global FIFO queue. When the queue reaches specified threshold,
+// oldest memory is recycled.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_QUARANTINE_H
+#define SANITIZER_QUARANTINE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_list.h"
+
+namespace __sanitizer {
+
+template<typename Node> class QuarantineCache;
+
+struct QuarantineBatch {
+ static const uptr kSize = 1021;
+ QuarantineBatch *next;
+ uptr size;
+ uptr count;
+ void *batch[kSize];
+};
+
+COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb.
+
+// The callback interface is:
+// void Callback::Recycle(Node *ptr);
+// void *cb.Allocate(uptr size);
+// void cb.Deallocate(void *ptr);
+template<typename Callback, typename Node>
+class Quarantine {
+ public:
+ typedef QuarantineCache<Callback> Cache;
+
+ explicit Quarantine(LinkerInitialized)
+ : cache_(LINKER_INITIALIZED) {
+ }
+
+ void Init(uptr size, uptr cache_size) {
+ atomic_store(&max_size_, size, memory_order_release);
+ atomic_store(&min_size_, size / 10 * 9,
+ memory_order_release); // 90% of max size.
+ max_cache_size_ = cache_size;
+ }
+
+ uptr GetSize() const { return atomic_load(&max_size_, memory_order_acquire); }
+
+ void Put(Cache *c, Callback cb, Node *ptr, uptr size) {
+ c->Enqueue(cb, ptr, size);
+ if (c->Size() > max_cache_size_)
+ Drain(c, cb);
+ }
+
+ void NOINLINE Drain(Cache *c, Callback cb) {
+ {
+ SpinMutexLock l(&cache_mutex_);
+ cache_.Transfer(c);
+ }
+ if (cache_.Size() > GetSize() && recycle_mutex_.TryLock())
+ Recycle(cb);
+ }
+
+ private:
+ // Read-only data.
+ char pad0_[kCacheLineSize];
+ atomic_uintptr_t max_size_;
+ atomic_uintptr_t min_size_;
+ uptr max_cache_size_;
+ char pad1_[kCacheLineSize];
+ SpinMutex cache_mutex_;
+ SpinMutex recycle_mutex_;
+ Cache cache_;
+ char pad2_[kCacheLineSize];
+
+ void NOINLINE Recycle(Callback cb) {
+ Cache tmp;
+ uptr min_size = atomic_load(&min_size_, memory_order_acquire);
+ {
+ SpinMutexLock l(&cache_mutex_);
+ while (cache_.Size() > min_size) {
+ QuarantineBatch *b = cache_.DequeueBatch();
+ tmp.EnqueueBatch(b);
+ }
+ }
+ recycle_mutex_.Unlock();
+ DoRecycle(&tmp, cb);
+ }
+
+ void NOINLINE DoRecycle(Cache *c, Callback cb) {
+ while (QuarantineBatch *b = c->DequeueBatch()) {
+ const uptr kPrefetch = 16;
+ for (uptr i = 0; i < kPrefetch; i++)
+ PREFETCH(b->batch[i]);
+ for (uptr i = 0; i < b->count; i++) {
+ PREFETCH(b->batch[i + kPrefetch]);
+ cb.Recycle((Node*)b->batch[i]);
+ }
+ cb.Deallocate(b);
+ }
+ }
+};
+
+// Per-thread cache of memory blocks.
+template<typename Callback>
+class QuarantineCache {
+ public:
+ explicit QuarantineCache(LinkerInitialized) {
+ }
+
+ QuarantineCache()
+ : size_() {
+ list_.clear();
+ }
+
+ uptr Size() const {
+ return atomic_load(&size_, memory_order_relaxed);
+ }
+
+ void Enqueue(Callback cb, void *ptr, uptr size) {
+ if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) {
+ AllocBatch(cb);
+ size += sizeof(QuarantineBatch); // Count the batch in Quarantine size.
+ }
+ QuarantineBatch *b = list_.back();
+ CHECK(b);
+ b->batch[b->count++] = ptr;
+ b->size += size;
+ SizeAdd(size);
+ }
+
+ void Transfer(QuarantineCache *c) {
+ list_.append_back(&c->list_);
+ SizeAdd(c->Size());
+ atomic_store(&c->size_, 0, memory_order_relaxed);
+ }
+
+ void EnqueueBatch(QuarantineBatch *b) {
+ list_.push_back(b);
+ SizeAdd(b->size);
+ }
+
+ QuarantineBatch *DequeueBatch() {
+ if (list_.empty())
+ return 0;
+ QuarantineBatch *b = list_.front();
+ list_.pop_front();
+ SizeSub(b->size);
+ return b;
+ }
+
+ private:
+ IntrusiveList<QuarantineBatch> list_;
+ atomic_uintptr_t size_;
+
+ void SizeAdd(uptr add) {
+ atomic_store(&size_, Size() + add, memory_order_relaxed);
+ }
+ void SizeSub(uptr sub) {
+ atomic_store(&size_, Size() - sub, memory_order_relaxed);
+ }
+
+ NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
+ QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
+ CHECK(b);
+ b->count = 0;
+ b->size = 0;
+ list_.push_back(b);
+ return b;
+ }
+};
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_QUARANTINE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h
new file mode 100644
index 000000000000..86536aa19658
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h
@@ -0,0 +1,47 @@
+//===-- sanitizer_report_decorator.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tags to decorate the sanitizer reports.
+// Currently supported tags:
+// * None.
+// * ANSI color sequences.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_REPORT_DECORATOR_H
+#define SANITIZER_REPORT_DECORATOR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+class SanitizerCommonDecorator {
+ // FIXME: This is not portable. It assumes the special strings are printed to
+ // stdout, which is not the case on Windows (see SetConsoleTextAttribute()).
+ public:
+ SanitizerCommonDecorator() : ansi_(ColorizeReports()) {}
+ const char *Bold() const { return ansi_ ? "\033[1m" : ""; }
+ const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; }
+ const char *Warning() { return Red(); }
+ const char *EndWarning() { return Default(); }
+ protected:
+ const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; }
+ const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; }
+ const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; }
+ const char *Yellow() const { return ansi_ ? "\033[1m\033[33m" : ""; }
+ const char *Blue() const { return ansi_ ? "\033[1m\033[34m" : ""; }
+ const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; }
+ const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; }
+ const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; }
+ private:
+ bool ansi_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_REPORT_DECORATOR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc
new file mode 100644
index 000000000000..59b53f4dcd84
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc
@@ -0,0 +1,163 @@
+//===-- sanitizer_stackdepot.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_stackdepot.h"
+
+#include "sanitizer_common.h"
+#include "sanitizer_stackdepotbase.h"
+
+namespace __sanitizer {
+
+struct StackDepotNode {
+ StackDepotNode *link;
+ u32 id;
+ atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20;
+ u32 size;
+ u32 tag;
+ uptr stack[1]; // [size]
+
+ static const u32 kTabSizeLog = 20;
+ // Lower kTabSizeLog bits are equal for all items in one bucket.
+ // We use these bits to store the per-stack use counter.
+ static const u32 kUseCountBits = kTabSizeLog;
+ static const u32 kMaxUseCount = 1 << kUseCountBits;
+ static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
+ static const u32 kHashMask = ~kUseCountMask;
+
+ typedef StackTrace args_type;
+ bool eq(u32 hash, const args_type &args) const {
+ u32 hash_bits =
+ atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask;
+ if ((hash & kHashMask) != hash_bits || args.size != size || args.tag != tag)
+ return false;
+ uptr i = 0;
+ for (; i < size; i++) {
+ if (stack[i] != args.trace[i]) return false;
+ }
+ return true;
+ }
+ static uptr storage_size(const args_type &args) {
+ return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
+ }
+ static u32 hash(const args_type &args) {
+ // murmur2
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed ^ (args.size * sizeof(uptr));
+ for (uptr i = 0; i < args.size; i++) {
+ u32 k = args.trace[i];
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ }
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+ }
+ static bool is_valid(const args_type &args) {
+ return args.size > 0 && args.trace;
+ }
+ void store(const args_type &args, u32 hash) {
+ atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed);
+ size = args.size;
+ tag = args.tag;
+ internal_memcpy(stack, args.trace, size * sizeof(uptr));
+ }
+ args_type load() const {
+ return args_type(&stack[0], size, tag);
+ }
+ StackDepotHandle get_handle() { return StackDepotHandle(this); }
+
+ typedef StackDepotHandle handle_type;
+};
+
+COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount);
+
+u32 StackDepotHandle::id() { return node_->id; }
+int StackDepotHandle::use_count() {
+ return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) &
+ StackDepotNode::kUseCountMask;
+}
+void StackDepotHandle::inc_use_count_unsafe() {
+ u32 prev =
+ atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) &
+ StackDepotNode::kUseCountMask;
+ CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount);
+}
+
+// FIXME(dvyukov): this single reserved bit is used in TSan.
+typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog>
+ StackDepot;
+static StackDepot theDepot;
+
+StackDepotStats *StackDepotGetStats() {
+ return theDepot.GetStats();
+}
+
+u32 StackDepotPut(StackTrace stack) {
+ StackDepotHandle h = theDepot.Put(stack);
+ return h.valid() ? h.id() : 0;
+}
+
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) {
+ return theDepot.Put(stack);
+}
+
+StackTrace StackDepotGet(u32 id) {
+ return theDepot.Get(id);
+}
+
+void StackDepotLockAll() {
+ theDepot.LockAll();
+}
+
+void StackDepotUnlockAll() {
+ theDepot.UnlockAll();
+}
+
+bool StackDepotReverseMap::IdDescPair::IdComparator(
+ const StackDepotReverseMap::IdDescPair &a,
+ const StackDepotReverseMap::IdDescPair &b) {
+ return a.id < b.id;
+}
+
+StackDepotReverseMap::StackDepotReverseMap()
+ : map_(StackDepotGetStats()->n_uniq_ids + 100) {
+ for (int idx = 0; idx < StackDepot::kTabSize; idx++) {
+ atomic_uintptr_t *p = &theDepot.tab[idx];
+ uptr v = atomic_load(p, memory_order_consume);
+ StackDepotNode *s = (StackDepotNode*)(v & ~1);
+ for (; s; s = s->link) {
+ IdDescPair pair = {s->id, s};
+ map_.push_back(pair);
+ }
+ }
+ InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
+}
+
+StackTrace StackDepotReverseMap::Get(u32 id) {
+ if (!map_.size())
+ return StackTrace();
+ IdDescPair pair = {id, 0};
+ uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
+ IdDescPair::IdComparator);
+ if (idx > map_.size())
+ return StackTrace();
+ return map_[idx].desc->load();
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
new file mode 100644
index 000000000000..5e3a8b783ac7
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -0,0 +1,71 @@
+//===-- sanitizer_stackdepot.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKDEPOT_H
+#define SANITIZER_STACKDEPOT_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_stacktrace.h"
+
+namespace __sanitizer {
+
+// StackDepot efficiently stores huge amounts of stack traces.
+struct StackDepotNode;
+struct StackDepotHandle {
+ StackDepotNode *node_;
+ StackDepotHandle() : node_(0) {}
+ explicit StackDepotHandle(StackDepotNode *node) : node_(node) {}
+ bool valid() { return node_; }
+ u32 id();
+ int use_count();
+ void inc_use_count_unsafe();
+};
+
+const int kStackDepotMaxUseCount = 1U << 20;
+
+StackDepotStats *StackDepotGetStats();
+u32 StackDepotPut(StackTrace stack);
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack);
+// Retrieves a stored stack trace by the id.
+StackTrace StackDepotGet(u32 id);
+
+void StackDepotLockAll();
+void StackDepotUnlockAll();
+
+// Instantiating this class creates a snapshot of StackDepot which can be
+// efficiently queried with StackDepotGet(). You can use it concurrently with
+// StackDepot, but the snapshot is only guaranteed to contain those stack traces
+// which were stored before it was instantiated.
+class StackDepotReverseMap {
+ public:
+ StackDepotReverseMap();
+ StackTrace Get(u32 id);
+
+ private:
+ struct IdDescPair {
+ u32 id;
+ StackDepotNode *desc;
+
+ static bool IdComparator(const IdDescPair &a, const IdDescPair &b);
+ };
+
+ InternalMmapVector<IdDescPair> map_;
+
+ // Disallow evil constructors.
+ StackDepotReverseMap(const StackDepotReverseMap&);
+ void operator=(const StackDepotReverseMap&);
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_STACKDEPOT_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
new file mode 100644
index 000000000000..5de2e711fe45
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
@@ -0,0 +1,176 @@
+//===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of a mapping from arbitrary values to unique 32-bit
+// identifiers.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKDEPOTBASE_H
+#define SANITIZER_STACKDEPOTBASE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_persistent_allocator.h"
+
+namespace __sanitizer {
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+class StackDepotBase {
+ public:
+ typedef typename Node::args_type args_type;
+ typedef typename Node::handle_type handle_type;
+ // Maps stack trace to an unique id.
+ handle_type Put(args_type args, bool *inserted = 0);
+ // Retrieves a stored stack trace by the id.
+ args_type Get(u32 id);
+
+ StackDepotStats *GetStats() { return &stats; }
+
+ void LockAll();
+ void UnlockAll();
+
+ private:
+ static Node *find(Node *s, args_type args, u32 hash);
+ static Node *lock(atomic_uintptr_t *p);
+ static void unlock(atomic_uintptr_t *p, Node *s);
+
+ static const int kTabSize = 1 << kTabSizeLog; // Hash table size.
+ static const int kPartBits = 8;
+ static const int kPartShift = sizeof(u32) * 8 - kPartBits - kReservedBits;
+ static const int kPartCount =
+ 1 << kPartBits; // Number of subparts in the table.
+ static const int kPartSize = kTabSize / kPartCount;
+ static const int kMaxId = 1 << kPartShift;
+
+ atomic_uintptr_t tab[kTabSize]; // Hash table of Node's.
+ atomic_uint32_t seq[kPartCount]; // Unique id generators.
+
+ StackDepotStats stats;
+
+ friend class StackDepotReverseMap;
+};
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s,
+ args_type args,
+ u32 hash) {
+ // Searches linked list s for the stack, returns its id.
+ for (; s; s = s->link) {
+ if (s->eq(hash, args)) {
+ return s;
+ }
+ }
+ return 0;
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock(
+ atomic_uintptr_t *p) {
+ // Uses the pointer lsb as mutex.
+ for (int i = 0;; i++) {
+ uptr cmp = atomic_load(p, memory_order_relaxed);
+ if ((cmp & 1) == 0 &&
+ atomic_compare_exchange_weak(p, &cmp, cmp | 1, memory_order_acquire))
+ return (Node *)cmp;
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ }
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock(
+ atomic_uintptr_t *p, Node *s) {
+ DCHECK_EQ((uptr)s & 1, 0);
+ atomic_store(p, (uptr)s, memory_order_release);
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type
+StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args,
+ bool *inserted) {
+ if (inserted) *inserted = false;
+ if (!Node::is_valid(args)) return handle_type();
+ uptr h = Node::hash(args);
+ atomic_uintptr_t *p = &tab[h % kTabSize];
+ uptr v = atomic_load(p, memory_order_consume);
+ Node *s = (Node *)(v & ~1);
+ // First, try to find the existing stack.
+ Node *node = find(s, args, h);
+ if (node) return node->get_handle();
+ // If failed, lock, retry and insert new.
+ Node *s2 = lock(p);
+ if (s2 != s) {
+ node = find(s2, args, h);
+ if (node) {
+ unlock(p, s2);
+ return node->get_handle();
+ }
+ }
+ uptr part = (h % kTabSize) / kPartSize;
+ u32 id = atomic_fetch_add(&seq[part], 1, memory_order_relaxed) + 1;
+ stats.n_uniq_ids++;
+ CHECK_LT(id, kMaxId);
+ id |= part << kPartShift;
+ CHECK_NE(id, 0);
+ CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
+ uptr memsz = Node::storage_size(args);
+ s = (Node *)PersistentAlloc(memsz);
+ stats.allocated += memsz;
+ s->id = id;
+ s->store(args, h);
+ s->link = s2;
+ unlock(p, s);
+ if (inserted) *inserted = true;
+ return s->get_handle();
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type
+StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) {
+ if (id == 0) {
+ return args_type();
+ }
+ CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
+ // High kPartBits contain part id, so we need to scan at most kPartSize lists.
+ uptr part = id >> kPartShift;
+ for (int i = 0; i != kPartSize; i++) {
+ uptr idx = part * kPartSize + i;
+ CHECK_LT(idx, kTabSize);
+ atomic_uintptr_t *p = &tab[idx];
+ uptr v = atomic_load(p, memory_order_consume);
+ Node *s = (Node *)(v & ~1);
+ for (; s; s = s->link) {
+ if (s->id == id) {
+ return s->load();
+ }
+ }
+ }
+ return args_type();
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() {
+ for (int i = 0; i < kTabSize; ++i) {
+ lock(&tab[i]);
+ }
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
+ for (int i = 0; i < kTabSize; ++i) {
+ atomic_uintptr_t *p = &tab[i];
+ uptr s = atomic_load(p, memory_order_relaxed);
+ unlock(p, (Node *)(s & ~1UL));
+ }
+}
+
+} // namespace __sanitizer
+#endif // SANITIZER_STACKDEPOTBASE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc
new file mode 100644
index 000000000000..2deadb6e3560
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -0,0 +1,116 @@
+//===-- sanitizer_stacktrace.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_stacktrace.h"
+
+namespace __sanitizer {
+
+uptr StackTrace::GetNextInstructionPc(uptr pc) {
+#if defined(__mips__)
+ return pc + 8;
+#else
+ return pc + 1;
+#endif
+}
+
+uptr StackTrace::GetCurrentPc() {
+ return GET_CALLER_PC();
+}
+
+void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+ size = cnt + !!extra_top_pc;
+ CHECK_LE(size, kStackTraceMax);
+ internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+ if (extra_top_pc)
+ trace_buffer[cnt] = extra_top_pc;
+ top_frame_bp = 0;
+}
+
+// Check if given pointer points into allocated stack area.
+static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
+ return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
+}
+
+// In GCC on ARM bp points to saved lr, not fp, so we should check the next
+// cell in stack to be a saved frame pointer. GetCanonicFrame returns the
+// pointer to saved frame pointer in any case.
+static inline uhwptr *GetCanonicFrame(uptr bp,
+ uptr stack_top,
+ uptr stack_bottom) {
+#ifdef __arm__
+ if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0;
+ uhwptr *bp_prev = (uhwptr *)bp;
+ if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev;
+ // The next frame pointer does not look right. This could be a GCC frame, step
+ // back by 1 word and try again.
+ if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom))
+ return bp_prev - 1;
+ // Nope, this does not look right either. This means the frame after next does
+ // not have a valid frame pointer, but we can still extract the caller PC.
+ // Unfortunately, there is no way to decide between GCC and LLVM frame
+ // layouts. Assume LLVM.
+ return bp_prev;
+#else
+ return (uhwptr*)bp;
+#endif
+}
+
+void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
+ uptr stack_bottom, u32 max_depth) {
+ CHECK_GE(max_depth, 2);
+ trace_buffer[0] = pc;
+ size = 1;
+ if (stack_top < 4096) return; // Sanity check for stack top.
+ uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom);
+ // Lowest possible address that makes sense as the next frame pointer.
+ // Goes up as we walk the stack.
+ uptr bottom = stack_bottom;
+ // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
+ while (IsValidFrame((uptr)frame, stack_top, bottom) &&
+ IsAligned((uptr)frame, sizeof(*frame)) &&
+ size < max_depth) {
+ uhwptr pc1 = frame[1];
+ if (pc1 != pc) {
+ trace_buffer[size++] = (uptr) pc1;
+ }
+ bottom = (uptr)frame;
+ frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom);
+ }
+}
+
+static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
+ return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
+}
+
+void BufferedStackTrace::PopStackFrames(uptr count) {
+ CHECK_LT(count, size);
+ size -= count;
+ for (uptr i = 0; i < size; ++i) {
+ trace_buffer[i] = trace_buffer[i + count];
+ }
+}
+
+uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
+ // Use threshold to find PC in stack trace, as PC we want to unwind from may
+ // slightly differ from return address in the actual unwinded stack trace.
+ const int kPcThreshold = 304;
+ for (uptr i = 0; i < size; ++i) {
+ if (MatchPc(pc, trace[i], kPcThreshold))
+ return i;
+ }
+ return 0;
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
new file mode 100644
index 000000000000..6c3a1511f337
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -0,0 +1,138 @@
+//===-- sanitizer_stacktrace.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKTRACE_H
+#define SANITIZER_STACKTRACE_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+static const u32 kStackTraceMax = 256;
+
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \
+ defined(__powerpc64__) || defined(__sparc__) || \
+ defined(__mips__))
+# define SANITIZER_CAN_FAST_UNWIND 0
+#elif SANITIZER_WINDOWS
+# define SANITIZER_CAN_FAST_UNWIND 0
+#else
+# define SANITIZER_CAN_FAST_UNWIND 1
+#endif
+
+// Fast unwind is the only option on Mac for now; we will need to
+// revisit this macro when slow unwind works on Mac, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+#if SANITIZER_MAC
+# define SANITIZER_CAN_SLOW_UNWIND 0
+#else
+# define SANITIZER_CAN_SLOW_UNWIND 1
+#endif
+
+struct StackTrace {
+ const uptr *trace;
+ u32 size;
+ u32 tag;
+
+ static const int TAG_UNKNOWN = 0;
+ static const int TAG_ALLOC = 1;
+ static const int TAG_DEALLOC = 2;
+ static const int TAG_CUSTOM = 100; // Tool specific tags start here.
+
+ StackTrace() : trace(nullptr), size(0), tag(0) {}
+ StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {}
+ StackTrace(const uptr *trace, u32 size, u32 tag)
+ : trace(trace), size(size), tag(tag) {}
+
+ // Prints a symbolized stacktrace, followed by an empty line.
+ void Print() const;
+
+ static bool WillUseFastUnwind(bool request_fast_unwind) {
+ if (!SANITIZER_CAN_FAST_UNWIND)
+ return false;
+ else if (!SANITIZER_CAN_SLOW_UNWIND)
+ return true;
+ return request_fast_unwind;
+ }
+
+ static uptr GetCurrentPc();
+ static inline uptr GetPreviousInstructionPc(uptr pc);
+ static uptr GetNextInstructionPc(uptr pc);
+ typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
+ int out_size);
+};
+
+// Performance-critical, must be in the header.
+ALWAYS_INLINE
+uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
+#if defined(__arm__)
+ // Cancel Thumb bit.
+ pc = pc & (~1);
+#endif
+#if defined(__powerpc__) || defined(__powerpc64__)
+ // PCs are always 4 byte aligned.
+ return pc - 4;
+#elif defined(__sparc__) || defined(__mips__)
+ return pc - 8;
+#else
+ return pc - 1;
+#endif
+}
+
+// StackTrace that owns the buffer used to store the addresses.
+struct BufferedStackTrace : public StackTrace {
+ uptr trace_buffer[kStackTraceMax];
+ uptr top_frame_bp; // Optional bp of a top frame.
+
+ BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {}
+
+ void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+ void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
+ uptr stack_bottom, bool request_fast_unwind);
+
+ private:
+ void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
+ u32 max_depth);
+ void SlowUnwindStack(uptr pc, u32 max_depth);
+ void SlowUnwindStackWithContext(uptr pc, void *context,
+ u32 max_depth);
+ void PopStackFrames(uptr count);
+ uptr LocatePcInTrace(uptr pc);
+
+ BufferedStackTrace(const BufferedStackTrace &);
+ void operator=(const BufferedStackTrace &);
+};
+
+} // namespace __sanitizer
+
+// Use this macro if you want to print stack trace with the caller
+// of the current function in the top frame.
+#define GET_CALLER_PC_BP_SP \
+ uptr bp = GET_CURRENT_FRAME(); \
+ uptr pc = GET_CALLER_PC(); \
+ uptr local_stack; \
+ uptr sp = (uptr)&local_stack
+
+#define GET_CALLER_PC_BP \
+ uptr bp = GET_CURRENT_FRAME(); \
+ uptr pc = GET_CALLER_PC();
+
+// Use this macro if you want to print stack trace with the current
+// function in the top frame.
+#define GET_CURRENT_PC_BP_SP \
+ uptr bp = GET_CURRENT_FRAME(); \
+ uptr pc = StackTrace::GetCurrentPc(); \
+ uptr local_stack; \
+ uptr sp = (uptr)&local_stack
+
+
+#endif // SANITIZER_STACKTRACE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
new file mode 100644
index 000000000000..0f98c7d5af4c
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -0,0 +1,71 @@
+//===-- sanitizer_stacktrace_libcdep.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+void StackTrace::Print() const {
+ if (trace == nullptr || size == 0) {
+ Printf(" <empty stack>\n\n");
+ return;
+ }
+ InternalScopedString frame_desc(GetPageSizeCached() * 2);
+ uptr frame_num = 0;
+ for (uptr i = 0; i < size && trace[i]; i++) {
+ // PCs in stack traces are actually the return addresses, that is,
+ // addresses of the next instructions after the call.
+ uptr pc = GetPreviousInstructionPc(trace[i]);
+ SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
+ CHECK(frames);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ frame_desc.clear();
+ RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
+ cur->info, common_flags()->strip_path_prefix);
+ Printf("%s\n", frame_desc.data());
+ }
+ frames->ClearAll();
+ }
+ // Always print a trailing empty line after stack trace.
+ Printf("\n");
+}
+
+void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
+ uptr stack_top, uptr stack_bottom,
+ bool request_fast_unwind) {
+ top_frame_bp = (max_depth > 0) ? bp : 0;
+ // Avoid doing any work for small max_depth.
+ if (max_depth == 0) {
+ size = 0;
+ return;
+ }
+ if (max_depth == 1) {
+ size = 1;
+ trace_buffer[0] = pc;
+ return;
+ }
+ if (!WillUseFastUnwind(request_fast_unwind)) {
+ if (context)
+ SlowUnwindStackWithContext(pc, context, max_depth);
+ else
+ SlowUnwindStack(pc, max_depth);
+ } else {
+ FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+ }
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
new file mode 100644
index 000000000000..7b37dbcf3860
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
@@ -0,0 +1,132 @@
+//===-- sanitizer_common.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 shared between sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_stacktrace_printer.h"
+
+namespace __sanitizer {
+
+static const char *StripFunctionName(const char *function, const char *prefix) {
+ if (function == 0) return 0;
+ if (prefix == 0) return function;
+ uptr prefix_len = internal_strlen(prefix);
+ if (0 == internal_strncmp(function, prefix, prefix_len))
+ return function + prefix_len;
+ return function;
+}
+
+static const char kDefaultFormat[] = " #%n %p %F %L";
+
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+ const AddressInfo &info, const char *strip_path_prefix,
+ const char *strip_func_prefix) {
+ if (0 == internal_strcmp(format, "DEFAULT"))
+ format = kDefaultFormat;
+ for (const char *p = format; *p != '\0'; p++) {
+ if (*p != '%') {
+ buffer->append("%c", *p);
+ continue;
+ }
+ p++;
+ switch (*p) {
+ case '%':
+ buffer->append("%%");
+ break;
+ // Frame number and all fields of AddressInfo structure.
+ case 'n':
+ buffer->append("%zu", frame_no);
+ break;
+ case 'p':
+ buffer->append("0x%zx", info.address);
+ break;
+ case 'm':
+ buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
+ break;
+ case 'o':
+ buffer->append("0x%zx", info.module_offset);
+ break;
+ case 'f':
+ buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
+ break;
+ case 'q':
+ buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
+ ? info.function_offset
+ : 0x0);
+ break;
+ case 's':
+ buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
+ break;
+ case 'l':
+ buffer->append("%d", info.line);
+ break;
+ case 'c':
+ buffer->append("%d", info.column);
+ break;
+ // Smarter special cases.
+ case 'F':
+ // Function name and offset, if file is unknown.
+ if (info.function) {
+ buffer->append("in %s",
+ StripFunctionName(info.function, strip_func_prefix));
+ if (!info.file && info.function_offset != AddressInfo::kUnknown)
+ buffer->append("+0x%zx", info.function_offset);
+ }
+ break;
+ case 'S':
+ // File/line information.
+ RenderSourceLocation(buffer, info.file, info.line, info.column,
+ strip_path_prefix);
+ break;
+ case 'L':
+ // Source location, or module location.
+ if (info.file) {
+ RenderSourceLocation(buffer, info.file, info.line, info.column,
+ strip_path_prefix);
+ } else if (info.module) {
+ RenderModuleLocation(buffer, info.module, info.module_offset,
+ strip_path_prefix);
+ } else {
+ buffer->append("(<unknown module>)");
+ }
+ break;
+ case 'M':
+ // Module basename and offset, or PC.
+ if (info.module)
+ buffer->append("(%s+%p)", StripModuleName(info.module),
+ (void *)info.module_offset);
+ else
+ buffer->append("(%p)", (void *)info.address);
+ break;
+ default:
+ Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n",
+ *p, *p);
+ Die();
+ }
+ }
+}
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+ int line, int column, const char *strip_path_prefix) {
+ buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
+ if (line > 0) {
+ buffer->append(":%d", line);
+ if (column > 0)
+ buffer->append(":%d", column);
+ }
+}
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+ uptr offset, const char *strip_path_prefix) {
+ buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
+ offset);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
new file mode 100644
index 000000000000..93569882ba9d
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -0,0 +1,62 @@
+//===-- sanitizer_stacktrace_printer.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 shared between sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKTRACE_PRINTER_H
+#define SANITIZER_STACKTRACE_PRINTER_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// Render the contents of "info" structure, which represents the contents of
+// stack frame "frame_no" and appends it to the "buffer". "format" is a
+// string with placeholders, which is copied to the output with
+// placeholders substituted with the contents of "info". For example,
+// format string
+// " frame %n: function %F at %S"
+// will be turned into
+// " frame 10: function foo::bar() at my/file.cc:10"
+// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
+// source files and modules, and "strip_func_prefix" to strip prefixes of
+// function names.
+// Here's the full list of available placeholders:
+// %% - represents a '%' character;
+// %n - frame number (copy of frame_no);
+// %p - PC in hex format;
+// %m - path to module (binary or shared object);
+// %o - offset in the module in hex format;
+// %f - function name;
+// %q - offset in the function in hex format (*if available*);
+// %s - path to source file;
+// %l - line in the source file;
+// %c - column in the source file;
+// %F - if function is known to be <foo>, prints "in <foo>", possibly
+// followed by the offset in this function, but only if source file
+// is unknown;
+// %S - prints file/line/column information;
+// %L - prints location information: file/line/column, if it is known, or
+// module+offset if it is known, or (<unknown module>) string.
+// %M - prints module basename and offset, if it is known, or PC.
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+ const AddressInfo &info, const char *strip_path_prefix = "",
+ const char *strip_func_prefix = "");
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+ int line, int column, const char *strip_path_prefix);
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+ uptr offset, const char *strip_path_prefix);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_STACKTRACE_PRINTER_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h
new file mode 100644
index 000000000000..a32646708d45
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h
@@ -0,0 +1,68 @@
+//===-- sanitizer_stoptheworld.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the StopTheWorld function which suspends the execution of the current
+// process and runs the user-supplied callback in the same address space.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STOPTHEWORLD_H
+#define SANITIZER_STOPTHEWORLD_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+typedef int SuspendedThreadID;
+
+// Holds the list of suspended threads and provides an interface to dump their
+// register contexts.
+class SuspendedThreadsList {
+ public:
+ SuspendedThreadsList()
+ : thread_ids_(1024) {}
+ SuspendedThreadID GetThreadID(uptr index) const {
+ CHECK_LT(index, thread_ids_.size());
+ return thread_ids_[index];
+ }
+ int GetRegistersAndSP(uptr index, uptr *buffer, uptr *sp) const;
+ // The buffer in GetRegistersAndSP should be at least this big.
+ static uptr RegisterCount();
+ uptr thread_count() const { return thread_ids_.size(); }
+ bool Contains(SuspendedThreadID thread_id) const {
+ for (uptr i = 0; i < thread_ids_.size(); i++) {
+ if (thread_ids_[i] == thread_id)
+ return true;
+ }
+ return false;
+ }
+ void Append(SuspendedThreadID thread_id) {
+ thread_ids_.push_back(thread_id);
+ }
+
+ private:
+ InternalMmapVector<SuspendedThreadID> thread_ids_;
+
+ // Prohibit copy and assign.
+ SuspendedThreadsList(const SuspendedThreadsList&);
+ void operator=(const SuspendedThreadsList&);
+};
+
+typedef void (*StopTheWorldCallback)(
+ const SuspendedThreadsList &suspended_threads_list,
+ void *argument);
+
+// Suspend all threads in the current process and run the callback on the list
+// of suspended threads. This function will resume the threads before returning.
+// The callback should not call any libc functions.
+// This function should NOT be called from multiple threads simultaneously.
+void StopTheWorld(StopTheWorldCallback callback, void *argument);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_STOPTHEWORLD_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
new file mode 100644
index 000000000000..ad20e39556d8
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -0,0 +1,468 @@
+//===-- sanitizer_stoptheworld_linux_libcdep.cc ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See sanitizer_stoptheworld.h for details.
+// This implementation was inspired by Markus Gutschke's linuxthreads.cc.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
+
+#include "sanitizer_stoptheworld.h"
+
+#include "sanitizer_platform_limits_posix.h"
+
+#include <errno.h>
+#include <sched.h> // for CLONE_* definitions
+#include <stddef.h>
+#include <sys/prctl.h> // for PR_* definitions
+#include <sys/ptrace.h> // for PTRACE_* definitions
+#include <sys/types.h> // for pid_t
+#if SANITIZER_ANDROID && defined(__arm__)
+# include <linux/user.h> // for pt_regs
+#else
+# include <sys/user.h> // for user_regs_struct
+#endif
+#include <sys/wait.h> // for signal-related stuff
+
+#ifdef sa_handler
+# undef sa_handler
+#endif
+
+#ifdef sa_sigaction
+# undef sa_sigaction
+#endif
+
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_placement_new.h"
+
+// This module works by spawning a Linux task which then attaches to every
+// thread in the caller process with ptrace. This suspends the threads, and
+// PTRACE_GETREGS can then be used to obtain their register state. The callback
+// supplied to StopTheWorld() is run in the tracer task while the threads are
+// suspended.
+// The tracer task must be placed in a different thread group for ptrace to
+// work, so it cannot be spawned as a pthread. Instead, we use the low-level
+// clone() interface (we want to share the address space with the caller
+// process, so we prefer clone() over fork()).
+//
+// We don't use any libc functions, relying instead on direct syscalls. There
+// are two reasons for this:
+// 1. calling a library function while threads are suspended could cause a
+// deadlock, if one of the treads happens to be holding a libc lock;
+// 2. it's generally not safe to call libc functions from the tracer task,
+// because clone() does not set up a thread-local storage for it. Any
+// thread-local variables used by libc will be shared between the tracer task
+// and the thread which spawned it.
+
+COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
+
+namespace __sanitizer {
+// This class handles thread suspending/unsuspending in the tracer thread.
+class ThreadSuspender {
+ public:
+ explicit ThreadSuspender(pid_t pid)
+ : pid_(pid) {
+ CHECK_GE(pid, 0);
+ }
+ bool SuspendAllThreads();
+ void ResumeAllThreads();
+ void KillAllThreads();
+ SuspendedThreadsList &suspended_threads_list() {
+ return suspended_threads_list_;
+ }
+ private:
+ SuspendedThreadsList suspended_threads_list_;
+ pid_t pid_;
+ bool SuspendThread(SuspendedThreadID thread_id);
+};
+
+bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
+ // Are we already attached to this thread?
+ // Currently this check takes linear time, however the number of threads is
+ // usually small.
+ if (suspended_threads_list_.Contains(tid))
+ return false;
+ int pterrno;
+ if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, NULL, NULL),
+ &pterrno)) {
+ // Either the thread is dead, or something prevented us from attaching.
+ // Log this event and move on.
+ VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno);
+ return false;
+ } else {
+ VReport(1, "Attached to thread %d.\n", tid);
+ // The thread is not guaranteed to stop before ptrace returns, so we must
+ // wait on it. Note: if the thread receives a signal concurrently,
+ // we can get notification about the signal before notification about stop.
+ // In such case we need to forward the signal to the thread, otherwise
+ // the signal will be missed (as we do PTRACE_DETACH with arg=0) and
+ // any logic relying on signals will break. After forwarding we need to
+ // continue to wait for stopping, because the thread is not stopped yet.
+ // We do ignore delivery of SIGSTOP, because we want to make stop-the-world
+ // as invisible as possible.
+ for (;;) {
+ int status;
+ uptr waitpid_status;
+ HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL));
+ int wperrno;
+ if (internal_iserror(waitpid_status, &wperrno)) {
+ // Got a ECHILD error. I don't think this situation is possible, but it
+ // doesn't hurt to report it.
+ VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
+ tid, wperrno);
+ internal_ptrace(PTRACE_DETACH, tid, NULL, NULL);
+ return false;
+ }
+ if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) {
+ internal_ptrace(PTRACE_CONT, tid, 0, (void*)(uptr)WSTOPSIG(status));
+ continue;
+ }
+ break;
+ }
+ suspended_threads_list_.Append(tid);
+ return true;
+ }
+}
+
+void ThreadSuspender::ResumeAllThreads() {
+ for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
+ pid_t tid = suspended_threads_list_.GetThreadID(i);
+ int pterrno;
+ if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
+ &pterrno)) {
+ VReport(1, "Detached from thread %d.\n", tid);
+ } else {
+ // Either the thread is dead, or we are already detached.
+ // The latter case is possible, for instance, if this function was called
+ // from a signal handler.
+ VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno);
+ }
+ }
+}
+
+void ThreadSuspender::KillAllThreads() {
+ for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++)
+ internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i),
+ NULL, NULL);
+}
+
+bool ThreadSuspender::SuspendAllThreads() {
+ ThreadLister thread_lister(pid_);
+ bool added_threads;
+ do {
+ // Run through the directory entries once.
+ added_threads = false;
+ pid_t tid = thread_lister.GetNextTID();
+ while (tid >= 0) {
+ if (SuspendThread(tid))
+ added_threads = true;
+ tid = thread_lister.GetNextTID();
+ }
+ if (thread_lister.error()) {
+ // Detach threads and fail.
+ ResumeAllThreads();
+ return false;
+ }
+ thread_lister.Reset();
+ } while (added_threads);
+ return true;
+}
+
+// Pointer to the ThreadSuspender instance for use in signal handler.
+static ThreadSuspender *thread_suspender_instance = NULL;
+
+// Synchronous signals that should not be blocked.
+static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS,
+ SIGXCPU, SIGXFSZ };
+
+// Structure for passing arguments into the tracer thread.
+struct TracerThreadArgument {
+ StopTheWorldCallback callback;
+ void *callback_argument;
+ // The tracer thread waits on this mutex while the parent finishes its
+ // preparations.
+ BlockingMutex mutex;
+ uptr parent_pid;
+};
+
+static DieCallbackType old_die_callback;
+
+// Signal handler to wake up suspended threads when the tracer thread dies.
+static void TracerThreadSignalHandler(int signum, void *siginfo, void *) {
+ if (thread_suspender_instance != NULL) {
+ if (signum == SIGABRT)
+ thread_suspender_instance->KillAllThreads();
+ else
+ thread_suspender_instance->ResumeAllThreads();
+ }
+ internal__exit((signum == SIGABRT) ? 1 : 2);
+}
+
+static void TracerThreadDieCallback() {
+ // Generally a call to Die() in the tracer thread should be fatal to the
+ // parent process as well, because they share the address space.
+ // This really only works correctly if all the threads are suspended at this
+ // point. So we correctly handle calls to Die() from within the callback, but
+ // not those that happen before or after the callback. Hopefully there aren't
+ // a lot of opportunities for that to happen...
+ if (thread_suspender_instance)
+ thread_suspender_instance->KillAllThreads();
+ if (old_die_callback)
+ old_die_callback();
+}
+
+// Size of alternative stack for signal handlers in the tracer thread.
+static const int kHandlerStackSize = 4096;
+
+// This function will be run as a cloned task.
+static int TracerThread(void* argument) {
+ TracerThreadArgument *tracer_thread_argument =
+ (TracerThreadArgument *)argument;
+
+ internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ // Check if parent is already dead.
+ if (internal_getppid() != tracer_thread_argument->parent_pid)
+ internal__exit(4);
+
+ // Wait for the parent thread to finish preparations.
+ tracer_thread_argument->mutex.Lock();
+ tracer_thread_argument->mutex.Unlock();
+
+ old_die_callback = GetDieCallback();
+ SetDieCallback(TracerThreadDieCallback);
+
+ ThreadSuspender thread_suspender(internal_getppid());
+ // Global pointer for the signal handler.
+ thread_suspender_instance = &thread_suspender;
+
+ // Alternate stack for signal handling.
+ InternalScopedBuffer<char> handler_stack_memory(kHandlerStackSize);
+ struct sigaltstack handler_stack;
+ internal_memset(&handler_stack, 0, sizeof(handler_stack));
+ handler_stack.ss_sp = handler_stack_memory.data();
+ handler_stack.ss_size = kHandlerStackSize;
+ internal_sigaltstack(&handler_stack, NULL);
+
+ // Install our handler for synchronous signals. Other signals should be
+ // blocked by the mask we inherited from the parent thread.
+ for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) {
+ __sanitizer_sigaction act;
+ internal_memset(&act, 0, sizeof(act));
+ act.sigaction = TracerThreadSignalHandler;
+ act.sa_flags = SA_ONSTACK | SA_SIGINFO;
+ internal_sigaction_norestorer(kSyncSignals[i], &act, 0);
+ }
+
+ int exit_code = 0;
+ if (!thread_suspender.SuspendAllThreads()) {
+ VReport(1, "Failed suspending threads.\n");
+ exit_code = 3;
+ } else {
+ tracer_thread_argument->callback(thread_suspender.suspended_threads_list(),
+ tracer_thread_argument->callback_argument);
+ thread_suspender.ResumeAllThreads();
+ exit_code = 0;
+ }
+ // Note, this is a bad race. If TracerThreadDieCallback is already started
+ // in another thread and observed that thread_suspender_instance != 0,
+ // it can call KillAllThreads on the destroyed variable.
+ SetDieCallback(old_die_callback);
+ thread_suspender_instance = NULL;
+ return exit_code;
+}
+
+class ScopedStackSpaceWithGuard {
+ public:
+ explicit ScopedStackSpaceWithGuard(uptr stack_size) {
+ stack_size_ = stack_size;
+ guard_size_ = GetPageSizeCached();
+ // FIXME: Omitting MAP_STACK here works in current kernels but might break
+ // in the future.
+ guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_,
+ "ScopedStackWithGuard");
+ CHECK_EQ(guard_start_, (uptr)Mprotect((uptr)guard_start_, guard_size_));
+ }
+ ~ScopedStackSpaceWithGuard() {
+ UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_);
+ }
+ void *Bottom() const {
+ return (void *)(guard_start_ + stack_size_ + guard_size_);
+ }
+
+ private:
+ uptr stack_size_;
+ uptr guard_size_;
+ uptr guard_start_;
+};
+
+// We have a limitation on the stack frame size, so some stuff had to be moved
+// into globals.
+static __sanitizer_sigset_t blocked_sigset;
+static __sanitizer_sigset_t old_sigset;
+
+class StopTheWorldScope {
+ public:
+ StopTheWorldScope() {
+ // Make this process dumpable. Processes that are not dumpable cannot be
+ // attached to.
+ process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+ if (!process_was_dumpable_)
+ internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ }
+
+ ~StopTheWorldScope() {
+ // Restore the dumpable flag.
+ if (!process_was_dumpable_)
+ internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+ }
+
+ private:
+ int process_was_dumpable_;
+};
+
+// When sanitizer output is being redirected to file (i.e. by using log_path),
+// the tracer should write to the parent's log instead of trying to open a new
+// file. Alert the logging code to the fact that we have a tracer.
+struct ScopedSetTracerPID {
+ explicit ScopedSetTracerPID(uptr tracer_pid) {
+ stoptheworld_tracer_pid = tracer_pid;
+ stoptheworld_tracer_ppid = internal_getpid();
+ }
+ ~ScopedSetTracerPID() {
+ stoptheworld_tracer_pid = 0;
+ stoptheworld_tracer_ppid = 0;
+ }
+};
+
+void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+ StopTheWorldScope in_stoptheworld;
+ // Prepare the arguments for TracerThread.
+ struct TracerThreadArgument tracer_thread_argument;
+ tracer_thread_argument.callback = callback;
+ tracer_thread_argument.callback_argument = argument;
+ tracer_thread_argument.parent_pid = internal_getpid();
+ const uptr kTracerStackSize = 2 * 1024 * 1024;
+ ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize);
+ // Block the execution of TracerThread until after we have set ptrace
+ // permissions.
+ tracer_thread_argument.mutex.Lock();
+ // Signal handling story.
+ // We don't want async signals to be delivered to the tracer thread,
+ // so we block all async signals before creating the thread. An async signal
+ // handler can temporary modify errno, which is shared with this thread.
+ // We ought to use pthread_sigmask here, because sigprocmask has undefined
+ // behavior in multithreaded programs. However, on linux sigprocmask is
+ // equivalent to pthread_sigmask with the exception that pthread_sigmask
+ // does not allow to block some signals used internally in pthread
+ // implementation. We are fine with blocking them here, we are really not
+ // going to pthread_cancel the thread.
+ // The tracer thread should not raise any synchronous signals. But in case it
+ // does, we setup a special handler for sync signals that properly kills the
+ // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers
+ // in the tracer thread won't interfere with user program. Double note: if a
+ // user does something along the lines of 'kill -11 pid', that can kill the
+ // process even if user setup own handler for SEGV.
+ // Thing to watch out for: this code should not change behavior of user code
+ // in any observable way. In particular it should not override user signal
+ // handlers.
+ internal_sigfillset(&blocked_sigset);
+ for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++)
+ internal_sigdelset(&blocked_sigset, kSyncSignals[i]);
+ int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
+ CHECK_EQ(rv, 0);
+ uptr tracer_pid = internal_clone(
+ TracerThread, tracer_stack.Bottom(),
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
+ &tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0
+ /* child_tidptr */);
+ internal_sigprocmask(SIG_SETMASK, &old_sigset, 0);
+ int local_errno = 0;
+ if (internal_iserror(tracer_pid, &local_errno)) {
+ VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno);
+ tracer_thread_argument.mutex.Unlock();
+ } else {
+ ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid);
+ // On some systems we have to explicitly declare that we want to be traced
+ // by the tracer thread.
+#ifdef PR_SET_PTRACER
+ internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0);
+#endif
+ // Allow the tracer thread to start.
+ tracer_thread_argument.mutex.Unlock();
+ // Since errno is shared between this thread and the tracer thread, we
+ // must avoid using errno while the tracer thread is running.
+ // At this point, any signal will either be blocked or kill us, so waitpid
+ // should never return (and set errno) while the tracer thread is alive.
+ uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
+ if (internal_iserror(waitpid_status, &local_errno))
+ VReport(1, "Waiting on the tracer thread failed (errno %d).\n",
+ local_errno);
+ }
+}
+
+// Platform-specific methods from SuspendedThreadsList.
+#if SANITIZER_ANDROID && defined(__arm__)
+typedef pt_regs regs_struct;
+#define REG_SP ARM_sp
+
+#elif SANITIZER_LINUX && defined(__arm__)
+typedef user_regs regs_struct;
+#define REG_SP uregs[13]
+
+#elif defined(__i386__) || defined(__x86_64__)
+typedef user_regs_struct regs_struct;
+#if defined(__i386__)
+#define REG_SP esp
+#else
+#define REG_SP rsp
+#endif
+
+#elif defined(__powerpc__) || defined(__powerpc64__)
+typedef pt_regs regs_struct;
+#define REG_SP gpr[PT_R1]
+
+#elif defined(__mips__)
+typedef struct user regs_struct;
+#define REG_SP regs[EF_REG29]
+
+#else
+#error "Unsupported architecture"
+#endif // SANITIZER_ANDROID && defined(__arm__)
+
+int SuspendedThreadsList::GetRegistersAndSP(uptr index,
+ uptr *buffer,
+ uptr *sp) const {
+ pid_t tid = GetThreadID(index);
+ regs_struct regs;
+ int pterrno;
+ if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
+ &pterrno)) {
+ VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
+ pterrno);
+ return -1;
+ }
+
+ *sp = regs.REG_SP;
+ internal_memcpy(buffer, &regs, sizeof(regs));
+ return 0;
+}
+
+uptr SuspendedThreadsList::RegisterCount() {
+ return sizeof(regs_struct) / sizeof(uptr);
+}
+} // namespace __sanitizer
+
+#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
new file mode 100644
index 000000000000..2b697e955709
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -0,0 +1,139 @@
+//===-- sanitizer_suppressions.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_suppressions.h"
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
+
+namespace __sanitizer {
+
+SuppressionContext::SuppressionContext(const char *suppression_types[],
+ int suppression_types_num)
+ : suppression_types_(suppression_types),
+ suppression_types_num_(suppression_types_num), suppressions_(1),
+ can_parse_(true) {
+ CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);
+ internal_memset(has_suppression_type_, 0, suppression_types_num_);
+}
+
+void SuppressionContext::ParseFromFile(const char *filename) {
+ if (filename[0] == '\0')
+ return;
+ char *file_contents;
+ uptr buffer_size;
+ uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size,
+ 1 << 26 /* max_len */);
+ if (contents_size == 0) {
+ Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
+ filename);
+ Die();
+ }
+ Parse(file_contents);
+}
+
+bool SuppressionContext::Match(const char *str, const char *type,
+ Suppression **s) {
+ can_parse_ = false;
+ if (!HasSuppressionType(type))
+ return false;
+ for (uptr i = 0; i < suppressions_.size(); i++) {
+ Suppression &cur = suppressions_[i];
+ if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) {
+ *s = &cur;
+ return true;
+ }
+ }
+ return false;
+}
+
+static const char *StripPrefix(const char *str, const char *prefix) {
+ while (str && *str == *prefix) {
+ str++;
+ prefix++;
+ }
+ if (!*prefix)
+ return str;
+ return 0;
+}
+
+void SuppressionContext::Parse(const char *str) {
+ // Context must not mutate once Match has been called.
+ CHECK(can_parse_);
+ const char *line = str;
+ while (line) {
+ while (line[0] == ' ' || line[0] == '\t')
+ line++;
+ const char *end = internal_strchr(line, '\n');
+ if (end == 0)
+ end = line + internal_strlen(line);
+ if (line != end && line[0] != '#') {
+ const char *end2 = end;
+ while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
+ end2--;
+ int type;
+ for (type = 0; type < suppression_types_num_; type++) {
+ const char *next_char = StripPrefix(line, suppression_types_[type]);
+ if (next_char && *next_char == ':') {
+ line = ++next_char;
+ break;
+ }
+ }
+ if (type == suppression_types_num_) {
+ Printf("%s: failed to parse suppressions\n", SanitizerToolName);
+ Die();
+ }
+ Suppression s;
+ s.type = suppression_types_[type];
+ s.templ = (char*)InternalAlloc(end2 - line + 1);
+ internal_memcpy(s.templ, line, end2 - line);
+ s.templ[end2 - line] = 0;
+ s.hit_count = 0;
+ s.weight = 0;
+ suppressions_.push_back(s);
+ has_suppression_type_[type] = true;
+ }
+ if (end[0] == 0)
+ break;
+ line = end + 1;
+ }
+}
+
+uptr SuppressionContext::SuppressionCount() const {
+ return suppressions_.size();
+}
+
+bool SuppressionContext::HasSuppressionType(const char *type) const {
+ for (int i = 0; i < suppression_types_num_; i++) {
+ if (0 == internal_strcmp(type, suppression_types_[i]))
+ return has_suppression_type_[i];
+ }
+ return false;
+}
+
+const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
+ CHECK_LT(i, suppressions_.size());
+ return &suppressions_[i];
+}
+
+void SuppressionContext::GetMatched(
+ InternalMmapVector<Suppression *> *matched) {
+ for (uptr i = 0; i < suppressions_.size(); i++)
+ if (suppressions_[i].hit_count)
+ matched->push_back(&suppressions_[i]);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
new file mode 100644
index 000000000000..02dbf6f9690b
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
@@ -0,0 +1,55 @@
+//===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SUPPRESSIONS_H
+#define SANITIZER_SUPPRESSIONS_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+struct Suppression {
+ const char *type;
+ char *templ;
+ unsigned hit_count;
+ uptr weight;
+};
+
+class SuppressionContext {
+ public:
+ // Create new SuppressionContext capable of parsing given suppression types.
+ SuppressionContext(const char *supprression_types[],
+ int suppression_types_num);
+
+ void ParseFromFile(const char *filename);
+ void Parse(const char *str);
+
+ bool Match(const char *str, const char *type, Suppression **s);
+ uptr SuppressionCount() const;
+ bool HasSuppressionType(const char *type) const;
+ const Suppression *SuppressionAt(uptr i) const;
+ void GetMatched(InternalMmapVector<Suppression *> *matched);
+
+ private:
+ static const int kMaxSuppressionTypes = 16;
+ const char **const suppression_types_;
+ const int suppression_types_num_;
+
+ InternalMmapVector<Suppression> suppressions_;
+ bool has_suppression_type_[kMaxSuppressionTypes];
+ bool can_parse_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_SUPPRESSIONS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc
new file mode 100644
index 000000000000..135720ed5eb1
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -0,0 +1,100 @@
+//===-- sanitizer_symbolizer.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_platform.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+AddressInfo::AddressInfo() {
+ internal_memset(this, 0, sizeof(AddressInfo));
+ function_offset = kUnknown;
+}
+
+void AddressInfo::Clear() {
+ InternalFree(module);
+ InternalFree(function);
+ InternalFree(file);
+ internal_memset(this, 0, sizeof(AddressInfo));
+ function_offset = kUnknown;
+}
+
+void AddressInfo::FillAddressAndModuleInfo(uptr addr, const char *mod_name,
+ uptr mod_offset) {
+ address = addr;
+ module = internal_strdup(mod_name);
+ module_offset = mod_offset;
+}
+
+SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
+
+SymbolizedStack *SymbolizedStack::New(uptr addr) {
+ void *mem = InternalAlloc(sizeof(SymbolizedStack));
+ SymbolizedStack *res = new(mem) SymbolizedStack();
+ res->info.address = addr;
+ return res;
+}
+
+void SymbolizedStack::ClearAll() {
+ info.Clear();
+ if (next)
+ next->ClearAll();
+ InternalFree(this);
+}
+
+DataInfo::DataInfo() {
+ internal_memset(this, 0, sizeof(DataInfo));
+}
+
+void DataInfo::Clear() {
+ InternalFree(module);
+ InternalFree(name);
+ internal_memset(this, 0, sizeof(DataInfo));
+}
+
+Symbolizer *Symbolizer::symbolizer_;
+StaticSpinMutex Symbolizer::init_mu_;
+LowLevelAllocator Symbolizer::symbolizer_allocator_;
+
+Symbolizer *Symbolizer::Disable() {
+ CHECK_EQ(0, symbolizer_);
+ // Initialize a dummy symbolizer.
+ symbolizer_ = new(symbolizer_allocator_) Symbolizer;
+ return symbolizer_;
+}
+
+void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook,
+ Symbolizer::EndSymbolizationHook end_hook) {
+ CHECK(start_hook_ == 0 && end_hook_ == 0);
+ start_hook_ = start_hook;
+ end_hook_ = end_hook;
+}
+
+Symbolizer::Symbolizer() : start_hook_(0), end_hook_(0) {}
+
+Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
+ : sym_(sym) {
+ if (sym_->start_hook_)
+ sym_->start_hook_();
+}
+
+Symbolizer::SymbolizerScope::~SymbolizerScope() {
+ if (sym_->end_hook_)
+ sym_->end_hook_();
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
new file mode 100644
index 000000000000..3ccfce9995be
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -0,0 +1,142 @@
+//===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Symbolizer is used by sanitizers to map instruction address to a location in
+// source code at run-time. Symbolizer either uses __sanitizer_symbolize_*
+// defined in the program, or (if they are missing) tries to find and
+// launch "llvm-symbolizer" commandline tool in a separate process and
+// communicate with it.
+//
+// Generally we should try to avoid calling system library functions during
+// symbolization (and use their replacements from sanitizer_libc.h instead).
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_H
+#define SANITIZER_SYMBOLIZER_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+struct AddressInfo {
+ // Owns all the string members. Storage for them is
+ // (de)allocated using sanitizer internal allocator.
+ uptr address;
+
+ char *module;
+ uptr module_offset;
+
+ static const uptr kUnknown = ~(uptr)0;
+ char *function;
+ uptr function_offset;
+
+ char *file;
+ int line;
+ int column;
+
+ AddressInfo();
+ // Deletes all strings and resets all fields.
+ void Clear();
+ void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
+ uptr mod_offset);
+};
+
+// Linked list of symbolized frames (each frame is described by AddressInfo).
+struct SymbolizedStack {
+ SymbolizedStack *next;
+ AddressInfo info;
+ static SymbolizedStack *New(uptr addr);
+ // Deletes current, and all subsequent frames in the linked list.
+ // The object cannot be accessed after the call to this function.
+ void ClearAll();
+
+ private:
+ SymbolizedStack();
+};
+
+// For now, DataInfo is used to describe global variable.
+struct DataInfo {
+ // Owns all the string members. Storage for them is
+ // (de)allocated using sanitizer internal allocator.
+ char *module;
+ uptr module_offset;
+ char *name;
+ uptr start;
+ uptr size;
+
+ DataInfo();
+ void Clear();
+};
+
+class Symbolizer {
+ public:
+ /// Initialize and return platform-specific implementation of symbolizer
+ /// (if it wasn't already initialized).
+ static Symbolizer *GetOrInit();
+ // Returns a list of symbolized frames for a given address (containing
+ // all inlined functions, if necessary).
+ virtual SymbolizedStack *SymbolizePC(uptr address) {
+ return SymbolizedStack::New(address);
+ }
+ virtual bool SymbolizeData(uptr address, DataInfo *info) {
+ return false;
+ }
+ virtual bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+ uptr *module_address) {
+ return false;
+ }
+ virtual bool CanReturnFileLineInfo() {
+ return false;
+ }
+ // Release internal caches (if any).
+ virtual void Flush() {}
+ // Attempts to demangle the provided C++ mangled name.
+ virtual const char *Demangle(const char *name) {
+ return name;
+ }
+ virtual void PrepareForSandboxing() {}
+
+ // Allow user to install hooks that would be called before/after Symbolizer
+ // does the actual file/line info fetching. Specific sanitizers may need this
+ // to distinguish system library calls made in user code from calls made
+ // during in-process symbolization.
+ typedef void (*StartSymbolizationHook)();
+ typedef void (*EndSymbolizationHook)();
+ // May be called at most once.
+ void AddHooks(StartSymbolizationHook start_hook,
+ EndSymbolizationHook end_hook);
+
+ private:
+ /// Platform-specific function for creating a Symbolizer object.
+ static Symbolizer *PlatformInit();
+ /// Initialize the symbolizer in a disabled state. Not thread safe.
+ static Symbolizer *Disable();
+
+ static Symbolizer *symbolizer_;
+ static StaticSpinMutex init_mu_;
+
+ protected:
+ Symbolizer();
+
+ static LowLevelAllocator symbolizer_allocator_;
+
+ StartSymbolizationHook start_hook_;
+ EndSymbolizationHook end_hook_;
+ class SymbolizerScope {
+ public:
+ explicit SymbolizerScope(const Symbolizer *sym);
+ ~SymbolizerScope();
+ private:
+ const Symbolizer *sym_;
+ };
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_SYMBOLIZER_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
new file mode 100644
index 000000000000..9317a78eef13
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -0,0 +1,211 @@
+//===-- sanitizer_symbolizer_libbacktrace.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Libbacktrace implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
+
+#if SANITIZER_LIBBACKTRACE
+# include "backtrace-supported.h"
+# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
+# include "backtrace.h"
+# if SANITIZER_CP_DEMANGLE
+# undef ARRAY_SIZE
+# include "demangle.h"
+# endif
+# else
+# define SANITIZER_LIBBACKTRACE 0
+# endif
+#endif
+
+namespace __sanitizer {
+
+#if SANITIZER_LIBBACKTRACE
+
+namespace {
+
+# if SANITIZER_CP_DEMANGLE
+struct CplusV3DemangleData {
+ char *buf;
+ uptr size, allocated;
+};
+
+extern "C" {
+static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
+ CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
+ uptr needed = data->size + l + 1;
+ if (needed > data->allocated) {
+ data->allocated *= 2;
+ if (needed > data->allocated)
+ data->allocated = needed;
+ char *buf = (char *)InternalAlloc(data->allocated);
+ if (data->buf) {
+ internal_memcpy(buf, data->buf, data->size);
+ InternalFree(data->buf);
+ }
+ data->buf = buf;
+ }
+ internal_memcpy(data->buf + data->size, s, l);
+ data->buf[data->size + l] = '\0';
+ data->size += l;
+}
+} // extern "C"
+
+char *CplusV3Demangle(const char *name) {
+ CplusV3DemangleData data;
+ data.buf = 0;
+ data.size = 0;
+ data.allocated = 0;
+ if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
+ CplusV3DemangleCallback, &data)) {
+ if (data.size + 64 > data.allocated)
+ return data.buf;
+ char *buf = internal_strdup(data.buf);
+ InternalFree(data.buf);
+ return buf;
+ }
+ if (data.buf)
+ InternalFree(data.buf);
+ return 0;
+}
+# endif // SANITIZER_CP_DEMANGLE
+
+struct SymbolizeCodeCallbackArg {
+ SymbolizedStack *first;
+ SymbolizedStack *last;
+ const char *module_name;
+ uptr module_offset;
+
+ void append(SymbolizedStack *f) {
+ if (last != nullptr) {
+ last->next = f;
+ last = f;
+ } else {
+ first = f;
+ last = f;
+ }
+ }
+};
+
+extern "C" {
+static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
+ const char *filename, int lineno,
+ const char *function) {
+ SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
+ if (function) {
+ SymbolizedStack *cur = SymbolizedStack::New(addr);
+ cdata->append(cur);
+ AddressInfo *info = &cur->info;
+ info->FillAddressAndModuleInfo(addr, cdata->module_name,
+ cdata->module_offset);
+ info->function = LibbacktraceSymbolizer::Demangle(function, true);
+ if (filename)
+ info->file = internal_strdup(filename);
+ info->line = lineno;
+ }
+ return 0;
+}
+
+static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
+ const char *symname, uintptr_t, uintptr_t) {
+ SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
+ if (symname) {
+ SymbolizedStack *cur = SymbolizedStack::New(addr);
+ cdata->append(cur);
+ AddressInfo *info = &cur->info;
+ info->FillAddressAndModuleInfo(addr, cdata->module_name,
+ cdata->module_offset);
+ info->function = LibbacktraceSymbolizer::Demangle(symname, true);
+ }
+}
+
+static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
+ uintptr_t symval, uintptr_t symsize) {
+ DataInfo *info = (DataInfo *)vdata;
+ if (symname && symval) {
+ info->name = LibbacktraceSymbolizer::Demangle(symname, true);
+ info->start = symval;
+ info->size = symsize;
+ }
+}
+
+static void ErrorCallback(void *, const char *, int) {}
+} // extern "C"
+
+} // namespace
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+ // State created in backtrace_create_state is leaked.
+ void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
+ ErrorCallback, NULL));
+ if (!state)
+ return 0;
+ return new(*alloc) LibbacktraceSymbolizer(state);
+}
+
+SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
+ const char *module_name,
+ uptr module_offset) {
+ SymbolizeCodeCallbackArg data;
+ data.first = nullptr;
+ data.last = nullptr;
+ data.module_name = module_name;
+ data.module_offset = module_offset;
+ backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
+ ErrorCallback, &data);
+ if (data.first)
+ return data.first;
+ backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
+ ErrorCallback, &data);
+ return data.first;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+ backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback,
+ ErrorCallback, info);
+ return true;
+}
+
+#else // SANITIZER_LIBBACKTRACE
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+ return 0;
+}
+
+SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
+ const char *module_name,
+ uptr module_offset) {
+ (void)state_;
+ return nullptr;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+ return false;
+}
+
+#endif // SANITIZER_LIBBACKTRACE
+
+char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) {
+#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
+ if (char *demangled = CplusV3Demangle(name))
+ return demangled;
+#endif
+ if (always_alloc)
+ return internal_strdup(name);
+ return 0;
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
new file mode 100644
index 000000000000..1ff005042a11
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -0,0 +1,50 @@
+//===-- sanitizer_symbolizer_libbacktrace.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Header for libbacktrace symbolizer.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
+#define SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
+
+#include "sanitizer_platform.h"
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+#ifndef SANITIZER_LIBBACKTRACE
+# define SANITIZER_LIBBACKTRACE 0
+#endif
+
+#ifndef SANITIZER_CP_DEMANGLE
+# define SANITIZER_CP_DEMANGLE 0
+#endif
+
+namespace __sanitizer {
+
+class LibbacktraceSymbolizer {
+ public:
+ static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
+
+ SymbolizedStack *SymbolizeCode(uptr addr, const char *module_name,
+ uptr module_offset);
+
+ bool SymbolizeData(uptr addr, DataInfo *info);
+
+ // May return NULL if demangling failed.
+ static char *Demangle(const char *name, bool always_alloc = false);
+
+ private:
+ explicit LibbacktraceSymbolizer(void *state) : state_(state) {}
+
+ void *state_; // Leaked.
+};
+
+} // namespace __sanitizer
+#endif // SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
new file mode 100644
index 000000000000..63c9356a521f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -0,0 +1,28 @@
+//===-- sanitizer_symbolizer_libcdep.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+Symbolizer *Symbolizer::GetOrInit() {
+ SpinMutexLock l(&init_mu_);
+ if (symbolizer_)
+ return symbolizer_;
+ if ((symbolizer_ = PlatformInit()))
+ return symbolizer_;
+ return Disable();
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
new file mode 100644
index 000000000000..69ac18e8426f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -0,0 +1,766 @@
+//===-- sanitizer_symbolizer_posix_libcdep.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// POSIX-specific implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// C++ demangling function, as required by Itanium C++ ABI. This is weak,
+// because we do not require a C++ ABI library to be linked to a program
+// using sanitizers; if it's not present, we'll just use the mangled name.
+namespace __cxxabiv1 {
+ extern "C" SANITIZER_WEAK_ATTRIBUTE
+ char *__cxa_demangle(const char *mangled, char *buffer,
+ size_t *length, int *status);
+}
+
+namespace __sanitizer {
+
+// Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
+static const char *DemangleCXXABI(const char *name) {
+ // FIXME: __cxa_demangle aggressively insists on allocating memory.
+ // There's not much we can do about that, short of providing our
+ // own demangler (libc++abi's implementation could be adapted so that
+ // it does not allocate). For now, we just call it anyway, and we leak
+ // the returned value.
+ if (__cxxabiv1::__cxa_demangle)
+ if (const char *demangled_name =
+ __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
+ return demangled_name;
+
+ return name;
+}
+
+// Extracts the prefix of "str" that consists of any characters not
+// present in "delims" string, and copies this prefix to "result", allocating
+// space for it.
+// Returns a pointer to "str" after skipping extracted prefix and first
+// delimiter char.
+static const char *ExtractToken(const char *str, const char *delims,
+ char **result) {
+ uptr prefix_len = internal_strcspn(str, delims);
+ *result = (char*)InternalAlloc(prefix_len + 1);
+ internal_memcpy(*result, str, prefix_len);
+ (*result)[prefix_len] = '\0';
+ const char *prefix_end = str + prefix_len;
+ if (*prefix_end != '\0') prefix_end++;
+ return prefix_end;
+}
+
+// Same as ExtractToken, but converts extracted token to integer.
+static const char *ExtractInt(const char *str, const char *delims,
+ int *result) {
+ char *buff;
+ const char *ret = ExtractToken(str, delims, &buff);
+ if (buff != 0) {
+ *result = (int)internal_atoll(buff);
+ }
+ InternalFree(buff);
+ return ret;
+}
+
+static const char *ExtractUptr(const char *str, const char *delims,
+ uptr *result) {
+ char *buff;
+ const char *ret = ExtractToken(str, delims, &buff);
+ if (buff != 0) {
+ *result = (uptr)internal_atoll(buff);
+ }
+ InternalFree(buff);
+ return ret;
+}
+
+class ExternalSymbolizerInterface {
+ public:
+ // Can't declare pure virtual functions in sanitizer runtimes:
+ // __cxa_pure_virtual might be unavailable.
+ virtual char *SendCommand(bool is_data, const char *module_name,
+ uptr module_offset) {
+ UNIMPLEMENTED();
+ }
+};
+
+// SymbolizerProcess encapsulates communication between the tool and
+// external symbolizer program, running in a different subprocess.
+// SymbolizerProcess may not be used from two threads simultaneously.
+class SymbolizerProcess : public ExternalSymbolizerInterface {
+ public:
+ explicit SymbolizerProcess(const char *path)
+ : path_(path),
+ input_fd_(kInvalidFd),
+ output_fd_(kInvalidFd),
+ times_restarted_(0),
+ failed_to_start_(false),
+ reported_invalid_path_(false) {
+ CHECK(path_);
+ CHECK_NE(path_[0], '\0');
+ }
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
+ // Start or restart symbolizer if we failed to send command to it.
+ if (char *res = SendCommandImpl(is_data, module_name, module_offset))
+ return res;
+ Restart();
+ }
+ if (!failed_to_start_) {
+ Report("WARNING: Failed to use and restart external symbolizer!\n");
+ failed_to_start_ = true;
+ }
+ return 0;
+ }
+
+ private:
+ bool Restart() {
+ if (input_fd_ != kInvalidFd)
+ internal_close(input_fd_);
+ if (output_fd_ != kInvalidFd)
+ internal_close(output_fd_);
+ return StartSymbolizerSubprocess();
+ }
+
+ char *SendCommandImpl(bool is_data, const char *module_name,
+ uptr module_offset) {
+ if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
+ return 0;
+ CHECK(module_name);
+ if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name,
+ module_offset))
+ return 0;
+ if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
+ return 0;
+ if (!readFromSymbolizer(buffer_, kBufferSize))
+ return 0;
+ return buffer_;
+ }
+
+ bool readFromSymbolizer(char *buffer, uptr max_length) {
+ if (max_length == 0)
+ return true;
+ uptr read_len = 0;
+ while (true) {
+ uptr just_read = internal_read(input_fd_, buffer + read_len,
+ max_length - read_len - 1);
+ // We can't read 0 bytes, as we don't expect external symbolizer to close
+ // its stdout.
+ if (just_read == 0 || just_read == (uptr)-1) {
+ Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
+ return false;
+ }
+ read_len += just_read;
+ if (ReachedEndOfOutput(buffer, read_len))
+ break;
+ }
+ buffer[read_len] = '\0';
+ return true;
+ }
+
+ bool writeToSymbolizer(const char *buffer, uptr length) {
+ if (length == 0)
+ return true;
+ uptr write_len = internal_write(output_fd_, buffer, length);
+ if (write_len == 0 || write_len == (uptr)-1) {
+ Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
+ return false;
+ }
+ return true;
+ }
+
+ bool StartSymbolizerSubprocess() {
+ if (!FileExists(path_)) {
+ if (!reported_invalid_path_) {
+ Report("WARNING: invalid path to external symbolizer!\n");
+ reported_invalid_path_ = true;
+ }
+ return false;
+ }
+
+ int *infd = NULL;
+ int *outfd = NULL;
+ // The client program may close its stdin and/or stdout and/or stderr
+ // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+ // In this case the communication between the forked processes may be
+ // broken if either the parent or the child tries to close or duplicate
+ // these descriptors. The loop below produces two pairs of file
+ // descriptors, each greater than 2 (stderr).
+ int sock_pair[5][2];
+ for (int i = 0; i < 5; i++) {
+ if (pipe(sock_pair[i]) == -1) {
+ for (int j = 0; j < i; j++) {
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ Report("WARNING: Can't create a socket pair to start "
+ "external symbolizer (errno: %d)\n", errno);
+ return false;
+ } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+ if (infd == NULL) {
+ infd = sock_pair[i];
+ } else {
+ outfd = sock_pair[i];
+ for (int j = 0; j < i; j++) {
+ if (sock_pair[j] == infd) continue;
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ break;
+ }
+ }
+ }
+ CHECK(infd);
+ CHECK(outfd);
+
+ // Real fork() may call user callbacks registered with pthread_atfork().
+ int pid = internal_fork();
+ if (pid == -1) {
+ // Fork() failed.
+ internal_close(infd[0]);
+ internal_close(infd[1]);
+ internal_close(outfd[0]);
+ internal_close(outfd[1]);
+ Report("WARNING: failed to fork external symbolizer "
+ " (errno: %d)\n", errno);
+ return false;
+ } else if (pid == 0) {
+ // Child subprocess.
+ internal_close(STDOUT_FILENO);
+ internal_close(STDIN_FILENO);
+ internal_dup2(outfd[0], STDIN_FILENO);
+ internal_dup2(infd[1], STDOUT_FILENO);
+ internal_close(outfd[0]);
+ internal_close(outfd[1]);
+ internal_close(infd[0]);
+ internal_close(infd[1]);
+ for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
+ internal_close(fd);
+ ExecuteWithDefaultArgs(path_);
+ internal__exit(1);
+ }
+
+ // Continue execution in parent process.
+ internal_close(outfd[0]);
+ internal_close(infd[1]);
+ input_fd_ = infd[0];
+ output_fd_ = outfd[1];
+
+ // Check that symbolizer subprocess started successfully.
+ int pid_status;
+ SleepForMillis(kSymbolizerStartupTimeMillis);
+ int exited_pid = waitpid(pid, &pid_status, WNOHANG);
+ if (exited_pid != 0) {
+ // Either waitpid failed, or child has already exited.
+ Report("WARNING: external symbolizer didn't start up correctly!\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+ const char *module_name,
+ uptr module_offset) const {
+ UNIMPLEMENTED();
+ }
+
+ virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ UNIMPLEMENTED();
+ }
+
+ virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ UNIMPLEMENTED();
+ }
+
+ const char *path_;
+ int input_fd_;
+ int output_fd_;
+
+ static const uptr kBufferSize = 16 * 1024;
+ char buffer_[kBufferSize];
+
+ static const uptr kMaxTimesRestarted = 5;
+ static const int kSymbolizerStartupTimeMillis = 10;
+ uptr times_restarted_;
+ bool failed_to_start_;
+ bool reported_invalid_path_;
+};
+
+// For now we assume the following protocol:
+// For each request of the form
+// <module_name> <module_offset>
+// passed to STDIN, external symbolizer prints to STDOUT response:
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// ...
+// <empty line>
+class LLVMSymbolizerProcess : public SymbolizerProcess {
+ public:
+ explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
+
+ private:
+ bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+ const char *module_name, uptr module_offset) const {
+ internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n",
+ is_data ? "DATA " : "", module_name, module_offset);
+ return true;
+ }
+
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ // Empty line marks the end of llvm-symbolizer output.
+ return length >= 2 && buffer[length - 1] == '\n' &&
+ buffer[length - 2] == '\n';
+ }
+
+ void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+#if defined(__x86_64__)
+ const char* const kSymbolizerArch = "--default-arch=x86_64";
+#elif defined(__i386__)
+ const char* const kSymbolizerArch = "--default-arch=i386";
+#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
+ const char* const kSymbolizerArch = "--default-arch=powerpc64le";
+#else
+ const char* const kSymbolizerArch = "--default-arch=unknown";
+#endif
+
+ const char *const inline_flag = common_flags()->symbolize_inline_frames
+ ? "--inlining=true"
+ : "--inlining=false";
+ execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch,
+ (char *)0);
+ }
+};
+
+class Addr2LineProcess : public SymbolizerProcess {
+ public:
+ Addr2LineProcess(const char *path, const char *module_name)
+ : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
+
+ const char *module_name() const { return module_name_; }
+
+ private:
+ bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+ const char *module_name, uptr module_offset) const {
+ if (is_data)
+ return false;
+ CHECK_EQ(0, internal_strcmp(module_name, module_name_));
+ internal_snprintf(buffer, max_length, "0x%zx\n", module_offset);
+ return true;
+ }
+
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ // Output should consist of two lines.
+ int num_lines = 0;
+ for (uptr i = 0; i < length; ++i) {
+ if (buffer[i] == '\n')
+ num_lines++;
+ if (num_lines >= 2)
+ return true;
+ }
+ return false;
+ }
+
+ void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
+ }
+
+ const char *module_name_; // Owned, leaked.
+};
+
+class Addr2LinePool : public ExternalSymbolizerInterface {
+ public:
+ explicit Addr2LinePool(const char *addr2line_path,
+ LowLevelAllocator *allocator)
+ : addr2line_path_(addr2line_path), allocator_(allocator),
+ addr2line_pool_(16) {}
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ if (is_data)
+ return 0;
+ Addr2LineProcess *addr2line = 0;
+ for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
+ if (0 ==
+ internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
+ addr2line = addr2line_pool_[i];
+ break;
+ }
+ }
+ if (!addr2line) {
+ addr2line =
+ new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
+ addr2line_pool_.push_back(addr2line);
+ }
+ return addr2line->SendCommand(is_data, module_name, module_offset);
+ }
+
+ private:
+ const char *addr2line_path_;
+ LowLevelAllocator *allocator_;
+ InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
+};
+
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_symbolize_flush();
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
+ int MaxLength);
+} // extern "C"
+
+class InternalSymbolizer {
+ public:
+ typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
+
+ static InternalSymbolizer *get(LowLevelAllocator *alloc) {
+ if (__sanitizer_symbolize_code != 0 &&
+ __sanitizer_symbolize_data != 0) {
+ return new(*alloc) InternalSymbolizer();
+ }
+ return 0;
+ }
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
+ : __sanitizer_symbolize_code;
+ if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
+ return buffer_;
+ return 0;
+ }
+
+ void Flush() {
+ if (__sanitizer_symbolize_flush)
+ __sanitizer_symbolize_flush();
+ }
+
+ const char *Demangle(const char *name) {
+ if (__sanitizer_symbolize_demangle) {
+ for (uptr res_length = 1024;
+ res_length <= InternalSizeClassMap::kMaxSize;) {
+ char *res_buff = static_cast<char*>(InternalAlloc(res_length));
+ uptr req_length =
+ __sanitizer_symbolize_demangle(name, res_buff, res_length);
+ if (req_length > res_length) {
+ res_length = req_length + 1;
+ InternalFree(res_buff);
+ continue;
+ }
+ return res_buff;
+ }
+ }
+ return name;
+ }
+
+ private:
+ InternalSymbolizer() { }
+
+ static const int kBufferSize = 16 * 1024;
+ static const int kMaxDemangledNameSize = 1024;
+ char buffer_[kBufferSize];
+};
+#else // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class InternalSymbolizer {
+ public:
+ static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ return 0;
+ }
+ void Flush() { }
+ const char *Demangle(const char *name) { return name; }
+};
+
+#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class POSIXSymbolizer : public Symbolizer {
+ public:
+ POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer,
+ InternalSymbolizer *internal_symbolizer,
+ LibbacktraceSymbolizer *libbacktrace_symbolizer)
+ : Symbolizer(),
+ external_symbolizer_(external_symbolizer),
+ internal_symbolizer_(internal_symbolizer),
+ libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
+
+ SymbolizedStack *SymbolizePC(uptr addr) override {
+ BlockingMutexLock l(&mu_);
+ const char *module_name;
+ uptr module_offset;
+ if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+ return SymbolizedStack::New(addr);
+ // First, try to use libbacktrace symbolizer (if it's available).
+ if (libbacktrace_symbolizer_ != 0) {
+ mu_.CheckLocked();
+ if (SymbolizedStack *res = libbacktrace_symbolizer_->SymbolizeCode(
+ addr, module_name, module_offset))
+ return res;
+ }
+ // Always fill data about module name and offset.
+ SymbolizedStack *res = SymbolizedStack::New(addr);
+ res->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
+
+ const char *str = SendCommand(false, module_name, module_offset);
+ if (str == 0) {
+ // Symbolizer was not initialized or failed.
+ return res;
+ }
+
+ bool top_frame = true;
+ SymbolizedStack *last = res;
+ while (true) {
+ char *function_name = 0;
+ str = ExtractToken(str, "\n", &function_name);
+ CHECK(function_name);
+ if (function_name[0] == '\0') {
+ // There are no more frames.
+ break;
+ }
+ SymbolizedStack *cur;
+ if (top_frame) {
+ cur = res;
+ top_frame = false;
+ } else {
+ cur = SymbolizedStack::New(addr);
+ cur->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
+ last->next = cur;
+ last = cur;
+ }
+
+ AddressInfo *info = &cur->info;
+ info->function = function_name;
+ // Parse <file>:<line>:<column> buffer.
+ char *file_line_info = 0;
+ str = ExtractToken(str, "\n", &file_line_info);
+ CHECK(file_line_info);
+ const char *line_info = ExtractToken(file_line_info, ":", &info->file);
+ line_info = ExtractInt(line_info, ":", &info->line);
+ line_info = ExtractInt(line_info, "", &info->column);
+ InternalFree(file_line_info);
+
+ // Functions and filenames can be "??", in which case we write 0
+ // to address info to mark that names are unknown.
+ if (0 == internal_strcmp(info->function, "??")) {
+ InternalFree(info->function);
+ info->function = 0;
+ }
+ if (0 == internal_strcmp(info->file, "??")) {
+ InternalFree(info->file);
+ info->file = 0;
+ }
+ }
+ return res;
+ }
+
+ bool SymbolizeData(uptr addr, DataInfo *info) override {
+ BlockingMutexLock l(&mu_);
+ LoadedModule *module = FindModuleForAddress(addr);
+ if (module == 0)
+ return false;
+ const char *module_name = module->full_name();
+ uptr module_offset = addr - module->base_address();
+ info->Clear();
+ info->module = internal_strdup(module_name);
+ info->module_offset = module_offset;
+ // First, try to use libbacktrace symbolizer (if it's available).
+ if (libbacktrace_symbolizer_ != 0) {
+ mu_.CheckLocked();
+ if (libbacktrace_symbolizer_->SymbolizeData(addr, info))
+ return true;
+ }
+ const char *str = SendCommand(true, module_name, module_offset);
+ if (str == 0)
+ return true;
+ str = ExtractToken(str, "\n", &info->name);
+ str = ExtractUptr(str, " ", &info->start);
+ str = ExtractUptr(str, "\n", &info->size);
+ info->start += module->base_address();
+ return true;
+ }
+
+ bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+ uptr *module_address) override {
+ BlockingMutexLock l(&mu_);
+ return FindModuleNameAndOffsetForAddress(pc, module_name, module_address);
+ }
+
+ bool CanReturnFileLineInfo() override {
+ return internal_symbolizer_ != 0 || external_symbolizer_ != 0 ||
+ libbacktrace_symbolizer_ != 0;
+ }
+
+ void Flush() override {
+ BlockingMutexLock l(&mu_);
+ if (internal_symbolizer_ != 0) {
+ SymbolizerScope sym_scope(this);
+ internal_symbolizer_->Flush();
+ }
+ }
+
+ const char *Demangle(const char *name) override {
+ BlockingMutexLock l(&mu_);
+ // Run hooks even if we don't use internal symbolizer, as cxxabi
+ // demangle may call system functions.
+ SymbolizerScope sym_scope(this);
+ // Try to use libbacktrace demangler (if available).
+ if (libbacktrace_symbolizer_ != 0) {
+ if (const char *demangled = libbacktrace_symbolizer_->Demangle(name))
+ return demangled;
+ }
+ if (internal_symbolizer_ != 0)
+ return internal_symbolizer_->Demangle(name);
+ return DemangleCXXABI(name);
+ }
+
+ void PrepareForSandboxing() override {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ BlockingMutexLock l(&mu_);
+ // Cache /proc/self/exe on Linux.
+ CacheBinaryName();
+#endif
+ }
+
+ private:
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ mu_.CheckLocked();
+ // First, try to use internal symbolizer.
+ if (internal_symbolizer_) {
+ SymbolizerScope sym_scope(this);
+ return internal_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
+ }
+ // Otherwise, fall back to external symbolizer.
+ if (external_symbolizer_) {
+ SymbolizerScope sym_scope(this);
+ return external_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
+ }
+ return 0;
+ }
+
+ LoadedModule *FindModuleForAddress(uptr address) {
+ mu_.CheckLocked();
+ bool modules_were_reloaded = false;
+ if (modules_ == 0 || !modules_fresh_) {
+ modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate(
+ kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
+ CHECK(modules_);
+ n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
+ /* filter */ 0);
+ CHECK_GT(n_modules_, 0);
+ CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
+ modules_fresh_ = true;
+ modules_were_reloaded = true;
+ }
+ for (uptr i = 0; i < n_modules_; i++) {
+ if (modules_[i].containsAddress(address)) {
+ return &modules_[i];
+ }
+ }
+ // Reload the modules and look up again, if we haven't tried it yet.
+ if (!modules_were_reloaded) {
+ // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+ // It's too aggressive to reload the list of modules each time we fail
+ // to find a module for a given address.
+ modules_fresh_ = false;
+ return FindModuleForAddress(address);
+ }
+ return 0;
+ }
+
+ bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
+ uptr *module_offset) {
+ mu_.CheckLocked();
+ LoadedModule *module = FindModuleForAddress(address);
+ if (module == 0)
+ return false;
+ *module_name = module->full_name();
+ *module_offset = address - module->base_address();
+ return true;
+ }
+
+ // 16K loaded modules should be enough for everyone.
+ static const uptr kMaxNumberOfModuleContexts = 1 << 14;
+ LoadedModule *modules_; // Array of module descriptions is leaked.
+ uptr n_modules_;
+ // If stale, need to reload the modules before looking up addresses.
+ bool modules_fresh_;
+ BlockingMutex mu_;
+
+ ExternalSymbolizerInterface *external_symbolizer_; // Leaked.
+ InternalSymbolizer *const internal_symbolizer_; // Leaked.
+ LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked.
+};
+
+Symbolizer *Symbolizer::PlatformInit() {
+ if (!common_flags()->symbolize) {
+ return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0);
+ }
+ InternalSymbolizer* internal_symbolizer =
+ InternalSymbolizer::get(&symbolizer_allocator_);
+ ExternalSymbolizerInterface *external_symbolizer = 0;
+ LibbacktraceSymbolizer *libbacktrace_symbolizer = 0;
+
+ if (!internal_symbolizer) {
+ libbacktrace_symbolizer =
+ LibbacktraceSymbolizer::get(&symbolizer_allocator_);
+ if (!libbacktrace_symbolizer) {
+ const char *path_to_external = common_flags()->external_symbolizer_path;
+ if (path_to_external && path_to_external[0] == '\0') {
+ // External symbolizer is explicitly disabled. Do nothing.
+ } else {
+ // Find path to llvm-symbolizer if it's not provided.
+ if (!path_to_external)
+ path_to_external = FindPathToBinary("llvm-symbolizer");
+ if (path_to_external) {
+ external_symbolizer = new(symbolizer_allocator_)
+ LLVMSymbolizerProcess(path_to_external);
+ } else if (common_flags()->allow_addr2line) {
+ // If llvm-symbolizer is not found, try to use addr2line.
+ if (const char *addr2line_path = FindPathToBinary("addr2line")) {
+ external_symbolizer = new(symbolizer_allocator_)
+ Addr2LinePool(addr2line_path, &symbolizer_allocator_);
+ }
+ }
+ }
+ }
+ }
+
+ return new(symbolizer_allocator_) POSIXSymbolizer(
+ external_symbolizer, internal_symbolizer, libbacktrace_symbolizer);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc
new file mode 100644
index 000000000000..ed96a3a895a8
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -0,0 +1,158 @@
+//===-- sanitizer_symbolizer_win.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Windows-specific implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+#include <windows.h>
+#include <dbghelp.h>
+#pragma comment(lib, "dbghelp.lib")
+
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+class WinSymbolizer : public Symbolizer {
+ public:
+ WinSymbolizer() : initialized_(false) {}
+
+ SymbolizedStack *SymbolizePC(uptr addr) override {
+ SymbolizedStack *frame = SymbolizedStack::New(addr);
+
+ BlockingMutexLock l(&dbghelp_mu_);
+ InitializeIfNeeded();
+
+ // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+ char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
+ PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ symbol->MaxNameLen = MAX_SYM_NAME;
+ DWORD64 offset = 0;
+ BOOL got_objname = SymFromAddr(GetCurrentProcess(),
+ (DWORD64)addr, &offset, symbol);
+ if (!got_objname)
+ return frame;
+
+ DWORD unused;
+ IMAGEHLP_LINE64 line_info;
+ line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+ BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
+ &unused, &line_info);
+ frame->info.function = internal_strdup(symbol->Name);
+ frame->info.function_offset = (uptr)offset;
+ if (got_fileline) {
+ frame->info.file = internal_strdup(line_info.FileName);
+ frame->info.line = line_info.LineNumber;
+ }
+
+ IMAGEHLP_MODULE64 mod_info;
+ internal_memset(&mod_info, 0, sizeof(mod_info));
+ mod_info.SizeOfStruct = sizeof(mod_info);
+ if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info))
+ frame->info.FillAddressAndModuleInfo(addr, mod_info.ImageName,
+ addr - (uptr)mod_info.BaseOfImage);
+ return frame;
+ }
+
+ bool CanReturnFileLineInfo() override {
+ return true;
+ }
+
+ const char *Demangle(const char *name) override {
+ CHECK(initialized_);
+ static char demangle_buffer[1000];
+ if (name[0] == '\01' &&
+ UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
+ UNDNAME_NAME_ONLY))
+ return demangle_buffer;
+ else
+ return name;
+ }
+
+ // FIXME: Implement GetModuleNameAndOffsetForPC().
+
+ private:
+ void InitializeIfNeeded() {
+ if (initialized_)
+ return;
+ if (!TrySymInitialize()) {
+ // OK, maybe the client app has called SymInitialize already.
+ // That's a bit unfortunate for us as all the DbgHelp functions are
+ // single-threaded and we can't coordinate with the app.
+ // FIXME: Can we stop the other threads at this point?
+ // Anyways, we have to reconfigure stuff to make sure that SymInitialize
+ // has all the appropriate options set.
+ // Cross our fingers and reinitialize DbgHelp.
+ Report("*** WARNING: Failed to initialize DbgHelp! ***\n");
+ Report("*** Most likely this means that the app is already ***\n");
+ Report("*** using DbgHelp, possibly with incompatible flags. ***\n");
+ Report("*** Due to technical reasons, symbolization might crash ***\n");
+ Report("*** or produce wrong results. ***\n");
+ SymCleanup(GetCurrentProcess());
+ TrySymInitialize();
+ }
+ initialized_ = true;
+
+ // When an executable is run from a location different from the one where it
+ // was originally built, we may not see the nearby PDB files.
+ // To work around this, let's append the directory of the main module
+ // to the symbol search path. All the failures below are not fatal.
+ const size_t kSymPathSize = 2048;
+ static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH];
+ if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) {
+ Report("*** WARNING: Failed to SymGetSearchPathW ***\n");
+ return;
+ }
+ size_t sz = wcslen(path_buffer);
+ if (sz) {
+ CHECK_EQ(0, wcscat_s(path_buffer, L";"));
+ sz++;
+ }
+ DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH);
+ if (res == 0 || res == MAX_PATH) {
+ Report("*** WARNING: Failed to getting the EXE directory ***\n");
+ return;
+ }
+ // Write the zero character in place of the last backslash to get the
+ // directory of the main module at the end of path_buffer.
+ wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\');
+ CHECK_NE(last_bslash, 0);
+ *last_bslash = L'\0';
+ if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) {
+ Report("*** WARNING: Failed to SymSetSearchPathW\n");
+ return;
+ }
+ }
+
+ bool TrySymInitialize() {
+ SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
+ return SymInitialize(GetCurrentProcess(), 0, TRUE);
+ // FIXME: We don't call SymCleanup() on exit yet - should we?
+ }
+
+ // All DbgHelp functions are single threaded, so we should use a mutex to
+ // serialize accesses.
+ BlockingMutex dbghelp_mu_;
+ bool initialized_;
+};
+
+Symbolizer *Symbolizer::PlatformInit() {
+ static bool called_once = false;
+ CHECK(!called_once && "Shouldn't create more than one symbolizer");
+ called_once = true;
+ return new(symbolizer_allocator_) WinSymbolizer();
+}
+
+} // namespace __sanitizer
+
+#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
new file mode 100644
index 000000000000..15cf05f06087
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -0,0 +1,34 @@
+//===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic implementations of internal_syscall and internal_iserror.
+//
+//===----------------------------------------------------------------------===//
+
+#if SANITIZER_FREEBSD || SANITIZER_MAC
+# define SYSCALL(name) SYS_ ## name
+#else
+# define SYSCALL(name) __NR_ ## name
+#endif
+
+#if (SANITIZER_FREEBSD || SANITIZER_MAC) && defined(__x86_64__)
+# define internal_syscall __syscall
+# else
+# define internal_syscall syscall
+#endif
+
+bool internal_iserror(uptr retval, int *rverrno) {
+ if (retval == (uptr)-1) {
+ if (rverrno)
+ *rverrno = errno;
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
new file mode 100644
index 000000000000..9853a6a675d3
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
@@ -0,0 +1,91 @@
+//===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of internal_syscall and internal_iserror for Linux/x86_64.
+//
+//===----------------------------------------------------------------------===//
+
+#define SYSCALL(name) __NR_ ## name
+
+static uptr internal_syscall(u64 nr) {
+ u64 retval;
+ asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11",
+ "memory", "cc");
+ return retval;
+}
+
+template <typename T1>
+static uptr internal_syscall(u64 nr, T1 arg1) {
+ u64 retval;
+ asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) :
+ "rcx", "r11", "memory", "cc");
+ return retval;
+}
+
+template <typename T1, typename T2>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) {
+ u64 retval;
+ asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+ "S"((u64)arg2) : "rcx", "r11", "memory", "cc");
+ return retval;
+}
+
+template <typename T1, typename T2, typename T3>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) {
+ u64 retval;
+ asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+ "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11", "memory", "cc");
+ return retval;
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
+ u64 retval;
+ asm volatile("mov %5, %%r10;"
+ "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+ "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) :
+ "rcx", "r11", "r10", "memory", "cc");
+ return retval;
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
+ T5 arg5) {
+ u64 retval;
+ asm volatile("mov %5, %%r10;"
+ "mov %6, %%r8;"
+ "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+ "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) :
+ "rcx", "r11", "r10", "r8", "memory", "cc");
+ return retval;
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
+ T5 arg5, T6 arg6) {
+ u64 retval;
+ asm volatile("mov %5, %%r10;"
+ "mov %6, %%r8;"
+ "mov %7, %%r9;"
+ "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+ "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5),
+ "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9",
+ "memory", "cc");
+ return retval;
+}
+
+bool internal_iserror(uptr retval, int *rverrno) {
+ if (retval >= (uptr)-4095) {
+ if (rverrno)
+ *rverrno = -retval;
+ return true;
+ }
+ return false;
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cc
new file mode 100644
index 000000000000..2ec92ffd385f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -0,0 +1,301 @@
+//===-- sanitizer_thread_registry.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 shared between sanitizer tools.
+//
+// General thread bookkeeping functionality.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_thread_registry.h"
+
+namespace __sanitizer {
+
+ThreadContextBase::ThreadContextBase(u32 tid)
+ : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
+ status(ThreadStatusInvalid),
+ detached(false), parent_tid(0), next(0) {
+ name[0] = '\0';
+}
+
+ThreadContextBase::~ThreadContextBase() {
+ // ThreadContextBase should never be deleted.
+ CHECK(0);
+}
+
+void ThreadContextBase::SetName(const char *new_name) {
+ name[0] = '\0';
+ if (new_name) {
+ internal_strncpy(name, new_name, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+ }
+}
+
+void ThreadContextBase::SetDead() {
+ CHECK(status == ThreadStatusRunning ||
+ status == ThreadStatusFinished);
+ status = ThreadStatusDead;
+ user_id = 0;
+ OnDead();
+}
+
+void ThreadContextBase::SetJoined(void *arg) {
+ // FIXME(dvyukov): print message and continue (it's user error).
+ CHECK_EQ(false, detached);
+ CHECK_EQ(ThreadStatusFinished, status);
+ status = ThreadStatusDead;
+ user_id = 0;
+ OnJoined(arg);
+}
+
+void ThreadContextBase::SetFinished() {
+ if (!detached)
+ status = ThreadStatusFinished;
+ OnFinished();
+}
+
+void ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
+ status = ThreadStatusRunning;
+ os_id = _os_id;
+ OnStarted(arg);
+}
+
+void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
+ bool _detached, u32 _parent_tid, void *arg) {
+ status = ThreadStatusCreated;
+ user_id = _user_id;
+ unique_id = _unique_id;
+ detached = _detached;
+ // Parent tid makes no sense for the main thread.
+ if (tid != 0)
+ parent_tid = _parent_tid;
+ OnCreated(arg);
+}
+
+void ThreadContextBase::Reset() {
+ status = ThreadStatusInvalid;
+ SetName(0);
+ OnReset();
+}
+
+// ThreadRegistry implementation.
+
+const u32 ThreadRegistry::kUnknownTid = ~0U;
+
+ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
+ u32 thread_quarantine_size, u32 max_reuse)
+ : context_factory_(factory),
+ max_threads_(max_threads),
+ thread_quarantine_size_(thread_quarantine_size),
+ max_reuse_(max_reuse),
+ mtx_(),
+ n_contexts_(0),
+ total_threads_(0),
+ alive_threads_(0),
+ max_alive_threads_(0),
+ running_threads_(0) {
+ threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
+ "ThreadRegistry");
+ dead_threads_.clear();
+ invalid_threads_.clear();
+}
+
+void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
+ uptr *alive) {
+ BlockingMutexLock l(&mtx_);
+ if (total) *total = n_contexts_;
+ if (running) *running = running_threads_;
+ if (alive) *alive = alive_threads_;
+}
+
+uptr ThreadRegistry::GetMaxAliveThreads() {
+ BlockingMutexLock l(&mtx_);
+ return max_alive_threads_;
+}
+
+u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
+ void *arg) {
+ BlockingMutexLock l(&mtx_);
+ u32 tid = kUnknownTid;
+ ThreadContextBase *tctx = QuarantinePop();
+ if (tctx) {
+ tid = tctx->tid;
+ } else if (n_contexts_ < max_threads_) {
+ // Allocate new thread context and tid.
+ tid = n_contexts_++;
+ tctx = context_factory_(tid);
+ threads_[tid] = tctx;
+ } else {
+#ifndef SANITIZER_GO
+ Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
+ SanitizerToolName, max_threads_);
+#else
+ Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
+ " dying\n", max_threads_);
+#endif
+ Die();
+ }
+ CHECK_NE(tctx, 0);
+ CHECK_NE(tid, kUnknownTid);
+ CHECK_LT(tid, max_threads_);
+ CHECK_EQ(tctx->status, ThreadStatusInvalid);
+ alive_threads_++;
+ if (max_alive_threads_ < alive_threads_) {
+ max_alive_threads_++;
+ CHECK_EQ(alive_threads_, max_alive_threads_);
+ }
+ tctx->SetCreated(user_id, total_threads_++, detached,
+ parent_tid, arg);
+ return tid;
+}
+
+void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
+ void *arg) {
+ CheckLocked();
+ for (u32 tid = 0; tid < n_contexts_; tid++) {
+ ThreadContextBase *tctx = threads_[tid];
+ if (tctx == 0)
+ continue;
+ cb(tctx, arg);
+ }
+}
+
+u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
+ BlockingMutexLock l(&mtx_);
+ for (u32 tid = 0; tid < n_contexts_; tid++) {
+ ThreadContextBase *tctx = threads_[tid];
+ if (tctx != 0 && cb(tctx, arg))
+ return tctx->tid;
+ }
+ return kUnknownTid;
+}
+
+ThreadContextBase *
+ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
+ CheckLocked();
+ for (u32 tid = 0; tid < n_contexts_; tid++) {
+ ThreadContextBase *tctx = threads_[tid];
+ if (tctx != 0 && cb(tctx, arg))
+ return tctx;
+ }
+ return 0;
+}
+
+static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
+ void *arg) {
+ return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
+ tctx->status != ThreadStatusDead);
+}
+
+ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) {
+ return FindThreadContextLocked(FindThreadContextByOsIdCallback,
+ (void *)os_id);
+}
+
+void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
+ BlockingMutexLock l(&mtx_);
+ CHECK_LT(tid, n_contexts_);
+ ThreadContextBase *tctx = threads_[tid];
+ CHECK_NE(tctx, 0);
+ CHECK_EQ(ThreadStatusRunning, tctx->status);
+ tctx->SetName(name);
+}
+
+void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
+ BlockingMutexLock l(&mtx_);
+ for (u32 tid = 0; tid < n_contexts_; tid++) {
+ ThreadContextBase *tctx = threads_[tid];
+ if (tctx != 0 && tctx->user_id == user_id &&
+ tctx->status != ThreadStatusInvalid) {
+ tctx->SetName(name);
+ return;
+ }
+ }
+}
+
+void ThreadRegistry::DetachThread(u32 tid, void *arg) {
+ BlockingMutexLock l(&mtx_);
+ CHECK_LT(tid, n_contexts_);
+ ThreadContextBase *tctx = threads_[tid];
+ CHECK_NE(tctx, 0);
+ if (tctx->status == ThreadStatusInvalid) {
+ Report("%s: Detach of non-existent thread\n", SanitizerToolName);
+ return;
+ }
+ tctx->OnDetached(arg);
+ if (tctx->status == ThreadStatusFinished) {
+ tctx->SetDead();
+ QuarantinePush(tctx);
+ } else {
+ tctx->detached = true;
+ }
+}
+
+void ThreadRegistry::JoinThread(u32 tid, void *arg) {
+ BlockingMutexLock l(&mtx_);
+ CHECK_LT(tid, n_contexts_);
+ ThreadContextBase *tctx = threads_[tid];
+ CHECK_NE(tctx, 0);
+ if (tctx->status == ThreadStatusInvalid) {
+ Report("%s: Join of non-existent thread\n", SanitizerToolName);
+ return;
+ }
+ tctx->SetJoined(arg);
+ QuarantinePush(tctx);
+}
+
+void ThreadRegistry::FinishThread(u32 tid) {
+ BlockingMutexLock l(&mtx_);
+ CHECK_GT(alive_threads_, 0);
+ alive_threads_--;
+ CHECK_GT(running_threads_, 0);
+ running_threads_--;
+ CHECK_LT(tid, n_contexts_);
+ ThreadContextBase *tctx = threads_[tid];
+ CHECK_NE(tctx, 0);
+ CHECK_EQ(ThreadStatusRunning, tctx->status);
+ tctx->SetFinished();
+ if (tctx->detached) {
+ tctx->SetDead();
+ QuarantinePush(tctx);
+ }
+}
+
+void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
+ BlockingMutexLock l(&mtx_);
+ running_threads_++;
+ CHECK_LT(tid, n_contexts_);
+ ThreadContextBase *tctx = threads_[tid];
+ CHECK_NE(tctx, 0);
+ CHECK_EQ(ThreadStatusCreated, tctx->status);
+ tctx->SetStarted(os_id, arg);
+}
+
+void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
+ dead_threads_.push_back(tctx);
+ if (dead_threads_.size() <= thread_quarantine_size_)
+ return;
+ tctx = dead_threads_.front();
+ dead_threads_.pop_front();
+ CHECK_EQ(tctx->status, ThreadStatusDead);
+ tctx->Reset();
+ tctx->reuse_count++;
+ if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
+ return;
+ invalid_threads_.push_back(tctx);
+}
+
+ThreadContextBase *ThreadRegistry::QuarantinePop() {
+ if (invalid_threads_.size() == 0)
+ return 0;
+ ThreadContextBase *tctx = invalid_threads_.front();
+ invalid_threads_.pop_front();
+ return tctx;
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
new file mode 100644
index 000000000000..5d9c3b9694e8
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -0,0 +1,148 @@
+//===-- sanitizer_thread_registry.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 shared between sanitizer tools.
+//
+// General thread bookkeeping functionality.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_THREAD_REGISTRY_H
+#define SANITIZER_THREAD_REGISTRY_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_list.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+enum ThreadStatus {
+ ThreadStatusInvalid, // Non-existent thread, data is invalid.
+ ThreadStatusCreated, // Created but not yet running.
+ ThreadStatusRunning, // The thread is currently running.
+ ThreadStatusFinished, // Joinable thread is finished but not yet joined.
+ ThreadStatusDead // Joined, but some info is still available.
+};
+
+// Generic thread context. Specific sanitizer tools may inherit from it.
+// If thread is dead, context may optionally be reused for a new thread.
+class ThreadContextBase {
+ public:
+ explicit ThreadContextBase(u32 tid);
+ ~ThreadContextBase(); // Should never be called.
+
+ const u32 tid; // Thread ID. Main thread should have tid = 0.
+ u64 unique_id; // Unique thread ID.
+ u32 reuse_count; // Number of times this tid was reused.
+ uptr os_id; // PID (used for reporting).
+ uptr user_id; // Some opaque user thread id (e.g. pthread_t).
+ char name[64]; // As annotated by user.
+
+ ThreadStatus status;
+ bool detached;
+
+ u32 parent_tid;
+ ThreadContextBase *next; // For storing thread contexts in a list.
+
+ void SetName(const char *new_name);
+
+ void SetDead();
+ void SetJoined(void *arg);
+ void SetFinished();
+ void SetStarted(uptr _os_id, void *arg);
+ void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
+ u32 _parent_tid, void *arg);
+ void Reset();
+
+ // The following methods may be overriden by subclasses.
+ // Some of them take opaque arg that may be optionally be used
+ // by subclasses.
+ virtual void OnDead() {}
+ virtual void OnJoined(void *arg) {}
+ virtual void OnFinished() {}
+ virtual void OnStarted(void *arg) {}
+ virtual void OnCreated(void *arg) {}
+ virtual void OnReset() {}
+ virtual void OnDetached(void *arg) {}
+};
+
+typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
+
+class ThreadRegistry {
+ public:
+ static const u32 kUnknownTid;
+
+ ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
+ u32 thread_quarantine_size, u32 max_reuse = 0);
+ void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0);
+ uptr GetMaxAliveThreads();
+
+ void Lock() { mtx_.Lock(); }
+ void CheckLocked() { mtx_.CheckLocked(); }
+ void Unlock() { mtx_.Unlock(); }
+
+ // Should be guarded by ThreadRegistryLock.
+ ThreadContextBase *GetThreadLocked(u32 tid) {
+ DCHECK_LT(tid, n_contexts_);
+ return threads_[tid];
+ }
+
+ u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
+
+ typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
+ // Invokes callback with a specified arg for each thread context.
+ // Should be guarded by ThreadRegistryLock.
+ void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
+
+ typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
+ // Finds a thread using the provided callback. Returns kUnknownTid if no
+ // thread is found.
+ u32 FindThread(FindThreadCallback cb, void *arg);
+ // Should be guarded by ThreadRegistryLock. Return 0 if no thread
+ // is found.
+ ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
+ void *arg);
+ ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id);
+
+ void SetThreadName(u32 tid, const char *name);
+ void SetThreadNameByUserId(uptr user_id, const char *name);
+ void DetachThread(u32 tid, void *arg);
+ void JoinThread(u32 tid, void *arg);
+ void FinishThread(u32 tid);
+ void StartThread(u32 tid, uptr os_id, void *arg);
+
+ private:
+ const ThreadContextFactory context_factory_;
+ const u32 max_threads_;
+ const u32 thread_quarantine_size_;
+ const u32 max_reuse_;
+
+ BlockingMutex mtx_;
+
+ u32 n_contexts_; // Number of created thread contexts,
+ // at most max_threads_.
+ u64 total_threads_; // Total number of created threads. May be greater than
+ // max_threads_ if contexts were reused.
+ uptr alive_threads_; // Created or running.
+ uptr max_alive_threads_;
+ uptr running_threads_;
+
+ ThreadContextBase **threads_; // Array of thread contexts is leaked.
+ IntrusiveList<ThreadContextBase> dead_threads_;
+ IntrusiveList<ThreadContextBase> invalid_threads_;
+
+ void QuarantinePush(ThreadContextBase *tctx);
+ ThreadContextBase *QuarantinePop();
+};
+
+typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_THREAD_REGISTRY_H
+
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc
new file mode 100644
index 000000000000..6142ce517db5
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc
@@ -0,0 +1,131 @@
+//===-- sanitizer_tls_get_addr.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handle the __tls_get_addr call.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_tls_get_addr.h"
+
+#include "sanitizer_flags.h"
+#include "sanitizer_platform_interceptors.h"
+
+namespace __sanitizer {
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+// The actual parameter that comes to __tls_get_addr
+// is a pointer to a struct with two words in it:
+struct TlsGetAddrParam {
+ uptr dso_id;
+ uptr offset;
+};
+
+// Glibc starting from 2.19 allocates tls using __signal_safe_memalign,
+// which has such header.
+struct Glibc_2_19_tls_header {
+ uptr size;
+ uptr start;
+};
+
+// This must be static TLS
+__attribute__((tls_model("initial-exec")))
+static __thread DTLS dtls;
+
+// Make sure we properly destroy the DTLS objects:
+// this counter should never get too large.
+static atomic_uintptr_t number_of_live_dtls;
+
+static const uptr kDestroyedThread = -1;
+
+static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
+ if (!size) return;
+ VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
+ UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
+ atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
+}
+
+static inline void DTLS_Resize(uptr new_size) {
+ if (dtls.dtv_size >= new_size) return;
+ new_size = RoundUpToPowerOfTwo(new_size);
+ new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
+ DTLS::DTV *new_dtv =
+ (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
+ uptr num_live_dtls =
+ atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
+ VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
+ CHECK_LT(num_live_dtls, 1 << 20);
+ uptr old_dtv_size = dtls.dtv_size;
+ DTLS::DTV *old_dtv = dtls.dtv;
+ if (old_dtv_size)
+ internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
+ dtls.dtv = new_dtv;
+ dtls.dtv_size = new_size;
+ if (old_dtv_size)
+ DTLS_Deallocate(old_dtv, old_dtv_size);
+}
+
+void DTLS_Destroy() {
+ if (!common_flags()->intercept_tls_get_addr) return;
+ VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
+ uptr s = dtls.dtv_size;
+ dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
+ DTLS_Deallocate(dtls.dtv, s);
+}
+
+DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res) {
+ if (!common_flags()->intercept_tls_get_addr) return 0;
+ TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
+ uptr dso_id = arg->dso_id;
+ if (dtls.dtv_size == kDestroyedThread) return 0;
+ DTLS_Resize(dso_id + 1);
+ if (dtls.dtv[dso_id].beg) return 0;
+ uptr tls_size = 0;
+ uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset;
+ VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
+ "num_live_dtls %zd\n",
+ arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
+ atomic_load(&number_of_live_dtls, memory_order_relaxed));
+ if (dtls.last_memalign_ptr == tls_beg) {
+ tls_size = dtls.last_memalign_size;
+ VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
+ tls_beg, tls_size);
+ } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) {
+ // We may want to check gnu_get_libc_version().
+ Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1;
+ tls_size = header->size;
+ tls_beg = header->start;
+ VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
+ tls_beg, tls_size);
+ } else {
+ VPrintf(2, "__tls_get_addr: Can't guess glibc version\n");
+ // This may happen inside the DTOR of main thread, so just ignore it.
+ tls_size = 0;
+ }
+ dtls.dtv[dso_id].beg = tls_beg;
+ dtls.dtv[dso_id].size = tls_size;
+ return dtls.dtv + dso_id;
+}
+
+void DTLS_on_libc_memalign(void *ptr, uptr size) {
+ if (!common_flags()->intercept_tls_get_addr) return;
+ VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
+ dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr);
+ dtls.last_memalign_size = size;
+}
+
+DTLS *DTLS_Get() { return &dtls; }
+
+#else
+void DTLS_on_libc_memalign(void *ptr, uptr size) {}
+DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; }
+DTLS *DTLS_Get() { return 0; }
+void DTLS_Destroy() {}
+#endif // SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h
new file mode 100644
index 000000000000..0fc9a2257c68
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h
@@ -0,0 +1,60 @@
+//===-- sanitizer_tls_get_addr.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handle the __tls_get_addr call.
+//
+// All this magic is specific to glibc and is required to workaround
+// the lack of interface that would tell us about the Dynamic TLS (DTLS).
+// https://sourceware.org/bugzilla/show_bug.cgi?id=16291
+//
+// The matters get worse because the glibc implementation changed between
+// 2.18 and 2.19:
+// https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM
+//
+// Before 2.19, every DTLS chunk is allocated with __libc_memalign,
+// which we intercept and thus know where is the DTLS.
+// Since 2.19, DTLS chunks are allocated with __signal_safe_memalign,
+// which is an internal function that wraps a mmap call, neither of which
+// we can intercept. Luckily, __signal_safe_memalign has a simple parseable
+// header which we can use.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_TLS_GET_ADDR_H
+#define SANITIZER_TLS_GET_ADDR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+struct DTLS {
+ // Array of DTLS chunks for the current Thread.
+ // If beg == 0, the chunk is unused.
+ struct DTV {
+ uptr beg, size;
+ };
+
+ uptr dtv_size;
+ DTV *dtv; // dtv_size elements, allocated by MmapOrDie.
+
+ // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cc
+ uptr last_memalign_size;
+ uptr last_memalign_ptr;
+};
+
+// Returns pointer and size of a linker-allocated TLS block.
+// Each block is returned exactly once.
+DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res);
+void DTLS_on_libc_memalign(void *ptr, uptr size);
+DTLS *DTLS_Get();
+void DTLS_Destroy(); // Make sure to call this before the thread is destroyed.
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_TLS_GET_ADDR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
new file mode 100644
index 000000000000..7ab2efbd75bd
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
@@ -0,0 +1,158 @@
+//===-- sanitizer_unwind_posix.cc ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the unwind.h-based (aka "slow") stack unwinding routines
+// available to the tools on Linux, Android, FreeBSD and OS X.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common.h"
+#include "sanitizer_stacktrace.h"
+
+#if SANITIZER_ANDROID
+#include <dlfcn.h> // for dlopen()
+#endif
+
+#if SANITIZER_FREEBSD
+#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h>
+#endif
+#include <unwind.h>
+
+namespace __sanitizer {
+
+//------------------------- SlowUnwindStack -----------------------------------
+
+typedef struct {
+ uptr absolute_pc;
+ uptr stack_top;
+ uptr stack_size;
+} backtrace_frame_t;
+
+extern "C" {
+typedef void *(*acquire_my_map_info_list_func)();
+typedef void (*release_my_map_info_list_func)(void *map);
+typedef sptr (*unwind_backtrace_signal_arch_func)(
+ void *siginfo, void *sigcontext, void *map_info_list,
+ backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
+acquire_my_map_info_list_func acquire_my_map_info_list;
+release_my_map_info_list_func release_my_map_info_list;
+unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
+} // extern "C"
+
+#if SANITIZER_ANDROID
+void SanitizerInitializeUnwinder() {
+ void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
+ if (!p) {
+ VReport(1,
+ "Failed to open libcorkscrew.so. You may see broken stack traces "
+ "in SEGV reports.");
+ return;
+ }
+ acquire_my_map_info_list =
+ (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
+ release_my_map_info_list =
+ (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
+ unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
+ p, "unwind_backtrace_signal_arch");
+ if (!acquire_my_map_info_list || !release_my_map_info_list ||
+ !unwind_backtrace_signal_arch) {
+ VReport(1,
+ "Failed to find one of the required symbols in libcorkscrew.so. "
+ "You may see broken stack traces in SEGV reports.");
+ acquire_my_map_info_list = 0;
+ unwind_backtrace_signal_arch = 0;
+ release_my_map_info_list = 0;
+ }
+}
+#endif
+
+#ifdef __arm__
+#define UNWIND_STOP _URC_END_OF_STACK
+#define UNWIND_CONTINUE _URC_NO_REASON
+#else
+#define UNWIND_STOP _URC_NORMAL_STOP
+#define UNWIND_CONTINUE _URC_NO_REASON
+#endif
+
+uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
+#ifdef __arm__
+ uptr val;
+ _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
+ 15 /* r15 = PC */, _UVRSD_UINT32, &val);
+ CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
+ // Clear the Thumb bit.
+ return val & ~(uptr)1;
+#else
+ return _Unwind_GetIP(ctx);
+#endif
+}
+
+struct UnwindTraceArg {
+ BufferedStackTrace *stack;
+ u32 max_depth;
+};
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+ UnwindTraceArg *arg = (UnwindTraceArg*)param;
+ CHECK_LT(arg->stack->size, arg->max_depth);
+ uptr pc = Unwind_GetIP(ctx);
+ arg->stack->trace_buffer[arg->stack->size++] = pc;
+ if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
+ return UNWIND_CONTINUE;
+}
+
+void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
+ CHECK_GE(max_depth, 2);
+ size = 0;
+ UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
+ _Unwind_Backtrace(Unwind_Trace, &arg);
+ // We need to pop a few frames so that pc is on top.
+ uptr to_pop = LocatePcInTrace(pc);
+ // trace_buffer[0] belongs to the current function so we always pop it,
+ // unless there is only 1 frame in the stack trace (1 frame is always better
+ // than 0!).
+ // 1-frame stacks don't normally happen, but this depends on the actual
+ // unwinder implementation (libgcc, libunwind, etc) which is outside of our
+ // control.
+ if (to_pop == 0 && size > 1)
+ to_pop = 1;
+ PopStackFrames(to_pop);
+ trace_buffer[0] = pc;
+}
+
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+ u32 max_depth) {
+ CHECK_GE(max_depth, 2);
+ if (!unwind_backtrace_signal_arch) {
+ SlowUnwindStack(pc, max_depth);
+ return;
+ }
+
+ void *map = acquire_my_map_info_list();
+ CHECK(map);
+ InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax);
+ // siginfo argument appears to be unused.
+ sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,
+ frames.data(),
+ /* ignore_depth */ 0, max_depth);
+ release_my_map_info_list(map);
+ if (res < 0) return;
+ CHECK_LE((uptr)res, kStackTraceMax);
+
+ size = 0;
+ // +2 compensate for libcorkscrew unwinder returning addresses of call
+ // instructions instead of raw return addresses.
+ for (sptr i = 0; i < res; ++i)
+ trace_buffer[size++] = frames[i].absolute_pc + 2;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
new file mode 100644
index 000000000000..335cecabe118
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
@@ -0,0 +1,623 @@
+//===-- sanitizer_win.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements windows-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
+#define WIN32_LEAN_AND_MEAN
+#define NOGDI
+#include <windows.h>
+#include <dbghelp.h>
+#include <io.h>
+#include <psapi.h>
+#include <stdlib.h>
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_stacktrace.h"
+
+namespace __sanitizer {
+
+#include "sanitizer_syscall_generic.inc"
+
+// --------------------- sanitizer_common.h
+uptr GetPageSize() {
+ return 1U << 14; // FIXME: is this configurable?
+}
+
+uptr GetMmapGranularity() {
+ return 1U << 16; // FIXME: is this configurable?
+}
+
+uptr GetMaxVirtualAddress() {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return (uptr)si.lpMaximumApplicationAddress;
+}
+
+bool FileExists(const char *filename) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_getpid() {
+ return GetProcessId(GetCurrentProcess());
+}
+
+// In contrast to POSIX, on Windows GetCurrentThreadId()
+// returns a system-unique identifier.
+uptr GetTid() {
+ return GetCurrentThreadId();
+}
+
+uptr GetThreadSelf() {
+ return GetTid();
+}
+
+#if !SANITIZER_GO
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom) {
+ CHECK(stack_top);
+ CHECK(stack_bottom);
+ MEMORY_BASIC_INFORMATION mbi;
+ CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
+ // FIXME: is it possible for the stack to not be a single allocation?
+ // Are these values what ASan expects to get (reserved, not committed;
+ // including stack guard page) ?
+ *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
+ *stack_bottom = (uptr)mbi.AllocationBase;
+}
+#endif // #if !SANITIZER_GO
+
+void *MmapOrDie(uptr size, const char *mem_type) {
+ void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (rv == 0) {
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
+ SanitizerToolName, size, size, mem_type, GetLastError());
+ CHECK("unable to mmap" && 0);
+ }
+ return rv;
+}
+
+void UnmapOrDie(void *addr, uptr size) {
+ if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
+ Report("ERROR: %s failed to "
+ "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
+ SanitizerToolName, size, size, addr, GetLastError());
+ CHECK("unable to unmap" && 0);
+ }
+}
+
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
+ // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
+ // but on Win64 it does.
+ void *p = VirtualAlloc((LPVOID)fixed_addr, size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (p == 0)
+ Report("ERROR: %s failed to "
+ "allocate %p (%zd) bytes at %p (error code: %d)\n",
+ SanitizerToolName, size, size, fixed_addr, GetLastError());
+ return p;
+}
+
+void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
+ return MmapFixedNoReserve(fixed_addr, size);
+}
+
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+ // FIXME: make this really NoReserve?
+ return MmapOrDie(size, mem_type);
+}
+
+void *Mprotect(uptr fixed_addr, uptr size) {
+ void *res = VirtualAlloc((LPVOID)fixed_addr, size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
+ if (res == 0)
+ Report("WARNING: %s failed to "
+ "mprotect %p (%zd) bytes at %p (error code: %d)\n",
+ SanitizerToolName, size, size, fixed_addr, GetLastError());
+ return res;
+}
+
+void FlushUnneededShadowMemory(uptr addr, uptr size) {
+ // This is almost useless on 32-bits.
+ // FIXME: add madvise-analog when we move to 64-bits.
+}
+
+void NoHugePagesInRegion(uptr addr, uptr size) {
+ // FIXME: probably similar to FlushUnneededShadowMemory.
+}
+
+void DontDumpShadowMemory(uptr addr, uptr length) {
+ // This is almost useless on 32-bits.
+ // FIXME: add madvise-analog when we move to 64-bits.
+}
+
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
+ MEMORY_BASIC_INFORMATION mbi;
+ CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
+ return mbi.Protect == PAGE_NOACCESS &&
+ (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end;
+}
+
+void *MapFileToMemory(const char *file_name, uptr *buff_size) {
+ UNIMPLEMENTED();
+}
+
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+ UNIMPLEMENTED();
+}
+
+static const int kMaxEnvNameLength = 128;
+static const DWORD kMaxEnvValueLength = 32767;
+
+namespace {
+
+struct EnvVariable {
+ char name[kMaxEnvNameLength];
+ char value[kMaxEnvValueLength];
+};
+
+} // namespace
+
+static const int kEnvVariables = 5;
+static EnvVariable env_vars[kEnvVariables];
+static int num_env_vars;
+
+const char *GetEnv(const char *name) {
+ // Note: this implementation caches the values of the environment variables
+ // and limits their quantity.
+ for (int i = 0; i < num_env_vars; i++) {
+ if (0 == internal_strcmp(name, env_vars[i].name))
+ return env_vars[i].value;
+ }
+ CHECK_LT(num_env_vars, kEnvVariables);
+ DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
+ kMaxEnvValueLength);
+ if (rv > 0 && rv < kMaxEnvValueLength) {
+ CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
+ internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
+ num_env_vars++;
+ return env_vars[num_env_vars - 1].value;
+ }
+ return 0;
+}
+
+const char *GetPwd() {
+ UNIMPLEMENTED();
+}
+
+u32 GetUid() {
+ UNIMPLEMENTED();
+}
+
+namespace {
+struct ModuleInfo {
+ HMODULE handle;
+ uptr base_address;
+ uptr end_address;
+};
+
+int CompareModulesBase(const void *pl, const void *pr) {
+ const ModuleInfo &l = *(ModuleInfo *)pl, &r = *(ModuleInfo *)pr;
+ if (l.base_address < r.base_address)
+ return -1;
+ return l.base_address > r.base_address;
+}
+} // namespace
+
+#ifndef SANITIZER_GO
+void DumpProcessMap() {
+ Report("Dumping process modules:\n");
+ HANDLE cur_process = GetCurrentProcess();
+
+ // Query the list of modules. Start by assuming there are no more than 256
+ // modules and retry if that's not sufficient.
+ ModuleInfo *modules;
+ size_t num_modules;
+ {
+ HMODULE *hmodules = 0;
+ uptr modules_buffer_size = sizeof(HMODULE) * 256;
+ DWORD bytes_required;
+ while (!hmodules) {
+ hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
+ CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
+ &bytes_required));
+ if (bytes_required > modules_buffer_size) {
+ // Either there turned out to be more than 256 hmodules, or new hmodules
+ // could have loaded since the last try. Retry.
+ UnmapOrDie(hmodules, modules_buffer_size);
+ hmodules = 0;
+ modules_buffer_size = bytes_required;
+ }
+ }
+
+ num_modules = bytes_required / sizeof(HMODULE);
+ modules =
+ (ModuleInfo *)MmapOrDie(num_modules * sizeof(ModuleInfo), __FUNCTION__);
+ for (size_t i = 0; i < num_modules; ++i) {
+ modules[i].handle = hmodules[i];
+ MODULEINFO mi;
+ if (!GetModuleInformation(cur_process, hmodules[i], &mi, sizeof(mi)))
+ continue;
+ modules[i].base_address = (uptr)mi.lpBaseOfDll;
+ modules[i].end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
+ }
+ UnmapOrDie(hmodules, modules_buffer_size);
+ }
+
+ qsort(modules, num_modules, sizeof(ModuleInfo), CompareModulesBase);
+
+ for (size_t i = 0; i < num_modules; ++i) {
+ const ModuleInfo &mi = modules[i];
+ char module_name[MAX_PATH];
+ bool got_module_name = GetModuleFileNameA(
+ mi.handle, module_name, sizeof(module_name));
+ if (mi.end_address != 0) {
+ Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
+ got_module_name ? module_name : "[no name]");
+ } else if (got_module_name) {
+ Printf("\t??\?-??? %s\n", module_name);
+ } else {
+ Printf("\t???\n");
+ }
+ }
+ UnmapOrDie(modules, num_modules * sizeof(ModuleInfo));
+}
+#endif
+
+void DisableCoreDumperIfNecessary() {
+ // Do nothing.
+}
+
+void ReExec() {
+ UNIMPLEMENTED();
+}
+
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ (void)args;
+ // Nothing here for now.
+}
+
+bool StackSizeIsUnlimited() {
+ UNIMPLEMENTED();
+}
+
+void SetStackSizeLimitInBytes(uptr limit) {
+ UNIMPLEMENTED();
+}
+
+bool AddressSpaceIsUnlimited() {
+ UNIMPLEMENTED();
+}
+
+void SetAddressSpaceUnlimited() {
+ UNIMPLEMENTED();
+}
+
+char *FindPathToBinary(const char *name) {
+ // Nothing here for now.
+ return 0;
+}
+
+void SleepForSeconds(int seconds) {
+ Sleep(seconds * 1000);
+}
+
+void SleepForMillis(int millis) {
+ Sleep(millis);
+}
+
+u64 NanoTime() {
+ return 0;
+}
+
+void Abort() {
+ if (::IsDebuggerPresent())
+ __debugbreak();
+ internal__exit(3);
+}
+
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ UNIMPLEMENTED();
+};
+
+#ifndef SANITIZER_GO
+int Atexit(void (*function)(void)) {
+ return atexit(function);
+}
+#endif
+
+// ------------------ sanitizer_libc.h
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+ int fd, u64 offset) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_munmap(void *addr, uptr length) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_close(fd_t fd) {
+ UNIMPLEMENTED();
+}
+
+int internal_isatty(fd_t fd) {
+ return _isatty(fd);
+}
+
+uptr internal_open(const char *filename, int flags) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_open(const char *filename, int flags, u32 mode) {
+ UNIMPLEMENTED();
+}
+
+uptr OpenFile(const char *filename, bool write) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_read(fd_t fd, void *buf, uptr count) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_write(fd_t fd, const void *buf, uptr count) {
+ if (fd != kStderrFd)
+ UNIMPLEMENTED();
+
+ static HANDLE output_stream = 0;
+ // Abort immediately if we know printing is not possible.
+ if (output_stream == INVALID_HANDLE_VALUE)
+ return 0;
+
+ // If called for the first time, try to use stderr to output stuff,
+ // falling back to stdout if anything goes wrong.
+ bool fallback_to_stdout = false;
+ if (output_stream == 0) {
+ output_stream = GetStdHandle(STD_ERROR_HANDLE);
+ // We don't distinguish "no such handle" from error.
+ if (output_stream == 0)
+ output_stream = INVALID_HANDLE_VALUE;
+
+ if (output_stream == INVALID_HANDLE_VALUE) {
+ // Retry with stdout?
+ output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (output_stream == 0)
+ output_stream = INVALID_HANDLE_VALUE;
+ if (output_stream == INVALID_HANDLE_VALUE)
+ return 0;
+ } else {
+ // Successfully got an stderr handle. However, if WriteFile() fails,
+ // we can still try to fallback to stdout.
+ fallback_to_stdout = true;
+ }
+ }
+
+ DWORD ret;
+ if (WriteFile(output_stream, buf, count, &ret, 0))
+ return ret;
+
+ // Re-try with stdout if using a valid stderr handle fails.
+ if (fallback_to_stdout) {
+ output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (output_stream == 0)
+ output_stream = INVALID_HANDLE_VALUE;
+ if (output_stream != INVALID_HANDLE_VALUE)
+ return internal_write(fd, buf, count);
+ }
+ return 0;
+}
+
+uptr internal_stat(const char *path, void *buf) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_lstat(const char *path, void *buf) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_fstat(fd_t fd, void *buf) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_filesize(fd_t fd) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_dup2(int oldfd, int newfd) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_sched_yield() {
+ Sleep(0);
+ return 0;
+}
+
+void internal__exit(int exitcode) {
+ ExitProcess(exitcode);
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+ UNIMPLEMENTED();
+}
+
+uptr GetRSS() {
+ return 0;
+}
+
+void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
+void internal_join_thread(void *th) { }
+
+// ---------------------- BlockingMutex ---------------- {{{1
+const uptr LOCK_UNINITIALIZED = 0;
+const uptr LOCK_READY = (uptr)-1;
+
+BlockingMutex::BlockingMutex(LinkerInitialized li) {
+ // FIXME: see comments in BlockingMutex::Lock() for the details.
+ CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
+
+ CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
+ InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
+ owner_ = LOCK_READY;
+}
+
+BlockingMutex::BlockingMutex() {
+ CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
+ InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
+ owner_ = LOCK_READY;
+}
+
+void BlockingMutex::Lock() {
+ if (owner_ == LOCK_UNINITIALIZED) {
+ // FIXME: hm, global BlockingMutex objects are not initialized?!?
+ // This might be a side effect of the clang+cl+link Frankenbuild...
+ new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
+
+ // FIXME: If it turns out the linker doesn't invoke our
+ // constructors, we should probably manually Lock/Unlock all the global
+ // locks while we're starting in one thread to avoid double-init races.
+ }
+ EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
+ CHECK_EQ(owner_, LOCK_READY);
+ owner_ = GetThreadSelf();
+}
+
+void BlockingMutex::Unlock() {
+ CHECK_EQ(owner_, GetThreadSelf());
+ owner_ = LOCK_READY;
+ LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
+}
+
+void BlockingMutex::CheckLocked() {
+ CHECK_EQ(owner_, GetThreadSelf());
+}
+
+uptr GetTlsSize() {
+ return 0;
+}
+
+void InitTlsSize() {
+}
+
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size) {
+#ifdef SANITIZER_GO
+ *stk_addr = 0;
+ *stk_size = 0;
+ *tls_addr = 0;
+ *tls_size = 0;
+#else
+ uptr stack_top, stack_bottom;
+ GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
+ *stk_addr = stack_bottom;
+ *stk_size = stack_top - stack_bottom;
+ *tls_addr = 0;
+ *tls_size = 0;
+#endif
+}
+
+#if !SANITIZER_GO
+void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
+ CHECK_GE(max_depth, 2);
+ // FIXME: CaptureStackBackTrace might be too slow for us.
+ // FIXME: Compare with StackWalk64.
+ // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
+ size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
+ (void**)trace, 0);
+ if (size == 0)
+ return;
+
+ // Skip the RTL frames by searching for the PC in the stacktrace.
+ uptr pc_location = LocatePcInTrace(pc);
+ PopStackFrames(pc_location);
+}
+
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+ u32 max_depth) {
+ CONTEXT ctx = *(CONTEXT *)context;
+ STACKFRAME64 stack_frame;
+ memset(&stack_frame, 0, sizeof(stack_frame));
+ size = 0;
+#if defined(_WIN64)
+ int machine_type = IMAGE_FILE_MACHINE_AMD64;
+ stack_frame.AddrPC.Offset = ctx.Rip;
+ stack_frame.AddrFrame.Offset = ctx.Rbp;
+ stack_frame.AddrStack.Offset = ctx.Rsp;
+#else
+ int machine_type = IMAGE_FILE_MACHINE_I386;
+ stack_frame.AddrPC.Offset = ctx.Eip;
+ stack_frame.AddrFrame.Offset = ctx.Ebp;
+ stack_frame.AddrStack.Offset = ctx.Esp;
+#endif
+ stack_frame.AddrPC.Mode = AddrModeFlat;
+ stack_frame.AddrFrame.Mode = AddrModeFlat;
+ stack_frame.AddrStack.Mode = AddrModeFlat;
+ while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
+ &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
+ &SymGetModuleBase64, NULL) &&
+ size < Min(max_depth, kStackTraceMax)) {
+ trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
+ }
+}
+#endif // #if !SANITIZER_GO
+
+void ReportFile::Write(const char *buffer, uptr length) {
+ SpinMutexLock l(mu);
+ ReopenIfNecessary();
+ if (length != internal_write(fd, buffer, length)) {
+ // stderr may be closed, but we may be able to print to the debugger
+ // instead. This is the case when launching a program from Visual Studio,
+ // and the following routine should write to its console.
+ OutputDebugStringA(buffer);
+ }
+}
+
+void SetAlternateSignalStack() {
+ // FIXME: Decide what to do on Windows.
+}
+
+void UnsetAlternateSignalStack() {
+ // FIXME: Decide what to do on Windows.
+}
+
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {
+ (void)handler;
+ // FIXME: Decide what to do on Windows.
+}
+
+bool IsDeadlySignal(int signum) {
+ // FIXME: Decide what to do on Windows.
+ return false;
+}
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+ // FIXME: Actually implement this function.
+ return true;
+}
+
+} // namespace __sanitizer
+
+#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh b/contrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh
new file mode 100755
index 000000000000..7ed05d73563a
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+# Guess path to LLVM_CHECKOUT if not provided
+if [ "${LLVM_CHECKOUT}" = "" ]; then
+ LLVM_CHECKOUT="${SCRIPT_DIR}/../../../../../"
+fi
+
+# python tools setup
+CPPLINT=${SCRIPT_DIR}/cpplint.py
+LITLINT=${SCRIPT_DIR}/litlint.py
+if [ "${PYTHON_EXECUTABLE}" != "" ]; then
+ CPPLINT="${PYTHON_EXECUTABLE} ${CPPLINT}"
+ LITLINT="${PYTHON_EXECUTABLE} ${LITLINT}"
+fi
+
+# Filters
+# TODO: remove some of these filters
+LLVM_LINT_FILTER=-,+whitespace
+COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\
+-build/namespaces
+ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
+ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf,-runtime/threadsafe_fn
+ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length
+TSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
+TSAN_TEST_LINT_FILTER=${TSAN_RTL_LINT_FILTER},-runtime/threadsafe_fn,-runtime/int
+TSAN_LIT_TEST_LINT_FILTER=${TSAN_TEST_LINT_FILTER},-whitespace/line_length
+MSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
+LSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
+LSAN_LIT_TEST_LINT_FILTER=${LSAN_RTL_LINT_FILTER},-whitespace/line_length
+DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references,-readability/function
+COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf,-readability/fn_size
+SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
+
+MKTEMP_DIR=$(mktemp -qd /tmp/check_lint.XXXXXXXXXX)
+MKTEMP="mktemp -q ${MKTEMP_DIR}/tmp.XXXXXXXXXX"
+cleanup() {
+ rm -rf $MKTEMP_DIR
+}
+trap cleanup EXIT
+
+cd ${LLVM_CHECKOUT}
+
+EXITSTATUS=0
+ERROR_LOG=$(${MKTEMP})
+
+run_lint() {
+ FILTER=$1
+ shift
+ TASK_LOG=$(${MKTEMP})
+ ${CPPLINT} --filter=${FILTER} "$@" 2>$TASK_LOG
+ if [ "$?" != "0" ]; then
+ cat $TASK_LOG | grep -v "Done processing" | grep -v "Total errors found" \
+ | grep -v "Skipping input" >> $ERROR_LOG
+ fi
+ if [ "${SILENT}" != "1" ]; then
+ cat $TASK_LOG
+ fi
+ ${LITLINT} "$@" 2>>$ERROR_LOG
+}
+
+run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \
+ lib/Transforms/Instrumentation/*Sanitizer.cpp &
+
+if [ "${COMPILER_RT}" = "" ]; then
+ COMPILER_RT=projects/compiler-rt
+fi
+LIT_TESTS=${COMPILER_RT}/test
+# Headers
+SANITIZER_INCLUDES=${COMPILER_RT}/include/sanitizer
+run_lint ${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h &
+
+# Sanitizer_common
+COMMON_RTL=${COMPILER_RT}/lib/sanitizer_common
+run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.cc \
+ ${COMMON_RTL}/*.h \
+ ${COMMON_RTL}/tests/*.cc &
+
+# Interception
+INTERCEPTION=${COMPILER_RT}/lib/interception
+run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.cc \
+ ${INTERCEPTION}/*.h &
+
+# ASan
+ASAN_RTL=${COMPILER_RT}/lib/asan
+run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.cc \
+ ${ASAN_RTL}/*.h &
+run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.cc \
+ ${ASAN_RTL}/tests/*.h &
+run_lint ${ASAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/asan/*/*.cc &
+
+# TSan
+TSAN_RTL=${COMPILER_RT}/lib/tsan
+run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.cc \
+ ${TSAN_RTL}/rtl/*.h &
+run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.cc \
+ ${TSAN_RTL}/tests/rtl/*.h \
+ ${TSAN_RTL}/tests/unit/*.cc &
+run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/tsan/*.cc &
+
+# MSan
+MSAN_RTL=${COMPILER_RT}/lib/msan
+run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.cc \
+ ${MSAN_RTL}/*.h &
+
+# LSan
+LSAN_RTL=${COMPILER_RT}/lib/lsan
+run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.cc \
+ ${LSAN_RTL}/*.h &
+run_lint ${LSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/lsan/*/*.cc &
+
+# DFSan
+DFSAN_RTL=${COMPILER_RT}/lib/dfsan
+run_lint ${DFSAN_RTL_LINT_FILTER} ${DFSAN_RTL}/*.cc \
+ ${DFSAN_RTL}/*.h &
+${DFSAN_RTL}/scripts/check_custom_wrappers.sh >> $ERROR_LOG
+
+# Misc files
+FILES=${COMMON_RTL}/*.inc
+TMPFILES=""
+for FILE in $FILES; do
+ TMPFILE="$(${MKTEMP}).$(basename ${FILE}).cc"
+ cp -f $FILE $TMPFILE
+ run_lint ${COMMON_RTL_INC_LINT_FILTER} $TMPFILE &
+ TMPFILES="$TMPFILES $TMPFILE"
+done
+
+wait
+
+for temp in $TMPFILES; do
+ rm -f $temp
+done
+
+if [ -s $ERROR_LOG ]; then
+ cat $ERROR_LOG
+ exit 1
+fi
+
+exit 0
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py
new file mode 100755
index 000000000000..742459af172f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py
@@ -0,0 +1,4024 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Here are some issues that I've had people identify in my code during reviews,
+# that I think are possible to flag automatically in a lint tool. If these were
+# caught by lint, it would save time both for myself and that of my reviewers.
+# Most likely, some of these are beyond the scope of the current lint framework,
+# but I think it is valuable to retain these wish-list items even if they cannot
+# be immediately implemented.
+#
+# Suggestions
+# -----------
+# - Check for no 'explicit' for multi-arg ctor
+# - Check for boolean assign RHS in parens
+# - Check for ctor initializer-list colon position and spacing
+# - Check that if there's a ctor, there should be a dtor
+# - Check accessors that return non-pointer member variables are
+# declared const
+# - Check accessors that return non-const pointer member vars are
+# *not* declared const
+# - Check for using public includes for testing
+# - Check for spaces between brackets in one-line inline method
+# - Check for no assert()
+# - Check for spaces surrounding operators
+# - Check for 0 in pointer context (should be NULL)
+# - Check for 0 in char context (should be '\0')
+# - Check for camel-case method name conventions for methods
+# that are not simple inline getters and setters
+# - Do not indent namespace contents
+# - Avoid inlining non-trivial constructors in header files
+# - Check for old-school (void) cast for call-sites of functions
+# ignored return value
+# - Check gUnit usage of anonymous namespace
+# - Check for class declaration order (typedefs, consts, enums,
+# ctor(s?), dtor, friend declarations, methods, member vars)
+#
+
+"""Does google-lint on c++ files.
+
+The goal of this script is to identify places in the code that *may*
+be in non-compliance with google style. It does not attempt to fix
+up these problems -- the point is to educate. It does also not
+attempt to find all problems, or to ensure that everything it does
+find is legitimately a problem.
+
+In particular, we can get very confused by /* and // inside strings!
+We do a small hack, which is to ignore //'s with "'s after them on the
+same line, but it is far from perfect (in either direction).
+"""
+
+import codecs
+import copy
+import getopt
+import math # for log
+import os
+import re
+import sre_compile
+import string
+import sys
+import unicodedata
+
+
+_USAGE = """
+Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
+ [--counting=total|toplevel|detailed]
+ <file> [file] ...
+
+ The style guidelines this tries to follow are those in
+ http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+
+ Every problem is given a confidence score from 1-5, with 5 meaning we are
+ certain of the problem, and 1 meaning it could be a legitimate construct.
+ This will miss some errors, and is not a substitute for a code review.
+
+ To suppress false-positive errors of a certain category, add a
+ 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
+ suppresses errors of all categories on that line.
+
+ The files passed in will be linted; at least one file must be provided.
+ Linted extensions are .cc, .cpp, and .h. Other file types will be ignored.
+
+ Flags:
+
+ output=vs7
+ By default, the output is formatted to ease emacs parsing. Visual Studio
+ compatible output (vs7) may also be used. Other formats are unsupported.
+
+ verbose=#
+ Specify a number 0-5 to restrict errors to certain verbosity levels.
+
+ filter=-x,+y,...
+ Specify a comma-separated list of category-filters to apply: only
+ error messages whose category names pass the filters will be printed.
+ (Category names are printed with the message and look like
+ "[whitespace/indent]".) Filters are evaluated left to right.
+ "-FOO" and "FOO" means "do not print categories that start with FOO".
+ "+FOO" means "do print categories that start with FOO".
+
+ Examples: --filter=-whitespace,+whitespace/braces
+ --filter=whitespace,runtime/printf,+runtime/printf_format
+ --filter=-,+build/include_what_you_use
+
+ To see a list of all the categories used in cpplint, pass no arg:
+ --filter=
+
+ counting=total|toplevel|detailed
+ The total number of errors found is always printed. If
+ 'toplevel' is provided, then the count of errors in each of
+ the top-level categories like 'build' and 'whitespace' will
+ also be printed. If 'detailed' is provided, then a count
+ is provided for each category like 'build/class'.
+
+ root=subdir
+ The root directory used for deriving header guard CPP variable.
+ By default, the header guard CPP variable is calculated as the relative
+ path to the directory that contains .git, .hg, or .svn. When this flag
+ is specified, the relative path is calculated from the specified
+ directory. If the specified directory does not exist, this flag is
+ ignored.
+
+ Examples:
+ Assuing that src/.git exists, the header guard CPP variables for
+ src/chrome/browser/ui/browser.h are:
+
+ No flag => CHROME_BROWSER_UI_BROWSER_H_
+ --root=chrome => BROWSER_UI_BROWSER_H_
+ --root=chrome/browser => UI_BROWSER_H_
+"""
+
+# We categorize each error message we print. Here are the categories.
+# We want an explicit list so we can list them all in cpplint --filter=.
+# If you add a new error message with a new category, add it to the list
+# here! cpplint_unittest.py should tell you if you forget to do this.
+# \ used for clearer layout -- pylint: disable-msg=C6013
+_ERROR_CATEGORIES = [
+ 'build/class',
+ 'build/deprecated',
+ 'build/endif_comment',
+ 'build/explicit_make_pair',
+ 'build/forward_decl',
+ 'build/header_guard',
+ 'build/include',
+ 'build/include_alpha',
+ 'build/include_order',
+ 'build/include_what_you_use',
+ 'build/namespaces',
+ 'build/printf_format',
+ 'build/storage_class',
+ 'legal/copyright',
+ 'readability/alt_tokens',
+ 'readability/braces',
+ 'readability/casting',
+ 'readability/check',
+ 'readability/constructors',
+ 'readability/fn_size',
+ 'readability/function',
+ 'readability/multiline_comment',
+ 'readability/multiline_string',
+ 'readability/namespace',
+ 'readability/nolint',
+ 'readability/streams',
+ 'readability/todo',
+ 'readability/utf8',
+ 'runtime/arrays',
+ 'runtime/casting',
+ 'runtime/explicit',
+ 'runtime/int',
+ 'runtime/init',
+ 'runtime/invalid_increment',
+ 'runtime/member_string_references',
+ 'runtime/memset',
+ 'runtime/operator',
+ 'runtime/printf',
+ 'runtime/printf_format',
+ 'runtime/references',
+ 'runtime/rtti',
+ 'runtime/sizeof',
+ 'runtime/string',
+ 'runtime/threadsafe_fn',
+ 'whitespace/blank_line',
+ 'whitespace/braces',
+ 'whitespace/comma',
+ 'whitespace/comments',
+ 'whitespace/empty_loop_body',
+ 'whitespace/end_of_line',
+ 'whitespace/ending_newline',
+ 'whitespace/forcolon',
+ 'whitespace/indent',
+ 'whitespace/labels',
+ 'whitespace/line_length',
+ 'whitespace/newline',
+ 'whitespace/operators',
+ 'whitespace/parens',
+ 'whitespace/semicolon',
+ 'whitespace/tab',
+ 'whitespace/todo'
+ ]
+
+# The default state of the category filter. This is overrided by the --filter=
+# flag. By default all errors are on, so only add here categories that should be
+# off by default (i.e., categories that must be enabled by the --filter= flags).
+# All entries here should start with a '-' or '+', as in the --filter= flag.
+_DEFAULT_FILTERS = ['-build/include_alpha']
+
+# We used to check for high-bit characters, but after much discussion we
+# decided those were OK, as long as they were in UTF-8 and didn't represent
+# hard-coded international strings, which belong in a separate i18n file.
+
+# Headers that we consider STL headers.
+_STL_HEADERS = frozenset([
+ 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
+ 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
+ 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
+ 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
+ 'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
+ 'utility', 'vector', 'vector.h',
+ ])
+
+
+# Non-STL C++ system headers.
+_CPP_HEADERS = frozenset([
+ 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
+ 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
+ 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
+ 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
+ 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
+ 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
+ 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',
+ 'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
+ 'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',
+ 'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',
+ 'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
+ 'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h',
+ 'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo',
+ 'valarray',
+ ])
+
+
+# Assertion macros. These are defined in base/logging.h and
+# testing/base/gunit.h. Note that the _M versions need to come first
+# for substring matching to work.
+_CHECK_MACROS = [
+ 'DCHECK', 'CHECK',
+ 'EXPECT_TRUE_M', 'EXPECT_TRUE',
+ 'ASSERT_TRUE_M', 'ASSERT_TRUE',
+ 'EXPECT_FALSE_M', 'EXPECT_FALSE',
+ 'ASSERT_FALSE_M', 'ASSERT_FALSE',
+ ]
+
+# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
+_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
+
+for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
+ ('>=', 'GE'), ('>', 'GT'),
+ ('<=', 'LE'), ('<', 'LT')]:
+ _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
+ _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
+
+for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
+ ('>=', 'LT'), ('>', 'LE'),
+ ('<=', 'GT'), ('<', 'GE')]:
+ _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
+
+# Alternative tokens and their replacements. For full list, see section 2.5
+# Alternative tokens [lex.digraph] in the C++ standard.
+#
+# Digraphs (such as '%:') are not included here since it's a mess to
+# match those on a word boundary.
+_ALT_TOKEN_REPLACEMENT = {
+ 'and': '&&',
+ 'bitor': '|',
+ 'or': '||',
+ 'xor': '^',
+ 'compl': '~',
+ 'bitand': '&',
+ 'and_eq': '&=',
+ 'or_eq': '|=',
+ 'xor_eq': '^=',
+ 'not': '!',
+ 'not_eq': '!='
+ }
+
+# Compile regular expression that matches all the above keywords. The "[ =()]"
+# bit is meant to avoid matching these keywords outside of boolean expressions.
+#
+# False positives include C-style multi-line comments (http://go/nsiut )
+# and multi-line strings (http://go/beujw ), but those have always been
+# troublesome for cpplint.
+_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
+ r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
+
+
+# These constants define types of headers for use with
+# _IncludeState.CheckNextIncludeOrder().
+_C_SYS_HEADER = 1
+_CPP_SYS_HEADER = 2
+_LIKELY_MY_HEADER = 3
+_POSSIBLE_MY_HEADER = 4
+_OTHER_HEADER = 5
+
+# These constants define the current inline assembly state
+_NO_ASM = 0 # Outside of inline assembly block
+_INSIDE_ASM = 1 # Inside inline assembly block
+_END_ASM = 2 # Last line of inline assembly block
+_BLOCK_ASM = 3 # The whole block is an inline assembly block
+
+# Match start of assembly blocks
+_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
+ r'(?:\s+(volatile|__volatile__))?'
+ r'\s*[{(]')
+
+
+_regexp_compile_cache = {}
+
+# Finds occurrences of NOLINT or NOLINT(...).
+_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
+
+# {str, set(int)}: a map from error categories to sets of linenumbers
+# on which those errors are expected and should be suppressed.
+_error_suppressions = {}
+
+# The root directory used for deriving header guard CPP variable.
+# This is set by --root flag.
+_root = None
+
+def ParseNolintSuppressions(filename, raw_line, linenum, error):
+ """Updates the global list of error-suppressions.
+
+ Parses any NOLINT comments on the current line, updating the global
+ error_suppressions store. Reports an error if the NOLINT comment
+ was malformed.
+
+ Args:
+ filename: str, the name of the input file.
+ raw_line: str, the line of input text, with comments.
+ linenum: int, the number of the current line.
+ error: function, an error handler.
+ """
+ # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
+ matched = _RE_SUPPRESSION.search(raw_line)
+ if matched:
+ category = matched.group(1)
+ if category in (None, '(*)'): # => "suppress all"
+ _error_suppressions.setdefault(None, set()).add(linenum)
+ else:
+ if category.startswith('(') and category.endswith(')'):
+ category = category[1:-1]
+ if category in _ERROR_CATEGORIES:
+ _error_suppressions.setdefault(category, set()).add(linenum)
+ else:
+ error(filename, linenum, 'readability/nolint', 5,
+ 'Unknown NOLINT error category: %s' % category)
+
+
+def ResetNolintSuppressions():
+ "Resets the set of NOLINT suppressions to empty."
+ _error_suppressions.clear()
+
+
+def IsErrorSuppressedByNolint(category, linenum):
+ """Returns true if the specified error category is suppressed on this line.
+
+ Consults the global error_suppressions map populated by
+ ParseNolintSuppressions/ResetNolintSuppressions.
+
+ Args:
+ category: str, the category of the error.
+ linenum: int, the current line number.
+ Returns:
+ bool, True iff the error should be suppressed due to a NOLINT comment.
+ """
+ return (linenum in _error_suppressions.get(category, set()) or
+ linenum in _error_suppressions.get(None, set()))
+
+def Match(pattern, s):
+ """Matches the string with the pattern, caching the compiled regexp."""
+ # The regexp compilation caching is inlined in both Match and Search for
+ # performance reasons; factoring it out into a separate function turns out
+ # to be noticeably expensive.
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].match(s)
+
+
+def Search(pattern, s):
+ """Searches the string for the pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].search(s)
+
+
+class _IncludeState(dict):
+ """Tracks line numbers for includes, and the order in which includes appear.
+
+ As a dict, an _IncludeState object serves as a mapping between include
+ filename and line number on which that file was included.
+
+ Call CheckNextIncludeOrder() once for each header in the file, passing
+ in the type constants defined above. Calls in an illegal order will
+ raise an _IncludeError with an appropriate error message.
+
+ """
+ # self._section will move monotonically through this set. If it ever
+ # needs to move backwards, CheckNextIncludeOrder will raise an error.
+ _INITIAL_SECTION = 0
+ _MY_H_SECTION = 1
+ _C_SECTION = 2
+ _CPP_SECTION = 3
+ _OTHER_H_SECTION = 4
+
+ _TYPE_NAMES = {
+ _C_SYS_HEADER: 'C system header',
+ _CPP_SYS_HEADER: 'C++ system header',
+ _LIKELY_MY_HEADER: 'header this file implements',
+ _POSSIBLE_MY_HEADER: 'header this file may implement',
+ _OTHER_HEADER: 'other header',
+ }
+ _SECTION_NAMES = {
+ _INITIAL_SECTION: "... nothing. (This can't be an error.)",
+ _MY_H_SECTION: 'a header this file implements',
+ _C_SECTION: 'C system header',
+ _CPP_SECTION: 'C++ system header',
+ _OTHER_H_SECTION: 'other header',
+ }
+
+ def __init__(self):
+ dict.__init__(self)
+ # The name of the current section.
+ self._section = self._INITIAL_SECTION
+ # The path of last found header.
+ self._last_header = ''
+
+ def CanonicalizeAlphabeticalOrder(self, header_path):
+ """Returns a path canonicalized for alphabetical comparison.
+
+ - replaces "-" with "_" so they both cmp the same.
+ - removes '-inl' since we don't require them to be after the main header.
+ - lowercase everything, just in case.
+
+ Args:
+ header_path: Path to be canonicalized.
+
+ Returns:
+ Canonicalized path.
+ """
+ return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
+
+ def IsInAlphabeticalOrder(self, header_path):
+ """Check if a header is in alphabetical order with the previous header.
+
+ Args:
+ header_path: Header to be checked.
+
+ Returns:
+ Returns true if the header is in alphabetical order.
+ """
+ canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)
+ if self._last_header > canonical_header:
+ return False
+ self._last_header = canonical_header
+ return True
+
+ def CheckNextIncludeOrder(self, header_type):
+ """Returns a non-empty error message if the next header is out of order.
+
+ This function also updates the internal state to be ready to check
+ the next include.
+
+ Args:
+ header_type: One of the _XXX_HEADER constants defined above.
+
+ Returns:
+ The empty string if the header is in the right order, or an
+ error message describing what's wrong.
+
+ """
+ error_message = ('Found %s after %s' %
+ (self._TYPE_NAMES[header_type],
+ self._SECTION_NAMES[self._section]))
+
+ last_section = self._section
+
+ if header_type == _C_SYS_HEADER:
+ if self._section <= self._C_SECTION:
+ self._section = self._C_SECTION
+ else:
+ self._last_header = ''
+ return error_message
+ elif header_type == _CPP_SYS_HEADER:
+ if self._section <= self._CPP_SECTION:
+ self._section = self._CPP_SECTION
+ else:
+ self._last_header = ''
+ return error_message
+ elif header_type == _LIKELY_MY_HEADER:
+ if self._section <= self._MY_H_SECTION:
+ self._section = self._MY_H_SECTION
+ else:
+ self._section = self._OTHER_H_SECTION
+ elif header_type == _POSSIBLE_MY_HEADER:
+ if self._section <= self._MY_H_SECTION:
+ self._section = self._MY_H_SECTION
+ else:
+ # This will always be the fallback because we're not sure
+ # enough that the header is associated with this file.
+ self._section = self._OTHER_H_SECTION
+ else:
+ assert header_type == _OTHER_HEADER
+ self._section = self._OTHER_H_SECTION
+
+ if last_section != self._section:
+ self._last_header = ''
+
+ return ''
+
+
+class _CppLintState(object):
+ """Maintains module-wide state.."""
+
+ def __init__(self):
+ self.verbose_level = 1 # global setting.
+ self.error_count = 0 # global count of reported errors
+ # filters to apply when emitting error messages
+ self.filters = _DEFAULT_FILTERS[:]
+ self.counting = 'total' # In what way are we counting errors?
+ self.errors_by_category = {} # string to int dict storing error counts
+
+ # output format:
+ # "emacs" - format that emacs can parse (default)
+ # "vs7" - format that Microsoft Visual Studio 7 can parse
+ self.output_format = 'emacs'
+
+ def SetOutputFormat(self, output_format):
+ """Sets the output format for errors."""
+ self.output_format = output_format
+
+ def SetVerboseLevel(self, level):
+ """Sets the module's verbosity, and returns the previous setting."""
+ last_verbose_level = self.verbose_level
+ self.verbose_level = level
+ return last_verbose_level
+
+ def SetCountingStyle(self, counting_style):
+ """Sets the module's counting options."""
+ self.counting = counting_style
+
+ def SetFilters(self, filters):
+ """Sets the error-message filters.
+
+ These filters are applied when deciding whether to emit a given
+ error message.
+
+ Args:
+ filters: A string of comma-separated filters (eg "+whitespace/indent").
+ Each filter should start with + or -; else we die.
+
+ Raises:
+ ValueError: The comma-separated filters did not all start with '+' or '-'.
+ E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
+ """
+ # Default filters always have less priority than the flag ones.
+ self.filters = _DEFAULT_FILTERS[:]
+ for filt in filters.split(','):
+ clean_filt = filt.strip()
+ if clean_filt:
+ self.filters.append(clean_filt)
+ for filt in self.filters:
+ if not (filt.startswith('+') or filt.startswith('-')):
+ raise ValueError('Every filter in --filters must start with + or -'
+ ' (%s does not)' % filt)
+
+ def ResetErrorCounts(self):
+ """Sets the module's error statistic back to zero."""
+ self.error_count = 0
+ self.errors_by_category = {}
+
+ def IncrementErrorCount(self, category):
+ """Bumps the module's error statistic."""
+ self.error_count += 1
+ if self.counting in ('toplevel', 'detailed'):
+ if self.counting != 'detailed':
+ category = category.split('/')[0]
+ if category not in self.errors_by_category:
+ self.errors_by_category[category] = 0
+ self.errors_by_category[category] += 1
+
+ def PrintErrorCounts(self):
+ """Print a summary of errors by category, and the total."""
+ for category, count in self.errors_by_category.iteritems():
+ sys.stderr.write('Category \'%s\' errors found: %d\n' %
+ (category, count))
+ sys.stderr.write('Total errors found: %d\n' % self.error_count)
+
+_cpplint_state = _CppLintState()
+
+
+def _OutputFormat():
+ """Gets the module's output format."""
+ return _cpplint_state.output_format
+
+
+def _SetOutputFormat(output_format):
+ """Sets the module's output format."""
+ _cpplint_state.SetOutputFormat(output_format)
+
+
+def _VerboseLevel():
+ """Returns the module's verbosity setting."""
+ return _cpplint_state.verbose_level
+
+
+def _SetVerboseLevel(level):
+ """Sets the module's verbosity, and returns the previous setting."""
+ return _cpplint_state.SetVerboseLevel(level)
+
+
+def _SetCountingStyle(level):
+ """Sets the module's counting options."""
+ _cpplint_state.SetCountingStyle(level)
+
+
+def _Filters():
+ """Returns the module's list of output filters, as a list."""
+ return _cpplint_state.filters
+
+
+def _SetFilters(filters):
+ """Sets the module's error-message filters.
+
+ These filters are applied when deciding whether to emit a given
+ error message.
+
+ Args:
+ filters: A string of comma-separated filters (eg "whitespace/indent").
+ Each filter should start with + or -; else we die.
+ """
+ _cpplint_state.SetFilters(filters)
+
+
+class _FunctionState(object):
+ """Tracks current function name and the number of lines in its body."""
+
+ _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
+ _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
+
+ def __init__(self):
+ self.in_a_function = False
+ self.lines_in_function = 0
+ self.current_function = ''
+
+ def Begin(self, function_name):
+ """Start analyzing function body.
+
+ Args:
+ function_name: The name of the function being tracked.
+ """
+ self.in_a_function = True
+ self.lines_in_function = 0
+ self.current_function = function_name
+
+ def Count(self):
+ """Count line in current function body."""
+ if self.in_a_function:
+ self.lines_in_function += 1
+
+ def Check(self, error, filename, linenum):
+ """Report if too many lines in function body.
+
+ Args:
+ error: The function to call with any errors found.
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ """
+ if Match(r'T(EST|est)', self.current_function):
+ base_trigger = self._TEST_TRIGGER
+ else:
+ base_trigger = self._NORMAL_TRIGGER
+ trigger = base_trigger * 2**_VerboseLevel()
+
+ if self.lines_in_function > trigger:
+ error_level = int(math.log(self.lines_in_function / base_trigger, 2))
+ # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
+ if error_level > 5:
+ error_level = 5
+ error(filename, linenum, 'readability/fn_size', error_level,
+ 'Small and focused functions are preferred:'
+ ' %s has %d non-comment lines'
+ ' (error triggered by exceeding %d lines).' % (
+ self.current_function, self.lines_in_function, trigger))
+
+ def End(self):
+ """Stop analyzing function body."""
+ self.in_a_function = False
+
+
+class _IncludeError(Exception):
+ """Indicates a problem with the include order in a file."""
+ pass
+
+
+class FileInfo:
+ """Provides utility functions for filenames.
+
+ FileInfo provides easy access to the components of a file's path
+ relative to the project root.
+ """
+
+ def __init__(self, filename):
+ self._filename = filename
+
+ def FullName(self):
+ """Make Windows paths like Unix."""
+ return os.path.abspath(self._filename).replace('\\', '/')
+
+ def RepositoryName(self):
+ """FullName after removing the local path to the repository.
+
+ If we have a real absolute path name here we can try to do something smart:
+ detecting the root of the checkout and truncating /path/to/checkout from
+ the name so that we get header guards that don't include things like
+ "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+ people on different computers who have checked the source out to different
+ locations won't see bogus errors.
+ """
+ fullname = self.FullName()
+
+ if os.path.exists(fullname):
+ project_dir = os.path.dirname(fullname)
+
+ if os.path.exists(os.path.join(project_dir, ".svn")):
+ # If there's a .svn file in the current directory, we recursively look
+ # up the directory tree for the top of the SVN checkout
+ root_dir = project_dir
+ one_up_dir = os.path.dirname(root_dir)
+ while os.path.exists(os.path.join(one_up_dir, ".svn")):
+ root_dir = os.path.dirname(root_dir)
+ one_up_dir = os.path.dirname(one_up_dir)
+
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
+ # searching up from the current path.
+ root_dir = os.path.dirname(fullname)
+ while (root_dir != os.path.dirname(root_dir) and
+ not os.path.exists(os.path.join(root_dir, ".git")) and
+ not os.path.exists(os.path.join(root_dir, ".hg")) and
+ not os.path.exists(os.path.join(root_dir, ".svn"))):
+ root_dir = os.path.dirname(root_dir)
+
+ if (os.path.exists(os.path.join(root_dir, ".git")) or
+ os.path.exists(os.path.join(root_dir, ".hg")) or
+ os.path.exists(os.path.join(root_dir, ".svn"))):
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Don't know what to do; header guard warnings may be wrong...
+ return fullname
+
+ def Split(self):
+ """Splits the file into the directory, basename, and extension.
+
+ For 'chrome/browser/browser.cc', Split() would
+ return ('chrome/browser', 'browser', '.cc')
+
+ Returns:
+ A tuple of (directory, basename, extension).
+ """
+
+ googlename = self.RepositoryName()
+ project, rest = os.path.split(googlename)
+ return (project,) + os.path.splitext(rest)
+
+ def BaseName(self):
+ """File base name - text after the final slash, before the final period."""
+ return self.Split()[1]
+
+ def Extension(self):
+ """File extension - text following the final period."""
+ return self.Split()[2]
+
+ def NoExtension(self):
+ """File has no source file extension."""
+ return '/'.join(self.Split()[0:2])
+
+ def IsSource(self):
+ """File has a source file extension."""
+ return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
+
+
+def _ShouldPrintError(category, confidence, linenum):
+ """If confidence >= verbose, category passes filter and is not suppressed."""
+
+ # There are three ways we might decide not to print an error message:
+ # a "NOLINT(category)" comment appears in the source,
+ # the verbosity level isn't high enough, or the filters filter it out.
+ if IsErrorSuppressedByNolint(category, linenum):
+ return False
+ if confidence < _cpplint_state.verbose_level:
+ return False
+
+ is_filtered = False
+ for one_filter in _Filters():
+ if one_filter.startswith('-'):
+ if category.startswith(one_filter[1:]):
+ is_filtered = True
+ elif one_filter.startswith('+'):
+ if category.startswith(one_filter[1:]):
+ is_filtered = False
+ else:
+ assert False # should have been checked for in SetFilter.
+ if is_filtered:
+ return False
+
+ return True
+
+
+def Error(filename, linenum, category, confidence, message):
+ """Logs the fact we've found a lint error.
+
+ We log where the error was found, and also our confidence in the error,
+ that is, how certain we are this is a legitimate style regression, and
+ not a misidentification or a use that's sometimes justified.
+
+ False positives can be suppressed by the use of
+ "cpplint(category)" comments on the offending line. These are
+ parsed into _error_suppressions.
+
+ Args:
+ filename: The name of the file containing the error.
+ linenum: The number of the line containing the error.
+ category: A string used to describe the "category" this bug
+ falls under: "whitespace", say, or "runtime". Categories
+ may have a hierarchy separated by slashes: "whitespace/indent".
+ confidence: A number from 1-5 representing a confidence score for
+ the error, with 5 meaning that we are certain of the problem,
+ and 1 meaning that it could be a legitimate construct.
+ message: The error message.
+ """
+ if _ShouldPrintError(category, confidence, linenum):
+ _cpplint_state.IncrementErrorCount(category)
+ if _cpplint_state.output_format == 'vs7':
+ sys.stderr.write('%s(%s): %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+ elif _cpplint_state.output_format == 'eclipse':
+ sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+ else:
+ sys.stderr.write('%s:%s: %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+
+
+# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
+_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
+ r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
+# Matches strings. Escape codes should already be removed by ESCAPES.
+_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
+# Matches characters. Escape codes should already be removed by ESCAPES.
+_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
+# Matches multi-line C++ comments.
+# This RE is a little bit more complicated than one might expect, because we
+# have to take care of space removals tools so we can handle comments inside
+# statements better.
+# The current rule is: We only clear spaces from both sides when we're at the
+# end of the line. Otherwise, we try to remove spaces from the right side,
+# if this doesn't work we try on left side but only if there's a non-character
+# on the right.
+_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
+ r"""(\s*/\*.*\*/\s*$|
+ /\*.*\*/\s+|
+ \s+/\*.*\*/(?=\W)|
+ /\*.*\*/)""", re.VERBOSE)
+
+
+def IsCppString(line):
+ """Does line terminate so, that the next symbol is in string constant.
+
+ This function does not consider single-line nor multi-line comments.
+
+ Args:
+ line: is a partial line of code starting from the 0..n.
+
+ Returns:
+ True, if next character appended to 'line' is inside a
+ string constant.
+ """
+
+ line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
+ return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
+
+
+def FindNextMultiLineCommentStart(lines, lineix):
+ """Find the beginning marker for a multiline comment."""
+ while lineix < len(lines):
+ if lines[lineix].strip().startswith('/*'):
+ # Only return this marker if the comment goes beyond this line
+ if lines[lineix].strip().find('*/', 2) < 0:
+ return lineix
+ lineix += 1
+ return len(lines)
+
+
+def FindNextMultiLineCommentEnd(lines, lineix):
+ """We are inside a comment, find the end marker."""
+ while lineix < len(lines):
+ if lines[lineix].strip().endswith('*/'):
+ return lineix
+ lineix += 1
+ return len(lines)
+
+
+def RemoveMultiLineCommentsFromRange(lines, begin, end):
+ """Clears a range of lines for multi-line comments."""
+ # Having // dummy comments makes the lines non-empty, so we will not get
+ # unnecessary blank line warnings later in the code.
+ for i in range(begin, end):
+ lines[i] = '// dummy'
+
+
+def RemoveMultiLineComments(filename, lines, error):
+ """Removes multiline (c-style) comments from lines."""
+ lineix = 0
+ while lineix < len(lines):
+ lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
+ if lineix_begin >= len(lines):
+ return
+ lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
+ if lineix_end >= len(lines):
+ error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
+ 'Could not find end of multi-line comment')
+ return
+ RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
+ lineix = lineix_end + 1
+
+
+def CleanseComments(line):
+ """Removes //-comments and single-line C-style /* */ comments.
+
+ Args:
+ line: A line of C++ source.
+
+ Returns:
+ The line with single-line comments removed.
+ """
+ commentpos = line.find('//')
+ if commentpos != -1 and not IsCppString(line[:commentpos]):
+ line = line[:commentpos].rstrip()
+ # get rid of /* ... */
+ return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
+
+
+class CleansedLines(object):
+ """Holds 3 copies of all lines with different preprocessing applied to them.
+
+ 1) elided member contains lines without strings and comments,
+ 2) lines member contains lines without comments, and
+ 3) raw_lines member contains all the lines without processing.
+ All these three members are of <type 'list'>, and of the same length.
+ """
+
+ def __init__(self, lines):
+ self.elided = []
+ self.lines = []
+ self.raw_lines = lines
+ self.num_lines = len(lines)
+ for linenum in range(len(lines)):
+ self.lines.append(CleanseComments(lines[linenum]))
+ elided = self._CollapseStrings(lines[linenum])
+ self.elided.append(CleanseComments(elided))
+
+ def NumLines(self):
+ """Returns the number of lines represented."""
+ return self.num_lines
+
+ @staticmethod
+ def _CollapseStrings(elided):
+ """Collapses strings and chars on a line to simple "" or '' blocks.
+
+ We nix strings first so we're not fooled by text like '"http://"'
+
+ Args:
+ elided: The line being processed.
+
+ Returns:
+ The line with collapsed strings.
+ """
+ if not _RE_PATTERN_INCLUDE.match(elided):
+ # Remove escaped characters first to make quote/single quote collapsing
+ # basic. Things that look like escaped characters shouldn't occur
+ # outside of strings and chars.
+ elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
+ elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
+ elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
+ return elided
+
+
+def FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar):
+ """Find the position just after the matching endchar.
+
+ Args:
+ line: a CleansedLines line.
+ startpos: start searching at this position.
+ depth: nesting level at startpos.
+ startchar: expression opening character.
+ endchar: expression closing character.
+
+ Returns:
+ Index just after endchar.
+ """
+ for i in xrange(startpos, len(line)):
+ if line[i] == startchar:
+ depth += 1
+ elif line[i] == endchar:
+ depth -= 1
+ if depth == 0:
+ return i + 1
+ return -1
+
+
+def CloseExpression(clean_lines, linenum, pos):
+ """If input points to ( or { or [, finds the position that closes it.
+
+ If lines[linenum][pos] points to a '(' or '{' or '[', finds the
+ linenum/pos that correspond to the closing of the expression.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ pos: A position on the line.
+
+ Returns:
+ A tuple (line, linenum, pos) pointer *past* the closing brace, or
+ (line, len(lines), -1) if we never find a close. Note we ignore
+ strings and comments when matching; and the line we return is the
+ 'cleansed' line at linenum.
+ """
+
+ line = clean_lines.elided[linenum]
+ startchar = line[pos]
+ if startchar not in '({[':
+ return (line, clean_lines.NumLines(), -1)
+ if startchar == '(': endchar = ')'
+ if startchar == '[': endchar = ']'
+ if startchar == '{': endchar = '}'
+
+ # Check first line
+ end_pos = FindEndOfExpressionInLine(line, pos, 0, startchar, endchar)
+ if end_pos > -1:
+ return (line, linenum, end_pos)
+ tail = line[pos:]
+ num_open = tail.count(startchar) - tail.count(endchar)
+ while linenum < clean_lines.NumLines() - 1:
+ linenum += 1
+ line = clean_lines.elided[linenum]
+ delta = line.count(startchar) - line.count(endchar)
+ if num_open + delta <= 0:
+ return (line, linenum,
+ FindEndOfExpressionInLine(line, 0, num_open, startchar, endchar))
+ num_open += delta
+
+ # Did not find endchar before end of file, give up
+ return (line, clean_lines.NumLines(), -1)
+
+def CheckForCopyright(filename, lines, error):
+ """Logs an error if no Copyright message appears at the top of the file."""
+
+ # We'll say it should occur by line 10. Don't forget there's a
+ # dummy line at the front.
+ for line in xrange(1, min(len(lines), 11)):
+ if re.search(r'Copyright', lines[line], re.I): break
+ else: # means no copyright line was found
+ error(filename, 0, 'legal/copyright', 5,
+ 'No copyright message found. '
+ 'You should have a line: "Copyright [year] <Copyright Owner>"')
+
+
+def GetHeaderGuardCPPVariable(filename):
+ """Returns the CPP variable that should be used as a header guard.
+
+ Args:
+ filename: The name of a C++ header file.
+
+ Returns:
+ The CPP variable that should be used as a header guard in the
+ named file.
+
+ """
+
+ # Restores original filename in case that cpplint is invoked from Emacs's
+ # flymake.
+ filename = re.sub(r'_flymake\.h$', '.h', filename)
+ filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
+
+ fileinfo = FileInfo(filename)
+ file_path_from_root = fileinfo.RepositoryName()
+ if _root:
+ file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
+ return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_'
+
+
+def CheckForHeaderGuard(filename, lines, error):
+ """Checks that the file contains a header guard.
+
+ Logs an error if no #ifndef header guard is present. For other
+ headers, checks that the full pathname is used.
+
+ Args:
+ filename: The name of the C++ header file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ cppvar = GetHeaderGuardCPPVariable(filename)
+
+ ifndef = None
+ ifndef_linenum = 0
+ define = None
+ endif = None
+ endif_linenum = 0
+ for linenum, line in enumerate(lines):
+ linesplit = line.split()
+ if len(linesplit) >= 2:
+ # find the first occurrence of #ifndef and #define, save arg
+ if not ifndef and linesplit[0] == '#ifndef':
+ # set ifndef to the header guard presented on the #ifndef line.
+ ifndef = linesplit[1]
+ ifndef_linenum = linenum
+ if not define and linesplit[0] == '#define':
+ define = linesplit[1]
+ # find the last occurrence of #endif, save entire line
+ if line.startswith('#endif'):
+ endif = line
+ endif_linenum = linenum
+
+ if not ifndef:
+ error(filename, 0, 'build/header_guard', 5,
+ 'No #ifndef header guard found, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ if not define:
+ error(filename, 0, 'build/header_guard', 5,
+ 'No #define header guard found, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
+ # for backward compatibility.
+ if ifndef != cppvar:
+ error_level = 0
+ if ifndef != cppvar + '_':
+ error_level = 5
+
+ ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
+ error)
+ error(filename, ifndef_linenum, 'build/header_guard', error_level,
+ '#ifndef header guard has wrong style, please use: %s' % cppvar)
+
+ if define != ifndef:
+ error(filename, 0, 'build/header_guard', 5,
+ '#ifndef and #define don\'t match, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ if endif != ('#endif // %s' % cppvar):
+ error_level = 0
+ if endif != ('#endif // %s' % (cppvar + '_')):
+ error_level = 5
+
+ ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
+ error)
+ error(filename, endif_linenum, 'build/header_guard', error_level,
+ '#endif line should be "#endif // %s"' % cppvar)
+
+
+def CheckForUnicodeReplacementCharacters(filename, lines, error):
+ """Logs an error for each line containing Unicode replacement characters.
+
+ These indicate that either the file contained invalid UTF-8 (likely)
+ or Unicode replacement characters (which it shouldn't). Note that
+ it's possible for this to throw off line numbering if the invalid
+ UTF-8 occurred adjacent to a newline.
+
+ Args:
+ filename: The name of the current file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+ for linenum, line in enumerate(lines):
+ if u'\ufffd' in line:
+ error(filename, linenum, 'readability/utf8', 5,
+ 'Line contains invalid UTF-8 (or Unicode replacement character).')
+
+
+def CheckForNewlineAtEOF(filename, lines, error):
+ """Logs an error if there is no newline char at the end of the file.
+
+ Args:
+ filename: The name of the current file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ # The array lines() was created by adding two newlines to the
+ # original file (go figure), then splitting on \n.
+ # To verify that the file ends in \n, we just have to make sure the
+ # last-but-two element of lines() exists and is empty.
+ if len(lines) < 3 or lines[-2]:
+ error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
+ 'Could not find a newline character at the end of the file.')
+
+
+def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
+ """Logs an error if we see /* ... */ or "..." that extend past one line.
+
+ /* ... */ comments are legit inside macros, for one line.
+ Otherwise, we prefer // comments, so it's ok to warn about the
+ other. Likewise, it's ok for strings to extend across multiple
+ lines, as long as a line continuation character (backslash)
+ terminates each line. Although not currently prohibited by the C++
+ style guide, it's ugly and unnecessary. We don't do well with either
+ in this lint program, so we warn about both.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Remove all \\ (escaped backslashes) from the line. They are OK, and the
+ # second (escaped) slash may trigger later \" detection erroneously.
+ line = line.replace('\\\\', '')
+
+ if line.count('/*') > line.count('*/'):
+ error(filename, linenum, 'readability/multiline_comment', 5,
+ 'Complex multi-line /*...*/-style comment found. '
+ 'Lint may give bogus warnings. '
+ 'Consider replacing these with //-style comments, '
+ 'with #if 0...#endif, '
+ 'or with more clearly structured multi-line comments.')
+
+ if (line.count('"') - line.count('\\"')) % 2:
+ error(filename, linenum, 'readability/multiline_string', 5,
+ 'Multi-line string ("...") found. This lint script doesn\'t '
+ 'do well with such strings, and may give bogus warnings. They\'re '
+ 'ugly and unnecessary, and you should use concatenation instead".')
+
+
+threading_list = (
+ ('asctime(', 'asctime_r('),
+ ('ctime(', 'ctime_r('),
+ ('getgrgid(', 'getgrgid_r('),
+ ('getgrnam(', 'getgrnam_r('),
+ ('getlogin(', 'getlogin_r('),
+ ('getpwnam(', 'getpwnam_r('),
+ ('getpwuid(', 'getpwuid_r('),
+ ('gmtime(', 'gmtime_r('),
+ ('localtime(', 'localtime_r('),
+ ('rand(', 'rand_r('),
+ ('readdir(', 'readdir_r('),
+ ('strtok(', 'strtok_r('),
+ ('ttyname(', 'ttyname_r('),
+ )
+
+
+def CheckPosixThreading(filename, clean_lines, linenum, error):
+ """Checks for calls to thread-unsafe functions.
+
+ Much code has been originally written without consideration of
+ multi-threading. Also, engineers are relying on their old experience;
+ they have learned posix before threading extensions were added. These
+ tests guide the engineers to use thread-safe functions (when using
+ posix directly).
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ for single_thread_function, multithread_safe_function in threading_list:
+ ix = line.find(single_thread_function)
+ # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
+ if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
+ line[ix - 1] not in ('_', '.', '>'))):
+ error(filename, linenum, 'runtime/threadsafe_fn', 2,
+ 'Consider using ' + multithread_safe_function +
+ '...) instead of ' + single_thread_function +
+ '...) for improved thread safety.')
+
+
+# Matches invalid increment: *count++, which moves pointer instead of
+# incrementing a value.
+_RE_PATTERN_INVALID_INCREMENT = re.compile(
+ r'^\s*\*\w+(\+\+|--);')
+
+
+def CheckInvalidIncrement(filename, clean_lines, linenum, error):
+ """Checks for invalid increment *count++.
+
+ For example following function:
+ void increment_counter(int* count) {
+ *count++;
+ }
+ is invalid, because it effectively does count++, moving pointer, and should
+ be replaced with ++*count, (*count)++ or *count += 1.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ if _RE_PATTERN_INVALID_INCREMENT.match(line):
+ error(filename, linenum, 'runtime/invalid_increment', 5,
+ 'Changing pointer instead of value (or unused value of operator*).')
+
+
+class _BlockInfo(object):
+ """Stores information about a generic block of code."""
+
+ def __init__(self, seen_open_brace):
+ self.seen_open_brace = seen_open_brace
+ self.open_parentheses = 0
+ self.inline_asm = _NO_ASM
+
+ def CheckBegin(self, filename, clean_lines, linenum, error):
+ """Run checks that applies to text up to the opening brace.
+
+ This is mostly for checking the text after the class identifier
+ and the "{", usually where the base class is specified. For other
+ blocks, there isn't much to check, so we always pass.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ pass
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ """Run checks that applies to text after the closing brace.
+
+ This is mostly used for checking end of namespace comments.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ pass
+
+
+class _ClassInfo(_BlockInfo):
+ """Stores information about a class."""
+
+ def __init__(self, name, class_or_struct, clean_lines, linenum):
+ _BlockInfo.__init__(self, False)
+ self.name = name
+ self.starting_linenum = linenum
+ self.is_derived = False
+ if class_or_struct == 'struct':
+ self.access = 'public'
+ else:
+ self.access = 'private'
+
+ # Try to find the end of the class. This will be confused by things like:
+ # class A {
+ # } *x = { ...
+ #
+ # But it's still good enough for CheckSectionSpacing.
+ self.last_line = 0
+ depth = 0
+ for i in range(linenum, clean_lines.NumLines()):
+ line = clean_lines.elided[i]
+ depth += line.count('{') - line.count('}')
+ if not depth:
+ self.last_line = i
+ break
+
+ def CheckBegin(self, filename, clean_lines, linenum, error):
+ # Look for a bare ':'
+ if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
+ self.is_derived = True
+
+
+class _NamespaceInfo(_BlockInfo):
+ """Stores information about a namespace."""
+
+ def __init__(self, name, linenum):
+ _BlockInfo.__init__(self, False)
+ self.name = name or ''
+ self.starting_linenum = linenum
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ """Check end of namespace comments."""
+ line = clean_lines.raw_lines[linenum]
+
+ # Check how many lines is enclosed in this namespace. Don't issue
+ # warning for missing namespace comments if there aren't enough
+ # lines. However, do apply checks if there is already an end of
+ # namespace comment and it's incorrect.
+ #
+ # TODO(unknown): We always want to check end of namespace comments
+ # if a namespace is large, but sometimes we also want to apply the
+ # check if a short namespace contained nontrivial things (something
+ # other than forward declarations). There is currently no logic on
+ # deciding what these nontrivial things are, so this check is
+ # triggered by namespace size only, which works most of the time.
+ if (linenum - self.starting_linenum < 10
+ and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
+ return
+
+ # Look for matching comment at end of namespace.
+ #
+ # Note that we accept C style "/* */" comments for terminating
+ # namespaces, so that code that terminate namespaces inside
+ # preprocessor macros can be cpplint clean. Example: http://go/nxpiz
+ #
+ # We also accept stuff like "// end of namespace <name>." with the
+ # period at the end.
+ #
+ # Besides these, we don't accept anything else, otherwise we might
+ # get false negatives when existing comment is a substring of the
+ # expected namespace. Example: http://go/ldkdc, http://cl/23548205
+ if self.name:
+ # Named namespace
+ if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
+ r'[\*/\.\\\s]*$'),
+ line):
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Namespace should be terminated with "// namespace %s"' %
+ self.name)
+ else:
+ # Anonymous namespace
+ if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Namespace should be terminated with "// namespace"')
+
+
+class _PreprocessorInfo(object):
+ """Stores checkpoints of nesting stacks when #if/#else is seen."""
+
+ def __init__(self, stack_before_if):
+ # The entire nesting stack before #if
+ self.stack_before_if = stack_before_if
+
+ # The entire nesting stack up to #else
+ self.stack_before_else = []
+
+ # Whether we have already seen #else or #elif
+ self.seen_else = False
+
+
+class _NestingState(object):
+ """Holds states related to parsing braces."""
+
+ def __init__(self):
+ # Stack for tracking all braces. An object is pushed whenever we
+ # see a "{", and popped when we see a "}". Only 3 types of
+ # objects are possible:
+ # - _ClassInfo: a class or struct.
+ # - _NamespaceInfo: a namespace.
+ # - _BlockInfo: some other type of block.
+ self.stack = []
+
+ # Stack of _PreprocessorInfo objects.
+ self.pp_stack = []
+
+ def SeenOpenBrace(self):
+ """Check if we have seen the opening brace for the innermost block.
+
+ Returns:
+ True if we have seen the opening brace, False if the innermost
+ block is still expecting an opening brace.
+ """
+ return (not self.stack) or self.stack[-1].seen_open_brace
+
+ def InNamespaceBody(self):
+ """Check if we are currently one level inside a namespace body.
+
+ Returns:
+ True if top of the stack is a namespace block, False otherwise.
+ """
+ return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
+
+ def UpdatePreprocessor(self, line):
+ """Update preprocessor stack.
+
+ We need to handle preprocessors due to classes like this:
+ #ifdef SWIG
+ struct ResultDetailsPageElementExtensionPoint {
+ #else
+ struct ResultDetailsPageElementExtensionPoint : public Extension {
+ #endif
+ (see http://go/qwddn for original example)
+
+ We make the following assumptions (good enough for most files):
+ - Preprocessor condition evaluates to true from #if up to first
+ #else/#elif/#endif.
+
+ - Preprocessor condition evaluates to false from #else/#elif up
+ to #endif. We still perform lint checks on these lines, but
+ these do not affect nesting stack.
+
+ Args:
+ line: current line to check.
+ """
+ if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
+ # Beginning of #if block, save the nesting stack here. The saved
+ # stack will allow us to restore the parsing state in the #else case.
+ self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
+ elif Match(r'^\s*#\s*(else|elif)\b', line):
+ # Beginning of #else block
+ if self.pp_stack:
+ if not self.pp_stack[-1].seen_else:
+ # This is the first #else or #elif block. Remember the
+ # whole nesting stack up to this point. This is what we
+ # keep after the #endif.
+ self.pp_stack[-1].seen_else = True
+ self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
+
+ # Restore the stack to how it was before the #if
+ self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
+ else:
+ # TODO(unknown): unexpected #else, issue warning?
+ pass
+ elif Match(r'^\s*#\s*endif\b', line):
+ # End of #if or #else blocks.
+ if self.pp_stack:
+ # If we saw an #else, we will need to restore the nesting
+ # stack to its former state before the #else, otherwise we
+ # will just continue from where we left off.
+ if self.pp_stack[-1].seen_else:
+ # Here we can just use a shallow copy since we are the last
+ # reference to it.
+ self.stack = self.pp_stack[-1].stack_before_else
+ # Drop the corresponding #if
+ self.pp_stack.pop()
+ else:
+ # TODO(unknown): unexpected #endif, issue warning?
+ pass
+
+ def Update(self, filename, clean_lines, linenum, error):
+ """Update nesting state with current line.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Update pp_stack first
+ self.UpdatePreprocessor(line)
+
+ # Count parentheses. This is to avoid adding struct arguments to
+ # the nesting stack.
+ if self.stack:
+ inner_block = self.stack[-1]
+ depth_change = line.count('(') - line.count(')')
+ inner_block.open_parentheses += depth_change
+
+ # Also check if we are starting or ending an inline assembly block.
+ if inner_block.inline_asm in (_NO_ASM, _END_ASM):
+ if (depth_change != 0 and
+ inner_block.open_parentheses == 1 and
+ _MATCH_ASM.match(line)):
+ # Enter assembly block
+ inner_block.inline_asm = _INSIDE_ASM
+ else:
+ # Not entering assembly block. If previous line was _END_ASM,
+ # we will now shift to _NO_ASM state.
+ inner_block.inline_asm = _NO_ASM
+ elif (inner_block.inline_asm == _INSIDE_ASM and
+ inner_block.open_parentheses == 0):
+ # Exit assembly block
+ inner_block.inline_asm = _END_ASM
+
+ # Consume namespace declaration at the beginning of the line. Do
+ # this in a loop so that we catch same line declarations like this:
+ # namespace proto2 { namespace bridge { class MessageSet; } }
+ while True:
+ # Match start of namespace. The "\b\s*" below catches namespace
+ # declarations even if it weren't followed by a whitespace, this
+ # is so that we don't confuse our namespace checker. The
+ # missing spaces will be flagged by CheckSpacing.
+ namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
+ if not namespace_decl_match:
+ break
+
+ new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
+ self.stack.append(new_namespace)
+
+ line = namespace_decl_match.group(2)
+ if line.find('{') != -1:
+ new_namespace.seen_open_brace = True
+ line = line[line.find('{') + 1:]
+
+ # Look for a class declaration in whatever is left of the line
+ # after parsing namespaces. The regexp accounts for decorated classes
+ # such as in:
+ # class LOCKABLE API Object {
+ # };
+ #
+ # Templates with class arguments may confuse the parser, for example:
+ # template <class T
+ # class Comparator = less<T>,
+ # class Vector = vector<T> >
+ # class HeapQueue {
+ #
+ # Because this parser has no nesting state about templates, by the
+ # time it saw "class Comparator", it may think that it's a new class.
+ # Nested templates have a similar problem:
+ # template <
+ # typename ExportedType,
+ # typename TupleType,
+ # template <typename, typename> class ImplTemplate>
+ #
+ # To avoid these cases, we ignore classes that are followed by '=' or '>'
+ class_decl_match = Match(
+ r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
+ '(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
+ '(([^=>]|<[^<>]*>)*)$', line)
+ if (class_decl_match and
+ (not self.stack or self.stack[-1].open_parentheses == 0)):
+ self.stack.append(_ClassInfo(
+ class_decl_match.group(4), class_decl_match.group(2),
+ clean_lines, linenum))
+ line = class_decl_match.group(5)
+
+ # If we have not yet seen the opening brace for the innermost block,
+ # run checks here.
+ if not self.SeenOpenBrace():
+ self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
+
+ # Update access control if we are inside a class/struct
+ if self.stack and isinstance(self.stack[-1], _ClassInfo):
+ access_match = Match(r'\s*(public|private|protected)\s*:', line)
+ if access_match:
+ self.stack[-1].access = access_match.group(1)
+
+ # Consume braces or semicolons from what's left of the line
+ while True:
+ # Match first brace, semicolon, or closed parenthesis.
+ matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
+ if not matched:
+ break
+
+ token = matched.group(1)
+ if token == '{':
+ # If namespace or class hasn't seen a opening brace yet, mark
+ # namespace/class head as complete. Push a new block onto the
+ # stack otherwise.
+ if not self.SeenOpenBrace():
+ self.stack[-1].seen_open_brace = True
+ else:
+ self.stack.append(_BlockInfo(True))
+ if _MATCH_ASM.match(line):
+ self.stack[-1].inline_asm = _BLOCK_ASM
+ elif token == ';' or token == ')':
+ # If we haven't seen an opening brace yet, but we already saw
+ # a semicolon, this is probably a forward declaration. Pop
+ # the stack for these.
+ #
+ # Similarly, if we haven't seen an opening brace yet, but we
+ # already saw a closing parenthesis, then these are probably
+ # function arguments with extra "class" or "struct" keywords.
+ # Also pop these stack for these.
+ if not self.SeenOpenBrace():
+ self.stack.pop()
+ else: # token == '}'
+ # Perform end of block checks and pop the stack.
+ if self.stack:
+ self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
+ self.stack.pop()
+ line = matched.group(2)
+
+ def InnermostClass(self):
+ """Get class info on the top of the stack.
+
+ Returns:
+ A _ClassInfo object if we are inside a class, or None otherwise.
+ """
+ for i in range(len(self.stack), 0, -1):
+ classinfo = self.stack[i - 1]
+ if isinstance(classinfo, _ClassInfo):
+ return classinfo
+ return None
+
+ def CheckClassFinished(self, filename, error):
+ """Checks that all classes have been completely parsed.
+
+ Call this when all lines in a file have been processed.
+ Args:
+ filename: The name of the current file.
+ error: The function to call with any errors found.
+ """
+ # Note: This test can result in false positives if #ifdef constructs
+ # get in the way of brace matching. See the testBuildClass test in
+ # cpplint_unittest.py for an example of this.
+ for obj in self.stack:
+ if isinstance(obj, _ClassInfo):
+ error(filename, obj.starting_linenum, 'build/class', 5,
+ 'Failed to find complete declaration of class %s' %
+ obj.name)
+
+
+def CheckForNonStandardConstructs(filename, clean_lines, linenum,
+ nesting_state, error):
+ """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
+
+ Complain about several constructs which gcc-2 accepts, but which are
+ not standard C++. Warning about these in lint is one way to ease the
+ transition to new compilers.
+ - put storage class first (e.g. "static const" instead of "const static").
+ - "%lld" instead of %qd" in printf-type functions.
+ - "%1$d" is non-standard in printf-type functions.
+ - "\%" is an undefined character escape sequence.
+ - text after #endif is not allowed.
+ - invalid inner-style forward declaration.
+ - >? and <? operators, and their >?= and <?= cousins.
+
+ Additionally, check for constructor/destructor style violations and reference
+ members, as it is very convenient to do so while checking for
+ gcc-2 compliance.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ """
+
+ # Remove comments from the line, but leave in strings for now.
+ line = clean_lines.lines[linenum]
+
+ if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
+ error(filename, linenum, 'runtime/printf_format', 3,
+ '%q in format strings is deprecated. Use %ll instead.')
+
+ if Search(r'printf\s*\(.*".*%\d+\$', line):
+ error(filename, linenum, 'runtime/printf_format', 2,
+ '%N$ formats are unconventional. Try rewriting to avoid them.')
+
+ # Remove escaped backslashes before looking for undefined escapes.
+ line = line.replace('\\\\', '')
+
+ if Search(r'("|\').*\\(%|\[|\(|{)', line):
+ error(filename, linenum, 'build/printf_format', 3,
+ '%, [, (, and { are undefined character escapes. Unescape them.')
+
+ # For the rest, work with both comments and strings removed.
+ line = clean_lines.elided[linenum]
+
+ if Search(r'\b(const|volatile|void|char|short|int|long'
+ r'|float|double|signed|unsigned'
+ r'|schar|u?int8|u?int16|u?int32|u?int64)'
+ r'\s+(register|static|extern|typedef)\b',
+ line):
+ error(filename, linenum, 'build/storage_class', 5,
+ 'Storage class (static, extern, typedef, etc) should be first.')
+
+ if Match(r'\s*#\s*endif\s*[^/\s]+', line):
+ error(filename, linenum, 'build/endif_comment', 5,
+ 'Uncommented text after #endif is non-standard. Use a comment.')
+
+ if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
+ error(filename, linenum, 'build/forward_decl', 5,
+ 'Inner-style forward declarations are invalid. Remove this line.')
+
+ if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
+ line):
+ error(filename, linenum, 'build/deprecated', 3,
+ '>? and <? (max and min) operators are non-standard and deprecated.')
+
+ if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
+ # TODO(unknown): Could it be expanded safely to arbitrary references,
+ # without triggering too many false positives? The first
+ # attempt triggered 5 warnings for mostly benign code in the regtest, hence
+ # the restriction.
+ # Here's the original regexp, for the reference:
+ # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
+ # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
+ error(filename, linenum, 'runtime/member_string_references', 2,
+ 'const string& members are dangerous. It is much better to use '
+ 'alternatives, such as pointers or simple constants.')
+
+ # Everything else in this function operates on class declarations.
+ # Return early if the top of the nesting stack is not a class, or if
+ # the class head is not completed yet.
+ classinfo = nesting_state.InnermostClass()
+ if not classinfo or not classinfo.seen_open_brace:
+ return
+
+ # The class may have been declared with namespace or classname qualifiers.
+ # The constructor and destructor will not have those qualifiers.
+ base_classname = classinfo.name.split('::')[-1]
+
+ # Look for single-argument constructors that aren't marked explicit.
+ # Technically a valid construct, but against style.
+ args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)'
+ % re.escape(base_classname),
+ line)
+ if (args and
+ args.group(1) != 'void' and
+ not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
+ args.group(1).strip())):
+ error(filename, linenum, 'runtime/explicit', 5,
+ 'Single-argument constructors should be marked explicit.')
+
+
+def CheckSpacingForFunctionCall(filename, line, linenum, error):
+ """Checks for the correctness of various spacing around function calls.
+
+ Args:
+ filename: The name of the current file.
+ line: The text of the line to check.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Since function calls often occur inside if/for/while/switch
+ # expressions - which have their own, more liberal conventions - we
+ # first see if we should be looking inside such an expression for a
+ # function call, to which we can apply more strict standards.
+ fncall = line # if there's no control flow construct, look at whole line
+ for pattern in (r'\bif\s*\((.*)\)\s*{',
+ r'\bfor\s*\((.*)\)\s*{',
+ r'\bwhile\s*\((.*)\)\s*[{;]',
+ r'\bswitch\s*\((.*)\)\s*{'):
+ match = Search(pattern, line)
+ if match:
+ fncall = match.group(1) # look inside the parens for function calls
+ break
+
+ # Except in if/for/while/switch, there should never be space
+ # immediately inside parens (eg "f( 3, 4 )"). We make an exception
+ # for nested parens ( (a+b) + c ). Likewise, there should never be
+ # a space before a ( when it's a function argument. I assume it's a
+ # function argument when the char before the whitespace is legal in
+ # a function name (alnum + _) and we're not starting a macro. Also ignore
+ # pointers and references to arrays and functions coz they're too tricky:
+ # we use a very simple way to recognize these:
+ # " (something)(maybe-something)" or
+ # " (something)(maybe-something," or
+ # " (something)[something]"
+ # Note that we assume the contents of [] to be short enough that
+ # they'll never need to wrap.
+ if ( # Ignore control structures.
+ not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and
+ # Ignore pointers/references to functions.
+ not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
+ # Ignore pointers/references to arrays.
+ not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
+ if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call
+ error(filename, linenum, 'whitespace/parens', 4,
+ 'Extra space after ( in function call')
+ elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Extra space after (')
+ if (Search(r'\w\s+\(', fncall) and
+ not Search(r'#\s*define|typedef', fncall) and
+ not Search(r'\w\s+\((\w+::)?\*\w+\)\(', fncall)):
+ error(filename, linenum, 'whitespace/parens', 4,
+ 'Extra space before ( in function call')
+ # If the ) is followed only by a newline or a { + newline, assume it's
+ # part of a control statement (if/while/etc), and don't complain
+ if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
+ # If the closing parenthesis is preceded by only whitespaces,
+ # try to give a more descriptive error message.
+ if Search(r'^\s+\)', fncall):
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Closing ) should be moved to the previous line')
+ else:
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Extra space before )')
+
+
+def IsBlankLine(line):
+ """Returns true if the given line is blank.
+
+ We consider a line to be blank if the line is empty or consists of
+ only white spaces.
+
+ Args:
+ line: A line of a string.
+
+ Returns:
+ True, if the given line is blank.
+ """
+ return not line or line.isspace()
+
+
+def CheckForFunctionLengths(filename, clean_lines, linenum,
+ function_state, error):
+ """Reports for long function bodies.
+
+ For an overview why this is done, see:
+ http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
+
+ Uses a simplistic algorithm assuming other style guidelines
+ (especially spacing) are followed.
+ Only checks unindented functions, so class members are unchecked.
+ Trivial bodies are unchecked, so constructors with huge initializer lists
+ may be missed.
+ Blank/comment lines are not counted so as to avoid encouraging the removal
+ of vertical space and comments just to get through a lint check.
+ NOLINT *on the last line of a function* disables this check.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ function_state: Current function name and lines in body so far.
+ error: The function to call with any errors found.
+ """
+ lines = clean_lines.lines
+ line = lines[linenum]
+ raw = clean_lines.raw_lines
+ raw_line = raw[linenum]
+ joined_line = ''
+
+ starting_func = False
+ regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ...
+ match_result = Match(regexp, line)
+ if match_result:
+ # If the name is all caps and underscores, figure it's a macro and
+ # ignore it, unless it's TEST or TEST_F.
+ function_name = match_result.group(1).split()[-1]
+ if function_name == 'TEST' or function_name == 'TEST_F' or (
+ not Match(r'[A-Z_]+$', function_name)):
+ starting_func = True
+
+ if starting_func:
+ body_found = False
+ for start_linenum in xrange(linenum, clean_lines.NumLines()):
+ start_line = lines[start_linenum]
+ joined_line += ' ' + start_line.lstrip()
+ if Search(r'(;|})', start_line): # Declarations and trivial functions
+ body_found = True
+ break # ... ignore
+ elif Search(r'{', start_line):
+ body_found = True
+ function = Search(r'((\w|:)*)\(', line).group(1)
+ if Match(r'TEST', function): # Handle TEST... macros
+ parameter_regexp = Search(r'(\(.*\))', joined_line)
+ if parameter_regexp: # Ignore bad syntax
+ function += parameter_regexp.group(1)
+ else:
+ function += '()'
+ function_state.Begin(function)
+ break
+ if not body_found:
+ # No body for the function (or evidence of a non-function) was found.
+ error(filename, linenum, 'readability/fn_size', 5,
+ 'Lint failed to find start of function body.')
+ elif Match(r'^\}\s*$', line): # function end
+ function_state.Check(error, filename, linenum)
+ function_state.End()
+ elif not Match(r'^\s*$', line):
+ function_state.Count() # Count non-blank/non-comment lines.
+
+
+_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
+
+
+def CheckComment(comment, filename, linenum, error):
+ """Checks for common mistakes in TODO comments.
+
+ Args:
+ comment: The text of the comment from the line in question.
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ match = _RE_PATTERN_TODO.match(comment)
+ if match:
+ # One whitespace is correct; zero whitespace is handled elsewhere.
+ leading_whitespace = match.group(1)
+ if len(leading_whitespace) > 1:
+ error(filename, linenum, 'whitespace/todo', 2,
+ 'Too many spaces before TODO')
+
+ username = match.group(2)
+ if not username:
+ error(filename, linenum, 'readability/todo', 2,
+ 'Missing username in TODO; it should look like '
+ '"// TODO(my_username): Stuff."')
+
+ middle_whitespace = match.group(3)
+ # Comparisons made explicit for correctness -- pylint: disable-msg=C6403
+ if middle_whitespace != ' ' and middle_whitespace != '':
+ error(filename, linenum, 'whitespace/todo', 2,
+ 'TODO(my_username) should be followed by a space')
+
+def CheckAccess(filename, clean_lines, linenum, nesting_state, error):
+ """Checks for improper use of DISALLOW* macros.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
+ r'DISALLOW_EVIL_CONSTRUCTORS|'
+ r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
+ if not matched:
+ return
+ if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
+ if nesting_state.stack[-1].access != 'private':
+ error(filename, linenum, 'readability/constructors', 3,
+ '%s must be in the private: section' % matched.group(1))
+
+ else:
+ # Found DISALLOW* macro outside a class declaration, or perhaps it
+ # was used inside a function when it should have been part of the
+ # class declaration. We could issue a warning here, but it
+ # probably resulted in a compiler error already.
+ pass
+
+
+def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
+ """Find the corresponding > to close a template.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: Current line number.
+ init_suffix: Remainder of the current line after the initial <.
+
+ Returns:
+ True if a matching bracket exists.
+ """
+ line = init_suffix
+ nesting_stack = ['<']
+ while True:
+ # Find the next operator that can tell us whether < is used as an
+ # opening bracket or as a less-than operator. We only want to
+ # warn on the latter case.
+ #
+ # We could also check all other operators and terminate the search
+ # early, e.g. if we got something like this "a<b+c", the "<" is
+ # most likely a less-than operator, but then we will get false
+ # positives for default arguments (e.g. http://go/prccd) and
+ # other template expressions (e.g. http://go/oxcjq).
+ match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line)
+ if match:
+ # Found an operator, update nesting stack
+ operator = match.group(1)
+ line = match.group(2)
+
+ if nesting_stack[-1] == '<':
+ # Expecting closing angle bracket
+ if operator in ('<', '(', '['):
+ nesting_stack.append(operator)
+ elif operator == '>':
+ nesting_stack.pop()
+ if not nesting_stack:
+ # Found matching angle bracket
+ return True
+ elif operator == ',':
+ # Got a comma after a bracket, this is most likely a template
+ # argument. We have not seen a closing angle bracket yet, but
+ # it's probably a few lines later if we look for it, so just
+ # return early here.
+ return True
+ else:
+ # Got some other operator.
+ return False
+
+ else:
+ # Expecting closing parenthesis or closing bracket
+ if operator in ('<', '(', '['):
+ nesting_stack.append(operator)
+ elif operator in (')', ']'):
+ # We don't bother checking for matching () or []. If we got
+ # something like (] or [), it would have been a syntax error.
+ nesting_stack.pop()
+
+ else:
+ # Scan the next line
+ linenum += 1
+ if linenum >= len(clean_lines.elided):
+ break
+ line = clean_lines.elided[linenum]
+
+ # Exhausted all remaining lines and still no matching angle bracket.
+ # Most likely the input was incomplete, otherwise we should have
+ # seen a semicolon and returned early.
+ return True
+
+
+def FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix):
+ """Find the corresponding < that started a template.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: Current line number.
+ init_prefix: Part of the current line before the initial >.
+
+ Returns:
+ True if a matching bracket exists.
+ """
+ line = init_prefix
+ nesting_stack = ['>']
+ while True:
+ # Find the previous operator
+ match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line)
+ if match:
+ # Found an operator, update nesting stack
+ operator = match.group(2)
+ line = match.group(1)
+
+ if nesting_stack[-1] == '>':
+ # Expecting opening angle bracket
+ if operator in ('>', ')', ']'):
+ nesting_stack.append(operator)
+ elif operator == '<':
+ nesting_stack.pop()
+ if not nesting_stack:
+ # Found matching angle bracket
+ return True
+ elif operator == ',':
+ # Got a comma before a bracket, this is most likely a
+ # template argument. The opening angle bracket is probably
+ # there if we look for it, so just return early here.
+ return True
+ else:
+ # Got some other operator.
+ return False
+
+ else:
+ # Expecting opening parenthesis or opening bracket
+ if operator in ('>', ')', ']'):
+ nesting_stack.append(operator)
+ elif operator in ('(', '['):
+ nesting_stack.pop()
+
+ else:
+ # Scan the previous line
+ linenum -= 1
+ if linenum < 0:
+ break
+ line = clean_lines.elided[linenum]
+
+ # Exhausted all earlier lines and still no matching angle bracket.
+ return False
+
+
+def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
+ """Checks for the correctness of various spacing issues in the code.
+
+ Things we check for: spaces around operators, spaces after
+ if/for/while/switch, no spaces around parens in function calls, two
+ spaces between code and comment, don't start a block with a blank
+ line, don't end a function with a blank line, don't add a blank line
+ after public/protected/private, don't have too many blank lines in a row.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+
+ raw = clean_lines.raw_lines
+ line = raw[linenum]
+
+ # Before nixing comments, check if the line is blank for no good
+ # reason. This includes the first line after a block is opened, and
+ # blank lines at the end of a function (ie, right before a line like '}'
+ #
+ # Skip all the blank line checks if we are immediately inside a
+ # namespace body. In other words, don't issue blank line warnings
+ # for this block:
+ # namespace {
+ #
+ # }
+ #
+ # A warning about missing end of namespace comments will be issued instead.
+ if IsBlankLine(line) and not nesting_state.InNamespaceBody():
+ elided = clean_lines.elided
+ prev_line = elided[linenum - 1]
+ prevbrace = prev_line.rfind('{')
+ # TODO(unknown): Don't complain if line before blank line, and line after,
+ # both start with alnums and are indented the same amount.
+ # This ignores whitespace at the start of a namespace block
+ # because those are not usually indented.
+ if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
+ # OK, we have a blank line at the start of a code block. Before we
+ # complain, we check if it is an exception to the rule: The previous
+ # non-empty line has the parameters of a function header that are indented
+ # 4 spaces (because they did not fit in a 80 column line when placed on
+ # the same line as the function name). We also check for the case where
+ # the previous line is indented 6 spaces, which may happen when the
+ # initializers of a constructor do not fit into a 80 column line.
+ exception = False
+ if Match(r' {6}\w', prev_line): # Initializer list?
+ # We are looking for the opening column of initializer list, which
+ # should be indented 4 spaces to cause 6 space indentation afterwards.
+ search_position = linenum-2
+ while (search_position >= 0
+ and Match(r' {6}\w', elided[search_position])):
+ search_position -= 1
+ exception = (search_position >= 0
+ and elided[search_position][:5] == ' :')
+ else:
+ # Search for the function arguments or an initializer list. We use a
+ # simple heuristic here: If the line is indented 4 spaces; and we have a
+ # closing paren, without the opening paren, followed by an opening brace
+ # or colon (for initializer lists) we assume that it is the last line of
+ # a function header. If we have a colon indented 4 spaces, it is an
+ # initializer list.
+ exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
+ prev_line)
+ or Match(r' {4}:', prev_line))
+
+ if not exception:
+ error(filename, linenum, 'whitespace/blank_line', 2,
+ 'Blank line at the start of a code block. Is this needed?')
+ # Ignore blank lines at the end of a block in a long if-else
+ # chain, like this:
+ # if (condition1) {
+ # // Something followed by a blank line
+ #
+ # } else if (condition2) {
+ # // Something else
+ # }
+ if linenum + 1 < clean_lines.NumLines():
+ next_line = raw[linenum + 1]
+ if (next_line
+ and Match(r'\s*}', next_line)
+ and next_line.find('} else ') == -1):
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ 'Blank line at the end of a code block. Is this needed?')
+
+ matched = Match(r'\s*(public|protected|private):', prev_line)
+ if matched:
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ 'Do not leave a blank line after "%s:"' % matched.group(1))
+
+ # Next, we complain if there's a comment too near the text
+ commentpos = line.find('//')
+ if commentpos != -1:
+ # Check if the // may be in quotes. If so, ignore it
+ # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
+ if (line.count('"', 0, commentpos) -
+ line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes
+ # Allow one space for new scopes, two spaces otherwise:
+ if (not Match(r'^\s*{ //', line) and
+ ((commentpos >= 1 and
+ line[commentpos-1] not in string.whitespace) or
+ (commentpos >= 2 and
+ line[commentpos-2] not in string.whitespace))):
+ error(filename, linenum, 'whitespace/comments', 2,
+ 'At least two spaces is best between code and comments')
+ # There should always be a space between the // and the comment
+ commentend = commentpos + 2
+ if commentend < len(line) and not line[commentend] == ' ':
+ # but some lines are exceptions -- e.g. if they're big
+ # comment delimiters like:
+ # //----------------------------------------------------------
+ # or are an empty C++ style Doxygen comment, like:
+ # ///
+ # or they begin with multiple slashes followed by a space:
+ # //////// Header comment
+ match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
+ Search(r'^/$', line[commentend:]) or
+ Search(r'^/+ ', line[commentend:]))
+ if not match:
+ error(filename, linenum, 'whitespace/comments', 4,
+ 'Should have a space between // and comment')
+ CheckComment(line[commentpos:], filename, linenum, error)
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ # Don't try to do spacing checks for operator methods
+ line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
+
+ # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
+ # Otherwise not. Note we only check for non-spaces on *both* sides;
+ # sometimes people put non-spaces on one side when aligning ='s among
+ # many lines (not that this is behavior that I approve of...)
+ if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line):
+ error(filename, linenum, 'whitespace/operators', 4,
+ 'Missing spaces around =')
+
+ # It's ok not to have spaces around binary operators like + - * /, but if
+ # there's too little whitespace, we get concerned. It's hard to tell,
+ # though, so we punt on this one for now. TODO.
+
+ # You should always have whitespace around binary operators.
+ #
+ # Check <= and >= first to avoid false positives with < and >, then
+ # check non-include lines for spacing around < and >.
+ match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around %s' % match.group(1))
+ # We allow no-spaces around << when used like this: 10<<20, but
+ # not otherwise (particularly, not when used as streams)
+ match = Search(r'(\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line)
+ if match and not (match.group(1).isdigit() and match.group(2).isdigit()):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around <<')
+ elif not Match(r'#.*include', line):
+ # Avoid false positives on ->
+ reduced_line = line.replace('->', '')
+
+ # Look for < that is not surrounded by spaces. This is only
+ # triggered if both sides are missing spaces, even though
+ # technically should should flag if at least one side is missing a
+ # space. This is done to avoid some false positives with shifts.
+ match = Search(r'[^\s<]<([^\s=<].*)', reduced_line)
+ if (match and
+ not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around <')
+
+ # Look for > that is not surrounded by spaces. Similar to the
+ # above, we only trigger if both sides are missing spaces to avoid
+ # false positives with shifts.
+ match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line)
+ if (match and
+ not FindPreviousMatchingAngleBracket(clean_lines, linenum,
+ match.group(1))):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around >')
+
+ # We allow no-spaces around >> for almost anything. This is because
+ # C++11 allows ">>" to close nested templates, which accounts for
+ # most cases when ">>" is not followed by a space.
+ #
+ # We still warn on ">>" followed by alpha character, because that is
+ # likely due to ">>" being used for right shifts, e.g.:
+ # value >> alpha
+ #
+ # When ">>" is used to close templates, the alphanumeric letter that
+ # follows would be part of an identifier, and there should still be
+ # a space separating the template type and the identifier.
+ # type<type<type>> alpha
+ match = Search(r'>>[a-zA-Z_]', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around >>')
+
+ # There shouldn't be space around unary operators
+ match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 4,
+ 'Extra space for operator %s' % match.group(1))
+
+ # A pet peeve of mine: no spaces after an if, while, switch, or for
+ match = Search(r' (if\(|for\(|while\(|switch\()', line)
+ if match:
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Missing space before ( in %s' % match.group(1))
+
+ # For if/for/while/switch, the left and right parens should be
+ # consistent about how many spaces are inside the parens, and
+ # there should either be zero or one spaces inside the parens.
+ # We don't want: "if ( foo)" or "if ( foo )".
+ # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
+ match = Search(r'\b(if|for|while|switch)\s*'
+ r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
+ line)
+ if match:
+ if len(match.group(2)) != len(match.group(4)):
+ if not (match.group(3) == ';' and
+ len(match.group(2)) == 1 + len(match.group(4)) or
+ not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Mismatching spaces inside () in %s' % match.group(1))
+ if not len(match.group(2)) in [0, 1]:
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Should have zero or one spaces inside ( and ) in %s' %
+ match.group(1))
+
+ # You should always have a space after a comma (either as fn arg or operator)
+ if Search(r',[^\s]', line):
+ error(filename, linenum, 'whitespace/comma', 3,
+ 'Missing space after ,')
+
+ # You should always have a space after a semicolon
+ # except for few corner cases
+ # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
+ # space after ;
+ if Search(r';[^\s};\\)/]', line):
+ error(filename, linenum, 'whitespace/semicolon', 3,
+ 'Missing space after ;')
+
+ # Next we will look for issues with function calls.
+ CheckSpacingForFunctionCall(filename, line, linenum, error)
+
+ # Except after an opening paren, or after another opening brace (in case of
+ # an initializer list, for instance), you should have spaces before your
+ # braces. And since you should never have braces at the beginning of a line,
+ # this is an easy test.
+ if Search(r'[^ ({]{', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Missing space before {')
+
+ # Make sure '} else {' has spaces.
+ if Search(r'}else', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Missing space before else')
+
+ # You shouldn't have spaces before your brackets, except maybe after
+ # 'delete []' or 'new char * []'.
+ if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Extra space before [')
+
+ # You shouldn't have a space before a semicolon at the end of the line.
+ # There's a special case for "for" since the style guide allows space before
+ # the semicolon there.
+ if Search(r':\s*;\s*$', line):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Semicolon defining empty statement. Use {} instead.')
+ elif Search(r'^\s*;\s*$', line):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Line contains only semicolon. If this should be an empty statement, '
+ 'use {} instead.')
+ elif (Search(r'\s+;\s*$', line) and
+ not Search(r'\bfor\b', line)):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Extra space before last semicolon. If this should be an empty '
+ 'statement, use {} instead.')
+
+ # In range-based for, we wanted spaces before and after the colon, but
+ # not around "::" tokens that might appear.
+ if (Search('for *\(.*[^:]:[^: ]', line) or
+ Search('for *\(.*[^: ]:[^:]', line)):
+ error(filename, linenum, 'whitespace/forcolon', 2,
+ 'Missing space around colon in range-based for loop')
+
+
+def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
+ """Checks for additional blank line issues related to sections.
+
+ Currently the only thing checked here is blank line before protected/private.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ class_info: A _ClassInfo objects.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ # Skip checks if the class is small, where small means 25 lines or less.
+ # 25 lines seems like a good cutoff since that's the usual height of
+ # terminals, and any class that can't fit in one screen can't really
+ # be considered "small".
+ #
+ # Also skip checks if we are on the first line. This accounts for
+ # classes that look like
+ # class Foo { public: ... };
+ #
+ # If we didn't find the end of the class, last_line would be zero,
+ # and the check will be skipped by the first condition.
+ if (class_info.last_line - class_info.starting_linenum <= 24 or
+ linenum <= class_info.starting_linenum):
+ return
+
+ matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
+ if matched:
+ # Issue warning if the line before public/protected/private was
+ # not a blank line, but don't do this if the previous line contains
+ # "class" or "struct". This can happen two ways:
+ # - We are at the beginning of the class.
+ # - We are forward-declaring an inner class that is semantically
+ # private, but needed to be public for implementation reasons.
+ # Also ignores cases where the previous line ends with a backslash as can be
+ # common when defining classes in C macros.
+ prev_line = clean_lines.lines[linenum - 1]
+ if (not IsBlankLine(prev_line) and
+ not Search(r'\b(class|struct)\b', prev_line) and
+ not Search(r'\\$', prev_line)):
+ # Try a bit harder to find the beginning of the class. This is to
+ # account for multi-line base-specifier lists, e.g.:
+ # class Derived
+ # : public Base {
+ end_class_head = class_info.starting_linenum
+ for i in range(class_info.starting_linenum, linenum):
+ if Search(r'\{\s*$', clean_lines.lines[i]):
+ end_class_head = i
+ break
+ if end_class_head < linenum - 1:
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ '"%s:" should be preceded by a blank line' % matched.group(1))
+
+
+def GetPreviousNonBlankLine(clean_lines, linenum):
+ """Return the most recent non-blank line and its line number.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file contents.
+ linenum: The number of the line to check.
+
+ Returns:
+ A tuple with two elements. The first element is the contents of the last
+ non-blank line before the current line, or the empty string if this is the
+ first non-blank line. The second is the line number of that line, or -1
+ if this is the first non-blank line.
+ """
+
+ prevlinenum = linenum - 1
+ while prevlinenum >= 0:
+ prevline = clean_lines.elided[prevlinenum]
+ if not IsBlankLine(prevline): # if not a blank line...
+ return (prevline, prevlinenum)
+ prevlinenum -= 1
+ return ('', -1)
+
+
+def CheckBraces(filename, clean_lines, linenum, error):
+ """Looks for misplaced braces (e.g. at the end of line).
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ if Match(r'\s*{\s*$', line):
+ # We allow an open brace to start a line in the case where someone
+ # is using braces in a block to explicitly create a new scope,
+ # which is commonly used to control the lifetime of
+ # stack-allocated variables. We don't detect this perfectly: we
+ # just don't complain if the last non-whitespace character on the
+ # previous non-blank line is ';', ':', '{', or '}', or if the previous
+ # line starts a preprocessor block.
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if (not Search(r'[;:}{]\s*$', prevline) and
+ not Match(r'\s*#', prevline)):
+ error(filename, linenum, 'whitespace/braces', 4,
+ '{ should almost always be at the end of the previous line')
+
+ # An else clause should be on the same line as the preceding closing brace.
+ if Match(r'\s*else\s*', line):
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if Match(r'\s*}\s*$', prevline):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'An else should appear on the same line as the preceding }')
+
+ # If braces come on one side of an else, they should be on both.
+ # However, we have to worry about "else if" that spans multiple lines!
+ if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
+ if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if
+ # find the ( after the if
+ pos = line.find('else if')
+ pos = line.find('(', pos)
+ if pos > 0:
+ (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
+ if endline[endpos:].find('{') == -1: # must be brace after if
+ error(filename, linenum, 'readability/braces', 5,
+ 'If an else has a brace on one side, it should have it on both')
+ else: # common case: else not followed by a multi-line if
+ error(filename, linenum, 'readability/braces', 5,
+ 'If an else has a brace on one side, it should have it on both')
+
+ # Likewise, an else should never have the else clause on the same line
+ if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'Else clause should never be on same line as else (use 2 lines)')
+
+ # In the same way, a do/while should never be on one line
+ if Match(r'\s*do [^\s{]', line):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'do/while clauses should not be on a single line')
+
+ # Braces shouldn't be followed by a ; unless they're defining a struct
+ # or initializing an array.
+ # We can't tell in general, but we can for some common cases.
+ prevlinenum = linenum
+ while True:
+ (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum)
+ if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'):
+ line = prevline + line
+ else:
+ break
+ if (Search(r'{.*}\s*;', line) and
+ line.count('{') == line.count('}') and
+ not Search(r'struct|class|enum|\s*=\s*{', line)):
+ error(filename, linenum, 'readability/braces', 4,
+ "You don't need a ; after a }")
+
+
+def CheckEmptyLoopBody(filename, clean_lines, linenum, error):
+ """Loop for empty loop body with only a single semicolon.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Search for loop keywords at the beginning of the line. Because only
+ # whitespaces are allowed before the keywords, this will also ignore most
+ # do-while-loops, since those lines should start with closing brace.
+ line = clean_lines.elided[linenum]
+ if Match(r'\s*(for|while)\s*\(', line):
+ # Find the end of the conditional expression
+ (end_line, end_linenum, end_pos) = CloseExpression(
+ clean_lines, linenum, line.find('('))
+
+ # Output warning if what follows the condition expression is a semicolon.
+ # No warning for all other cases, including whitespace or newline, since we
+ # have a separate check for semicolons preceded by whitespace.
+ if end_pos >= 0 and Match(r';', end_line[end_pos:]):
+ error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
+ 'Empty loop bodies should use {} or continue')
+
+
+def ReplaceableCheck(operator, macro, line):
+ """Determine whether a basic CHECK can be replaced with a more specific one.
+
+ For example suggest using CHECK_EQ instead of CHECK(a == b) and
+ similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
+
+ Args:
+ operator: The C++ operator used in the CHECK.
+ macro: The CHECK or EXPECT macro being called.
+ line: The current source line.
+
+ Returns:
+ True if the CHECK can be replaced with a more specific one.
+ """
+
+ # This matches decimal and hex integers, strings, and chars (in that order).
+ match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
+
+ # Expression to match two sides of the operator with something that
+ # looks like a literal, since CHECK(x == iterator) won't compile.
+ # This means we can't catch all the cases where a more specific
+ # CHECK is possible, but it's less annoying than dealing with
+ # extraneous warnings.
+ match_this = (r'\s*' + macro + r'\((\s*' +
+ match_constant + r'\s*' + operator + r'[^<>].*|'
+ r'.*[^<>]' + operator + r'\s*' + match_constant +
+ r'\s*\))')
+
+ # Don't complain about CHECK(x == NULL) or similar because
+ # CHECK_EQ(x, NULL) won't compile (requires a cast).
+ # Also, don't complain about more complex boolean expressions
+ # involving && or || such as CHECK(a == b || c == d).
+ return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line)
+
+
+def CheckCheck(filename, clean_lines, linenum, error):
+ """Checks the use of CHECK and EXPECT macros.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Decide the set of replacement macros that should be suggested
+ raw_lines = clean_lines.raw_lines
+ current_macro = ''
+ for macro in _CHECK_MACROS:
+ if raw_lines[linenum].find(macro) >= 0:
+ current_macro = macro
+ break
+ if not current_macro:
+ # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
+ return
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
+ for operator in ['==', '!=', '>=', '>', '<=', '<']:
+ if ReplaceableCheck(operator, current_macro, line):
+ error(filename, linenum, 'readability/check', 2,
+ 'Consider using %s instead of %s(a %s b)' % (
+ _CHECK_REPLACEMENT[current_macro][operator],
+ current_macro, operator))
+ break
+
+
+def CheckAltTokens(filename, clean_lines, linenum, error):
+ """Check alternative keywords being used in boolean expressions.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Avoid preprocessor lines
+ if Match(r'^\s*#', line):
+ return
+
+ # Last ditch effort to avoid multi-line comments. This will not help
+ # if the comment started before the current line or ended after the
+ # current line, but it catches most of the false positives. At least,
+ # it provides a way to workaround this warning for people who use
+ # multi-line comments in preprocessor macros.
+ #
+ # TODO(unknown): remove this once cpplint has better support for
+ # multi-line comments.
+ if line.find('/*') >= 0 or line.find('*/') >= 0:
+ return
+
+ for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
+ error(filename, linenum, 'readability/alt_tokens', 2,
+ 'Use operator %s instead of %s' % (
+ _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
+
+
+def GetLineWidth(line):
+ """Determines the width of the line in column positions.
+
+ Args:
+ line: A string, which may be a Unicode string.
+
+ Returns:
+ The width of the line in column positions, accounting for Unicode
+ combining characters and wide characters.
+ """
+ if isinstance(line, unicode):
+ width = 0
+ for uc in unicodedata.normalize('NFC', line):
+ if unicodedata.east_asian_width(uc) in ('W', 'F'):
+ width += 2
+ elif not unicodedata.combining(uc):
+ width += 1
+ return width
+ else:
+ return len(line)
+
+
+def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
+ error):
+ """Checks rules from the 'C++ style rules' section of cppguide.html.
+
+ Most of these rules are hard to test (naming, comment style), but we
+ do what we can. In particular we check for 2-space indents, line lengths,
+ tab usage, spaces inside code, etc.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+
+ raw_lines = clean_lines.raw_lines
+ line = raw_lines[linenum]
+
+ if line.find('\t') != -1:
+ error(filename, linenum, 'whitespace/tab', 1,
+ 'Tab found; better to use spaces')
+
+ # One or three blank spaces at the beginning of the line is weird; it's
+ # hard to reconcile that with 2-space indents.
+ # NOTE: here are the conditions rob pike used for his tests. Mine aren't
+ # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces
+ # if(RLENGTH > 20) complain = 0;
+ # if(match($0, " +(error|private|public|protected):")) complain = 0;
+ # if(match(prev, "&& *$")) complain = 0;
+ # if(match(prev, "\\|\\| *$")) complain = 0;
+ # if(match(prev, "[\",=><] *$")) complain = 0;
+ # if(match($0, " <<")) complain = 0;
+ # if(match(prev, " +for \\(")) complain = 0;
+ # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
+ initial_spaces = 0
+ cleansed_line = clean_lines.elided[linenum]
+ while initial_spaces < len(line) and line[initial_spaces] == ' ':
+ initial_spaces += 1
+ if line and line[-1].isspace():
+ error(filename, linenum, 'whitespace/end_of_line', 4,
+ 'Line ends in whitespace. Consider deleting these extra spaces.')
+ # There are certain situations we allow one space, notably for labels
+ elif ((initial_spaces == 1 or initial_spaces == 3) and
+ not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
+ error(filename, linenum, 'whitespace/indent', 3,
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 2-space indent?')
+ # Labels should always be indented at least one space.
+ elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$',
+ line):
+ error(filename, linenum, 'whitespace/labels', 4,
+ 'Labels should always be indented at least one space. '
+ 'If this is a member-initializer list in a constructor or '
+ 'the base class list in a class definition, the colon should '
+ 'be on the following line.')
+
+
+ # Check if the line is a header guard.
+ is_header_guard = False
+ if file_extension == 'h':
+ cppvar = GetHeaderGuardCPPVariable(filename)
+ if (line.startswith('#ifndef %s' % cppvar) or
+ line.startswith('#define %s' % cppvar) or
+ line.startswith('#endif // %s' % cppvar)):
+ is_header_guard = True
+ # #include lines and header guards can be long, since there's no clean way to
+ # split them.
+ #
+ # URLs can be long too. It's possible to split these, but it makes them
+ # harder to cut&paste.
+ #
+ # The "$Id:...$" comment may also get very long without it being the
+ # developers fault.
+ if (not line.startswith('#include') and not is_header_guard and
+ not Match(r'^\s*//.*http(s?)://\S*$', line) and
+ not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
+ line_width = GetLineWidth(line)
+ if line_width > 100:
+ error(filename, linenum, 'whitespace/line_length', 4,
+ 'Lines should very rarely be longer than 100 characters')
+ elif line_width > 80:
+ error(filename, linenum, 'whitespace/line_length', 2,
+ 'Lines should be <= 80 characters long')
+
+ if (cleansed_line.count(';') > 1 and
+ # for loops are allowed two ;'s (and may run over two lines).
+ cleansed_line.find('for') == -1 and
+ (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
+ GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
+ # It's ok to have many commands in a switch case that fits in 1 line
+ not ((cleansed_line.find('case ') != -1 or
+ cleansed_line.find('default:') != -1) and
+ cleansed_line.find('break;') != -1)):
+ error(filename, linenum, 'whitespace/newline', 0,
+ 'More than one command on the same line')
+
+ # Some more style checks
+ CheckBraces(filename, clean_lines, linenum, error)
+ CheckEmptyLoopBody(filename, clean_lines, linenum, error)
+ CheckAccess(filename, clean_lines, linenum, nesting_state, error)
+ CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
+ CheckCheck(filename, clean_lines, linenum, error)
+ CheckAltTokens(filename, clean_lines, linenum, error)
+ classinfo = nesting_state.InnermostClass()
+ if classinfo:
+ CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
+
+
+_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
+_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
+# Matches the first component of a filename delimited by -s and _s. That is:
+# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
+_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
+
+
+def _DropCommonSuffixes(filename):
+ """Drops common suffixes like _test.cc or -inl.h from filename.
+
+ For example:
+ >>> _DropCommonSuffixes('foo/foo-inl.h')
+ 'foo/foo'
+ >>> _DropCommonSuffixes('foo/bar/foo.cc')
+ 'foo/bar/foo'
+ >>> _DropCommonSuffixes('foo/foo_internal.h')
+ 'foo/foo'
+ >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
+ 'foo/foo_unusualinternal'
+
+ Args:
+ filename: The input filename.
+
+ Returns:
+ The filename with the common suffix removed.
+ """
+ for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
+ 'inl.h', 'impl.h', 'internal.h'):
+ if (filename.endswith(suffix) and len(filename) > len(suffix) and
+ filename[-len(suffix) - 1] in ('-', '_')):
+ return filename[:-len(suffix) - 1]
+ return os.path.splitext(filename)[0]
+
+
+def _IsTestFilename(filename):
+ """Determines if the given filename has a suffix that identifies it as a test.
+
+ Args:
+ filename: The input filename.
+
+ Returns:
+ True if 'filename' looks like a test, False otherwise.
+ """
+ if (filename.endswith('_test.cc') or
+ filename.endswith('_unittest.cc') or
+ filename.endswith('_regtest.cc')):
+ return True
+ else:
+ return False
+
+
+def _ClassifyInclude(fileinfo, include, is_system):
+ """Figures out what kind of header 'include' is.
+
+ Args:
+ fileinfo: The current file cpplint is running over. A FileInfo instance.
+ include: The path to a #included file.
+ is_system: True if the #include used <> rather than "".
+
+ Returns:
+ One of the _XXX_HEADER constants.
+
+ For example:
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
+ _C_SYS_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
+ _CPP_SYS_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
+ _LIKELY_MY_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
+ ... 'bar/foo_other_ext.h', False)
+ _POSSIBLE_MY_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
+ _OTHER_HEADER
+ """
+ # This is a list of all standard c++ header files, except
+ # those already checked for above.
+ is_stl_h = include in _STL_HEADERS
+ is_cpp_h = is_stl_h or include in _CPP_HEADERS
+
+ if is_system:
+ if is_cpp_h:
+ return _CPP_SYS_HEADER
+ else:
+ return _C_SYS_HEADER
+
+ # If the target file and the include we're checking share a
+ # basename when we drop common extensions, and the include
+ # lives in . , then it's likely to be owned by the target file.
+ target_dir, target_base = (
+ os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
+ include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
+ if target_base == include_base and (
+ include_dir == target_dir or
+ include_dir == os.path.normpath(target_dir + '/../public')):
+ return _LIKELY_MY_HEADER
+
+ # If the target and include share some initial basename
+ # component, it's possible the target is implementing the
+ # include, so it's allowed to be first, but we'll never
+ # complain if it's not there.
+ target_first_component = _RE_FIRST_COMPONENT.match(target_base)
+ include_first_component = _RE_FIRST_COMPONENT.match(include_base)
+ if (target_first_component and include_first_component and
+ target_first_component.group(0) ==
+ include_first_component.group(0)):
+ return _POSSIBLE_MY_HEADER
+
+ return _OTHER_HEADER
+
+
+
+def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
+ """Check rules that are applicable to #include lines.
+
+ Strings on #include lines are NOT removed from elided line, to make
+ certain tasks easier. However, to prevent false positives, checks
+ applicable to #include lines in CheckLanguage must be put here.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ error: The function to call with any errors found.
+ """
+ fileinfo = FileInfo(filename)
+
+ line = clean_lines.lines[linenum]
+
+ # "include" should use the new style "foo/bar.h" instead of just "bar.h"
+ if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):
+ error(filename, linenum, 'build/include', 4,
+ 'Include the directory when naming .h files')
+
+ # we shouldn't include a file more than once. actually, there are a
+ # handful of instances where doing so is okay, but in general it's
+ # not.
+ match = _RE_PATTERN_INCLUDE.search(line)
+ if match:
+ include = match.group(2)
+ is_system = (match.group(1) == '<')
+ if include in include_state:
+ error(filename, linenum, 'build/include', 4,
+ '"%s" already included at %s:%s' %
+ (include, filename, include_state[include]))
+ else:
+ include_state[include] = linenum
+
+ # We want to ensure that headers appear in the right order:
+ # 1) for foo.cc, foo.h (preferred location)
+ # 2) c system files
+ # 3) cpp system files
+ # 4) for foo.cc, foo.h (deprecated location)
+ # 5) other google headers
+ #
+ # We classify each include statement as one of those 5 types
+ # using a number of techniques. The include_state object keeps
+ # track of the highest type seen, and complains if we see a
+ # lower type after that.
+ error_message = include_state.CheckNextIncludeOrder(
+ _ClassifyInclude(fileinfo, include, is_system))
+ if error_message:
+ error(filename, linenum, 'build/include_order', 4,
+ '%s. Should be: %s.h, c system, c++ system, other.' %
+ (error_message, fileinfo.BaseName()))
+ if not include_state.IsInAlphabeticalOrder(include):
+ error(filename, linenum, 'build/include_alpha', 4,
+ 'Include "%s" not in alphabetical order' % include)
+
+ # Look for any of the stream classes that are part of standard C++.
+ match = _RE_PATTERN_INCLUDE.match(line)
+ if match:
+ include = match.group(2)
+ if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
+ # Many unit tests use cout, so we exempt them.
+ if not _IsTestFilename(filename):
+ error(filename, linenum, 'readability/streams', 3,
+ 'Streams are highly discouraged.')
+
+
+def _GetTextInside(text, start_pattern):
+ """Retrieves all the text between matching open and close parentheses.
+
+ Given a string of lines and a regular expression string, retrieve all the text
+ following the expression and between opening punctuation symbols like
+ (, [, or {, and the matching close-punctuation symbol. This properly nested
+ occurrences of the punctuations, so for the text like
+ printf(a(), b(c()));
+ a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
+ start_pattern must match string having an open punctuation symbol at the end.
+
+ Args:
+ text: The lines to extract text. Its comments and strings must be elided.
+ It can be single line and can span multiple lines.
+ start_pattern: The regexp string indicating where to start extracting
+ the text.
+ Returns:
+ The extracted text.
+ None if either the opening string or ending punctuation could not be found.
+ """
+ # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably
+ # rewritten to use _GetTextInside (and use inferior regexp matching today).
+
+ # Give opening punctuations to get the matching close-punctuations.
+ matching_punctuation = {'(': ')', '{': '}', '[': ']'}
+ closing_punctuation = set(matching_punctuation.itervalues())
+
+ # Find the position to start extracting text.
+ match = re.search(start_pattern, text, re.M)
+ if not match: # start_pattern not found in text.
+ return None
+ start_position = match.end(0)
+
+ assert start_position > 0, (
+ 'start_pattern must ends with an opening punctuation.')
+ assert text[start_position - 1] in matching_punctuation, (
+ 'start_pattern must ends with an opening punctuation.')
+ # Stack of closing punctuations we expect to have in text after position.
+ punctuation_stack = [matching_punctuation[text[start_position - 1]]]
+ position = start_position
+ while punctuation_stack and position < len(text):
+ if text[position] == punctuation_stack[-1]:
+ punctuation_stack.pop()
+ elif text[position] in closing_punctuation:
+ # A closing punctuation without matching opening punctuations.
+ return None
+ elif text[position] in matching_punctuation:
+ punctuation_stack.append(matching_punctuation[text[position]])
+ position += 1
+ if punctuation_stack:
+ # Opening punctuations left without matching close-punctuations.
+ return None
+ # punctuations match.
+ return text[start_position:position - 1]
+
+
+def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
+ error):
+ """Checks rules from the 'C++ language rules' section of cppguide.html.
+
+ Some of these rules are hard to test (function overloading, using
+ uint32 inappropriately), but we do the best we can.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ error: The function to call with any errors found.
+ """
+ # If the line is empty or consists of entirely a comment, no need to
+ # check it.
+ line = clean_lines.elided[linenum]
+ if not line:
+ return
+
+ match = _RE_PATTERN_INCLUDE.search(line)
+ if match:
+ CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
+ return
+
+ # Create an extended_line, which is the concatenation of the current and
+ # next lines, for more effective checking of code that may span more than one
+ # line.
+ if linenum + 1 < clean_lines.NumLines():
+ extended_line = line + clean_lines.elided[linenum + 1]
+ else:
+ extended_line = line
+
+ # Make Windows paths like Unix.
+ fullname = os.path.abspath(filename).replace('\\', '/')
+
+ # TODO(unknown): figure out if they're using default arguments in fn proto.
+
+ # Check for non-const references in functions. This is tricky because &
+ # is also used to take the address of something. We allow <> for templates,
+ # (ignoring whatever is between the braces) and : for classes.
+ # These are complicated re's. They try to capture the following:
+ # paren (for fn-prototype start), typename, &, varname. For the const
+ # version, we're willing for const to be before typename or after
+ # Don't check the implementation on same line.
+ fnline = line.split('{', 1)[0]
+ if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
+ len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
+ r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) +
+ len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+',
+ fnline))):
+
+ # We allow non-const references in a few standard places, like functions
+ # called "swap()" or iostream operators like "<<" or ">>". We also filter
+ # out for loops, which lint otherwise mistakenly thinks are functions.
+ if not Search(
+ r'(for|swap|Swap|operator[<>][<>])\s*\(\s*'
+ r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&',
+ fnline):
+ error(filename, linenum, 'runtime/references', 2,
+ 'Is this a non-const reference? '
+ 'If so, make const or use a pointer.')
+
+ # Check to see if they're using an conversion function cast.
+ # I just try to capture the most common basic types, though there are more.
+ # Parameterless conversion functions, such as bool(), are allowed as they are
+ # probably a member operator declaration or default constructor.
+ match = Search(
+ r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there
+ r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
+ if match:
+ # gMock methods are defined using some variant of MOCK_METHODx(name, type)
+ # where type may be float(), int(string), etc. Without context they are
+ # virtually indistinguishable from int(x) casts. Likewise, gMock's
+ # MockCallback takes a template parameter of the form return_type(arg_type),
+ # which looks much like the cast we're trying to detect.
+ if (match.group(1) is None and # If new operator, then this isn't a cast
+ not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
+ Match(r'^\s*MockCallback<.*>', line))):
+ # Try a bit harder to catch gmock lines: the only place where
+ # something looks like an old-style cast is where we declare the
+ # return type of the mocked method, and the only time when we
+ # are missing context is if MOCK_METHOD was split across
+ # multiple lines (for example http://go/hrfhr ), so we only need
+ # to check the previous line for MOCK_METHOD.
+ if (linenum == 0 or
+ not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(\S+,\s*$',
+ clean_lines.elided[linenum - 1])):
+ error(filename, linenum, 'readability/casting', 4,
+ 'Using deprecated casting style. '
+ 'Use static_cast<%s>(...) instead' %
+ match.group(2))
+
+ CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
+ 'static_cast',
+ r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
+
+ # This doesn't catch all cases. Consider (const char * const)"hello".
+ #
+ # (char *) "foo" should always be a const_cast (reinterpret_cast won't
+ # compile).
+ if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
+ 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error):
+ pass
+ else:
+ # Check pointer casts for other than string constants
+ CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
+ 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
+
+ # In addition, we look for people taking the address of a cast. This
+ # is dangerous -- casts can assign to temporaries, so the pointer doesn't
+ # point where you think.
+ if Search(
+ r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
+ error(filename, linenum, 'runtime/casting', 4,
+ ('Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'))
+
+ # Check for people declaring static/global STL strings at the top level.
+ # This is dangerous because the C++ language does not guarantee that
+ # globals with constructors are initialized before the first access.
+ match = Match(
+ r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
+ line)
+ # Make sure it's not a function.
+ # Function template specialization looks like: "string foo<Type>(...".
+ # Class template definitions look like: "string Foo<Type>::Method(...".
+ if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
+ match.group(3)):
+ error(filename, linenum, 'runtime/string', 4,
+ 'For a static/global string constant, use a C style string instead: '
+ '"%schar %s[]".' %
+ (match.group(1), match.group(2)))
+
+ # Check that we're not using RTTI outside of testing code.
+ if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename):
+ error(filename, linenum, 'runtime/rtti', 5,
+ 'Do not use dynamic_cast<>. If you need to cast within a class '
+ "hierarchy, use static_cast<> to upcast. Google doesn't support "
+ 'RTTI.')
+
+ if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
+ error(filename, linenum, 'runtime/init', 4,
+ 'You seem to be initializing a member variable with itself.')
+
+ if file_extension == 'h':
+ # TODO(unknown): check that 1-arg constructors are explicit.
+ # How to tell it's a constructor?
+ # (handled in CheckForNonStandardConstructs for now)
+ # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS
+ # (level 1 error)
+ pass
+
+ # Check if people are using the verboten C basic types. The only exception
+ # we regularly allow is "unsigned short port" for port.
+ if Search(r'\bshort port\b', line):
+ if not Search(r'\bunsigned short port\b', line):
+ error(filename, linenum, 'runtime/int', 4,
+ 'Use "unsigned short" for ports, not "short"')
+ else:
+ match = Search(r'\b(short|long(?! +double)|long long)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/int', 4,
+ 'Use int16/int64/etc, rather than the C type %s' % match.group(1))
+
+ # When snprintf is used, the second argument shouldn't be a literal.
+ match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
+ if match and match.group(2) != '0':
+ # If 2nd arg is zero, snprintf is used to calculate size.
+ error(filename, linenum, 'runtime/printf', 3,
+ 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
+ 'to snprintf.' % (match.group(1), match.group(2)))
+
+ # Check if some verboten C functions are being used.
+ if Search(r'\bsprintf\b', line):
+ error(filename, linenum, 'runtime/printf', 5,
+ 'Never use sprintf. Use snprintf instead.')
+ match = Search(r'\b(strcpy|strcat)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Almost always, snprintf is better than %s' % match.group(1))
+
+ if Search(r'\bsscanf\b', line):
+ error(filename, linenum, 'runtime/printf', 1,
+ 'sscanf can be ok, but is slow and can overflow buffers.')
+
+ # Check if some verboten operator overloading is going on
+ # TODO(unknown): catch out-of-line unary operator&:
+ # class X {};
+ # int operator&(const X& x) { return 42; } // unary operator&
+ # The trick is it's hard to tell apart from binary operator&:
+ # class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
+ if Search(r'\boperator\s*&\s*\(\s*\)', line):
+ error(filename, linenum, 'runtime/operator', 4,
+ 'Unary operator& is dangerous. Do not use it.')
+
+ # Check for suspicious usage of "if" like
+ # } if (a == b) {
+ if Search(r'\}\s*if\s*\(', line):
+ error(filename, linenum, 'readability/braces', 4,
+ 'Did you mean "else if"? If not, start a new line for "if".')
+
+ # Check for potential format string bugs like printf(foo).
+ # We constrain the pattern not to pick things like DocidForPrintf(foo).
+ # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
+ # TODO(sugawarayu): Catch the following case. Need to change the calling
+ # convention of the whole function to process multiple line to handle it.
+ # printf(
+ # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
+ printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
+ if printf_args:
+ match = Match(r'([\w.\->()]+)$', printf_args)
+ if match and match.group(1) != '__VA_ARGS__':
+ function_name = re.search(r'\b((?:string)?printf)\s*\(',
+ line, re.I).group(1)
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Potential format string bug. Do %s("%%s", %s) instead.'
+ % (function_name, match.group(1)))
+
+ # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
+ match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
+ if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
+ error(filename, linenum, 'runtime/memset', 4,
+ 'Did you mean "memset(%s, 0, %s)"?'
+ % (match.group(1), match.group(2)))
+
+ if Search(r'\busing namespace\b', line):
+ error(filename, linenum, 'build/namespaces', 5,
+ 'Do not use namespace using-directives. '
+ 'Use using-declarations instead.')
+
+ # Detect variable-length arrays.
+ match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
+ if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
+ match.group(3).find(']') == -1):
+ # Split the size using space and arithmetic operators as delimiters.
+ # If any of the resulting tokens are not compile time constants then
+ # report the error.
+ tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
+ is_const = True
+ skip_next = False
+ for tok in tokens:
+ if skip_next:
+ skip_next = False
+ continue
+
+ if Search(r'sizeof\(.+\)', tok): continue
+ if Search(r'arraysize\(\w+\)', tok): continue
+
+ tok = tok.lstrip('(')
+ tok = tok.rstrip(')')
+ if not tok: continue
+ if Match(r'\d+', tok): continue
+ if Match(r'0[xX][0-9a-fA-F]+', tok): continue
+ if Match(r'k[A-Z0-9]\w*', tok): continue
+ if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
+ if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
+ # A catch all for tricky sizeof cases, including 'sizeof expression',
+ # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
+ # requires skipping the next token because we split on ' ' and '*'.
+ if tok.startswith('sizeof'):
+ skip_next = True
+ continue
+ is_const = False
+ break
+ if not is_const:
+ error(filename, linenum, 'runtime/arrays', 1,
+ 'Do not use variable-length arrays. Use an appropriately named '
+ "('k' followed by CamelCase) compile-time constant for the size.")
+
+ # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or
+ # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing
+ # in the class declaration.
+ match = Match(
+ (r'\s*'
+ r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))'
+ r'\(.*\);$'),
+ line)
+ if match and linenum + 1 < clean_lines.NumLines():
+ next_line = clean_lines.elided[linenum + 1]
+ # We allow some, but not all, declarations of variables to be present
+ # in the statement that defines the class. The [\w\*,\s]* fragment of
+ # the regular expression below allows users to declare instances of
+ # the class or pointers to instances, but not less common types such
+ # as function pointers or arrays. It's a tradeoff between allowing
+ # reasonable code and avoiding trying to parse more C++ using regexps.
+ if not Search(r'^\s*}[\w\*,\s]*;', next_line):
+ error(filename, linenum, 'readability/constructors', 3,
+ match.group(1) + ' should be the last thing in the class')
+
+ # Check for use of unnamed namespaces in header files. Registration
+ # macros are typically OK, so we allow use of "namespace {" on lines
+ # that end with backslashes.
+ if (file_extension == 'h'
+ and Search(r'\bnamespace\s*{', line)
+ and line[-1] != '\\'):
+ error(filename, linenum, 'build/namespaces', 4,
+ 'Do not use unnamed namespaces in header files. See '
+ 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+ ' for more information.')
+
+
+def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
+ error):
+ """Checks for a C-style cast by looking for the pattern.
+
+ This also handles sizeof(type) warnings, due to similarity of content.
+
+ Args:
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ line: The line of code to check.
+ raw_line: The raw line of code to check, with comments.
+ cast_type: The string for the C++ cast to recommend. This is either
+ reinterpret_cast, static_cast, or const_cast, depending.
+ pattern: The regular expression used to find C-style casts.
+ error: The function to call with any errors found.
+
+ Returns:
+ True if an error was emitted.
+ False otherwise.
+ """
+ match = Search(pattern, line)
+ if not match:
+ return False
+
+ # e.g., sizeof(int)
+ sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
+ if sizeof_match:
+ error(filename, linenum, 'runtime/sizeof', 1,
+ 'Using sizeof(type). Use sizeof(varname) instead if possible')
+ return True
+
+ # operator++(int) and operator--(int)
+ if (line[0:match.start(1) - 1].endswith(' operator++') or
+ line[0:match.start(1) - 1].endswith(' operator--')):
+ return False
+
+ remainder = line[match.end(0):]
+
+ # The close paren is for function pointers as arguments to a function.
+ # eg, void foo(void (*bar)(int));
+ # The semicolon check is a more basic function check; also possibly a
+ # function pointer typedef.
+ # eg, void foo(int); or void foo(int) const;
+ # The equals check is for function pointer assignment.
+ # eg, void *(*foo)(int) = ...
+ # The > is for MockCallback<...> ...
+ #
+ # Right now, this will only catch cases where there's a single argument, and
+ # it's unnamed. It should probably be expanded to check for multiple
+ # arguments with some unnamed.
+ function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder)
+ if function_match:
+ if (not function_match.group(3) or
+ function_match.group(3) == ';' or
+ ('MockCallback<' not in raw_line and
+ '/*' not in raw_line)):
+ error(filename, linenum, 'readability/function', 3,
+ 'All parameters should be named in a function')
+ return True
+
+ # At this point, all that should be left is actual casts.
+ error(filename, linenum, 'readability/casting', 4,
+ 'Using C-style cast. Use %s<%s>(...) instead' %
+ (cast_type, match.group(1)))
+
+ return True
+
+
+_HEADERS_CONTAINING_TEMPLATES = (
+ ('<deque>', ('deque',)),
+ ('<functional>', ('unary_function', 'binary_function',
+ 'plus', 'minus', 'multiplies', 'divides', 'modulus',
+ 'negate',
+ 'equal_to', 'not_equal_to', 'greater', 'less',
+ 'greater_equal', 'less_equal',
+ 'logical_and', 'logical_or', 'logical_not',
+ 'unary_negate', 'not1', 'binary_negate', 'not2',
+ 'bind1st', 'bind2nd',
+ 'pointer_to_unary_function',
+ 'pointer_to_binary_function',
+ 'ptr_fun',
+ 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
+ 'mem_fun_ref_t',
+ 'const_mem_fun_t', 'const_mem_fun1_t',
+ 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
+ 'mem_fun_ref',
+ )),
+ ('<limits>', ('numeric_limits',)),
+ ('<list>', ('list',)),
+ ('<map>', ('map', 'multimap',)),
+ ('<memory>', ('allocator',)),
+ ('<queue>', ('queue', 'priority_queue',)),
+ ('<set>', ('set', 'multiset',)),
+ ('<stack>', ('stack',)),
+ ('<string>', ('char_traits', 'basic_string',)),
+ ('<utility>', ('pair',)),
+ ('<vector>', ('vector',)),
+
+ # gcc extensions.
+ # Note: std::hash is their hash, ::hash is our hash
+ ('<hash_map>', ('hash_map', 'hash_multimap',)),
+ ('<hash_set>', ('hash_set', 'hash_multiset',)),
+ ('<slist>', ('slist',)),
+ )
+
+_RE_PATTERN_STRING = re.compile(r'\bstring\b')
+
+_re_pattern_algorithm_header = []
+for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
+ 'transform'):
+ # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
+ # type::max().
+ _re_pattern_algorithm_header.append(
+ (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
+ _template,
+ '<algorithm>'))
+
+_re_pattern_templates = []
+for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
+ for _template in _templates:
+ _re_pattern_templates.append(
+ (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
+ _template + '<>',
+ _header))
+
+
+def FilesBelongToSameModule(filename_cc, filename_h):
+ """Check if these two filenames belong to the same module.
+
+ The concept of a 'module' here is a as follows:
+ foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
+ same 'module' if they are in the same directory.
+ some/path/public/xyzzy and some/path/internal/xyzzy are also considered
+ to belong to the same module here.
+
+ If the filename_cc contains a longer path than the filename_h, for example,
+ '/absolute/path/to/base/sysinfo.cc', and this file would include
+ 'base/sysinfo.h', this function also produces the prefix needed to open the
+ header. This is used by the caller of this function to more robustly open the
+ header file. We don't have access to the real include paths in this context,
+ so we need this guesswork here.
+
+ Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
+ according to this implementation. Because of this, this function gives
+ some false positives. This should be sufficiently rare in practice.
+
+ Args:
+ filename_cc: is the path for the .cc file
+ filename_h: is the path for the header path
+
+ Returns:
+ Tuple with a bool and a string:
+ bool: True if filename_cc and filename_h belong to the same module.
+ string: the additional prefix needed to open the header file.
+ """
+
+ if not filename_cc.endswith('.cc'):
+ return (False, '')
+ filename_cc = filename_cc[:-len('.cc')]
+ if filename_cc.endswith('_unittest'):
+ filename_cc = filename_cc[:-len('_unittest')]
+ elif filename_cc.endswith('_test'):
+ filename_cc = filename_cc[:-len('_test')]
+ filename_cc = filename_cc.replace('/public/', '/')
+ filename_cc = filename_cc.replace('/internal/', '/')
+
+ if not filename_h.endswith('.h'):
+ return (False, '')
+ filename_h = filename_h[:-len('.h')]
+ if filename_h.endswith('-inl'):
+ filename_h = filename_h[:-len('-inl')]
+ filename_h = filename_h.replace('/public/', '/')
+ filename_h = filename_h.replace('/internal/', '/')
+
+ files_belong_to_same_module = filename_cc.endswith(filename_h)
+ common_path = ''
+ if files_belong_to_same_module:
+ common_path = filename_cc[:-len(filename_h)]
+ return files_belong_to_same_module, common_path
+
+
+def UpdateIncludeState(filename, include_state, io=codecs):
+ """Fill up the include_state with new includes found from the file.
+
+ Args:
+ filename: the name of the header to read.
+ include_state: an _IncludeState instance in which the headers are inserted.
+ io: The io factory to use to read the file. Provided for testability.
+
+ Returns:
+ True if a header was successfully added. False otherwise.
+ """
+ headerfile = None
+ try:
+ headerfile = io.open(filename, 'r', 'utf8', 'replace')
+ except IOError:
+ return False
+ linenum = 0
+ for line in headerfile:
+ linenum += 1
+ clean_line = CleanseComments(line)
+ match = _RE_PATTERN_INCLUDE.search(clean_line)
+ if match:
+ include = match.group(2)
+ # The value formatting is cute, but not really used right now.
+ # What matters here is that the key is in include_state.
+ include_state.setdefault(include, '%s:%d' % (filename, linenum))
+ return True
+
+
+def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
+ io=codecs):
+ """Reports for missing stl includes.
+
+ This function will output warnings to make sure you are including the headers
+ necessary for the stl containers and functions that you use. We only give one
+ reason to include a header. For example, if you use both equal_to<> and
+ less<> in a .h file, only one (the latter in the file) of these will be
+ reported as a reason to include the <functional>.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ include_state: An _IncludeState instance.
+ error: The function to call with any errors found.
+ io: The IO factory to use to read the header file. Provided for unittest
+ injection.
+ """
+ required = {} # A map of header name to linenumber and the template entity.
+ # Example of required: { '<functional>': (1219, 'less<>') }
+
+ for linenum in xrange(clean_lines.NumLines()):
+ line = clean_lines.elided[linenum]
+ if not line or line[0] == '#':
+ continue
+
+ # String is special -- it is a non-templatized type in STL.
+ matched = _RE_PATTERN_STRING.search(line)
+ if matched:
+ # Don't warn about strings in non-STL namespaces:
+ # (We check only the first match per line; good enough.)
+ prefix = line[:matched.start()]
+ if prefix.endswith('std::') or not prefix.endswith('::'):
+ required['<string>'] = (linenum, 'string')
+
+ for pattern, template, header in _re_pattern_algorithm_header:
+ if pattern.search(line):
+ required[header] = (linenum, template)
+
+ # The following function is just a speed up, no semantics are changed.
+ if not '<' in line: # Reduces the cpu time usage by skipping lines.
+ continue
+
+ for pattern, template, header in _re_pattern_templates:
+ if pattern.search(line):
+ required[header] = (linenum, template)
+
+ # The policy is that if you #include something in foo.h you don't need to
+ # include it again in foo.cc. Here, we will look at possible includes.
+ # Let's copy the include_state so it is only messed up within this function.
+ include_state = include_state.copy()
+
+ # Did we find the header for this file (if any) and successfully load it?
+ header_found = False
+
+ # Use the absolute path so that matching works properly.
+ abs_filename = FileInfo(filename).FullName()
+
+ # For Emacs's flymake.
+ # If cpplint is invoked from Emacs's flymake, a temporary file is generated
+ # by flymake and that file name might end with '_flymake.cc'. In that case,
+ # restore original file name here so that the corresponding header file can be
+ # found.
+ # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
+ # instead of 'foo_flymake.h'
+ abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
+
+ # include_state is modified during iteration, so we iterate over a copy of
+ # the keys.
+ header_keys = include_state.keys()
+ for header in header_keys:
+ (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
+ fullpath = common_path + header
+ if same_module and UpdateIncludeState(fullpath, include_state, io):
+ header_found = True
+
+ # If we can't find the header file for a .cc, assume it's because we don't
+ # know where to look. In that case we'll give up as we're not sure they
+ # didn't include it in the .h file.
+ # TODO(unknown): Do a better job of finding .h files so we are confident that
+ # not having the .h file means there isn't one.
+ if filename.endswith('.cc') and not header_found:
+ return
+
+ # All the lines have been processed, report the errors found.
+ for required_header_unstripped in required:
+ template = required[required_header_unstripped][1]
+ if required_header_unstripped.strip('<>"') not in include_state:
+ error(filename, required[required_header_unstripped][0],
+ 'build/include_what_you_use', 4,
+ 'Add #include ' + required_header_unstripped + ' for ' + template)
+
+
+_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
+
+
+def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
+ """Check that make_pair's template arguments are deduced.
+
+ G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are
+ specified explicitly, and such use isn't intended in any case.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ raw = clean_lines.raw_lines
+ line = raw[linenum]
+ match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
+ if match:
+ error(filename, linenum, 'build/explicit_make_pair',
+ 4, # 4 = high confidence
+ 'For C++11-compatibility, omit template arguments from make_pair'
+ ' OR use pair directly OR if appropriate, construct a pair directly')
+
+
+def ProcessLine(filename, file_extension, clean_lines, line,
+ include_state, function_state, nesting_state, error,
+ extra_check_functions=[]):
+ """Processes a single line in the file.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ clean_lines: An array of strings, each representing a line of the file,
+ with comments stripped.
+ line: Number of line being processed.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ function_state: A _FunctionState instance which counts function lines, etc.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+ raw_lines = clean_lines.raw_lines
+ ParseNolintSuppressions(filename, raw_lines[line], line, error)
+ nesting_state.Update(filename, clean_lines, line, error)
+ if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM:
+ return
+ CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
+ CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
+ CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
+ CheckLanguage(filename, clean_lines, line, file_extension, include_state,
+ error)
+ CheckForNonStandardConstructs(filename, clean_lines, line,
+ nesting_state, error)
+ CheckPosixThreading(filename, clean_lines, line, error)
+ CheckInvalidIncrement(filename, clean_lines, line, error)
+ CheckMakePairUsesDeduction(filename, clean_lines, line, error)
+ for check_fn in extra_check_functions:
+ check_fn(filename, clean_lines, line, error)
+
+def ProcessFileData(filename, file_extension, lines, error,
+ extra_check_functions=[]):
+ """Performs lint checks and reports any errors to the given error function.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ lines: An array of strings, each representing a line of the file, with the
+ last element being empty if the file is terminated with a newline.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+ lines = (['// marker so line numbers and indices both start at 1'] + lines +
+ ['// marker so line numbers end in a known way'])
+
+ include_state = _IncludeState()
+ function_state = _FunctionState()
+ nesting_state = _NestingState()
+
+ ResetNolintSuppressions()
+
+ CheckForCopyright(filename, lines, error)
+
+ if file_extension == 'h':
+ CheckForHeaderGuard(filename, lines, error)
+
+ RemoveMultiLineComments(filename, lines, error)
+ clean_lines = CleansedLines(lines)
+ for line in xrange(clean_lines.NumLines()):
+ ProcessLine(filename, file_extension, clean_lines, line,
+ include_state, function_state, nesting_state, error,
+ extra_check_functions)
+ nesting_state.CheckClassFinished(filename, error)
+
+ CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
+
+ # We check here rather than inside ProcessLine so that we see raw
+ # lines rather than "cleaned" lines.
+ CheckForUnicodeReplacementCharacters(filename, lines, error)
+
+ CheckForNewlineAtEOF(filename, lines, error)
+
+def ProcessFile(filename, vlevel, extra_check_functions=[]):
+ """Does google-lint on a single file.
+
+ Args:
+ filename: The name of the file to parse.
+
+ vlevel: The level of errors to report. Every error of confidence
+ >= verbose_level will be reported. 0 is a good default.
+
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+
+ _SetVerboseLevel(vlevel)
+
+ try:
+ # Support the UNIX convention of using "-" for stdin. Note that
+ # we are not opening the file with universal newline support
+ # (which codecs doesn't support anyway), so the resulting lines do
+ # contain trailing '\r' characters if we are reading a file that
+ # has CRLF endings.
+ # If after the split a trailing '\r' is present, it is removed
+ # below. If it is not expected to be present (i.e. os.linesep !=
+ # '\r\n' as in Windows), a warning is issued below if this file
+ # is processed.
+
+ if filename == '-':
+ lines = codecs.StreamReaderWriter(sys.stdin,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace').read().split('\n')
+ else:
+ lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+
+ carriage_return_found = False
+ # Remove trailing '\r'.
+ for linenum in range(len(lines)):
+ if lines[linenum].endswith('\r'):
+ lines[linenum] = lines[linenum].rstrip('\r')
+ carriage_return_found = True
+
+ except IOError:
+ sys.stderr.write(
+ "Skipping input '%s': Can't open for reading\n" % filename)
+ return
+
+ # Note, if no dot is found, this will give the entire filename as the ext.
+ file_extension = filename[filename.rfind('.') + 1:]
+
+ # When reading from stdin, the extension is unknown, so no cpplint tests
+ # should rely on the extension.
+ if (filename != '-' and file_extension != 'cc' and file_extension != 'h'
+ and file_extension != 'cpp'):
+ sys.stderr.write('Ignoring %s; not a .cc or .h file\n' % filename)
+ else:
+ ProcessFileData(filename, file_extension, lines, Error,
+ extra_check_functions)
+ if carriage_return_found and os.linesep != '\r\n':
+ # Use 0 for linenum since outputting only one error for potentially
+ # several lines.
+ Error(filename, 0, 'whitespace/newline', 1,
+ 'One or more unexpected \\r (^M) found;'
+ 'better to use only a \\n')
+
+ sys.stderr.write('Done processing %s\n' % filename)
+
+
+def PrintUsage(message):
+ """Prints a brief usage string and exits, optionally with an error message.
+
+ Args:
+ message: The optional error message.
+ """
+ sys.stderr.write(_USAGE)
+ if message:
+ sys.exit('\nFATAL ERROR: ' + message)
+ else:
+ sys.exit(1)
+
+
+def PrintCategories():
+ """Prints a list of all the error-categories used by error messages.
+
+ These are the categories used to filter messages via --filter.
+ """
+ sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
+ sys.exit(0)
+
+
+def ParseArguments(args):
+ """Parses the command line arguments.
+
+ This may set the output format and verbosity level as side-effects.
+
+ Args:
+ args: The command line arguments:
+
+ Returns:
+ The list of filenames to lint.
+ """
+ try:
+ (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
+ 'counting=',
+ 'filter=',
+ 'root='])
+ except getopt.GetoptError:
+ PrintUsage('Invalid arguments.')
+
+ verbosity = _VerboseLevel()
+ output_format = _OutputFormat()
+ filters = ''
+ counting_style = ''
+
+ for (opt, val) in opts:
+ if opt == '--help':
+ PrintUsage(None)
+ elif opt == '--output':
+ if not val in ('emacs', 'vs7', 'eclipse'):
+ PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
+ output_format = val
+ elif opt == '--verbose':
+ verbosity = int(val)
+ elif opt == '--filter':
+ filters = val
+ if not filters:
+ PrintCategories()
+ elif opt == '--counting':
+ if val not in ('total', 'toplevel', 'detailed'):
+ PrintUsage('Valid counting options are total, toplevel, and detailed')
+ counting_style = val
+ elif opt == '--root':
+ global _root
+ _root = val
+
+ if not filenames:
+ PrintUsage('No files were specified.')
+
+ _SetOutputFormat(output_format)
+ _SetVerboseLevel(verbosity)
+ _SetFilters(filters)
+ _SetCountingStyle(counting_style)
+
+ return filenames
+
+
+def main():
+ filenames = ParseArguments(sys.argv[1:])
+
+ # Change stderr to write with replacement characters so we don't die
+ # if we try to print something containing non-ASCII characters.
+ sys.stderr = codecs.StreamReaderWriter(sys.stderr,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace')
+
+ _cpplint_state.ResetErrorCounts()
+ for filename in filenames:
+ ProcessFile(filename, _cpplint_state.verbose_level)
+ _cpplint_state.PrintErrorCounts()
+
+ sys.exit(_cpplint_state.error_count > 0)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py
new file mode 100755
index 000000000000..7bab230650cb
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+#===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+#
+# Generates the list of functions that should be exported from sanitizer
+# runtimes. The output format is recognized by --dynamic-list linker option.
+# Usage:
+# gen_dynamic_list.py libclang_rt.*san*.a [ files ... ]
+#
+#===------------------------------------------------------------------------===#
+import os
+import re
+import subprocess
+import sys
+
+new_delete = set(['_ZdaPv', '_ZdaPvRKSt9nothrow_t',
+ '_ZdlPv', '_ZdlPvRKSt9nothrow_t',
+ '_Znam', '_ZnamRKSt9nothrow_t',
+ '_Znwm', '_ZnwmRKSt9nothrow_t'])
+
+versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np',
+ 'pthread_cond_broadcast',
+ 'pthread_cond_destroy', 'pthread_cond_init',
+ 'pthread_cond_signal', 'pthread_cond_timedwait',
+ 'pthread_cond_wait', 'realpath',
+ 'sched_getaffinity'])
+
+def get_global_functions(library):
+ functions = []
+ nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ nm_out = nm_proc.communicate()[0].decode().split('\n')
+ if nm_proc.returncode != 0:
+ raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
+ func_symbols = ['T', 'W']
+ # On PowerPC, nm prints function descriptors from .data section.
+ if os.uname()[4] in ["powerpc", "ppc64"]:
+ func_symbols += ['D']
+ for line in nm_out:
+ cols = line.split(' ')
+ if len(cols) == 3 and cols[1] in func_symbols :
+ functions.append(cols[2])
+ return functions
+
+def main(argv):
+ result = []
+
+ library = argv[1]
+ all_functions = get_global_functions(library)
+ function_set = set(all_functions)
+ for func in all_functions:
+ # Export new/delete operators.
+ if func in new_delete:
+ result.append(func)
+ continue
+ # Export interceptors.
+ match = re.match('__interceptor_(.*)', func)
+ if match:
+ result.append(func)
+ # We have to avoid exporting the interceptors for versioned library
+ # functions due to gold internal error.
+ orig_name = match.group(1)
+ if orig_name in function_set and orig_name not in versioned_functions:
+ result.append(orig_name)
+ continue
+ # Export sanitizer interface functions.
+ if re.match('__sanitizer_(.*)', func):
+ result.append(func)
+
+ # Additional exported functions from files.
+ for fname in argv[2:]:
+ f = open(fname, 'r')
+ for line in f:
+ result.append(line.rstrip())
+ # Print the resulting list in the format recognized by ld.
+ print('{')
+ result.sort()
+ for f in result:
+ print(' ' + f + ';')
+ print('};')
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py
new file mode 100755
index 000000000000..1e78448b63d4
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+#
+# litlint
+#
+# Ensure RUN commands in lit tests are free of common errors.
+#
+# If any errors are detected, litlint returns a nonzero exit code.
+#
+
+import optparse
+import re
+import sys
+
+# Compile regex once for all files
+runRegex = re.compile(r'(?<!-o)(?<!%run) %t\s')
+
+def LintLine(s):
+ """ Validate a line
+
+ Args:
+ s: str, the line to validate
+
+ Returns:
+ Returns an error message and a 1-based column number if an error was
+ detected, otherwise (None, None).
+ """
+
+ # Check that RUN command can be executed with an emulator
+ m = runRegex.search(s)
+ if m:
+ start, end = m.span()
+ return ('missing %run before %t', start + 2)
+
+ # No errors
+ return (None, None)
+
+
+def LintFile(p):
+ """ Check that each RUN command can be executed with an emulator
+
+ Args:
+ p: str, valid path to a file
+
+ Returns:
+ The number of errors detected.
+ """
+ errs = 0
+ with open(p, 'r') as f:
+ for i, s in enumerate(f.readlines(), start=1):
+ msg, col = LintLine(s)
+ if msg != None:
+ errs += 1
+ errorMsg = 'litlint: {}:{}:{}: error: {}.\n{}{}\n'
+ arrow = (col-1) * ' ' + '^'
+ sys.stderr.write(errorMsg.format(p, i, col, msg, s, arrow))
+ return errs
+
+
+if __name__ == "__main__":
+ # Parse args
+ parser = optparse.OptionParser()
+ parser.add_option('--filter') # ignored
+ (options, filenames) = parser.parse_args()
+
+ # Lint each file
+ errs = 0
+ for p in filenames:
+ errs += LintFile(p)
+
+ # If errors, return nonzero
+ if errs > 0:
+ sys.exit(1)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py
new file mode 100755
index 000000000000..3ce482d70444
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+
+# Tests for litlint.py
+#
+# Usage: python litlint_test.py
+#
+# Returns nonzero if any test fails
+
+import litlint
+import unittest
+
+class TestLintLine(unittest.TestCase):
+ def test_missing_run(self):
+ f = litlint.LintLine
+ self.assertEqual(f(' %t '), ('missing %run before %t', 2))
+ self.assertEqual(f(' %t\n'), ('missing %run before %t', 2))
+ self.assertEqual(f(' %t.so '), (None, None))
+ self.assertEqual(f(' %t.o '), (None, None))
+ self.assertEqual(f('%run %t '), (None, None))
+ self.assertEqual(f('-o %t '), (None, None))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py
new file mode 100755
index 000000000000..566116eb2334
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+# Merge or print the coverage data collected by asan's coverage.
+# Input files are sequences of 4-byte integers.
+# We need to merge these integers into a set and then
+# either print them (as hex) or dump them into another file.
+import array
+import struct
+import sys
+import bisect
+import os.path
+
+prog_name = "";
+
+def Usage():
+ print >> sys.stderr, "Usage: \n" + \
+ " " + prog_name + " merge file1 [file2 ...] > output\n" \
+ " " + prog_name + " print file1 [file2 ...]\n" \
+ " " + prog_name + " unpack file1 [file2 ...]\n" \
+ " " + prog_name + " rawunpack file1 [file2 ...]\n"
+ exit(1)
+
+def ReadOneFile(path):
+ with open(path, mode="rb") as f:
+ f.seek(0, 2)
+ size = f.tell()
+ f.seek(0, 0)
+ s = set(array.array('I', f.read(size)))
+ print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size / 4, path)
+ return s
+
+def Merge(files):
+ s = set()
+ for f in files:
+ s = s.union(ReadOneFile(f))
+ print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
+ (prog_name, len(files), len(s))
+ return sorted(s)
+
+def PrintFiles(files):
+ s = Merge(files)
+ for i in s:
+ print "0x%x" % i
+
+def MergeAndPrint(files):
+ if sys.stdout.isatty():
+ Usage()
+ s = Merge(files)
+ a = array.array('I', s)
+ a.tofile(sys.stdout)
+
+
+def UnpackOneFile(path):
+ with open(path, mode="rb") as f:
+ print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
+ while True:
+ header = f.read(12)
+ if not header: return
+ if len(header) < 12:
+ break
+ pid, module_length, blob_size = struct.unpack('iII', header)
+ module = f.read(module_length)
+ blob = f.read(blob_size)
+ assert(len(module) == module_length)
+ assert(len(blob) == blob_size)
+ extracted_file = "%s.%d.sancov" % (module, pid)
+ print >> sys.stderr, "%s: extracting %s" % \
+ (prog_name, extracted_file)
+ # The packed file may contain multiple blobs for the same pid/module
+ # pair. Append to the end of the file instead of overwriting.
+ with open(extracted_file, 'ab') as f2:
+ f2.write(blob)
+ # fail
+ raise Exception('Error reading file %s' % path)
+
+
+def Unpack(files):
+ for f in files:
+ UnpackOneFile(f)
+
+def UnpackOneRawFile(path, map_path):
+ mem_map = []
+ with open(map_path, mode="rt") as f_map:
+ print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
+ bits = int(f_map.readline())
+ for line in f_map:
+ parts = line.rstrip().split()
+ mem_map.append((int(parts[0], 16),
+ int(parts[1], 16),
+ int(parts[2], 16),
+ ' '.join(parts[3:])))
+ mem_map.sort(key=lambda m : m[0])
+ mem_map_keys = [m[0] for m in mem_map]
+
+ with open(path, mode="rb") as f:
+ print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
+
+ f.seek(0, 2)
+ size = f.tell()
+ f.seek(0, 0)
+ if bits == 64:
+ typecode = 'L'
+ else:
+ typecode = 'I'
+ pcs = array.array(typecode, f.read(size))
+ mem_map_pcs = [[] for i in range(0, len(mem_map))]
+
+ for pc in pcs:
+ if pc == 0: continue
+ map_idx = bisect.bisect(mem_map_keys, pc) - 1
+ (start, end, base, module_path) = mem_map[map_idx]
+ assert pc >= start
+ if pc >= end:
+ print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc)
+ continue
+ mem_map_pcs[map_idx].append(pc - base)
+
+ for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs):
+ if len(pc_list) == 0: continue
+ assert path.endswith('.sancov.raw')
+ dst_path = module_path + '.' + os.path.basename(path)[:-4]
+ print >> sys.stderr, "%s: writing %d PCs to %s" % (prog_name, len(pc_list), dst_path)
+ arr = array.array('I')
+ arr.fromlist(sorted(pc_list))
+ with open(dst_path, 'ab') as f2:
+ arr.tofile(f2)
+
+def RawUnpack(files):
+ for f in files:
+ if not f.endswith('.sancov.raw'):
+ raise Exception('Unexpected raw file name %s' % f)
+ f_map = f[:-3] + 'map'
+ UnpackOneRawFile(f, f_map)
+
+if __name__ == '__main__':
+ prog_name = sys.argv[0]
+ if len(sys.argv) <= 2:
+ Usage();
+ if sys.argv[1] == "print":
+ PrintFiles(sys.argv[2:])
+ elif sys.argv[1] == "merge":
+ MergeAndPrint(sys.argv[2:])
+ elif sys.argv[1] == "unpack":
+ Unpack(sys.argv[2:])
+ elif sys.argv[1] == "rawunpack":
+ RawUnpack(sys.argv[2:])
+ else:
+ Usage()
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
new file mode 100644
index 000000000000..be8fc91aa861
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -0,0 +1,860 @@
+//===-- sanitizer_allocator_test.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 ThreadSanitizer/AddressSanitizer runtime.
+// Tests for sanitizer_allocator.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
+
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+#include <algorithm>
+#include <vector>
+#include <set>
+
+// Too slow for debug build
+#if !SANITIZER_DEBUG
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+static const uptr kAllocatorSpace = 0x700000000000ULL;
+static const uptr kAllocatorSize = 0x010000000000ULL; // 1T.
+static const u64 kAddressSpaceSize = 1ULL << 47;
+
+typedef SizeClassAllocator64<
+ kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap> Allocator64;
+
+typedef SizeClassAllocator64<
+ kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact;
+#elif defined(__mips64)
+static const u64 kAddressSpaceSize = 1ULL << 40;
+#else
+static const u64 kAddressSpaceSize = 1ULL << 32;
+#endif
+
+static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24);
+static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
+
+typedef SizeClassAllocator32<
+ 0, kAddressSpaceSize,
+ /*kMetadataSize*/16,
+ CompactSizeClassMap,
+ kRegionSizeLog,
+ FlatByteMap<kFlatByteMapSize> >
+ Allocator32Compact;
+
+template <class SizeClassMap>
+void TestSizeClassMap() {
+ typedef SizeClassMap SCMap;
+ // SCMap::Print();
+ SCMap::Validate();
+}
+
+TEST(SanitizerCommon, DefaultSizeClassMap) {
+ TestSizeClassMap<DefaultSizeClassMap>();
+}
+
+TEST(SanitizerCommon, CompactSizeClassMap) {
+ TestSizeClassMap<CompactSizeClassMap>();
+}
+
+TEST(SanitizerCommon, InternalSizeClassMap) {
+ TestSizeClassMap<InternalSizeClassMap>();
+}
+
+template <class Allocator>
+void TestSizeClassAllocator() {
+ Allocator *a = new Allocator;
+ a->Init();
+ SizeClassAllocatorLocalCache<Allocator> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+
+ static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
+ 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000};
+
+ std::vector<void *> allocated;
+
+ uptr last_total_allocated = 0;
+ for (int i = 0; i < 3; i++) {
+ // Allocate a bunch of chunks.
+ for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
+ uptr size = sizes[s];
+ if (!a->CanAllocate(size, 1)) continue;
+ // printf("s = %ld\n", size);
+ uptr n_iter = std::max((uptr)6, 8000000 / size);
+ // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter);
+ for (uptr i = 0; i < n_iter; i++) {
+ uptr class_id0 = Allocator::SizeClassMapT::ClassID(size);
+ char *x = (char*)cache.Allocate(a, class_id0);
+ x[0] = 0;
+ x[size - 1] = 0;
+ x[size / 2] = 0;
+ allocated.push_back(x);
+ CHECK_EQ(x, a->GetBlockBegin(x));
+ CHECK_EQ(x, a->GetBlockBegin(x + size - 1));
+ CHECK(a->PointerIsMine(x));
+ CHECK(a->PointerIsMine(x + size - 1));
+ CHECK(a->PointerIsMine(x + size / 2));
+ CHECK_GE(a->GetActuallyAllocatedSize(x), size);
+ uptr class_id = a->GetSizeClass(x);
+ CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size));
+ uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
+ metadata[0] = reinterpret_cast<uptr>(x) + 1;
+ metadata[1] = 0xABCD;
+ }
+ }
+ // Deallocate all.
+ for (uptr i = 0; i < allocated.size(); i++) {
+ void *x = allocated[i];
+ uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
+ CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
+ CHECK_EQ(metadata[1], 0xABCD);
+ cache.Deallocate(a, a->GetSizeClass(x), x);
+ }
+ allocated.clear();
+ uptr total_allocated = a->TotalMemoryUsed();
+ if (last_total_allocated == 0)
+ last_total_allocated = total_allocated;
+ CHECK_EQ(last_total_allocated, total_allocated);
+ }
+
+ // Check that GetBlockBegin never crashes.
+ for (uptr x = 0, step = kAddressSpaceSize / 100000;
+ x < kAddressSpaceSize - step; x += step)
+ if (a->PointerIsMine(reinterpret_cast<void *>(x)))
+ Ident(a->GetBlockBegin(reinterpret_cast<void *>(x)));
+
+ a->TestOnlyUnmap();
+ delete a;
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64) {
+ TestSizeClassAllocator<Allocator64>();
+}
+
+TEST(SanitizerCommon, SizeClassAllocator64Compact) {
+ TestSizeClassAllocator<Allocator64Compact>();
+}
+#endif
+
+TEST(SanitizerCommon, SizeClassAllocator32Compact) {
+ TestSizeClassAllocator<Allocator32Compact>();
+}
+
+template <class Allocator>
+void SizeClassAllocatorMetadataStress() {
+ Allocator *a = new Allocator;
+ a->Init();
+ SizeClassAllocatorLocalCache<Allocator> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+
+ const uptr kNumAllocs = 1 << 13;
+ void *allocated[kNumAllocs];
+ void *meta[kNumAllocs];
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ void *x = cache.Allocate(a, 1 + i % 50);
+ allocated[i] = x;
+ meta[i] = a->GetMetaData(x);
+ }
+ // Get Metadata kNumAllocs^2 times.
+ for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
+ uptr idx = i % kNumAllocs;
+ void *m = a->GetMetaData(allocated[idx]);
+ EXPECT_EQ(m, meta[idx]);
+ }
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ cache.Deallocate(a, 1 + i % 50, allocated[i]);
+ }
+
+ a->TestOnlyUnmap();
+ delete a;
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
+ SizeClassAllocatorMetadataStress<Allocator64>();
+}
+
+TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) {
+ SizeClassAllocatorMetadataStress<Allocator64Compact>();
+}
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) {
+ SizeClassAllocatorMetadataStress<Allocator32Compact>();
+}
+
+template <class Allocator>
+void SizeClassAllocatorGetBlockBeginStress() {
+ Allocator *a = new Allocator;
+ a->Init();
+ SizeClassAllocatorLocalCache<Allocator> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+
+ uptr max_size_class = Allocator::kNumClasses - 1;
+ uptr size = Allocator::SizeClassMapT::Size(max_size_class);
+ u64 G8 = 1ULL << 33;
+ // Make sure we correctly compute GetBlockBegin() w/o overflow.
+ for (size_t i = 0; i <= G8 / size; i++) {
+ void *x = cache.Allocate(a, max_size_class);
+ void *beg = a->GetBlockBegin(x);
+ // if ((i & (i - 1)) == 0)
+ // fprintf(stderr, "[%zd] %p %p\n", i, x, beg);
+ EXPECT_EQ(x, beg);
+ }
+
+ a->TestOnlyUnmap();
+ delete a;
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64GetBlockBegin) {
+ SizeClassAllocatorGetBlockBeginStress<Allocator64>();
+}
+TEST(SanitizerCommon, SizeClassAllocator64CompactGetBlockBegin) {
+ SizeClassAllocatorGetBlockBeginStress<Allocator64Compact>();
+}
+TEST(SanitizerCommon, SizeClassAllocator32CompactGetBlockBegin) {
+ SizeClassAllocatorGetBlockBeginStress<Allocator32Compact>();
+}
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
+
+struct TestMapUnmapCallback {
+ static int map_count, unmap_count;
+ void OnMap(uptr p, uptr size) const { map_count++; }
+ void OnUnmap(uptr p, uptr size) const { unmap_count++; }
+};
+int TestMapUnmapCallback::map_count;
+int TestMapUnmapCallback::unmap_count;
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) {
+ TestMapUnmapCallback::map_count = 0;
+ TestMapUnmapCallback::unmap_count = 0;
+ typedef SizeClassAllocator64<
+ kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap,
+ TestMapUnmapCallback> Allocator64WithCallBack;
+ Allocator64WithCallBack *a = new Allocator64WithCallBack;
+ a->Init();
+ EXPECT_EQ(TestMapUnmapCallback::map_count, 1); // Allocator state.
+ SizeClassAllocatorLocalCache<Allocator64WithCallBack> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+ AllocatorStats stats;
+ stats.Init();
+ a->AllocateBatch(&stats, &cache, 32);
+ EXPECT_EQ(TestMapUnmapCallback::map_count, 3); // State + alloc + metadata.
+ a->TestOnlyUnmap();
+ EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); // The whole thing.
+ delete a;
+}
+#endif
+
+TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {
+ TestMapUnmapCallback::map_count = 0;
+ TestMapUnmapCallback::unmap_count = 0;
+ typedef SizeClassAllocator32<
+ 0, kAddressSpaceSize,
+ /*kMetadataSize*/16,
+ CompactSizeClassMap,
+ kRegionSizeLog,
+ FlatByteMap<kFlatByteMapSize>,
+ TestMapUnmapCallback>
+ Allocator32WithCallBack;
+ Allocator32WithCallBack *a = new Allocator32WithCallBack;
+ a->Init();
+ EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
+ SizeClassAllocatorLocalCache<Allocator32WithCallBack> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+ AllocatorStats stats;
+ stats.Init();
+ a->AllocateBatch(&stats, &cache, 32);
+ EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
+ a->TestOnlyUnmap();
+ EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
+ delete a;
+ // fprintf(stderr, "Map: %d Unmap: %d\n",
+ // TestMapUnmapCallback::map_count,
+ // TestMapUnmapCallback::unmap_count);
+}
+
+TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) {
+ TestMapUnmapCallback::map_count = 0;
+ TestMapUnmapCallback::unmap_count = 0;
+ LargeMmapAllocator<TestMapUnmapCallback> a;
+ a.Init(/* may_return_null */ false);
+ AllocatorStats stats;
+ stats.Init();
+ void *x = a.Allocate(&stats, 1 << 20, 1);
+ EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
+ a.Deallocate(&stats, x);
+ EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
+}
+
+template<class Allocator>
+void FailInAssertionOnOOM() {
+ Allocator a;
+ a.Init();
+ SizeClassAllocatorLocalCache<Allocator> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+ AllocatorStats stats;
+ stats.Init();
+ for (int i = 0; i < 1000000; i++) {
+ a.AllocateBatch(&stats, &cache, 52);
+ }
+
+ a.TestOnlyUnmap();
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
+ EXPECT_DEATH(FailInAssertionOnOOM<Allocator64>(), "Out of memory");
+}
+#endif
+
+#if !defined(_WIN32) // FIXME: This currently fails on Windows.
+TEST(SanitizerCommon, LargeMmapAllocator) {
+ LargeMmapAllocator<> a;
+ a.Init(/* may_return_null */ false);
+ AllocatorStats stats;
+ stats.Init();
+
+ static const int kNumAllocs = 1000;
+ char *allocated[kNumAllocs];
+ static const uptr size = 4000;
+ // Allocate some.
+ for (int i = 0; i < kNumAllocs; i++) {
+ allocated[i] = (char *)a.Allocate(&stats, size, 1);
+ CHECK(a.PointerIsMine(allocated[i]));
+ }
+ // Deallocate all.
+ CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
+ for (int i = 0; i < kNumAllocs; i++) {
+ char *p = allocated[i];
+ CHECK(a.PointerIsMine(p));
+ a.Deallocate(&stats, p);
+ }
+ // Check that non left.
+ CHECK_EQ(a.TotalMemoryUsed(), 0);
+
+ // Allocate some more, also add metadata.
+ for (int i = 0; i < kNumAllocs; i++) {
+ char *x = (char *)a.Allocate(&stats, size, 1);
+ CHECK_GE(a.GetActuallyAllocatedSize(x), size);
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ *meta = i;
+ allocated[i] = x;
+ }
+ for (int i = 0; i < kNumAllocs * kNumAllocs; i++) {
+ char *p = allocated[i % kNumAllocs];
+ CHECK(a.PointerIsMine(p));
+ CHECK(a.PointerIsMine(p + 2000));
+ }
+ CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
+ // Deallocate all in reverse order.
+ for (int i = 0; i < kNumAllocs; i++) {
+ int idx = kNumAllocs - i - 1;
+ char *p = allocated[idx];
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
+ CHECK_EQ(*meta, idx);
+ CHECK(a.PointerIsMine(p));
+ a.Deallocate(&stats, p);
+ }
+ CHECK_EQ(a.TotalMemoryUsed(), 0);
+
+ // Test alignments.
+ uptr max_alignment = SANITIZER_WORDSIZE == 64 ? (1 << 28) : (1 << 24);
+ for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) {
+ const uptr kNumAlignedAllocs = 100;
+ for (uptr i = 0; i < kNumAlignedAllocs; i++) {
+ uptr size = ((i % 10) + 1) * 4096;
+ char *p = allocated[i] = (char *)a.Allocate(&stats, size, alignment);
+ CHECK_EQ(p, a.GetBlockBegin(p));
+ CHECK_EQ(p, a.GetBlockBegin(p + size - 1));
+ CHECK_EQ(p, a.GetBlockBegin(p + size / 2));
+ CHECK_EQ(0, (uptr)allocated[i] % alignment);
+ p[0] = p[size - 1] = 0;
+ }
+ for (uptr i = 0; i < kNumAlignedAllocs; i++) {
+ a.Deallocate(&stats, allocated[i]);
+ }
+ }
+
+ // Regression test for boundary condition in GetBlockBegin().
+ uptr page_size = GetPageSizeCached();
+ char *p = (char *)a.Allocate(&stats, page_size, 1);
+ CHECK_EQ(p, a.GetBlockBegin(p));
+ CHECK_EQ(p, (char *)a.GetBlockBegin(p + page_size - 1));
+ CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
+ a.Deallocate(&stats, p);
+}
+#endif
+
+template
+<class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
+void TestCombinedAllocator() {
+ typedef
+ CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator>
+ Allocator;
+ Allocator *a = new Allocator;
+ a->Init(/* may_return_null */ true);
+
+ AllocatorCache cache;
+ memset(&cache, 0, sizeof(cache));
+ a->InitCache(&cache);
+
+ EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0);
+ EXPECT_EQ(a->Allocate(&cache, -1, 1024), (void*)0);
+ EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);
+ EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);
+ EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0);
+
+ // Set to false
+ a->SetMayReturnNull(false);
+ EXPECT_DEATH(a->Allocate(&cache, -1, 1),
+ "allocator is terminating the process");
+
+ const uptr kNumAllocs = 100000;
+ const uptr kNumIter = 10;
+ for (uptr iter = 0; iter < kNumIter; iter++) {
+ std::vector<void*> allocated;
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ uptr size = (i % (1 << 14)) + 1;
+ if ((i % 1024) == 0)
+ size = 1 << (10 + (i % 14));
+ void *x = a->Allocate(&cache, size, 1);
+ uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
+ CHECK_EQ(*meta, 0);
+ *meta = size;
+ allocated.push_back(x);
+ }
+
+ random_shuffle(allocated.begin(), allocated.end());
+
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ void *x = allocated[i];
+ uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
+ CHECK_NE(*meta, 0);
+ CHECK(a->PointerIsMine(x));
+ *meta = 0;
+ a->Deallocate(&cache, x);
+ }
+ allocated.clear();
+ a->SwallowCache(&cache);
+ }
+ a->DestroyCache(&cache);
+ a->TestOnlyUnmap();
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, CombinedAllocator64) {
+ TestCombinedAllocator<Allocator64,
+ LargeMmapAllocator<>,
+ SizeClassAllocatorLocalCache<Allocator64> > ();
+}
+
+TEST(SanitizerCommon, CombinedAllocator64Compact) {
+ TestCombinedAllocator<Allocator64Compact,
+ LargeMmapAllocator<>,
+ SizeClassAllocatorLocalCache<Allocator64Compact> > ();
+}
+#endif
+
+#if !defined(_WIN32) // FIXME: This currently fails on Windows.
+TEST(SanitizerCommon, CombinedAllocator32Compact) {
+ TestCombinedAllocator<Allocator32Compact,
+ LargeMmapAllocator<>,
+ SizeClassAllocatorLocalCache<Allocator32Compact> > ();
+}
+#endif
+
+template <class AllocatorCache>
+void TestSizeClassAllocatorLocalCache() {
+ AllocatorCache cache;
+ typedef typename AllocatorCache::Allocator Allocator;
+ Allocator *a = new Allocator();
+
+ a->Init();
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+
+ const uptr kNumAllocs = 10000;
+ const int kNumIter = 100;
+ uptr saved_total = 0;
+ for (int class_id = 1; class_id <= 5; class_id++) {
+ for (int it = 0; it < kNumIter; it++) {
+ void *allocated[kNumAllocs];
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ allocated[i] = cache.Allocate(a, class_id);
+ }
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ cache.Deallocate(a, class_id, allocated[i]);
+ }
+ cache.Drain(a);
+ uptr total_allocated = a->TotalMemoryUsed();
+ if (it)
+ CHECK_EQ(saved_total, total_allocated);
+ saved_total = total_allocated;
+ }
+ }
+
+ a->TestOnlyUnmap();
+ delete a;
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64LocalCache) {
+ TestSizeClassAllocatorLocalCache<
+ SizeClassAllocatorLocalCache<Allocator64> >();
+}
+
+TEST(SanitizerCommon, SizeClassAllocator64CompactLocalCache) {
+ TestSizeClassAllocatorLocalCache<
+ SizeClassAllocatorLocalCache<Allocator64Compact> >();
+}
+#endif
+
+TEST(SanitizerCommon, SizeClassAllocator32CompactLocalCache) {
+ TestSizeClassAllocatorLocalCache<
+ SizeClassAllocatorLocalCache<Allocator32Compact> >();
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+typedef SizeClassAllocatorLocalCache<Allocator64> AllocatorCache;
+static AllocatorCache static_allocator_cache;
+
+void *AllocatorLeakTestWorker(void *arg) {
+ typedef AllocatorCache::Allocator Allocator;
+ Allocator *a = (Allocator*)(arg);
+ static_allocator_cache.Allocate(a, 10);
+ static_allocator_cache.Drain(a);
+ return 0;
+}
+
+TEST(SanitizerCommon, AllocatorLeakTest) {
+ typedef AllocatorCache::Allocator Allocator;
+ Allocator a;
+ a.Init();
+ uptr total_used_memory = 0;
+ for (int i = 0; i < 100; i++) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a);
+ PTHREAD_JOIN(t, 0);
+ if (i == 0)
+ total_used_memory = a.TotalMemoryUsed();
+ EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory);
+ }
+
+ a.TestOnlyUnmap();
+}
+
+// Struct which is allocated to pass info to new threads. The new thread frees
+// it.
+struct NewThreadParams {
+ AllocatorCache *thread_cache;
+ AllocatorCache::Allocator *allocator;
+ uptr class_id;
+};
+
+// Called in a new thread. Just frees its argument.
+static void *DeallocNewThreadWorker(void *arg) {
+ NewThreadParams *params = reinterpret_cast<NewThreadParams*>(arg);
+ params->thread_cache->Deallocate(params->allocator, params->class_id, params);
+ return NULL;
+}
+
+// The allocator cache is supposed to be POD and zero initialized. We should be
+// able to call Deallocate on a zeroed cache, and it will self-initialize.
+TEST(Allocator, AllocatorCacheDeallocNewThread) {
+ AllocatorCache::Allocator allocator;
+ allocator.Init();
+ AllocatorCache main_cache;
+ AllocatorCache child_cache;
+ memset(&main_cache, 0, sizeof(main_cache));
+ memset(&child_cache, 0, sizeof(child_cache));
+
+ uptr class_id = DefaultSizeClassMap::ClassID(sizeof(NewThreadParams));
+ NewThreadParams *params = reinterpret_cast<NewThreadParams*>(
+ main_cache.Allocate(&allocator, class_id));
+ params->thread_cache = &child_cache;
+ params->allocator = &allocator;
+ params->class_id = class_id;
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params);
+ PTHREAD_JOIN(t, 0);
+}
+#endif
+
+TEST(Allocator, Basic) {
+ char *p = (char*)InternalAlloc(10);
+ EXPECT_NE(p, (char*)0);
+ char *p2 = (char*)InternalAlloc(20);
+ EXPECT_NE(p2, (char*)0);
+ EXPECT_NE(p2, p);
+ InternalFree(p);
+ InternalFree(p2);
+}
+
+TEST(Allocator, Stress) {
+ const int kCount = 1000;
+ char *ptrs[kCount];
+ unsigned rnd = 42;
+ for (int i = 0; i < kCount; i++) {
+ uptr sz = my_rand_r(&rnd) % 1000;
+ char *p = (char*)InternalAlloc(sz);
+ EXPECT_NE(p, (char*)0);
+ ptrs[i] = p;
+ }
+ for (int i = 0; i < kCount; i++) {
+ InternalFree(ptrs[i]);
+ }
+}
+
+TEST(Allocator, LargeAlloc) {
+ void *p = InternalAlloc(10 << 20);
+ InternalFree(p);
+}
+
+TEST(Allocator, ScopedBuffer) {
+ const int kSize = 512;
+ {
+ InternalScopedBuffer<int> int_buf(kSize);
+ EXPECT_EQ(sizeof(int) * kSize, int_buf.size()); // NOLINT
+ }
+ InternalScopedBuffer<char> char_buf(kSize);
+ EXPECT_EQ(sizeof(char) * kSize, char_buf.size()); // NOLINT
+ internal_memset(char_buf.data(), 'c', kSize);
+ for (int i = 0; i < kSize; i++) {
+ EXPECT_EQ('c', char_buf[i]);
+ }
+}
+
+void IterationTestCallback(uptr chunk, void *arg) {
+ reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk);
+}
+
+template <class Allocator>
+void TestSizeClassAllocatorIteration() {
+ Allocator *a = new Allocator;
+ a->Init();
+ SizeClassAllocatorLocalCache<Allocator> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+
+ static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
+ 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000};
+
+ std::vector<void *> allocated;
+
+ // Allocate a bunch of chunks.
+ for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
+ uptr size = sizes[s];
+ if (!a->CanAllocate(size, 1)) continue;
+ // printf("s = %ld\n", size);
+ uptr n_iter = std::max((uptr)6, 80000 / size);
+ // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter);
+ for (uptr j = 0; j < n_iter; j++) {
+ uptr class_id0 = Allocator::SizeClassMapT::ClassID(size);
+ void *x = cache.Allocate(a, class_id0);
+ allocated.push_back(x);
+ }
+ }
+
+ std::set<uptr> reported_chunks;
+ a->ForceLock();
+ a->ForEachChunk(IterationTestCallback, &reported_chunks);
+ a->ForceUnlock();
+
+ for (uptr i = 0; i < allocated.size(); i++) {
+ // Don't use EXPECT_NE. Reporting the first mismatch is enough.
+ ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
+ reported_chunks.end());
+ }
+
+ a->TestOnlyUnmap();
+ delete a;
+}
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+TEST(SanitizerCommon, SizeClassAllocator64Iteration) {
+ TestSizeClassAllocatorIteration<Allocator64>();
+}
+#endif
+
+TEST(SanitizerCommon, SizeClassAllocator32Iteration) {
+ TestSizeClassAllocatorIteration<Allocator32Compact>();
+}
+
+TEST(SanitizerCommon, LargeMmapAllocatorIteration) {
+ LargeMmapAllocator<> a;
+ a.Init(/* may_return_null */ false);
+ AllocatorStats stats;
+ stats.Init();
+
+ static const uptr kNumAllocs = 1000;
+ char *allocated[kNumAllocs];
+ static const uptr size = 40;
+ // Allocate some.
+ for (uptr i = 0; i < kNumAllocs; i++)
+ allocated[i] = (char *)a.Allocate(&stats, size, 1);
+
+ std::set<uptr> reported_chunks;
+ a.ForceLock();
+ a.ForEachChunk(IterationTestCallback, &reported_chunks);
+ a.ForceUnlock();
+
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ // Don't use EXPECT_NE. Reporting the first mismatch is enough.
+ ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
+ reported_chunks.end());
+ }
+ for (uptr i = 0; i < kNumAllocs; i++)
+ a.Deallocate(&stats, allocated[i]);
+}
+
+TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) {
+ LargeMmapAllocator<> a;
+ a.Init(/* may_return_null */ false);
+ AllocatorStats stats;
+ stats.Init();
+
+ static const uptr kNumAllocs = 1024;
+ static const uptr kNumExpectedFalseLookups = 10000000;
+ char *allocated[kNumAllocs];
+ static const uptr size = 4096;
+ // Allocate some.
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ allocated[i] = (char *)a.Allocate(&stats, size, 1);
+ }
+
+ a.ForceLock();
+ for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
+ // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i);
+ char *p1 = allocated[i % kNumAllocs];
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1));
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2));
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1));
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100));
+ }
+
+ for (uptr i = 0; i < kNumExpectedFalseLookups; i++) {
+ void *p = reinterpret_cast<void *>(i % 1024);
+ EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
+ p = reinterpret_cast<void *>(~0L - (i % 1024));
+ EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
+ }
+ a.ForceUnlock();
+
+ for (uptr i = 0; i < kNumAllocs; i++)
+ a.Deallocate(&stats, allocated[i]);
+}
+
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+// Regression test for out-of-memory condition in PopulateFreeList().
+TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
+ // In a world where regions are small and chunks are huge...
+ typedef SizeClassMap<63, 128, 16> SpecialSizeClassMap;
+ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
+ SpecialSizeClassMap> SpecialAllocator64;
+ const uptr kRegionSize =
+ kAllocatorSize / SpecialSizeClassMap::kNumClassesRounded;
+ SpecialAllocator64 *a = new SpecialAllocator64;
+ a->Init();
+ SizeClassAllocatorLocalCache<SpecialAllocator64> cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.Init(0);
+
+ // ...one man is on a mission to overflow a region with a series of
+ // successive allocations.
+ const uptr kClassID = 107;
+ const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID);
+ ASSERT_LT(2 * kAllocationSize, kRegionSize);
+ ASSERT_GT(3 * kAllocationSize, kRegionSize);
+ cache.Allocate(a, kClassID);
+ EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID),
+ "The process has exhausted");
+ a->TestOnlyUnmap();
+ delete a;
+}
+#endif
+
+TEST(SanitizerCommon, TwoLevelByteMap) {
+ const u64 kSize1 = 1 << 6, kSize2 = 1 << 12;
+ const u64 n = kSize1 * kSize2;
+ TwoLevelByteMap<kSize1, kSize2> m;
+ m.TestOnlyInit();
+ for (u64 i = 0; i < n; i += 7) {
+ m.set(i, (i % 100) + 1);
+ }
+ for (u64 j = 0; j < n; j++) {
+ if (j % 7)
+ EXPECT_EQ(m[j], 0);
+ else
+ EXPECT_EQ(m[j], (j % 100) + 1);
+ }
+
+ m.TestOnlyUnmap();
+}
+
+
+typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap;
+
+struct TestByteMapParam {
+ TestByteMap *m;
+ size_t shard;
+ size_t num_shards;
+};
+
+void *TwoLevelByteMapUserThread(void *param) {
+ TestByteMapParam *p = (TestByteMapParam*)param;
+ for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) {
+ size_t val = (i % 100) + 1;
+ p->m->set(i, val);
+ EXPECT_EQ((*p->m)[i], val);
+ }
+ return 0;
+}
+
+TEST(SanitizerCommon, ThreadedTwoLevelByteMap) {
+ TestByteMap m;
+ m.TestOnlyInit();
+ TestMapUnmapCallback::map_count = 0;
+ TestMapUnmapCallback::unmap_count = 0;
+ static const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ TestByteMapParam p[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ p[i].m = &m;
+ p[i].shard = i;
+ p[i].num_shards = kNumThreads;
+ PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+ EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+ EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL);
+ m.TestOnlyUnmap();
+ EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+ EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1());
+}
+
+#endif // #if !SANITIZER_DEBUG
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
new file mode 100644
index 000000000000..0cc3b9ba6944
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
@@ -0,0 +1,162 @@
+//===-- sanitizer_allocator_testlib.cc ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Malloc replacement library based on CombinedAllocator.
+// The primary purpose of this file is an end-to-end integration test
+// for CombinedAllocator.
+//===----------------------------------------------------------------------===//
+/* Usage:
+clang++ -fno-exceptions -g -fPIC -I. -I../include -Isanitizer \
+ sanitizer_common/tests/sanitizer_allocator_testlib.cc \
+ sanitizer_common/sanitizer_*.cc -shared -lpthread -o testmalloc.so
+LD_PRELOAD=`pwd`/testmalloc.so /your/app
+*/
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+#ifndef SANITIZER_MALLOC_HOOK
+# define SANITIZER_MALLOC_HOOK(p, s)
+#endif
+
+#ifndef SANITIZER_FREE_HOOK
+# define SANITIZER_FREE_HOOK(p)
+#endif
+
+namespace {
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
+
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
+ CompactSizeClassMap> PrimaryAllocator;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static bool global_inited;
+static THREADLOCAL AllocatorCache cache;
+static THREADLOCAL bool thread_inited;
+static pthread_key_t pkey;
+
+static void thread_dtor(void *v) {
+ if ((uptr)v != 3) {
+ pthread_setspecific(pkey, (void*)((uptr)v + 1));
+ return;
+ }
+ allocator.SwallowCache(&cache);
+}
+
+static void NOINLINE thread_init() {
+ if (!global_inited) {
+ global_inited = true;
+ allocator.Init();
+ pthread_key_create(&pkey, thread_dtor);
+ }
+ thread_inited = true;
+ pthread_setspecific(pkey, (void*)1);
+ cache.Init();
+}
+} // namespace
+
+extern "C" {
+void *malloc(size_t size) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ void *p = allocator.Allocate(&cache, size, 8);
+ SANITIZER_MALLOC_HOOK(p, size);
+ return p;
+}
+
+void free(void *p) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ SANITIZER_FREE_HOOK(p);
+ allocator.Deallocate(&cache, p);
+}
+
+void *calloc(size_t nmemb, size_t size) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ size *= nmemb;
+ void *p = allocator.Allocate(&cache, size, 8, false);
+ memset(p, 0, size);
+ SANITIZER_MALLOC_HOOK(p, size);
+ return p;
+}
+
+void *realloc(void *p, size_t size) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ if (p) {
+ SANITIZER_FREE_HOOK(p);
+ }
+ p = allocator.Reallocate(&cache, p, size, 8);
+ if (p) {
+ SANITIZER_MALLOC_HOOK(p, size);
+ }
+ return p;
+}
+
+void *memalign(size_t alignment, size_t size) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ void *p = allocator.Allocate(&cache, size, alignment);
+ SANITIZER_MALLOC_HOOK(p, size);
+ return p;
+}
+
+int posix_memalign(void **memptr, size_t alignment, size_t size) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ *memptr = allocator.Allocate(&cache, size, alignment);
+ SANITIZER_MALLOC_HOOK(*memptr, size);
+ return 0;
+}
+
+void *valloc(size_t size) {
+ if (UNLIKELY(!thread_inited))
+ thread_init();
+ if (size == 0)
+ size = GetPageSizeCached();
+ void *p = allocator.Allocate(&cache, size, GetPageSizeCached());
+ SANITIZER_MALLOC_HOOK(p, size);
+ return p;
+}
+
+void cfree(void *p) ALIAS("free");
+void *pvalloc(size_t size) ALIAS("valloc");
+void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign");
+
+void malloc_usable_size() {
+}
+
+void mallinfo() {
+}
+
+void mallopt() {
+}
+} // extern "C"
+
+namespace std {
+ struct nothrow_t;
+}
+
+void *operator new(size_t size) ALIAS("malloc");
+void *operator new[](size_t size) ALIAS("malloc");
+void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc");
+void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc");
+void operator delete(void *ptr) throw() ALIAS("free");
+void operator delete[](void *ptr) throw() ALIAS("free");
+void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free");
+void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free");
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
new file mode 100644
index 000000000000..56bcd35c826c
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
@@ -0,0 +1,128 @@
+//===-- sanitizer_atomic_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+template<typename T>
+struct ValAndMagic {
+ typename T::Type magic0;
+ T a;
+ typename T::Type magic1;
+
+ static ValAndMagic<T> *sink;
+};
+
+template<typename T>
+ValAndMagic<T> *ValAndMagic<T>::sink;
+
+template<typename T, memory_order load_mo, memory_order store_mo>
+void CheckStoreLoad() {
+ typedef typename T::Type Type;
+ ValAndMagic<T> val;
+ // Prevent the compiler from scalarizing the struct.
+ ValAndMagic<T>::sink = &val;
+ // Ensure that surrounding memory is not overwritten.
+ val.magic0 = val.magic1 = (Type)-3;
+ for (u64 i = 0; i < 100; i++) {
+ // Generate a value that occupies all bytes of the variable.
+ u64 v = i;
+ v |= v << 8;
+ v |= v << 16;
+ v |= v << 32;
+ val.a.val_dont_use = (Type)v;
+ EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
+ val.a.val_dont_use = (Type)-1;
+ atomic_store(&val.a, (Type)v, store_mo);
+ EXPECT_EQ(val.a.val_dont_use, (Type)v);
+ }
+ EXPECT_EQ(val.magic0, (Type)-3);
+ EXPECT_EQ(val.magic1, (Type)-3);
+}
+
+TEST(SanitizerCommon, AtomicStoreLoad) {
+ CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
+ ();
+}
+
+// Clang crashes while compiling this test for Android:
+// http://llvm.org/bugs/show_bug.cgi?id=15587
+#if !SANITIZER_ANDROID
+template<typename T>
+void CheckAtomicCompareExchange() {
+ typedef typename T::Type Type;
+ {
+ Type old_val = 42;
+ Type new_val = 24;
+ Type var = old_val;
+ EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
+ memory_order_relaxed));
+ EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
+ memory_order_relaxed));
+ EXPECT_EQ(new_val, old_val);
+ }
+ {
+ Type old_val = 42;
+ Type new_val = 24;
+ Type var = old_val;
+ EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
+ memory_order_relaxed));
+ EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
+ memory_order_relaxed));
+ EXPECT_EQ(new_val, old_val);
+ }
+}
+
+TEST(SanitizerCommon, AtomicCompareExchangeTest) {
+ CheckAtomicCompareExchange<atomic_uint8_t>();
+ CheckAtomicCompareExchange<atomic_uint16_t>();
+ CheckAtomicCompareExchange<atomic_uint32_t>();
+ CheckAtomicCompareExchange<atomic_uint64_t>();
+ CheckAtomicCompareExchange<atomic_uintptr_t>();
+}
+#endif //!SANITIZER_ANDROID
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
new file mode 100644
index 000000000000..706b4c58968e
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
@@ -0,0 +1,176 @@
+//===-- sanitizer_bitvector_test.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 Sanitizer runtime.
+// Tests for sanitizer_bitvector.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bitvector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+
+// Check the 'bv' == 's' and that the indexes go in increasing order.
+// Also check the BV::Iterator
+template <class BV>
+static void CheckBV(const BV &bv, const set<uptr> &s) {
+ BV t;
+ t.copyFrom(bv);
+ set<uptr> t_s(s);
+ uptr last_idx = bv.size();
+ uptr count = 0;
+ for (typename BV::Iterator it(bv); it.hasNext();) {
+ uptr idx = it.next();
+ count++;
+ if (last_idx != bv.size())
+ EXPECT_LT(last_idx, idx);
+ last_idx = idx;
+ EXPECT_TRUE(s.count(idx));
+ }
+ EXPECT_EQ(count, s.size());
+
+ last_idx = bv.size();
+ while (!t.empty()) {
+ uptr idx = t.getAndClearFirstOne();
+ if (last_idx != bv.size())
+ EXPECT_LT(last_idx, idx);
+ last_idx = idx;
+ EXPECT_TRUE(t_s.erase(idx));
+ }
+ EXPECT_TRUE(t_s.empty());
+}
+
+template <class BV>
+void Print(const BV &bv) {
+ BV t;
+ t.copyFrom(bv);
+ while (!t.empty()) {
+ uptr idx = t.getAndClearFirstOne();
+ fprintf(stderr, "%zd ", idx);
+ }
+ fprintf(stderr, "\n");
+}
+
+void Print(const set<uptr> &s) {
+ for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it) {
+ fprintf(stderr, "%zd ", *it);
+ }
+ fprintf(stderr, "\n");
+}
+
+template <class BV>
+void TestBitVector(uptr expected_size) {
+ BV bv, bv1, t_bv;
+ EXPECT_EQ(expected_size, BV::kSize);
+ bv.clear();
+ EXPECT_TRUE(bv.empty());
+ bv.setBit(5);
+ EXPECT_FALSE(bv.empty());
+ EXPECT_FALSE(bv.getBit(4));
+ EXPECT_FALSE(bv.getBit(6));
+ EXPECT_TRUE(bv.getBit(5));
+ bv.clearBit(5);
+ EXPECT_FALSE(bv.getBit(5));
+
+ // test random bits
+ bv.clear();
+ set<uptr> s;
+ for (uptr it = 0; it < 1000; it++) {
+ uptr bit = ((uptr)my_rand() % bv.size());
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ switch (my_rand() % 2) {
+ case 0:
+ EXPECT_EQ(bv.setBit(bit), s.insert(bit).second);
+ break;
+ case 1:
+ size_t old_size = s.size();
+ s.erase(bit);
+ EXPECT_EQ(bv.clearBit(bit), old_size > s.size());
+ break;
+ }
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ }
+
+ vector<uptr>bits(bv.size());
+ // Test setUnion, setIntersection, setDifference,
+ // intersectsWith, and getAndClearFirstOne.
+ for (uptr it = 0; it < 30; it++) {
+ // iota
+ for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
+ random_shuffle(bits.begin(), bits.end());
+ set<uptr> s, s1, t_s;
+ bv.clear();
+ bv1.clear();
+ uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
+ uptr n_bits1 = (uptr)my_rand() % (bv.size() / 2);
+ EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
+ EXPECT_TRUE(n_bits1 < bv.size() / 2);
+ for (uptr i = 0; i < n_bits; i++) {
+ bv.setBit(bits[i]);
+ s.insert(bits[i]);
+ }
+ CheckBV(bv, s);
+ for (uptr i = 0; i < n_bits1; i++) {
+ bv1.setBit(bits[bv.size() / 2 + i]);
+ s1.insert(bits[bv.size() / 2 + i]);
+ }
+ CheckBV(bv1, s1);
+
+ vector<uptr> vec;
+ set_intersection(s.begin(), s.end(), s1.begin(), s1.end(),
+ back_insert_iterator<vector<uptr> >(vec));
+ EXPECT_EQ(bv.intersectsWith(bv1), !vec.empty());
+
+ // setUnion
+ t_s = s;
+ t_bv.copyFrom(bv);
+ t_s.insert(s1.begin(), s1.end());
+ EXPECT_EQ(t_bv.setUnion(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+
+ // setIntersection
+ t_s = set<uptr>(vec.begin(), vec.end());
+ t_bv.copyFrom(bv);
+ EXPECT_EQ(t_bv.setIntersection(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+
+ // setDifference
+ vec.clear();
+ set_difference(s.begin(), s.end(), s1.begin(), s1.end(),
+ back_insert_iterator<vector<uptr> >(vec));
+ t_s = set<uptr>(vec.begin(), vec.end());
+ t_bv.copyFrom(bv);
+ EXPECT_EQ(t_bv.setDifference(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+ }
+}
+
+TEST(SanitizerCommon, BasicBitVector) {
+ TestBitVector<BasicBitVector<u8> >(8);
+ TestBitVector<BasicBitVector<u16> >(16);
+ TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
+}
+
+TEST(SanitizerCommon, TwoLevelBitVector) {
+ uptr ws = SANITIZER_WORDSIZE;
+ TestBitVector<TwoLevelBitVector<1, BasicBitVector<u8> > >(8 * 8);
+ TestBitVector<TwoLevelBitVector<> >(ws * ws);
+ TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
+ TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
+ TestBitVector<TwoLevelBitVector<3, BasicBitVector<u16> > >(16 * 16 * 3);
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
new file mode 100644
index 000000000000..3b39f8dd734a
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
@@ -0,0 +1,339 @@
+//===-- sanitizer_bvgraph_test.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 Sanitizer runtime.
+// Tests for sanitizer_bvgraph.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bvgraph.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+template<class G>
+void PrintGraph(const G &g) {
+ for (uptr i = 0; i < g.size(); i++) {
+ for (uptr j = 0; j < g.size(); j++) {
+ fprintf(stderr, "%d", g.hasEdge(i, j));
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+
+class SimpleGraph {
+ public:
+ void clear() { s_.clear(); }
+ bool addEdge(uptr from, uptr to) {
+ return s_.insert(idx(from, to)).second;
+ }
+ bool removeEdge(uptr from, uptr to) {
+ return s_.erase(idx(from, to));
+ }
+ template <class G>
+ void checkSameAs(G *g) {
+ for (set<uptr>::iterator it = s_.begin(); it != s_.end(); ++it) {
+ uptr from = *it >> 16;
+ uptr to = *it & ((1 << 16) - 1);
+ EXPECT_TRUE(g->removeEdge(from, to));
+ }
+ EXPECT_TRUE(g->empty());
+ }
+ private:
+ uptr idx(uptr from, uptr to) {
+ CHECK_LE(from|to, 1 << 16);
+ return (from << 16) + to;
+ }
+ set<uptr> s_;
+};
+
+template <class BV>
+void BasicTest() {
+ BVGraph<BV> g;
+ g.clear();
+ BV target;
+ SimpleGraph s_g;
+ set<uptr> s;
+ set<uptr> s_target;
+ int num_reachable = 0;
+ for (int it = 0; it < 1000; it++) {
+ target.clear();
+ s_target.clear();
+ for (int t = 0; t < 4; t++) {
+ uptr idx = (uptr)my_rand() % g.size();
+ EXPECT_EQ(target.setBit(idx), s_target.insert(idx).second);
+ }
+ uptr from = my_rand() % g.size();
+ uptr to = my_rand() % g.size();
+ EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+ EXPECT_TRUE(g.hasEdge(from, to));
+ for (int i = 0; i < 10; i++) {
+ from = my_rand() % g.size();
+ bool is_reachable = g.isReachable(from, target);
+ if (is_reachable) {
+ uptr path[BV::kSize];
+ uptr len;
+ for (len = 1; len < BV::kSize; len++) {
+ if (g.findPath(from, target, path, len) == len)
+ break;
+ }
+ EXPECT_LT(len, BV::kSize);
+ EXPECT_TRUE(target.getBit(path[len - 1]));
+ // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n",
+ // from, len, path[0], path[1], path[2]);
+ num_reachable++;
+ }
+ }
+ }
+ EXPECT_GT(num_reachable, 0);
+}
+
+TEST(BVGraph, BasicTest) {
+ BasicTest<BV1>();
+ BasicTest<BV2>();
+ BasicTest<BV3>();
+ BasicTest<BV4>();
+}
+
+template <class BV>
+void RemoveEdges() {
+ SimpleGraph s_g;
+ BVGraph<BV> g;
+ g.clear();
+ BV bv;
+ set<uptr> s;
+ for (int it = 0; it < 100; it++) {
+ s.clear();
+ bv.clear();
+ s_g.clear();
+ g.clear();
+ for (uptr j = 0; j < g.size() * 2; j++) {
+ uptr from = my_rand() % g.size();
+ uptr to = my_rand() % g.size();
+ EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+ }
+ for (uptr j = 0; j < 5; j++) {
+ uptr idx = my_rand() % g.size();
+ s.insert(idx);
+ bv.setBit(idx);
+ }
+
+ if (it % 2) {
+ g.removeEdgesFrom(bv);
+ for (set<uptr>::iterator from = s.begin(); from != s.end(); ++from) {
+ for (uptr to = 0; to < g.size(); to++)
+ s_g.removeEdge(*from, to);
+ }
+ } else {
+ g.removeEdgesTo(bv);
+ for (set<uptr>::iterator to = s.begin(); to != s.end(); ++to) {
+ for (uptr from = 0; from < g.size(); from++)
+ s_g.removeEdge(from, *to);
+ }
+ }
+ s_g.checkSameAs(&g);
+ }
+}
+
+TEST(BVGraph, RemoveEdges) {
+ RemoveEdges<BV1>();
+ RemoveEdges<BV2>();
+ RemoveEdges<BV3>();
+ RemoveEdges<BV4>();
+}
+
+template <class BV>
+void Test_isReachable() {
+ uptr path[5];
+ BVGraph<BV> g;
+ g.clear();
+ BV target;
+ target.clear();
+ uptr t0 = 0;
+ uptr t1 = g.size() - 1;
+ target.setBit(t0);
+ target.setBit(t1);
+
+ uptr f0 = 1;
+ uptr f1 = 2;
+ uptr f2 = g.size() / 2;
+ uptr f3 = g.size() - 2;
+
+ EXPECT_FALSE(g.isReachable(f0, target));
+ EXPECT_FALSE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+
+ g.addEdge(f0, f1);
+ g.addEdge(f1, f2);
+ g.addEdge(f2, f3);
+ EXPECT_FALSE(g.isReachable(f0, target));
+ EXPECT_FALSE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+
+ g.addEdge(f1, t0);
+ EXPECT_TRUE(g.isReachable(f0, target));
+ EXPECT_TRUE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+ EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U);
+ EXPECT_EQ(path[0], f0);
+ EXPECT_EQ(path[1], f1);
+ EXPECT_EQ(path[2], t0);
+ EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U);
+ EXPECT_EQ(path[0], f1);
+ EXPECT_EQ(path[1], t0);
+
+ g.addEdge(f3, t1);
+ EXPECT_TRUE(g.isReachable(f0, target));
+ EXPECT_TRUE(g.isReachable(f1, target));
+ EXPECT_TRUE(g.isReachable(f2, target));
+ EXPECT_TRUE(g.isReachable(f3, target));
+}
+
+TEST(BVGraph, isReachable) {
+ Test_isReachable<BV1>();
+ Test_isReachable<BV2>();
+ Test_isReachable<BV3>();
+ Test_isReachable<BV4>();
+}
+
+template <class BV>
+void LongCycle() {
+ BVGraph<BV> g;
+ g.clear();
+ vector<uptr> path_vec(g.size());
+ uptr *path = path_vec.data();
+ uptr start = 5;
+ for (uptr i = start; i < g.size() - 1; i++) {
+ g.addEdge(i, i + 1);
+ for (uptr j = 0; j < start; j++)
+ g.addEdge(i, j);
+ }
+ // Bad graph that looks like this:
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 11111010000000
+ // 11111001000000
+ // 11111000100000
+ // 11111000010000
+ // 11111000001000
+ // 11111000000100
+ // 11111000000010
+ // 11111000000001
+ // if (g.size() <= 64) PrintGraph(g);
+ BV target;
+ for (uptr i = start + 1; i < g.size(); i += 11) {
+ // if ((i & (i - 1)) == 0) fprintf(stderr, "Path: : %zd\n", i);
+ target.clear();
+ target.setBit(i);
+ EXPECT_TRUE(g.isReachable(start, target));
+ EXPECT_EQ(g.findPath(start, target, path, g.size()), i - start + 1);
+ }
+}
+
+TEST(BVGraph, LongCycle) {
+ LongCycle<BV1>();
+ LongCycle<BV2>();
+ LongCycle<BV3>();
+ LongCycle<BV4>();
+}
+
+template <class BV>
+void ShortestPath() {
+ uptr path[8];
+ BVGraph<BV> g;
+ g.clear();
+ BV t7;
+ t7.clear();
+ t7.setBit(7);
+ // 1=>2=>3=>4=>5=>6=>7
+ // 1=>7
+ g.addEdge(1, 2);
+ g.addEdge(2, 3);
+ g.addEdge(3, 4);
+ g.addEdge(4, 5);
+ g.addEdge(5, 6);
+ g.addEdge(6, 7);
+ g.addEdge(1, 7);
+ EXPECT_TRUE(g.isReachable(1, t7));
+ // No path of length 1.
+ EXPECT_EQ(0U, g.findPath(1, t7, path, 1));
+ // Trying to find a path of len 2..6 gives path of len 2.
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 2));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 3));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 4));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 5));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 6));
+ // Trying to find a path of len 7 gives path of len 7, because this is DFS.
+ EXPECT_EQ(7U, g.findPath(1, t7, path, 7));
+ // But findShortestPath will find the shortest path.
+ EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 2));
+ EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 7));
+}
+
+TEST(BVGraph, ShortestPath) {
+ ShortestPath<BV1>();
+ ShortestPath<BV2>();
+ ShortestPath<BV3>();
+ ShortestPath<BV4>();
+}
+
+template <class BV>
+void RunAddEdgesTest() {
+ BVGraph<BV> g;
+ BV from;
+ const int kMaxEdges = 10;
+ uptr added_edges[kMaxEdges];
+ g.clear();
+ from.clear();
+ EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
+ EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+ from.setBit(0);
+ EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
+ EXPECT_EQ(0U, added_edges[0]);
+ EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+
+ from.clear();
+ from.setBit(1);
+ EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
+ EXPECT_TRUE(g.hasEdge(1, 4));
+ EXPECT_FALSE(g.hasEdge(1, 5));
+ EXPECT_EQ(1U, added_edges[0]);
+ from.setBit(2);
+ from.setBit(3);
+ EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
+ EXPECT_TRUE(g.hasEdge(2, 4));
+ EXPECT_FALSE(g.hasEdge(2, 5));
+ EXPECT_TRUE(g.hasEdge(3, 4));
+ EXPECT_FALSE(g.hasEdge(3, 5));
+ EXPECT_EQ(2U, added_edges[0]);
+ EXPECT_EQ(3U, added_edges[1]);
+}
+
+TEST(BVGraph, AddEdgesTest) {
+ RunAddEdgesTest<BV2>();
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc
new file mode 100644
index 000000000000..e08a38c82450
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -0,0 +1,229 @@
+//===-- sanitizer_common_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+static bool IsSorted(const uptr *array, uptr n) {
+ for (uptr i = 1; i < n; i++) {
+ if (array[i] < array[i - 1]) return false;
+ }
+ return true;
+}
+
+TEST(SanitizerCommon, SortTest) {
+ uptr array[100];
+ uptr n = 100;
+ // Already sorted.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = i;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // Reverse order.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = n - 1 - i;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // Mixed order.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = (i % 2 == 0) ? i : n - 1 - i;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // All equal.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = 42;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // All but one sorted.
+ for (uptr i = 0; i < n - 1; i++) {
+ array[i] = i;
+ }
+ array[n - 1] = 42;
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // Minimal case - sort three elements.
+ array[0] = 1;
+ array[1] = 0;
+ SortArray(array, 2);
+ EXPECT_TRUE(IsSorted(array, 2));
+}
+
+TEST(SanitizerCommon, MmapAlignedOrDie) {
+ uptr PageSize = GetPageSizeCached();
+ for (uptr size = 1; size <= 32; size *= 2) {
+ for (uptr alignment = 1; alignment <= 32; alignment *= 2) {
+ for (int iter = 0; iter < 100; iter++) {
+ uptr res = (uptr)MmapAlignedOrDie(
+ size * PageSize, alignment * PageSize, "MmapAlignedOrDieTest");
+ EXPECT_EQ(0U, res % (alignment * PageSize));
+ internal_memset((void*)res, 1, size * PageSize);
+ UnmapOrDie((void*)res, size * PageSize);
+ }
+ }
+ }
+}
+
+#if SANITIZER_LINUX
+TEST(SanitizerCommon, SanitizerSetThreadName) {
+ const char *names[] = {
+ "0123456789012",
+ "01234567890123",
+ "012345678901234", // Larger names will be truncated on linux.
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
+ EXPECT_TRUE(SanitizerSetThreadName(names[i]));
+ char buff[100];
+ EXPECT_TRUE(SanitizerGetThreadName(buff, sizeof(buff) - 1));
+ EXPECT_EQ(0, internal_strcmp(buff, names[i]));
+ }
+}
+#endif
+
+TEST(SanitizerCommon, InternalMmapVector) {
+ InternalMmapVector<uptr> vector(1);
+ for (uptr i = 0; i < 100; i++) {
+ EXPECT_EQ(i, vector.size());
+ vector.push_back(i);
+ }
+ for (uptr i = 0; i < 100; i++) {
+ EXPECT_EQ(i, vector[i]);
+ }
+ for (int i = 99; i >= 0; i--) {
+ EXPECT_EQ((uptr)i, vector.back());
+ vector.pop_back();
+ EXPECT_EQ((uptr)i, vector.size());
+ }
+ InternalMmapVector<uptr> empty_vector(0);
+ CHECK_GT(empty_vector.capacity(), 0U);
+ CHECK_EQ(0U, empty_vector.size());
+}
+
+void TestThreadInfo(bool main) {
+ uptr stk_addr = 0;
+ uptr stk_size = 0;
+ uptr tls_addr = 0;
+ uptr tls_size = 0;
+ GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
+
+ int stack_var;
+ EXPECT_NE(stk_addr, (uptr)0);
+ EXPECT_NE(stk_size, (uptr)0);
+ EXPECT_GT((uptr)&stack_var, stk_addr);
+ EXPECT_LT((uptr)&stack_var, stk_addr + stk_size);
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+ static __thread int thread_var;
+ EXPECT_NE(tls_addr, (uptr)0);
+ EXPECT_NE(tls_size, (uptr)0);
+ EXPECT_GT((uptr)&thread_var, tls_addr);
+ EXPECT_LT((uptr)&thread_var, tls_addr + tls_size);
+
+ // Ensure that tls and stack do not intersect.
+ uptr tls_end = tls_addr + tls_size;
+ EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
+ EXPECT_TRUE(tls_end < stk_addr || tls_end >= stk_addr + stk_size);
+ EXPECT_TRUE((tls_addr < stk_addr) == (tls_end < stk_addr));
+#endif
+}
+
+static void *WorkerThread(void *arg) {
+ TestThreadInfo(false);
+ return 0;
+}
+
+TEST(SanitizerCommon, ThreadStackTlsMain) {
+ InitTlsSize();
+ TestThreadInfo(true);
+}
+
+TEST(SanitizerCommon, ThreadStackTlsWorker) {
+ InitTlsSize();
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, WorkerThread, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+bool UptrLess(uptr a, uptr b) {
+ return a < b;
+}
+
+TEST(SanitizerCommon, InternalBinarySearch) {
+ static const uptr kSize = 5;
+ uptr arr[kSize];
+ for (uptr i = 0; i < kSize; i++) arr[i] = i * i;
+
+ for (uptr i = 0; i < kSize; i++)
+ ASSERT_EQ(InternalBinarySearch(arr, 0, kSize, i * i, UptrLess), i);
+
+ ASSERT_EQ(InternalBinarySearch(arr, 0, kSize, 7, UptrLess), kSize + 1);
+}
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+TEST(SanitizerCommon, FindPathToBinary) {
+ char *true_path = FindPathToBinary("true");
+ EXPECT_NE((char*)0, internal_strstr(true_path, "/bin/true"));
+ InternalFree(true_path);
+ EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj"));
+}
+#endif
+
+TEST(SanitizerCommon, StripPathPrefix) {
+ EXPECT_EQ(0, StripPathPrefix(0, "prefix"));
+ EXPECT_STREQ("foo", StripPathPrefix("foo", 0));
+ EXPECT_STREQ("dir/file.cc",
+ StripPathPrefix("/usr/lib/dir/file.cc", "/usr/lib/"));
+ EXPECT_STREQ("/file.cc", StripPathPrefix("/usr/myroot/file.cc", "/myroot"));
+ EXPECT_STREQ("file.h", StripPathPrefix("/usr/lib/./file.h", "/usr/lib/"));
+}
+
+TEST(SanitizerCommon, InternalScopedString) {
+ InternalScopedString str(10);
+ EXPECT_EQ(0U, str.length());
+ EXPECT_STREQ("", str.data());
+
+ str.append("foo");
+ EXPECT_EQ(3U, str.length());
+ EXPECT_STREQ("foo", str.data());
+
+ int x = 1234;
+ str.append("%d", x);
+ EXPECT_EQ(7U, str.length());
+ EXPECT_STREQ("foo1234", str.data());
+
+ str.append("%d", x);
+ EXPECT_EQ(9U, str.length());
+ EXPECT_STREQ("foo123412", str.data());
+
+ str.clear();
+ EXPECT_EQ(0U, str.length());
+ EXPECT_STREQ("", str.data());
+
+ str.append("0123456789");
+ EXPECT_EQ(9U, str.length());
+ EXPECT_STREQ("012345678", str.data());
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
new file mode 100644
index 000000000000..7835eef76d06
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
@@ -0,0 +1,496 @@
+//===-- sanitizer_deadlock_detector_test.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 Sanitizer runtime.
+// Tests for sanitizer_deadlock_detector.h
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_deadlock_detector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+// Poor man's unique_ptr.
+template<class BV>
+struct ScopedDD {
+ ScopedDD() {
+ dp = new DeadlockDetector<BV>;
+ dp->clear();
+ dtls.clear();
+ }
+ ~ScopedDD() { delete dp; }
+ DeadlockDetector<BV> *dp;
+ DeadlockDetectorTLS<BV> dtls;
+};
+
+template <class BV>
+void RunBasicTest() {
+ uptr path[10];
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ set<uptr> s;
+ for (size_t i = 0; i < d.size() * 3; i++) {
+ uptr node = d.newNode(0);
+ EXPECT_TRUE(s.insert(node).second);
+ }
+
+ d.clear();
+ s.clear();
+ // Add size() nodes.
+ for (size_t i = 0; i < d.size(); i++) {
+ uptr node = d.newNode(0);
+ EXPECT_TRUE(s.insert(node).second);
+ }
+ // Remove all nodes.
+ for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it)
+ d.removeNode(*it);
+ // The nodes should be reused.
+ for (size_t i = 0; i < d.size(); i++) {
+ uptr node = d.newNode(0);
+ EXPECT_FALSE(s.insert(node).second);
+ }
+
+ // Cycle: n1->n2->n1
+ {
+ d.clear();
+ dtls.clear();
+ uptr n1 = d.newNode(1);
+ uptr n2 = d.newNode(2);
+ EXPECT_FALSE(d.onLock(&dtls, n1));
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ d.onUnlock(&dtls, n2);
+ d.onUnlock(&dtls, n1);
+
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 1));
+ EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 10));
+ EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 2));
+ EXPECT_TRUE(d.onLock(&dtls, n1));
+ EXPECT_EQ(path[0], n1);
+ EXPECT_EQ(path[1], n2);
+ EXPECT_EQ(d.getData(n1), 1U);
+ EXPECT_EQ(d.getData(n2), 2U);
+ d.onUnlock(&dtls, n1);
+ d.onUnlock(&dtls, n2);
+ }
+
+ // Cycle: n1->n2->n3->n1
+ {
+ d.clear();
+ dtls.clear();
+ uptr n1 = d.newNode(1);
+ uptr n2 = d.newNode(2);
+ uptr n3 = d.newNode(3);
+
+ EXPECT_FALSE(d.onLock(&dtls, n1));
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ d.onUnlock(&dtls, n2);
+ d.onUnlock(&dtls, n1);
+
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ EXPECT_FALSE(d.onLock(&dtls, n3));
+ d.onUnlock(&dtls, n3);
+ d.onUnlock(&dtls, n2);
+
+ EXPECT_FALSE(d.onLock(&dtls, n3));
+ EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 2));
+ EXPECT_EQ(3U, d.findPathToLock(&dtls, n1, path, 10));
+ EXPECT_TRUE(d.onLock(&dtls, n1));
+ EXPECT_EQ(path[0], n1);
+ EXPECT_EQ(path[1], n2);
+ EXPECT_EQ(path[2], n3);
+ EXPECT_EQ(d.getData(n1), 1U);
+ EXPECT_EQ(d.getData(n2), 2U);
+ EXPECT_EQ(d.getData(n3), 3U);
+ d.onUnlock(&dtls, n1);
+ d.onUnlock(&dtls, n3);
+ }
+}
+
+TEST(DeadlockDetector, BasicTest) {
+ RunBasicTest<BV1>();
+ RunBasicTest<BV2>();
+ RunBasicTest<BV3>();
+ RunBasicTest<BV4>();
+}
+
+template <class BV>
+void RunRemoveNodeTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(1);
+ uptr l2 = d.newNode(2);
+ uptr l3 = d.newNode(3);
+ uptr l4 = d.newNode(4);
+ uptr l5 = d.newNode(5);
+
+ // l0=>l1=>l2
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ d.onLock(&dtls, l2);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l2);
+ // l3=>l4=>l5
+ d.onLock(&dtls, l3);
+ d.onLock(&dtls, l4);
+ d.onLock(&dtls, l5);
+ d.onUnlock(&dtls, l4);
+ d.onUnlock(&dtls, l3);
+ d.onUnlock(&dtls, l5);
+
+ set<uptr> locks;
+ locks.insert(l0);
+ locks.insert(l1);
+ locks.insert(l2);
+ locks.insert(l3);
+ locks.insert(l4);
+ locks.insert(l5);
+ for (uptr i = 6; i < d.size(); i++) {
+ uptr lt = d.newNode(i);
+ locks.insert(lt);
+ d.onLock(&dtls, lt);
+ d.onUnlock(&dtls, lt);
+ d.removeNode(lt);
+ }
+ EXPECT_EQ(locks.size(), d.size());
+ // l2=>l0
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ EXPECT_TRUE(d.onLock(&dtls, l0));
+ d.onUnlock(&dtls, l2);
+ d.onUnlock(&dtls, l0);
+ // l4=>l3
+ EXPECT_FALSE(d.onLock(&dtls, l4));
+ EXPECT_TRUE(d.onLock(&dtls, l3));
+ d.onUnlock(&dtls, l4);
+ d.onUnlock(&dtls, l3);
+
+ EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+
+ d.removeNode(l2);
+ d.removeNode(l3);
+ locks.clear();
+ // make sure no edges from or to l0,l1,l4,l5 left.
+ for (uptr i = 4; i < d.size(); i++) {
+ uptr lt = d.newNode(i);
+ locks.insert(lt);
+ uptr a, b;
+ // l0 => lt?
+ a = l0; b = lt;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // l1 => lt?
+ a = l1; b = lt;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // lt => l4?
+ a = lt; b = l4;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // lt => l5?
+ a = lt; b = l5;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+
+ d.removeNode(lt);
+ }
+ // Still the same epoch.
+ EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+ EXPECT_EQ(locks.size(), d.size() - 4);
+ // l2 and l3 should have ben reused.
+ EXPECT_EQ(locks.count(l2), 1U);
+ EXPECT_EQ(locks.count(l3), 1U);
+}
+
+TEST(DeadlockDetector, RemoveNodeTest) {
+ RunRemoveNodeTest<BV1>();
+ RunRemoveNodeTest<BV2>();
+ RunRemoveNodeTest<BV3>();
+ RunRemoveNodeTest<BV4>();
+}
+
+template <class BV>
+void RunMultipleEpochsTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ set<uptr> locks;
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ }
+ locks.clear();
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), 3 * d.size());
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
+
+#if !SANITIZER_DEBUG
+ // EXPECT_DEATH clones a thread with 4K stack,
+ // which is overflown by tsan memory accesses functions in debug mode.
+
+ // Can not handle the locks from the previous epoch.
+ // The caller should update the lock id.
+ EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
+#endif
+}
+
+TEST(DeadlockDetector, MultipleEpochsTest) {
+ RunMultipleEpochsTest<BV1>();
+ RunMultipleEpochsTest<BV2>();
+ RunMultipleEpochsTest<BV3>();
+ RunMultipleEpochsTest<BV4>();
+}
+
+template <class BV>
+void RunCorrectEpochFlush() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ vector<uptr> locks1;
+ for (uptr i = 0; i < d.size(); i++)
+ locks1.push_back(d.newNode(i));
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ d.onLock(&dtls, locks1[3]);
+ d.onLock(&dtls, locks1[4]);
+ d.onLock(&dtls, locks1[5]);
+
+ // We have a new epoch, old locks in dtls will have to be forgotten.
+ uptr l0 = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ uptr l1 = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ EXPECT_TRUE(d.testOnlyHasEdgeRaw(0, 1));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(1, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(3, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(4, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(5, 0));
+}
+
+TEST(DeadlockDetector, CorrectEpochFlush) {
+ RunCorrectEpochFlush<BV1>();
+ RunCorrectEpochFlush<BV2>();
+}
+
+template <class BV>
+void RunTryLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ EXPECT_FALSE(d.onLock(&dtls, l0));
+ EXPECT_FALSE(d.onTryLock(&dtls, l1));
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ EXPECT_TRUE(d.isHeld(&dtls, l0));
+ EXPECT_TRUE(d.isHeld(&dtls, l1));
+ EXPECT_TRUE(d.isHeld(&dtls, l2));
+ EXPECT_FALSE(d.testOnlyHasEdge(l0, l1));
+ EXPECT_TRUE(d.testOnlyHasEdge(l1, l2));
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l2);
+}
+
+TEST(DeadlockDetector, TryLockTest) {
+ RunTryLockTest<BV1>();
+ RunTryLockTest<BV2>();
+}
+
+template <class BV>
+void RunOnFirstLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // dtls has old epoch.
+ d.onLock(&dtls, l0);
+ d.onUnlock(&dtls, l0);
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok, same ecpoch, first lock.
+ EXPECT_FALSE(d.onFirstLock(&dtls, l1)); // Second lock.
+ d.onLock(&dtls, l1);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok
+ d.onUnlock(&dtls, l0);
+
+ vector<uptr> locks1;
+ for (uptr i = 0; i < d.size(); i++)
+ locks1.push_back(d.newNode(i));
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Epoch has changed, but not in dtls.
+
+ uptr l3 = d.newNode(0);
+ d.onLock(&dtls, l3);
+ d.onUnlock(&dtls, l3);
+
+ EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // Epoch has changed in dtls.
+}
+
+TEST(DeadlockDetector, onFirstLockTest) {
+ RunOnFirstLockTest<BV2>();
+}
+
+template <class BV>
+void RunRecusriveLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ uptr l3 = d.newNode(0);
+
+ EXPECT_FALSE(d.onLock(&dtls, l0));
+ EXPECT_FALSE(d.onLock(&dtls, l1));
+ EXPECT_FALSE(d.onLock(&dtls, l0)); // Recurisve.
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ d.onUnlock(&dtls, l0);
+ EXPECT_FALSE(d.onLock(&dtls, l3));
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l2);
+ d.onUnlock(&dtls, l3);
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l1));
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l2));
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l3));
+}
+
+TEST(DeadlockDetector, RecusriveLockTest) {
+ RunRecusriveLockTest<BV2>();
+}
+
+template <class BV>
+void RunLockContextTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ uptr l3 = d.newNode(0);
+ uptr l4 = d.newNode(0);
+ EXPECT_FALSE(d.onLock(&dtls, l0, 10));
+ EXPECT_FALSE(d.onLock(&dtls, l1, 11));
+ EXPECT_FALSE(d.onLock(&dtls, l2, 12));
+ EXPECT_FALSE(d.onLock(&dtls, l3, 13));
+ EXPECT_EQ(10U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+ d.onUnlock(&dtls, l0);
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+ d.onUnlock(&dtls, l2);
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+
+ EXPECT_FALSE(d.onLock(&dtls, l4, 14));
+ EXPECT_EQ(14U, d.findLockContext(&dtls, l4));
+}
+
+TEST(DeadlockDetector, LockContextTest) {
+ RunLockContextTest<BV2>();
+}
+
+template <class BV>
+void RunRemoveEdgesTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ vector<uptr> node(BV::kSize);
+ u32 stk_from = 0, stk_to = 0;
+ int unique_tid = 0;
+ for (size_t i = 0; i < BV::kSize; i++)
+ node[i] = d.newNode(0);
+
+ for (size_t i = 0; i < BV::kSize; i++)
+ EXPECT_FALSE(d.onLock(&dtls, node[i], i + 1));
+ for (size_t i = 0; i < BV::kSize; i++) {
+ for (uptr j = i + 1; j < BV::kSize; j++) {
+ EXPECT_TRUE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ EXPECT_EQ(stk_from, i + 1);
+ EXPECT_EQ(stk_to, j + 1);
+ }
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ // Remove and re-create half of the nodes.
+ for (uptr i = 1; i < BV::kSize; i += 2)
+ d.removeNode(node[i]);
+ for (uptr i = 1; i < BV::kSize; i += 2)
+ node[i] = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ // The edges from or to the removed nodes should be gone.
+ for (size_t i = 0; i < BV::kSize; i++) {
+ for (uptr j = i + 1; j < BV::kSize; j++) {
+ if ((i % 2) || (j % 2))
+ EXPECT_FALSE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ else
+ EXPECT_TRUE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ }
+ }
+}
+
+TEST(DeadlockDetector, RemoveEdgesTest) {
+ RunRemoveEdgesTest<BV1>();
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc
new file mode 100644
index 000000000000..3e5d8381ed3a
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -0,0 +1,142 @@
+//===-- sanitizer_flags_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace __sanitizer {
+
+static const char kFlagName[] = "flag_name";
+static const char kFlagDesc[] = "flag description";
+
+template <typename T>
+static void TestFlag(T start_value, const char *env, T final_value) {
+ T flag = start_value;
+
+ FlagParser parser;
+ RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
+
+ parser.ParseString(env);
+
+ EXPECT_EQ(final_value, flag);
+}
+
+template <>
+void TestFlag(const char *start_value, const char *env,
+ const char *final_value) {
+ const char *flag = start_value;
+
+ FlagParser parser;
+ RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
+
+ parser.ParseString(env);
+
+ EXPECT_EQ(0, internal_strcmp(final_value, flag));
+}
+
+TEST(SanitizerCommon, BooleanFlags) {
+ TestFlag(false, "flag_name=1", true);
+ TestFlag(false, "flag_name=yes", true);
+ TestFlag(false, "flag_name=true", true);
+ TestFlag(true, "flag_name=0", false);
+ TestFlag(true, "flag_name=no", false);
+ TestFlag(true, "flag_name=false", false);
+}
+
+TEST(SanitizerCommon, IntFlags) {
+ TestFlag(-11, 0, -11);
+ TestFlag(-11, "flag_name=0", 0);
+ TestFlag(-11, "flag_name=42", 42);
+ TestFlag(-11, "flag_name=-42", -42);
+
+ // Unrecognized flags are ignored.
+ TestFlag(-11, "--flag_name=42", -11);
+ TestFlag(-11, "zzzzzzz=42", -11);
+
+ EXPECT_DEATH(TestFlag(-11, "flag_name", 0), "expected '='");
+ EXPECT_DEATH(TestFlag(-11, "flag_name=42U", 0),
+ "Invalid value for int option");
+}
+
+TEST(SanitizerCommon, StrFlags) {
+ TestFlag("zzz", 0, "zzz");
+ TestFlag("zzz", "flag_name=", "");
+ TestFlag("zzz", "flag_name=abc", "abc");
+ TestFlag("", "flag_name=abc", "abc");
+ TestFlag("", "flag_name='abc zxc'", "abc zxc");
+ // TestStrFlag("", "flag_name=\"abc qwe\" asd", "abc qwe");
+}
+
+static void TestTwoFlags(const char *env, bool expected_flag1,
+ const char *expected_flag2,
+ const char *name1 = "flag1",
+ const char *name2 = "flag2") {
+ bool flag1 = !expected_flag1;
+ const char *flag2 = "";
+
+ FlagParser parser;
+ RegisterFlag(&parser, name1, kFlagDesc, &flag1);
+ RegisterFlag(&parser, name2, kFlagDesc, &flag2);
+
+ parser.ParseString(env);
+
+ EXPECT_EQ(expected_flag1, flag1);
+ EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
+}
+
+TEST(SanitizerCommon, MultipleFlags) {
+ TestTwoFlags("flag1=1 flag2='zzz'", true, "zzz");
+ TestTwoFlags("flag2='qxx' flag1=0", false, "qxx");
+ TestTwoFlags("flag1=false:flag2='zzz'", false, "zzz");
+ TestTwoFlags("flag2=qxx:flag1=yes", true, "qxx");
+ TestTwoFlags("flag2=qxx\nflag1=yes", true, "qxx");
+ TestTwoFlags("flag2=qxx\r\nflag1=yes", true, "qxx");
+ TestTwoFlags("flag2=qxx\tflag1=yes", true, "qxx");
+}
+
+TEST(SanitizerCommon, CommonSuffixFlags) {
+ TestTwoFlags("flag=1 other_flag='zzz'", true, "zzz", "flag", "other_flag");
+ TestTwoFlags("other_flag='zzz' flag=1", true, "zzz", "flag", "other_flag");
+ TestTwoFlags("other_flag=' flag=0 ' flag=1", true, " flag=0 ", "flag",
+ "other_flag");
+ TestTwoFlags("flag=1 other_flag=' flag=0 '", true, " flag=0 ", "flag",
+ "other_flag");
+}
+
+TEST(SanitizerCommon, CommonFlags) {
+ CommonFlags cf;
+ FlagParser parser;
+ RegisterCommonFlags(&parser, &cf);
+
+ cf.SetDefaults();
+ EXPECT_TRUE(cf.symbolize);
+ EXPECT_STREQ(".", cf.coverage_dir);
+
+ cf.symbolize = false;
+ cf.coverage = true;
+ cf.coverage_direct = true;
+ cf.log_path = "path/one";
+
+ parser.ParseString("symbolize=1:coverage_direct=false log_path='path/two'");
+ EXPECT_TRUE(cf.symbolize);
+ EXPECT_TRUE(cf.coverage);
+ EXPECT_FALSE(cf.coverage_direct);
+ EXPECT_STREQ("path/two", cf.log_path);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
new file mode 100644
index 000000000000..13918aff1009
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
@@ -0,0 +1,259 @@
+//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for *scanf interceptors implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size) \
+ do { \
+ ((std::vector<unsigned> *)ctx)->push_back(size); \
+ ptr = ptr; \
+ } while (0)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define SANITIZER_INTERCEPT_PRINTF 1
+#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
+
+static const unsigned I = sizeof(int);
+static const unsigned L = sizeof(long);
+static const unsigned LL = sizeof(long long);
+static const unsigned S = sizeof(short);
+static const unsigned C = sizeof(char);
+static const unsigned LC = sizeof(wchar_t);
+static const unsigned D = sizeof(double);
+static const unsigned LD = sizeof(long double);
+static const unsigned F = sizeof(float);
+static const unsigned P = sizeof(char *);
+
+static void verifyFormatResults(const char *format, unsigned n,
+ const std::vector<unsigned> &computed_sizes,
+ va_list expected_sizes) {
+ // "+ 1" because of format string
+ ASSERT_EQ(n + 1,
+ computed_sizes.size()) << "Unexpected number of format arguments: '"
+ << format << "'";
+ for (unsigned i = 0; i < n; ++i)
+ EXPECT_EQ(va_arg(expected_sizes, unsigned), computed_sizes[i + 1])
+ << "Unexpect write size for argument " << i << ", format string '"
+ << format << "'";
+}
+
+static const char test_buf[] = "Test string.";
+static const size_t test_buf_size = sizeof(test_buf);
+
+static const unsigned SCANF_ARGS_MAX = 16;
+
+static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
+ const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ scanf_common(ctx, result, allowGnuMalloc, format, ap);
+ va_end(ap);
+}
+
+static void testScanf2(const char *format, int scanf_result,
+ bool allowGnuMalloc, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> scanf_sizes;
+ // 16 args should be enough.
+ testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, scanf_sizes, expected_sizes);
+}
+
+static void testScanf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
+ va_end(ap);
+}
+
+static void testScanfPartial(const char *format, int scanf_result, unsigned n,
+ ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, scanf_result, /* allowGnuMalloc */ true, n, ap);
+ va_end(ap);
+}
+
+static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Scanf) {
+ testScanf("%d", 1, I);
+ testScanf("%d%d%d", 3, I, I, I);
+ testScanf("ab%u%dc", 2, I, I);
+ testScanf("%ld", 1, L);
+ testScanf("%llu", 1, LL);
+ testScanf("%qd", 1, LL);
+ testScanf("a %hd%hhx", 2, S, C);
+ testScanf("%c", 1, C);
+ testScanf("%lc", 1, LC);
+
+ testScanf("%%", 0);
+ testScanf("a%%", 0);
+ testScanf("a%%b", 0);
+ testScanf("a%%%%b", 0);
+ testScanf("a%%b%%", 0);
+ testScanf("a%%%%%%b", 0);
+ testScanf("a%%%%%b", 0);
+ testScanf("a%%%%%f", 1, F);
+ testScanf("a%%%lxb", 1, L);
+ testScanf("a%lf%%%lxb", 2, D, L);
+ testScanf("%nf", 1, I);
+
+ testScanf("%10s", 1, 11);
+ testScanf("%10c", 1, 10);
+ testScanf("%10ls", 1, 11 * LC);
+ testScanf("%10lc", 1, 10 * LC);
+ testScanf("%%10s", 0);
+ testScanf("%*10s", 0);
+ testScanf("%*d", 0);
+
+ testScanf("%4d%8f%c", 3, I, F, C);
+ testScanf("%s%d", 2, test_buf_size, I);
+ testScanf("%[abc]", 1, test_buf_size);
+ testScanf("%4[bcdef]", 1, 5);
+ testScanf("%[]]", 1, test_buf_size);
+ testScanf("%8[^]%d0-9-]%c", 2, 9, C);
+
+ testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
+
+ testScanf("%*d%u", 1, I);
+
+ testScanf("%c%d", 2, C, I);
+ testScanf("%A%lf", 2, F, D);
+
+ testScanf("%ms %Lf", 2, P, LD);
+ testScanf("s%Las", 1, LD);
+ testScanf("%ar", 1, F);
+
+ // In the cases with std::min below the format spec can be interpreted as
+ // either floating-something, or (GNU extension) callee-allocated string.
+ // Our conservative implementation reports one of the two possibilities with
+ // the least store range.
+ testScanf("%a[", 0);
+ testScanf("%a[]", 0);
+ testScanf("%a[]]", 1, std::min(F, P));
+ testScanf("%a[abc]", 1, std::min(F, P));
+ testScanf("%a[^abc]", 1, std::min(F, P));
+ testScanf("%a[ab%c] %d", 0);
+ testScanf("%a[^ab%c] %d", 0);
+ testScanf("%as", 1, std::min(F, P));
+ testScanf("%aS", 1, std::min(F, P));
+ testScanf("%a13S", 1, std::min(F, P));
+ testScanf("%alS", 1, std::min(F, P));
+
+ testScanfNoGnuMalloc("s%Las", 1, LD);
+ testScanfNoGnuMalloc("%ar", 1, F);
+ testScanfNoGnuMalloc("%a[", 1, F);
+ testScanfNoGnuMalloc("%a[]", 1, F);
+ testScanfNoGnuMalloc("%a[]]", 1, F);
+ testScanfNoGnuMalloc("%a[abc]", 1, F);
+ testScanfNoGnuMalloc("%a[^abc]", 1, F);
+ testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
+ testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
+ testScanfNoGnuMalloc("%as", 1, F);
+ testScanfNoGnuMalloc("%aS", 1, F);
+ testScanfNoGnuMalloc("%a13S", 1, F);
+ testScanfNoGnuMalloc("%alS", 1, F);
+
+ testScanf("%5$d", 0);
+ testScanf("%md", 0);
+ testScanf("%m10s", 0);
+
+ testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
+ testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
+ testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
+ testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
+
+ testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
+ testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
+
+ testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, test_buf_size);
+ testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
+ test_buf_size);
+}
+
+static void testPrintf3(void *ctx, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ printf_common(ctx, format, ap);
+ va_end(ap);
+}
+
+static void testPrintf2(const char *format, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> printf_sizes;
+ // 16 args should be enough.
+ testPrintf3((void *)&printf_sizes, format,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, printf_sizes, expected_sizes);
+}
+
+static void testPrintf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testPrintf2(format, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Printf) {
+ // Only test functionality which differs from scanf
+
+ // Indexed arguments
+ testPrintf("%5$d", 0);
+ testPrintf("%.*5$d", 0);
+
+ // errno
+ testPrintf("%0-m", 0);
+
+ // Dynamic width
+ testPrintf("%*n", 1, I);
+ testPrintf("%*.10n", 1, I);
+
+ // Precision
+ testPrintf("%10.10n", 1, I);
+ testPrintf("%.3s", 1, 3);
+ testPrintf("%.20s", 1, test_buf_size);
+
+ // Dynamic precision
+ testPrintf("%.*n", 1, I);
+ testPrintf("%10.*n", 1, I);
+
+ // Dynamic precision for strings is not implemented yet.
+ testPrintf("%.*s", 1, 0);
+
+ // Checks for wide-character strings are not implemented yet.
+ testPrintf("%ls", 1, 0);
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
new file mode 100644
index 000000000000..22fa5228dfbd
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
@@ -0,0 +1,103 @@
+//===-- sanitizer_ioctl_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for ioctl interceptor implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include <linux/input.h>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, sz) \
+ do { \
+ (void) ctx; \
+ (void) ptr; \
+ (void) sz; \
+ } while (0)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sz) \
+ do { \
+ (void) ctx; \
+ (void) ptr; \
+ (void) sz; \
+ } while (0)
+
+#include "sanitizer_common/sanitizer_common_interceptors_ioctl.inc"
+
+static struct IoctlInit {
+ IoctlInit() {
+ ioctl_init();
+ // Avoid unused function warnings.
+ (void)&ioctl_common_pre;
+ (void)&ioctl_common_post;
+ (void)&ioctl_decode;
+ }
+} ioctl_static_initializer;
+
+TEST(SanitizerIoctl, Fixup) {
+ EXPECT_EQ((unsigned)FIONBIO, ioctl_request_fixup(FIONBIO));
+
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(0, 16)));
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 16)));
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 17)));
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(31, 16)));
+ EXPECT_NE(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(32, 16)));
+
+ EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(0)));
+ EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(5)));
+ EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(63)));
+ EXPECT_NE(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(64)));
+
+ EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(0)));
+ EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(5)));
+ EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(63)));
+ EXPECT_NE(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(64)));
+
+ const ioctl_desc *desc = ioctl_lookup(EVIOCGKEY(16));
+ EXPECT_NE((void *)0, desc);
+ EXPECT_EQ(EVIOCGKEY(0), desc->req);
+}
+
+// Test decoding KVM ioctl numbers.
+TEST(SanitizerIoctl, KVM_GET_MP_STATE) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0x8004ae98U, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::WRITE, desc.type);
+ EXPECT_EQ(4U, desc.size);
+}
+
+TEST(SanitizerIoctl, KVM_GET_LAPIC) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0x8400ae8eU, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::WRITE, desc.type);
+ EXPECT_EQ(1024U, desc.size);
+}
+
+TEST(SanitizerIoctl, KVM_GET_MSR_INDEX_LIST) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0xc004ae02U, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::READWRITE, desc.type);
+ EXPECT_EQ(4U, desc.size);
+}
+
+#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc
new file mode 100644
index 000000000000..8712d2c1b2a5
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -0,0 +1,161 @@
+//===-- sanitizer_libc_test.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Tests for sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_platform.h"
+#include "gtest/gtest.h"
+
+#if SANITIZER_LINUX || SANITIZER_MAC
+# define SANITIZER_TEST_HAS_STAT_H 1
+# include <sys/stat.h>
+#else
+# define SANITIZER_TEST_HAS_STAT_H 0
+#endif
+
+// A regression test for internal_memmove() implementation.
+TEST(SanitizerCommon, InternalMemmoveRegression) {
+ char src[] = "Hello World";
+ char *dest = src + 6;
+ __sanitizer::internal_memmove(dest, src, 5);
+ EXPECT_EQ(dest[0], src[0]);
+ EXPECT_EQ(dest[4], src[4]);
+}
+
+TEST(SanitizerCommon, mem_is_zero) {
+ size_t size = 128;
+ char *x = new char[size];
+ memset(x, 0, size);
+ for (size_t pos = 0; pos < size; pos++) {
+ x[pos] = 1;
+ for (size_t beg = 0; beg < size; beg++) {
+ for (size_t end = beg; end < size; end++) {
+ // fprintf(stderr, "pos %zd beg %zd end %zd \n", pos, beg, end);
+ if (beg <= pos && pos < end)
+ EXPECT_FALSE(__sanitizer::mem_is_zero(x + beg, end - beg));
+ else
+ EXPECT_TRUE(__sanitizer::mem_is_zero(x + beg, end - beg));
+ }
+ }
+ x[pos] = 0;
+ }
+ delete [] x;
+}
+
+struct stat_and_more {
+ struct stat st;
+ unsigned char z;
+};
+
+static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {
+ const char *tmpdir = "/tmp";
+#if SANITIZER_ANDROID
+ // I don't know a way to query temp directory location on Android without
+ // going through Java interfaces. The code below is not ideal, but should
+ // work. May require "adb root", but it is needed for almost any use of ASan
+ // on Android already.
+ tmpdir = GetEnv("EXTERNAL_STORAGE");
+#endif
+ u32 uid = GetUid();
+ internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid);
+}
+
+// FIXME: File manipulations are not yet supported on Windows
+#if !defined(_WIN32)
+TEST(SanitizerCommon, FileOps) {
+ const char *str1 = "qwerty";
+ uptr len1 = internal_strlen(str1);
+ const char *str2 = "zxcv";
+ uptr len2 = internal_strlen(str2);
+
+ char tmpfile[128];
+ temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
+ uptr openrv = OpenFile(tmpfile, true);
+ EXPECT_FALSE(internal_iserror(openrv));
+ fd_t fd = openrv;
+ EXPECT_EQ(len1, internal_write(fd, str1, len1));
+ EXPECT_EQ(len2, internal_write(fd, str2, len2));
+ internal_close(fd);
+
+ openrv = OpenFile(tmpfile, false);
+ EXPECT_FALSE(internal_iserror(openrv));
+ fd = openrv;
+ uptr fsize = internal_filesize(fd);
+ EXPECT_EQ(len1 + len2, fsize);
+
+#if SANITIZER_TEST_HAS_STAT_H
+ struct stat st1, st2, st3;
+ EXPECT_EQ(0u, internal_stat(tmpfile, &st1));
+ EXPECT_EQ(0u, internal_lstat(tmpfile, &st2));
+ EXPECT_EQ(0u, internal_fstat(fd, &st3));
+ EXPECT_EQ(fsize, (uptr)st3.st_size);
+
+ // Verify that internal_fstat does not write beyond the end of the supplied
+ // buffer.
+ struct stat_and_more sam;
+ memset(&sam, 0xAB, sizeof(sam));
+ EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
+ EXPECT_EQ(0xAB, sam.z);
+ EXPECT_NE(0xAB, sam.st.st_size);
+ EXPECT_NE(0, sam.st.st_size);
+#endif
+
+ char buf[64] = {};
+ EXPECT_EQ(len1, internal_read(fd, buf, len1));
+ EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
+ EXPECT_EQ((char)0, buf[len1 + 1]);
+ internal_memset(buf, 0, len1);
+ EXPECT_EQ(len2, internal_read(fd, buf, len2));
+ EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
+ internal_close(fd);
+ internal_unlink(tmpfile);
+}
+#endif
+
+TEST(SanitizerCommon, InternalStrFunctions) {
+ const char *haystack = "haystack";
+ EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
+ EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
+ EXPECT_EQ(0, internal_strchr(haystack, 'z'));
+ EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z'));
+}
+
+// FIXME: File manipulations are not yet supported on Windows
+#if !defined(_WIN32) && !SANITIZER_MAC
+TEST(SanitizerCommon, InternalMmapWithOffset) {
+ char tmpfile[128];
+ temp_file_name(tmpfile, sizeof(tmpfile),
+ "sanitizer_common.internalmmapwithoffset.tmp.");
+ uptr res = OpenFile(tmpfile, true);
+ ASSERT_FALSE(internal_iserror(res));
+ fd_t fd = res;
+
+ uptr page_size = GetPageSizeCached();
+ res = internal_ftruncate(fd, page_size * 2);
+ ASSERT_FALSE(internal_iserror(res));
+
+ res = internal_lseek(fd, page_size, SEEK_SET);
+ ASSERT_FALSE(internal_iserror(res));
+
+ res = internal_write(fd, "AB", 2);
+ ASSERT_FALSE(internal_iserror(res));
+
+ char *p = (char *)MapWritableFileToMemory(nullptr, page_size, fd, page_size);
+ ASSERT_NE(nullptr, p);
+
+ ASSERT_EQ('A', p[0]);
+ ASSERT_EQ('B', p[1]);
+
+ internal_close(fd);
+ internal_munmap(p, page_size);
+ internal_unlink(tmpfile);
+}
+#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
new file mode 100644
index 000000000000..11342b775cc7
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -0,0 +1,268 @@
+//===-- sanitizer_linux_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for sanitizer_linux.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_common/sanitizer_linux.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+#include <pthread.h>
+#include <sched.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <vector>
+
+namespace __sanitizer {
+
+struct TidReporterArgument {
+ TidReporterArgument() {
+ pthread_mutex_init(&terminate_thread_mutex, NULL);
+ pthread_mutex_init(&tid_reported_mutex, NULL);
+ pthread_cond_init(&terminate_thread_cond, NULL);
+ pthread_cond_init(&tid_reported_cond, NULL);
+ terminate_thread = false;
+ }
+
+ ~TidReporterArgument() {
+ pthread_mutex_destroy(&terminate_thread_mutex);
+ pthread_mutex_destroy(&tid_reported_mutex);
+ pthread_cond_destroy(&terminate_thread_cond);
+ pthread_cond_destroy(&tid_reported_cond);
+ }
+
+ pid_t reported_tid;
+ // For signaling to spawned threads that they should terminate.
+ pthread_cond_t terminate_thread_cond;
+ pthread_mutex_t terminate_thread_mutex;
+ bool terminate_thread;
+ // For signaling to main thread that a child thread has reported its tid.
+ pthread_cond_t tid_reported_cond;
+ pthread_mutex_t tid_reported_mutex;
+
+ private:
+ // Disallow evil constructors
+ TidReporterArgument(const TidReporterArgument &);
+ void operator=(const TidReporterArgument &);
+};
+
+class ThreadListerTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ pthread_t pthread_id;
+ pid_t tid;
+ for (uptr i = 0; i < kThreadCount; i++) {
+ SpawnTidReporter(&pthread_id, &tid);
+ pthread_ids_.push_back(pthread_id);
+ tids_.push_back(tid);
+ }
+ }
+
+ virtual void TearDown() {
+ pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
+ thread_arg.terminate_thread = true;
+ pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
+ pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
+ for (uptr i = 0; i < pthread_ids_.size(); i++)
+ pthread_join(pthread_ids_[i], NULL);
+ }
+
+ void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid);
+
+ static const uptr kThreadCount = 20;
+
+ std::vector<pthread_t> pthread_ids_;
+ std::vector<pid_t> tids_;
+
+ TidReporterArgument thread_arg;
+};
+
+// Writes its TID once to reported_tid and waits until signaled to terminate.
+void *TidReporterThread(void *argument) {
+ TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
+ pthread_mutex_lock(&arg->tid_reported_mutex);
+ arg->reported_tid = GetTid();
+ pthread_cond_broadcast(&arg->tid_reported_cond);
+ pthread_mutex_unlock(&arg->tid_reported_mutex);
+
+ pthread_mutex_lock(&arg->terminate_thread_mutex);
+ while (!arg->terminate_thread)
+ pthread_cond_wait(&arg->terminate_thread_cond,
+ &arg->terminate_thread_mutex);
+ pthread_mutex_unlock(&arg->terminate_thread_mutex);
+ return NULL;
+}
+
+void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id,
+ pid_t *tid) {
+ pthread_mutex_lock(&thread_arg.tid_reported_mutex);
+ thread_arg.reported_tid = -1;
+ ASSERT_EQ(0, pthread_create(pthread_id, NULL,
+ TidReporterThread,
+ &thread_arg));
+ while (thread_arg.reported_tid == -1)
+ pthread_cond_wait(&thread_arg.tid_reported_cond,
+ &thread_arg.tid_reported_mutex);
+ pthread_mutex_unlock(&thread_arg.tid_reported_mutex);
+ *tid = thread_arg.reported_tid;
+}
+
+static std::vector<pid_t> ReadTidsToVector(ThreadLister *thread_lister) {
+ std::vector<pid_t> listed_tids;
+ pid_t tid;
+ while ((tid = thread_lister->GetNextTID()) >= 0)
+ listed_tids.push_back(tid);
+ EXPECT_FALSE(thread_lister->error());
+ return listed_tids;
+}
+
+static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) {
+ std::sort(first.begin(), first.end());
+ std::sort(second.begin(), second.end());
+ return std::includes(first.begin(), first.end(),
+ second.begin(), second.end());
+}
+
+static bool HasElement(std::vector<pid_t> vector, pid_t element) {
+ return std::find(vector.begin(), vector.end(), element) != vector.end();
+}
+
+// ThreadLister's output should include the current thread's TID and the TID of
+// every thread we spawned.
+TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
+ pid_t self_tid = GetTid();
+ ThreadLister thread_lister(getpid());
+ std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
+ ASSERT_TRUE(HasElement(listed_tids, self_tid));
+ ASSERT_TRUE(Includes(listed_tids, tids_));
+}
+
+// Calling Reset() should not cause ThreadLister to forget any threads it's
+// supposed to know about.
+TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) {
+ ThreadLister thread_lister(getpid());
+
+ // Run the loop body twice, because Reset() might behave differently if called
+ // on a freshly created object.
+ for (uptr i = 0; i < 2; i++) {
+ thread_lister.Reset();
+ std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
+ ASSERT_TRUE(Includes(listed_tids, tids_));
+ }
+}
+
+// If new threads have spawned during ThreadLister object's lifetime, calling
+// Reset() should cause ThreadLister to recognize their existence.
+TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) {
+ ThreadLister thread_lister(getpid());
+ std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
+
+ pthread_t extra_pthread_id;
+ pid_t extra_tid;
+ SpawnTidReporter(&extra_pthread_id, &extra_tid);
+ // Register the new thread so it gets terminated in TearDown().
+ pthread_ids_.push_back(extra_pthread_id);
+
+ // It would be very bizarre if the new TID had been listed before we even
+ // spawned that thread, but it would also cause a false success in this test,
+ // so better check for that.
+ ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
+
+ thread_lister.Reset();
+
+ std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
+ ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
+}
+
+TEST(SanitizerCommon, SetEnvTest) {
+ const char kEnvName[] = "ENV_FOO";
+ SetEnv(kEnvName, "value");
+ EXPECT_STREQ("value", getenv(kEnvName));
+ unsetenv(kEnvName);
+ EXPECT_EQ(0, getenv(kEnvName));
+}
+
+#if defined(__x86_64__) || defined(__i386__)
+void *thread_self_offset_test_func(void *arg) {
+ bool result =
+ *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
+ return (void *)result;
+}
+
+TEST(SanitizerLinux, ThreadSelfOffset) {
+ EXPECT_TRUE((bool)thread_self_offset_test_func(0));
+ pthread_t tid;
+ void *result;
+ ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
+ ASSERT_EQ(0, pthread_join(tid, &result));
+ EXPECT_TRUE((bool)result);
+}
+
+// libpthread puts the thread descriptor at the end of stack space.
+void *thread_descriptor_size_test_func(void *arg) {
+ uptr descr_addr = ThreadSelf();
+ pthread_attr_t attr;
+ pthread_getattr_np(pthread_self(), &attr);
+ void *stackaddr;
+ size_t stacksize;
+ pthread_attr_getstack(&attr, &stackaddr, &stacksize);
+ return (void *)((uptr)stackaddr + stacksize - descr_addr);
+}
+
+TEST(SanitizerLinux, ThreadDescriptorSize) {
+ pthread_t tid;
+ void *result;
+ ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
+ ASSERT_EQ(0, pthread_join(tid, &result));
+ EXPECT_EQ((uptr)result, ThreadDescriptorSize());
+}
+#endif
+
+TEST(SanitizerCommon, LibraryNameIs) {
+ EXPECT_FALSE(LibraryNameIs("", ""));
+
+ char full_name[256];
+ const char *paths[] = { "", "/", "/path/to/" };
+ const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
+ const char *base_names[] = { "lib", "lib.0", "lib-i386" };
+ const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
+ for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
+ for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
+ for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
+ internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
+ paths[i], base_names[k], suffixes[j]);
+ EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
+ << "Full name " << full_name
+ << " doesn't match base name " << base_names[k];
+ for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
+ EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
+ << "Full name " << full_name
+ << " matches base name " << wrong_names[m];
+ }
+ }
+}
+
+#if defined(__mips64)
+// Effectively, this is a test for ThreadDescriptorSize() which is used to
+// compute ThreadSelf().
+TEST(SanitizerLinux, ThreadSelfTest) {
+ ASSERT_EQ(pthread_self(), ThreadSelf());
+}
+#endif
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc
new file mode 100644
index 000000000000..fbe53c0375c0
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc
@@ -0,0 +1,173 @@
+//===-- sanitizer_list_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_list.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+struct ListItem {
+ ListItem *next;
+};
+
+typedef IntrusiveList<ListItem> List;
+
+static List static_list;
+
+static void SetList(List *l, ListItem *x = 0,
+ ListItem *y = 0, ListItem *z = 0) {
+ l->clear();
+ if (x) l->push_back(x);
+ if (y) l->push_back(y);
+ if (z) l->push_back(z);
+}
+
+static void CheckList(List *l, ListItem *i1, ListItem *i2 = 0, ListItem *i3 = 0,
+ ListItem *i4 = 0, ListItem *i5 = 0, ListItem *i6 = 0) {
+ if (i1) {
+ CHECK_EQ(l->front(), i1);
+ l->pop_front();
+ }
+ if (i2) {
+ CHECK_EQ(l->front(), i2);
+ l->pop_front();
+ }
+ if (i3) {
+ CHECK_EQ(l->front(), i3);
+ l->pop_front();
+ }
+ if (i4) {
+ CHECK_EQ(l->front(), i4);
+ l->pop_front();
+ }
+ if (i5) {
+ CHECK_EQ(l->front(), i5);
+ l->pop_front();
+ }
+ if (i6) {
+ CHECK_EQ(l->front(), i6);
+ l->pop_front();
+ }
+ CHECK(l->empty());
+}
+
+TEST(SanitizerCommon, IntrusiveList) {
+ ListItem items[6];
+ CHECK_EQ(static_list.size(), 0);
+
+ List l;
+ l.clear();
+
+ ListItem *x = &items[0];
+ ListItem *y = &items[1];
+ ListItem *z = &items[2];
+ ListItem *a = &items[3];
+ ListItem *b = &items[4];
+ ListItem *c = &items[5];
+
+ CHECK_EQ(l.size(), 0);
+ l.push_back(x);
+ CHECK_EQ(l.size(), 1);
+ CHECK_EQ(l.back(), x);
+ CHECK_EQ(l.front(), x);
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ l.push_front(x);
+ CHECK_EQ(l.size(), 1);
+ CHECK_EQ(l.back(), x);
+ CHECK_EQ(l.front(), x);
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ l.push_front(x);
+ l.push_front(y);
+ l.push_front(z);
+ CHECK_EQ(l.size(), 3);
+ CHECK_EQ(l.front(), z);
+ CHECK_EQ(l.back(), x);
+ l.CheckConsistency();
+
+ l.pop_front();
+ CHECK_EQ(l.size(), 2);
+ CHECK_EQ(l.front(), y);
+ CHECK_EQ(l.back(), x);
+ l.pop_front();
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ l.push_back(x);
+ l.push_back(y);
+ l.push_back(z);
+ CHECK_EQ(l.size(), 3);
+ CHECK_EQ(l.front(), x);
+ CHECK_EQ(l.back(), z);
+ l.CheckConsistency();
+
+ l.pop_front();
+ CHECK_EQ(l.size(), 2);
+ CHECK_EQ(l.front(), y);
+ CHECK_EQ(l.back(), z);
+ l.pop_front();
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ List l1, l2;
+ l1.clear();
+ l2.clear();
+
+ l1.append_front(&l2);
+ CHECK(l1.empty());
+ CHECK(l2.empty());
+
+ l1.append_back(&l2);
+ CHECK(l1.empty());
+ CHECK(l2.empty());
+
+ SetList(&l1, x);
+ CheckList(&l1, x);
+
+ SetList(&l1, x, y, z);
+ SetList(&l2, a, b, c);
+ l1.append_back(&l2);
+ CheckList(&l1, x, y, z, a, b, c);
+ CHECK(l2.empty());
+
+ SetList(&l1, x, y);
+ SetList(&l2);
+ l1.append_front(&l2);
+ CheckList(&l1, x, y);
+ CHECK(l2.empty());
+}
+
+TEST(SanitizerCommon, IntrusiveListAppendEmpty) {
+ ListItem i;
+ List l;
+ l.clear();
+ l.push_back(&i);
+ List l2;
+ l2.clear();
+ l.append_back(&l2);
+ CHECK_EQ(l.back(), &i);
+ CHECK_EQ(l.front(), &i);
+ CHECK_EQ(l.size(), 1);
+ l.append_front(&l2);
+ CHECK_EQ(l.back(), &i);
+ CHECK_EQ(l.front(), &i);
+ CHECK_EQ(l.size(), 1);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
new file mode 100644
index 000000000000..d14e7c2fba21
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
@@ -0,0 +1,137 @@
+//===-- sanitizer_mutex_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace __sanitizer {
+
+template<typename MutexType>
+class TestData {
+ public:
+ explicit TestData(MutexType *mtx)
+ : mtx_(mtx) {
+ for (int i = 0; i < kSize; i++)
+ data_[i] = 0;
+ }
+
+ void Write() {
+ Lock l(mtx_);
+ T v0 = data_[0];
+ for (int i = 0; i < kSize; i++) {
+ CHECK_EQ(data_[i], v0);
+ data_[i]++;
+ }
+ }
+
+ void TryWrite() {
+ if (!mtx_->TryLock())
+ return;
+ T v0 = data_[0];
+ for (int i = 0; i < kSize; i++) {
+ CHECK_EQ(data_[i], v0);
+ data_[i]++;
+ }
+ mtx_->Unlock();
+ }
+
+ void Backoff() {
+ volatile T data[kSize] = {};
+ for (int i = 0; i < kSize; i++) {
+ data[i]++;
+ CHECK_EQ(data[i], 1);
+ }
+ }
+
+ private:
+ typedef GenericScopedLock<MutexType> Lock;
+ static const int kSize = 64;
+ typedef u64 T;
+ MutexType *mtx_;
+ char pad_[kCacheLineSize];
+ T data_[kSize];
+};
+
+const int kThreads = 8;
+#if SANITIZER_DEBUG
+const int kIters = 16*1024;
+#else
+const int kIters = 64*1024;
+#endif
+
+template<typename MutexType>
+static void *lock_thread(void *param) {
+ TestData<MutexType> *data = (TestData<MutexType>*)param;
+ for (int i = 0; i < kIters; i++) {
+ data->Write();
+ data->Backoff();
+ }
+ return 0;
+}
+
+template<typename MutexType>
+static void *try_thread(void *param) {
+ TestData<MutexType> *data = (TestData<MutexType>*)param;
+ for (int i = 0; i < kIters; i++) {
+ data->TryWrite();
+ data->Backoff();
+ }
+ return 0;
+}
+
+template<typename MutexType>
+static void check_locked(MutexType *mtx) {
+ GenericScopedLock<MutexType> l(mtx);
+ mtx->CheckLocked();
+}
+
+TEST(SanitizerCommon, SpinMutex) {
+ SpinMutex mtx;
+ mtx.Init();
+ TestData<SpinMutex> data(&mtx);
+ pthread_t threads[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
+ for (int i = 0; i < kThreads; i++)
+ PTHREAD_JOIN(threads[i], 0);
+}
+
+TEST(SanitizerCommon, SpinMutexTry) {
+ SpinMutex mtx;
+ mtx.Init();
+ TestData<SpinMutex> data(&mtx);
+ pthread_t threads[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
+ for (int i = 0; i < kThreads; i++)
+ PTHREAD_JOIN(threads[i], 0);
+}
+
+TEST(SanitizerCommon, BlockingMutex) {
+ u64 mtxmem[1024] = {};
+ BlockingMutex *mtx = new(mtxmem) BlockingMutex(LINKER_INITIALIZED);
+ TestData<BlockingMutex> data(mtx);
+ pthread_t threads[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
+ for (int i = 0; i < kThreads; i++)
+ PTHREAD_JOIN(threads[i], 0);
+ check_locked(mtx);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
new file mode 100644
index 000000000000..d0d5a5e13898
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
@@ -0,0 +1,31 @@
+//===-- sanitizer_nolibc_test.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 ThreadSanitizer/AddressSanitizer runtime.
+// Tests for libc independence of sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+
+extern const char *argv0;
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+TEST(SanitizerCommon, NolibcMain) {
+ std::string NolibcTestPath = argv0;
+ NolibcTestPath += "-Nolibc";
+ int status = system(NolibcTestPath.c_str());
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
new file mode 100644
index 000000000000..72df621d07ff
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_nolibc_test_main.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 ThreadSanitizer/AddressSanitizer runtime.
+// Tests for libc independence of sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_libc.h"
+
+extern "C" void _start() {
+ internal__exit(0);
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc
new file mode 100644
index 000000000000..56ce416141fa
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc
@@ -0,0 +1,80 @@
+//===-- sanitizer_posix_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for POSIX-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_POSIX
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+#include <pthread.h>
+#include <sys/mman.h>
+
+namespace __sanitizer {
+
+static pthread_key_t key;
+static bool destructor_executed;
+
+extern "C"
+void destructor(void *arg) {
+ uptr iter = reinterpret_cast<uptr>(arg);
+ if (iter > 1) {
+ ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void *>(iter - 1)));
+ return;
+ }
+ destructor_executed = true;
+}
+
+extern "C"
+void *thread_func(void *arg) {
+ return reinterpret_cast<void*>(pthread_setspecific(key, arg));
+}
+
+static void SpawnThread(uptr iteration) {
+ destructor_executed = false;
+ pthread_t tid;
+ ASSERT_EQ(0, pthread_create(&tid, 0, &thread_func,
+ reinterpret_cast<void *>(iteration)));
+ void *retval;
+ ASSERT_EQ(0, pthread_join(tid, &retval));
+ ASSERT_EQ(0, retval);
+}
+
+TEST(SanitizerCommon, PthreadDestructorIterations) {
+ ASSERT_EQ(0, pthread_key_create(&key, &destructor));
+ SpawnThread(kPthreadDestructorIterations);
+ EXPECT_TRUE(destructor_executed);
+ SpawnThread(kPthreadDestructorIterations + 1);
+ EXPECT_FALSE(destructor_executed);
+}
+
+TEST(SanitizerCommon, IsAccessibleMemoryRange) {
+ const int page_size = GetPageSize();
+ uptr mem = (uptr)mmap(0, 3 * page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ // Protect the middle page.
+ mprotect((void *)(mem + page_size), page_size, PROT_NONE);
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2));
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc
new file mode 100644
index 000000000000..5e39e0a591d6
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc
@@ -0,0 +1,153 @@
+//===-- sanitizer_printf_test.cc ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for sanitizer_printf.cc
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+#include <limits.h>
+
+namespace __sanitizer {
+
+TEST(Printf, Basic) {
+ char buf[1024];
+ uptr len = internal_snprintf(buf, sizeof(buf),
+ "a%db%zdc%ue%zuf%xh%zxq%pe%sr",
+ (int)-1, (long)-2, // NOLINT
+ (unsigned)-4, (unsigned long)5, // NOLINT
+ (unsigned)10, (unsigned long)11, // NOLINT
+ (void*)0x123, "_string_");
+ EXPECT_EQ(len, strlen(buf));
+
+ std::string expectedString = "a-1b-2c4294967292e5fahbq0x";
+ expectedString += std::string(SANITIZER_POINTER_FORMAT_LENGTH - 3, '0');
+ expectedString += "123e_string_r";
+ EXPECT_STREQ(expectedString.c_str(), buf);
+}
+
+TEST(Printf, OverflowStr) {
+ char buf[] = "123456789";
+ uptr len = internal_snprintf(buf, 4, "%s", "abcdef"); // NOLINT
+ EXPECT_EQ(len, (uptr)6);
+ EXPECT_STREQ("abc", buf);
+ EXPECT_EQ(buf[3], 0);
+ EXPECT_EQ(buf[4], '5');
+ EXPECT_EQ(buf[5], '6');
+ EXPECT_EQ(buf[6], '7');
+ EXPECT_EQ(buf[7], '8');
+ EXPECT_EQ(buf[8], '9');
+ EXPECT_EQ(buf[9], 0);
+}
+
+TEST(Printf, OverflowInt) {
+ char buf[] = "123456789";
+ internal_snprintf(buf, 4, "%d", -123456789); // NOLINT
+ EXPECT_STREQ("-12", buf);
+ EXPECT_EQ(buf[3], 0);
+ EXPECT_EQ(buf[4], '5');
+ EXPECT_EQ(buf[5], '6');
+ EXPECT_EQ(buf[6], '7');
+ EXPECT_EQ(buf[7], '8');
+ EXPECT_EQ(buf[8], '9');
+ EXPECT_EQ(buf[9], 0);
+}
+
+TEST(Printf, OverflowUint) {
+ char buf[] = "123456789";
+ uptr val;
+ if (sizeof(val) == 4) {
+ val = (uptr)0x12345678;
+ } else {
+ val = (uptr)0x123456789ULL;
+ }
+ internal_snprintf(buf, 4, "a%zx", val); // NOLINT
+ EXPECT_STREQ("a12", buf);
+ EXPECT_EQ(buf[3], 0);
+ EXPECT_EQ(buf[4], '5');
+ EXPECT_EQ(buf[5], '6');
+ EXPECT_EQ(buf[6], '7');
+ EXPECT_EQ(buf[7], '8');
+ EXPECT_EQ(buf[8], '9');
+ EXPECT_EQ(buf[9], 0);
+}
+
+TEST(Printf, OverflowPtr) {
+ char buf[] = "123456789";
+ void *p;
+ if (sizeof(p) == 4) {
+ p = (void*)0x1234567;
+ } else {
+ p = (void*)0x123456789ULL;
+ }
+ internal_snprintf(buf, 4, "%p", p); // NOLINT
+ EXPECT_STREQ("0x0", buf);
+ EXPECT_EQ(buf[3], 0);
+ EXPECT_EQ(buf[4], '5');
+ EXPECT_EQ(buf[5], '6');
+ EXPECT_EQ(buf[6], '7');
+ EXPECT_EQ(buf[7], '8');
+ EXPECT_EQ(buf[8], '9');
+ EXPECT_EQ(buf[9], 0);
+}
+
+#if defined(_WIN32)
+// Oh well, MSVS headers don't define snprintf.
+# define snprintf _snprintf
+#endif
+
+template<typename T>
+static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
+ char buf[1024];
+ uptr len = internal_snprintf(buf, sizeof(buf), fmt, arg1, arg2);
+ char buf2[1024];
+ snprintf(buf2, sizeof(buf2), fmt, arg1, arg2);
+ EXPECT_EQ(len, strlen(buf));
+ EXPECT_STREQ(buf2, buf);
+}
+
+TEST(Printf, MinMax) {
+ TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
+ TestAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
+ TestAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
+#if !defined(_WIN32)
+ // %z* format doesn't seem to be supported by MSVS.
+ TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
+ TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
+ TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
+#endif
+}
+
+TEST(Printf, Padding) {
+ TestAgainstLibc<int>("%3d - %3d", 1, 0);
+ TestAgainstLibc<int>("%3d - %3d", -1, 123);
+ TestAgainstLibc<int>("%3d - %3d", -1, -123);
+ TestAgainstLibc<int>("%3d - %3d", 12, 1234);
+ TestAgainstLibc<int>("%3d - %3d", -12, -1234);
+ TestAgainstLibc<int>("%03d - %03d", 1, 0);
+ TestAgainstLibc<int>("%03d - %03d", -1, 123);
+ TestAgainstLibc<int>("%03d - %03d", -1, -123);
+ TestAgainstLibc<int>("%03d - %03d", 12, 1234);
+ TestAgainstLibc<int>("%03d - %03d", -12, -1234);
+}
+
+TEST(Printf, Precision) {
+ char buf[1024];
+ uptr len = internal_snprintf(buf, sizeof(buf), "%.*s", 3, "12345");
+ EXPECT_EQ(3U, len);
+ EXPECT_STREQ("123", buf);
+ len = internal_snprintf(buf, sizeof(buf), "%.*s", 6, "12345");
+ EXPECT_EQ(5U, len);
+ EXPECT_STREQ("12345", buf);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
new file mode 100644
index 000000000000..abe4ef43093f
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -0,0 +1,58 @@
+//===-- sanitizer_procmaps_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(_WIN32) // There are no /proc/maps on Windows.
+
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+
+static void noop() {}
+extern const char *argv0;
+
+namespace __sanitizer {
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+TEST(MemoryMappingLayout, CodeRange) {
+ uptr start, end;
+ bool res = GetCodeRangeForFile("[vdso]", &start, &end);
+ EXPECT_EQ(res, true);
+ EXPECT_GT(start, 0U);
+ EXPECT_LT(start, end);
+}
+#endif
+
+TEST(MemoryMappingLayout, DumpListOfModules) {
+ const char *last_slash = strrchr(argv0, '/');
+ const char *binary_name = last_slash ? last_slash + 1 : argv0;
+ MemoryMappingLayout memory_mapping(false);
+ const uptr kMaxModules = 100;
+ LoadedModule *modules =
+ (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+ uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
+ EXPECT_GT(n_modules, 0U);
+ bool found = false;
+ for (uptr i = 0; i < n_modules; ++i) {
+ if (modules[i].containsAddress((uptr)&noop)) {
+ // Verify that the module name is sane.
+ if (strstr(modules[i].full_name(), binary_name) != 0)
+ found = true;
+ }
+ modules[i].clear();
+ }
+ EXPECT_TRUE(found);
+ free(modules);
+}
+
+} // namespace __sanitizer
+#endif // !defined(_WIN32)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
new file mode 100644
index 000000000000..47b0f97de840
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
@@ -0,0 +1,66 @@
+//===-- sanitizer_pthread_wrappers.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 *Sanitizer runtime.
+// It provides handy wrappers for thread manipulation, that:
+// a) assert on any failure rather than returning an error code
+// b) defines pthread-like interface on platforms where where <pthread.h>
+// is not supplied by default.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PTHREAD_WRAPPERS_H
+#define SANITIZER_PTHREAD_WRAPPERS_H
+
+#include "sanitizer_test_utils.h"
+
+#if !defined(_WIN32)
+# include <pthread.h>
+// Simply forward the arguments and check that the pthread functions succeed.
+# define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
+# define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
+#else
+typedef HANDLE pthread_t;
+
+struct PthreadHelperCreateThreadInfo {
+ void *(*start_routine)(void *);
+ void *arg;
+};
+
+inline DWORD WINAPI PthreadHelperThreadProc(void *arg) {
+ PthreadHelperCreateThreadInfo *start_data =
+ reinterpret_cast<PthreadHelperCreateThreadInfo*>(arg);
+ void *ret = (start_data->start_routine)(start_data->arg);
+ delete start_data;
+ return (DWORD)ret;
+}
+
+inline void PTHREAD_CREATE(pthread_t *thread, void *attr,
+ void *(*start_routine)(void *), void *arg) {
+ ASSERT_EQ(0, attr) << "Thread attributes are not supported yet.";
+ PthreadHelperCreateThreadInfo *data = new PthreadHelperCreateThreadInfo;
+ data->start_routine = start_routine;
+ data->arg = arg;
+ *thread = CreateThread(0, 0, PthreadHelperThreadProc, data, 0, 0);
+ ASSERT_NE(nullptr, *thread) << "Failed to create a thread.";
+}
+
+inline void PTHREAD_JOIN(pthread_t thread, void **value_ptr) {
+ ASSERT_EQ(0, value_ptr) << "Nonzero value_ptr is not supported yet.";
+ ASSERT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
+ ASSERT_NE(0, CloseHandle(thread));
+}
+
+inline void pthread_exit(void *retval) {
+ ASSERT_EQ(0, retval) << "Nonzero retval is not supported yet.";
+ ExitThread((DWORD)retval);
+}
+#endif // _WIN32
+
+#endif // SANITIZER_PTHREAD_WRAPPERS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
new file mode 100644
index 000000000000..513432fac214
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
@@ -0,0 +1,93 @@
+//===-- sanitizer_stackdepot_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+TEST(SanitizerCommon, StackDepotBasic) {
+ uptr array[] = {1, 2, 3, 4, 5};
+ StackTrace s1(array, ARRAY_SIZE(array));
+ u32 i1 = StackDepotPut(s1);
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_NE(stack.trace, (uptr*)0);
+ EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+ EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
+}
+
+TEST(SanitizerCommon, StackDepotAbsent) {
+ StackTrace stack = StackDepotGet((1 << 30) - 1);
+ EXPECT_EQ((uptr*)0, stack.trace);
+}
+
+TEST(SanitizerCommon, StackDepotEmptyStack) {
+ u32 i1 = StackDepotPut(StackTrace());
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_EQ((uptr*)0, stack.trace);
+}
+
+TEST(SanitizerCommon, StackDepotZeroId) {
+ StackTrace stack = StackDepotGet(0);
+ EXPECT_EQ((uptr*)0, stack.trace);
+}
+
+TEST(SanitizerCommon, StackDepotSame) {
+ uptr array[] = {1, 2, 3, 4, 6};
+ StackTrace s1(array, ARRAY_SIZE(array));
+ u32 i1 = StackDepotPut(s1);
+ u32 i2 = StackDepotPut(s1);
+ EXPECT_EQ(i1, i2);
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_NE(stack.trace, (uptr*)0);
+ EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+ EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
+}
+
+TEST(SanitizerCommon, StackDepotSeveral) {
+ uptr array1[] = {1, 2, 3, 4, 7};
+ StackTrace s1(array1, ARRAY_SIZE(array1));
+ u32 i1 = StackDepotPut(s1);
+ uptr array2[] = {1, 2, 3, 4, 8, 9};
+ StackTrace s2(array2, ARRAY_SIZE(array2));
+ u32 i2 = StackDepotPut(s2);
+ EXPECT_NE(i1, i2);
+}
+
+TEST(SanitizerCommon, StackDepotReverseMap) {
+ uptr array1[] = {1, 2, 3, 4, 5};
+ uptr array2[] = {7, 1, 3, 0};
+ uptr array3[] = {10, 2, 5, 3};
+ uptr array4[] = {1, 3, 2, 5};
+ u32 ids[4] = {0};
+ StackTrace s1(array1, ARRAY_SIZE(array1));
+ StackTrace s2(array2, ARRAY_SIZE(array2));
+ StackTrace s3(array3, ARRAY_SIZE(array3));
+ StackTrace s4(array4, ARRAY_SIZE(array4));
+ ids[0] = StackDepotPut(s1);
+ ids[1] = StackDepotPut(s2);
+ ids[2] = StackDepotPut(s3);
+ ids[3] = StackDepotPut(s4);
+
+ StackDepotReverseMap map;
+
+ for (uptr i = 0; i < 4; i++) {
+ StackTrace stack = StackDepotGet(ids[i]);
+ StackTrace from_map = map.Get(ids[i]);
+ EXPECT_EQ(stack.size, from_map.size);
+ EXPECT_EQ(stack.trace, from_map.trace);
+ }
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
new file mode 100644
index 000000000000..cc9a9edbbb46
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
@@ -0,0 +1,122 @@
+//===-- sanitizer_common_printer_test.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 sanitizer_common test suite.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
+
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+TEST(SanitizerStacktracePrinter, RenderSourceLocation) {
+ InternalScopedString str(128);
+ RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "");
+ EXPECT_STREQ("/dir/file.cc:10:5", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 11, 0, "");
+ EXPECT_STREQ("/dir/file.cc:11", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 0, 0, "");
+ EXPECT_STREQ("/dir/file.cc", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "/dir/");
+ EXPECT_STREQ("file.cc:10:5", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderModuleLocation) {
+ InternalScopedString str(128);
+ RenderModuleLocation(&str, "/dir/exe", 0x123, "");
+ EXPECT_STREQ("(/dir/exe+0x123)", str.data());
+
+ // Check that we strip file prefix if necessary.
+ str.clear();
+ RenderModuleLocation(&str, "/dir/exe", 0x123, "/dir/");
+ EXPECT_STREQ("(exe+0x123)", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderFrame) {
+ int frame_no = 42;
+ AddressInfo info;
+ info.address = 0x400000;
+ info.module = internal_strdup("/path/to/my/module");
+ info.module_offset = 0x200;
+ info.function = internal_strdup("function_foo");
+ info.function_offset = 0x100;
+ info.file = internal_strdup("/path/to/my/source");
+ info.line = 10;
+ info.column = 5;
+ InternalScopedString str(256);
+
+ // Dump all the AddressInfo fields.
+ RenderFrame(&str, "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
+ "Function:%f FunctionOffset:%q Source:%s Line:%l "
+ "Column:%c",
+ frame_no, info, "/path/to/", "function_");
+ EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
+ "Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
+ "Column:5",
+ str.data());
+ info.Clear();
+ str.clear();
+
+ // Test special format specifiers.
+ info.address = 0x400000;
+ RenderFrame(&str, "%M", frame_no, info);
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
+ str.clear();
+
+ RenderFrame(&str, "%L", frame_no, info);
+ EXPECT_STREQ("(<unknown module>)", str.data());
+ str.clear();
+
+ info.module = internal_strdup("/path/to/module");
+ info.module_offset = 0x200;
+ RenderFrame(&str, "%M", frame_no, info);
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
+ str.clear();
+
+ RenderFrame(&str, "%L", frame_no, info);
+ EXPECT_STREQ("(/path/to/module+0x200)", str.data());
+ str.clear();
+
+ info.function = internal_strdup("my_function");
+ RenderFrame(&str, "%F", frame_no, info);
+ EXPECT_STREQ("in my_function", str.data());
+ str.clear();
+
+ info.function_offset = 0x100;
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function+0x100 <null>", str.data());
+ str.clear();
+
+ info.file = internal_strdup("my_file");
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function my_file", str.data());
+ str.clear();
+
+ info.line = 10;
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function my_file:10", str.data());
+ str.clear();
+
+ info.column = 5;
+ RenderFrame(&str, "%S %L", frame_no, info);
+ EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
+ str.clear();
+
+ info.Clear();
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
new file mode 100644
index 000000000000..ac820c25a0f8
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -0,0 +1,154 @@
+//===-- sanitizer_stacktrace_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+class FastUnwindTest : public ::testing::Test {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+ bool TryFastUnwind(uptr max_depth) {
+ if (!StackTrace::WillUseFastUnwind(true))
+ return false;
+ trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top,
+ fake_bottom, true);
+ return true;
+ }
+
+ void *mapping;
+ uptr *fake_stack;
+ const uptr fake_stack_size = 10;
+ uptr start_pc;
+ uptr fake_top;
+ uptr fake_bottom;
+ BufferedStackTrace trace;
+};
+
+static uptr PC(uptr idx) {
+ return (1<<20) + idx;
+}
+
+void FastUnwindTest::SetUp() {
+ size_t ps = GetPageSize();
+ mapping = MmapOrDie(2 * ps, "FastUnwindTest");
+ Mprotect((uptr)mapping, ps);
+
+ // Unwinder may peek 1 word down from the starting FP.
+ fake_stack = (uptr *)((uptr)mapping + ps + sizeof(uptr));
+
+ // Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have
+ // even indices.
+ for (uptr i = 0; i + 1 < fake_stack_size; i += 2) {
+ fake_stack[i] = (uptr)&fake_stack[i+2]; // fp
+ fake_stack[i+1] = PC(i + 1); // retaddr
+ }
+ // Mark the last fp point back up to terminate the stack trace.
+ fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uptr)&fake_stack[0];
+
+ // Top is two slots past the end because FastUnwindStack subtracts two.
+ fake_top = (uptr)&fake_stack[fake_stack_size + 2];
+ // Bottom is one slot before the start because FastUnwindStack uses >.
+ fake_bottom = (uptr)mapping;
+ start_pc = PC(0);
+}
+
+void FastUnwindTest::TearDown() {
+ size_t ps = GetPageSize();
+ UnmapOrDie(mapping, 2 * ps);
+}
+
+TEST_F(FastUnwindTest, Basic) {
+ if (!TryFastUnwind(kStackTraceMax))
+ return;
+ // Should get all on-stack retaddrs and start_pc.
+ EXPECT_EQ(6U, trace.size);
+ EXPECT_EQ(start_pc, trace.trace[0]);
+ for (uptr i = 1; i <= 5; i++) {
+ EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
+ }
+}
+
+// From: http://code.google.com/p/address-sanitizer/issues/detail?id=162
+TEST_F(FastUnwindTest, FramePointerLoop) {
+ // Make one fp point to itself.
+ fake_stack[4] = (uptr)&fake_stack[4];
+ if (!TryFastUnwind(kStackTraceMax))
+ return;
+ // Should get all on-stack retaddrs up to the 4th slot and start_pc.
+ EXPECT_EQ(4U, trace.size);
+ EXPECT_EQ(start_pc, trace.trace[0]);
+ for (uptr i = 1; i <= 3; i++) {
+ EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
+ }
+}
+
+TEST_F(FastUnwindTest, MisalignedFramePointer) {
+ // Make one fp misaligned.
+ fake_stack[4] += 3;
+ if (!TryFastUnwind(kStackTraceMax))
+ return;
+ // Should get all on-stack retaddrs up to the 4th slot and start_pc.
+ EXPECT_EQ(4U, trace.size);
+ EXPECT_EQ(start_pc, trace.trace[0]);
+ for (uptr i = 1; i < 4U; i++) {
+ EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
+ }
+}
+
+TEST_F(FastUnwindTest, OneFrameStackTrace) {
+ if (!TryFastUnwind(1))
+ return;
+ EXPECT_EQ(1U, trace.size);
+ EXPECT_EQ(start_pc, trace.trace[0]);
+ EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
+}
+
+TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
+ if (!TryFastUnwind(0))
+ return;
+ EXPECT_EQ(0U, trace.size);
+ EXPECT_EQ(0U, trace.top_frame_bp);
+}
+
+TEST_F(FastUnwindTest, FPBelowPrevFP) {
+ // The next FP points to unreadable memory inside the stack limits, but below
+ // current FP.
+ fake_stack[0] = (uptr)&fake_stack[-50];
+ fake_stack[1] = PC(1);
+ if (!TryFastUnwind(3))
+ return;
+ EXPECT_EQ(2U, trace.size);
+ EXPECT_EQ(PC(0), trace.trace[0]);
+ EXPECT_EQ(PC(1), trace.trace[1]);
+}
+
+TEST(SlowUnwindTest, ShortStackTrace) {
+ if (StackTrace::WillUseFastUnwind(false))
+ return;
+ BufferedStackTrace stack;
+ uptr pc = StackTrace::GetCurrentPc();
+ uptr bp = GET_CURRENT_FRAME();
+ stack.Unwind(0, pc, bp, 0, 0, 0, false);
+ EXPECT_EQ(0U, stack.size);
+ EXPECT_EQ(0U, stack.top_frame_bp);
+ stack.Unwind(1, pc, bp, 0, 0, 0, false);
+ EXPECT_EQ(1U, stack.size);
+ EXPECT_EQ(pc, stack.trace[0]);
+ EXPECT_EQ(bp, stack.top_frame_bp);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
new file mode 100644
index 000000000000..b6786ba8b013
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
@@ -0,0 +1,194 @@
+//===-- sanitizer_stoptheworld_test.cc ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for sanitizer_stoptheworld.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX && defined(__x86_64__)
+
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "gtest/gtest.h"
+
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include <pthread.h>
+#include <sched.h>
+
+namespace __sanitizer {
+
+static pthread_mutex_t incrementer_thread_exit_mutex;
+
+struct CallbackArgument {
+ volatile int counter;
+ volatile bool threads_stopped;
+ volatile bool callback_executed;
+ CallbackArgument()
+ : counter(0),
+ threads_stopped(false),
+ callback_executed(false) {}
+};
+
+void *IncrementerThread(void *argument) {
+ CallbackArgument *callback_argument = (CallbackArgument *)argument;
+ while (true) {
+ __sync_fetch_and_add(&callback_argument->counter, 1);
+ if (pthread_mutex_trylock(&incrementer_thread_exit_mutex) == 0) {
+ pthread_mutex_unlock(&incrementer_thread_exit_mutex);
+ return NULL;
+ } else {
+ sched_yield();
+ }
+ }
+}
+
+// This callback checks that IncrementerThread is suspended at the time of its
+// execution.
+void Callback(const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
+ CallbackArgument *callback_argument = (CallbackArgument *)argument;
+ callback_argument->callback_executed = true;
+ int counter_at_init = __sync_fetch_and_add(&callback_argument->counter, 0);
+ for (uptr i = 0; i < 1000; i++) {
+ sched_yield();
+ if (__sync_fetch_and_add(&callback_argument->counter, 0) !=
+ counter_at_init) {
+ callback_argument->threads_stopped = false;
+ return;
+ }
+ }
+ callback_argument->threads_stopped = true;
+}
+
+TEST(StopTheWorld, SuspendThreadsSimple) {
+ pthread_mutex_init(&incrementer_thread_exit_mutex, NULL);
+ CallbackArgument argument;
+ pthread_t thread_id;
+ int pthread_create_result;
+ pthread_mutex_lock(&incrementer_thread_exit_mutex);
+ pthread_create_result = pthread_create(&thread_id, NULL, IncrementerThread,
+ &argument);
+ ASSERT_EQ(0, pthread_create_result);
+ StopTheWorld(&Callback, &argument);
+ pthread_mutex_unlock(&incrementer_thread_exit_mutex);
+ EXPECT_TRUE(argument.callback_executed);
+ EXPECT_TRUE(argument.threads_stopped);
+ // argument is on stack, so we have to wait for the incrementer thread to
+ // terminate before we can return from this function.
+ ASSERT_EQ(0, pthread_join(thread_id, NULL));
+ pthread_mutex_destroy(&incrementer_thread_exit_mutex);
+}
+
+// A more comprehensive test where we spawn a bunch of threads while executing
+// StopTheWorld in parallel.
+static const uptr kThreadCount = 50;
+static const uptr kStopWorldAfter = 10; // let this many threads spawn first
+
+static pthread_mutex_t advanced_incrementer_thread_exit_mutex;
+
+struct AdvancedCallbackArgument {
+ volatile uptr thread_index;
+ volatile int counters[kThreadCount];
+ pthread_t thread_ids[kThreadCount];
+ volatile bool threads_stopped;
+ volatile bool callback_executed;
+ volatile bool fatal_error;
+ AdvancedCallbackArgument()
+ : thread_index(0),
+ threads_stopped(false),
+ callback_executed(false),
+ fatal_error(false) {}
+};
+
+void *AdvancedIncrementerThread(void *argument) {
+ AdvancedCallbackArgument *callback_argument =
+ (AdvancedCallbackArgument *)argument;
+ uptr this_thread_index = __sync_fetch_and_add(
+ &callback_argument->thread_index, 1);
+ // Spawn the next thread.
+ int pthread_create_result;
+ if (this_thread_index + 1 < kThreadCount) {
+ pthread_create_result =
+ pthread_create(&callback_argument->thread_ids[this_thread_index + 1],
+ NULL, AdvancedIncrementerThread, argument);
+ // Cannot use ASSERT_EQ in non-void-returning functions. If there's a
+ // problem, defer failing to the main thread.
+ if (pthread_create_result != 0) {
+ callback_argument->fatal_error = true;
+ __sync_fetch_and_add(&callback_argument->thread_index,
+ kThreadCount - callback_argument->thread_index);
+ }
+ }
+ // Do the actual work.
+ while (true) {
+ __sync_fetch_and_add(&callback_argument->counters[this_thread_index], 1);
+ if (pthread_mutex_trylock(&advanced_incrementer_thread_exit_mutex) == 0) {
+ pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex);
+ return NULL;
+ } else {
+ sched_yield();
+ }
+ }
+}
+
+void AdvancedCallback(const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
+ AdvancedCallbackArgument *callback_argument =
+ (AdvancedCallbackArgument *)argument;
+ callback_argument->callback_executed = true;
+
+ int counters_at_init[kThreadCount];
+ for (uptr j = 0; j < kThreadCount; j++)
+ counters_at_init[j] = __sync_fetch_and_add(&callback_argument->counters[j],
+ 0);
+ for (uptr i = 0; i < 10; i++) {
+ sched_yield();
+ for (uptr j = 0; j < kThreadCount; j++)
+ if (__sync_fetch_and_add(&callback_argument->counters[j], 0) !=
+ counters_at_init[j]) {
+ callback_argument->threads_stopped = false;
+ return;
+ }
+ }
+ callback_argument->threads_stopped = true;
+}
+
+TEST(StopTheWorld, SuspendThreadsAdvanced) {
+ pthread_mutex_init(&advanced_incrementer_thread_exit_mutex, NULL);
+ AdvancedCallbackArgument argument;
+
+ pthread_mutex_lock(&advanced_incrementer_thread_exit_mutex);
+ int pthread_create_result;
+ pthread_create_result = pthread_create(&argument.thread_ids[0], NULL,
+ AdvancedIncrementerThread,
+ &argument);
+ ASSERT_EQ(0, pthread_create_result);
+ // Wait for several threads to spawn before proceeding.
+ while (__sync_fetch_and_add(&argument.thread_index, 0) < kStopWorldAfter)
+ sched_yield();
+ StopTheWorld(&AdvancedCallback, &argument);
+ EXPECT_TRUE(argument.callback_executed);
+ EXPECT_TRUE(argument.threads_stopped);
+
+ // Wait for all threads to spawn before we start terminating them.
+ while (__sync_fetch_and_add(&argument.thread_index, 0) < kThreadCount)
+ sched_yield();
+ ASSERT_FALSE(argument.fatal_error); // a pthread_create has failed
+ // Signal the threads to terminate.
+ pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex);
+ for (uptr i = 0; i < kThreadCount; i++)
+ ASSERT_EQ(0, pthread_join(argument.thread_ids[i], NULL));
+ pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LINUX && defined(__x86_64__)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
new file mode 100644
index 000000000000..d8be2afb19e9
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
@@ -0,0 +1,53 @@
+//===-- sanitizer_stoptheworld_testlib.cc ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Dynamic library to test StopTheWorld functionality.
+// When loaded with LD_PRELOAD, it will periodically suspend all threads.
+//===----------------------------------------------------------------------===//
+/* Usage:
+clang++ -fno-exceptions -g -fPIC -I. \
+ sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc \
+ sanitizer_common/sanitizer_*.cc -shared -lpthread -o teststoptheworld.so
+LD_PRELOAD=`pwd`/teststoptheworld.so /your/app
+*/
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+
+namespace {
+const uptr kSuspendDuration = 3;
+const uptr kRunDuration = 3;
+
+void Callback(const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
+ sleep(kSuspendDuration);
+}
+
+void *SuspenderThread(void *argument) {
+ while (true) {
+ sleep(kRunDuration);
+ StopTheWorld(Callback, NULL);
+ }
+ return NULL;
+}
+
+__attribute__((constructor)) void StopTheWorldTestLibConstructor(void) {
+ pthread_t thread_id;
+ pthread_create(&thread_id, NULL, SuspenderThread, NULL);
+}
+} // namespace
+
+#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
new file mode 100644
index 000000000000..e8c30d07e78c
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -0,0 +1,134 @@
+//===-- sanitizer_suppressions_test.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace __sanitizer {
+
+static bool MyMatch(const char *templ, const char *func) {
+ char tmp[1024];
+ strcpy(tmp, templ); // NOLINT
+ return TemplateMatch(tmp, func);
+}
+
+TEST(Suppressions, Match) {
+ EXPECT_TRUE(MyMatch("foobar$", "foobar"));
+
+ EXPECT_TRUE(MyMatch("foobar", "foobar"));
+ EXPECT_TRUE(MyMatch("*foobar*", "foobar"));
+ EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
+ EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
+ EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
+ EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
+ EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
+ EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
+ EXPECT_TRUE(MyMatch("^foobar", "foobar"));
+ EXPECT_TRUE(MyMatch("^foobar", "foobar_postfix"));
+ EXPECT_TRUE(MyMatch("^*foobar", "foobar"));
+ EXPECT_TRUE(MyMatch("^*foobar", "prefix_foobar"));
+ EXPECT_TRUE(MyMatch("foobar$", "foobar"));
+ EXPECT_TRUE(MyMatch("foobar$", "prefix_foobar"));
+ EXPECT_TRUE(MyMatch("*foobar*$", "foobar"));
+ EXPECT_TRUE(MyMatch("*foobar*$", "foobar_postfix"));
+ EXPECT_TRUE(MyMatch("^foobar$", "foobar"));
+
+ EXPECT_FALSE(MyMatch("foo", "baz"));
+ EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
+ EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
+ EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
+ EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
+ EXPECT_FALSE(MyMatch("^foobar", "prefix_foobar"));
+ EXPECT_FALSE(MyMatch("foobar$", "foobar_postfix"));
+ EXPECT_FALSE(MyMatch("^foobar$", "prefix_foobar"));
+ EXPECT_FALSE(MyMatch("^foobar$", "foobar_postfix"));
+ EXPECT_FALSE(MyMatch("foo^bar", "foobar"));
+ EXPECT_FALSE(MyMatch("foo$bar", "foobar"));
+ EXPECT_FALSE(MyMatch("foo$^bar", "foobar"));
+}
+
+static const char *kTestSuppressionTypes[] = {"race", "thread", "mutex",
+ "signal"};
+
+class SuppressionContextTest : public ::testing::Test {
+ public:
+ SuppressionContextTest()
+ : ctx_(kTestSuppressionTypes, ARRAY_SIZE(kTestSuppressionTypes)) {}
+
+ protected:
+ SuppressionContext ctx_;
+
+ void CheckSuppressions(unsigned count, std::vector<const char *> types,
+ std::vector<const char *> templs) const {
+ EXPECT_EQ(count, ctx_.SuppressionCount());
+ for (unsigned i = 0; i < count; i++) {
+ const Suppression *s = ctx_.SuppressionAt(i);
+ EXPECT_STREQ(types[i], s->type);
+ EXPECT_STREQ(templs[i], s->templ);
+ }
+ }
+};
+
+TEST_F(SuppressionContextTest, Parse) {
+ ctx_.Parse("race:foo\n"
+ " race:bar\n" // NOLINT
+ "race:baz \n" // NOLINT
+ "# a comment\n"
+ "race:quz\n"); // NOLINT
+ CheckSuppressions(4, {"race", "race", "race", "race"},
+ {"foo", "bar", "baz", "quz"});
+}
+
+TEST_F(SuppressionContextTest, Parse2) {
+ ctx_.Parse(
+ " # first line comment\n" // NOLINT
+ " race:bar \n" // NOLINT
+ "race:baz* *baz\n"
+ "# a comment\n"
+ "# last line comment\n"
+ ); // NOLINT
+ CheckSuppressions(2, {"race", "race"}, {"bar", "baz* *baz"});
+}
+
+TEST_F(SuppressionContextTest, Parse3) {
+ ctx_.Parse(
+ "# last suppression w/o line-feed\n"
+ "race:foo\n"
+ "race:bar"
+ ); // NOLINT
+ CheckSuppressions(2, {"race", "race"}, {"foo", "bar"});
+}
+
+TEST_F(SuppressionContextTest, ParseType) {
+ ctx_.Parse(
+ "race:foo\n"
+ "thread:bar\n"
+ "mutex:baz\n"
+ "signal:quz\n"
+ ); // NOLINT
+ CheckSuppressions(4, {"race", "thread", "mutex", "signal"},
+ {"foo", "bar", "baz", "quz"});
+}
+
+TEST_F(SuppressionContextTest, HasSuppressionType) {
+ ctx_.Parse(
+ "race:foo\n"
+ "thread:bar\n");
+ EXPECT_TRUE(ctx_.HasSuppressionType("race"));
+ EXPECT_TRUE(ctx_.HasSuppressionType("thread"));
+ EXPECT_FALSE(ctx_.HasSuppressionType("mutex"));
+ EXPECT_FALSE(ctx_.HasSuppressionType("signal"));
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h
new file mode 100644
index 000000000000..bdf614606d6a
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h
@@ -0,0 +1,30 @@
+//===-- sanitizer_test_config.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 *Sanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_SANITIZER_TEST_UTILS_H)
+# error "This file should be included into sanitizer_test_utils.h only"
+#endif
+
+#ifndef SANITIZER_TEST_CONFIG_H
+#define SANITIZER_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#if SANITIZER_USE_DEJAGNU_GTEST
+# include "dejagnu-gtest.h"
+#else
+# include "gtest/gtest.h"
+#endif
+
+#endif // SANITIZER_TEST_CONFIG_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc
new file mode 100644
index 000000000000..b7fd3dafab26
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc
@@ -0,0 +1,22 @@
+//===-- sanitizer_test_main.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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
+
+const char *argv0;
+
+int main(int argc, char **argv) {
+ argv0 = argv[0];
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h
new file mode 100644
index 000000000000..9c162a66f547
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h
@@ -0,0 +1,127 @@
+//===-- sanitizer_test_utils.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 *Sanitizer runtime.
+// Common unit tests utilities.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_TEST_UTILS_H
+#define SANITIZER_TEST_UTILS_H
+
+#if defined(_WIN32)
+// <windows.h> should always be the first include on Windows.
+# include <windows.h>
+// MSVS headers define max/min as macros, so std::max/min gets crazy.
+# undef max
+# undef min
+#endif
+
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+# include "sanitizer_test_config.h"
+# undef INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+#endif
+
+#include <stdint.h>
+
+#if defined(_MSC_VER)
+# define NOINLINE __declspec(noinline)
+#else // defined(_MSC_VER)
+# define NOINLINE __attribute__((noinline))
+#endif // defined(_MSC_VER)
+
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
+# define USED __attribute__((used))
+#else
+# define UNUSED
+# define USED
+#endif
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+
+#ifndef ATTRIBUTE_NO_SANITIZE_ADDRESS
+# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS \
+ __attribute__((no_sanitize_address))
+# else
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS
+# endif
+#endif // ATTRIBUTE_NO_SANITIZE_ADDRESS
+
+#if __LP64__ || defined(_WIN64)
+# define SANITIZER_WORDSIZE 64
+#else
+# define SANITIZER_WORDSIZE 32
+#endif
+
+// Make the compiler thinks that something is going on there.
+inline void break_optimization(void *arg) {
+#if !defined(_WIN32) || defined(__clang__)
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
+}
+
+// This function returns its parameter but in such a way that compiler
+// can not prove it.
+template<class T>
+NOINLINE
+static T Ident(T t) {
+ T ret = t;
+ break_optimization(&ret);
+ return ret;
+}
+
+// Simple stand-alone pseudorandom number generator.
+// Current algorithm is ANSI C linear congruential PRNG.
+static inline uint32_t my_rand_r(uint32_t* state) {
+ return (*state = *state * 1103515245 + 12345) >> 16;
+}
+
+static uint32_t global_seed = 0;
+
+static inline uint32_t my_rand() {
+ return my_rand_r(&global_seed);
+}
+
+// Set availability of platform-specific functions.
+
+#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 1
+#else
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 0
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && \
+ !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_MEMALIGN 1
+# define SANITIZER_TEST_HAS_PVALLOC 1
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1
+#else
+# define SANITIZER_TEST_HAS_MEMALIGN 0
+# define SANITIZER_TEST_HAS_PVALLOC 0
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 0
+#endif
+
+#if !defined(__APPLE__)
+# define SANITIZER_TEST_HAS_STRNLEN 1
+#else
+# define SANITIZER_TEST_HAS_STRNLEN 0
+#endif
+
+#if defined(__FreeBSD__)
+# define SANITIZER_TEST_HAS_PRINTF_L 1
+#else
+# define SANITIZER_TEST_HAS_PRINTF_L 0
+#endif
+
+#endif // SANITIZER_TEST_UTILS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
new file mode 100644
index 000000000000..58c627a704ff
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -0,0 +1,232 @@
+//===-- sanitizer_thread_registry_test.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 shared sanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
+#include "gtest/gtest.h"
+
+#include <vector>
+
+namespace __sanitizer {
+
+static BlockingMutex tctx_allocator_lock(LINKER_INITIALIZED);
+static LowLevelAllocator tctx_allocator;
+
+template<typename TCTX>
+static ThreadContextBase *GetThreadContext(u32 tid) {
+ BlockingMutexLock l(&tctx_allocator_lock);
+ return new(tctx_allocator) TCTX(tid);
+}
+
+static const u32 kMaxRegistryThreads = 1000;
+static const u32 kRegistryQuarantine = 2;
+
+static void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total,
+ uptr exp_running, uptr exp_alive) {
+ uptr total, running, alive;
+ registry->GetNumberOfThreads(&total, &running, &alive);
+ EXPECT_EQ(exp_total, total);
+ EXPECT_EQ(exp_running, running);
+ EXPECT_EQ(exp_alive, alive);
+}
+
+static bool is_detached(u32 tid) {
+ return (tid % 2 == 0);
+}
+
+static uptr get_uid(u32 tid) {
+ return tid * 2;
+}
+
+static bool HasName(ThreadContextBase *tctx, void *arg) {
+ char *name = (char*)arg;
+ return (0 == internal_strcmp(tctx->name, name));
+}
+
+static bool HasUid(ThreadContextBase *tctx, void *arg) {
+ uptr uid = (uptr)arg;
+ return (tctx->user_id == uid);
+}
+
+static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
+ bool *arr = (bool*)arg;
+ arr[tctx->tid] = true;
+}
+
+static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
+ // Create and start a main thread.
+ EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0));
+ registry->StartThread(0, 0, 0);
+ // Create a bunch of threads.
+ for (u32 i = 1; i <= 10; i++) {
+ EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
+ }
+ CheckThreadQuantity(registry, 11, 1, 11);
+ // Start some of them.
+ for (u32 i = 1; i <= 5; i++) {
+ registry->StartThread(i, 0, 0);
+ }
+ CheckThreadQuantity(registry, 11, 6, 11);
+ // Finish, create and start more threads.
+ for (u32 i = 1; i <= 5; i++) {
+ registry->FinishThread(i);
+ if (!is_detached(i))
+ registry->JoinThread(i, 0);
+ }
+ for (u32 i = 6; i <= 10; i++) {
+ registry->StartThread(i, 0, 0);
+ }
+ std::vector<u32> new_tids;
+ for (u32 i = 11; i <= 15; i++) {
+ new_tids.push_back(
+ registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
+ }
+ ASSERT_LE(kRegistryQuarantine, 5U);
+ u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0);
+ CheckThreadQuantity(registry, exp_total, 6, 11);
+ // Test SetThreadName and FindThread.
+ registry->SetThreadName(6, "six");
+ registry->SetThreadName(7, "seven");
+ EXPECT_EQ(7U, registry->FindThread(HasName, (void*)"seven"));
+ EXPECT_EQ(ThreadRegistry::kUnknownTid,
+ registry->FindThread(HasName, (void*)"none"));
+ EXPECT_EQ(0U, registry->FindThread(HasUid, (void*)get_uid(0)));
+ EXPECT_EQ(10U, registry->FindThread(HasUid, (void*)get_uid(10)));
+ EXPECT_EQ(ThreadRegistry::kUnknownTid,
+ registry->FindThread(HasUid, (void*)0x1234));
+ // Detach and finish and join remaining threads.
+ for (u32 i = 6; i <= 10; i++) {
+ registry->DetachThread(i, 0);
+ registry->FinishThread(i);
+ }
+ for (u32 i = 0; i < new_tids.size(); i++) {
+ u32 tid = new_tids[i];
+ registry->StartThread(tid, 0, 0);
+ registry->DetachThread(tid, 0);
+ registry->FinishThread(tid);
+ }
+ CheckThreadQuantity(registry, exp_total, 1, 1);
+ // Test methods that require the caller to hold a ThreadRegistryLock.
+ bool has_tid[16];
+ internal_memset(&has_tid[0], 0, sizeof(has_tid));
+ {
+ ThreadRegistryLock l(registry);
+ registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]);
+ }
+ for (u32 i = 0; i < exp_total; i++) {
+ EXPECT_TRUE(has_tid[i]);
+ }
+ {
+ ThreadRegistryLock l(registry);
+ registry->CheckLocked();
+ ThreadContextBase *main_thread = registry->GetThreadLocked(0);
+ EXPECT_EQ(main_thread, registry->FindThreadContextLocked(
+ HasUid, (void*)get_uid(0)));
+ }
+ EXPECT_EQ(11U, registry->GetMaxAliveThreads());
+}
+
+TEST(SanitizerCommon, ThreadRegistryTest) {
+ ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>,
+ kMaxRegistryThreads,
+ kRegistryQuarantine);
+ TestRegistry(&quarantine_registry, true);
+
+ ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>,
+ kMaxRegistryThreads,
+ kMaxRegistryThreads);
+ TestRegistry(&no_quarantine_registry, false);
+}
+
+static const int kThreadsPerShard = 20;
+static const int kNumShards = 25;
+
+static int num_created[kNumShards + 1];
+static int num_started[kNumShards + 1];
+static int num_joined[kNumShards + 1];
+
+namespace {
+
+struct RunThreadArgs {
+ ThreadRegistry *registry;
+ uptr shard; // started from 1.
+};
+
+class TestThreadContext : public ThreadContextBase {
+ public:
+ explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
+ void OnJoined(void *arg) {
+ uptr shard = (uptr)arg;
+ num_joined[shard]++;
+ }
+ void OnStarted(void *arg) {
+ uptr shard = (uptr)arg;
+ num_started[shard]++;
+ }
+ void OnCreated(void *arg) {
+ uptr shard = (uptr)arg;
+ num_created[shard]++;
+ }
+};
+
+} // namespace
+
+void *RunThread(void *arg) {
+ RunThreadArgs *args = static_cast<RunThreadArgs*>(arg);
+ std::vector<int> tids;
+ for (int i = 0; i < kThreadsPerShard; i++)
+ tids.push_back(
+ args->registry->CreateThread(0, false, 0, (void*)args->shard));
+ for (int i = 0; i < kThreadsPerShard; i++)
+ args->registry->StartThread(tids[i], 0, (void*)args->shard);
+ for (int i = 0; i < kThreadsPerShard; i++)
+ args->registry->FinishThread(tids[i]);
+ for (int i = 0; i < kThreadsPerShard; i++)
+ args->registry->JoinThread(tids[i], (void*)args->shard);
+ return 0;
+}
+
+static void ThreadedTestRegistry(ThreadRegistry *registry) {
+ // Create and start a main thread.
+ EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));
+ registry->StartThread(0, 0, 0);
+ pthread_t threads[kNumShards];
+ RunThreadArgs args[kNumShards];
+ for (int i = 0; i < kNumShards; i++) {
+ args[i].registry = registry;
+ args[i].shard = i + 1;
+ PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
+ }
+ for (int i = 0; i < kNumShards; i++) {
+ PTHREAD_JOIN(threads[i], 0);
+ }
+ // Check that each thread created/started/joined correct amount
+ // of "threads" in thread_registry.
+ EXPECT_EQ(1, num_created[0]);
+ EXPECT_EQ(1, num_started[0]);
+ EXPECT_EQ(0, num_joined[0]);
+ for (int i = 1; i <= kNumShards; i++) {
+ EXPECT_EQ(kThreadsPerShard, num_created[i]);
+ EXPECT_EQ(kThreadsPerShard, num_started[i]);
+ EXPECT_EQ(kThreadsPerShard, num_joined[i]);
+ }
+}
+
+TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
+ ThreadRegistry registry(GetThreadContext<TestThreadContext>,
+ kThreadsPerShard * kNumShards + 1, 10);
+ ThreadedTestRegistry(&registry);
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc
new file mode 100644
index 000000000000..9e6f7c93b04b
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <vector>
+#include <pthread.h>
+#include <malloc.h>
+#include <algorithm>
+
+using namespace std;
+
+const size_t kNumThreds = 16;
+const size_t kNumIters = 1 << 23;
+
+inline void break_optimization(void *arg) {
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+}
+
+__attribute__((noinline))
+static void *MallocThread(void *t) {
+ size_t total_malloced = 0, total_freed = 0;
+ size_t max_in_use = 0;
+ size_t tid = reinterpret_cast<size_t>(t);
+ vector<pair<char *, size_t> > allocated;
+ allocated.reserve(kNumIters);
+ for (size_t i = 1; i < kNumIters; i++) {
+ if ((i % (kNumIters / 4)) == 0 && tid == 0)
+ fprintf(stderr, " T[%ld] iter %ld\n", tid, i);
+ bool allocate = (i % 5) <= 2; // 60% malloc, 40% free
+ if (i > kNumIters / 4)
+ allocate = i % 2; // then switch to 50% malloc, 50% free
+ if (allocate) {
+ size_t size = 1 + (i % 200);
+ if ((i % 10001) == 0)
+ size *= 4096;
+ total_malloced += size;
+ char *x = new char[size];
+ x[0] = x[size - 1] = x[size / 2] = 0;
+ allocated.push_back(make_pair(x, size));
+ max_in_use = max(max_in_use, total_malloced - total_freed);
+ } else {
+ if (allocated.empty()) continue;
+ size_t slot = i % allocated.size();
+ char *p = allocated[slot].first;
+ p[0] = 0; // emulate last user touch of the block
+ size_t size = allocated[slot].second;
+ total_freed += size;
+ swap(allocated[slot], allocated.back());
+ allocated.pop_back();
+ delete [] p;
+ }
+ }
+ if (tid == 0)
+ fprintf(stderr, " T[%ld] total_malloced: %ldM in use %ldM max %ldM\n",
+ tid, total_malloced >> 20, (total_malloced - total_freed) >> 20,
+ max_in_use >> 20);
+ for (size_t i = 0; i < allocated.size(); i++)
+ delete [] allocated[i].first;
+ return 0;
+}
+
+template <int depth>
+struct DeepStack {
+ __attribute__((noinline))
+ static void *run(void *t) {
+ break_optimization(0);
+ DeepStack<depth - 1>::run(t);
+ break_optimization(0);
+ return 0;
+ }
+};
+
+template<>
+struct DeepStack<0> {
+ static void *run(void *t) {
+ MallocThread(t);
+ return 0;
+ }
+};
+
+// Build with -Dstandalone_malloc_test=main to make it a separate program.
+int standalone_malloc_test() {
+ pthread_t t[kNumThreds];
+ for (size_t i = 0; i < kNumThreds; i++)
+ pthread_create(&t[i], 0, DeepStack<200>::run, reinterpret_cast<void *>(i));
+ for (size_t i = 0; i < kNumThreds; i++)
+ pthread_join(t[i], 0);
+ malloc_stats();
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/tsan/analyze_libtsan.sh b/contrib/compiler-rt/lib/tsan/analyze_libtsan.sh
new file mode 100755
index 000000000000..705e4c5460f2
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/analyze_libtsan.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+set -e
+set -u
+
+get_asm() {
+ grep __tsan_$1.: -A 10000 libtsan.objdump | \
+ awk "/[^:]$/ {print;} />:/ {c++; if (c == 2) {exit}}"
+}
+
+list="write1 \
+ write2 \
+ write4 \
+ write8 \
+ read1 \
+ read2 \
+ read4 \
+ read8 \
+ func_entry \
+ func_exit"
+
+BIN=`dirname $0`/tsan_test
+objdump -d $BIN > libtsan.objdump
+nm -S $BIN | grep "__tsan_" > libtsan.nm
+
+for f in $list; do
+ file=asm_$f.s
+ get_asm $f > $file
+ tot=$(wc -l < $file)
+ size=$(grep __tsan_$f$ libtsan.nm | awk --non-decimal-data '{print ("0x"$2)+0}')
+ rsp=$(grep '(%rsp)' $file | wc -l)
+ push=$(grep 'push' $file | wc -l)
+ pop=$(grep 'pop' $file | wc -l)
+ call=$(grep 'call' $file | wc -l)
+ load=$(egrep 'mov .*\,.*\(.*\)|cmp .*\,.*\(.*\)' $file | wc -l)
+ store=$(egrep 'mov .*\(.*\),' $file | wc -l)
+ mov=$(grep 'mov' $file | wc -l)
+ lea=$(grep 'lea' $file | wc -l)
+ sh=$(grep 'shr\|shl' $file | wc -l)
+ cmp=$(grep 'cmp\|test' $file | wc -l)
+ printf "%10s tot %3d; size %4d; rsp %d; push %d; pop %d; call %d; load %2d; store %2d; sh %3d; mov %3d; lea %3d; cmp %3d\n" \
+ $f $tot $size $rsp $push $pop $call $load $store $sh $mov $lea $cmp;
+done
diff --git a/contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_local.cc b/contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_local.cc
new file mode 100644
index 000000000000..accdcb63878f
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_local.cc
@@ -0,0 +1,49 @@
+// Mini-benchmark for tsan: non-shared memory writes.
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int len;
+int *a;
+const int kNumIter = 1000;
+
+__attribute__((noinline))
+void Run(int idx) {
+ for (int i = 0, n = len; i < n; i++)
+ a[i + idx * n] = i;
+}
+
+void *Thread(void *arg) {
+ long idx = (long)arg;
+ printf("Thread %ld started\n", idx);
+ for (int i = 0; i < kNumIter; i++)
+ Run(idx);
+ printf("Thread %ld done\n", idx);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int n_threads = 0;
+ if (argc != 3) {
+ n_threads = 4;
+ len = 1000000;
+ } else {
+ n_threads = atoi(argv[1]);
+ assert(n_threads > 0 && n_threads <= 32);
+ len = atoi(argv[2]);
+ }
+ printf("%s: n_threads=%d len=%d iter=%d\n",
+ __FILE__, n_threads, len, kNumIter);
+ a = new int[n_threads * len];
+ pthread_t *t = new pthread_t[n_threads];
+ for (int i = 0; i < n_threads; i++) {
+ pthread_create(&t[i], 0, Thread, (void*)i);
+ }
+ for (int i = 0; i < n_threads; i++) {
+ pthread_join(t[i], 0);
+ }
+ delete [] t;
+ delete [] a;
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_shared.cc b/contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_shared.cc
new file mode 100644
index 000000000000..f9b9f42f78a4
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/benchmarks/mini_bench_shared.cc
@@ -0,0 +1,51 @@
+// Mini-benchmark for tsan: shared memory reads.
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int len;
+int *a;
+const int kNumIter = 1000;
+
+__attribute__((noinline))
+void Run(int idx) {
+ for (int i = 0, n = len; i < n; i++)
+ if (a[i] != i) abort();
+}
+
+void *Thread(void *arg) {
+ long idx = (long)arg;
+ printf("Thread %ld started\n", idx);
+ for (int i = 0; i < kNumIter; i++)
+ Run(idx);
+ printf("Thread %ld done\n", idx);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int n_threads = 0;
+ if (argc != 3) {
+ n_threads = 4;
+ len = 1000000;
+ } else {
+ n_threads = atoi(argv[1]);
+ assert(n_threads > 0 && n_threads <= 32);
+ len = atoi(argv[2]);
+ }
+ printf("%s: n_threads=%d len=%d iter=%d\n",
+ __FILE__, n_threads, len, kNumIter);
+ a = new int[len];
+ for (int i = 0, n = len; i < n; i++)
+ a[i] = i;
+ pthread_t *t = new pthread_t[n_threads];
+ for (int i = 0; i < n_threads; i++) {
+ pthread_create(&t[i], 0, Thread, (void*)i);
+ }
+ for (int i = 0; i < n_threads; i++) {
+ pthread_join(t[i], 0);
+ }
+ delete [] t;
+ delete [] a;
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/tsan/benchmarks/start_many_threads.cc b/contrib/compiler-rt/lib/tsan/benchmarks/start_many_threads.cc
new file mode 100644
index 000000000000..1e86fa6c502e
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/benchmarks/start_many_threads.cc
@@ -0,0 +1,52 @@
+// Mini-benchmark for creating a lot of threads.
+//
+// Some facts:
+// a) clang -O1 takes <15ms to start N=500 threads,
+// consuming ~4MB more RAM than N=1.
+// b) clang -O1 -ftsan takes ~26s to start N=500 threads,
+// eats 5GB more RAM than N=1 (which is somewhat expected but still a lot)
+// but then it consumes ~4GB of extra memory when the threads shut down!
+// (definitely not in the barrier_wait interceptor)
+// Also, it takes 26s to run with N=500 vs just 1.1s to run with N=1.
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_barrier_t all_threads_ready;
+
+void* Thread(void *unused) {
+ pthread_barrier_wait(&all_threads_ready);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int n_threads;
+ if (argc == 1) {
+ n_threads = 100;
+ } else if (argc == 2) {
+ n_threads = atoi(argv[1]);
+ } else {
+ printf("Usage: %s n_threads\n", argv[0]);
+ return 1;
+ }
+ printf("%s: n_threads=%d\n", __FILE__, n_threads);
+
+ pthread_barrier_init(&all_threads_ready, NULL, n_threads + 1);
+
+ pthread_t *t = new pthread_t[n_threads];
+ for (int i = 0; i < n_threads; i++) {
+ int status = pthread_create(&t[i], 0, Thread, (void*)i);
+ assert(status == 0);
+ }
+ // sleep(5); // FIXME: simplify measuring the memory usage.
+ pthread_barrier_wait(&all_threads_ready);
+ for (int i = 0; i < n_threads; i++) {
+ pthread_join(t[i], 0);
+ }
+ // sleep(5); // FIXME: simplify measuring the memory usage.
+ delete [] t;
+
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/tsan/benchmarks/vts_many_threads_bench.cc b/contrib/compiler-rt/lib/tsan/benchmarks/vts_many_threads_bench.cc
new file mode 100644
index 000000000000..f1056e20c874
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/benchmarks/vts_many_threads_bench.cc
@@ -0,0 +1,120 @@
+// Mini-benchmark for tsan VTS worst case performance
+// Idea:
+// 1) Spawn M + N threads (M >> N)
+// We'll call the 'M' threads as 'garbage threads'.
+// 2) Make sure all threads have created thus no TIDs were reused
+// 3) Join the garbage threads
+// 4) Do many sync operations on the remaining N threads
+//
+// It turns out that due to O(M+N) VTS complexity the (4) is much slower with
+// when N is large.
+//
+// Some numbers:
+// a) clang++ native O1 with n_iterations=200kk takes
+// 5s regardless of M
+// clang++ tsanv2 O1 with n_iterations=20kk takes
+// 23.5s with M=200
+// 11.5s with M=1
+// i.e. tsanv2 is ~23x to ~47x slower than native, depends on M.
+// b) g++ native O1 with n_iterations=200kk takes
+// 5.5s regardless of M
+// g++ tsanv1 O1 with n_iterations=2kk takes
+// 39.5s with M=200
+// 20.5s with M=1
+// i.e. tsanv1 is ~370x to ~720x slower than native, depends on M.
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+class __attribute__((aligned(64))) Mutex {
+ public:
+ Mutex() { pthread_mutex_init(&m_, NULL); }
+ ~Mutex() { pthread_mutex_destroy(&m_); }
+ void Lock() { pthread_mutex_lock(&m_); }
+ void Unlock() { pthread_mutex_unlock(&m_); }
+
+ private:
+ pthread_mutex_t m_;
+};
+
+const int kNumMutexes = 1024;
+Mutex mutexes[kNumMutexes];
+
+int n_threads, n_iterations;
+
+pthread_barrier_t all_threads_ready, main_threads_ready;
+
+void* GarbageThread(void *unused) {
+ pthread_barrier_wait(&all_threads_ready);
+ return 0;
+}
+
+void *Thread(void *arg) {
+ long idx = (long)arg;
+ pthread_barrier_wait(&all_threads_ready);
+
+ // Wait for the main thread to join the garbage threads.
+ pthread_barrier_wait(&main_threads_ready);
+
+ printf("Thread %ld go!\n", idx);
+ int offset = idx * kNumMutexes / n_threads;
+ for (int i = 0; i < n_iterations; i++) {
+ mutexes[(offset + i) % kNumMutexes].Lock();
+ mutexes[(offset + i) % kNumMutexes].Unlock();
+ }
+ printf("Thread %ld done\n", idx);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int n_garbage_threads;
+ if (argc == 1) {
+ n_threads = 2;
+ n_garbage_threads = 200;
+ n_iterations = 20000000;
+ } else if (argc == 4) {
+ n_threads = atoi(argv[1]);
+ assert(n_threads > 0 && n_threads <= 32);
+ n_garbage_threads = atoi(argv[2]);
+ assert(n_garbage_threads > 0 && n_garbage_threads <= 16000);
+ n_iterations = atoi(argv[3]);
+ } else {
+ printf("Usage: %s n_threads n_garbage_threads n_iterations\n", argv[0]);
+ return 1;
+ }
+ printf("%s: n_threads=%d n_garbage_threads=%d n_iterations=%d\n",
+ __FILE__, n_threads, n_garbage_threads, n_iterations);
+
+ pthread_barrier_init(&all_threads_ready, NULL, n_garbage_threads + n_threads + 1);
+ pthread_barrier_init(&main_threads_ready, NULL, n_threads + 1);
+
+ pthread_t *t = new pthread_t[n_threads];
+ {
+ pthread_t *g_t = new pthread_t[n_garbage_threads];
+ for (int i = 0; i < n_garbage_threads; i++) {
+ int status = pthread_create(&g_t[i], 0, GarbageThread, NULL);
+ assert(status == 0);
+ }
+ for (int i = 0; i < n_threads; i++) {
+ int status = pthread_create(&t[i], 0, Thread, (void*)i);
+ assert(status == 0);
+ }
+ pthread_barrier_wait(&all_threads_ready);
+ printf("All threads started! Killing the garbage threads.\n");
+ for (int i = 0; i < n_garbage_threads; i++) {
+ pthread_join(g_t[i], 0);
+ }
+ delete [] g_t;
+ }
+ printf("Resuming the main threads.\n");
+ pthread_barrier_wait(&main_threads_ready);
+
+
+ for (int i = 0; i < n_threads; i++) {
+ pthread_join(t[i], 0);
+ }
+ delete [] t;
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/tsan/check_analyze.sh b/contrib/compiler-rt/lib/tsan/check_analyze.sh
new file mode 100755
index 000000000000..4b33393ef648
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/check_analyze.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+set -u
+
+RES=$(./analyze_libtsan.sh)
+PrintRes() {
+ printf "%s\n" "$RES"
+}
+
+PrintRes
+
+check() {
+ res=$(PrintRes | egrep "$1 .* $2 $3; ")
+ if [ "$res" == "" ]; then
+ echo FAILED $1 must contain $2 $3
+ exit 1
+ fi
+}
+
+for f in write1; do
+ check $f rsp 1
+ check $f push 2
+ check $f pop 2
+done
+
+for f in write2 write4 write8; do
+ check $f rsp 1
+ check $f push 3
+ check $f pop 3
+done
+
+for f in read1 read2 read4 read8; do
+ check $f rsp 1
+ check $f push 5
+ check $f pop 5
+done
+
+for f in func_entry func_exit; do
+ check $f rsp 0
+ check $f push 0
+ check $f pop 0
+ check $f call 1 # TraceSwitch()
+done
+
+echo LGTM
diff --git a/contrib/compiler-rt/lib/tsan/check_cmake.sh b/contrib/compiler-rt/lib/tsan/check_cmake.sh
new file mode 100755
index 000000000000..7668c5b49e1a
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/check_cmake.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -u
+set -e
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+if [ -d "$ROOT/llvm-build" ]; then
+ cd $ROOT/llvm-build
+else
+ mkdir -p $ROOT/llvm-build
+ cd $ROOT/llvm-build
+ CC=clang CXX=clang++ cmake -G Ninja -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
+fi
+ninja
+ninja check-sanitizer
+ninja check-tsan
+ninja check-asan
+ninja check-msan
+ninja check-lsan
diff --git a/contrib/compiler-rt/lib/tsan/check_memcpy.sh b/contrib/compiler-rt/lib/tsan/check_memcpy.sh
new file mode 100755
index 000000000000..101df1166b7c
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/check_memcpy.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Ensure that tsan runtime does not contain compiler-emitted memcpy and memset calls.
+
+set -eu
+
+ROOTDIR=$(dirname $0)
+TEST_DIR=$ROOTDIR/../../test/tsan
+
+: ${CXX:=clang++}
+CFLAGS="-fsanitize=thread -fPIE -O1 -g"
+LDFLAGS="-pie -lpthread -ldl -lrt -lm -Wl,--whole-archive $ROOTDIR/rtl/libtsan.a -Wl,--no-whole-archive"
+
+SRC=$TEST_DIR/simple_race.cc
+OBJ=$SRC.o
+EXE=$SRC.exe
+$CXX $SRC $CFLAGS -c -o $OBJ
+$CXX $OBJ $LDFLAGS -o $EXE
+
+NCALL=$(objdump -d $EXE | egrep "callq .*<__interceptor_mem(cpy|set)>" | wc -l)
+if [ "$NCALL" != "0" ]; then
+ echo FAIL: found $NCALL memcpy/memset calls
+ exit 1
+fi
+
+# tail calls
+NCALL=$(objdump -d $EXE | egrep "jmpq .*<__interceptor_mem(cpy|set)>" | wc -l)
+if [ "$NCALL" != "0" ]; then
+ echo FAIL: found $NCALL memcpy/memset calls
+ exit 1
+fi
diff --git a/contrib/compiler-rt/lib/tsan/dd/dd_interceptors.cc b/contrib/compiler-rt/lib/tsan/dd/dd_interceptors.cc
new file mode 100644
index 000000000000..8151f7fd3c67
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/dd/dd_interceptors.cc
@@ -0,0 +1,333 @@
+//===-- dd_interceptors.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "dd_rtl.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include <pthread.h>
+#include <stdlib.h>
+
+using namespace __dsan;
+
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void __libc_free(void *ptr);
+
+__attribute__((tls_model("initial-exec")))
+static __thread Thread *thr;
+__attribute__((tls_model("initial-exec")))
+static __thread volatile int initing;
+static bool inited;
+static uptr g_data_start;
+static uptr g_data_end;
+
+static bool InitThread() {
+ if (initing)
+ return false;
+ if (thr != 0)
+ return true;
+ initing = true;
+ if (!inited) {
+ inited = true;
+ Initialize();
+ }
+ thr = (Thread*)InternalAlloc(sizeof(*thr));
+ internal_memset(thr, 0, sizeof(*thr));
+ ThreadInit(thr);
+ initing = false;
+ return true;
+}
+
+INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) {
+ InitThread();
+ MutexDestroy(thr, (uptr)m);
+ return REAL(pthread_mutex_destroy)(m);
+}
+
+INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_mutex_lock)(m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) {
+ InitThread();
+ int res = REAL(pthread_mutex_trylock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) {
+ InitThread();
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ return REAL(pthread_mutex_unlock)(m);
+}
+
+INTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_spin_destroy)(m);
+ MutexDestroy(thr, (uptr)m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_spin_lock)(m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_spin_trylock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) {
+ InitThread();
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ return REAL(pthread_spin_unlock)(m);
+}
+
+INTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) {
+ InitThread();
+ MutexDestroy(thr, (uptr)m);
+ return REAL(pthread_rwlock_destroy)(m);
+}
+
+INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, false);
+ int res = REAL(pthread_rwlock_rdlock)(m);
+ MutexAfterLock(thr, (uptr)m, false, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_rwlock_tryrdlock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, false, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m,
+ const timespec *abstime) {
+ InitThread();
+ int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, false, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_rwlock_wrlock)(m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_rwlock_trywrlock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m,
+ const timespec *abstime) {
+ InitThread();
+ int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) {
+ InitThread();
+ MutexBeforeUnlock(thr, (uptr)m, true); // note: not necessary write unlock
+ return REAL(pthread_rwlock_unlock)(m);
+}
+
+static pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) {
+ atomic_uintptr_t *p = (atomic_uintptr_t*)c;
+ uptr cond = atomic_load(p, memory_order_acquire);
+ if (!force && cond != 0)
+ return (pthread_cond_t*)cond;
+ void *newcond = malloc(sizeof(pthread_cond_t));
+ internal_memset(newcond, 0, sizeof(pthread_cond_t));
+ if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
+ memory_order_acq_rel))
+ return (pthread_cond_t*)newcond;
+ free(newcond);
+ return (pthread_cond_t*)cond;
+}
+
+INTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c,
+ const pthread_condattr_t *a) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c, true);
+ return REAL(pthread_cond_init)(cond, a);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_cond_wait)(cond, m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m,
+ const timespec *abstime) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_cond_timedwait)(cond, m, abstime);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ int res = REAL(pthread_cond_destroy)(cond);
+ free(cond);
+ atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
+ return res;
+}
+
+// for symbolizer
+INTERCEPTOR(char*, realpath, const char *path, char *resolved_path) {
+ InitThread();
+ return REAL(realpath)(path, resolved_path);
+}
+
+INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
+ InitThread();
+ return REAL(read)(fd, ptr, count);
+}
+
+INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ InitThread();
+ return REAL(pread)(fd, ptr, count, offset);
+}
+
+extern "C" {
+void __dsan_before_mutex_lock(uptr m, int writelock) {
+ if (!InitThread())
+ return;
+ MutexBeforeLock(thr, m, writelock);
+}
+
+void __dsan_after_mutex_lock(uptr m, int writelock, int trylock) {
+ if (!InitThread())
+ return;
+ MutexAfterLock(thr, m, writelock, trylock);
+}
+
+void __dsan_before_mutex_unlock(uptr m, int writelock) {
+ if (!InitThread())
+ return;
+ MutexBeforeUnlock(thr, m, writelock);
+}
+
+void __dsan_mutex_destroy(uptr m) {
+ if (!InitThread())
+ return;
+ // if (m >= g_data_start && m < g_data_end)
+ // return;
+ MutexDestroy(thr, m);
+}
+} // extern "C"
+
+namespace __dsan {
+
+static void InitDataSeg() {
+ MemoryMappingLayout proc_maps(true);
+ uptr start, end, offset;
+ char name[128];
+ bool prev_is_data = false;
+ while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+ /*protection*/ 0)) {
+ bool is_data = offset != 0 && name[0] != 0;
+ // BSS may get merged with [heap] in /proc/self/maps. This is not very
+ // reliable.
+ bool is_bss = offset == 0 &&
+ (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
+ if (g_data_start == 0 && is_data)
+ g_data_start = start;
+ if (is_bss)
+ g_data_end = end;
+ prev_is_data = is_data;
+ }
+ VPrintf(1, "guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
+ CHECK_LT(g_data_start, g_data_end);
+ CHECK_GE((uptr)&g_data_start, g_data_start);
+ CHECK_LT((uptr)&g_data_start, g_data_end);
+}
+
+void InitializeInterceptors() {
+ INTERCEPT_FUNCTION(pthread_mutex_destroy);
+ INTERCEPT_FUNCTION(pthread_mutex_lock);
+ INTERCEPT_FUNCTION(pthread_mutex_trylock);
+ INTERCEPT_FUNCTION(pthread_mutex_unlock);
+
+ INTERCEPT_FUNCTION(pthread_spin_destroy);
+ INTERCEPT_FUNCTION(pthread_spin_lock);
+ INTERCEPT_FUNCTION(pthread_spin_trylock);
+ INTERCEPT_FUNCTION(pthread_spin_unlock);
+
+ INTERCEPT_FUNCTION(pthread_rwlock_destroy);
+ INTERCEPT_FUNCTION(pthread_rwlock_rdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_wrlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_trywrlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_unlock);
+
+ INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+
+ // for symbolizer
+ INTERCEPT_FUNCTION(realpath);
+ INTERCEPT_FUNCTION(read);
+ INTERCEPT_FUNCTION(pread);
+
+ InitDataSeg();
+}
+
+} // namespace __dsan
diff --git a/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc b/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc
new file mode 100644
index 000000000000..99b8ee597cd1
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc
@@ -0,0 +1,159 @@
+//===-- dd_rtl.cc ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "dd_rtl.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __dsan {
+
+static Context *ctx;
+
+static u32 CurrentStackTrace(Thread *thr, uptr skip) {
+ BufferedStackTrace stack;
+ thr->ignore_interceptors = true;
+ stack.Unwind(1000, 0, 0, 0, 0, 0, false);
+ thr->ignore_interceptors = false;
+ if (stack.size <= skip)
+ return 0;
+ return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
+}
+
+static void PrintStackTrace(Thread *thr, u32 stk) {
+ StackTrace stack = StackDepotGet(stk);
+ thr->ignore_interceptors = true;
+ stack.Print();
+ thr->ignore_interceptors = false;
+}
+
+static void ReportDeadlock(Thread *thr, DDReport *rep) {
+ if (rep == 0)
+ return;
+ BlockingMutexLock lock(&ctx->report_mutex);
+ Printf("==============================\n");
+ Printf("WARNING: lock-order-inversion (potential deadlock)\n");
+ for (int i = 0; i < rep->n; i++) {
+ Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
+ rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
+ PrintStackTrace(thr, rep->loop[i].stk[1]);
+ if (rep->loop[i].stk[0]) {
+ Printf("Mutex %llu was acquired here:\n",
+ rep->loop[i].mtx_ctx0);
+ PrintStackTrace(thr, rep->loop[i].stk[0]);
+ }
+ }
+ Printf("==============================\n");
+}
+
+Callback::Callback(Thread *thr)
+ : thr(thr) {
+ lt = thr->dd_lt;
+ pt = thr->dd_pt;
+}
+
+u32 Callback::Unwind() {
+ return CurrentStackTrace(thr, 3);
+}
+
+static void InitializeFlags() {
+ Flags *f = flags();
+
+ // Default values.
+ f->second_deadlock_stack = false;
+
+ SetCommonFlagsDefaults();
+ {
+ // Override some common flags defaults.
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.allow_addr2line = true;
+ OverrideCommonFlags(cf);
+ }
+
+ // Override from command line.
+ FlagParser parser;
+ RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
+ RegisterCommonFlags(&parser);
+ parser.ParseString(GetEnv("DSAN_OPTIONS"));
+ SetVerbosity(common_flags()->verbosity);
+}
+
+void Initialize() {
+ static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
+ ctx = new(ctx_mem) Context();
+
+ InitializeInterceptors();
+ InitializeFlags();
+ ctx->dd = DDetector::Create(flags());
+}
+
+void ThreadInit(Thread *thr) {
+ static atomic_uintptr_t id_gen;
+ uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
+ thr->dd_pt = ctx->dd->CreatePhysicalThread();
+ thr->dd_lt = ctx->dd->CreateLogicalThread(id);
+}
+
+void ThreadDestroy(Thread *thr) {
+ ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+ ctx->dd->DestroyLogicalThread(thr->dd_lt);
+}
+
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ if (h.created())
+ ctx->dd->MutexInit(&cb, &h->dd);
+ ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ if (h.created())
+ ctx->dd->MutexInit(&cb, &h->dd);
+ ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexDestroy(Thread *thr, uptr m) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ MutexHashMap::Handle h(&ctx->mutex_map, m, true);
+ if (!h.exists())
+ return;
+ ctx->dd->MutexDestroy(&cb, &h->dd);
+}
+
+} // namespace __dsan
diff --git a/contrib/compiler-rt/lib/tsan/dd/dd_rtl.h b/contrib/compiler-rt/lib/tsan/dd/dd_rtl.h
new file mode 100644
index 000000000000..bb1b20205b54
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/dd/dd_rtl.h
@@ -0,0 +1,67 @@
+//===-- dd_rtl.h ----------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DD_RTL_H
+#define DD_RTL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_addrhashmap.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+
+namespace __dsan {
+
+typedef DDFlags Flags;
+
+struct Mutex {
+ DDMutex dd;
+};
+
+struct Thread {
+ DDPhysicalThread *dd_pt;
+ DDLogicalThread *dd_lt;
+
+ bool ignore_interceptors;
+};
+
+struct Callback : DDCallback {
+ Thread *thr;
+
+ Callback(Thread *thr);
+ virtual u32 Unwind();
+};
+
+typedef AddrHashMap<Mutex, 31051> MutexHashMap;
+
+struct Context {
+ DDetector *dd;
+
+ BlockingMutex report_mutex;
+ MutexHashMap mutex_map;
+};
+
+inline Flags* flags() {
+ static Flags flags;
+ return &flags;
+}
+
+void Initialize();
+void InitializeInterceptors();
+
+void ThreadInit(Thread *thr);
+void ThreadDestroy(Thread *thr);
+
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock);
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock);
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock);
+void MutexDestroy(Thread *thr, uptr m);
+
+} // namespace __dsan
+#endif // DD_RTL_H
diff --git a/contrib/compiler-rt/lib/tsan/go/build.bat b/contrib/compiler-rt/lib/tsan/go/build.bat
new file mode 100644
index 000000000000..7d393dc0e025
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/go/build.bat
@@ -0,0 +1,4 @@
+type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc ..\..\sanitizer_common\sanitizer_flag_parser.cc ..\..\sanitizer_common\sanitizer_symbolizer.cc > gotsan.cc
+
+gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -Wno-maybe-uninitialized -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer -std=c++11
+
diff --git a/contrib/compiler-rt/lib/tsan/go/buildgo.sh b/contrib/compiler-rt/lib/tsan/go/buildgo.sh
new file mode 100755
index 000000000000..5ac60349e081
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/go/buildgo.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+set -e
+
+SRCS="
+ tsan_go.cc
+ ../rtl/tsan_clock.cc
+ ../rtl/tsan_flags.cc
+ ../rtl/tsan_interface_atomic.cc
+ ../rtl/tsan_md5.cc
+ ../rtl/tsan_mutex.cc
+ ../rtl/tsan_report.cc
+ ../rtl/tsan_rtl.cc
+ ../rtl/tsan_rtl_mutex.cc
+ ../rtl/tsan_rtl_report.cc
+ ../rtl/tsan_rtl_thread.cc
+ ../rtl/tsan_stack_trace.cc
+ ../rtl/tsan_stat.cc
+ ../rtl/tsan_suppressions.cc
+ ../rtl/tsan_sync.cc
+ ../../sanitizer_common/sanitizer_allocator.cc
+ ../../sanitizer_common/sanitizer_common.cc
+ ../../sanitizer_common/sanitizer_deadlock_detector2.cc
+ ../../sanitizer_common/sanitizer_flag_parser.cc
+ ../../sanitizer_common/sanitizer_flags.cc
+ ../../sanitizer_common/sanitizer_libc.cc
+ ../../sanitizer_common/sanitizer_persistent_allocator.cc
+ ../../sanitizer_common/sanitizer_printf.cc
+ ../../sanitizer_common/sanitizer_suppressions.cc
+ ../../sanitizer_common/sanitizer_thread_registry.cc
+ ../../sanitizer_common/sanitizer_stackdepot.cc
+ ../../sanitizer_common/sanitizer_stacktrace.cc
+ ../../sanitizer_common/sanitizer_symbolizer.cc
+"
+
+if [ "`uname -a | grep Linux`" != "" ]; then
+ SUFFIX="linux_amd64"
+ OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option"
+ OSLDFLAGS="-lpthread -fPIC -fpie"
+ SRCS="
+ $SRCS
+ ../rtl/tsan_platform_linux.cc
+ ../../sanitizer_common/sanitizer_posix.cc
+ ../../sanitizer_common/sanitizer_posix_libcdep.cc
+ ../../sanitizer_common/sanitizer_procmaps_common.cc
+ ../../sanitizer_common/sanitizer_procmaps_linux.cc
+ ../../sanitizer_common/sanitizer_linux.cc
+ ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+ "
+elif [ "`uname -a | grep FreeBSD`" != "" ]; then
+ SUFFIX="freebsd_amd64"
+ OSCFLAGS="-fno-strict-aliasing -fPIC -Werror"
+ OSLDFLAGS="-lpthread -fPIC -fpie"
+ SRCS="
+ $SRCS
+ ../rtl/tsan_platform_linux.cc
+ ../../sanitizer_common/sanitizer_posix.cc
+ ../../sanitizer_common/sanitizer_posix_libcdep.cc
+ ../../sanitizer_common/sanitizer_procmaps_common.cc
+ ../../sanitizer_common/sanitizer_procmaps_freebsd.cc
+ ../../sanitizer_common/sanitizer_linux.cc
+ ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+ "
+elif [ "`uname -a | grep Darwin`" != "" ]; then
+ SUFFIX="darwin_amd64"
+ OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option"
+ OSLDFLAGS="-lpthread -fPIC -fpie"
+ SRCS="
+ $SRCS
+ ../rtl/tsan_platform_mac.cc
+ ../../sanitizer_common/sanitizer_mac.cc
+ ../../sanitizer_common/sanitizer_posix.cc
+ ../../sanitizer_common/sanitizer_posix_libcdep.cc
+ ../../sanitizer_common/sanitizer_procmaps_mac.cc
+ "
+elif [ "`uname -a | grep MINGW`" != "" ]; then
+ SUFFIX="windows_amd64"
+ OSCFLAGS="-Wno-error=attributes -Wno-attributes -Wno-unused-const-variable -Wno-unknown-warning-option"
+ OSLDFLAGS=""
+ SRCS="
+ $SRCS
+ ../rtl/tsan_platform_windows.cc
+ ../../sanitizer_common/sanitizer_win.cc
+ "
+else
+ echo Unknown platform
+ exit 1
+fi
+
+CC=${CC:-gcc}
+IN_TMPDIR=${IN_TMPDIR:-0}
+SILENT=${SILENT:-0}
+
+if [ $IN_TMPDIR != "0" ]; then
+ DIR=$(mktemp -qd /tmp/gotsan.XXXXXXXXXX)
+ cleanup() {
+ rm -rf $DIR
+ }
+ trap cleanup EXIT
+else
+ DIR=.
+fi
+
+SRCS="$SRCS $ADD_SRCS"
+
+rm -f $DIR/gotsan.cc
+for F in $SRCS; do
+ cat $F >> $DIR/gotsan.cc
+done
+
+FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -std=c++11 -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS"
+if [ "$DEBUG" = "" ]; then
+ FLAGS="$FLAGS -DSANITIZER_DEBUG=0 -O3 -msse3 -fomit-frame-pointer"
+else
+ FLAGS="$FLAGS -DSANITIZER_DEBUG=1 -g"
+fi
+
+if [ "$SILENT" != "1" ]; then
+ echo $CC gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS
+fi
+$CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS
+
+$CC test.c $DIR/race_$SUFFIX.syso -m64 -o $DIR/test $OSLDFLAGS
+
+export GORACE="exitcode=0 atexit_sleep_ms=0"
+if [ "$SILENT" != "1" ]; then
+ $DIR/test
+else
+ $DIR/test 2>/dev/null
+fi
diff --git a/contrib/compiler-rt/lib/tsan/go/test.c b/contrib/compiler-rt/lib/tsan/go/test.c
new file mode 100644
index 000000000000..94433f1b8c22
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/go/test.c
@@ -0,0 +1,65 @@
+//===-- test.c ------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanity test for Go runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+void __tsan_init(void **thr, void (*cb)(void*));
+void __tsan_fini();
+void __tsan_map_shadow(void *addr, unsigned long size);
+void __tsan_go_start(void *thr, void **chthr, void *pc);
+void __tsan_go_end(void *thr);
+void __tsan_read(void *thr, void *addr, void *pc);
+void __tsan_write(void *thr, void *addr, void *pc);
+void __tsan_func_enter(void *thr, void *pc);
+void __tsan_func_exit(void *thr);
+void __tsan_malloc(void *p, unsigned long sz);
+void __tsan_acquire(void *thr, void *addr);
+void __tsan_release(void *thr, void *addr);
+void __tsan_release_merge(void *thr, void *addr);
+
+void symbolize_cb(void *ctx) {}
+
+char buf0[100<<10];
+
+void foobar() {}
+void barfoo() {}
+
+int main(void) {
+ void *thr0 = 0;
+ char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1));
+ __tsan_malloc(buf, 10);
+ __tsan_init(&thr0, symbolize_cb);
+ __tsan_map_shadow(buf, 4096);
+ __tsan_func_enter(thr0, (char*)&main + 1);
+ __tsan_malloc(buf, 10);
+ __tsan_release(thr0, buf);
+ __tsan_release_merge(thr0, buf);
+ void *thr1 = 0;
+ __tsan_go_start(thr0, &thr1, (char*)&barfoo + 1);
+ void *thr2 = 0;
+ __tsan_go_start(thr0, &thr2, (char*)&barfoo + 1);
+ __tsan_func_enter(thr1, (char*)&foobar + 1);
+ __tsan_func_enter(thr1, (char*)&foobar + 1);
+ __tsan_write(thr1, buf, (char*)&barfoo + 1);
+ __tsan_acquire(thr1, buf);
+ __tsan_func_exit(thr1);
+ __tsan_func_exit(thr1);
+ __tsan_go_end(thr1);
+ __tsan_func_enter(thr2, (char*)&foobar + 1);
+ __tsan_read(thr2, buf, (char*)&barfoo + 1);
+ __tsan_func_exit(thr2);
+ __tsan_go_end(thr2);
+ __tsan_func_exit(thr0);
+ __tsan_fini();
+ return 0;
+}
diff --git a/contrib/compiler-rt/lib/tsan/go/tsan_go.cc b/contrib/compiler-rt/lib/tsan/go/tsan_go.cc
new file mode 100644
index 000000000000..ea0beb74215b
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/go/tsan_go.cc
@@ -0,0 +1,211 @@
+//===-- tsan_go.cc --------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ThreadSanitizer runtime for Go language.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_rtl.h"
+#include "tsan_symbolize.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include <stdlib.h>
+
+namespace __tsan {
+
+void InitializeInterceptors() {
+}
+
+void InitializeDynamicAnnotations() {
+}
+
+bool IsExpectedReport(uptr addr, uptr size) {
+ return false;
+}
+
+ReportLocation *SymbolizeData(uptr addr) {
+ return 0;
+}
+
+void *internal_alloc(MBlockType typ, uptr sz) {
+ return InternalAlloc(sz);
+}
+
+void internal_free(void *p) {
+ InternalFree(p);
+}
+
+struct SymbolizeContext {
+ uptr pc;
+ char *func;
+ char *file;
+ uptr line;
+ uptr off;
+ uptr res;
+};
+
+// Callback into Go.
+static void (*symbolize_cb)(SymbolizeContext *ctx);
+
+SymbolizedStack *SymbolizeCode(uptr addr) {
+ SymbolizedStack *s = SymbolizedStack::New(addr);
+ SymbolizeContext ctx;
+ internal_memset(&ctx, 0, sizeof(ctx));
+ ctx.pc = addr;
+ symbolize_cb(&ctx);
+ if (ctx.res) {
+ AddressInfo &info = s->info;
+ info.module_offset = ctx.off;
+ info.function = internal_strdup(ctx.func ? ctx.func : "??");
+ info.file = internal_strdup(ctx.file ? ctx.file : "-");
+ info.line = ctx.line;
+ info.column = 0;
+ }
+ return s;
+}
+
+extern "C" {
+
+static ThreadState *main_thr;
+static bool inited;
+
+static ThreadState *AllocGoroutine() {
+ ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
+ sizeof(ThreadState));
+ internal_memset(thr, 0, sizeof(*thr));
+ return thr;
+}
+
+void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) {
+ symbolize_cb = cb;
+ ThreadState *thr = AllocGoroutine();
+ main_thr = *thrp = thr;
+ Initialize(thr);
+ inited = true;
+}
+
+void __tsan_fini() {
+ // FIXME: Not necessary thread 0.
+ ThreadState *thr = main_thr;
+ int res = Finalize(thr);
+ exit(res);
+}
+
+void __tsan_map_shadow(uptr addr, uptr size) {
+ MapShadow(addr, size);
+}
+
+void __tsan_read(ThreadState *thr, void *addr, void *pc) {
+ MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
+}
+
+void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
+ if (callpc != 0)
+ FuncEntry(thr, callpc);
+ MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
+ if (callpc != 0)
+ FuncExit(thr);
+}
+
+void __tsan_write(ThreadState *thr, void *addr, void *pc) {
+ MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
+}
+
+void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
+ if (callpc != 0)
+ FuncEntry(thr, callpc);
+ MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
+ if (callpc != 0)
+ FuncExit(thr);
+}
+
+void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
+ MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
+}
+
+void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
+ MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
+}
+
+void __tsan_func_enter(ThreadState *thr, void *pc) {
+ FuncEntry(thr, (uptr)pc);
+}
+
+void __tsan_func_exit(ThreadState *thr) {
+ FuncExit(thr);
+}
+
+void __tsan_malloc(void *p, uptr sz) {
+ if (!inited)
+ return;
+ MemoryResetRange(0, 0, (uptr)p, sz);
+}
+
+void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
+ ThreadState *thr = AllocGoroutine();
+ *pthr = thr;
+ int goid = ThreadCreate(parent, (uptr)pc, 0, true);
+ ThreadStart(thr, goid, 0);
+}
+
+void __tsan_go_end(ThreadState *thr) {
+ ThreadFinish(thr);
+ internal_free(thr);
+}
+
+void __tsan_acquire(ThreadState *thr, void *addr) {
+ Acquire(thr, 0, (uptr)addr);
+}
+
+void __tsan_release(ThreadState *thr, void *addr) {
+ ReleaseStore(thr, 0, (uptr)addr);
+}
+
+void __tsan_release_merge(ThreadState *thr, void *addr) {
+ Release(thr, 0, (uptr)addr);
+}
+
+void __tsan_finalizer_goroutine(ThreadState *thr) {
+ AcquireGlobal(thr, 0);
+}
+
+void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
+}
+
+void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
+ if (write)
+ MutexLock(thr, 0, addr);
+ else
+ MutexReadLock(thr, 0, addr);
+}
+
+void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
+ if (write)
+ MutexUnlock(thr, 0, addr);
+ else
+ MutexReadUnlock(thr, 0, addr);
+}
+
+void __tsan_go_ignore_sync_begin(ThreadState *thr) {
+ ThreadIgnoreSyncBegin(thr, 0);
+}
+
+void __tsan_go_ignore_sync_end(ThreadState *thr) {
+ ThreadIgnoreSyncEnd(thr, 0);
+}
+
+} // extern "C"
+} // namespace __tsan
+
+namespace __sanitizer {
+
+void SymbolizerPrepareForSandboxing() {
+ // Nothing to do here for Go.
+}
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan.syms.extra b/contrib/compiler-rt/lib/tsan/rtl/tsan.syms.extra
new file mode 100644
index 000000000000..49ed6b46629e
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan.syms.extra
@@ -0,0 +1,14 @@
+__tsan_init
+__tsan_read*
+__tsan_write*
+__tsan_vptr*
+__tsan_func*
+__tsan_atomic*
+__tsan_java*
+__tsan_unaligned*
+__tsan_release
+__tsan_acquire
+Annotate*
+WTFAnnotate*
+RunningOnValgrind
+ValgrindSlowdown
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc
new file mode 100644
index 000000000000..59e3de435f1b
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc
@@ -0,0 +1,429 @@
+//===-- tsan_clock.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_clock.h"
+#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+
+// SyncClock and ThreadClock implement vector clocks for sync variables
+// (mutexes, atomic variables, file descriptors, etc) and threads, respectively.
+// ThreadClock contains fixed-size vector clock for maximum number of threads.
+// SyncClock contains growable vector clock for currently necessary number of
+// threads.
+// Together they implement very simple model of operations, namely:
+//
+// void ThreadClock::acquire(const SyncClock *src) {
+// for (int i = 0; i < kMaxThreads; i++)
+// clock[i] = max(clock[i], src->clock[i]);
+// }
+//
+// void ThreadClock::release(SyncClock *dst) const {
+// for (int i = 0; i < kMaxThreads; i++)
+// dst->clock[i] = max(dst->clock[i], clock[i]);
+// }
+//
+// void ThreadClock::ReleaseStore(SyncClock *dst) const {
+// for (int i = 0; i < kMaxThreads; i++)
+// dst->clock[i] = clock[i];
+// }
+//
+// void ThreadClock::acq_rel(SyncClock *dst) {
+// acquire(dst);
+// release(dst);
+// }
+//
+// Conformance to this model is extensively verified in tsan_clock_test.cc.
+// However, the implementation is significantly more complex. The complexity
+// allows to implement important classes of use cases in O(1) instead of O(N).
+//
+// The use cases are:
+// 1. Singleton/once atomic that has a single release-store operation followed
+// by zillions of acquire-loads (the acquire-load is O(1)).
+// 2. Thread-local mutex (both lock and unlock can be O(1)).
+// 3. Leaf mutex (unlock is O(1)).
+// 4. A mutex shared by 2 threads (both lock and unlock can be O(1)).
+// 5. An atomic with a single writer (writes can be O(1)).
+// The implementation dynamically adopts to workload. So if an atomic is in
+// read-only phase, these reads will be O(1); if it later switches to read/write
+// phase, the implementation will correctly handle that by switching to O(N).
+//
+// Thread-safety note: all const operations on SyncClock's are conducted under
+// a shared lock; all non-const operations on SyncClock's are conducted under
+// an exclusive lock; ThreadClock's are private to respective threads and so
+// do not need any protection.
+//
+// Description of ThreadClock state:
+// clk_ - fixed size vector clock.
+// nclk_ - effective size of the vector clock (the rest is zeros).
+// tid_ - index of the thread associated with he clock ("current thread").
+// last_acquire_ - current thread time when it acquired something from
+// other threads.
+//
+// Description of SyncClock state:
+// clk_ - variable size vector clock, low kClkBits hold timestamp,
+// the remaining bits hold "acquired" flag (the actual value is thread's
+// reused counter);
+// if acquried == thr->reused_, then the respective thread has already
+// acquired this clock (except possibly dirty_tids_).
+// dirty_tids_ - holds up to two indeces in the vector clock that other threads
+// need to acquire regardless of "acquired" flag value;
+// release_store_tid_ - denotes that the clock state is a result of
+// release-store operation by the thread with release_store_tid_ index.
+// release_store_reused_ - reuse count of release_store_tid_.
+
+// We don't have ThreadState in these methods, so this is an ugly hack that
+// works only in C++.
+#ifndef SANITIZER_GO
+# define CPP_STAT_INC(typ) StatInc(cur_thread(), typ)
+#else
+# define CPP_STAT_INC(typ) (void)0
+#endif
+
+namespace __tsan {
+
+const unsigned kInvalidTid = (unsigned)-1;
+
+ThreadClock::ThreadClock(unsigned tid, unsigned reused)
+ : tid_(tid)
+ , reused_(reused + 1) { // 0 has special meaning
+ CHECK_LT(tid, kMaxTidInClock);
+ CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
+ nclk_ = tid_ + 1;
+ last_acquire_ = 0;
+ internal_memset(clk_, 0, sizeof(clk_));
+ clk_[tid_].reused = reused_;
+}
+
+void ThreadClock::acquire(ClockCache *c, const SyncClock *src) {
+ DCHECK_LE(nclk_, kMaxTid);
+ DCHECK_LE(src->size_, kMaxTid);
+ CPP_STAT_INC(StatClockAcquire);
+
+ // Check if it's empty -> no need to do anything.
+ const uptr nclk = src->size_;
+ if (nclk == 0) {
+ CPP_STAT_INC(StatClockAcquireEmpty);
+ return;
+ }
+
+ // Check if we've already acquired src after the last release operation on src
+ bool acquired = false;
+ if (nclk > tid_) {
+ CPP_STAT_INC(StatClockAcquireLarge);
+ if (src->elem(tid_).reused == reused_) {
+ CPP_STAT_INC(StatClockAcquireRepeat);
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ unsigned tid = src->dirty_tids_[i];
+ if (tid != kInvalidTid) {
+ u64 epoch = src->elem(tid).epoch;
+ if (clk_[tid].epoch < epoch) {
+ clk_[tid].epoch = epoch;
+ acquired = true;
+ }
+ }
+ }
+ if (acquired) {
+ CPP_STAT_INC(StatClockAcquiredSomething);
+ last_acquire_ = clk_[tid_].epoch;
+ }
+ return;
+ }
+ }
+
+ // O(N) acquire.
+ CPP_STAT_INC(StatClockAcquireFull);
+ nclk_ = max(nclk_, nclk);
+ for (uptr i = 0; i < nclk; i++) {
+ u64 epoch = src->elem(i).epoch;
+ if (clk_[i].epoch < epoch) {
+ clk_[i].epoch = epoch;
+ acquired = true;
+ }
+ }
+
+ // Remember that this thread has acquired this clock.
+ if (nclk > tid_)
+ src->elem(tid_).reused = reused_;
+
+ if (acquired) {
+ CPP_STAT_INC(StatClockAcquiredSomething);
+ last_acquire_ = clk_[tid_].epoch;
+ }
+}
+
+void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
+ DCHECK_LE(nclk_, kMaxTid);
+ DCHECK_LE(dst->size_, kMaxTid);
+
+ if (dst->size_ == 0) {
+ // ReleaseStore will correctly set release_store_tid_,
+ // which can be important for future operations.
+ ReleaseStore(c, dst);
+ return;
+ }
+
+ CPP_STAT_INC(StatClockRelease);
+ // Check if we need to resize dst.
+ if (dst->size_ < nclk_)
+ dst->Resize(c, nclk_);
+
+ // Check if we had not acquired anything from other threads
+ // since the last release on dst. If so, we need to update
+ // only dst->elem(tid_).
+ if (dst->elem(tid_).epoch > last_acquire_) {
+ UpdateCurrentThread(dst);
+ if (dst->release_store_tid_ != tid_ ||
+ dst->release_store_reused_ != reused_)
+ dst->release_store_tid_ = kInvalidTid;
+ return;
+ }
+
+ // O(N) release.
+ CPP_STAT_INC(StatClockReleaseFull);
+ // First, remember whether we've acquired dst.
+ bool acquired = IsAlreadyAcquired(dst);
+ if (acquired)
+ CPP_STAT_INC(StatClockReleaseAcquired);
+ // Update dst->clk_.
+ for (uptr i = 0; i < nclk_; i++) {
+ ClockElem &ce = dst->elem(i);
+ ce.epoch = max(ce.epoch, clk_[i].epoch);
+ ce.reused = 0;
+ }
+ // Clear 'acquired' flag in the remaining elements.
+ if (nclk_ < dst->size_)
+ CPP_STAT_INC(StatClockReleaseClearTail);
+ for (uptr i = nclk_; i < dst->size_; i++)
+ dst->elem(i).reused = 0;
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dst->dirty_tids_[i] = kInvalidTid;
+ dst->release_store_tid_ = kInvalidTid;
+ dst->release_store_reused_ = 0;
+ // If we've acquired dst, remember this fact,
+ // so that we don't need to acquire it on next acquire.
+ if (acquired)
+ dst->elem(tid_).reused = reused_;
+}
+
+void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const {
+ DCHECK_LE(nclk_, kMaxTid);
+ DCHECK_LE(dst->size_, kMaxTid);
+ CPP_STAT_INC(StatClockStore);
+
+ // Check if we need to resize dst.
+ if (dst->size_ < nclk_)
+ dst->Resize(c, nclk_);
+
+ if (dst->release_store_tid_ == tid_ &&
+ dst->release_store_reused_ == reused_ &&
+ dst->elem(tid_).epoch > last_acquire_) {
+ CPP_STAT_INC(StatClockStoreFast);
+ UpdateCurrentThread(dst);
+ return;
+ }
+
+ // O(N) release-store.
+ CPP_STAT_INC(StatClockStoreFull);
+ for (uptr i = 0; i < nclk_; i++) {
+ ClockElem &ce = dst->elem(i);
+ ce.epoch = clk_[i].epoch;
+ ce.reused = 0;
+ }
+ // Clear the tail of dst->clk_.
+ if (nclk_ < dst->size_) {
+ for (uptr i = nclk_; i < dst->size_; i++) {
+ ClockElem &ce = dst->elem(i);
+ ce.epoch = 0;
+ ce.reused = 0;
+ }
+ CPP_STAT_INC(StatClockStoreTail);
+ }
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dst->dirty_tids_[i] = kInvalidTid;
+ dst->release_store_tid_ = tid_;
+ dst->release_store_reused_ = reused_;
+ // Rememeber that we don't need to acquire it in future.
+ dst->elem(tid_).reused = reused_;
+}
+
+void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
+ CPP_STAT_INC(StatClockAcquireRelease);
+ acquire(c, dst);
+ ReleaseStore(c, dst);
+}
+
+// Updates only single element related to the current thread in dst->clk_.
+void ThreadClock::UpdateCurrentThread(SyncClock *dst) const {
+ // Update the threads time, but preserve 'acquired' flag.
+ dst->elem(tid_).epoch = clk_[tid_].epoch;
+
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ if (dst->dirty_tids_[i] == tid_) {
+ CPP_STAT_INC(StatClockReleaseFast1);
+ return;
+ }
+ if (dst->dirty_tids_[i] == kInvalidTid) {
+ CPP_STAT_INC(StatClockReleaseFast2);
+ dst->dirty_tids_[i] = tid_;
+ return;
+ }
+ }
+ // Reset all 'acquired' flags, O(N).
+ CPP_STAT_INC(StatClockReleaseSlow);
+ for (uptr i = 0; i < dst->size_; i++)
+ dst->elem(i).reused = 0;
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dst->dirty_tids_[i] = kInvalidTid;
+}
+
+// Checks whether the current threads has already acquired src.
+bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
+ if (src->elem(tid_).reused != reused_)
+ return false;
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ unsigned tid = src->dirty_tids_[i];
+ if (tid != kInvalidTid) {
+ if (clk_[tid].epoch < src->elem(tid).epoch)
+ return false;
+ }
+ }
+ return true;
+}
+
+void SyncClock::Resize(ClockCache *c, uptr nclk) {
+ CPP_STAT_INC(StatClockReleaseResize);
+ if (RoundUpTo(nclk, ClockBlock::kClockCount) <=
+ RoundUpTo(size_, ClockBlock::kClockCount)) {
+ // Growing within the same block.
+ // Memory is already allocated, just increase the size.
+ size_ = nclk;
+ return;
+ }
+ if (nclk <= ClockBlock::kClockCount) {
+ // Grow from 0 to one-level table.
+ CHECK_EQ(size_, 0);
+ CHECK_EQ(tab_, 0);
+ CHECK_EQ(tab_idx_, 0);
+ size_ = nclk;
+ tab_idx_ = ctx->clock_alloc.Alloc(c);
+ tab_ = ctx->clock_alloc.Map(tab_idx_);
+ internal_memset(tab_, 0, sizeof(*tab_));
+ return;
+ }
+ // Growing two-level table.
+ if (size_ == 0) {
+ // Allocate first level table.
+ tab_idx_ = ctx->clock_alloc.Alloc(c);
+ tab_ = ctx->clock_alloc.Map(tab_idx_);
+ internal_memset(tab_, 0, sizeof(*tab_));
+ } else if (size_ <= ClockBlock::kClockCount) {
+ // Transform one-level table to two-level table.
+ u32 old = tab_idx_;
+ tab_idx_ = ctx->clock_alloc.Alloc(c);
+ tab_ = ctx->clock_alloc.Map(tab_idx_);
+ internal_memset(tab_, 0, sizeof(*tab_));
+ tab_->table[0] = old;
+ }
+ // At this point we have first level table allocated.
+ // Add second level tables as necessary.
+ for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount);
+ i < nclk; i += ClockBlock::kClockCount) {
+ u32 idx = ctx->clock_alloc.Alloc(c);
+ ClockBlock *cb = ctx->clock_alloc.Map(idx);
+ internal_memset(cb, 0, sizeof(*cb));
+ CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0);
+ tab_->table[i/ClockBlock::kClockCount] = idx;
+ }
+ size_ = nclk;
+}
+
+// Sets a single element in the vector clock.
+// This function is called only from weird places like AcquireGlobal.
+void ThreadClock::set(unsigned tid, u64 v) {
+ DCHECK_LT(tid, kMaxTid);
+ DCHECK_GE(v, clk_[tid].epoch);
+ clk_[tid].epoch = v;
+ if (nclk_ <= tid)
+ nclk_ = tid + 1;
+ last_acquire_ = clk_[tid_].epoch;
+}
+
+void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
+ printf("clock=[");
+ for (uptr i = 0; i < nclk_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
+ printf("] reused=[");
+ for (uptr i = 0; i < nclk_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
+ printf("] tid=%u/%u last_acq=%llu",
+ tid_, reused_, last_acquire_);
+}
+
+SyncClock::SyncClock()
+ : release_store_tid_(kInvalidTid)
+ , release_store_reused_()
+ , tab_()
+ , tab_idx_()
+ , size_() {
+ for (uptr i = 0; i < kDirtyTids; i++)
+ dirty_tids_[i] = kInvalidTid;
+}
+
+SyncClock::~SyncClock() {
+ // Reset must be called before dtor.
+ CHECK_EQ(size_, 0);
+ CHECK_EQ(tab_, 0);
+ CHECK_EQ(tab_idx_, 0);
+}
+
+void SyncClock::Reset(ClockCache *c) {
+ if (size_ == 0) {
+ // nothing
+ } else if (size_ <= ClockBlock::kClockCount) {
+ // One-level table.
+ ctx->clock_alloc.Free(c, tab_idx_);
+ } else {
+ // Two-level table.
+ for (uptr i = 0; i < size_; i += ClockBlock::kClockCount)
+ ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]);
+ ctx->clock_alloc.Free(c, tab_idx_);
+ }
+ tab_ = 0;
+ tab_idx_ = 0;
+ size_ = 0;
+ release_store_tid_ = kInvalidTid;
+ release_store_reused_ = 0;
+ for (uptr i = 0; i < kDirtyTids; i++)
+ dirty_tids_[i] = kInvalidTid;
+}
+
+ClockElem &SyncClock::elem(unsigned tid) const {
+ DCHECK_LT(tid, size_);
+ if (size_ <= ClockBlock::kClockCount)
+ return tab_->clock[tid];
+ u32 idx = tab_->table[tid / ClockBlock::kClockCount];
+ ClockBlock *cb = ctx->clock_alloc.Map(idx);
+ return cb->clock[tid % ClockBlock::kClockCount];
+}
+
+void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
+ printf("clock=[");
+ for (uptr i = 0; i < size_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", elem(i).epoch);
+ printf("] reused=[");
+ for (uptr i = 0; i < size_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
+ printf("] release_store_tid=%d/%d dirty_tids=%d/%d",
+ release_store_tid_, release_store_reused_,
+ dirty_tids_[0], dirty_tids_[1]);
+}
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.h
new file mode 100644
index 000000000000..4e352cb81d11
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.h
@@ -0,0 +1,129 @@
+//===-- tsan_clock.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_CLOCK_H
+#define TSAN_CLOCK_H
+
+#include "tsan_defs.h"
+#include "tsan_dense_alloc.h"
+
+namespace __tsan {
+
+struct ClockElem {
+ u64 epoch : kClkBits;
+ u64 reused : 64 - kClkBits;
+};
+
+struct ClockBlock {
+ static const uptr kSize = 512;
+ static const uptr kTableSize = kSize / sizeof(u32);
+ static const uptr kClockCount = kSize / sizeof(ClockElem);
+
+ union {
+ u32 table[kTableSize];
+ ClockElem clock[kClockCount];
+ };
+
+ ClockBlock() {
+ }
+};
+
+typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
+typedef DenseSlabAllocCache ClockCache;
+
+// The clock that lives in sync variables (mutexes, atomics, etc).
+class SyncClock {
+ public:
+ SyncClock();
+ ~SyncClock();
+
+ uptr size() const {
+ return size_;
+ }
+
+ u64 get(unsigned tid) const {
+ return elem(tid).epoch;
+ }
+
+ void Resize(ClockCache *c, uptr nclk);
+ void Reset(ClockCache *c);
+
+ void DebugDump(int(*printf)(const char *s, ...));
+
+ private:
+ friend struct ThreadClock;
+ static const uptr kDirtyTids = 2;
+
+ unsigned release_store_tid_;
+ unsigned release_store_reused_;
+ unsigned dirty_tids_[kDirtyTids];
+ // tab_ contains indirect pointer to a 512b block using DenseSlabAlloc.
+ // If size_ <= 64, then tab_ points to an array with 64 ClockElem's.
+ // Otherwise, tab_ points to an array with 128 u32 elements,
+ // each pointing to the second-level 512b block with 64 ClockElem's.
+ ClockBlock *tab_;
+ u32 tab_idx_;
+ u32 size_;
+
+ ClockElem &elem(unsigned tid) const;
+};
+
+// The clock that lives in threads.
+struct ThreadClock {
+ public:
+ typedef DenseSlabAllocCache Cache;
+
+ explicit ThreadClock(unsigned tid, unsigned reused = 0);
+
+ u64 get(unsigned tid) const {
+ DCHECK_LT(tid, kMaxTidInClock);
+ return clk_[tid].epoch;
+ }
+
+ void set(unsigned tid, u64 v);
+
+ void set(u64 v) {
+ DCHECK_GE(v, clk_[tid_].epoch);
+ clk_[tid_].epoch = v;
+ }
+
+ void tick() {
+ clk_[tid_].epoch++;
+ }
+
+ uptr size() const {
+ return nclk_;
+ }
+
+ void acquire(ClockCache *c, const SyncClock *src);
+ void release(ClockCache *c, SyncClock *dst) const;
+ void acq_rel(ClockCache *c, SyncClock *dst);
+ void ReleaseStore(ClockCache *c, SyncClock *dst) const;
+
+ void DebugReset();
+ void DebugDump(int(*printf)(const char *s, ...));
+
+ private:
+ static const uptr kDirtyTids = SyncClock::kDirtyTids;
+ const unsigned tid_;
+ const unsigned reused_;
+ u64 last_acquire_;
+ uptr nclk_;
+ ClockElem clk_[kMaxTidInClock];
+
+ bool IsAlreadyAcquired(const SyncClock *src) const;
+ void UpdateCurrentThread(SyncClock *dst) const;
+};
+
+} // namespace __tsan
+
+#endif // TSAN_CLOCK_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h
new file mode 100644
index 000000000000..910a483127d5
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h
@@ -0,0 +1,162 @@
+//===-- tsan_defs.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TSAN_DEFS_H
+#define TSAN_DEFS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "tsan_stat.h"
+
+// Setup defaults for compile definitions.
+#ifndef TSAN_NO_HISTORY
+# define TSAN_NO_HISTORY 0
+#endif
+
+#ifndef TSAN_COLLECT_STATS
+# define TSAN_COLLECT_STATS 0
+#endif
+
+namespace __tsan {
+
+#ifdef SANITIZER_GO
+const bool kGoMode = true;
+const bool kCppMode = false;
+const char *const kTsanOptionsEnv = "GORACE";
+// Go linker does not support weak symbols.
+#define CPP_WEAK
+#else
+const bool kGoMode = false;
+const bool kCppMode = true;
+const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
+#define CPP_WEAK WEAK
+#endif
+
+const int kTidBits = 13;
+const unsigned kMaxTid = 1 << kTidBits;
+#ifndef SANITIZER_GO
+const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
+#else
+const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory.
+#endif
+const int kClkBits = 42;
+const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
+const uptr kShadowStackSize = 64 * 1024;
+
+// Count of shadow values in a shadow cell.
+const uptr kShadowCnt = 4;
+
+// That many user bytes are mapped onto a single shadow cell.
+const uptr kShadowCell = 8;
+
+// Size of a single shadow value (u64).
+const uptr kShadowSize = 8;
+
+// Shadow memory is kShadowMultiplier times larger than user memory.
+const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell;
+
+// That many user bytes are mapped onto a single meta shadow cell.
+// Must be less or equal to minimal memory allocator alignment.
+const uptr kMetaShadowCell = 8;
+
+// Size of a single meta shadow value (u32).
+const uptr kMetaShadowSize = 4;
+
+#if TSAN_NO_HISTORY
+const bool kCollectHistory = false;
+#else
+const bool kCollectHistory = true;
+#endif
+
+// The following "build consistency" machinery ensures that all source files
+// are built in the same configuration. Inconsistent builds lead to
+// hard to debug crashes.
+#if SANITIZER_DEBUG
+void build_consistency_debug();
+#else
+void build_consistency_release();
+#endif
+
+#if TSAN_COLLECT_STATS
+void build_consistency_stats();
+#else
+void build_consistency_nostats();
+#endif
+
+static inline void USED build_consistency() {
+#if SANITIZER_DEBUG
+ build_consistency_debug();
+#else
+ build_consistency_release();
+#endif
+#if TSAN_COLLECT_STATS
+ build_consistency_stats();
+#else
+ build_consistency_nostats();
+#endif
+}
+
+template<typename T>
+T min(T a, T b) {
+ return a < b ? a : b;
+}
+
+template<typename T>
+T max(T a, T b) {
+ return a > b ? a : b;
+}
+
+template<typename T>
+T RoundUp(T p, u64 align) {
+ DCHECK_EQ(align & (align - 1), 0);
+ return (T)(((u64)p + align - 1) & ~(align - 1));
+}
+
+template<typename T>
+T RoundDown(T p, u64 align) {
+ DCHECK_EQ(align & (align - 1), 0);
+ return (T)((u64)p & ~(align - 1));
+}
+
+// Zeroizes high part, returns 'bits' lsb bits.
+template<typename T>
+T GetLsb(T v, int bits) {
+ return (T)((u64)v & ((1ull << bits) - 1));
+}
+
+struct MD5Hash {
+ u64 hash[2];
+ bool operator==(const MD5Hash &other) const;
+};
+
+MD5Hash md5_hash(const void *data, uptr size);
+
+struct ThreadState;
+class ThreadContext;
+struct Context;
+struct ReportStack;
+class ReportDesc;
+class RegionAlloc;
+
+// Descriptor of user's memory block.
+struct MBlock {
+ u64 siz;
+ u32 stk;
+ u16 tid;
+};
+
+COMPILER_CHECK(sizeof(MBlock) == 16);
+
+} // namespace __tsan
+
+#endif // TSAN_DEFS_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h
new file mode 100644
index 000000000000..a1cf84b8f166
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h
@@ -0,0 +1,137 @@
+//===-- tsan_dense_alloc.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 ThreadSanitizer (TSan), a race detector.
+//
+// A DenseSlabAlloc is a freelist-based allocator of fixed-size objects.
+// DenseSlabAllocCache is a thread-local cache for DenseSlabAlloc.
+// The only difference with traditional slab allocators is that DenseSlabAlloc
+// allocates/free indices of objects and provide a functionality to map
+// the index onto the real pointer. The index is u32, that is, 2 times smaller
+// than uptr (hense the Dense prefix).
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_DENSE_ALLOC_H
+#define TSAN_DENSE_ALLOC_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "tsan_defs.h"
+#include "tsan_mutex.h"
+
+namespace __tsan {
+
+class DenseSlabAllocCache {
+ static const uptr kSize = 128;
+ typedef u32 IndexT;
+ uptr pos;
+ IndexT cache[kSize];
+ template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
+};
+
+template<typename T, uptr kL1Size, uptr kL2Size>
+class DenseSlabAlloc {
+ public:
+ typedef DenseSlabAllocCache Cache;
+ typedef typename Cache::IndexT IndexT;
+
+ DenseSlabAlloc() {
+ // Check that kL1Size and kL2Size are sane.
+ CHECK_EQ(kL1Size & (kL1Size - 1), 0);
+ CHECK_EQ(kL2Size & (kL2Size - 1), 0);
+ CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
+ // Check that it makes sense to use the dense alloc.
+ CHECK_GE(sizeof(T), sizeof(IndexT));
+ internal_memset(map_, 0, sizeof(map_));
+ freelist_ = 0;
+ fillpos_ = 0;
+ }
+
+ ~DenseSlabAlloc() {
+ for (uptr i = 0; i < kL1Size; i++) {
+ if (map_[i] != 0)
+ UnmapOrDie(map_[i], kL2Size * sizeof(T));
+ }
+ }
+
+ IndexT Alloc(Cache *c) {
+ if (c->pos == 0)
+ Refill(c);
+ return c->cache[--c->pos];
+ }
+
+ void Free(Cache *c, IndexT idx) {
+ DCHECK_NE(idx, 0);
+ if (c->pos == Cache::kSize)
+ Drain(c);
+ c->cache[c->pos++] = idx;
+ }
+
+ T *Map(IndexT idx) {
+ DCHECK_NE(idx, 0);
+ DCHECK_LE(idx, kL1Size * kL2Size);
+ return &map_[idx / kL2Size][idx % kL2Size];
+ }
+
+ void FlushCache(Cache *c) {
+ SpinMutexLock lock(&mtx_);
+ while (c->pos) {
+ IndexT idx = c->cache[--c->pos];
+ *(IndexT*)Map(idx) = freelist_;
+ freelist_ = idx;
+ }
+ }
+
+ void InitCache(Cache *c) {
+ c->pos = 0;
+ internal_memset(c->cache, 0, sizeof(c->cache));
+ }
+
+ private:
+ T *map_[kL1Size];
+ SpinMutex mtx_;
+ IndexT freelist_;
+ uptr fillpos_;
+
+ void Refill(Cache *c) {
+ SpinMutexLock lock(&mtx_);
+ if (freelist_ == 0) {
+ if (fillpos_ == kL1Size) {
+ Printf("ThreadSanitizer: DenseSlabAllocator overflow. Dying.\n");
+ Die();
+ }
+ T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), "DenseSlabAllocator");
+ // Reserve 0 as invalid index.
+ IndexT start = fillpos_ == 0 ? 1 : 0;
+ for (IndexT i = start; i < kL2Size; i++) {
+ new(batch + i) T();
+ *(IndexT*)(batch + i) = i + 1 + fillpos_ * kL2Size;
+ }
+ *(IndexT*)(batch + kL2Size - 1) = 0;
+ freelist_ = fillpos_ * kL2Size + start;
+ map_[fillpos_++] = batch;
+ }
+ for (uptr i = 0; i < Cache::kSize / 2 && freelist_ != 0; i++) {
+ IndexT idx = freelist_;
+ c->cache[c->pos++] = idx;
+ freelist_ = *(IndexT*)Map(idx);
+ }
+ }
+
+ void Drain(Cache *c) {
+ SpinMutexLock lock(&mtx_);
+ for (uptr i = 0; i < Cache::kSize / 2; i++) {
+ IndexT idx = c->cache[--c->pos];
+ *(IndexT*)Map(idx) = freelist_;
+ freelist_ = idx;
+ }
+ }
+};
+
+} // namespace __tsan
+
+#endif // TSAN_DENSE_ALLOC_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_fd.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_fd.cc
new file mode 100644
index 000000000000..d18502f00540
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_fd.cc
@@ -0,0 +1,298 @@
+//===-- tsan_fd.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_fd.h"
+#include "tsan_rtl.h"
+#include <sanitizer_common/sanitizer_atomic.h>
+
+namespace __tsan {
+
+const int kTableSizeL1 = 1024;
+const int kTableSizeL2 = 1024;
+const int kTableSize = kTableSizeL1 * kTableSizeL2;
+
+struct FdSync {
+ atomic_uint64_t rc;
+};
+
+struct FdDesc {
+ FdSync *sync;
+ int creation_tid;
+ u32 creation_stack;
+};
+
+struct FdContext {
+ atomic_uintptr_t tab[kTableSizeL1];
+ // Addresses used for synchronization.
+ FdSync globsync;
+ FdSync filesync;
+ FdSync socksync;
+ u64 connectsync;
+};
+
+static FdContext fdctx;
+
+static bool bogusfd(int fd) {
+ // Apparently a bogus fd value.
+ return fd < 0 || fd >= kTableSize;
+}
+
+static FdSync *allocsync(ThreadState *thr, uptr pc) {
+ FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
+ false);
+ atomic_store(&s->rc, 1, memory_order_relaxed);
+ return s;
+}
+
+static FdSync *ref(FdSync *s) {
+ if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1)
+ atomic_fetch_add(&s->rc, 1, memory_order_relaxed);
+ return s;
+}
+
+static void unref(ThreadState *thr, uptr pc, FdSync *s) {
+ if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) {
+ if (atomic_fetch_sub(&s->rc, 1, memory_order_acq_rel) == 1) {
+ CHECK_NE(s, &fdctx.globsync);
+ CHECK_NE(s, &fdctx.filesync);
+ CHECK_NE(s, &fdctx.socksync);
+ user_free(thr, pc, s, false);
+ }
+ }
+}
+
+static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
+ CHECK_GE(fd, 0);
+ CHECK_LT(fd, kTableSize);
+ atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2];
+ uptr l1 = atomic_load(pl1, memory_order_consume);
+ if (l1 == 0) {
+ uptr size = kTableSizeL2 * sizeof(FdDesc);
+ // We need this to reside in user memory to properly catch races on it.
+ void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
+ internal_memset(p, 0, size);
+ MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
+ if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
+ l1 = (uptr)p;
+ else
+ user_free(thr, pc, p, false);
+ }
+ return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT
+}
+
+// pd must be already ref'ed.
+static void init(ThreadState *thr, uptr pc, int fd, FdSync *s) {
+ FdDesc *d = fddesc(thr, pc, fd);
+ // As a matter of fact, we don't intercept all close calls.
+ // See e.g. libc __res_iclose().
+ if (d->sync) {
+ unref(thr, pc, d->sync);
+ d->sync = 0;
+ }
+ if (flags()->io_sync == 0) {
+ unref(thr, pc, s);
+ } else if (flags()->io_sync == 1) {
+ d->sync = s;
+ } else if (flags()->io_sync == 2) {
+ unref(thr, pc, s);
+ d->sync = &fdctx.globsync;
+ }
+ d->creation_tid = thr->tid;
+ d->creation_stack = CurrentStackId(thr, pc);
+ // To catch races between fd usage and open.
+ MemoryRangeImitateWrite(thr, pc, (uptr)d, 8);
+}
+
+void FdInit() {
+ atomic_store(&fdctx.globsync.rc, (u64)-1, memory_order_relaxed);
+ atomic_store(&fdctx.filesync.rc, (u64)-1, memory_order_relaxed);
+ atomic_store(&fdctx.socksync.rc, (u64)-1, memory_order_relaxed);
+}
+
+void FdOnFork(ThreadState *thr, uptr pc) {
+ // On fork() we need to reset all fd's, because the child is going
+ // close all them, and that will cause races between previous read/write
+ // and the close.
+ for (int l1 = 0; l1 < kTableSizeL1; l1++) {
+ FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed);
+ if (tab == 0)
+ break;
+ for (int l2 = 0; l2 < kTableSizeL2; l2++) {
+ FdDesc *d = &tab[l2];
+ MemoryResetRange(thr, pc, (uptr)d, 8);
+ }
+ }
+}
+
+bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) {
+ for (int l1 = 0; l1 < kTableSizeL1; l1++) {
+ FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed);
+ if (tab == 0)
+ break;
+ if (addr >= (uptr)tab && addr < (uptr)(tab + kTableSizeL2)) {
+ int l2 = (addr - (uptr)tab) / sizeof(FdDesc);
+ FdDesc *d = &tab[l2];
+ *fd = l1 * kTableSizeL1 + l2;
+ *tid = d->creation_tid;
+ *stack = d->creation_stack;
+ return true;
+ }
+ }
+ return false;
+}
+
+void FdAcquire(ThreadState *thr, uptr pc, int fd) {
+ if (bogusfd(fd))
+ return;
+ FdDesc *d = fddesc(thr, pc, fd);
+ FdSync *s = d->sync;
+ DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
+ if (s)
+ Acquire(thr, pc, (uptr)s);
+}
+
+void FdRelease(ThreadState *thr, uptr pc, int fd) {
+ if (bogusfd(fd))
+ return;
+ FdDesc *d = fddesc(thr, pc, fd);
+ FdSync *s = d->sync;
+ DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
+ if (s)
+ Release(thr, pc, (uptr)s);
+}
+
+void FdAccess(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ FdDesc *d = fddesc(thr, pc, fd);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
+}
+
+void FdClose(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ FdDesc *d = fddesc(thr, pc, fd);
+ // To catch races between fd usage and close.
+ MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
+ // We need to clear it, because if we do not intercept any call out there
+ // that creates fd, we will hit false postives.
+ MemoryResetRange(thr, pc, (uptr)d, 8);
+ unref(thr, pc, d->sync);
+ d->sync = 0;
+ d->creation_tid = 0;
+ d->creation_stack = 0;
+}
+
+void FdFileCreate(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ init(thr, pc, fd, &fdctx.filesync);
+}
+
+void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
+ DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
+ if (bogusfd(oldfd) || bogusfd(newfd))
+ return;
+ // Ignore the case when user dups not yet connected socket.
+ FdDesc *od = fddesc(thr, pc, oldfd);
+ MemoryRead(thr, pc, (uptr)od, kSizeLog8);
+ FdClose(thr, pc, newfd);
+ init(thr, pc, newfd, ref(od->sync));
+}
+
+void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
+ DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd);
+ FdSync *s = allocsync(thr, pc);
+ init(thr, pc, rfd, ref(s));
+ init(thr, pc, wfd, ref(s));
+ unref(thr, pc, s);
+}
+
+void FdEventCreate(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ init(thr, pc, fd, allocsync(thr, pc));
+}
+
+void FdSignalCreate(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdSignalCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ init(thr, pc, fd, 0);
+}
+
+void FdInotifyCreate(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdInotifyCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ init(thr, pc, fd, 0);
+}
+
+void FdPollCreate(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ init(thr, pc, fd, allocsync(thr, pc));
+}
+
+void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ // It can be a UDP socket.
+ init(thr, pc, fd, &fdctx.socksync);
+}
+
+void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
+ DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd);
+ if (bogusfd(fd))
+ return;
+ // Synchronize connect->accept.
+ Acquire(thr, pc, (uptr)&fdctx.connectsync);
+ init(thr, pc, newfd, &fdctx.socksync);
+}
+
+void FdSocketConnecting(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdSocketConnecting(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ // Synchronize connect->accept.
+ Release(thr, pc, (uptr)&fdctx.connectsync);
+}
+
+void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
+ DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
+ init(thr, pc, fd, &fdctx.socksync);
+}
+
+uptr File2addr(const char *path) {
+ (void)path;
+ static u64 addr;
+ return (uptr)&addr;
+}
+
+uptr Dir2addr(const char *path) {
+ (void)path;
+ static u64 addr;
+ return (uptr)&addr;
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_fd.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_fd.h
new file mode 100644
index 000000000000..75c616dae0fd
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_fd.h
@@ -0,0 +1,65 @@
+//===-- tsan_fd.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 ThreadSanitizer (TSan), a race detector.
+//
+// This file handles synchronization via IO.
+// People use IO for synchronization along the lines of:
+//
+// int X;
+// int client_socket; // initialized elsewhere
+// int server_socket; // initialized elsewhere
+//
+// Thread 1:
+// X = 42;
+// send(client_socket, ...);
+//
+// Thread 2:
+// if (recv(server_socket, ...) > 0)
+// assert(X == 42);
+//
+// This file determines the scope of the file descriptor (pipe, socket,
+// all local files, etc) and executes acquire and release operations on
+// the scope as necessary. Some scopes are very fine grained (e.g. pipe
+// operations synchronize only with operations on the same pipe), while
+// others are corse-grained (e.g. all operations on local files synchronize
+// with each other).
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_FD_H
+#define TSAN_FD_H
+
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+void FdInit();
+void FdAcquire(ThreadState *thr, uptr pc, int fd);
+void FdRelease(ThreadState *thr, uptr pc, int fd);
+void FdAccess(ThreadState *thr, uptr pc, int fd);
+void FdClose(ThreadState *thr, uptr pc, int fd);
+void FdFileCreate(ThreadState *thr, uptr pc, int fd);
+void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd);
+void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd);
+void FdEventCreate(ThreadState *thr, uptr pc, int fd);
+void FdSignalCreate(ThreadState *thr, uptr pc, int fd);
+void FdInotifyCreate(ThreadState *thr, uptr pc, int fd);
+void FdPollCreate(ThreadState *thr, uptr pc, int fd);
+void FdSocketCreate(ThreadState *thr, uptr pc, int fd);
+void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd);
+void FdSocketConnecting(ThreadState *thr, uptr pc, int fd);
+void FdSocketConnect(ThreadState *thr, uptr pc, int fd);
+bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack);
+void FdOnFork(ThreadState *thr, uptr pc);
+
+uptr File2addr(const char *path);
+uptr Dir2addr(const char *path);
+
+} // namespace __tsan
+
+#endif // TSAN_INTERFACE_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc
new file mode 100644
index 000000000000..1e81ef3d0003
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc
@@ -0,0 +1,104 @@
+//===-- tsan_flags.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "tsan_flags.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+
+namespace __tsan {
+
+Flags *flags() {
+ return &ctx->flags;
+}
+
+// Can be overriden in frontend.
+#ifdef TSAN_EXTERNAL_HOOKS
+extern "C" const char* __tsan_default_options();
+#else
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+const char *WEAK __tsan_default_options() {
+ return "";
+}
+#endif
+
+void Flags::SetDefaults() {
+#define TSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "tsan_flags.inc"
+#undef TSAN_FLAG
+ // DDFlags
+ second_deadlock_stack = false;
+}
+
+void RegisterTsanFlags(FlagParser *parser, Flags *f) {
+#define TSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "tsan_flags.inc"
+#undef TSAN_FLAG
+}
+
+void InitializeFlags(Flags *f, const char *env) {
+ FlagParser parser;
+ RegisterTsanFlags(&parser, f);
+ RegisterCommonFlags(&parser);
+
+ f->SetDefaults();
+
+ SetCommonFlagsDefaults();
+ {
+ // Override some common flags defaults.
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.allow_addr2line = true;
+#ifndef SANITIZER_GO
+ cf.detect_deadlocks = true;
+#endif
+ cf.print_suppressions = false;
+ cf.stack_trace_format = " #%n %f %S %M";
+ OverrideCommonFlags(cf);
+ }
+
+ // Let a frontend override.
+ parser.ParseString(__tsan_default_options());
+ // Override from command line.
+ parser.ParseString(env);
+
+ // Sanity check.
+ if (!f->report_bugs) {
+ f->report_thread_leaks = false;
+ f->report_destroy_locked = false;
+ f->report_signal_unsafe = false;
+ }
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+
+ if (f->history_size < 0 || f->history_size > 7) {
+ Printf("ThreadSanitizer: incorrect value for history_size"
+ " (must be [0..7])\n");
+ Die();
+ }
+
+ if (f->io_sync < 0 || f->io_sync > 2) {
+ Printf("ThreadSanitizer: incorrect value for io_sync"
+ " (must be [0..2])\n");
+ Die();
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.h
new file mode 100644
index 000000000000..e2f6b3c9f021
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.h
@@ -0,0 +1,35 @@
+//===-- tsan_flags.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 ThreadSanitizer (TSan), a race detector.
+// NOTE: This file may be included into user code.
+//===----------------------------------------------------------------------===//
+
+#ifndef TSAN_FLAGS_H
+#define TSAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+
+namespace __tsan {
+
+struct Flags : DDFlags {
+#define TSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "tsan_flags.inc"
+#undef TSAN_FLAG
+
+ void SetDefaults();
+ void ParseFromString(const char *str);
+};
+
+Flags *flags();
+void InitializeFlags(Flags *flags, const char *env);
+} // namespace __tsan
+
+#endif // TSAN_FLAGS_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc
new file mode 100644
index 000000000000..e4994685fa0d
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc
@@ -0,0 +1,79 @@
+//===-- tsan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// TSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_FLAG
+# error "Define TSAN_FLAG prior to including this file!"
+#endif
+
+// TSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+TSAN_FLAG(bool, enable_annotations, true,
+ "Enable dynamic annotations, otherwise they are no-ops.")
+// Suppress a race report if we've already output another race report
+// with the same stack.
+TSAN_FLAG(bool, suppress_equal_stacks, true,
+ "Suppress a race report if we've already output another race report "
+ "with the same stack.")
+TSAN_FLAG(bool, suppress_equal_addresses, true,
+ "Suppress a race report if we've already output another race report "
+ "on the same address.")
+
+TSAN_FLAG(bool, report_bugs, true,
+ "Turns off bug reporting entirely (useful for benchmarking).")
+TSAN_FLAG(bool, report_thread_leaks, true, "Report thread leaks at exit?")
+TSAN_FLAG(bool, report_destroy_locked, true,
+ "Report destruction of a locked mutex?")
+TSAN_FLAG(bool, report_mutex_bugs, true,
+ "Report incorrect usages of mutexes and mutex annotations?")
+TSAN_FLAG(bool, report_signal_unsafe, true,
+ "Report violations of async signal-safety "
+ "(e.g. malloc() call from a signal handler).")
+TSAN_FLAG(bool, report_atomic_races, true,
+ "Report races between atomic and plain memory accesses.")
+TSAN_FLAG(
+ bool, force_seq_cst_atomics, false,
+ "If set, all atomics are effectively sequentially consistent (seq_cst), "
+ "regardless of what user actually specified.")
+TSAN_FLAG(bool, print_benign, false, "Print matched \"benign\" races at exit.")
+TSAN_FLAG(int, exitcode, 66, "Override exit status if something was reported.")
+TSAN_FLAG(bool, halt_on_error, false, "Exit after first reported error.")
+TSAN_FLAG(int, atexit_sleep_ms, 1000,
+ "Sleep in main thread before exiting for that many ms "
+ "(useful to catch \"at exit\" races).")
+TSAN_FLAG(const char *, profile_memory, "",
+ "If set, periodically write memory profile to that file.")
+TSAN_FLAG(int, flush_memory_ms, 0, "Flush shadow memory every X ms.")
+TSAN_FLAG(int, flush_symbolizer_ms, 5000, "Flush symbolizer caches every X ms.")
+TSAN_FLAG(
+ int, memory_limit_mb, 0,
+ "Resident memory limit in MB to aim at."
+ "If the process consumes more memory, then TSan will flush shadow memory.")
+TSAN_FLAG(bool, stop_on_start, false,
+ "Stops on start until __tsan_resume() is called (for debugging).")
+TSAN_FLAG(bool, running_on_valgrind, false,
+ "Controls whether RunningOnValgrind() returns true or false.")
+TSAN_FLAG(
+ int, history_size, kGoMode ? 1 : 3, // There are a lot of goroutines in Go.
+ "Per-thread history size, controls how many previous memory accesses "
+ "are remembered per thread. Possible values are [0..7]. "
+ "history_size=0 amounts to 32K memory accesses. Each next value doubles "
+ "the amount of memory accesses, up to history_size=7 that amounts to "
+ "4M memory accesses. The default value is 2 (128K memory accesses).")
+TSAN_FLAG(int, io_sync, 1,
+ "Controls level of synchronization implied by IO operations. "
+ "0 - no synchronization "
+ "1 - reasonable level of synchronization (write->read)"
+ "2 - global synchronization of all IO operations.")
+TSAN_FLAG(bool, die_after_fork, true,
+ "Die after multi-threaded fork if the child creates new threads.")
+TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.cc
new file mode 100644
index 000000000000..cdb90d229980
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.cc
@@ -0,0 +1,47 @@
+//===-- tsan_ignoreset.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_ignoreset.h"
+
+namespace __tsan {
+
+const uptr IgnoreSet::kMaxSize;
+
+IgnoreSet::IgnoreSet()
+ : size_() {
+}
+
+void IgnoreSet::Add(u32 stack_id) {
+ if (size_ == kMaxSize)
+ return;
+ for (uptr i = 0; i < size_; i++) {
+ if (stacks_[i] == stack_id)
+ return;
+ }
+ stacks_[size_++] = stack_id;
+}
+
+void IgnoreSet::Reset() {
+ size_ = 0;
+}
+
+uptr IgnoreSet::Size() const {
+ return size_;
+}
+
+u32 IgnoreSet::At(uptr i) const {
+ CHECK_LT(i, size_);
+ CHECK_LE(size_, kMaxSize);
+ return stacks_[i];
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.h
new file mode 100644
index 000000000000..e747d819c758
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_ignoreset.h
@@ -0,0 +1,38 @@
+//===-- tsan_ignoreset.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 ThreadSanitizer (TSan), a race detector.
+//
+// IgnoreSet holds a set of stack traces where ignores were enabled.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_IGNORESET_H
+#define TSAN_IGNORESET_H
+
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+class IgnoreSet {
+ public:
+ static const uptr kMaxSize = 16;
+
+ IgnoreSet();
+ void Add(u32 stack_id);
+ void Reset();
+ uptr Size() const;
+ u32 At(uptr i) const;
+
+ private:
+ uptr size_;
+ u32 stacks_[kMaxSize];
+};
+
+} // namespace __tsan
+
+#endif // TSAN_IGNORESET_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
new file mode 100644
index 000000000000..31ff7d56aac7
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
@@ -0,0 +1,2629 @@
+//===-- tsan_interceptors.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 ThreadSanitizer (TSan), a race detector.
+//
+// FIXME: move as many interceptors as possible into
+// sanitizer_common/sanitizer_common_interceptors.inc
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "interception/interception.h"
+#include "tsan_interface.h"
+#include "tsan_platform.h"
+#include "tsan_suppressions.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "tsan_fd.h"
+
+using namespace __tsan; // NOLINT
+
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#define __libc_malloc __malloc
+#define __libc_realloc __realloc
+#define __libc_calloc __calloc
+#define __libc_free __free
+#define stdout __stdoutp
+#define stderr __stderrp
+#endif
+
+#ifdef __mips__
+const int kSigCount = 129;
+#else
+const int kSigCount = 65;
+#endif
+
+struct my_siginfo_t {
+ // The size is determined by looking at sizeof of real siginfo_t on linux.
+ u64 opaque[128 / sizeof(u64)];
+};
+
+#ifdef __mips__
+struct ucontext_t {
+ u64 opaque[768 / sizeof(u64) + 1];
+};
+#else
+struct ucontext_t {
+ // The size is determined by looking at sizeof of real ucontext_t on linux.
+ u64 opaque[936 / sizeof(u64) + 1];
+};
+#endif
+
+extern "C" int pthread_attr_init(void *attr);
+extern "C" int pthread_attr_destroy(void *attr);
+DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
+extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
+extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
+extern "C" int pthread_setspecific(unsigned key, const void *v);
+DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
+extern "C" int pthread_yield();
+extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset);
+// REAL(sigfillset) defined in common interceptors.
+DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set)
+DECLARE_REAL(int, fflush, __sanitizer_FILE *fp)
+extern "C" void *pthread_self();
+extern "C" void _exit(int status);
+extern "C" int *__errno_location();
+extern "C" int fileno_unlocked(void *stream);
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void *__libc_calloc(uptr size, uptr n);
+extern "C" void *__libc_realloc(void *ptr, uptr size);
+extern "C" void __libc_free(void *ptr);
+extern "C" int dirfd(void *dirp);
+#if !SANITIZER_FREEBSD
+extern "C" int mallopt(int param, int value);
+#endif
+extern __sanitizer_FILE *stdout, *stderr;
+const int PTHREAD_MUTEX_RECURSIVE = 1;
+const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
+const int EINVAL = 22;
+const int EBUSY = 16;
+const int EOWNERDEAD = 130;
+const int EPOLL_CTL_ADD = 1;
+const int SIGILL = 4;
+const int SIGABRT = 6;
+const int SIGFPE = 8;
+const int SIGSEGV = 11;
+const int SIGPIPE = 13;
+const int SIGTERM = 15;
+#ifdef __mips__
+const int SIGBUS = 10;
+const int SIGSYS = 12;
+#else
+const int SIGBUS = 7;
+const int SIGSYS = 31;
+#endif
+void *const MAP_FAILED = (void*)-1;
+const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
+const int MAP_FIXED = 0x10;
+typedef long long_t; // NOLINT
+
+// From /usr/include/unistd.h
+# define F_ULOCK 0 /* Unlock a previously locked region. */
+# define F_LOCK 1 /* Lock a region for exclusive use. */
+# define F_TLOCK 2 /* Test and lock a region for exclusive use. */
+# define F_TEST 3 /* Test a region for other processes locks. */
+
+#define errno (*__errno_location())
+
+typedef void (*sighandler_t)(int sig);
+typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx);
+
+struct sigaction_t {
+#ifdef __mips__
+ u32 sa_flags;
+#endif
+ union {
+ sighandler_t sa_handler;
+ sigactionhandler_t sa_sigaction;
+ };
+#if SANITIZER_FREEBSD
+ int sa_flags;
+ __sanitizer_sigset_t sa_mask;
+#else
+ __sanitizer_sigset_t sa_mask;
+#ifndef __mips__
+ int sa_flags;
+#endif
+ void (*sa_restorer)();
+#endif
+};
+
+const sighandler_t SIG_DFL = (sighandler_t)0;
+const sighandler_t SIG_IGN = (sighandler_t)1;
+const sighandler_t SIG_ERR = (sighandler_t)-1;
+#ifdef __mips__
+const int SA_SIGINFO = 8;
+const int SIG_SETMASK = 3;
+#else
+const int SA_SIGINFO = 4;
+const int SIG_SETMASK = 2;
+#endif
+
+namespace std {
+struct nothrow_t {};
+} // namespace std
+
+static sigaction_t sigactions[kSigCount];
+
+namespace __tsan {
+struct SignalDesc {
+ bool armed;
+ bool sigaction;
+ my_siginfo_t siginfo;
+ ucontext_t ctx;
+};
+
+struct SignalContext {
+ int int_signal_send;
+ atomic_uintptr_t in_blocking_func;
+ atomic_uintptr_t have_pending_signals;
+ SignalDesc pending_signals[kSigCount];
+};
+
+// The object is 64-byte aligned, because we want hot data to be located in
+// a single cache line if possible (it's accessed in every interceptor).
+static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
+static LibIgnore *libignore() {
+ return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
+}
+
+void InitializeLibIgnore() {
+ const SuppressionContext &supp = *Suppressions();
+ const uptr n = supp.SuppressionCount();
+ for (uptr i = 0; i < n; i++) {
+ const Suppression *s = supp.SuppressionAt(i);
+ if (0 == internal_strcmp(s->type, kSuppressionLib))
+ libignore()->AddIgnoredLibrary(s->templ);
+ }
+ libignore()->OnLibraryLoaded(0);
+}
+
+} // namespace __tsan
+
+static SignalContext *SigCtx(ThreadState *thr) {
+ SignalContext *ctx = (SignalContext*)thr->signal_ctx;
+ if (ctx == 0 && !thr->is_dead) {
+ ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
+ MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
+ thr->signal_ctx = ctx;
+ }
+ return ctx;
+}
+
+static unsigned g_thread_finalize_key;
+
+class ScopedInterceptor {
+ public:
+ ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc);
+ ~ScopedInterceptor();
+ private:
+ ThreadState *const thr_;
+ const uptr pc_;
+ bool in_ignored_lib_;
+};
+
+ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
+ uptr pc)
+ : thr_(thr)
+ , pc_(pc)
+ , in_ignored_lib_(false) {
+ if (!thr_->ignore_interceptors) {
+ Initialize(thr);
+ FuncEntry(thr, pc);
+ }
+ DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
+ if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
+ in_ignored_lib_ = true;
+ thr_->in_ignored_lib = true;
+ ThreadIgnoreBegin(thr_, pc_);
+ }
+}
+
+ScopedInterceptor::~ScopedInterceptor() {
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = false;
+ ThreadIgnoreEnd(thr_, pc_);
+ }
+ if (!thr_->ignore_interceptors) {
+ ProcessPendingSignals(thr_);
+ FuncExit(thr_);
+ CheckNoLocks(thr_);
+ }
+}
+
+#define SCOPED_INTERCEPTOR_RAW(func, ...) \
+ ThreadState *thr = cur_thread(); \
+ const uptr caller_pc = GET_CALLER_PC(); \
+ ScopedInterceptor si(thr, #func, caller_pc); \
+ const uptr pc = StackTrace::GetCurrentPc(); \
+ (void)pc; \
+/**/
+
+#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
+ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
+ if (REAL(func) == 0) { \
+ Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
+ Die(); \
+ } \
+ if (thr->ignore_interceptors || thr->in_ignored_lib) \
+ return REAL(func)(__VA_ARGS__); \
+/**/
+
+#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
+#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
+#if SANITIZER_FREEBSD
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
+#else
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
+#endif
+
+#define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
+
+struct BlockingCall {
+ explicit BlockingCall(ThreadState *thr)
+ : thr(thr)
+ , ctx(SigCtx(thr)) {
+ for (;;) {
+ atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed);
+ if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0)
+ break;
+ atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
+ ProcessPendingSignals(thr);
+ }
+ // When we are in a "blocking call", we process signals asynchronously
+ // (right when they arrive). In this context we do not expect to be
+ // executing any user/runtime code. The known interceptor sequence when
+ // this is not true is: pthread_join -> munmap(stack). It's fine
+ // to ignore munmap in this case -- we handle stack shadow separately.
+ thr->ignore_interceptors++;
+ }
+
+ ~BlockingCall() {
+ thr->ignore_interceptors--;
+ atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
+ }
+
+ ThreadState *thr;
+ SignalContext *ctx;
+};
+
+TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
+ SCOPED_TSAN_INTERCEPTOR(sleep, sec);
+ unsigned res = BLOCK_REAL(sleep)(sec);
+ AfterSleep(thr, pc);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, usleep, long_t usec) {
+ SCOPED_TSAN_INTERCEPTOR(usleep, usec);
+ int res = BLOCK_REAL(usleep)(usec);
+ AfterSleep(thr, pc);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
+ SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem);
+ int res = BLOCK_REAL(nanosleep)(req, rem);
+ AfterSleep(thr, pc);
+ return res;
+}
+
+// The sole reason tsan wraps atexit callbacks is to establish synchronization
+// between callback setup and callback execution.
+struct AtExitCtx {
+ void (*f)();
+ void *arg;
+};
+
+static void at_exit_wrapper(void *arg) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ Acquire(thr, pc, (uptr)arg);
+ AtExitCtx *ctx = (AtExitCtx*)arg;
+ ((void(*)(void *arg))ctx->f)(ctx->arg);
+ __libc_free(ctx);
+}
+
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+ void *arg, void *dso);
+
+TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
+ if (cur_thread()->in_symbolizer)
+ return 0;
+ // We want to setup the atexit callback even if we are in ignored lib
+ // or after fork.
+ SCOPED_INTERCEPTOR_RAW(atexit, f);
+ return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0);
+}
+
+TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
+ if (cur_thread()->in_symbolizer)
+ return 0;
+ SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
+ return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso);
+}
+
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+ void *arg, void *dso) {
+ AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+ ctx->f = f;
+ ctx->arg = arg;
+ Release(thr, pc, (uptr)ctx);
+ // Memory allocation in __cxa_atexit will race with free during exit,
+ // because we do not see synchronization around atexit callback list.
+ ThreadIgnoreBegin(thr, pc);
+ int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso);
+ ThreadIgnoreEnd(thr, pc);
+ return res;
+}
+
+static void on_exit_wrapper(int status, void *arg) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ Acquire(thr, pc, (uptr)arg);
+ AtExitCtx *ctx = (AtExitCtx*)arg;
+ ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg);
+ __libc_free(ctx);
+}
+
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+ if (cur_thread()->in_symbolizer)
+ return 0;
+ SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+ AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+ ctx->f = (void(*)())f;
+ ctx->arg = arg;
+ Release(thr, pc, (uptr)ctx);
+ // Memory allocation in __cxa_atexit will race with free during exit,
+ // because we do not see synchronization around atexit callback list.
+ ThreadIgnoreBegin(thr, pc);
+ int res = REAL(on_exit)(on_exit_wrapper, ctx);
+ ThreadIgnoreEnd(thr, pc);
+ return res;
+}
+
+// Cleanup old bufs.
+static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
+ for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
+ JmpBuf *buf = &thr->jmp_bufs[i];
+ if (buf->sp <= sp) {
+ uptr sz = thr->jmp_bufs.Size();
+ thr->jmp_bufs[i] = thr->jmp_bufs[sz - 1];
+ thr->jmp_bufs.PopBack();
+ i--;
+ }
+ }
+}
+
+static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
+ if (thr->shadow_stack_pos == 0) // called from libc guts during bootstrap
+ return;
+ // Cleanup old bufs.
+ JmpBufGarbageCollect(thr, sp);
+ // Remember the buf.
+ JmpBuf *buf = thr->jmp_bufs.PushBack();
+ buf->sp = sp;
+ buf->mangled_sp = mangled_sp;
+ buf->shadow_stack_pos = thr->shadow_stack_pos;
+ SignalContext *sctx = SigCtx(thr);
+ buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
+ buf->in_blocking_func = sctx ?
+ atomic_load(&sctx->in_blocking_func, memory_order_relaxed) :
+ false;
+ buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
+ memory_order_relaxed);
+}
+
+static void LongJmp(ThreadState *thr, uptr *env) {
+#if SANITIZER_FREEBSD
+ uptr mangled_sp = env[2];
+#else
+ uptr mangled_sp = env[6];
+#endif // SANITIZER_FREEBSD
+ // Find the saved buf by mangled_sp.
+ for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
+ JmpBuf *buf = &thr->jmp_bufs[i];
+ if (buf->mangled_sp == mangled_sp) {
+ CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos);
+ // Unwind the stack.
+ while (thr->shadow_stack_pos > buf->shadow_stack_pos)
+ FuncExit(thr);
+ SignalContext *sctx = SigCtx(thr);
+ if (sctx) {
+ sctx->int_signal_send = buf->int_signal_send;
+ atomic_store(&sctx->in_blocking_func, buf->in_blocking_func,
+ memory_order_relaxed);
+ }
+ atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
+ memory_order_relaxed);
+ JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp
+ return;
+ }
+ }
+ Printf("ThreadSanitizer: can't find longjmp buf\n");
+ CHECK(0);
+}
+
+// FIXME: put everything below into a common extern "C" block?
+extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
+ SetJmp(cur_thread(), sp, mangled_sp);
+}
+
+// Not called. Merely to satisfy TSAN_INTERCEPT().
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor_setjmp(void *env);
+extern "C" int __interceptor_setjmp(void *env) {
+ CHECK(0);
+ return 0;
+}
+
+// FIXME: any reason to have a separate declaration?
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor__setjmp(void *env);
+extern "C" int __interceptor__setjmp(void *env) {
+ CHECK(0);
+ return 0;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor_sigsetjmp(void *env);
+extern "C" int __interceptor_sigsetjmp(void *env) {
+ CHECK(0);
+ return 0;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor___sigsetjmp(void *env);
+extern "C" int __interceptor___sigsetjmp(void *env) {
+ CHECK(0);
+ return 0;
+}
+
+extern "C" int setjmp(void *env);
+extern "C" int _setjmp(void *env);
+extern "C" int sigsetjmp(void *env);
+extern "C" int __sigsetjmp(void *env);
+DEFINE_REAL(int, setjmp, void *env)
+DEFINE_REAL(int, _setjmp, void *env)
+DEFINE_REAL(int, sigsetjmp, void *env)
+DEFINE_REAL(int, __sigsetjmp, void *env)
+
+TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
+ {
+ SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
+ }
+ LongJmp(cur_thread(), env);
+ REAL(longjmp)(env, val);
+}
+
+TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
+ {
+ SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
+ }
+ LongJmp(cur_thread(), env);
+ REAL(siglongjmp)(env, val);
+}
+
+TSAN_INTERCEPTOR(void*, malloc, uptr size) {
+ if (cur_thread()->in_symbolizer)
+ return __libc_malloc(size);
+ void *p = 0;
+ {
+ SCOPED_INTERCEPTOR_RAW(malloc, size);
+ p = user_alloc(thr, pc, size);
+ }
+ invoke_malloc_hook(p, size);
+ return p;
+}
+
+TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
+ SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
+ return user_alloc(thr, pc, sz, align);
+}
+
+TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
+ if (cur_thread()->in_symbolizer)
+ return __libc_calloc(size, n);
+ void *p = 0;
+ {
+ SCOPED_INTERCEPTOR_RAW(calloc, size, n);
+ p = user_calloc(thr, pc, size, n);
+ }
+ invoke_malloc_hook(p, n * size);
+ return p;
+}
+
+TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
+ if (cur_thread()->in_symbolizer)
+ return __libc_realloc(p, size);
+ if (p)
+ invoke_free_hook(p);
+ {
+ SCOPED_INTERCEPTOR_RAW(realloc, p, size);
+ p = user_realloc(thr, pc, p, size);
+ }
+ invoke_malloc_hook(p, size);
+ return p;
+}
+
+TSAN_INTERCEPTOR(void, free, void *p) {
+ if (p == 0)
+ return;
+ if (cur_thread()->in_symbolizer)
+ return __libc_free(p);
+ invoke_free_hook(p);
+ SCOPED_INTERCEPTOR_RAW(free, p);
+ user_free(thr, pc, p);
+}
+
+TSAN_INTERCEPTOR(void, cfree, void *p) {
+ if (p == 0)
+ return;
+ if (cur_thread()->in_symbolizer)
+ return __libc_free(p);
+ invoke_free_hook(p);
+ SCOPED_INTERCEPTOR_RAW(cfree, p);
+ user_free(thr, pc, p);
+}
+
+TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
+ SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
+ return user_alloc_usable_size(p);
+}
+
+#define OPERATOR_NEW_BODY(mangled_name) \
+ if (cur_thread()->in_symbolizer) \
+ return __libc_malloc(size); \
+ void *p = 0; \
+ { \
+ SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
+ p = user_alloc(thr, pc, size); \
+ } \
+ invoke_malloc_hook(p, size); \
+ return p;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new(__sanitizer::uptr size);
+void *operator new(__sanitizer::uptr size) {
+ OPERATOR_NEW_BODY(_Znwm);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new[](__sanitizer::uptr size);
+void *operator new[](__sanitizer::uptr size) {
+ OPERATOR_NEW_BODY(_Znam);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
+void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
+ OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
+void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
+ OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
+}
+
+#define OPERATOR_DELETE_BODY(mangled_name) \
+ if (ptr == 0) return; \
+ if (cur_thread()->in_symbolizer) \
+ return __libc_free(ptr); \
+ invoke_free_hook(ptr); \
+ SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
+ user_free(thr, pc, ptr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete(void *ptr) throw();
+void operator delete(void *ptr) throw() {
+ OPERATOR_DELETE_BODY(_ZdlPv);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete[](void *ptr) throw();
+void operator delete[](void *ptr) throw() {
+ OPERATOR_DELETE_BODY(_ZdaPv);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&);
+void operator delete(void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&);
+void operator delete[](void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t);
+}
+
+TSAN_INTERCEPTOR(uptr, strlen, const char *s) {
+ SCOPED_TSAN_INTERCEPTOR(strlen, s);
+ uptr len = internal_strlen(s);
+ MemoryAccessRange(thr, pc, (uptr)s, len + 1, false);
+ return len;
+}
+
+TSAN_INTERCEPTOR(void*, memset, void *dst, int v, uptr size) {
+ SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size);
+ MemoryAccessRange(thr, pc, (uptr)dst, size, true);
+ return internal_memset(dst, v, size);
+}
+
+TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
+ SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size);
+ MemoryAccessRange(thr, pc, (uptr)dst, size, true);
+ MemoryAccessRange(thr, pc, (uptr)src, size, false);
+ return internal_memcpy(dst, src, size);
+}
+
+TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) {
+ SCOPED_TSAN_INTERCEPTOR(memcmp, s1, s2, n);
+ int res = 0;
+ uptr len = 0;
+ for (; len < n; len++) {
+ if ((res = ((const unsigned char *)s1)[len] -
+ ((const unsigned char *)s2)[len]))
+ break;
+ }
+ MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false);
+ MemoryAccessRange(thr, pc, (uptr)s2, len < n ? len + 1 : n, false);
+ return res;
+}
+
+TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) {
+ SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
+ MemoryAccessRange(thr, pc, (uptr)dst, n, true);
+ MemoryAccessRange(thr, pc, (uptr)src, n, false);
+ return REAL(memmove)(dst, src, n);
+}
+
+TSAN_INTERCEPTOR(char*, strchr, char *s, int c) {
+ SCOPED_TSAN_INTERCEPTOR(strchr, s, c);
+ char *res = REAL(strchr)(s, c);
+ uptr len = res ? (char*)res - (char*)s + 1 : internal_strlen(s) + 1;
+ MemoryAccessRange(thr, pc, (uptr)s, len, false);
+ return res;
+}
+
+TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) {
+ SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c);
+ char *res = REAL(strchrnul)(s, c);
+ uptr len = (char*)res - (char*)s + 1;
+ MemoryAccessRange(thr, pc, (uptr)s, len, false);
+ return res;
+}
+
+TSAN_INTERCEPTOR(char*, strrchr, char *s, int c) {
+ SCOPED_TSAN_INTERCEPTOR(strrchr, s, c);
+ MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s) + 1, false);
+ return REAL(strrchr)(s, c);
+}
+
+TSAN_INTERCEPTOR(char*, strcpy, char *dst, const char *src) { // NOLINT
+ SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src); // NOLINT
+ uptr srclen = internal_strlen(src);
+ MemoryAccessRange(thr, pc, (uptr)dst, srclen + 1, true);
+ MemoryAccessRange(thr, pc, (uptr)src, srclen + 1, false);
+ return REAL(strcpy)(dst, src); // NOLINT
+}
+
+TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) {
+ SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n);
+ uptr srclen = internal_strnlen(src, n);
+ MemoryAccessRange(thr, pc, (uptr)dst, n, true);
+ MemoryAccessRange(thr, pc, (uptr)src, min(srclen + 1, n), false);
+ return REAL(strncpy)(dst, src, n);
+}
+
+TSAN_INTERCEPTOR(const char*, strstr, const char *s1, const char *s2) {
+ SCOPED_TSAN_INTERCEPTOR(strstr, s1, s2);
+ const char *res = REAL(strstr)(s1, s2);
+ uptr len1 = internal_strlen(s1);
+ uptr len2 = internal_strlen(s2);
+ MemoryAccessRange(thr, pc, (uptr)s1, len1 + 1, false);
+ MemoryAccessRange(thr, pc, (uptr)s2, len2 + 1, false);
+ return res;
+}
+
+TSAN_INTERCEPTOR(char*, strdup, const char *str) {
+ SCOPED_TSAN_INTERCEPTOR(strdup, str);
+ // strdup will call malloc, so no instrumentation is required here.
+ return REAL(strdup)(str);
+}
+
+static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
+ if (*addr) {
+ if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) {
+ if (flags & MAP_FIXED) {
+ errno = EINVAL;
+ return false;
+ } else {
+ *addr = 0;
+ }
+ }
+ }
+ return true;
+}
+
+TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
+ int flags, int fd, unsigned off) {
+ SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off);
+ if (!fix_mmap_addr(&addr, sz, flags))
+ return MAP_FAILED;
+ void *res = REAL(mmap)(addr, sz, prot, flags, fd, off);
+ if (res != MAP_FAILED) {
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
+ }
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
+ int flags, int fd, u64 off) {
+ SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off);
+ if (!fix_mmap_addr(&addr, sz, flags))
+ return MAP_FAILED;
+ void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off);
+ if (res != MAP_FAILED) {
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
+ }
+ return res;
+}
+#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64)
+#else
+#define TSAN_MAYBE_INTERCEPT_MMAP64
+#endif
+
+TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
+ SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
+ DontNeedShadowFor((uptr)addr, sz);
+ int res = REAL(munmap)(addr, sz);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
+ SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
+ return user_alloc(thr, pc, sz, align);
+}
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign)
+#else
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
+
+TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
+ SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
+ return user_alloc(thr, pc, sz, align);
+}
+
+TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
+ SCOPED_INTERCEPTOR_RAW(valloc, sz);
+ return user_alloc(thr, pc, sz, GetPageSizeCached());
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
+ SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
+ sz = RoundUp(sz, GetPageSizeCached());
+ return user_alloc(thr, pc, sz, GetPageSizeCached());
+}
+#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc)
+#else
+#define TSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
+
+TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
+ SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
+ *memptr = user_alloc(thr, pc, sz, align);
+ return 0;
+}
+
+// Used in thread-safe function static initialization.
+extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) {
+ SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
+ for (;;) {
+ u32 cmp = atomic_load(g, memory_order_acquire);
+ if (cmp == 0) {
+ if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed))
+ return 1;
+ } else if (cmp == 1) {
+ Acquire(thr, pc, (uptr)g);
+ return 0;
+ } else {
+ internal_sched_yield();
+ }
+ }
+}
+
+extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_release(atomic_uint32_t *g) {
+ SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
+ Release(thr, pc, (uptr)g);
+ atomic_store(g, 1, memory_order_release);
+}
+
+extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_abort(atomic_uint32_t *g) {
+ SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g);
+ atomic_store(g, 0, memory_order_relaxed);
+}
+
+static void thread_finalize(void *v) {
+ uptr iter = (uptr)v;
+ if (iter > 1) {
+ if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+ Printf("ThreadSanitizer: failed to set thread key\n");
+ Die();
+ }
+ return;
+ }
+ {
+ ThreadState *thr = cur_thread();
+ ThreadFinish(thr);
+ SignalContext *sctx = thr->signal_ctx;
+ if (sctx) {
+ thr->signal_ctx = 0;
+ UnmapOrDie(sctx, sizeof(*sctx));
+ }
+ }
+}
+
+
+struct ThreadParam {
+ void* (*callback)(void *arg);
+ void *param;
+ atomic_uintptr_t tid;
+};
+
+extern "C" void *__tsan_thread_start_func(void *arg) {
+ ThreadParam *p = (ThreadParam*)arg;
+ void* (*callback)(void *arg) = p->callback;
+ void *param = p->param;
+ int tid = 0;
+ {
+ ThreadState *thr = cur_thread();
+ // Thread-local state is not initialized yet.
+ ScopedIgnoreInterceptors ignore;
+ ThreadIgnoreBegin(thr, 0);
+ if (pthread_setspecific(g_thread_finalize_key,
+ (void *)kPthreadDestructorIterations)) {
+ Printf("ThreadSanitizer: failed to set thread key\n");
+ Die();
+ }
+ ThreadIgnoreEnd(thr, 0);
+ while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
+ pthread_yield();
+ atomic_store(&p->tid, 0, memory_order_release);
+ ThreadStart(thr, tid, GetTid());
+ }
+ void *res = callback(param);
+ // Prevent the callback from being tail called,
+ // it mixes up stack traces.
+ volatile int foo = 42;
+ foo++;
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_create,
+ void *th, void *attr, void *(*callback)(void*), void * param) {
+ SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param);
+ if (ctx->after_multithreaded_fork) {
+ if (flags()->die_after_fork) {
+ Report("ThreadSanitizer: starting new threads after multi-threaded "
+ "fork is not supported. Dying (set die_after_fork=0 to override)\n");
+ Die();
+ } else {
+ VPrintf(1, "ThreadSanitizer: starting new threads after multi-threaded "
+ "fork is not supported (pid %d). Continuing because of "
+ "die_after_fork=0, but you are on your own\n", internal_getpid());
+ }
+ }
+ __sanitizer_pthread_attr_t myattr;
+ if (attr == 0) {
+ pthread_attr_init(&myattr);
+ attr = &myattr;
+ }
+ int detached = 0;
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
+ AdjustStackSize(attr);
+
+ ThreadParam p;
+ p.callback = callback;
+ p.param = param;
+ atomic_store(&p.tid, 0, memory_order_relaxed);
+ int res = -1;
+ {
+ // Otherwise we see false positives in pthread stack manipulation.
+ ScopedIgnoreInterceptors ignore;
+ ThreadIgnoreBegin(thr, pc);
+ res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p);
+ ThreadIgnoreEnd(thr, pc);
+ }
+ if (res == 0) {
+ int tid = ThreadCreate(thr, pc, *(uptr*)th, detached);
+ CHECK_NE(tid, 0);
+ atomic_store(&p.tid, tid, memory_order_release);
+ while (atomic_load(&p.tid, memory_order_acquire) != 0)
+ pthread_yield();
+ }
+ if (attr == &myattr)
+ pthread_attr_destroy(&myattr);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
+ SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
+ int tid = ThreadTid(thr, pc, (uptr)th);
+ ThreadIgnoreBegin(thr, pc);
+ int res = BLOCK_REAL(pthread_join)(th, ret);
+ ThreadIgnoreEnd(thr, pc);
+ if (res == 0) {
+ ThreadJoin(thr, pc, tid);
+ }
+ return res;
+}
+
+DEFINE_REAL_PTHREAD_FUNCTIONS
+
+TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_detach, th);
+ int tid = ThreadTid(thr, pc, (uptr)th);
+ int res = REAL(pthread_detach)(th);
+ if (res == 0) {
+ ThreadDetach(thr, pc, tid);
+ }
+ return res;
+}
+
+// Problem:
+// NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
+// pthread_cond_t has different size in the different versions.
+// If call new REAL functions for old pthread_cond_t, they will corrupt memory
+// after pthread_cond_t (old cond is smaller).
+// If we call old REAL functions for new pthread_cond_t, we will lose some
+// functionality (e.g. old functions do not support waiting against
+// CLOCK_REALTIME).
+// Proper handling would require to have 2 versions of interceptors as well.
+// But this is messy, in particular requires linker scripts when sanitizer
+// runtime is linked into a shared library.
+// Instead we assume we don't have dynamic libraries built against old
+// pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag
+// that allows to work with old libraries (but this mode does not support
+// some features, e.g. pthread_condattr_getpshared).
+static void *init_cond(void *c, bool force = false) {
+ // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions.
+ // So we allocate additional memory on the side large enough to hold
+ // any pthread_cond_t object. Always call new REAL functions, but pass
+ // the aux object to them.
+ // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes
+ // first word of pthread_cond_t to zero.
+ // It's all relevant only for linux.
+ if (!common_flags()->legacy_pthread_cond)
+ return c;
+ atomic_uintptr_t *p = (atomic_uintptr_t*)c;
+ uptr cond = atomic_load(p, memory_order_acquire);
+ if (!force && cond != 0)
+ return (void*)cond;
+ void *newcond = WRAP(malloc)(pthread_cond_t_sz);
+ internal_memset(newcond, 0, pthread_cond_t_sz);
+ if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
+ memory_order_acq_rel))
+ return newcond;
+ WRAP(free)(newcond);
+ return (void*)cond;
+}
+
+struct CondMutexUnlockCtx {
+ ThreadState *thr;
+ uptr pc;
+ void *m;
+};
+
+static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
+ MutexLock(arg->thr, arg->pc, (uptr)arg->m);
+}
+
+INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
+ void *cond = init_cond(c, true);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
+ return REAL(pthread_cond_init)(cond, a);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
+ MutexUnlock(thr, pc, (uptr)m);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ CondMutexUnlockCtx arg = {thr, pc, m};
+ // This ensures that we handle mutex lock even in case of pthread_cancel.
+ // See test/tsan/cond_cancel.cc.
+ int res = call_pthread_cancel_with_cleanup(
+ (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
+ cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
+ if (res == errno_EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
+ MutexUnlock(thr, pc, (uptr)m);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ CondMutexUnlockCtx arg = {thr, pc, m};
+ // This ensures that we handle mutex lock even in case of pthread_cancel.
+ // See test/tsan/cond_cancel.cc.
+ int res = call_pthread_cancel_with_cleanup(
+ REAL(pthread_cond_timedwait), cond, m, abstime,
+ (void(*)(void *arg))cond_mutex_unlock, &arg);
+ if (res == errno_EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_signal, void *c) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_destroy, void *c) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
+ int res = REAL(pthread_cond_destroy)(cond);
+ if (common_flags()->legacy_pthread_cond) {
+ // Free our aux cond and zero the pointer to not leave dangling pointers.
+ WRAP(free)(cond);
+ atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a);
+ int res = REAL(pthread_mutex_init)(m, a);
+ if (res == 0) {
+ bool recursive = false;
+ if (a) {
+ int type = 0;
+ if (REAL(pthread_mutexattr_gettype)(a, &type) == 0)
+ recursive = (type == PTHREAD_MUTEX_RECURSIVE
+ || type == PTHREAD_MUTEX_RECURSIVE_NP);
+ }
+ MutexCreate(thr, pc, (uptr)m, false, recursive, false);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m);
+ int res = REAL(pthread_mutex_destroy)(m);
+ if (res == 0 || res == EBUSY) {
+ MutexDestroy(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
+ int res = REAL(pthread_mutex_trylock)(m);
+ if (res == EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ if (res == 0 || res == EOWNERDEAD)
+ MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime);
+ int res = REAL(pthread_mutex_timedlock)(m, abstime);
+ if (res == 0) {
+ MutexLock(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
+ int res = REAL(pthread_spin_init)(m, pshared);
+ if (res == 0) {
+ MutexCreate(thr, pc, (uptr)m, false, false, false);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_spin_destroy, m);
+ int res = REAL(pthread_spin_destroy)(m);
+ if (res == 0) {
+ MutexDestroy(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m);
+ int res = REAL(pthread_spin_lock)(m);
+ if (res == 0) {
+ MutexLock(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m);
+ int res = REAL(pthread_spin_trylock)(m);
+ if (res == 0) {
+ MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m);
+ MutexUnlock(thr, pc, (uptr)m);
+ int res = REAL(pthread_spin_unlock)(m);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a);
+ int res = REAL(pthread_rwlock_init)(m, a);
+ if (res == 0) {
+ MutexCreate(thr, pc, (uptr)m, true, false, false);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_destroy, m);
+ int res = REAL(pthread_rwlock_destroy)(m);
+ if (res == 0) {
+ MutexDestroy(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m);
+ int res = REAL(pthread_rwlock_rdlock)(m);
+ if (res == 0) {
+ MutexReadLock(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m);
+ int res = REAL(pthread_rwlock_tryrdlock)(m);
+ if (res == 0) {
+ MutexReadLock(thr, pc, (uptr)m, /*try_lock=*/true);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime);
+ int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
+ if (res == 0) {
+ MutexReadLock(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
+ int res = REAL(pthread_rwlock_wrlock)(m);
+ if (res == 0) {
+ MutexLock(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m);
+ int res = REAL(pthread_rwlock_trywrlock)(m);
+ if (res == 0) {
+ MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime);
+ int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
+ if (res == 0) {
+ MutexLock(thr, pc, (uptr)m);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m);
+ MutexReadOrWriteUnlock(thr, pc, (uptr)m);
+ int res = REAL(pthread_rwlock_unlock)(m);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
+ MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
+ int res = REAL(pthread_barrier_init)(b, a, count);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b);
+ MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
+ int res = REAL(pthread_barrier_destroy)(b);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b);
+ Release(thr, pc, (uptr)b);
+ MemoryRead(thr, pc, (uptr)b, kSizeLog1);
+ int res = REAL(pthread_barrier_wait)(b);
+ MemoryRead(thr, pc, (uptr)b, kSizeLog1);
+ if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) {
+ Acquire(thr, pc, (uptr)b);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
+ SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
+ if (o == 0 || f == 0)
+ return EINVAL;
+ atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
+ u32 v = atomic_load(a, memory_order_acquire);
+ if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
+ memory_order_relaxed)) {
+ (*f)();
+ if (!thr->in_ignored_lib)
+ Release(thr, pc, (uptr)o);
+ atomic_store(a, 2, memory_order_release);
+ } else {
+ while (v != 2) {
+ pthread_yield();
+ v = atomic_load(a, memory_order_acquire);
+ }
+ if (!thr->in_ignored_lib)
+ Acquire(thr, pc, (uptr)o);
+ }
+ return 0;
+}
+
+TSAN_INTERCEPTOR(int, sem_init, void *s, int pshared, unsigned value) {
+ SCOPED_TSAN_INTERCEPTOR(sem_init, s, pshared, value);
+ int res = REAL(sem_init)(s, pshared, value);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, sem_destroy, void *s) {
+ SCOPED_TSAN_INTERCEPTOR(sem_destroy, s);
+ int res = REAL(sem_destroy)(s);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, sem_wait, void *s) {
+ SCOPED_TSAN_INTERCEPTOR(sem_wait, s);
+ int res = BLOCK_REAL(sem_wait)(s);
+ if (res == 0) {
+ Acquire(thr, pc, (uptr)s);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, sem_trywait, void *s) {
+ SCOPED_TSAN_INTERCEPTOR(sem_trywait, s);
+ int res = BLOCK_REAL(sem_trywait)(s);
+ if (res == 0) {
+ Acquire(thr, pc, (uptr)s);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, sem_timedwait, void *s, void *abstime) {
+ SCOPED_TSAN_INTERCEPTOR(sem_timedwait, s, abstime);
+ int res = BLOCK_REAL(sem_timedwait)(s, abstime);
+ if (res == 0) {
+ Acquire(thr, pc, (uptr)s);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, sem_post, void *s) {
+ SCOPED_TSAN_INTERCEPTOR(sem_post, s);
+ Release(thr, pc, (uptr)s);
+ int res = REAL(sem_post)(s);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, sem_getvalue, void *s, int *sval) {
+ SCOPED_TSAN_INTERCEPTOR(sem_getvalue, s, sval);
+ int res = REAL(sem_getvalue)(s, sval);
+ if (res == 0) {
+ Acquire(thr, pc, (uptr)s);
+ }
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
+ return REAL(__xstat)(version, path, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT
+#endif
+
+TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+ SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
+ return REAL(stat)(path, buf);
+#else
+ SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
+ return REAL(__xstat)(0, path, buf);
+#endif
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
+ return REAL(__xstat64)(version, path, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
+ return REAL(__xstat64)(0, path, buf);
+}
+#define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_STAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
+ return REAL(__lxstat)(version, path, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
+
+TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+ SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
+ return REAL(lstat)(path, buf);
+#else
+ SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
+ return REAL(__lxstat)(0, path, buf);
+#endif
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
+ return REAL(__lxstat64)(version, path, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
+ return REAL(__lxstat64)(0, path, buf);
+}
+#define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_LSTAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat)(version, fd, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
+
+TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+#if SANITIZER_FREEBSD
+ SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(fstat)(fd, buf);
+#else
+ SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat)(0, fd, buf);
+#endif
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat64)(version, fd, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat64)(0, fd, buf);
+}
+#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_FSTAT64
+#endif
+
+TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
+ SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
+ int fd = REAL(open)(name, flags, mode);
+ if (fd >= 0)
+ FdFileCreate(thr, pc, fd);
+ return fd;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
+ SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
+ int fd = REAL(open64)(name, flags, mode);
+ if (fd >= 0)
+ FdFileCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64)
+#else
+#define TSAN_MAYBE_INTERCEPT_OPEN64
+#endif
+
+TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
+ SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
+ int fd = REAL(creat)(name, mode);
+ if (fd >= 0)
+ FdFileCreate(thr, pc, fd);
+ return fd;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
+ SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
+ int fd = REAL(creat64)(name, mode);
+ if (fd >= 0)
+ FdFileCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_CREAT64
+#endif
+
+TSAN_INTERCEPTOR(int, dup, int oldfd) {
+ SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
+ int newfd = REAL(dup)(oldfd);
+ if (oldfd >= 0 && newfd >= 0 && newfd != oldfd)
+ FdDup(thr, pc, oldfd, newfd);
+ return newfd;
+}
+
+TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) {
+ SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd);
+ int newfd2 = REAL(dup2)(oldfd, newfd);
+ if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd)
+ FdDup(thr, pc, oldfd, newfd2);
+ return newfd2;
+}
+
+TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags);
+ int newfd2 = REAL(dup3)(oldfd, newfd, flags);
+ if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd)
+ FdDup(thr, pc, oldfd, newfd2);
+ return newfd2;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
+ int fd = REAL(eventfd)(initval, flags);
+ if (fd >= 0)
+ FdEventCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_EVENTFD
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags);
+ if (fd >= 0)
+ FdClose(thr, pc, fd);
+ fd = REAL(signalfd)(fd, mask, flags);
+ if (fd >= 0)
+ FdSignalCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, inotify_init, int fake) {
+ SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
+ int fd = REAL(inotify_init)(fake);
+ if (fd >= 0)
+ FdInotifyCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
+ int fd = REAL(inotify_init1)(flags);
+ if (fd >= 0)
+ FdInotifyCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1
+#endif
+
+TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) {
+ SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol);
+ int fd = REAL(socket)(domain, type, protocol);
+ if (fd >= 0)
+ FdSocketCreate(thr, pc, fd);
+ return fd;
+}
+
+TSAN_INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int *fd) {
+ SCOPED_TSAN_INTERCEPTOR(socketpair, domain, type, protocol, fd);
+ int res = REAL(socketpair)(domain, type, protocol, fd);
+ if (res == 0 && fd[0] >= 0 && fd[1] >= 0)
+ FdPipeCreate(thr, pc, fd[0], fd[1]);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) {
+ SCOPED_TSAN_INTERCEPTOR(connect, fd, addr, addrlen);
+ FdSocketConnecting(thr, pc, fd);
+ int res = REAL(connect)(fd, addr, addrlen);
+ if (res == 0 && fd >= 0)
+ FdSocketConnect(thr, pc, fd);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) {
+ SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen);
+ int res = REAL(bind)(fd, addr, addrlen);
+ if (fd > 0 && res == 0)
+ FdAccess(thr, pc, fd);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
+ SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog);
+ int res = REAL(listen)(fd, backlog);
+ if (fd > 0 && res == 0)
+ FdAccess(thr, pc, fd);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, epoll_create, int size) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
+ int fd = REAL(epoll_create)(size);
+ if (fd >= 0)
+ FdPollCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE TSAN_INTERCEPT(epoll_create)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
+ int fd = REAL(epoll_create1)(flags);
+ if (fd >= 0)
+ FdPollCreate(thr, pc, fd);
+ return fd;
+}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 TSAN_INTERCEPT(epoll_create1)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1
+#endif
+
+TSAN_INTERCEPTOR(int, close, int fd) {
+ SCOPED_TSAN_INTERCEPTOR(close, fd);
+ if (fd >= 0)
+ FdClose(thr, pc, fd);
+ return REAL(close)(fd);
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, __close, int fd) {
+ SCOPED_TSAN_INTERCEPTOR(__close, fd);
+ if (fd >= 0)
+ FdClose(thr, pc, fd);
+ return REAL(__close)(fd);
+}
+#define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close)
+#else
+#define TSAN_MAYBE_INTERCEPT___CLOSE
+#endif
+
+// glibc guts
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
+ SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
+ int fds[64];
+ int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds));
+ for (int i = 0; i < cnt; i++) {
+ if (fds[i] > 0)
+ FdClose(thr, pc, fds[i]);
+ }
+ REAL(__res_iclose)(state, free_addr);
+}
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose)
+#else
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE
+#endif
+
+TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
+ SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
+ int res = REAL(pipe)(pipefd);
+ if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0)
+ FdPipeCreate(thr, pc, pipefd[0], pipefd[1]);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags);
+ int res = REAL(pipe2)(pipefd, flags);
+ if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0)
+ FdPipeCreate(thr, pc, pipefd[0], pipefd[1]);
+ return res;
+}
+
+TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
+ if (fd >= 0) {
+ FdAccess(thr, pc, fd);
+ FdRelease(thr, pc, fd);
+ }
+ int res = REAL(send)(fd, buf, len, flags);
+ return res;
+}
+
+TSAN_INTERCEPTOR(long_t, sendmsg, int fd, void *msg, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(sendmsg, fd, msg, flags);
+ if (fd >= 0) {
+ FdAccess(thr, pc, fd);
+ FdRelease(thr, pc, fd);
+ }
+ int res = REAL(sendmsg)(fd, msg, flags);
+ return res;
+}
+
+TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(recv, fd, buf, len, flags);
+ if (fd >= 0)
+ FdAccess(thr, pc, fd);
+ int res = REAL(recv)(fd, buf, len, flags);
+ if (res >= 0 && fd >= 0) {
+ FdAcquire(thr, pc, fd);
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, unlink, char *path) {
+ SCOPED_TSAN_INTERCEPTOR(unlink, path);
+ Release(thr, pc, File2addr(path));
+ int res = REAL(unlink)(path);
+ return res;
+}
+
+TSAN_INTERCEPTOR(void*, tmpfile, int fake) {
+ SCOPED_TSAN_INTERCEPTOR(tmpfile, fake);
+ void *res = REAL(tmpfile)(fake);
+ if (res) {
+ int fd = fileno_unlocked(res);
+ if (fd >= 0)
+ FdFileCreate(thr, pc, fd);
+ }
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
+ SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
+ void *res = REAL(tmpfile64)(fake);
+ if (res) {
+ int fd = fileno_unlocked(res);
+ if (fd >= 0)
+ FdFileCreate(thr, pc, fd);
+ }
+ return res;
+}
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64)
+#else
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64
+#endif
+
+TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
+ // libc file streams can call user-supplied functions, see fopencookie.
+ {
+ SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f);
+ MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true);
+ }
+ return REAL(fread)(ptr, size, nmemb, f);
+}
+
+TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
+ // libc file streams can call user-supplied functions, see fopencookie.
+ {
+ SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f);
+ MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false);
+ }
+ return REAL(fwrite)(p, size, nmemb, f);
+}
+
+static void FlushStreams() {
+ // Flushing all the streams here may freeze the process if a child thread is
+ // performing file stream operations at the same time.
+ REAL(fflush)(stdout);
+ REAL(fflush)(stderr);
+}
+
+TSAN_INTERCEPTOR(void, abort, int fake) {
+ SCOPED_TSAN_INTERCEPTOR(abort, fake);
+ FlushStreams();
+ REAL(abort)(fake);
+}
+
+TSAN_INTERCEPTOR(int, puts, const char *s) {
+ SCOPED_TSAN_INTERCEPTOR(puts, s);
+ MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s), false);
+ return REAL(puts)(s);
+}
+
+TSAN_INTERCEPTOR(int, rmdir, char *path) {
+ SCOPED_TSAN_INTERCEPTOR(rmdir, path);
+ Release(thr, pc, Dir2addr(path));
+ int res = REAL(rmdir)(path);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, closedir, void *dirp) {
+ SCOPED_TSAN_INTERCEPTOR(closedir, dirp);
+ int fd = dirfd(dirp);
+ FdClose(thr, pc, fd);
+ return REAL(closedir)(dirp);
+}
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
+ if (epfd >= 0)
+ FdAccess(thr, pc, epfd);
+ if (epfd >= 0 && fd >= 0)
+ FdAccess(thr, pc, fd);
+ if (op == EPOLL_CTL_ADD && epfd >= 0)
+ FdRelease(thr, pc, epfd);
+ int res = REAL(epoll_ctl)(epfd, op, fd, ev);
+ return res;
+}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL TSAN_INTERCEPT(epoll_ctl)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
+#endif
+
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
+ if (epfd >= 0)
+ FdAccess(thr, pc, epfd);
+ int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout);
+ if (res > 0 && epfd >= 0)
+ FdAcquire(thr, pc, epfd);
+ return res;
+}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT TSAN_INTERCEPT(epoll_wait)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
+
+namespace __tsan {
+
+static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
+ bool sigact, int sig, my_siginfo_t *info, void *uctx) {
+ if (acquire)
+ Acquire(thr, 0, (uptr)&sigactions[sig]);
+ // Ensure that the handler does not spoil errno.
+ const int saved_errno = errno;
+ errno = 99;
+ // This code races with sigaction. Be careful to not read sa_sigaction twice.
+ // Also need to remember pc for reporting before the call,
+ // because the handler can reset it.
+ volatile uptr pc = sigact ?
+ (uptr)sigactions[sig].sa_sigaction :
+ (uptr)sigactions[sig].sa_handler;
+ if (pc != (uptr)SIG_DFL && pc != (uptr)SIG_IGN) {
+ if (sigact)
+ ((sigactionhandler_t)pc)(sig, info, uctx);
+ else
+ ((sighandler_t)pc)(sig);
+ }
+ // We do not detect errno spoiling for SIGTERM,
+ // because some SIGTERM handlers do spoil errno but reraise SIGTERM,
+ // tsan reports false positive in such case.
+ // It's difficult to properly detect this situation (reraise),
+ // because in async signal processing case (when handler is called directly
+ // from rtl_generic_sighandler) we have not yet received the reraised
+ // signal; and it looks too fragile to intercept all ways to reraise a signal.
+ if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
+ VarSizeStackTrace stack;
+ // StackTrace::GetNestInstructionPc(pc) is used because return address is
+ // expected, OutputReport() will undo this.
+ ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack);
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeErrnoInSignal);
+ if (!IsFiredSuppression(ctx, rep, stack)) {
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
+ }
+ }
+ errno = saved_errno;
+}
+
+void ProcessPendingSignals(ThreadState *thr) {
+ SignalContext *sctx = SigCtx(thr);
+ if (sctx == 0 ||
+ atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0)
+ return;
+ atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed);
+ atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
+ // These are too big for stack.
+ static THREADLOCAL __sanitizer_sigset_t emptyset, oldset;
+ REAL(sigfillset)(&emptyset);
+ pthread_sigmask(SIG_SETMASK, &emptyset, &oldset);
+ for (int sig = 0; sig < kSigCount; sig++) {
+ SignalDesc *signal = &sctx->pending_signals[sig];
+ if (signal->armed) {
+ signal->armed = false;
+ CallUserSignalHandler(thr, false, true, signal->sigaction, sig,
+ &signal->siginfo, &signal->ctx);
+ }
+ }
+ pthread_sigmask(SIG_SETMASK, &oldset, 0);
+ atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
+}
+
+} // namespace __tsan
+
+static bool is_sync_signal(SignalContext *sctx, int sig) {
+ return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
+ sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
+ // If we are sending signal to ourselves, we must process it now.
+ (sctx && sig == sctx->int_signal_send);
+}
+
+void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
+ my_siginfo_t *info, void *ctx) {
+ ThreadState *thr = cur_thread();
+ SignalContext *sctx = SigCtx(thr);
+ if (sig < 0 || sig >= kSigCount) {
+ VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig);
+ return;
+ }
+ // Don't mess with synchronous signals.
+ const bool sync = is_sync_signal(sctx, sig);
+ if (sync ||
+ // If we are in blocking function, we can safely process it now
+ // (but check if we are in a recursive interceptor,
+ // i.e. pthread_join()->munmap()).
+ (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) {
+ atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
+ if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) {
+ // We ignore interceptors in blocking functions,
+ // temporary enbled them again while we are calling user function.
+ int const i = thr->ignore_interceptors;
+ thr->ignore_interceptors = 0;
+ atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed);
+ CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx);
+ thr->ignore_interceptors = i;
+ atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed);
+ } else {
+ // Be very conservative with when we do acquire in this case.
+ // It's unsafe to do acquire in async handlers, because ThreadState
+ // can be in inconsistent state.
+ // SIGSYS looks relatively safe -- it's synchronous and can actually
+ // need some global state.
+ bool acq = (sig == SIGSYS);
+ CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx);
+ }
+ atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
+ return;
+ }
+
+ if (sctx == 0)
+ return;
+ SignalDesc *signal = &sctx->pending_signals[sig];
+ if (signal->armed == false) {
+ signal->armed = true;
+ signal->sigaction = sigact;
+ if (info)
+ internal_memcpy(&signal->siginfo, info, sizeof(*info));
+ if (ctx)
+ internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx));
+ atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed);
+ }
+}
+
+static void rtl_sighandler(int sig) {
+ rtl_generic_sighandler(false, sig, 0, 0);
+}
+
+static void rtl_sigaction(int sig, my_siginfo_t *info, void *ctx) {
+ rtl_generic_sighandler(true, sig, info, ctx);
+}
+
+TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
+ SCOPED_TSAN_INTERCEPTOR(sigaction, sig, act, old);
+ if (old)
+ internal_memcpy(old, &sigactions[sig], sizeof(*old));
+ if (act == 0)
+ return 0;
+ // Copy act into sigactions[sig].
+ // Can't use struct copy, because compiler can emit call to memcpy.
+ // Can't use internal_memcpy, because it copies byte-by-byte,
+ // and signal handler reads the sa_handler concurrently. It it can read
+ // some bytes from old value and some bytes from new value.
+ // Use volatile to prevent insertion of memcpy.
+ sigactions[sig].sa_handler = *(volatile sighandler_t*)&act->sa_handler;
+ sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags;
+ internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask,
+ sizeof(sigactions[sig].sa_mask));
+#if !SANITIZER_FREEBSD
+ sigactions[sig].sa_restorer = act->sa_restorer;
+#endif
+ sigaction_t newact;
+ internal_memcpy(&newact, act, sizeof(newact));
+ REAL(sigfillset)(&newact.sa_mask);
+ if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) {
+ if (newact.sa_flags & SA_SIGINFO)
+ newact.sa_sigaction = rtl_sigaction;
+ else
+ newact.sa_handler = rtl_sighandler;
+ }
+ ReleaseStore(thr, pc, (uptr)&sigactions[sig]);
+ int res = REAL(sigaction)(sig, &newact, 0);
+ return res;
+}
+
+TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) {
+ sigaction_t act;
+ act.sa_handler = h;
+ REAL(memset)(&act.sa_mask, -1, sizeof(act.sa_mask));
+ act.sa_flags = 0;
+ sigaction_t old;
+ int res = sigaction(sig, &act, &old);
+ if (res)
+ return SIG_ERR;
+ return old.sa_handler;
+}
+
+TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) {
+ SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask);
+ return REAL(sigsuspend)(mask);
+}
+
+TSAN_INTERCEPTOR(int, raise, int sig) {
+ SCOPED_TSAN_INTERCEPTOR(raise, sig);
+ SignalContext *sctx = SigCtx(thr);
+ CHECK_NE(sctx, 0);
+ int prev = sctx->int_signal_send;
+ sctx->int_signal_send = sig;
+ int res = REAL(raise)(sig);
+ CHECK_EQ(sctx->int_signal_send, sig);
+ sctx->int_signal_send = prev;
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, kill, int pid, int sig) {
+ SCOPED_TSAN_INTERCEPTOR(kill, pid, sig);
+ SignalContext *sctx = SigCtx(thr);
+ CHECK_NE(sctx, 0);
+ int prev = sctx->int_signal_send;
+ if (pid == (int)internal_getpid()) {
+ sctx->int_signal_send = sig;
+ }
+ int res = REAL(kill)(pid, sig);
+ if (pid == (int)internal_getpid()) {
+ CHECK_EQ(sctx->int_signal_send, sig);
+ sctx->int_signal_send = prev;
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig);
+ SignalContext *sctx = SigCtx(thr);
+ CHECK_NE(sctx, 0);
+ int prev = sctx->int_signal_send;
+ if (tid == pthread_self()) {
+ sctx->int_signal_send = sig;
+ }
+ int res = REAL(pthread_kill)(tid, sig);
+ if (tid == pthread_self()) {
+ CHECK_EQ(sctx->int_signal_send, sig);
+ sctx->int_signal_send = prev;
+ }
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
+ SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz);
+ // It's intercepted merely to process pending signals.
+ return REAL(gettimeofday)(tv, tz);
+}
+
+TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
+ void *hints, void *rv) {
+ SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv);
+ // We miss atomic synchronization in getaddrinfo,
+ // and can report false race between malloc and free
+ // inside of getaddrinfo. So ignore memory accesses.
+ ThreadIgnoreBegin(thr, pc);
+ int res = REAL(getaddrinfo)(node, service, hints, rv);
+ ThreadIgnoreEnd(thr, pc);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, fork, int fake) {
+ if (cur_thread()->in_symbolizer)
+ return REAL(fork)(fake);
+ SCOPED_INTERCEPTOR_RAW(fork, fake);
+ ForkBefore(thr, pc);
+ int pid = REAL(fork)(fake);
+ if (pid == 0) {
+ // child
+ ForkChildAfter(thr, pc);
+ FdOnFork(thr, pc);
+ } else if (pid > 0) {
+ // parent
+ ForkParentAfter(thr, pc);
+ } else {
+ // error
+ ForkParentAfter(thr, pc);
+ }
+ return pid;
+}
+
+TSAN_INTERCEPTOR(int, vfork, int fake) {
+ // Some programs (e.g. openjdk) call close for all file descriptors
+ // in the child process. Under tsan it leads to false positives, because
+ // address space is shared, so the parent process also thinks that
+ // the descriptors are closed (while they are actually not).
+ // This leads to false positives due to missed synchronization.
+ // Strictly saying this is undefined behavior, because vfork child is not
+ // allowed to call any functions other than exec/exit. But this is what
+ // openjdk does, so we want to handle it.
+ // We could disable interceptors in the child process. But it's not possible
+ // to simply intercept and wrap vfork, because vfork child is not allowed
+ // to return from the function that calls vfork, and that's exactly what
+ // we would do. So this would require some assembly trickery as well.
+ // Instead we simply turn vfork into fork.
+ return WRAP(fork)(fake);
+}
+
+static int OnExit(ThreadState *thr) {
+ int status = Finalize(thr);
+ FlushStreams();
+ return status;
+}
+
+struct TsanInterceptorContext {
+ ThreadState *thr;
+ const uptr caller_pc;
+ const uptr pc;
+};
+
+static void HandleRecvmsg(ThreadState *thr, uptr pc,
+ __sanitizer_msghdr *msg) {
+ int fds[64];
+ int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds));
+ for (int i = 0; i < cnt; i++)
+ FdEventCreate(thr, pc, fds[i]);
+}
+
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+// Causes interceptor recursion (getaddrinfo() and fopen())
+#undef SANITIZER_INTERCEPT_GETADDRINFO
+// There interceptors do not seem to be strictly necessary for tsan.
+// But we see cases where the interceptors consume 70% of execution time.
+// Memory blocks passed to fgetgrent_r are "written to" by tsan several times.
+// First, there is some recursion (getgrnam_r calls fgetgrent_r), and each
+// function "writes to" the buffer. Then, the same memory is "written to"
+// twice, first as buf and then as pwbufp (both of them refer to the same
+// addresses).
+#undef SANITIZER_INTERCEPT_GETPWENT
+#undef SANITIZER_INTERCEPT_GETPWENT_R
+#undef SANITIZER_INTERCEPT_FGETPWENT
+#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+// __tls_get_addr can be called with mis-aligned stack due to:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
+// There are two potential issues:
+// 1. Sanitizer code contains a MOVDQA spill (it does not seem to be the case
+// right now). or 2. ProcessPendingSignal calls user handler which contains
+// MOVDQA spill (this happens right now).
+// Since the interceptor only initializes memory for msan, the simplest solution
+// is to disable the interceptor in tsan (other sanitizers do not call
+// signal handlers from COMMON_INTERCEPTOR_ENTER).
+#undef SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \
+ true)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \
+ ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \
+ false)
+
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \
+ TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx;
+
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \
+ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
+ TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx;
+
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \
+ Acquire(thr, pc, File2addr(path)); \
+ if (file) { \
+ int fd = fileno_unlocked(file); \
+ if (fd >= 0) FdFileCreate(thr, pc, fd); \
+ }
+
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \
+ if (file) { \
+ int fd = fileno_unlocked(file); \
+ if (fd >= 0) FdClose(thr, pc, fd); \
+ }
+
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
+ libignore()->OnLibraryLoaded(filename)
+
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \
+ libignore()->OnLibraryUnloaded()
+
+#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
+ Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path))
+
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+ FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \
+ FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd)
+
+#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
+ ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
+
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ __tsan::ctx->thread_registry->SetThreadNameByUserId(thread, name)
+
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name)
+
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) \
+ OnExit(((TsanInterceptorContext *) ctx)->thr)
+
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \
+ MutexLock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \
+ MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \
+ MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
+ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, msg)
+
+#include "sanitizer_common/sanitizer_common_interceptors.inc"
+
+#define TSAN_SYSCALL() \
+ ThreadState *thr = cur_thread(); \
+ if (thr->ignore_interceptors) \
+ return; \
+ ScopedSyscall scoped_syscall(thr) \
+/**/
+
+struct ScopedSyscall {
+ ThreadState *thr;
+
+ explicit ScopedSyscall(ThreadState *thr)
+ : thr(thr) {
+ Initialize(thr);
+ }
+
+ ~ScopedSyscall() {
+ ProcessPendingSignals(thr);
+ }
+};
+
+static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
+ TSAN_SYSCALL();
+ MemoryAccessRange(thr, pc, p, s, write);
+}
+
+static void syscall_acquire(uptr pc, uptr addr) {
+ TSAN_SYSCALL();
+ Acquire(thr, pc, addr);
+ DPrintf("syscall_acquire(%p)\n", addr);
+}
+
+static void syscall_release(uptr pc, uptr addr) {
+ TSAN_SYSCALL();
+ DPrintf("syscall_release(%p)\n", addr);
+ Release(thr, pc, addr);
+}
+
+static void syscall_fd_close(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ FdClose(thr, pc, fd);
+}
+
+static USED void syscall_fd_acquire(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ FdAcquire(thr, pc, fd);
+ DPrintf("syscall_fd_acquire(%p)\n", fd);
+}
+
+static USED void syscall_fd_release(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ DPrintf("syscall_fd_release(%p)\n", fd);
+ FdRelease(thr, pc, fd);
+}
+
+static void syscall_pre_fork(uptr pc) {
+ TSAN_SYSCALL();
+ ForkBefore(thr, pc);
+}
+
+static void syscall_post_fork(uptr pc, int pid) {
+ TSAN_SYSCALL();
+ if (pid == 0) {
+ // child
+ ForkChildAfter(thr, pc);
+ FdOnFork(thr, pc);
+ } else if (pid > 0) {
+ // parent
+ ForkParentAfter(thr, pc);
+ } else {
+ // error
+ ForkParentAfter(thr, pc);
+ }
+}
+
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
+ syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
+
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
+ syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true)
+
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+
+#define COMMON_SYSCALL_ACQUIRE(addr) \
+ syscall_acquire(GET_CALLER_PC(), (uptr)(addr))
+
+#define COMMON_SYSCALL_RELEASE(addr) \
+ syscall_release(GET_CALLER_PC(), (uptr)(addr))
+
+#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_PRE_FORK() \
+ syscall_pre_fork(GET_CALLER_PC())
+
+#define COMMON_SYSCALL_POST_FORK(res) \
+ syscall_post_fork(GET_CALLER_PC(), res)
+
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
+namespace __tsan {
+
+static void finalize(void *arg) {
+ ThreadState *thr = cur_thread();
+ int status = Finalize(thr);
+ // Make sure the output is not lost.
+ FlushStreams();
+ if (status)
+ REAL(_exit)(status);
+}
+
+static void unreachable() {
+ Report("FATAL: ThreadSanitizer: unreachable called\n");
+ Die();
+}
+
+void InitializeInterceptors() {
+ // We need to setup it early, because functions like dlsym() can call it.
+ REAL(memset) = internal_memset;
+ REAL(memcpy) = internal_memcpy;
+ REAL(memcmp) = internal_memcmp;
+
+ // Instruct libc malloc to consume less memory.
+#if !SANITIZER_FREEBSD
+ mallopt(1, 0); // M_MXFAST
+ mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
+#endif
+
+ InitializeCommonInterceptors();
+
+ // We can not use TSAN_INTERCEPT to get setjmp addr,
+ // because it does &setjmp and setjmp is not present in some versions of libc.
+ using __interception::GetRealFunctionAddress;
+ GetRealFunctionAddress("setjmp", (uptr*)&REAL(setjmp), 0, 0);
+ GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0);
+ GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0);
+ GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0);
+
+ TSAN_INTERCEPT(longjmp);
+ TSAN_INTERCEPT(siglongjmp);
+
+ TSAN_INTERCEPT(malloc);
+ TSAN_INTERCEPT(__libc_memalign);
+ TSAN_INTERCEPT(calloc);
+ TSAN_INTERCEPT(realloc);
+ TSAN_INTERCEPT(free);
+ TSAN_INTERCEPT(cfree);
+ TSAN_INTERCEPT(mmap);
+ TSAN_MAYBE_INTERCEPT_MMAP64;
+ TSAN_INTERCEPT(munmap);
+ TSAN_MAYBE_INTERCEPT_MEMALIGN;
+ TSAN_INTERCEPT(valloc);
+ TSAN_MAYBE_INTERCEPT_PVALLOC;
+ TSAN_INTERCEPT(posix_memalign);
+
+ TSAN_INTERCEPT(strlen);
+ TSAN_INTERCEPT(memset);
+ TSAN_INTERCEPT(memcpy);
+ TSAN_INTERCEPT(memmove);
+ TSAN_INTERCEPT(memcmp);
+ TSAN_INTERCEPT(strchr);
+ TSAN_INTERCEPT(strchrnul);
+ TSAN_INTERCEPT(strrchr);
+ TSAN_INTERCEPT(strcpy); // NOLINT
+ TSAN_INTERCEPT(strncpy);
+ TSAN_INTERCEPT(strstr);
+ TSAN_INTERCEPT(strdup);
+
+ TSAN_INTERCEPT(pthread_create);
+ TSAN_INTERCEPT(pthread_join);
+ TSAN_INTERCEPT(pthread_detach);
+
+ TSAN_INTERCEPT_VER(pthread_cond_init, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_signal, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_wait, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+
+ TSAN_INTERCEPT(pthread_mutex_init);
+ TSAN_INTERCEPT(pthread_mutex_destroy);
+ TSAN_INTERCEPT(pthread_mutex_trylock);
+ TSAN_INTERCEPT(pthread_mutex_timedlock);
+
+ TSAN_INTERCEPT(pthread_spin_init);
+ TSAN_INTERCEPT(pthread_spin_destroy);
+ TSAN_INTERCEPT(pthread_spin_lock);
+ TSAN_INTERCEPT(pthread_spin_trylock);
+ TSAN_INTERCEPT(pthread_spin_unlock);
+
+ TSAN_INTERCEPT(pthread_rwlock_init);
+ TSAN_INTERCEPT(pthread_rwlock_destroy);
+ TSAN_INTERCEPT(pthread_rwlock_rdlock);
+ TSAN_INTERCEPT(pthread_rwlock_tryrdlock);
+ TSAN_INTERCEPT(pthread_rwlock_timedrdlock);
+ TSAN_INTERCEPT(pthread_rwlock_wrlock);
+ TSAN_INTERCEPT(pthread_rwlock_trywrlock);
+ TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
+ TSAN_INTERCEPT(pthread_rwlock_unlock);
+
+ TSAN_INTERCEPT(pthread_barrier_init);
+ TSAN_INTERCEPT(pthread_barrier_destroy);
+ TSAN_INTERCEPT(pthread_barrier_wait);
+
+ TSAN_INTERCEPT(pthread_once);
+
+ TSAN_INTERCEPT(sem_init);
+ TSAN_INTERCEPT(sem_destroy);
+ TSAN_INTERCEPT(sem_wait);
+ TSAN_INTERCEPT(sem_trywait);
+ TSAN_INTERCEPT(sem_timedwait);
+ TSAN_INTERCEPT(sem_post);
+ TSAN_INTERCEPT(sem_getvalue);
+
+ TSAN_INTERCEPT(stat);
+ TSAN_MAYBE_INTERCEPT___XSTAT;
+ TSAN_MAYBE_INTERCEPT_STAT64;
+ TSAN_MAYBE_INTERCEPT___XSTAT64;
+ TSAN_INTERCEPT(lstat);
+ TSAN_MAYBE_INTERCEPT___LXSTAT;
+ TSAN_MAYBE_INTERCEPT_LSTAT64;
+ TSAN_MAYBE_INTERCEPT___LXSTAT64;
+ TSAN_INTERCEPT(fstat);
+ TSAN_MAYBE_INTERCEPT___FXSTAT;
+ TSAN_MAYBE_INTERCEPT_FSTAT64;
+ TSAN_MAYBE_INTERCEPT___FXSTAT64;
+ TSAN_INTERCEPT(open);
+ TSAN_MAYBE_INTERCEPT_OPEN64;
+ TSAN_INTERCEPT(creat);
+ TSAN_MAYBE_INTERCEPT_CREAT64;
+ TSAN_INTERCEPT(dup);
+ TSAN_INTERCEPT(dup2);
+ TSAN_INTERCEPT(dup3);
+ TSAN_MAYBE_INTERCEPT_EVENTFD;
+ TSAN_MAYBE_INTERCEPT_SIGNALFD;
+ TSAN_MAYBE_INTERCEPT_INOTIFY_INIT;
+ TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1;
+ TSAN_INTERCEPT(socket);
+ TSAN_INTERCEPT(socketpair);
+ TSAN_INTERCEPT(connect);
+ TSAN_INTERCEPT(bind);
+ TSAN_INTERCEPT(listen);
+ TSAN_MAYBE_INTERCEPT_EPOLL_CREATE;
+ TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1;
+ TSAN_INTERCEPT(close);
+ TSAN_MAYBE_INTERCEPT___CLOSE;
+ TSAN_MAYBE_INTERCEPT___RES_ICLOSE;
+ TSAN_INTERCEPT(pipe);
+ TSAN_INTERCEPT(pipe2);
+
+ TSAN_INTERCEPT(send);
+ TSAN_INTERCEPT(sendmsg);
+ TSAN_INTERCEPT(recv);
+
+ TSAN_INTERCEPT(unlink);
+ TSAN_INTERCEPT(tmpfile);
+ TSAN_MAYBE_INTERCEPT_TMPFILE64;
+ TSAN_INTERCEPT(fread);
+ TSAN_INTERCEPT(fwrite);
+ TSAN_INTERCEPT(abort);
+ TSAN_INTERCEPT(puts);
+ TSAN_INTERCEPT(rmdir);
+ TSAN_INTERCEPT(closedir);
+
+ TSAN_MAYBE_INTERCEPT_EPOLL_CTL;
+ TSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
+
+ TSAN_INTERCEPT(sigaction);
+ TSAN_INTERCEPT(signal);
+ TSAN_INTERCEPT(sigsuspend);
+ TSAN_INTERCEPT(raise);
+ TSAN_INTERCEPT(kill);
+ TSAN_INTERCEPT(pthread_kill);
+ TSAN_INTERCEPT(sleep);
+ TSAN_INTERCEPT(usleep);
+ TSAN_INTERCEPT(nanosleep);
+ TSAN_INTERCEPT(gettimeofday);
+ TSAN_INTERCEPT(getaddrinfo);
+
+ TSAN_INTERCEPT(fork);
+ TSAN_INTERCEPT(vfork);
+ TSAN_INTERCEPT(on_exit);
+ TSAN_INTERCEPT(__cxa_atexit);
+ TSAN_INTERCEPT(_exit);
+
+ // Need to setup it, because interceptors check that the function is resolved.
+ // But atexit is emitted directly into the module, so can't be resolved.
+ REAL(atexit) = (int(*)(void(*)()))unreachable;
+ if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
+ Printf("ThreadSanitizer: failed to setup atexit callback\n");
+ Die();
+ }
+
+ if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+ Printf("ThreadSanitizer: failed to create thread key\n");
+ Die();
+ }
+
+ FdInit();
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface.cc
new file mode 100644
index 000000000000..9bc9a696363d
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface.cc
@@ -0,0 +1,121 @@
+//===-- tsan_interface.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_interface.h"
+#include "tsan_interface_ann.h"
+#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+#define CALLERPC ((uptr)__builtin_return_address(0))
+
+using namespace __tsan; // NOLINT
+
+typedef u16 uint16_t;
+typedef u32 uint32_t;
+typedef u64 uint64_t;
+
+void __tsan_init() {
+ Initialize(cur_thread());
+}
+
+void __tsan_read16(void *addr) {
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
+}
+
+void __tsan_write16(void *addr) {
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
+}
+
+// __tsan_unaligned_read/write calls are emitted by compiler.
+
+void __tsan_unaligned_read2(const void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, false, false);
+}
+
+void __tsan_unaligned_read4(const void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, false, false);
+}
+
+void __tsan_unaligned_read8(const void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, false, false);
+}
+
+void __tsan_unaligned_read16(const void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 16, false, false);
+}
+
+void __tsan_unaligned_write2(void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, true, false);
+}
+
+void __tsan_unaligned_write4(void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, true, false);
+}
+
+void __tsan_unaligned_write8(void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, true, false);
+}
+
+void __tsan_unaligned_write16(void *addr) {
+ UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 16, true, false);
+}
+
+// __sanitizer_unaligned_load/store are for user instrumentation.
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *addr) {
+ __tsan_unaligned_read2(addr);
+ return *addr;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *addr) {
+ __tsan_unaligned_read4(addr);
+ return *addr;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *addr) {
+ __tsan_unaligned_read8(addr);
+ return *addr;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *addr, u16 v) {
+ __tsan_unaligned_write2(addr);
+ *addr = v;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *addr, u32 v) {
+ __tsan_unaligned_write4(addr);
+ *addr = v;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *addr, u64 v) {
+ __tsan_unaligned_write8(addr);
+ *addr = v;
+}
+} // extern "C"
+
+void __tsan_acquire(void *addr) {
+ Acquire(cur_thread(), CALLERPC, (uptr)addr);
+}
+
+void __tsan_release(void *addr) {
+ Release(cur_thread(), CALLERPC, (uptr)addr);
+}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface.h
new file mode 100644
index 000000000000..a05e6f0f6d09
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface.h
@@ -0,0 +1,70 @@
+//===-- tsan_interface.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 ThreadSanitizer (TSan), a race detector.
+//
+// The functions declared in this header will be inserted by the instrumentation
+// module.
+// This header can be included by the instrumented program or by TSan tests.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_INTERFACE_H
+#define TSAN_INTERFACE_H
+
+#include <sanitizer_common/sanitizer_internal_defs.h>
+
+// This header should NOT include any other headers.
+// All functions in this header are extern "C" and start with __tsan_.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// This function should be called at the very beginning of the process,
+// before any instrumented code is executed and before any call to malloc.
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_init();
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read16(void *addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write1(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write16(void *addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read2(const void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read4(const void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read8(const void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read16(const void *addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write16(void *addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_vptr_read(void **vptr_p);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_vptr_update(void **vptr_p, void *new_val);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_entry(void *call_pc);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_read_range(void *addr, unsigned long size); // NOLINT
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_write_range(void *addr, unsigned long size); // NOLINT
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // TSAN_INTERFACE_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc
new file mode 100644
index 000000000000..fd3c846678f5
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc
@@ -0,0 +1,459 @@
+//===-- tsan_interface_ann.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "tsan_interface_ann.h"
+#include "tsan_mutex.h"
+#include "tsan_report.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "tsan_flags.h"
+#include "tsan_platform.h"
+#include "tsan_vector.h"
+
+#define CALLERPC ((uptr)__builtin_return_address(0))
+
+using namespace __tsan; // NOLINT
+
+namespace __tsan {
+
+class ScopedAnnotation {
+ public:
+ ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
+ uptr pc)
+ : thr_(thr) {
+ FuncEntry(thr_, pc);
+ DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
+ }
+
+ ~ScopedAnnotation() {
+ FuncExit(thr_);
+ CheckNoLocks(thr_);
+ }
+ private:
+ ThreadState *const thr_;
+};
+
+#define SCOPED_ANNOTATION(typ) \
+ if (!flags()->enable_annotations) \
+ return; \
+ ThreadState *thr = cur_thread(); \
+ const uptr caller_pc = (uptr)__builtin_return_address(0); \
+ StatInc(thr, StatAnnotation); \
+ StatInc(thr, Stat##typ); \
+ ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \
+ const uptr pc = StackTrace::GetCurrentPc(); \
+ (void)pc; \
+/**/
+
+static const int kMaxDescLen = 128;
+
+struct ExpectRace {
+ ExpectRace *next;
+ ExpectRace *prev;
+ int hitcount;
+ int addcount;
+ uptr addr;
+ uptr size;
+ char *file;
+ int line;
+ char desc[kMaxDescLen];
+};
+
+struct DynamicAnnContext {
+ Mutex mtx;
+ ExpectRace expect;
+ ExpectRace benign;
+
+ DynamicAnnContext()
+ : mtx(MutexTypeAnnotations, StatMtxAnnotations) {
+ }
+};
+
+static DynamicAnnContext *dyn_ann_ctx;
+static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64);
+
+static void AddExpectRace(ExpectRace *list,
+ char *f, int l, uptr addr, uptr size, char *desc) {
+ ExpectRace *race = list->next;
+ for (; race != list; race = race->next) {
+ if (race->addr == addr && race->size == size) {
+ race->addcount++;
+ return;
+ }
+ }
+ race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace));
+ race->addr = addr;
+ race->size = size;
+ race->file = f;
+ race->line = l;
+ race->desc[0] = 0;
+ race->hitcount = 0;
+ race->addcount = 1;
+ if (desc) {
+ int i = 0;
+ for (; i < kMaxDescLen - 1 && desc[i]; i++)
+ race->desc[i] = desc[i];
+ race->desc[i] = 0;
+ }
+ race->prev = list;
+ race->next = list->next;
+ race->next->prev = race;
+ list->next = race;
+}
+
+static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {
+ for (ExpectRace *race = list->next; race != list; race = race->next) {
+ uptr maxbegin = max(race->addr, addr);
+ uptr minend = min(race->addr + race->size, addr + size);
+ if (maxbegin < minend)
+ return race;
+ }
+ return 0;
+}
+
+static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
+ ExpectRace *race = FindRace(list, addr, size);
+ if (race == 0)
+ return false;
+ DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
+ race->desc, race->addr, (int)race->size, race->file, race->line);
+ race->hitcount++;
+ return true;
+}
+
+static void InitList(ExpectRace *list) {
+ list->next = list;
+ list->prev = list;
+}
+
+void InitializeDynamicAnnotations() {
+ dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext;
+ InitList(&dyn_ann_ctx->expect);
+ InitList(&dyn_ann_ctx->benign);
+}
+
+bool IsExpectedReport(uptr addr, uptr size) {
+ Lock lock(&dyn_ann_ctx->mtx);
+ if (CheckContains(&dyn_ann_ctx->expect, addr, size))
+ return true;
+ if (CheckContains(&dyn_ann_ctx->benign, addr, size))
+ return true;
+ return false;
+}
+
+static void CollectMatchedBenignRaces(Vector<ExpectRace> *matched,
+ int *unique_count, int *hit_count, int ExpectRace::*counter) {
+ ExpectRace *list = &dyn_ann_ctx->benign;
+ for (ExpectRace *race = list->next; race != list; race = race->next) {
+ (*unique_count)++;
+ if (race->*counter == 0)
+ continue;
+ (*hit_count) += race->*counter;
+ uptr i = 0;
+ for (; i < matched->Size(); i++) {
+ ExpectRace *race0 = &(*matched)[i];
+ if (race->line == race0->line
+ && internal_strcmp(race->file, race0->file) == 0
+ && internal_strcmp(race->desc, race0->desc) == 0) {
+ race0->*counter += race->*counter;
+ break;
+ }
+ }
+ if (i == matched->Size())
+ matched->PushBack(*race);
+ }
+}
+
+void PrintMatchedBenignRaces() {
+ Lock lock(&dyn_ann_ctx->mtx);
+ int unique_count = 0;
+ int hit_count = 0;
+ int add_count = 0;
+ Vector<ExpectRace> hit_matched(MBlockScopedBuf);
+ CollectMatchedBenignRaces(&hit_matched, &unique_count, &hit_count,
+ &ExpectRace::hitcount);
+ Vector<ExpectRace> add_matched(MBlockScopedBuf);
+ CollectMatchedBenignRaces(&add_matched, &unique_count, &add_count,
+ &ExpectRace::addcount);
+ if (hit_matched.Size()) {
+ Printf("ThreadSanitizer: Matched %d \"benign\" races (pid=%d):\n",
+ hit_count, (int)internal_getpid());
+ for (uptr i = 0; i < hit_matched.Size(); i++) {
+ Printf("%d %s:%d %s\n",
+ hit_matched[i].hitcount, hit_matched[i].file,
+ hit_matched[i].line, hit_matched[i].desc);
+ }
+ }
+ if (hit_matched.Size()) {
+ Printf("ThreadSanitizer: Annotated %d \"benign\" races, %d unique"
+ " (pid=%d):\n",
+ add_count, unique_count, (int)internal_getpid());
+ for (uptr i = 0; i < add_matched.Size(); i++) {
+ Printf("%d %s:%d %s\n",
+ add_matched[i].addcount, add_matched[i].file,
+ add_matched[i].line, add_matched[i].desc);
+ }
+ }
+}
+
+static void ReportMissedExpectedRace(ExpectRace *race) {
+ Printf("==================\n");
+ Printf("WARNING: ThreadSanitizer: missed expected data race\n");
+ Printf(" %s addr=%zx %s:%d\n",
+ race->desc, race->addr, race->file, race->line);
+ Printf("==================\n");
+}
+} // namespace __tsan
+
+using namespace __tsan; // NOLINT
+
+extern "C" {
+void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {
+ SCOPED_ANNOTATION(AnnotateHappensBefore);
+ Release(thr, pc, addr);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {
+ SCOPED_ANNOTATION(AnnotateHappensAfter);
+ Acquire(thr, pc, addr);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {
+ SCOPED_ANNOTATION(AnnotateCondVarSignal);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateCondVarSignalAll(char *f, int l, uptr cv) {
+ SCOPED_ANNOTATION(AnnotateCondVarSignalAll);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {
+ SCOPED_ANNOTATION(AnnotateMutexIsNotPHB);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv,
+ uptr lock) {
+ SCOPED_ANNOTATION(AnnotateCondVarWait);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) {
+ SCOPED_ANNOTATION(AnnotateRWLockCreate);
+ MutexCreate(thr, pc, m, true, true, false);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) {
+ SCOPED_ANNOTATION(AnnotateRWLockCreateStatic);
+ MutexCreate(thr, pc, m, true, true, true);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) {
+ SCOPED_ANNOTATION(AnnotateRWLockDestroy);
+ MutexDestroy(thr, pc, m);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m,
+ uptr is_w) {
+ SCOPED_ANNOTATION(AnnotateRWLockAcquired);
+ if (is_w)
+ MutexLock(thr, pc, m);
+ else
+ MutexReadLock(thr, pc, m);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m,
+ uptr is_w) {
+ SCOPED_ANNOTATION(AnnotateRWLockReleased);
+ if (is_w)
+ MutexUnlock(thr, pc, m);
+ else
+ MutexReadUnlock(thr, pc, m);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateTraceMemory(char *f, int l, uptr mem) {
+ SCOPED_ANNOTATION(AnnotateTraceMemory);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateFlushState(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateFlushState);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateNewMemory(char *f, int l, uptr mem,
+ uptr size) {
+ SCOPED_ANNOTATION(AnnotateNewMemory);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) {
+ SCOPED_ANNOTATION(AnnotateNoOp);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
+ Lock lock(&dyn_ann_ctx->mtx);
+ while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) {
+ ExpectRace *race = dyn_ann_ctx->expect.next;
+ if (race->hitcount == 0) {
+ ctx->nmissed_expected++;
+ ReportMissedExpectedRace(race);
+ }
+ race->prev->next = race->next;
+ race->next->prev = race->prev;
+ internal_free(race);
+ }
+}
+
+void INTERFACE_ATTRIBUTE AnnotateEnableRaceDetection(
+ char *f, int l, int enable) {
+ SCOPED_ANNOTATION(AnnotateEnableRaceDetection);
+ // FIXME: Reconsider this functionality later. It may be irrelevant.
+}
+
+void INTERFACE_ATTRIBUTE AnnotateMutexIsUsedAsCondVar(
+ char *f, int l, uptr mu) {
+ SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar);
+}
+
+void INTERFACE_ATTRIBUTE AnnotatePCQGet(
+ char *f, int l, uptr pcq) {
+ SCOPED_ANNOTATION(AnnotatePCQGet);
+}
+
+void INTERFACE_ATTRIBUTE AnnotatePCQPut(
+ char *f, int l, uptr pcq) {
+ SCOPED_ANNOTATION(AnnotatePCQPut);
+}
+
+void INTERFACE_ATTRIBUTE AnnotatePCQDestroy(
+ char *f, int l, uptr pcq) {
+ SCOPED_ANNOTATION(AnnotatePCQDestroy);
+}
+
+void INTERFACE_ATTRIBUTE AnnotatePCQCreate(
+ char *f, int l, uptr pcq) {
+ SCOPED_ANNOTATION(AnnotatePCQCreate);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateExpectRace(
+ char *f, int l, uptr mem, char *desc) {
+ SCOPED_ANNOTATION(AnnotateExpectRace);
+ Lock lock(&dyn_ann_ctx->mtx);
+ AddExpectRace(&dyn_ann_ctx->expect,
+ f, l, mem, 1, desc);
+ DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l);
+}
+
+static void BenignRaceImpl(
+ char *f, int l, uptr mem, uptr size, char *desc) {
+ Lock lock(&dyn_ann_ctx->mtx);
+ AddExpectRace(&dyn_ann_ctx->benign,
+ f, l, mem, size, desc);
+ DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l);
+}
+
+// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
+void INTERFACE_ATTRIBUTE AnnotateBenignRaceSized(
+ char *f, int l, uptr mem, uptr size, char *desc) {
+ SCOPED_ANNOTATION(AnnotateBenignRaceSized);
+ BenignRaceImpl(f, l, mem, size, desc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateBenignRace(
+ char *f, int l, uptr mem, char *desc) {
+ SCOPED_ANNOTATION(AnnotateBenignRace);
+ BenignRaceImpl(f, l, mem, 1, desc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
+ ThreadIgnoreBegin(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
+ ThreadIgnoreEnd(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
+ ThreadIgnoreBegin(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
+ ThreadIgnoreEnd(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);
+ ThreadIgnoreSyncBegin(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);
+ ThreadIgnoreSyncEnd(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
+ char *f, int l, uptr addr, uptr size) {
+ SCOPED_ANNOTATION(AnnotatePublishMemoryRange);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateUnpublishMemoryRange(
+ char *f, int l, uptr addr, uptr size) {
+ SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateThreadName(
+ char *f, int l, char *name) {
+ SCOPED_ANNOTATION(AnnotateThreadName);
+ ThreadSetName(thr, name);
+}
+
+// We deliberately omit the implementation of WTFAnnotateHappensBefore() and
+// WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate
+// atomic operations, which should be handled by ThreadSanitizer correctly.
+void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
+ SCOPED_ANNOTATION(AnnotateHappensBefore);
+}
+
+void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
+ SCOPED_ANNOTATION(AnnotateHappensAfter);
+}
+
+void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
+ char *f, int l, uptr mem, uptr sz, char *desc) {
+ SCOPED_ANNOTATION(AnnotateBenignRaceSized);
+ BenignRaceImpl(f, l, mem, sz, desc);
+}
+
+int INTERFACE_ATTRIBUTE RunningOnValgrind() {
+ return flags()->running_on_valgrind;
+}
+
+double __attribute__((weak)) INTERFACE_ATTRIBUTE ValgrindSlowdown(void) {
+ return 10.0;
+}
+
+const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
+ if (internal_strcmp(query, "pure_happens_before") == 0)
+ return "1";
+ else
+ return "0";
+}
+
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.h
new file mode 100644
index 000000000000..963bcc55afaa
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.h
@@ -0,0 +1,33 @@
+//===-- tsan_interface_ann.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 ThreadSanitizer (TSan), a race detector.
+//
+// Interface for dynamic annotations.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_INTERFACE_ANN_H
+#define TSAN_INTERFACE_ANN_H
+
+#include <sanitizer_common/sanitizer_internal_defs.h>
+
+// This header should NOT include any other headers.
+// All functions in this header are extern "C" and start with __tsan_.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_acquire(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_release(void *addr);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // TSAN_INTERFACE_ANN_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc
new file mode 100644
index 000000000000..27031991438c
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc
@@ -0,0 +1,954 @@
+//===-- tsan_interface_atomic.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+// ThreadSanitizer atomic operations are based on C++11/C1x standards.
+// For background see C++11 standard. A slightly older, publicly
+// available draft of the standard (not entirely up-to-date, but close enough
+// for casual browsing) is available here:
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
+// The following page contains more background information:
+// http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
+
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "tsan_flags.h"
+#include "tsan_rtl.h"
+
+using namespace __tsan; // NOLINT
+
+// These should match declarations from public tsan_interface_atomic.h header.
+typedef unsigned char a8;
+typedef unsigned short a16; // NOLINT
+typedef unsigned int a32;
+typedef unsigned long long a64; // NOLINT
+#if !defined(SANITIZER_GO) && (defined(__SIZEOF_INT128__) \
+ || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64)
+__extension__ typedef __int128 a128;
+# define __TSAN_HAS_INT128 1
+#else
+# define __TSAN_HAS_INT128 0
+#endif
+
+#if !defined(SANITIZER_GO) && __TSAN_HAS_INT128
+// Protects emulation of 128-bit atomic operations.
+static StaticSpinMutex mutex128;
+#endif
+
+// Part of ABI, do not change.
+// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
+typedef enum {
+ mo_relaxed,
+ mo_consume,
+ mo_acquire,
+ mo_release,
+ mo_acq_rel,
+ mo_seq_cst
+} morder;
+
+static bool IsLoadOrder(morder mo) {
+ return mo == mo_relaxed || mo == mo_consume
+ || mo == mo_acquire || mo == mo_seq_cst;
+}
+
+static bool IsStoreOrder(morder mo) {
+ return mo == mo_relaxed || mo == mo_release || mo == mo_seq_cst;
+}
+
+static bool IsReleaseOrder(morder mo) {
+ return mo == mo_release || mo == mo_acq_rel || mo == mo_seq_cst;
+}
+
+static bool IsAcquireOrder(morder mo) {
+ return mo == mo_consume || mo == mo_acquire
+ || mo == mo_acq_rel || mo == mo_seq_cst;
+}
+
+static bool IsAcqRelOrder(morder mo) {
+ return mo == mo_acq_rel || mo == mo_seq_cst;
+}
+
+template<typename T> T func_xchg(volatile T *v, T op) {
+ T res = __sync_lock_test_and_set(v, op);
+ // __sync_lock_test_and_set does not contain full barrier.
+ __sync_synchronize();
+ return res;
+}
+
+template<typename T> T func_add(volatile T *v, T op) {
+ return __sync_fetch_and_add(v, op);
+}
+
+template<typename T> T func_sub(volatile T *v, T op) {
+ return __sync_fetch_and_sub(v, op);
+}
+
+template<typename T> T func_and(volatile T *v, T op) {
+ return __sync_fetch_and_and(v, op);
+}
+
+template<typename T> T func_or(volatile T *v, T op) {
+ return __sync_fetch_and_or(v, op);
+}
+
+template<typename T> T func_xor(volatile T *v, T op) {
+ return __sync_fetch_and_xor(v, op);
+}
+
+template<typename T> T func_nand(volatile T *v, T op) {
+ // clang does not support __sync_fetch_and_nand.
+ T cmp = *v;
+ for (;;) {
+ T newv = ~(cmp & op);
+ T cur = __sync_val_compare_and_swap(v, cmp, newv);
+ if (cmp == cur)
+ return cmp;
+ cmp = cur;
+ }
+}
+
+template<typename T> T func_cas(volatile T *v, T cmp, T xch) {
+ return __sync_val_compare_and_swap(v, cmp, xch);
+}
+
+// clang does not support 128-bit atomic ops.
+// Atomic ops are executed under tsan internal mutex,
+// here we assume that the atomic variables are not accessed
+// from non-instrumented code.
+#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO) \
+ && __TSAN_HAS_INT128
+a128 func_xchg(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = op;
+ return cmp;
+}
+
+a128 func_add(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = cmp + op;
+ return cmp;
+}
+
+a128 func_sub(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = cmp - op;
+ return cmp;
+}
+
+a128 func_and(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = cmp & op;
+ return cmp;
+}
+
+a128 func_or(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = cmp | op;
+ return cmp;
+}
+
+a128 func_xor(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = cmp ^ op;
+ return cmp;
+}
+
+a128 func_nand(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
+ a128 cmp = *v;
+ *v = ~(cmp & op);
+ return cmp;
+}
+
+a128 func_cas(volatile a128 *v, a128 cmp, a128 xch) {
+ SpinMutexLock lock(&mutex128);
+ a128 cur = *v;
+ if (cur == cmp)
+ *v = xch;
+ return cur;
+}
+#endif
+
+template<typename T>
+static int SizeLog() {
+ if (sizeof(T) <= 1)
+ return kSizeLog1;
+ else if (sizeof(T) <= 2)
+ return kSizeLog2;
+ else if (sizeof(T) <= 4)
+ return kSizeLog4;
+ else
+ return kSizeLog8;
+ // For 16-byte atomics we also use 8-byte memory access,
+ // this leads to false negatives only in very obscure cases.
+}
+
+#ifndef SANITIZER_GO
+static atomic_uint8_t *to_atomic(const volatile a8 *a) {
+ return reinterpret_cast<atomic_uint8_t *>(const_cast<a8 *>(a));
+}
+
+static atomic_uint16_t *to_atomic(const volatile a16 *a) {
+ return reinterpret_cast<atomic_uint16_t *>(const_cast<a16 *>(a));
+}
+#endif
+
+static atomic_uint32_t *to_atomic(const volatile a32 *a) {
+ return reinterpret_cast<atomic_uint32_t *>(const_cast<a32 *>(a));
+}
+
+static atomic_uint64_t *to_atomic(const volatile a64 *a) {
+ return reinterpret_cast<atomic_uint64_t *>(const_cast<a64 *>(a));
+}
+
+static memory_order to_mo(morder mo) {
+ switch (mo) {
+ case mo_relaxed: return memory_order_relaxed;
+ case mo_consume: return memory_order_consume;
+ case mo_acquire: return memory_order_acquire;
+ case mo_release: return memory_order_release;
+ case mo_acq_rel: return memory_order_acq_rel;
+ case mo_seq_cst: return memory_order_seq_cst;
+ }
+ CHECK(0);
+ return memory_order_seq_cst;
+}
+
+template<typename T>
+static T NoTsanAtomicLoad(const volatile T *a, morder mo) {
+ return atomic_load(to_atomic(a), to_mo(mo));
+}
+
+#if __TSAN_HAS_INT128 && !defined(SANITIZER_GO)
+static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) {
+ SpinMutexLock lock(&mutex128);
+ return *a;
+}
+#endif
+
+template<typename T>
+static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
+ morder mo) {
+ CHECK(IsLoadOrder(mo));
+ // This fast-path is critical for performance.
+ // Assume the access is atomic.
+ if (!IsAcquireOrder(mo)) {
+ MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
+ return NoTsanAtomicLoad(a, mo);
+ }
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, false);
+ AcquireImpl(thr, pc, &s->clock);
+ T v = NoTsanAtomicLoad(a, mo);
+ s->mtx.ReadUnlock();
+ MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
+ return v;
+}
+
+template<typename T>
+static void NoTsanAtomicStore(volatile T *a, T v, morder mo) {
+ atomic_store(to_atomic(a), v, to_mo(mo));
+}
+
+#if __TSAN_HAS_INT128 && !defined(SANITIZER_GO)
+static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) {
+ SpinMutexLock lock(&mutex128);
+ *a = v;
+}
+#endif
+
+template<typename T>
+static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ CHECK(IsStoreOrder(mo));
+ MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
+ // This fast-path is critical for performance.
+ // Assume the access is atomic.
+ // Strictly saying even relaxed store cuts off release sequence,
+ // so must reset the clock.
+ if (!IsReleaseOrder(mo)) {
+ NoTsanAtomicStore(a, v, mo);
+ return;
+ }
+ __sync_synchronize();
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseImpl(thr, pc, &s->clock);
+ NoTsanAtomicStore(a, v, mo);
+ s->mtx.Unlock();
+}
+
+template<typename T, T (*F)(volatile T *v, T op)>
+static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
+ MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
+ SyncVar *s = 0;
+ if (mo != mo_relaxed) {
+ s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ if (IsAcqRelOrder(mo))
+ AcquireReleaseImpl(thr, pc, &s->clock);
+ else if (IsReleaseOrder(mo))
+ ReleaseImpl(thr, pc, &s->clock);
+ else if (IsAcquireOrder(mo))
+ AcquireImpl(thr, pc, &s->clock);
+ }
+ v = F(a, v);
+ if (s)
+ s->mtx.Unlock();
+ return v;
+}
+
+template<typename T>
+static T NoTsanAtomicExchange(volatile T *a, T v, morder mo) {
+ return func_xchg(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchAdd(volatile T *a, T v, morder mo) {
+ return func_add(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchSub(volatile T *a, T v, morder mo) {
+ return func_sub(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchAnd(volatile T *a, T v, morder mo) {
+ return func_and(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchOr(volatile T *a, T v, morder mo) {
+ return func_or(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchXor(volatile T *a, T v, morder mo) {
+ return func_xor(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchNand(volatile T *a, T v, morder mo) {
+ return func_nand(a, v);
+}
+
+template<typename T>
+static T AtomicExchange(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_xchg>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static T AtomicFetchAdd(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_add>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static T AtomicFetchSub(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_sub>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static T AtomicFetchAnd(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_and>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static T AtomicFetchOr(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_or>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static T AtomicFetchXor(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_xor>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static T AtomicFetchNand(ThreadState *thr, uptr pc, volatile T *a, T v,
+ morder mo) {
+ return AtomicRMW<T, func_nand>(thr, pc, a, v, mo);
+}
+
+template<typename T>
+static bool NoTsanAtomicCAS(volatile T *a, T *c, T v, morder mo, morder fmo) {
+ return atomic_compare_exchange_strong(to_atomic(a), c, v, to_mo(mo));
+}
+
+#if __TSAN_HAS_INT128
+static bool NoTsanAtomicCAS(volatile a128 *a, a128 *c, a128 v,
+ morder mo, morder fmo) {
+ a128 old = *c;
+ a128 cur = func_cas(a, old, v);
+ if (cur == old)
+ return true;
+ *c = cur;
+ return false;
+}
+#endif
+
+template<typename T>
+static T NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) {
+ NoTsanAtomicCAS(a, &c, v, mo, fmo);
+ return c;
+}
+
+template<typename T>
+static bool AtomicCAS(ThreadState *thr, uptr pc,
+ volatile T *a, T *c, T v, morder mo, morder fmo) {
+ (void)fmo; // Unused because llvm does not pass it yet.
+ MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
+ SyncVar *s = 0;
+ bool write_lock = mo != mo_acquire && mo != mo_consume;
+ if (mo != mo_relaxed) {
+ s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, write_lock);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ if (IsAcqRelOrder(mo))
+ AcquireReleaseImpl(thr, pc, &s->clock);
+ else if (IsReleaseOrder(mo))
+ ReleaseImpl(thr, pc, &s->clock);
+ else if (IsAcquireOrder(mo))
+ AcquireImpl(thr, pc, &s->clock);
+ }
+ T cc = *c;
+ T pr = func_cas(a, cc, v);
+ if (s) {
+ if (write_lock)
+ s->mtx.Unlock();
+ else
+ s->mtx.ReadUnlock();
+ }
+ if (pr == cc)
+ return true;
+ *c = pr;
+ return false;
+}
+
+template<typename T>
+static T AtomicCAS(ThreadState *thr, uptr pc,
+ volatile T *a, T c, T v, morder mo, morder fmo) {
+ AtomicCAS(thr, pc, a, &c, v, mo, fmo);
+ return c;
+}
+
+#ifndef SANITIZER_GO
+static void NoTsanAtomicFence(morder mo) {
+ __sync_synchronize();
+}
+
+static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
+ // FIXME(dvyukov): not implemented.
+ __sync_synchronize();
+}
+#endif
+
+// Interface functions follow.
+#ifndef SANITIZER_GO
+
+// C/C++
+
+#define SCOPED_ATOMIC(func, ...) \
+ const uptr callpc = (uptr)__builtin_return_address(0); \
+ uptr pc = StackTrace::GetCurrentPc(); \
+ mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
+ ThreadState *const thr = cur_thread(); \
+ if (thr->ignore_interceptors) \
+ return NoTsanAtomic##func(__VA_ARGS__); \
+ AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
+ ScopedAtomic sa(thr, callpc, a, mo, __func__); \
+ return Atomic##func(thr, pc, __VA_ARGS__); \
+/**/
+
+class ScopedAtomic {
+ public:
+ ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
+ morder mo, const char *func)
+ : thr_(thr) {
+ FuncEntry(thr_, pc);
+ DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
+ }
+ ~ScopedAtomic() {
+ ProcessPendingSignals(thr_);
+ FuncExit(thr_);
+ }
+ private:
+ ThreadState *thr_;
+};
+
+static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
+ StatInc(thr, StatAtomic);
+ StatInc(thr, t);
+ StatInc(thr, size == 1 ? StatAtomic1
+ : size == 2 ? StatAtomic2
+ : size == 4 ? StatAtomic4
+ : size == 8 ? StatAtomic8
+ : StatAtomic16);
+ StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed
+ : mo == mo_consume ? StatAtomicConsume
+ : mo == mo_acquire ? StatAtomicAcquire
+ : mo == mo_release ? StatAtomicRelease
+ : mo == mo_acq_rel ? StatAtomicAcq_Rel
+ : StatAtomicSeq_Cst);
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_load(const volatile a8 *a, morder mo) {
+ SCOPED_ATOMIC(Load, a, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_load(const volatile a16 *a, morder mo) {
+ SCOPED_ATOMIC(Load, a, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_load(const volatile a32 *a, morder mo) {
+ SCOPED_ATOMIC(Load, a, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_load(const volatile a64 *a, morder mo) {
+ SCOPED_ATOMIC(Load, a, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_load(const volatile a128 *a, morder mo) {
+ SCOPED_ATOMIC(Load, a, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(Store, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(Store, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(Store, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(Store, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(Store, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(Exchange, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(Exchange, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(Exchange, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(Exchange, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(Exchange, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(FetchAdd, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(FetchAdd, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(FetchAdd, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(FetchAdd, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(FetchAdd, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(FetchSub, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(FetchSub, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(FetchSub, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(FetchSub, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(FetchSub, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(FetchAnd, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(FetchAnd, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(FetchAnd, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(FetchAnd, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(FetchAnd, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(FetchOr, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(FetchOr, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(FetchOr, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(FetchOr, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(FetchOr, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(FetchXor, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(FetchXor, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(FetchXor, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(FetchXor, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(FetchXor, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo) {
+ SCOPED_ATOMIC(FetchNand, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo) {
+ SCOPED_ATOMIC(FetchNand, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo) {
+ SCOPED_ATOMIC(FetchNand, a, v, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo) {
+ SCOPED_ATOMIC(FetchNand, a, v, mo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo) {
+ SCOPED_ATOMIC(FetchNand, a, v, mo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
+ morder mo, morder fmo) {
+ SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
+}
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic_thread_fence(morder mo) {
+ char* a = 0;
+ SCOPED_ATOMIC(Fence, mo);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic_signal_fence(morder mo) {
+}
+} // extern "C"
+
+#else // #ifndef SANITIZER_GO
+
+// Go
+
+#define ATOMIC(func, ...) \
+ if (thr->ignore_sync) { \
+ NoTsanAtomic##func(__VA_ARGS__); \
+ } else { \
+ FuncEntry(thr, cpc); \
+ Atomic##func(thr, pc, __VA_ARGS__); \
+ FuncExit(thr); \
+ } \
+/**/
+
+#define ATOMIC_RET(func, ret, ...) \
+ if (thr->ignore_sync) { \
+ (ret) = NoTsanAtomic##func(__VA_ARGS__); \
+ } else { \
+ FuncEntry(thr, cpc); \
+ (ret) = Atomic##func(thr, pc, __VA_ARGS__); \
+ FuncExit(thr); \
+ } \
+/**/
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Load, *(a32*)(a+8), *(a32**)a, mo_acquire);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Load, *(a64*)(a+8), *(a64**)a, mo_acquire);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC(Store, *(a32**)a, *(a32*)(a+8), mo_release);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC(Store, *(a64**)a, *(a64*)(a+8), mo_release);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(FetchAdd, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(FetchAdd, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Exchange, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Exchange, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_compare_exchange(
+ ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ a32 cur = 0;
+ a32 cmp = *(a32*)(a+8);
+ ATOMIC_RET(CAS, cur, *(a32**)a, cmp, *(a32*)(a+12), mo_acq_rel, mo_acquire);
+ *(bool*)(a+16) = (cur == cmp);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_compare_exchange(
+ ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ a64 cur = 0;
+ a64 cmp = *(a64*)(a+8);
+ ATOMIC_RET(CAS, cur, *(a64**)a, cmp, *(a64*)(a+16), mo_acq_rel, mo_acquire);
+ *(bool*)(a+24) = (cur == cmp);
+}
+} // extern "C"
+#endif // #ifndef SANITIZER_GO
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h
new file mode 100644
index 000000000000..0187e49d96e5
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h
@@ -0,0 +1,85 @@
+//===-- tsan_interface_inl.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_interface.h"
+#include "tsan_rtl.h"
+
+#define CALLERPC ((uptr)__builtin_return_address(0))
+
+using namespace __tsan; // NOLINT
+
+void __tsan_read1(void *addr) {
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
+}
+
+void __tsan_read2(void *addr) {
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
+}
+
+void __tsan_read4(void *addr) {
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
+}
+
+void __tsan_read8(void *addr) {
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+}
+
+void __tsan_write1(void *addr) {
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
+}
+
+void __tsan_write2(void *addr) {
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
+}
+
+void __tsan_write4(void *addr) {
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
+}
+
+void __tsan_write8(void *addr) {
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+}
+
+void __tsan_vptr_update(void **vptr_p, void *new_val) {
+ CHECK_EQ(sizeof(vptr_p), 8);
+ if (*vptr_p != new_val) {
+ ThreadState *thr = cur_thread();
+ thr->is_vptr_access = true;
+ MemoryWrite(thr, CALLERPC, (uptr)vptr_p, kSizeLog8);
+ thr->is_vptr_access = false;
+ }
+}
+
+void __tsan_vptr_read(void **vptr_p) {
+ CHECK_EQ(sizeof(vptr_p), 8);
+ ThreadState *thr = cur_thread();
+ thr->is_vptr_access = true;
+ MemoryRead(thr, CALLERPC, (uptr)vptr_p, kSizeLog8);
+ thr->is_vptr_access = false;
+}
+
+void __tsan_func_entry(void *pc) {
+ FuncEntry(cur_thread(), (uptr)pc);
+}
+
+void __tsan_func_exit() {
+ FuncExit(cur_thread());
+}
+
+void __tsan_read_range(void *addr, uptr size) {
+ MemoryAccessRange(cur_thread(), CALLERPC, (uptr)addr, size, false);
+}
+
+void __tsan_write_range(void *addr, uptr size) {
+ MemoryAccessRange(cur_thread(), CALLERPC, (uptr)addr, size, true);
+}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc
new file mode 100644
index 000000000000..0aea63d11671
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc
@@ -0,0 +1,251 @@
+//===-- tsan_interface_java.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_interface_java.h"
+#include "tsan_rtl.h"
+#include "tsan_mutex.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+using namespace __tsan; // NOLINT
+
+const jptr kHeapAlignment = 8;
+
+namespace __tsan {
+
+struct JavaContext {
+ const uptr heap_begin;
+ const uptr heap_size;
+
+ JavaContext(jptr heap_begin, jptr heap_size)
+ : heap_begin(heap_begin)
+ , heap_size(heap_size) {
+ }
+};
+
+class ScopedJavaFunc {
+ public:
+ ScopedJavaFunc(ThreadState *thr, uptr pc)
+ : thr_(thr) {
+ Initialize(thr_);
+ FuncEntry(thr, pc);
+ }
+
+ ~ScopedJavaFunc() {
+ FuncExit(thr_);
+ // FIXME(dvyukov): process pending signals.
+ }
+
+ private:
+ ThreadState *thr_;
+};
+
+static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
+static JavaContext *jctx;
+
+} // namespace __tsan
+
+#define SCOPED_JAVA_FUNC(func) \
+ ThreadState *thr = cur_thread(); \
+ const uptr caller_pc = GET_CALLER_PC(); \
+ const uptr pc = StackTrace::GetCurrentPc(); \
+ (void)pc; \
+ ScopedJavaFunc scoped(thr, caller_pc); \
+/**/
+
+void __tsan_java_init(jptr heap_begin, jptr heap_size) {
+ SCOPED_JAVA_FUNC(__tsan_java_init);
+ DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
+ CHECK_EQ(jctx, 0);
+ CHECK_GT(heap_begin, 0);
+ CHECK_GT(heap_size, 0);
+ CHECK_EQ(heap_begin % kHeapAlignment, 0);
+ CHECK_EQ(heap_size % kHeapAlignment, 0);
+ CHECK_LT(heap_begin, heap_begin + heap_size);
+ jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
+}
+
+int __tsan_java_fini() {
+ SCOPED_JAVA_FUNC(__tsan_java_fini);
+ DPrintf("#%d: java_fini()\n", thr->tid);
+ CHECK_NE(jctx, 0);
+ // FIXME(dvyukov): this does not call atexit() callbacks.
+ int status = Finalize(thr);
+ DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
+ return status;
+}
+
+void __tsan_java_alloc(jptr ptr, jptr size) {
+ SCOPED_JAVA_FUNC(__tsan_java_alloc);
+ DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
+ CHECK_NE(jctx, 0);
+ CHECK_NE(size, 0);
+ CHECK_EQ(ptr % kHeapAlignment, 0);
+ CHECK_EQ(size % kHeapAlignment, 0);
+ CHECK_GE(ptr, jctx->heap_begin);
+ CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
+
+ OnUserAlloc(thr, pc, ptr, size, false);
+}
+
+void __tsan_java_free(jptr ptr, jptr size) {
+ SCOPED_JAVA_FUNC(__tsan_java_free);
+ DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
+ CHECK_NE(jctx, 0);
+ CHECK_NE(size, 0);
+ CHECK_EQ(ptr % kHeapAlignment, 0);
+ CHECK_EQ(size % kHeapAlignment, 0);
+ CHECK_GE(ptr, jctx->heap_begin);
+ CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
+
+ ctx->metamap.FreeRange(thr, pc, ptr, size);
+}
+
+void __tsan_java_move(jptr src, jptr dst, jptr size) {
+ SCOPED_JAVA_FUNC(__tsan_java_move);
+ DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
+ CHECK_NE(jctx, 0);
+ CHECK_NE(size, 0);
+ CHECK_EQ(src % kHeapAlignment, 0);
+ CHECK_EQ(dst % kHeapAlignment, 0);
+ CHECK_EQ(size % kHeapAlignment, 0);
+ CHECK_GE(src, jctx->heap_begin);
+ CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
+ CHECK_GE(dst, jctx->heap_begin);
+ CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
+ CHECK_NE(dst, src);
+ CHECK_NE(size, 0);
+
+ // Assuming it's not running concurrently with threads that do
+ // memory accesses and mutex operations (stop-the-world phase).
+ ctx->metamap.MoveMemory(src, dst, size);
+
+ // Move shadow.
+ u64 *s = (u64*)MemToShadow(src);
+ u64 *d = (u64*)MemToShadow(dst);
+ u64 *send = (u64*)MemToShadow(src + size);
+ uptr inc = 1;
+ if (dst > src) {
+ s = (u64*)MemToShadow(src + size) - 1;
+ d = (u64*)MemToShadow(dst + size) - 1;
+ send = (u64*)MemToShadow(src) - 1;
+ inc = -1;
+ }
+ for (; s != send; s += inc, d += inc) {
+ *d = *s;
+ *s = 0;
+ }
+}
+
+void __tsan_java_finalize() {
+ SCOPED_JAVA_FUNC(__tsan_java_finalize);
+ DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
+ AcquireGlobal(thr, 0);
+}
+
+void __tsan_java_mutex_lock(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
+ DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ MutexCreate(thr, pc, addr, true, true, true);
+ MutexLock(thr, pc, addr);
+}
+
+void __tsan_java_mutex_unlock(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
+ DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ MutexUnlock(thr, pc, addr);
+}
+
+void __tsan_java_mutex_read_lock(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
+ DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ MutexCreate(thr, pc, addr, true, true, true);
+ MutexReadLock(thr, pc, addr);
+}
+
+void __tsan_java_mutex_read_unlock(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
+ DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ MutexReadUnlock(thr, pc, addr);
+}
+
+void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
+ SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
+ DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+ CHECK_GT(rec, 0);
+
+ MutexCreate(thr, pc, addr, true, true, true);
+ MutexLock(thr, pc, addr, rec);
+}
+
+int __tsan_java_mutex_unlock_rec(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
+ DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ return MutexUnlock(thr, pc, addr, true);
+}
+
+void __tsan_java_acquire(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_acquire);
+ DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ Acquire(thr, caller_pc, addr);
+}
+
+void __tsan_java_release(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_release);
+ DPrintf("#%d: java_release(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ Release(thr, caller_pc, addr);
+}
+
+void __tsan_java_release_store(jptr addr) {
+ SCOPED_JAVA_FUNC(__tsan_java_release);
+ DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr);
+ CHECK_NE(jctx, 0);
+ CHECK_GE(addr, jctx->heap_begin);
+ CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+ ReleaseStore(thr, caller_pc, addr);
+}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.h
new file mode 100644
index 000000000000..30153a1d8505
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_java.h
@@ -0,0 +1,96 @@
+//===-- tsan_interface_java.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 ThreadSanitizer (TSan), a race detector.
+//
+// Interface for verification of Java or mixed Java/C++ programs.
+// The interface is intended to be used from within a JVM and notify TSan
+// about such events like Java locks and GC memory compaction.
+//
+// For plain memory accesses and function entry/exit a JVM is intended to use
+// C++ interfaces: __tsan_readN/writeN and __tsan_func_enter/exit.
+//
+// For volatile memory accesses and atomic operations JVM is intended to use
+// standard atomics API: __tsan_atomicN_load/store/etc.
+//
+// For usage examples see lit_tests/java_*.cc
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_INTERFACE_JAVA_H
+#define TSAN_INTERFACE_JAVA_H
+
+#ifndef INTERFACE_ATTRIBUTE
+# define INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned long jptr; // NOLINT
+
+// Must be called before any other callback from Java.
+void __tsan_java_init(jptr heap_begin, jptr heap_size) INTERFACE_ATTRIBUTE;
+// Must be called when the application exits.
+// Not necessary the last callback (concurrently running threads are OK).
+// Returns exit status or 0 if tsan does not want to override it.
+int __tsan_java_fini() INTERFACE_ATTRIBUTE;
+
+// Callback for memory allocations.
+// May be omitted for allocations that are not subject to data races
+// nor contain synchronization objects (e.g. String).
+void __tsan_java_alloc(jptr ptr, jptr size) INTERFACE_ATTRIBUTE;
+// Callback for memory free.
+// Can be aggregated for several objects (preferably).
+void __tsan_java_free(jptr ptr, jptr size) INTERFACE_ATTRIBUTE;
+// Callback for memory move by GC.
+// Can be aggregated for several objects (preferably).
+// The ranges can overlap.
+void __tsan_java_move(jptr src, jptr dst, jptr size) INTERFACE_ATTRIBUTE;
+// This function must be called on the finalizer thread
+// before executing a batch of finalizers.
+// It ensures necessary synchronization between
+// java object creation and finalization.
+void __tsan_java_finalize() INTERFACE_ATTRIBUTE;
+
+// Mutex lock.
+// Addr is any unique address associated with the mutex.
+// Can be called on recursive reentry.
+void __tsan_java_mutex_lock(jptr addr) INTERFACE_ATTRIBUTE;
+// Mutex unlock.
+void __tsan_java_mutex_unlock(jptr addr) INTERFACE_ATTRIBUTE;
+// Mutex read lock.
+void __tsan_java_mutex_read_lock(jptr addr) INTERFACE_ATTRIBUTE;
+// Mutex read unlock.
+void __tsan_java_mutex_read_unlock(jptr addr) INTERFACE_ATTRIBUTE;
+// Recursive mutex lock, intended for handling of Object.wait().
+// The 'rec' value must be obtained from the previous
+// __tsan_java_mutex_unlock_rec().
+void __tsan_java_mutex_lock_rec(jptr addr, int rec) INTERFACE_ATTRIBUTE;
+// Recursive mutex unlock, intended for handling of Object.wait().
+// The return value says how many times this thread called lock()
+// w/o a pairing unlock() (i.e. how many recursive levels it unlocked).
+// It must be passed back to __tsan_java_mutex_lock_rec() to restore
+// the same recursion level.
+int __tsan_java_mutex_unlock_rec(jptr addr) INTERFACE_ATTRIBUTE;
+
+// Raw acquire/release primitives.
+// Can be used to establish happens-before edges on volatile/final fields,
+// in atomic operations, etc. release_store is the same as release, but it
+// breaks release sequence on addr (see C++ standard 1.10/7 for details).
+void __tsan_java_acquire(jptr addr) INTERFACE_ATTRIBUTE;
+void __tsan_java_release(jptr addr) INTERFACE_ATTRIBUTE;
+void __tsan_java_release_store(jptr addr) INTERFACE_ATTRIBUTE;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#undef INTERFACE_ATTRIBUTE
+
+#endif // #ifndef TSAN_INTERFACE_JAVA_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_md5.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_md5.cc
new file mode 100644
index 000000000000..51279c10d17a
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_md5.cc
@@ -0,0 +1,243 @@
+//===-- tsan_md5.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
+
+#define SET(n) \
+ (*(const MD5_u32plus *)&ptr[(n) * 4])
+#define GET(n) \
+ SET(n)
+
+typedef unsigned int MD5_u32plus;
+typedef unsigned long ulong_t; // NOLINT
+
+typedef struct {
+ MD5_u32plus lo, hi;
+ MD5_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ MD5_u32plus block[16];
+} MD5_CTX;
+
+static const void *body(MD5_CTX *ctx, const void *data, ulong_t size) {
+ const unsigned char *ptr = (const unsigned char *)data;
+ MD5_u32plus a, b, c, d;
+ MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return ptr;
+}
+
+void MD5_Init(MD5_CTX *ctx) {
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->lo = 0;
+ ctx->hi = 0;
+}
+
+void MD5_Update(MD5_CTX *ctx, const void *data, ulong_t size) {
+ MD5_u32plus saved_lo;
+ ulong_t used, free;
+
+ saved_lo = ctx->lo;
+ if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+ ctx->hi++;
+ ctx->hi += size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if (used) {
+ free = 64 - used;
+
+ if (size < free) {
+ internal_memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ internal_memcpy(&ctx->buffer[used], data, free);
+ data = (const unsigned char *)data + free;
+ size -= free;
+ body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = body(ctx, data, size & ~(ulong_t)0x3f);
+ size &= 0x3f;
+ }
+
+ internal_memcpy(ctx->buffer, data, size);
+}
+
+void MD5_Final(unsigned char *result, MD5_CTX *ctx) {
+ ulong_t used, free;
+
+ used = ctx->lo & 0x3f;
+
+ ctx->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ internal_memset(&ctx->buffer[used], 0, free);
+ body(ctx, ctx->buffer, 64);
+ used = 0;
+ free = 64;
+ }
+
+ internal_memset(&ctx->buffer[used], 0, free - 8);
+
+ ctx->lo <<= 3;
+ ctx->buffer[56] = ctx->lo;
+ ctx->buffer[57] = ctx->lo >> 8;
+ ctx->buffer[58] = ctx->lo >> 16;
+ ctx->buffer[59] = ctx->lo >> 24;
+ ctx->buffer[60] = ctx->hi;
+ ctx->buffer[61] = ctx->hi >> 8;
+ ctx->buffer[62] = ctx->hi >> 16;
+ ctx->buffer[63] = ctx->hi >> 24;
+
+ body(ctx, ctx->buffer, 64);
+
+ result[0] = ctx->a;
+ result[1] = ctx->a >> 8;
+ result[2] = ctx->a >> 16;
+ result[3] = ctx->a >> 24;
+ result[4] = ctx->b;
+ result[5] = ctx->b >> 8;
+ result[6] = ctx->b >> 16;
+ result[7] = ctx->b >> 24;
+ result[8] = ctx->c;
+ result[9] = ctx->c >> 8;
+ result[10] = ctx->c >> 16;
+ result[11] = ctx->c >> 24;
+ result[12] = ctx->d;
+ result[13] = ctx->d >> 8;
+ result[14] = ctx->d >> 16;
+ result[15] = ctx->d >> 24;
+
+ internal_memset(ctx, 0, sizeof(*ctx));
+}
+
+MD5Hash md5_hash(const void *data, uptr size) {
+ MD5Hash res;
+ MD5_CTX ctx;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, data, size);
+ MD5_Final((unsigned char*)&res.hash[0], &ctx);
+ return res;
+}
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc
new file mode 100644
index 000000000000..ebb3f77fb992
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc
@@ -0,0 +1,226 @@
+//===-- tsan_mman.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "tsan_mman.h"
+#include "tsan_rtl.h"
+#include "tsan_report.h"
+#include "tsan_flags.h"
+
+// May be overriden by front-end.
+extern "C" void WEAK __sanitizer_malloc_hook(void *ptr, uptr size) {
+ (void)ptr;
+ (void)size;
+}
+
+extern "C" void WEAK __sanitizer_free_hook(void *ptr) {
+ (void)ptr;
+}
+
+namespace __tsan {
+
+struct MapUnmapCallback {
+ void OnMap(uptr p, uptr size) const { }
+ void OnUnmap(uptr p, uptr size) const {
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ DontNeedShadowFor(p, size);
+ }
+};
+
+static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64);
+Allocator *allocator() {
+ return reinterpret_cast<Allocator*>(&allocator_placeholder);
+}
+
+void InitializeAllocator() {
+ allocator()->Init(common_flags()->allocator_may_return_null);
+}
+
+void AllocatorThreadStart(ThreadState *thr) {
+ allocator()->InitCache(&thr->alloc_cache);
+ internal_allocator()->InitCache(&thr->internal_alloc_cache);
+}
+
+void AllocatorThreadFinish(ThreadState *thr) {
+ allocator()->DestroyCache(&thr->alloc_cache);
+ internal_allocator()->DestroyCache(&thr->internal_alloc_cache);
+}
+
+void AllocatorPrintStats() {
+ allocator()->PrintStats();
+}
+
+static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
+ if (atomic_load(&thr->in_signal_handler, memory_order_relaxed) == 0 ||
+ !flags()->report_signal_unsafe)
+ return;
+ VarSizeStackTrace stack;
+ ObtainCurrentStack(thr, pc, &stack);
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeSignalUnsafe);
+ if (!IsFiredSuppression(ctx, rep, stack)) {
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
+ }
+}
+
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
+ if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
+ return allocator()->ReturnNullOrDie();
+ void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
+ if (p == 0)
+ return 0;
+ if (ctx && ctx->initialized)
+ OnUserAlloc(thr, pc, (uptr)p, sz, true);
+ if (signal)
+ SignalUnsafeCall(thr, pc);
+ return p;
+}
+
+void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
+ if (CallocShouldReturnNullDueToOverflow(size, n))
+ return allocator()->ReturnNullOrDie();
+ void *p = user_alloc(thr, pc, n * size);
+ if (p)
+ internal_memset(p, 0, n * size);
+ return p;
+}
+
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
+ if (ctx && ctx->initialized)
+ OnUserFree(thr, pc, (uptr)p, true);
+ allocator()->Deallocate(&thr->alloc_cache, p);
+ if (signal)
+ SignalUnsafeCall(thr, pc);
+}
+
+void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
+ DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
+ ctx->metamap.AllocBlock(thr, pc, p, sz);
+ if (write && thr->ignore_reads_and_writes == 0)
+ MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
+ else
+ MemoryResetRange(thr, pc, (uptr)p, sz);
+}
+
+void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) {
+ CHECK_NE(p, (void*)0);
+ uptr sz = ctx->metamap.FreeBlock(thr, pc, p);
+ DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz);
+ if (write && thr->ignore_reads_and_writes == 0)
+ MemoryRangeFreed(thr, pc, (uptr)p, sz);
+}
+
+void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
+ void *p2 = 0;
+ // FIXME: Handle "shrinking" more efficiently,
+ // it seems that some software actually does this.
+ if (sz) {
+ p2 = user_alloc(thr, pc, sz);
+ if (p2 == 0)
+ return 0;
+ if (p) {
+ uptr oldsz = user_alloc_usable_size(p);
+ internal_memcpy(p2, p, min(oldsz, sz));
+ }
+ }
+ if (p)
+ user_free(thr, pc, p);
+ return p2;
+}
+
+uptr user_alloc_usable_size(const void *p) {
+ if (p == 0)
+ return 0;
+ MBlock *b = ctx->metamap.GetBlock((uptr)p);
+ return b ? b->siz : 0;
+}
+
+void invoke_malloc_hook(void *ptr, uptr size) {
+ ThreadState *thr = cur_thread();
+ if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
+ return;
+ __sanitizer_malloc_hook(ptr, size);
+}
+
+void invoke_free_hook(void *ptr) {
+ ThreadState *thr = cur_thread();
+ if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
+ return;
+ __sanitizer_free_hook(ptr);
+}
+
+void *internal_alloc(MBlockType typ, uptr sz) {
+ ThreadState *thr = cur_thread();
+ if (thr->nomalloc) {
+ thr->nomalloc = 0; // CHECK calls internal_malloc().
+ CHECK(0);
+ }
+ return InternalAlloc(sz, &thr->internal_alloc_cache);
+}
+
+void internal_free(void *p) {
+ ThreadState *thr = cur_thread();
+ if (thr->nomalloc) {
+ thr->nomalloc = 0; // CHECK calls internal_malloc().
+ CHECK(0);
+ }
+ InternalFree(p, &thr->internal_alloc_cache);
+}
+
+} // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
+ allocator()->GetStats(stats);
+ return stats[AllocatorStatAllocated];
+}
+
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
+ allocator()->GetStats(stats);
+ return stats[AllocatorStatMapped];
+}
+
+uptr __sanitizer_get_free_bytes() {
+ return 1;
+}
+
+uptr __sanitizer_get_unmapped_bytes() {
+ return 1;
+}
+
+uptr __sanitizer_get_estimated_allocated_size(uptr size) {
+ return size;
+}
+
+int __sanitizer_get_ownership(const void *p) {
+ return allocator()->GetBlockBegin(p) != 0;
+}
+
+uptr __sanitizer_get_allocated_size(const void *p) {
+ return user_alloc_usable_size(p);
+}
+
+void __tsan_on_thread_idle() {
+ ThreadState *thr = cur_thread();
+ allocator()->SwallowCache(&thr->alloc_cache);
+ internal_allocator()->SwallowCache(&thr->internal_alloc_cache);
+ ctx->metamap.OnThreadIdle(thr);
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h
new file mode 100644
index 000000000000..5ff956d827f6
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h
@@ -0,0 +1,81 @@
+//===-- tsan_mman.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_MMAN_H
+#define TSAN_MMAN_H
+
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+const uptr kDefaultAlignment = 16;
+
+void InitializeAllocator();
+void AllocatorThreadStart(ThreadState *thr);
+void AllocatorThreadFinish(ThreadState *thr);
+void AllocatorPrintStats();
+
+// For user allocations.
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
+ uptr align = kDefaultAlignment, bool signal = true);
+void *user_calloc(ThreadState *thr, uptr pc, uptr sz, uptr n);
+// Does not accept NULL.
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true);
+void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz);
+void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
+uptr user_alloc_usable_size(const void *p);
+
+// Invoking malloc/free hooks that may be installed by the user.
+void invoke_malloc_hook(void *ptr, uptr size);
+void invoke_free_hook(void *ptr);
+
+enum MBlockType {
+ MBlockScopedBuf,
+ MBlockString,
+ MBlockStackTrace,
+ MBlockShadowStack,
+ MBlockSync,
+ MBlockClock,
+ MBlockThreadContex,
+ MBlockDeadInfo,
+ MBlockRacyStacks,
+ MBlockRacyAddresses,
+ MBlockAtExit,
+ MBlockFlag,
+ MBlockReport,
+ MBlockReportMop,
+ MBlockReportThread,
+ MBlockReportMutex,
+ MBlockReportLoc,
+ MBlockReportStack,
+ MBlockSuppression,
+ MBlockExpectRace,
+ MBlockSignal,
+ MBlockJmpBuf,
+
+ // This must be the last.
+ MBlockTypeCount
+};
+
+// For internal data structures.
+void *internal_alloc(MBlockType typ, uptr sz);
+void internal_free(void *p);
+
+template<typename T>
+void DestroyAndFree(T *&p) {
+ p->~T();
+ internal_free(p);
+ p = 0;
+}
+
+} // namespace __tsan
+#endif // TSAN_MMAN_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
new file mode 100644
index 000000000000..dc5a462a8081
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
@@ -0,0 +1,287 @@
+//===-- tsan_mutex.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_libc.h"
+#include "tsan_mutex.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+// Simple reader-writer spin-mutex. Optimized for not-so-contended case.
+// Readers have preference, can possibly starvate writers.
+
+// The table fixes what mutexes can be locked under what mutexes.
+// E.g. if the row for MutexTypeThreads contains MutexTypeReport,
+// then Report mutex can be locked while under Threads mutex.
+// The leaf mutexes can be locked under any other mutexes.
+// Recursive locking is not supported.
+#if SANITIZER_DEBUG && !SANITIZER_GO
+const MutexType MutexTypeLeaf = (MutexType)-1;
+static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
+ /*0 MutexTypeInvalid*/ {},
+ /*1 MutexTypeTrace*/ {MutexTypeLeaf},
+ /*2 MutexTypeThreads*/ {MutexTypeReport},
+ /*3 MutexTypeReport*/ {MutexTypeSyncVar,
+ MutexTypeMBlock, MutexTypeJavaMBlock},
+ /*4 MutexTypeSyncVar*/ {MutexTypeDDetector},
+ /*5 MutexTypeSyncTab*/ {}, // unused
+ /*6 MutexTypeSlab*/ {MutexTypeLeaf},
+ /*7 MutexTypeAnnotations*/ {},
+ /*8 MutexTypeAtExit*/ {MutexTypeSyncVar},
+ /*9 MutexTypeMBlock*/ {MutexTypeSyncVar},
+ /*10 MutexTypeJavaMBlock*/ {MutexTypeSyncVar},
+ /*11 MutexTypeDDetector*/ {},
+};
+
+static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
+#endif
+
+void InitializeMutex() {
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ // Build the "can lock" adjacency matrix.
+ // If [i][j]==true, then one can lock mutex j while under mutex i.
+ const int N = MutexTypeCount;
+ int cnt[N] = {};
+ bool leaf[N] = {};
+ for (int i = 1; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ MutexType z = CanLockTab[i][j];
+ if (z == MutexTypeInvalid)
+ continue;
+ if (z == MutexTypeLeaf) {
+ CHECK(!leaf[i]);
+ leaf[i] = true;
+ continue;
+ }
+ CHECK(!CanLockAdj[i][(int)z]);
+ CanLockAdj[i][(int)z] = true;
+ cnt[i]++;
+ }
+ }
+ for (int i = 0; i < N; i++) {
+ CHECK(!leaf[i] || cnt[i] == 0);
+ }
+ // Add leaf mutexes.
+ for (int i = 0; i < N; i++) {
+ if (!leaf[i])
+ continue;
+ for (int j = 0; j < N; j++) {
+ if (i == j || leaf[j] || j == MutexTypeInvalid)
+ continue;
+ CHECK(!CanLockAdj[j][i]);
+ CanLockAdj[j][i] = true;
+ }
+ }
+ // Build the transitive closure.
+ bool CanLockAdj2[MutexTypeCount][MutexTypeCount];
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ CanLockAdj2[i][j] = CanLockAdj[i][j];
+ }
+ }
+ for (int k = 0; k < N; k++) {
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ if (CanLockAdj2[i][k] && CanLockAdj2[k][j]) {
+ CanLockAdj2[i][j] = true;
+ }
+ }
+ }
+ }
+#if 0
+ Printf("Can lock graph:\n");
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ Printf("%d ", CanLockAdj[i][j]);
+ }
+ Printf("\n");
+ }
+ Printf("Can lock graph closure:\n");
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ Printf("%d ", CanLockAdj2[i][j]);
+ }
+ Printf("\n");
+ }
+#endif
+ // Verify that the graph is acyclic.
+ for (int i = 0; i < N; i++) {
+ if (CanLockAdj2[i][i]) {
+ Printf("Mutex %d participates in a cycle\n", i);
+ Die();
+ }
+ }
+#endif
+}
+
+InternalDeadlockDetector::InternalDeadlockDetector() {
+ // Rely on zero initialization because some mutexes can be locked before ctor.
+}
+
+#if SANITIZER_DEBUG && !SANITIZER_GO
+void InternalDeadlockDetector::Lock(MutexType t) {
+ // Printf("LOCK %d @%zu\n", t, seq_ + 1);
+ CHECK_GT(t, MutexTypeInvalid);
+ CHECK_LT(t, MutexTypeCount);
+ u64 max_seq = 0;
+ u64 max_idx = MutexTypeInvalid;
+ for (int i = 0; i != MutexTypeCount; i++) {
+ if (locked_[i] == 0)
+ continue;
+ CHECK_NE(locked_[i], max_seq);
+ if (max_seq < locked_[i]) {
+ max_seq = locked_[i];
+ max_idx = i;
+ }
+ }
+ locked_[t] = ++seq_;
+ if (max_idx == MutexTypeInvalid)
+ return;
+ // Printf(" last %d @%zu\n", max_idx, max_seq);
+ if (!CanLockAdj[max_idx][t]) {
+ Printf("ThreadSanitizer: internal deadlock detected\n");
+ Printf("ThreadSanitizer: can't lock %d while under %zu\n",
+ t, (uptr)max_idx);
+ CHECK(0);
+ }
+}
+
+void InternalDeadlockDetector::Unlock(MutexType t) {
+ // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
+ CHECK(locked_[t]);
+ locked_[t] = 0;
+}
+
+void InternalDeadlockDetector::CheckNoLocks() {
+ for (int i = 0; i != MutexTypeCount; i++) {
+ CHECK_EQ(locked_[i], 0);
+ }
+}
+#endif
+
+void CheckNoLocks(ThreadState *thr) {
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ thr->internal_deadlock_detector.CheckNoLocks();
+#endif
+}
+
+const uptr kUnlocked = 0;
+const uptr kWriteLock = 1;
+const uptr kReadLock = 2;
+
+class Backoff {
+ public:
+ Backoff()
+ : iter_() {
+ }
+
+ bool Do() {
+ if (iter_++ < kActiveSpinIters)
+ proc_yield(kActiveSpinCnt);
+ else
+ internal_sched_yield();
+ return true;
+ }
+
+ u64 Contention() const {
+ u64 active = iter_ % kActiveSpinIters;
+ u64 passive = iter_ - active;
+ return active + 10 * passive;
+ }
+
+ private:
+ int iter_;
+ static const int kActiveSpinIters = 10;
+ static const int kActiveSpinCnt = 20;
+};
+
+Mutex::Mutex(MutexType type, StatType stat_type) {
+ CHECK_GT(type, MutexTypeInvalid);
+ CHECK_LT(type, MutexTypeCount);
+#if SANITIZER_DEBUG
+ type_ = type;
+#endif
+#if TSAN_COLLECT_STATS
+ stat_type_ = stat_type;
+#endif
+ atomic_store(&state_, kUnlocked, memory_order_relaxed);
+}
+
+Mutex::~Mutex() {
+ CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+}
+
+void Mutex::Lock() {
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Lock(type_);
+#endif
+ uptr cmp = kUnlocked;
+ if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
+ memory_order_acquire))
+ return;
+ for (Backoff backoff; backoff.Do();) {
+ if (atomic_load(&state_, memory_order_relaxed) == kUnlocked) {
+ cmp = kUnlocked;
+ if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
+ memory_order_acquire)) {
+#if TSAN_COLLECT_STATS && !SANITIZER_GO
+ StatInc(cur_thread(), stat_type_, backoff.Contention());
+#endif
+ return;
+ }
+ }
+ }
+}
+
+void Mutex::Unlock() {
+ uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
+ (void)prev;
+ DCHECK_NE(prev & kWriteLock, 0);
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Unlock(type_);
+#endif
+}
+
+void Mutex::ReadLock() {
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Lock(type_);
+#endif
+ uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
+ if ((prev & kWriteLock) == 0)
+ return;
+ for (Backoff backoff; backoff.Do();) {
+ prev = atomic_load(&state_, memory_order_acquire);
+ if ((prev & kWriteLock) == 0) {
+#if TSAN_COLLECT_STATS && !SANITIZER_GO
+ StatInc(cur_thread(), stat_type_, backoff.Contention());
+#endif
+ return;
+ }
+ }
+}
+
+void Mutex::ReadUnlock() {
+ uptr prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
+ (void)prev;
+ DCHECK_EQ(prev & kWriteLock, 0);
+ DCHECK_GT(prev & ~kWriteLock, 0);
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Unlock(type_);
+#endif
+}
+
+void Mutex::CheckLocked() {
+ CHECK_NE(atomic_load(&state_, memory_order_relaxed), 0);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h
new file mode 100644
index 000000000000..88fad57c78a0
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h
@@ -0,0 +1,88 @@
+//===-- tsan_mutex.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_MUTEX_H
+#define TSAN_MUTEX_H
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+enum MutexType {
+ MutexTypeInvalid,
+ MutexTypeTrace,
+ MutexTypeThreads,
+ MutexTypeReport,
+ MutexTypeSyncVar,
+ MutexTypeSyncTab,
+ MutexTypeSlab,
+ MutexTypeAnnotations,
+ MutexTypeAtExit,
+ MutexTypeMBlock,
+ MutexTypeJavaMBlock,
+ MutexTypeDDetector,
+
+ // This must be the last.
+ MutexTypeCount
+};
+
+class Mutex {
+ public:
+ explicit Mutex(MutexType type, StatType stat_type);
+ ~Mutex();
+
+ void Lock();
+ void Unlock();
+
+ void ReadLock();
+ void ReadUnlock();
+
+ void CheckLocked();
+
+ private:
+ atomic_uintptr_t state_;
+#if SANITIZER_DEBUG
+ MutexType type_;
+#endif
+#if TSAN_COLLECT_STATS
+ StatType stat_type_;
+#endif
+
+ Mutex(const Mutex&);
+ void operator = (const Mutex&);
+};
+
+typedef GenericScopedLock<Mutex> Lock;
+typedef GenericScopedReadLock<Mutex> ReadLock;
+
+class InternalDeadlockDetector {
+ public:
+ InternalDeadlockDetector();
+ void Lock(MutexType t);
+ void Unlock(MutexType t);
+ void CheckNoLocks();
+ private:
+ u64 seq_;
+ u64 locked_[MutexTypeCount];
+};
+
+void InitializeMutex();
+
+// Checks that the current thread does not hold any runtime locks
+// (e.g. when returning from an interceptor).
+void CheckNoLocks(ThreadState *thr);
+
+} // namespace __tsan
+
+#endif // TSAN_MUTEX_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.cc
new file mode 100644
index 000000000000..21587770f687
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.cc
@@ -0,0 +1,89 @@
+//===-- tsan_mutexset.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_mutexset.h"
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+const uptr MutexSet::kMaxSize;
+
+MutexSet::MutexSet() {
+ size_ = 0;
+ internal_memset(&descs_, 0, sizeof(descs_));
+}
+
+void MutexSet::Add(u64 id, bool write, u64 epoch) {
+ // Look up existing mutex with the same id.
+ for (uptr i = 0; i < size_; i++) {
+ if (descs_[i].id == id) {
+ descs_[i].count++;
+ descs_[i].epoch = epoch;
+ return;
+ }
+ }
+ // On overflow, find the oldest mutex and drop it.
+ if (size_ == kMaxSize) {
+ u64 minepoch = (u64)-1;
+ u64 mini = (u64)-1;
+ for (uptr i = 0; i < size_; i++) {
+ if (descs_[i].epoch < minepoch) {
+ minepoch = descs_[i].epoch;
+ mini = i;
+ }
+ }
+ RemovePos(mini);
+ CHECK_EQ(size_, kMaxSize - 1);
+ }
+ // Add new mutex descriptor.
+ descs_[size_].id = id;
+ descs_[size_].write = write;
+ descs_[size_].epoch = epoch;
+ descs_[size_].count = 1;
+ size_++;
+}
+
+void MutexSet::Del(u64 id, bool write) {
+ for (uptr i = 0; i < size_; i++) {
+ if (descs_[i].id == id) {
+ if (--descs_[i].count == 0)
+ RemovePos(i);
+ return;
+ }
+ }
+}
+
+void MutexSet::Remove(u64 id) {
+ for (uptr i = 0; i < size_; i++) {
+ if (descs_[i].id == id) {
+ RemovePos(i);
+ return;
+ }
+ }
+}
+
+void MutexSet::RemovePos(uptr i) {
+ CHECK_LT(i, size_);
+ descs_[i] = descs_[size_ - 1];
+ size_--;
+}
+
+uptr MutexSet::Size() const {
+ return size_;
+}
+
+MutexSet::Desc MutexSet::Get(uptr i) const {
+ CHECK_LT(i, size_);
+ return descs_[i];
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.h
new file mode 100644
index 000000000000..68f0ec26fa25
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutexset.h
@@ -0,0 +1,70 @@
+//===-- tsan_mutexset.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 ThreadSanitizer (TSan), a race detector.
+//
+// MutexSet holds the set of mutexes currently held by a thread.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_MUTEXSET_H
+#define TSAN_MUTEXSET_H
+
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+class MutexSet {
+ public:
+ // Holds limited number of mutexes.
+ // The oldest mutexes are discarded on overflow.
+ static const uptr kMaxSize = 16;
+ struct Desc {
+ u64 id;
+ u64 epoch;
+ int count;
+ bool write;
+ };
+
+ MutexSet();
+ // The 'id' is obtained from SyncVar::GetId().
+ void Add(u64 id, bool write, u64 epoch);
+ void Del(u64 id, bool write);
+ void Remove(u64 id); // Removes the mutex completely (if it's destroyed).
+ uptr Size() const;
+ Desc Get(uptr i) const;
+
+ void operator=(const MutexSet &other) {
+ internal_memcpy(this, &other, sizeof(*this));
+ }
+
+ private:
+#ifndef SANITIZER_GO
+ uptr size_;
+ Desc descs_[kMaxSize];
+#endif
+
+ void RemovePos(uptr i);
+ MutexSet(const MutexSet&);
+};
+
+// Go does not have mutexes, so do not spend memory and time.
+// (Go sync.Mutex is actually a semaphore -- can be unlocked
+// in different goroutine).
+#ifdef SANITIZER_GO
+MutexSet::MutexSet() {}
+void MutexSet::Add(u64 id, bool write, u64 epoch) {}
+void MutexSet::Del(u64 id, bool write) {}
+void MutexSet::Remove(u64 id) {}
+void MutexSet::RemovePos(uptr i) {}
+uptr MutexSet::Size() const { return 0; }
+MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
+#endif
+
+} // namespace __tsan
+
+#endif // TSAN_MUTEXSET_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h
new file mode 100644
index 000000000000..135e16027132
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -0,0 +1,299 @@
+//===-- tsan_platform.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 ThreadSanitizer (TSan), a race detector.
+//
+// Platform-specific code.
+//===----------------------------------------------------------------------===//
+
+#ifndef TSAN_PLATFORM_H
+#define TSAN_PLATFORM_H
+
+#if !defined(__LP64__) && !defined(_WIN64)
+# error "Only 64-bit is supported"
+#endif
+
+#include "tsan_defs.h"
+#include "tsan_trace.h"
+
+namespace __tsan {
+
+#if !defined(SANITIZER_GO)
+
+#if defined(__x86_64__)
+/*
+C/C++ on linux/x86_64 and freebsd/x86_64
+0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings
+0100 0000 0000 - 0200 0000 0000: -
+0200 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
+4000 0000 0000 - 6000 0000 0000: -
+6000 0000 0000 - 6200 0000 0000: traces
+6200 0000 0000 - 7d00 0000 0000: -
+7d00 0000 0000 - 7e00 0000 0000: heap
+7e00 0000 0000 - 7e80 0000 0000: -
+7e80 0000 0000 - 8000 0000 0000: modules and main thread stack
+*/
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg = 0x600000000000ull;
+const uptr kTraceMemEnd = 0x620000000000ull;
+const uptr kShadowBeg = 0x020000000000ull;
+const uptr kShadowEnd = 0x100000000000ull;
+const uptr kHeapMemBeg = 0x7d0000000000ull;
+const uptr kHeapMemEnd = 0x7e0000000000ull;
+const uptr kLoAppMemBeg = 0x000000001000ull;
+const uptr kLoAppMemEnd = 0x010000000000ull;
+const uptr kHiAppMemBeg = 0x7e8000000000ull;
+const uptr kHiAppMemEnd = 0x800000000000ull;
+const uptr kAppMemMsk = 0x7c0000000000ull;
+const uptr kAppMemXor = 0x020000000000ull;
+const uptr kVdsoBeg = 0xf000000000000000ull;
+#elif defined(__mips64)
+/*
+C/C++ on linux/mips64
+0100 0000 00 - 0200 0000 00: main binary
+0200 0000 00 - 1400 0000 00: -
+1400 0000 00 - 2400 0000 00: shadow
+2400 0000 00 - 3000 0000 00: -
+3000 0000 00 - 4000 0000 00: metainfo (memory blocks and sync objects)
+4000 0000 00 - 6000 0000 00: -
+6000 0000 00 - 6200 0000 00: traces
+6200 0000 00 - fe00 0000 00: -
+fe00 0000 00 - ff00 0000 00: heap
+ff00 0000 00 - ff80 0000 00: -
+ff80 0000 00 - ffff ffff ff: modules and main thread stack
+*/
+const uptr kMetaShadowBeg = 0x3000000000ull;
+const uptr kMetaShadowEnd = 0x4000000000ull;
+const uptr kTraceMemBeg = 0x6000000000ull;
+const uptr kTraceMemEnd = 0x6200000000ull;
+const uptr kShadowBeg = 0x1400000000ull;
+const uptr kShadowEnd = 0x2400000000ull;
+const uptr kHeapMemBeg = 0xfe00000000ull;
+const uptr kHeapMemEnd = 0xff00000000ull;
+const uptr kLoAppMemBeg = 0x0100000000ull;
+const uptr kLoAppMemEnd = 0x0200000000ull;
+const uptr kHiAppMemBeg = 0xff80000000ull;
+const uptr kHiAppMemEnd = 0xffffffffffull;
+const uptr kAppMemMsk = 0xfc00000000ull;
+const uptr kAppMemXor = 0x0400000000ull;
+const uptr kVdsoBeg = 0xfffff00000ull;
+#endif
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+ return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
+ (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
+ (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+ return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+ return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
+ ^ kAppMemXor) * kShadowCnt;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
+ ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+ CHECK(IsShadowMem(s));
+ if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
+ return (s / kShadowCnt) ^ kAppMemXor;
+ else
+ return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
+}
+
+static USED uptr UserRegions[] = {
+ kLoAppMemBeg, kLoAppMemEnd,
+ kHiAppMemBeg, kHiAppMemEnd,
+ kHeapMemBeg, kHeapMemEnd,
+};
+
+#elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS
+
+/* Go on linux, darwin and freebsd
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00c0 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2380 0000 0000: shadow
+2380 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
+4000 0000 0000 - 6000 0000 0000: -
+6000 0000 0000 - 6200 0000 0000: traces
+6200 0000 0000 - 8000 0000 0000: -
+*/
+
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg = 0x600000000000ull;
+const uptr kTraceMemEnd = 0x620000000000ull;
+const uptr kShadowBeg = 0x200000000000ull;
+const uptr kShadowEnd = 0x238000000000ull;
+const uptr kAppMemBeg = 0x000000001000ull;
+const uptr kAppMemEnd = 0x00e000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+ return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+ return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+ return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+ DCHECK(IsAppMem(x));
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+ kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+ CHECK(IsShadowMem(s));
+ return (s & ~kShadowBeg) / kShadowCnt;
+}
+
+static USED uptr UserRegions[] = {
+ kAppMemBeg, kAppMemEnd,
+};
+
+#elif defined(SANITIZER_GO) && SANITIZER_WINDOWS
+
+/* Go on windows
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00f8 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 0500 0000 0000: shadow
+0500 0000 0000 - 0560 0000 0000: -
+0560 0000 0000 - 0760 0000 0000: traces
+0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
+07d0 0000 0000 - 8000 0000 0000: -
+*/
+
+const uptr kMetaShadowBeg = 0x076000000000ull;
+const uptr kMetaShadowEnd = 0x07d000000000ull;
+const uptr kTraceMemBeg = 0x056000000000ull;
+const uptr kTraceMemEnd = 0x076000000000ull;
+const uptr kShadowBeg = 0x010000000000ull;
+const uptr kShadowEnd = 0x050000000000ull;
+const uptr kAppMemBeg = 0x000000001000ull;
+const uptr kAppMemEnd = 0x00e000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+ return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+ return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+ return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+ DCHECK(IsAppMem(x));
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) + kShadowBeg;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+ kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+ CHECK(IsShadowMem(s));
+ // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
+ return (s - kShadowBeg) / kShadowCnt;
+}
+
+static USED uptr UserRegions[] = {
+ kAppMemBeg, kAppMemEnd,
+};
+
+#else
+# error "Unknown platform"
+#endif
+
+// The additional page is to catch shadow stack overflow as paging fault.
+// Windows wants 64K alignment for mmaps.
+const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace)
+ + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
+
+uptr ALWAYS_INLINE GetThreadTrace(int tid) {
+ uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
+ DCHECK_LT(p, kTraceMemEnd);
+ return p;
+}
+
+uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
+ uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
+ + kTraceSize * sizeof(Event);
+ DCHECK_LT(p, kTraceMemEnd);
+ return p;
+}
+
+void InitializePlatform();
+void FlushShadowMemory();
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
+
+// Says whether the addr relates to a global var.
+// Guesses with high probability, may yield both false positives and negatives.
+bool IsGlobalVar(uptr addr);
+int ExtractResolvFDs(void *state, int *fds, int nfd);
+int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
+
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+ void *abstime), void *c, void *m, void *abstime,
+ void(*cleanup)(void *arg), void *arg);
+
+} // namespace __tsan
+
+#endif // TSAN_PLATFORM_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
new file mode 100644
index 000000000000..659e8d8a8345
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
@@ -0,0 +1,412 @@
+//===-- tsan_platform_linux.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 ThreadSanitizer (TSan), a race detector.
+//
+// Linux- and FreeBSD-specific code.
+//===----------------------------------------------------------------------===//
+
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+#include "tsan_flags.h"
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+#include <dlfcn.h>
+#if SANITIZER_LINUX
+#define __need_res_state
+#include <resolv.h>
+#endif
+
+#ifdef sa_handler
+# undef sa_handler
+#endif
+
+#ifdef sa_sigaction
+# undef sa_sigaction
+#endif
+
+#if SANITIZER_FREEBSD
+extern "C" void *__libc_stack_end;
+void *__libc_stack_end = 0;
+#endif
+
+namespace __tsan {
+
+static uptr g_data_start;
+static uptr g_data_end;
+
+enum {
+ MemTotal = 0,
+ MemShadow = 1,
+ MemMeta = 2,
+ MemFile = 3,
+ MemMmap = 4,
+ MemTrace = 5,
+ MemHeap = 6,
+ MemOther = 7,
+ MemCount = 8,
+};
+
+void FillProfileCallback(uptr p, uptr rss, bool file,
+ uptr *mem, uptr stats_size) {
+ mem[MemTotal] += rss;
+ if (p >= kShadowBeg && p < kShadowEnd)
+ mem[MemShadow] += rss;
+ else if (p >= kMetaShadowBeg && p < kMetaShadowEnd)
+ mem[MemMeta] += rss;
+#ifndef SANITIZER_GO
+ else if (p >= kHeapMemBeg && p < kHeapMemEnd)
+ mem[MemHeap] += rss;
+ else if (p >= kLoAppMemBeg && p < kLoAppMemEnd)
+ mem[file ? MemFile : MemMmap] += rss;
+ else if (p >= kHiAppMemBeg && p < kHiAppMemEnd)
+ mem[file ? MemFile : MemMmap] += rss;
+#else
+ else if (p >= kAppMemBeg && p < kAppMemEnd)
+ mem[file ? MemFile : MemMmap] += rss;
+#endif
+ else if (p >= kTraceMemBeg && p < kTraceMemEnd)
+ mem[MemTrace] += rss;
+ else
+ mem[MemOther] += rss;
+}
+
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
+ uptr mem[MemCount] = {};
+ __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
+ StackDepotStats *stacks = StackDepotGetStats();
+ internal_snprintf(buf, buf_size,
+ "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd"
+ " trace:%zd heap:%zd other:%zd stacks=%zd[%zd] nthr=%zd/%zd\n",
+ mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20,
+ mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20,
+ mem[MemHeap] >> 20, mem[MemOther] >> 20,
+ stacks->allocated >> 20, stacks->n_uniq_ids,
+ nlive, nthread);
+}
+
+#if SANITIZER_LINUX
+void FlushShadowMemoryCallback(
+ const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
+ FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
+}
+#endif
+
+void FlushShadowMemory() {
+#if SANITIZER_LINUX
+ StopTheWorld(FlushShadowMemoryCallback, 0);
+#endif
+}
+
+#ifndef SANITIZER_GO
+static void ProtectRange(uptr beg, uptr end) {
+ CHECK_LE(beg, end);
+ if (beg == end)
+ return;
+ if (beg != (uptr)Mprotect(beg, end - beg)) {
+ Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
+ Printf("FATAL: Make sure you are not using unlimited stack\n");
+ Die();
+ }
+}
+
+// Mark shadow for .rodata sections with the special kShadowRodata marker.
+// Accesses to .rodata can't race, so this saves time, memory and trace space.
+static void MapRodata() {
+ // First create temp file.
+ const char *tmpdir = GetEnv("TMPDIR");
+ if (tmpdir == 0)
+ tmpdir = GetEnv("TEST_TMPDIR");
+#ifdef P_tmpdir
+ if (tmpdir == 0)
+ tmpdir = P_tmpdir;
+#endif
+ if (tmpdir == 0)
+ return;
+ char name[256];
+ internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d",
+ tmpdir, (int)internal_getpid());
+ uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
+ if (internal_iserror(openrv))
+ return;
+ internal_unlink(name); // Unlink it now, so that we can reuse the buffer.
+ fd_t fd = openrv;
+ // Fill the file with kShadowRodata.
+ const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
+ InternalScopedBuffer<u64> marker(kMarkerSize);
+ // volatile to prevent insertion of memset
+ for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
+ *p = kShadowRodata;
+ internal_write(fd, marker.data(), marker.size());
+ // Map the file into memory.
+ uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
+ if (internal_iserror(page)) {
+ internal_close(fd);
+ return;
+ }
+ // Map the file into shadow of .rodata sections.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr start, end, offset, prot;
+ // Reusing the buffer 'name'.
+ while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
+ if (name[0] != 0 && name[0] != '['
+ && (prot & MemoryMappingLayout::kProtectionRead)
+ && (prot & MemoryMappingLayout::kProtectionExecute)
+ && !(prot & MemoryMappingLayout::kProtectionWrite)
+ && IsAppMem(start)) {
+ // Assume it's .rodata
+ char *shadow_start = (char*)MemToShadow(start);
+ char *shadow_end = (char*)MemToShadow(end);
+ for (char *p = shadow_start; p < shadow_end; p += marker.size()) {
+ internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p),
+ PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
+ }
+ }
+ }
+ internal_close(fd);
+}
+
+void InitializeShadowMemory() {
+ // Map memory shadow.
+ uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+ kShadowEnd - kShadowBeg);
+ if (shadow != kShadowBeg) {
+ Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
+ Printf("FATAL: Make sure to compile with -fPIE and "
+ "to link with -pie (%p, %p).\n", shadow, kShadowBeg);
+ Die();
+ }
+ // This memory range is used for thread stacks and large user mmaps.
+ // Frequently a thread uses only a small part of stack and similarly
+ // a program uses a small part of large mmap. On some programs
+ // we see 20% memory usage reduction without huge pages for this range.
+ // FIXME: don't use constants here.
+#if defined(__x86_64__)
+ const uptr kMadviseRangeBeg = 0x7f0000000000ull;
+ const uptr kMadviseRangeSize = 0x010000000000ull;
+#elif defined(__mips64)
+ const uptr kMadviseRangeBeg = 0xff00000000ull;
+ const uptr kMadviseRangeSize = 0x0100000000ull;
+#endif
+ NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
+ kMadviseRangeSize * kShadowMultiplier);
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
+ DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
+ kShadowBeg, kShadowEnd,
+ (kShadowEnd - kShadowBeg) >> 30);
+
+ // Map meta shadow.
+ uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
+ uptr meta = (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size);
+ if (meta != kMetaShadowBeg) {
+ Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
+ Printf("FATAL: Make sure to compile with -fPIE and "
+ "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
+ Die();
+ }
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(meta, meta_size);
+ DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
+ meta, meta + meta_size, meta_size >> 30);
+
+ MapRodata();
+}
+
+static void InitDataSeg() {
+ MemoryMappingLayout proc_maps(true);
+ uptr start, end, offset;
+ char name[128];
+#if SANITIZER_FREEBSD
+ // On FreeBSD BSS is usually the last block allocated within the
+ // low range and heap is the last block allocated within the range
+ // 0x800000000-0x8ffffffff.
+ while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+ /*protection*/ 0)) {
+ DPrintf("%p-%p %p %s\n", start, end, offset, name);
+ if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 &&
+ name[0] == '\0') {
+ g_data_start = start;
+ g_data_end = end;
+ }
+ }
+#else
+ bool prev_is_data = false;
+ while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+ /*protection*/ 0)) {
+ DPrintf("%p-%p %p %s\n", start, end, offset, name);
+ bool is_data = offset != 0 && name[0] != 0;
+ // BSS may get merged with [heap] in /proc/self/maps. This is not very
+ // reliable.
+ bool is_bss = offset == 0 &&
+ (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
+ if (g_data_start == 0 && is_data)
+ g_data_start = start;
+ if (is_bss)
+ g_data_end = end;
+ prev_is_data = is_data;
+ }
+#endif
+ DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
+ CHECK_LT(g_data_start, g_data_end);
+ CHECK_GE((uptr)&g_data_start, g_data_start);
+ CHECK_LT((uptr)&g_data_start, g_data_end);
+}
+
+static void CheckAndProtect() {
+ // Ensure that the binary is indeed compiled with -pie.
+ MemoryMappingLayout proc_maps(true);
+ uptr p, end;
+ while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) {
+ if (IsAppMem(p))
+ continue;
+ if (p >= kHeapMemEnd &&
+ p < HeapEnd())
+ continue;
+ if (p >= kVdsoBeg) // vdso
+ break;
+ Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+ Die();
+ }
+
+ ProtectRange(kLoAppMemEnd, kShadowBeg);
+ ProtectRange(kShadowEnd, kMetaShadowBeg);
+ ProtectRange(kMetaShadowEnd, kTraceMemBeg);
+ // Memory for traces is mapped lazily in MapThreadTrace.
+ // Protect the whole range for now, so that user does not map something here.
+ ProtectRange(kTraceMemBeg, kTraceMemEnd);
+ ProtectRange(kTraceMemEnd, kHeapMemBeg);
+ ProtectRange(HeapEnd(), kHiAppMemBeg);
+}
+#endif // #ifndef SANITIZER_GO
+
+void InitializePlatform() {
+ DisableCoreDumperIfNecessary();
+
+ // Go maps shadow memory lazily and works fine with limited address space.
+ // Unlimited stack is not a problem as well, because the executable
+ // is not compiled with -pie.
+ if (kCppMode) {
+ bool reexec = false;
+ // TSan doesn't play well with unlimited stack size (as stack
+ // overlaps with shadow memory). If we detect unlimited stack size,
+ // we re-exec the program with limited stack size as a best effort.
+ if (StackSizeIsUnlimited()) {
+ const uptr kMaxStackSize = 32 * 1024 * 1024;
+ VReport(1, "Program is run with unlimited stack size, which wouldn't "
+ "work with ThreadSanitizer.\n"
+ "Re-execing with stack size limited to %zd bytes.\n",
+ kMaxStackSize);
+ SetStackSizeLimitInBytes(kMaxStackSize);
+ reexec = true;
+ }
+
+ if (!AddressSpaceIsUnlimited()) {
+ Report("WARNING: Program is run with limited virtual address space,"
+ " which wouldn't work with ThreadSanitizer.\n");
+ Report("Re-execing with unlimited virtual address space.\n");
+ SetAddressSpaceUnlimited();
+ reexec = true;
+ }
+ if (reexec)
+ ReExec();
+ }
+
+#ifndef SANITIZER_GO
+ CheckAndProtect();
+ InitTlsSize();
+ InitDataSeg();
+#endif
+}
+
+bool IsGlobalVar(uptr addr) {
+ return g_data_start && addr >= g_data_start && addr < g_data_end;
+}
+
+#ifndef SANITIZER_GO
+// Extract file descriptors passed to glibc internal __res_iclose function.
+// This is required to properly "close" the fds, because we do not see internal
+// closes within glibc. The code is a pure hack.
+int ExtractResolvFDs(void *state, int *fds, int nfd) {
+#if SANITIZER_LINUX
+ int cnt = 0;
+ __res_state *statp = (__res_state*)state;
+ for (int i = 0; i < MAXNS && cnt < nfd; i++) {
+ if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
+ fds[cnt++] = statp->_u._ext.nssocks[i];
+ }
+ return cnt;
+#else
+ return 0;
+#endif
+}
+
+// Extract file descriptors passed via UNIX domain sockets.
+// This is requried to properly handle "open" of these fds.
+// see 'man recvmsg' and 'man 3 cmsg'.
+int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
+ int res = 0;
+ msghdr *msg = (msghdr*)msgp;
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+ for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
+ continue;
+ int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);
+ for (int i = 0; i < n; i++) {
+ fds[res++] = ((int*)CMSG_DATA(cmsg))[i];
+ if (res == nfd)
+ return res;
+ }
+ }
+ return res;
+}
+
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+ void *abstime), void *c, void *m, void *abstime,
+ void(*cleanup)(void *arg), void *arg) {
+ // pthread_cleanup_push/pop are hardcore macros mess.
+ // We can't intercept nor call them w/o including pthread.h.
+ int res;
+ pthread_cleanup_push(cleanup, arg);
+ res = fn(c, m, abstime);
+ pthread_cleanup_pop(0);
+ return res;
+}
+#endif
+
+} // namespace __tsan
+
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc
new file mode 100644
index 000000000000..63f1748e13ce
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc
@@ -0,0 +1,94 @@
+//===-- tsan_platform_mac.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 ThreadSanitizer (TSan), a race detector.
+//
+// Mac-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+#include "tsan_flags.h"
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+
+namespace __tsan {
+
+uptr GetShadowMemoryConsumption() {
+ return 0;
+}
+
+void FlushShadowMemory() {
+}
+
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
+}
+
+#ifndef SANITIZER_GO
+void InitializeShadowMemory() {
+ uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+ kShadowEnd - kShadowBeg);
+ if (shadow != kShadowBeg) {
+ Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
+ Printf("FATAL: Make sure to compile with -fPIE and "
+ "to link with -pie.\n");
+ Die();
+ }
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
+ DPrintf("kShadow %zx-%zx (%zuGB)\n",
+ kShadowBeg, kShadowEnd,
+ (kShadowEnd - kShadowBeg) >> 30);
+ DPrintf("kAppMem %zx-%zx (%zuGB)\n",
+ kAppMemBeg, kAppMemEnd,
+ (kAppMemEnd - kAppMemBeg) >> 30);
+}
+#endif
+
+void InitializePlatform() {
+ DisableCoreDumperIfNecessary();
+}
+
+#ifndef SANITIZER_GO
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+ void *abstime), void *c, void *m, void *abstime,
+ void(*cleanup)(void *arg), void *arg) {
+ // pthread_cleanup_push/pop are hardcore macros mess.
+ // We can't intercept nor call them w/o including pthread.h.
+ int res;
+ pthread_cleanup_push(cleanup, arg);
+ res = fn(c, m, abstime);
+ pthread_cleanup_pop(0);
+ return res;
+}
+#endif
+
+} // namespace __tsan
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc
new file mode 100644
index 000000000000..cfbe77da2c07
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc
@@ -0,0 +1,39 @@
+//===-- tsan_platform_windows.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 ThreadSanitizer (TSan), a race detector.
+//
+// Windows-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
+#include "tsan_platform.h"
+
+#include <stdlib.h>
+
+namespace __tsan {
+
+uptr GetShadowMemoryConsumption() {
+ return 0;
+}
+
+void FlushShadowMemory() {
+}
+
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
+}
+
+void InitializePlatform() {
+}
+
+} // namespace __tsan
+
+#endif // SANITIZER_WINDOWS
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc
new file mode 100644
index 000000000000..7e69cb4ecfbc
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc
@@ -0,0 +1,413 @@
+//===-- tsan_report.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_report.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
+
+namespace __tsan {
+
+ReportStack::ReportStack() : frames(nullptr), suppressable(false) {}
+
+ReportStack *ReportStack::New() {
+ void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack));
+ return new(mem) ReportStack();
+}
+
+ReportLocation::ReportLocation(ReportLocationType type)
+ : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0),
+ fd(0), suppressable(false), stack(nullptr) {}
+
+ReportLocation *ReportLocation::New(ReportLocationType type) {
+ void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation));
+ return new(mem) ReportLocation(type);
+}
+
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() { }
+ const char *Warning() { return Red(); }
+ const char *EndWarning() { return Default(); }
+ const char *Access() { return Blue(); }
+ const char *EndAccess() { return Default(); }
+ const char *ThreadDescription() { return Cyan(); }
+ const char *EndThreadDescription() { return Default(); }
+ const char *Location() { return Green(); }
+ const char *EndLocation() { return Default(); }
+ const char *Sleep() { return Yellow(); }
+ const char *EndSleep() { return Default(); }
+ const char *Mutex() { return Magenta(); }
+ const char *EndMutex() { return Default(); }
+};
+
+ReportDesc::ReportDesc()
+ : stacks(MBlockReportStack)
+ , mops(MBlockReportMop)
+ , locs(MBlockReportLoc)
+ , mutexes(MBlockReportMutex)
+ , threads(MBlockReportThread)
+ , unique_tids(MBlockReportThread)
+ , sleep()
+ , count() {
+}
+
+ReportMop::ReportMop()
+ : mset(MBlockReportMutex) {
+}
+
+ReportDesc::~ReportDesc() {
+ // FIXME(dvyukov): it must be leaking a lot of memory.
+}
+
+#ifndef SANITIZER_GO
+
+const int kThreadBufSize = 32;
+const char *thread_name(char *buf, int tid) {
+ if (tid == 0)
+ return "main thread";
+ internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
+ return buf;
+}
+
+static const char *ReportTypeString(ReportType typ) {
+ if (typ == ReportTypeRace)
+ return "data race";
+ if (typ == ReportTypeVptrRace)
+ return "data race on vptr (ctor/dtor vs virtual call)";
+ if (typ == ReportTypeUseAfterFree)
+ return "heap-use-after-free";
+ if (typ == ReportTypeVptrUseAfterFree)
+ return "heap-use-after-free (virtual call vs free)";
+ if (typ == ReportTypeThreadLeak)
+ return "thread leak";
+ if (typ == ReportTypeMutexDestroyLocked)
+ return "destroy of a locked mutex";
+ if (typ == ReportTypeMutexDoubleLock)
+ return "double lock of a mutex";
+ if (typ == ReportTypeMutexBadUnlock)
+ return "unlock of an unlocked mutex (or by a wrong thread)";
+ if (typ == ReportTypeMutexBadReadLock)
+ return "read lock of a write locked mutex";
+ if (typ == ReportTypeMutexBadReadUnlock)
+ return "read unlock of a write locked mutex";
+ if (typ == ReportTypeSignalUnsafe)
+ return "signal-unsafe call inside of a signal";
+ if (typ == ReportTypeErrnoInSignal)
+ return "signal handler spoils errno";
+ if (typ == ReportTypeDeadlock)
+ return "lock-order-inversion (potential deadlock)";
+ return "";
+}
+
+void PrintStack(const ReportStack *ent) {
+ if (ent == 0 || ent->frames == 0) {
+ Printf(" [failed to restore the stack]\n\n");
+ return;
+ }
+ SymbolizedStack *frame = ent->frames;
+ for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
+ InternalScopedString res(2 * GetPageSizeCached());
+ RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info,
+ common_flags()->strip_path_prefix, "__interceptor_");
+ Printf("%s\n", res.data());
+ }
+ Printf("\n");
+}
+
+static void PrintMutexSet(Vector<ReportMopMutex> const& mset) {
+ for (uptr i = 0; i < mset.Size(); i++) {
+ if (i == 0)
+ Printf(" (mutexes:");
+ const ReportMopMutex m = mset[i];
+ Printf(" %s M%llu", m.write ? "write" : "read", m.id);
+ Printf(i == mset.Size() - 1 ? ")" : ",");
+ }
+}
+
+static const char *MopDesc(bool first, bool write, bool atomic) {
+ return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
+ : (write ? "Previous atomic write" : "Previous atomic read"))
+ : (first ? (write ? "Write" : "Read")
+ : (write ? "Previous write" : "Previous read"));
+}
+
+static void PrintMop(const ReportMop *mop, bool first) {
+ Decorator d;
+ char thrbuf[kThreadBufSize];
+ Printf("%s", d.Access());
+ Printf(" %s of size %d at %p by %s",
+ MopDesc(first, mop->write, mop->atomic),
+ mop->size, (void*)mop->addr,
+ thread_name(thrbuf, mop->tid));
+ PrintMutexSet(mop->mset);
+ Printf(":\n");
+ Printf("%s", d.EndAccess());
+ PrintStack(mop->stack);
+}
+
+static void PrintLocation(const ReportLocation *loc) {
+ Decorator d;
+ char thrbuf[kThreadBufSize];
+ bool print_stack = false;
+ Printf("%s", d.Location());
+ if (loc->type == ReportLocationGlobal) {
+ const DataInfo &global = loc->global;
+ Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
+ global.name, global.size, global.start,
+ StripModuleName(global.module), global.module_offset);
+ } else if (loc->type == ReportLocationHeap) {
+ char thrbuf[kThreadBufSize];
+ Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
+ loc->heap_chunk_size, loc->heap_chunk_start,
+ thread_name(thrbuf, loc->tid));
+ print_stack = true;
+ } else if (loc->type == ReportLocationStack) {
+ Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
+ } else if (loc->type == ReportLocationTLS) {
+ Printf(" Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid));
+ } else if (loc->type == ReportLocationFD) {
+ Printf(" Location is file descriptor %d created by %s at:\n",
+ loc->fd, thread_name(thrbuf, loc->tid));
+ print_stack = true;
+ }
+ Printf("%s", d.EndLocation());
+ if (print_stack)
+ PrintStack(loc->stack);
+}
+
+static void PrintMutexShort(const ReportMutex *rm, const char *after) {
+ Decorator d;
+ Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after);
+}
+
+static void PrintMutexShortWithAddress(const ReportMutex *rm,
+ const char *after) {
+ Decorator d;
+ Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after);
+}
+
+static void PrintMutex(const ReportMutex *rm) {
+ Decorator d;
+ if (rm->destroyed) {
+ Printf("%s", d.Mutex());
+ Printf(" Mutex M%llu is already destroyed.\n\n", rm->id);
+ Printf("%s", d.EndMutex());
+ } else {
+ Printf("%s", d.Mutex());
+ Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr);
+ Printf("%s", d.EndMutex());
+ PrintStack(rm->stack);
+ }
+}
+
+static void PrintThread(const ReportThread *rt) {
+ Decorator d;
+ if (rt->id == 0) // Little sense in describing the main thread.
+ return;
+ Printf("%s", d.ThreadDescription());
+ Printf(" Thread T%d", rt->id);
+ if (rt->name && rt->name[0] != '\0')
+ Printf(" '%s'", rt->name);
+ char thrbuf[kThreadBufSize];
+ Printf(" (tid=%zu, %s) created by %s",
+ rt->pid, rt->running ? "running" : "finished",
+ thread_name(thrbuf, rt->parent_tid));
+ if (rt->stack)
+ Printf(" at:");
+ Printf("\n");
+ Printf("%s", d.EndThreadDescription());
+ PrintStack(rt->stack);
+}
+
+static void PrintSleep(const ReportStack *s) {
+ Decorator d;
+ Printf("%s", d.Sleep());
+ Printf(" As if synchronized via sleep:\n");
+ Printf("%s", d.EndSleep());
+ PrintStack(s);
+}
+
+static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
+ if (rep->mops.Size())
+ return rep->mops[0]->stack;
+ if (rep->stacks.Size())
+ return rep->stacks[0];
+ if (rep->mutexes.Size())
+ return rep->mutexes[0]->stack;
+ if (rep->threads.Size())
+ return rep->threads[0]->stack;
+ return 0;
+}
+
+static bool FrameIsInternal(const SymbolizedStack *frame) {
+ if (frame == 0)
+ return false;
+ const char *file = frame->info.file;
+ return file != 0 &&
+ (internal_strstr(file, "tsan_interceptors.cc") ||
+ internal_strstr(file, "sanitizer_common_interceptors.inc") ||
+ internal_strstr(file, "tsan_interface_"));
+}
+
+static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
+ while (FrameIsInternal(frames) && frames->next)
+ frames = frames->next;
+ return frames;
+}
+
+void PrintReport(const ReportDesc *rep) {
+ Decorator d;
+ Printf("==================\n");
+ const char *rep_typ_str = ReportTypeString(rep->typ);
+ Printf("%s", d.Warning());
+ Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
+ (int)internal_getpid());
+ Printf("%s", d.EndWarning());
+
+ if (rep->typ == ReportTypeDeadlock) {
+ char thrbuf[kThreadBufSize];
+ Printf(" Cycle in lock order graph: ");
+ for (uptr i = 0; i < rep->mutexes.Size(); i++)
+ PrintMutexShortWithAddress(rep->mutexes[i], " => ");
+ PrintMutexShort(rep->mutexes[0], "\n\n");
+ CHECK_GT(rep->mutexes.Size(), 0U);
+ CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1),
+ rep->stacks.Size());
+ for (uptr i = 0; i < rep->mutexes.Size(); i++) {
+ Printf(" Mutex ");
+ PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()],
+ " acquired here while holding mutex ");
+ PrintMutexShort(rep->mutexes[i], " in ");
+ Printf("%s", d.ThreadDescription());
+ Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i]));
+ Printf("%s", d.EndThreadDescription());
+ if (flags()->second_deadlock_stack) {
+ PrintStack(rep->stacks[2*i]);
+ Printf(" Mutex ");
+ PrintMutexShort(rep->mutexes[i],
+ " previously acquired by the same thread here:\n");
+ PrintStack(rep->stacks[2*i+1]);
+ } else {
+ PrintStack(rep->stacks[i]);
+ if (i == 0)
+ Printf(" Hint: use TSAN_OPTIONS=second_deadlock_stack=1 "
+ "to get more informative warning message\n\n");
+ }
+ }
+ } else {
+ for (uptr i = 0; i < rep->stacks.Size(); i++) {
+ if (i)
+ Printf(" and:\n");
+ PrintStack(rep->stacks[i]);
+ }
+ }
+
+ for (uptr i = 0; i < rep->mops.Size(); i++)
+ PrintMop(rep->mops[i], i == 0);
+
+ if (rep->sleep)
+ PrintSleep(rep->sleep);
+
+ for (uptr i = 0; i < rep->locs.Size(); i++)
+ PrintLocation(rep->locs[i]);
+
+ if (rep->typ != ReportTypeDeadlock) {
+ for (uptr i = 0; i < rep->mutexes.Size(); i++)
+ PrintMutex(rep->mutexes[i]);
+ }
+
+ for (uptr i = 0; i < rep->threads.Size(); i++)
+ PrintThread(rep->threads[i]);
+
+ if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
+ Printf(" And %d more similar thread leaks.\n\n", rep->count - 1);
+
+ if (ReportStack *stack = ChooseSummaryStack(rep)) {
+ if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) {
+ const AddressInfo &info = frame->info;
+ ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
+ }
+ }
+
+ Printf("==================\n");
+}
+
+#else // #ifndef SANITIZER_GO
+
+const int kMainThreadId = 1;
+
+void PrintStack(const ReportStack *ent) {
+ if (ent == 0 || ent->frames == 0) {
+ Printf(" [failed to restore the stack]\n");
+ return;
+ }
+ SymbolizedStack *frame = ent->frames;
+ for (int i = 0; frame; frame = frame->next, i++) {
+ const AddressInfo &info = frame->info;
+ Printf(" %s()\n %s:%d +0x%zx\n", info.function,
+ StripPathPrefix(info.file, common_flags()->strip_path_prefix),
+ info.line, (void *)info.module_offset);
+ }
+}
+
+static void PrintMop(const ReportMop *mop, bool first) {
+ Printf("\n");
+ Printf("%s by ",
+ (first ? (mop->write ? "Write" : "Read")
+ : (mop->write ? "Previous write" : "Previous read")));
+ if (mop->tid == kMainThreadId)
+ Printf("main goroutine:\n");
+ else
+ Printf("goroutine %d:\n", mop->tid);
+ PrintStack(mop->stack);
+}
+
+static void PrintThread(const ReportThread *rt) {
+ if (rt->id == kMainThreadId)
+ return;
+ Printf("\n");
+ Printf("Goroutine %d (%s) created at:\n",
+ rt->id, rt->running ? "running" : "finished");
+ PrintStack(rt->stack);
+}
+
+void PrintReport(const ReportDesc *rep) {
+ Printf("==================\n");
+ if (rep->typ == ReportTypeRace) {
+ Printf("WARNING: DATA RACE");
+ for (uptr i = 0; i < rep->mops.Size(); i++)
+ PrintMop(rep->mops[i], i == 0);
+ for (uptr i = 0; i < rep->threads.Size(); i++)
+ PrintThread(rep->threads[i]);
+ } else if (rep->typ == ReportTypeDeadlock) {
+ Printf("WARNING: DEADLOCK\n");
+ for (uptr i = 0; i < rep->mutexes.Size(); i++) {
+ Printf("Goroutine %d lock mutex %d while holding mutex %d:\n",
+ 999, rep->mutexes[i]->id,
+ rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
+ PrintStack(rep->stacks[2*i]);
+ Printf("\n");
+ Printf("Mutex %d was previously locked here:\n",
+ rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
+ PrintStack(rep->stacks[2*i + 1]);
+ Printf("\n");
+ }
+ }
+ Printf("==================\n");
+}
+
+#endif
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_report.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_report.h
new file mode 100644
index 000000000000..3e344a048e43
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_report.h
@@ -0,0 +1,129 @@
+//===-- tsan_report.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_REPORT_H
+#define TSAN_REPORT_H
+
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "tsan_defs.h"
+#include "tsan_vector.h"
+
+namespace __tsan {
+
+enum ReportType {
+ ReportTypeRace,
+ ReportTypeVptrRace,
+ ReportTypeUseAfterFree,
+ ReportTypeVptrUseAfterFree,
+ ReportTypeThreadLeak,
+ ReportTypeMutexDestroyLocked,
+ ReportTypeMutexDoubleLock,
+ ReportTypeMutexBadUnlock,
+ ReportTypeMutexBadReadLock,
+ ReportTypeMutexBadReadUnlock,
+ ReportTypeSignalUnsafe,
+ ReportTypeErrnoInSignal,
+ ReportTypeDeadlock
+};
+
+struct ReportStack {
+ SymbolizedStack *frames;
+ bool suppressable;
+ static ReportStack *New();
+
+ private:
+ ReportStack();
+};
+
+struct ReportMopMutex {
+ u64 id;
+ bool write;
+};
+
+struct ReportMop {
+ int tid;
+ uptr addr;
+ int size;
+ bool write;
+ bool atomic;
+ Vector<ReportMopMutex> mset;
+ ReportStack *stack;
+
+ ReportMop();
+};
+
+enum ReportLocationType {
+ ReportLocationGlobal,
+ ReportLocationHeap,
+ ReportLocationStack,
+ ReportLocationTLS,
+ ReportLocationFD
+};
+
+struct ReportLocation {
+ ReportLocationType type;
+ DataInfo global;
+ uptr heap_chunk_start;
+ uptr heap_chunk_size;
+ int tid;
+ int fd;
+ bool suppressable;
+ ReportStack *stack;
+
+ static ReportLocation *New(ReportLocationType type);
+ private:
+ explicit ReportLocation(ReportLocationType type);
+};
+
+struct ReportThread {
+ int id;
+ uptr pid;
+ bool running;
+ char *name;
+ int parent_tid;
+ ReportStack *stack;
+};
+
+struct ReportMutex {
+ u64 id;
+ uptr addr;
+ bool destroyed;
+ ReportStack *stack;
+};
+
+class ReportDesc {
+ public:
+ ReportType typ;
+ Vector<ReportStack*> stacks;
+ Vector<ReportMop*> mops;
+ Vector<ReportLocation*> locs;
+ Vector<ReportMutex*> mutexes;
+ Vector<ReportThread*> threads;
+ Vector<int> unique_tids;
+ ReportStack *sleep;
+ int count;
+
+ ReportDesc();
+ ~ReportDesc();
+
+ private:
+ ReportDesc(const ReportDesc&);
+ void operator = (const ReportDesc&);
+};
+
+// Format and output the report to the console/log. No additional logic.
+void PrintReport(const ReportDesc *rep);
+void PrintStack(const ReportStack *stack);
+
+} // namespace __tsan
+
+#endif // TSAN_REPORT_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
new file mode 100644
index 000000000000..b76f3e05dde6
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
@@ -0,0 +1,1006 @@
+//===-- tsan_rtl.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 ThreadSanitizer (TSan), a race detector.
+//
+// Main file (entry points) for the TSan run-time.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "tsan_defs.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "tsan_suppressions.h"
+#include "tsan_symbolize.h"
+
+#ifdef __SSE3__
+// <emmintrin.h> transitively includes <stdlib.h>,
+// and it's prohibited to include std headers into tsan runtime.
+// So we do this dirty trick.
+#define _MM_MALLOC_H_INCLUDED
+#define __MM_MALLOC_H
+#include <emmintrin.h>
+typedef __m128i m128;
+#endif
+
+volatile int __tsan_resumed = 0;
+
+extern "C" void __tsan_resume() {
+ __tsan_resumed = 1;
+}
+
+namespace __tsan {
+
+#ifndef SANITIZER_GO
+THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
+#endif
+static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
+Context *ctx;
+
+// Can be overriden by a front-end.
+#ifdef TSAN_EXTERNAL_HOOKS
+bool OnFinalize(bool failed);
+void OnInitialize();
+#else
+SANITIZER_INTERFACE_ATTRIBUTE
+bool WEAK OnFinalize(bool failed) {
+ return failed;
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void WEAK OnInitialize() {}
+#endif
+
+static char thread_registry_placeholder[sizeof(ThreadRegistry)];
+
+static ThreadContextBase *CreateThreadContext(u32 tid) {
+ // Map thread trace when context is created.
+ MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event));
+ const uptr hdr = GetThreadTraceHeader(tid);
+ MapThreadTrace(hdr, sizeof(Trace));
+ new((void*)hdr) Trace();
+ // We are going to use only a small part of the trace with the default
+ // value of history_size. However, the constructor writes to the whole trace.
+ // Unmap the unused part.
+ uptr hdr_end = hdr + sizeof(Trace);
+ hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts());
+ hdr_end = RoundUp(hdr_end, GetPageSizeCached());
+ if (hdr_end < hdr + sizeof(Trace))
+ UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end);
+ void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
+ return new(mem) ThreadContext(tid);
+}
+
+#ifndef SANITIZER_GO
+static const u32 kThreadQuarantineSize = 16;
+#else
+static const u32 kThreadQuarantineSize = 64;
+#endif
+
+Context::Context()
+ : initialized()
+ , report_mtx(MutexTypeReport, StatMtxReport)
+ , nreported()
+ , nmissed_expected()
+ , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
+ CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
+ , racy_stacks(MBlockRacyStacks)
+ , racy_addresses(MBlockRacyAddresses)
+ , fired_suppressions(8) {
+}
+
+// The objects are allocated in TLS, so one may rely on zero-initialization.
+ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
+ unsigned reuse_count,
+ uptr stk_addr, uptr stk_size,
+ uptr tls_addr, uptr tls_size)
+ : fast_state(tid, epoch)
+ // Do not touch these, rely on zero initialization,
+ // they may be accessed before the ctor.
+ // , ignore_reads_and_writes()
+ // , ignore_interceptors()
+ , clock(tid, reuse_count)
+#ifndef SANITIZER_GO
+ , jmp_bufs(MBlockJmpBuf)
+#endif
+ , tid(tid)
+ , unique_id(unique_id)
+ , stk_addr(stk_addr)
+ , stk_size(stk_size)
+ , tls_addr(tls_addr)
+ , tls_size(tls_size)
+#ifndef SANITIZER_GO
+ , last_sleep_clock(tid)
+#endif
+{
+}
+
+#ifndef SANITIZER_GO
+static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
+ uptr n_threads;
+ uptr n_running_threads;
+ ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
+ InternalScopedBuffer<char> buf(4096);
+ WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads);
+ internal_write(fd, buf.data(), internal_strlen(buf.data()));
+}
+
+static void BackgroundThread(void *arg) {
+ // This is a non-initialized non-user thread, nothing to see here.
+ // We don't use ScopedIgnoreInterceptors, because we want ignores to be
+ // enabled even when the thread function exits (e.g. during pthread thread
+ // shutdown code).
+ cur_thread()->ignore_interceptors++;
+ const u64 kMs2Ns = 1000 * 1000;
+
+ fd_t mprof_fd = kInvalidFd;
+ if (flags()->profile_memory && flags()->profile_memory[0]) {
+ if (internal_strcmp(flags()->profile_memory, "stdout") == 0) {
+ mprof_fd = 1;
+ } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
+ mprof_fd = 2;
+ } else {
+ InternalScopedString filename(kMaxPathLength);
+ filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
+ uptr openrv = OpenFile(filename.data(), true);
+ if (internal_iserror(openrv)) {
+ Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
+ &filename[0]);
+ } else {
+ mprof_fd = openrv;
+ }
+ }
+ }
+
+ u64 last_flush = NanoTime();
+ uptr last_rss = 0;
+ for (int i = 0;
+ atomic_load(&ctx->stop_background_thread, memory_order_relaxed) == 0;
+ i++) {
+ SleepForMillis(100);
+ u64 now = NanoTime();
+
+ // Flush memory if requested.
+ if (flags()->flush_memory_ms > 0) {
+ if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
+ VPrintf(1, "ThreadSanitizer: periodic memory flush\n");
+ FlushShadowMemory();
+ last_flush = NanoTime();
+ }
+ }
+ // GetRSS can be expensive on huge programs, so don't do it every 100ms.
+ if (flags()->memory_limit_mb > 0) {
+ uptr rss = GetRSS();
+ uptr limit = uptr(flags()->memory_limit_mb) << 20;
+ VPrintf(1, "ThreadSanitizer: memory flush check"
+ " RSS=%llu LAST=%llu LIMIT=%llu\n",
+ (u64)rss >> 20, (u64)last_rss >> 20, (u64)limit >> 20);
+ if (2 * rss > limit + last_rss) {
+ VPrintf(1, "ThreadSanitizer: flushing memory due to RSS\n");
+ FlushShadowMemory();
+ rss = GetRSS();
+ VPrintf(1, "ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
+ }
+ last_rss = rss;
+ }
+
+ // Write memory profile if requested.
+ if (mprof_fd != kInvalidFd)
+ MemoryProfiler(ctx, mprof_fd, i);
+
+ // Flush symbolizer cache if requested.
+ if (flags()->flush_symbolizer_ms > 0) {
+ u64 last = atomic_load(&ctx->last_symbolize_time_ns,
+ memory_order_relaxed);
+ if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) {
+ Lock l(&ctx->report_mtx);
+ SpinMutexLock l2(&CommonSanitizerReportMutex);
+ SymbolizeFlush();
+ atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed);
+ }
+ }
+ }
+}
+
+static void StartBackgroundThread() {
+ ctx->background_thread = internal_start_thread(&BackgroundThread, 0);
+}
+
+#ifndef __mips__
+static void StopBackgroundThread() {
+ atomic_store(&ctx->stop_background_thread, 1, memory_order_relaxed);
+ internal_join_thread(ctx->background_thread);
+ ctx->background_thread = 0;
+}
+#endif
+#endif
+
+void DontNeedShadowFor(uptr addr, uptr size) {
+ uptr shadow_beg = MemToShadow(addr);
+ uptr shadow_end = MemToShadow(addr + size);
+ FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+}
+
+void MapShadow(uptr addr, uptr size) {
+ // Global data is not 64K aligned, but there are no adjacent mappings,
+ // so we can get away with unaligned mapping.
+ // CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
+ MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier);
+
+ // Meta shadow is 2:1, so tread carefully.
+ static bool data_mapped = false;
+ static uptr mapped_meta_end = 0;
+ uptr meta_begin = (uptr)MemToMeta(addr);
+ uptr meta_end = (uptr)MemToMeta(addr + size);
+ meta_begin = RoundDownTo(meta_begin, 64 << 10);
+ meta_end = RoundUpTo(meta_end, 64 << 10);
+ if (!data_mapped) {
+ // First call maps data+bss.
+ data_mapped = true;
+ MmapFixedNoReserve(meta_begin, meta_end - meta_begin);
+ } else {
+ // Mapping continous heap.
+ // Windows wants 64K alignment.
+ meta_begin = RoundDownTo(meta_begin, 64 << 10);
+ meta_end = RoundUpTo(meta_end, 64 << 10);
+ if (meta_end <= mapped_meta_end)
+ return;
+ if (meta_begin < mapped_meta_end)
+ meta_begin = mapped_meta_end;
+ MmapFixedNoReserve(meta_begin, meta_end - meta_begin);
+ mapped_meta_end = meta_end;
+ }
+ VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n",
+ addr, addr+size, meta_begin, meta_end);
+}
+
+void MapThreadTrace(uptr addr, uptr size) {
+ DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
+ CHECK_GE(addr, kTraceMemBeg);
+ CHECK_LE(addr + size, kTraceMemEnd);
+ CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
+ uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
+ if (addr1 != addr) {
+ Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n",
+ addr, size, addr1);
+ Die();
+ }
+}
+
+static void CheckShadowMapping() {
+ for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) {
+ const uptr beg = UserRegions[i];
+ const uptr end = UserRegions[i + 1];
+ VPrintf(3, "checking shadow region %p-%p\n", beg, end);
+ for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
+ for (int x = -1; x <= 1; x++) {
+ const uptr p = p0 + x;
+ if (p < beg || p >= end)
+ continue;
+ const uptr s = MemToShadow(p);
+ const uptr m = (uptr)MemToMeta(p);
+ VPrintf(3, " checking pointer %p: shadow=%p meta=%p\n", p, s, m);
+ CHECK(IsAppMem(p));
+ CHECK(IsShadowMem(s));
+ CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s));
+ CHECK(IsMetaMem(m));
+ }
+ }
+ }
+}
+
+void Initialize(ThreadState *thr) {
+ // Thread safe because done before all threads exist.
+ static bool is_initialized = false;
+ if (is_initialized)
+ return;
+ is_initialized = true;
+ // We are not ready to handle interceptors yet.
+ ScopedIgnoreInterceptors ignore;
+ SanitizerToolName = "ThreadSanitizer";
+ // Install tool-specific callbacks in sanitizer_common.
+ SetCheckFailedCallback(TsanCheckFailed);
+
+ ctx = new(ctx_placeholder) Context;
+ const char *options = GetEnv(kTsanOptionsEnv);
+ InitializeFlags(&ctx->flags, options);
+#ifndef SANITIZER_GO
+ InitializeAllocator();
+#endif
+ InitializeInterceptors();
+ CheckShadowMapping();
+ InitializePlatform();
+ InitializeMutex();
+ InitializeDynamicAnnotations();
+#ifndef SANITIZER_GO
+ InitializeShadowMemory();
+#endif
+ // Setup correct file descriptor for error reports.
+ __sanitizer_set_report_path(common_flags()->log_path);
+ InitializeSuppressions();
+#ifndef SANITIZER_GO
+ InitializeLibIgnore();
+ Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+ // On MIPS, TSan initialization is run before
+ // __pthread_initialize_minimal_internal() is finished, so we can not spawn
+ // new threads.
+#ifndef __mips__
+ StartBackgroundThread();
+ SetSandboxingCallback(StopBackgroundThread);
+#endif
+#endif
+ if (common_flags()->detect_deadlocks)
+ ctx->dd = DDetector::Create(flags());
+
+ VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n",
+ (int)internal_getpid());
+
+ // Initialize thread 0.
+ int tid = ThreadCreate(thr, 0, 0, true);
+ CHECK_EQ(tid, 0);
+ ThreadStart(thr, tid, internal_getpid());
+ ctx->initialized = true;
+
+ if (flags()->stop_on_start) {
+ Printf("ThreadSanitizer is suspended at startup (pid %d)."
+ " Call __tsan_resume().\n",
+ (int)internal_getpid());
+ while (__tsan_resumed == 0) {}
+ }
+
+ OnInitialize();
+}
+
+int Finalize(ThreadState *thr) {
+ bool failed = false;
+
+ if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
+ SleepForMillis(flags()->atexit_sleep_ms);
+
+ // Wait for pending reports.
+ ctx->report_mtx.Lock();
+ CommonSanitizerReportMutex.Lock();
+ CommonSanitizerReportMutex.Unlock();
+ ctx->report_mtx.Unlock();
+
+#ifndef SANITIZER_GO
+ if (Verbosity()) AllocatorPrintStats();
+#endif
+
+ ThreadFinalize(thr);
+
+ if (ctx->nreported) {
+ failed = true;
+#ifndef SANITIZER_GO
+ Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
+#else
+ Printf("Found %d data race(s)\n", ctx->nreported);
+#endif
+ }
+
+ if (ctx->nmissed_expected) {
+ failed = true;
+ Printf("ThreadSanitizer: missed %d expected races\n",
+ ctx->nmissed_expected);
+ }
+
+ if (common_flags()->print_suppressions)
+ PrintMatchedSuppressions();
+#ifndef SANITIZER_GO
+ if (flags()->print_benign)
+ PrintMatchedBenignRaces();
+#endif
+
+ failed = OnFinalize(failed);
+
+#if TSAN_COLLECT_STATS
+ StatAggregate(ctx->stat, thr->stat);
+ StatOutput(ctx->stat);
+#endif
+
+ return failed ? flags()->exitcode : 0;
+}
+
+#ifndef SANITIZER_GO
+void ForkBefore(ThreadState *thr, uptr pc) {
+ ctx->thread_registry->Lock();
+ ctx->report_mtx.Lock();
+}
+
+void ForkParentAfter(ThreadState *thr, uptr pc) {
+ ctx->report_mtx.Unlock();
+ ctx->thread_registry->Unlock();
+}
+
+void ForkChildAfter(ThreadState *thr, uptr pc) {
+ ctx->report_mtx.Unlock();
+ ctx->thread_registry->Unlock();
+
+ uptr nthread = 0;
+ ctx->thread_registry->GetNumberOfThreads(0, 0, &nthread /* alive threads */);
+ VPrintf(1, "ThreadSanitizer: forked new process with pid %d,"
+ " parent had %d threads\n", (int)internal_getpid(), (int)nthread);
+ if (nthread == 1) {
+ StartBackgroundThread();
+ } else {
+ // We've just forked a multi-threaded process. We cannot reasonably function
+ // after that (some mutexes may be locked before fork). So just enable
+ // ignores for everything in the hope that we will exec soon.
+ ctx->after_multithreaded_fork = true;
+ thr->ignore_interceptors++;
+ ThreadIgnoreBegin(thr, pc);
+ ThreadIgnoreSyncBegin(thr, pc);
+ }
+}
+#endif
+
+#ifdef SANITIZER_GO
+NOINLINE
+void GrowShadowStack(ThreadState *thr) {
+ const int sz = thr->shadow_stack_end - thr->shadow_stack;
+ const int newsz = 2 * sz;
+ uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
+ newsz * sizeof(uptr));
+ internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
+ internal_free(thr->shadow_stack);
+ thr->shadow_stack = newstack;
+ thr->shadow_stack_pos = newstack + sz;
+ thr->shadow_stack_end = newstack + newsz;
+}
+#endif
+
+u32 CurrentStackId(ThreadState *thr, uptr pc) {
+ if (thr->shadow_stack_pos == 0) // May happen during bootstrap.
+ return 0;
+ if (pc != 0) {
+#ifndef SANITIZER_GO
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
+#else
+ if (thr->shadow_stack_pos == thr->shadow_stack_end)
+ GrowShadowStack(thr);
+#endif
+ thr->shadow_stack_pos[0] = pc;
+ thr->shadow_stack_pos++;
+ }
+ u32 id = StackDepotPut(
+ StackTrace(thr->shadow_stack, thr->shadow_stack_pos - thr->shadow_stack));
+ if (pc != 0)
+ thr->shadow_stack_pos--;
+ return id;
+}
+
+void TraceSwitch(ThreadState *thr) {
+ thr->nomalloc++;
+ Trace *thr_trace = ThreadTrace(thr->tid);
+ Lock l(&thr_trace->mtx);
+ unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
+ TraceHeader *hdr = &thr_trace->headers[trace];
+ hdr->epoch0 = thr->fast_state.epoch();
+ ObtainCurrentStack(thr, 0, &hdr->stack0);
+ hdr->mset0 = thr->mset;
+ thr->nomalloc--;
+}
+
+Trace *ThreadTrace(int tid) {
+ return (Trace*)GetThreadTraceHeader(tid);
+}
+
+uptr TraceTopPC(ThreadState *thr) {
+ Event *events = (Event*)GetThreadTrace(thr->tid);
+ uptr pc = events[thr->fast_state.GetTracePos()];
+ return pc;
+}
+
+uptr TraceSize() {
+ return (uptr)(1ull << (kTracePartSizeBits + flags()->history_size + 1));
+}
+
+uptr TraceParts() {
+ return TraceSize() / kTracePartSize;
+}
+
+#ifndef SANITIZER_GO
+extern "C" void __tsan_trace_switch() {
+ TraceSwitch(cur_thread());
+}
+
+extern "C" void __tsan_report_race() {
+ ReportRace(cur_thread());
+}
+#endif
+
+ALWAYS_INLINE
+Shadow LoadShadow(u64 *p) {
+ u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed);
+ return Shadow(raw);
+}
+
+ALWAYS_INLINE
+void StoreShadow(u64 *sp, u64 s) {
+ atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed);
+}
+
+ALWAYS_INLINE
+void StoreIfNotYetStored(u64 *sp, u64 *s) {
+ StoreShadow(sp, *s);
+ *s = 0;
+}
+
+ALWAYS_INLINE
+void HandleRace(ThreadState *thr, u64 *shadow_mem,
+ Shadow cur, Shadow old) {
+ thr->racy_state[0] = cur.raw();
+ thr->racy_state[1] = old.raw();
+ thr->racy_shadow_addr = shadow_mem;
+#ifndef SANITIZER_GO
+ HACKY_CALL(__tsan_report_race);
+#else
+ ReportRace(thr);
+#endif
+}
+
+static inline bool HappensBefore(Shadow old, ThreadState *thr) {
+ return thr->clock.get(old.TidWithIgnore()) >= old.epoch();
+}
+
+ALWAYS_INLINE
+void MemoryAccessImpl1(ThreadState *thr, uptr addr,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
+ u64 *shadow_mem, Shadow cur) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+
+ // This potentially can live in an MMX/SSE scratch register.
+ // The required intrinsics are:
+ // __m128i _mm_move_epi64(__m128i*);
+ // _mm_storel_epi64(u64*, __m128i);
+ u64 store_word = cur.raw();
+
+ // scan all the shadow values and dispatch to 4 categories:
+ // same, replace, candidate and race (see comments below).
+ // we consider only 3 cases regarding access sizes:
+ // equal, intersect and not intersect. initially I considered
+ // larger and smaller as well, it allowed to replace some
+ // 'candidates' with 'same' or 'replace', but I think
+ // it's just not worth it (performance- and complexity-wise).
+
+ Shadow old(0);
+
+ // It release mode we manually unroll the loop,
+ // because empirically gcc generates better code this way.
+ // However, we can't afford unrolling in debug mode, because the function
+ // consumes almost 4K of stack. Gtest gives only 4K of stack to death test
+ // threads, which is not enough for the unrolled loop.
+#if SANITIZER_DEBUG
+ for (int idx = 0; idx < 4; idx++) {
+#include "tsan_update_shadow_word_inl.h"
+ }
+#else
+ int idx = 0;
+#include "tsan_update_shadow_word_inl.h"
+ idx = 1;
+#include "tsan_update_shadow_word_inl.h"
+ idx = 2;
+#include "tsan_update_shadow_word_inl.h"
+ idx = 3;
+#include "tsan_update_shadow_word_inl.h"
+#endif
+
+ // we did not find any races and had already stored
+ // the current access info, so we are done
+ if (LIKELY(store_word == 0))
+ return;
+ // choose a random candidate slot and replace it
+ StoreShadow(shadow_mem + (cur.epoch() % kShadowCnt), store_word);
+ StatInc(thr, StatShadowReplace);
+ return;
+ RACE:
+ HandleRace(thr, shadow_mem, cur, old);
+ return;
+}
+
+void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+ int size, bool kAccessIsWrite, bool kIsAtomic) {
+ while (size) {
+ int size1 = 1;
+ int kAccessSizeLog = kSizeLog1;
+ if (size >= 8 && (addr & ~7) == ((addr + 7) & ~7)) {
+ size1 = 8;
+ kAccessSizeLog = kSizeLog8;
+ } else if (size >= 4 && (addr & ~7) == ((addr + 3) & ~7)) {
+ size1 = 4;
+ kAccessSizeLog = kSizeLog4;
+ } else if (size >= 2 && (addr & ~7) == ((addr + 1) & ~7)) {
+ size1 = 2;
+ kAccessSizeLog = kSizeLog2;
+ }
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic);
+ addr += size1;
+ size -= size1;
+ }
+}
+
+ALWAYS_INLINE
+bool ContainsSameAccessSlow(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
+ Shadow cur(a);
+ for (uptr i = 0; i < kShadowCnt; i++) {
+ Shadow old(LoadShadow(&s[i]));
+ if (Shadow::Addr0AndSizeAreEqual(cur, old) &&
+ old.TidWithIgnore() == cur.TidWithIgnore() &&
+ old.epoch() > sync_epoch &&
+ old.IsAtomic() == cur.IsAtomic() &&
+ old.IsRead() <= cur.IsRead())
+ return true;
+ }
+ return false;
+}
+
+#if defined(__SSE3__)
+#define SHUF(v0, v1, i0, i1, i2, i3) _mm_castps_si128(_mm_shuffle_ps( \
+ _mm_castsi128_ps(v0), _mm_castsi128_ps(v1), \
+ (i0)*1 + (i1)*4 + (i2)*16 + (i3)*64))
+ALWAYS_INLINE
+bool ContainsSameAccessFast(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
+ // This is an optimized version of ContainsSameAccessSlow.
+ // load current access into access[0:63]
+ const m128 access = _mm_cvtsi64_si128(a);
+ // duplicate high part of access in addr0:
+ // addr0[0:31] = access[32:63]
+ // addr0[32:63] = access[32:63]
+ // addr0[64:95] = access[32:63]
+ // addr0[96:127] = access[32:63]
+ const m128 addr0 = SHUF(access, access, 1, 1, 1, 1);
+ // load 4 shadow slots
+ const m128 shadow0 = _mm_load_si128((__m128i*)s);
+ const m128 shadow1 = _mm_load_si128((__m128i*)s + 1);
+ // load high parts of 4 shadow slots into addr_vect:
+ // addr_vect[0:31] = shadow0[32:63]
+ // addr_vect[32:63] = shadow0[96:127]
+ // addr_vect[64:95] = shadow1[32:63]
+ // addr_vect[96:127] = shadow1[96:127]
+ m128 addr_vect = SHUF(shadow0, shadow1, 1, 3, 1, 3);
+ if (!is_write) {
+ // set IsRead bit in addr_vect
+ const m128 rw_mask1 = _mm_cvtsi64_si128(1<<15);
+ const m128 rw_mask = SHUF(rw_mask1, rw_mask1, 0, 0, 0, 0);
+ addr_vect = _mm_or_si128(addr_vect, rw_mask);
+ }
+ // addr0 == addr_vect?
+ const m128 addr_res = _mm_cmpeq_epi32(addr0, addr_vect);
+ // epoch1[0:63] = sync_epoch
+ const m128 epoch1 = _mm_cvtsi64_si128(sync_epoch);
+ // epoch[0:31] = sync_epoch[0:31]
+ // epoch[32:63] = sync_epoch[0:31]
+ // epoch[64:95] = sync_epoch[0:31]
+ // epoch[96:127] = sync_epoch[0:31]
+ const m128 epoch = SHUF(epoch1, epoch1, 0, 0, 0, 0);
+ // load low parts of shadow cell epochs into epoch_vect:
+ // epoch_vect[0:31] = shadow0[0:31]
+ // epoch_vect[32:63] = shadow0[64:95]
+ // epoch_vect[64:95] = shadow1[0:31]
+ // epoch_vect[96:127] = shadow1[64:95]
+ const m128 epoch_vect = SHUF(shadow0, shadow1, 0, 2, 0, 2);
+ // epoch_vect >= sync_epoch?
+ const m128 epoch_res = _mm_cmpgt_epi32(epoch_vect, epoch);
+ // addr_res & epoch_res
+ const m128 res = _mm_and_si128(addr_res, epoch_res);
+ // mask[0] = res[7]
+ // mask[1] = res[15]
+ // ...
+ // mask[15] = res[127]
+ const int mask = _mm_movemask_epi8(res);
+ return mask != 0;
+}
+#endif
+
+ALWAYS_INLINE
+bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
+#if defined(__SSE3__)
+ bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write);
+ // NOTE: this check can fail if the shadow is concurrently mutated
+ // by other threads. But it still can be useful if you modify
+ // ContainsSameAccessFast and want to ensure that it's not completely broken.
+ // DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write));
+ return res;
+#else
+ return ContainsSameAccessSlow(s, a, sync_epoch, is_write);
+#endif
+}
+
+ALWAYS_INLINE USED
+void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
+ u64 *shadow_mem = (u64*)MemToShadow(addr);
+ DPrintf2("#%d: MemoryAccess: @%p %p size=%d"
+ " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
+ (int)thr->fast_state.tid(), (void*)pc, (void*)addr,
+ (int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem,
+ (uptr)shadow_mem[0], (uptr)shadow_mem[1],
+ (uptr)shadow_mem[2], (uptr)shadow_mem[3]);
+#if SANITIZER_DEBUG
+ if (!IsAppMem(addr)) {
+ Printf("Access to non app mem %zx\n", addr);
+ DCHECK(IsAppMem(addr));
+ }
+ if (!IsShadowMem((uptr)shadow_mem)) {
+ Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
+ DCHECK(IsShadowMem((uptr)shadow_mem));
+ }
+#endif
+
+ if (kCppMode && *shadow_mem == kShadowRodata) {
+ // Access to .rodata section, no races here.
+ // Measurements show that it can be 10-20% of all memory accesses.
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopRodata);
+ return;
+ }
+
+ FastState fast_state = thr->fast_state;
+ if (fast_state.GetIgnoreBit()) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopIgnored);
+ return;
+ }
+
+ Shadow cur(fast_state);
+ cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
+ cur.SetWrite(kAccessIsWrite);
+ cur.SetAtomic(kIsAtomic);
+
+ if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(),
+ thr->fast_synch_epoch, kAccessIsWrite))) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopSame);
+ return;
+ }
+
+ if (kCollectHistory) {
+ fast_state.IncrementEpoch();
+ thr->fast_state = fast_state;
+ TraceAddEvent(thr, fast_state, EventTypeMop, pc);
+ cur.IncrementEpoch();
+ }
+
+ MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
+ shadow_mem, cur);
+}
+
+// Called by MemoryAccessRange in tsan_rtl_thread.cc
+ALWAYS_INLINE USED
+void MemoryAccessImpl(ThreadState *thr, uptr addr,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
+ u64 *shadow_mem, Shadow cur) {
+ if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(),
+ thr->fast_synch_epoch, kAccessIsWrite))) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopSame);
+ return;
+ }
+
+ MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
+ shadow_mem, cur);
+}
+
+static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
+ u64 val) {
+ (void)thr;
+ (void)pc;
+ if (size == 0)
+ return;
+ // FIXME: fix me.
+ uptr offset = addr % kShadowCell;
+ if (offset) {
+ offset = kShadowCell - offset;
+ if (size <= offset)
+ return;
+ addr += offset;
+ size -= offset;
+ }
+ DCHECK_EQ(addr % 8, 0);
+ // If a user passes some insane arguments (memset(0)),
+ // let it just crash as usual.
+ if (!IsAppMem(addr) || !IsAppMem(addr + size - 1))
+ return;
+ // Don't want to touch lots of shadow memory.
+ // If a program maps 10MB stack, there is no need reset the whole range.
+ size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
+ // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
+ // so we do it only for C/C++.
+ if (kGoMode || size < common_flags()->clear_shadow_mmap_threshold) {
+ u64 *p = (u64*)MemToShadow(addr);
+ CHECK(IsShadowMem((uptr)p));
+ CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
+ // FIXME: may overwrite a part outside the region
+ for (uptr i = 0; i < size / kShadowCell * kShadowCnt;) {
+ p[i++] = val;
+ for (uptr j = 1; j < kShadowCnt; j++)
+ p[i++] = 0;
+ }
+ } else {
+ // The region is big, reset only beginning and end.
+ const uptr kPageSize = GetPageSizeCached();
+ u64 *begin = (u64*)MemToShadow(addr);
+ u64 *end = begin + size / kShadowCell * kShadowCnt;
+ u64 *p = begin;
+ // Set at least first kPageSize/2 to page boundary.
+ while ((p < begin + kPageSize / kShadowSize / 2) || ((uptr)p % kPageSize)) {
+ *p++ = val;
+ for (uptr j = 1; j < kShadowCnt; j++)
+ *p++ = 0;
+ }
+ // Reset middle part.
+ u64 *p1 = p;
+ p = RoundDown(end, kPageSize);
+ UnmapOrDie((void*)p1, (uptr)p - (uptr)p1);
+ MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1);
+ // Set the ending.
+ while (p < end) {
+ *p++ = val;
+ for (uptr j = 1; j < kShadowCnt; j++)
+ *p++ = 0;
+ }
+ }
+}
+
+void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+ MemoryRangeSet(thr, pc, addr, size, 0);
+}
+
+void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+ // Processing more than 1k (4k of shadow) is expensive,
+ // can cause excessive memory consumption (user does not necessary touch
+ // the whole range) and most likely unnecessary.
+ if (size > 1024)
+ size = 1024;
+ CHECK_EQ(thr->is_freeing, false);
+ thr->is_freeing = true;
+ MemoryAccessRange(thr, pc, addr, size, true);
+ thr->is_freeing = false;
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
+ }
+ Shadow s(thr->fast_state);
+ s.ClearIgnoreBit();
+ s.MarkAsFreed();
+ s.SetWrite(true);
+ s.SetAddr0AndSizeLog(0, 3);
+ MemoryRangeSet(thr, pc, addr, size, s.raw());
+}
+
+void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
+ }
+ Shadow s(thr->fast_state);
+ s.ClearIgnoreBit();
+ s.SetWrite(true);
+ s.SetAddr0AndSizeLog(0, 3);
+ MemoryRangeSet(thr, pc, addr, size, s.raw());
+}
+
+ALWAYS_INLINE USED
+void FuncEntry(ThreadState *thr, uptr pc) {
+ StatInc(thr, StatFuncEnter);
+ DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc);
+ }
+
+ // Shadow stack maintenance can be replaced with
+ // stack unwinding during trace switch (which presumably must be faster).
+ DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
+#ifndef SANITIZER_GO
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
+#else
+ if (thr->shadow_stack_pos == thr->shadow_stack_end)
+ GrowShadowStack(thr);
+#endif
+ thr->shadow_stack_pos[0] = pc;
+ thr->shadow_stack_pos++;
+}
+
+ALWAYS_INLINE USED
+void FuncExit(ThreadState *thr) {
+ StatInc(thr, StatFuncExit);
+ DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
+ }
+
+ DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
+#ifndef SANITIZER_GO
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
+#endif
+ thr->shadow_stack_pos--;
+}
+
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid);
+ thr->ignore_reads_and_writes++;
+ CHECK_GT(thr->ignore_reads_and_writes, 0);
+ thr->fast_state.SetIgnoreBit();
+#ifndef SANITIZER_GO
+ if (!ctx->after_multithreaded_fork)
+ thr->mop_ignore_set.Add(CurrentStackId(thr, pc));
+#endif
+}
+
+void ThreadIgnoreEnd(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid);
+ thr->ignore_reads_and_writes--;
+ CHECK_GE(thr->ignore_reads_and_writes, 0);
+ if (thr->ignore_reads_and_writes == 0) {
+ thr->fast_state.ClearIgnoreBit();
+#ifndef SANITIZER_GO
+ thr->mop_ignore_set.Reset();
+#endif
+ }
+}
+
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid);
+ thr->ignore_sync++;
+ CHECK_GT(thr->ignore_sync, 0);
+#ifndef SANITIZER_GO
+ if (!ctx->after_multithreaded_fork)
+ thr->sync_ignore_set.Add(CurrentStackId(thr, pc));
+#endif
+}
+
+void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid);
+ thr->ignore_sync--;
+ CHECK_GE(thr->ignore_sync, 0);
+#ifndef SANITIZER_GO
+ if (thr->ignore_sync == 0)
+ thr->sync_ignore_set.Reset();
+#endif
+}
+
+bool MD5Hash::operator==(const MD5Hash &other) const {
+ return hash[0] == other.hash[0] && hash[1] == other.hash[1];
+}
+
+#if SANITIZER_DEBUG
+void build_consistency_debug() {}
+#else
+void build_consistency_release() {}
+#endif
+
+#if TSAN_COLLECT_STATS
+void build_consistency_stats() {}
+#else
+void build_consistency_nostats() {}
+#endif
+
+} // namespace __tsan
+
+#ifndef SANITIZER_GO
+// Must be included in this file to make sure everything is inlined.
+#include "tsan_interface_inl.h"
+#endif
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h
new file mode 100644
index 000000000000..7a60e5c55af4
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -0,0 +1,766 @@
+//===-- tsan_rtl.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 ThreadSanitizer (TSan), a race detector.
+//
+// Main internal TSan header file.
+//
+// Ground rules:
+// - C++ run-time should not be used (static CTORs, RTTI, exceptions, static
+// function-scope locals)
+// - All functions/classes/etc reside in namespace __tsan, except for those
+// declared in tsan_interface.h.
+// - Platform-specific files should be used instead of ifdefs (*).
+// - No system headers included in header files (*).
+// - Platform specific headres included only into platform-specific files (*).
+//
+// (*) Except when inlining is critical for performance.
+//===----------------------------------------------------------------------===//
+
+#ifndef TSAN_RTL_H
+#define TSAN_RTL_H
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_asm.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common/sanitizer_libignore.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+#include "tsan_clock.h"
+#include "tsan_defs.h"
+#include "tsan_flags.h"
+#include "tsan_sync.h"
+#include "tsan_trace.h"
+#include "tsan_vector.h"
+#include "tsan_report.h"
+#include "tsan_platform.h"
+#include "tsan_mutexset.h"
+#include "tsan_ignoreset.h"
+#include "tsan_stack_trace.h"
+
+#if SANITIZER_WORDSIZE != 64
+# error "ThreadSanitizer is supported only on 64-bit platforms"
+#endif
+
+namespace __tsan {
+
+#ifndef SANITIZER_GO
+struct MapUnmapCallback;
+#ifdef __mips64
+static const uptr kAllocatorSpace = 0;
+static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
+static const uptr kAllocatorRegionSizeLog = 20;
+static const uptr kAllocatorNumRegions =
+ kAllocatorSize >> kAllocatorRegionSizeLog;
+typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12,
+ MapUnmapCallback> ByteMap;
+typedef SizeClassAllocator32<kAllocatorSpace, kAllocatorSize, 0,
+ CompactSizeClassMap, kAllocatorRegionSizeLog, ByteMap,
+ MapUnmapCallback> PrimaryAllocator;
+#else
+typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0,
+ DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
+#endif
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+Allocator *allocator();
+#endif
+
+void TsanCheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2);
+
+const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
+
+// FastState (from most significant bit):
+// ignore : 1
+// tid : kTidBits
+// unused : -
+// history_size : 3
+// epoch : kClkBits
+class FastState {
+ public:
+ FastState(u64 tid, u64 epoch) {
+ x_ = tid << kTidShift;
+ x_ |= epoch;
+ DCHECK_EQ(tid, this->tid());
+ DCHECK_EQ(epoch, this->epoch());
+ DCHECK_EQ(GetIgnoreBit(), false);
+ }
+
+ explicit FastState(u64 x)
+ : x_(x) {
+ }
+
+ u64 raw() const {
+ return x_;
+ }
+
+ u64 tid() const {
+ u64 res = (x_ & ~kIgnoreBit) >> kTidShift;
+ return res;
+ }
+
+ u64 TidWithIgnore() const {
+ u64 res = x_ >> kTidShift;
+ return res;
+ }
+
+ u64 epoch() const {
+ u64 res = x_ & ((1ull << kClkBits) - 1);
+ return res;
+ }
+
+ void IncrementEpoch() {
+ u64 old_epoch = epoch();
+ x_ += 1;
+ DCHECK_EQ(old_epoch + 1, epoch());
+ (void)old_epoch;
+ }
+
+ void SetIgnoreBit() { x_ |= kIgnoreBit; }
+ void ClearIgnoreBit() { x_ &= ~kIgnoreBit; }
+ bool GetIgnoreBit() const { return (s64)x_ < 0; }
+
+ void SetHistorySize(int hs) {
+ CHECK_GE(hs, 0);
+ CHECK_LE(hs, 7);
+ x_ = (x_ & ~(kHistoryMask << kHistoryShift)) | (u64(hs) << kHistoryShift);
+ }
+
+ ALWAYS_INLINE
+ int GetHistorySize() const {
+ return (int)((x_ >> kHistoryShift) & kHistoryMask);
+ }
+
+ void ClearHistorySize() {
+ SetHistorySize(0);
+ }
+
+ ALWAYS_INLINE
+ u64 GetTracePos() const {
+ const int hs = GetHistorySize();
+ // When hs == 0, the trace consists of 2 parts.
+ const u64 mask = (1ull << (kTracePartSizeBits + hs + 1)) - 1;
+ return epoch() & mask;
+ }
+
+ private:
+ friend class Shadow;
+ static const int kTidShift = 64 - kTidBits - 1;
+ static const u64 kIgnoreBit = 1ull << 63;
+ static const u64 kFreedBit = 1ull << 63;
+ static const u64 kHistoryShift = kClkBits;
+ static const u64 kHistoryMask = 7;
+ u64 x_;
+};
+
+// Shadow (from most significant bit):
+// freed : 1
+// tid : kTidBits
+// is_atomic : 1
+// is_read : 1
+// size_log : 2
+// addr0 : 3
+// epoch : kClkBits
+class Shadow : public FastState {
+ public:
+ explicit Shadow(u64 x)
+ : FastState(x) {
+ }
+
+ explicit Shadow(const FastState &s)
+ : FastState(s.x_) {
+ ClearHistorySize();
+ }
+
+ void SetAddr0AndSizeLog(u64 addr0, unsigned kAccessSizeLog) {
+ DCHECK_EQ((x_ >> kClkBits) & 31, 0);
+ DCHECK_LE(addr0, 7);
+ DCHECK_LE(kAccessSizeLog, 3);
+ x_ |= ((kAccessSizeLog << 3) | addr0) << kClkBits;
+ DCHECK_EQ(kAccessSizeLog, size_log());
+ DCHECK_EQ(addr0, this->addr0());
+ }
+
+ void SetWrite(unsigned kAccessIsWrite) {
+ DCHECK_EQ(x_ & kReadBit, 0);
+ if (!kAccessIsWrite)
+ x_ |= kReadBit;
+ DCHECK_EQ(kAccessIsWrite, IsWrite());
+ }
+
+ void SetAtomic(bool kIsAtomic) {
+ DCHECK(!IsAtomic());
+ if (kIsAtomic)
+ x_ |= kAtomicBit;
+ DCHECK_EQ(IsAtomic(), kIsAtomic);
+ }
+
+ bool IsAtomic() const {
+ return x_ & kAtomicBit;
+ }
+
+ bool IsZero() const {
+ return x_ == 0;
+ }
+
+ static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) {
+ u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
+ DCHECK_EQ(shifted_xor == 0, s1.TidWithIgnore() == s2.TidWithIgnore());
+ return shifted_xor == 0;
+ }
+
+ static ALWAYS_INLINE
+ bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) {
+ u64 masked_xor = ((s1.x_ ^ s2.x_) >> kClkBits) & 31;
+ return masked_xor == 0;
+ }
+
+ static ALWAYS_INLINE bool TwoRangesIntersect(Shadow s1, Shadow s2,
+ unsigned kS2AccessSize) {
+ bool res = false;
+ u64 diff = s1.addr0() - s2.addr0();
+ if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // NOLINT
+ // if (s1.addr0() + size1) > s2.addr0()) return true;
+ if (s1.size() > -diff)
+ res = true;
+ } else {
+ // if (s2.addr0() + kS2AccessSize > s1.addr0()) return true;
+ if (kS2AccessSize > diff)
+ res = true;
+ }
+ DCHECK_EQ(res, TwoRangesIntersectSlow(s1, s2));
+ DCHECK_EQ(res, TwoRangesIntersectSlow(s2, s1));
+ return res;
+ }
+
+ u64 ALWAYS_INLINE addr0() const { return (x_ >> kClkBits) & 7; }
+ u64 ALWAYS_INLINE size() const { return 1ull << size_log(); }
+ bool ALWAYS_INLINE IsWrite() const { return !IsRead(); }
+ bool ALWAYS_INLINE IsRead() const { return x_ & kReadBit; }
+
+ // The idea behind the freed bit is as follows.
+ // When the memory is freed (or otherwise unaccessible) we write to the shadow
+ // values with tid/epoch related to the free and the freed bit set.
+ // During memory accesses processing the freed bit is considered
+ // as msb of tid. So any access races with shadow with freed bit set
+ // (it is as if write from a thread with which we never synchronized before).
+ // This allows us to detect accesses to freed memory w/o additional
+ // overheads in memory access processing and at the same time restore
+ // tid/epoch of free.
+ void MarkAsFreed() {
+ x_ |= kFreedBit;
+ }
+
+ bool IsFreed() const {
+ return x_ & kFreedBit;
+ }
+
+ bool GetFreedAndReset() {
+ bool res = x_ & kFreedBit;
+ x_ &= ~kFreedBit;
+ return res;
+ }
+
+ bool ALWAYS_INLINE IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
+ bool v = x_ & ((u64(kIsWrite ^ 1) << kReadShift)
+ | (u64(kIsAtomic) << kAtomicShift));
+ DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic));
+ return v;
+ }
+
+ bool ALWAYS_INLINE IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
+ bool v = ((x_ >> kReadShift) & 3)
+ <= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+ DCHECK_EQ(v, (IsAtomic() < kIsAtomic) ||
+ (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite));
+ return v;
+ }
+
+ bool ALWAYS_INLINE IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
+ bool v = ((x_ >> kReadShift) & 3)
+ >= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+ DCHECK_EQ(v, (IsAtomic() > kIsAtomic) ||
+ (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite));
+ return v;
+ }
+
+ private:
+ static const u64 kReadShift = 5 + kClkBits;
+ static const u64 kReadBit = 1ull << kReadShift;
+ static const u64 kAtomicShift = 6 + kClkBits;
+ static const u64 kAtomicBit = 1ull << kAtomicShift;
+
+ u64 size_log() const { return (x_ >> (3 + kClkBits)) & 3; }
+
+ static bool TwoRangesIntersectSlow(const Shadow s1, const Shadow s2) {
+ if (s1.addr0() == s2.addr0()) return true;
+ if (s1.addr0() < s2.addr0() && s1.addr0() + s1.size() > s2.addr0())
+ return true;
+ if (s2.addr0() < s1.addr0() && s2.addr0() + s2.size() > s1.addr0())
+ return true;
+ return false;
+ }
+};
+
+struct SignalContext;
+
+struct JmpBuf {
+ uptr sp;
+ uptr mangled_sp;
+ int int_signal_send;
+ bool in_blocking_func;
+ uptr in_signal_handler;
+ uptr *shadow_stack_pos;
+};
+
+// This struct is stored in TLS.
+struct ThreadState {
+ FastState fast_state;
+ // Synch epoch represents the threads's epoch before the last synchronization
+ // action. It allows to reduce number of shadow state updates.
+ // For example, fast_synch_epoch=100, last write to addr X was at epoch=150,
+ // if we are processing write to X from the same thread at epoch=200,
+ // we do nothing, because both writes happen in the same 'synch epoch'.
+ // That is, if another memory access does not race with the former write,
+ // it does not race with the latter as well.
+ // QUESTION: can we can squeeze this into ThreadState::Fast?
+ // E.g. ThreadState::Fast is a 44-bit, 32 are taken by synch_epoch and 12 are
+ // taken by epoch between synchs.
+ // This way we can save one load from tls.
+ u64 fast_synch_epoch;
+ // This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read.
+ // We do not distinguish beteween ignoring reads and writes
+ // for better performance.
+ int ignore_reads_and_writes;
+ int ignore_sync;
+ // Go does not support ignores.
+#ifndef SANITIZER_GO
+ IgnoreSet mop_ignore_set;
+ IgnoreSet sync_ignore_set;
+#endif
+ // C/C++ uses fixed size shadow stack embed into Trace.
+ // Go uses malloc-allocated shadow stack with dynamic size.
+ uptr *shadow_stack;
+ uptr *shadow_stack_end;
+ uptr *shadow_stack_pos;
+ u64 *racy_shadow_addr;
+ u64 racy_state[2];
+ MutexSet mset;
+ ThreadClock clock;
+#ifndef SANITIZER_GO
+ AllocatorCache alloc_cache;
+ InternalAllocatorCache internal_alloc_cache;
+ Vector<JmpBuf> jmp_bufs;
+ int ignore_interceptors;
+#endif
+#if TSAN_COLLECT_STATS
+ u64 stat[StatCnt];
+#endif
+ const int tid;
+ const int unique_id;
+ bool in_symbolizer;
+ bool in_ignored_lib;
+ bool is_dead;
+ bool is_freeing;
+ bool is_vptr_access;
+ const uptr stk_addr;
+ const uptr stk_size;
+ const uptr tls_addr;
+ const uptr tls_size;
+ ThreadContext *tctx;
+
+#if SANITIZER_DEBUG && !SANITIZER_GO
+ InternalDeadlockDetector internal_deadlock_detector;
+#endif
+ DDPhysicalThread *dd_pt;
+ DDLogicalThread *dd_lt;
+
+ atomic_uintptr_t in_signal_handler;
+ SignalContext *signal_ctx;
+
+ DenseSlabAllocCache block_cache;
+ DenseSlabAllocCache sync_cache;
+ DenseSlabAllocCache clock_cache;
+
+#ifndef SANITIZER_GO
+ u32 last_sleep_stack_id;
+ ThreadClock last_sleep_clock;
+#endif
+
+ // Set in regions of runtime that must be signal-safe and fork-safe.
+ // If set, malloc must not be called.
+ int nomalloc;
+
+ explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
+ unsigned reuse_count,
+ uptr stk_addr, uptr stk_size,
+ uptr tls_addr, uptr tls_size);
+};
+
+#ifndef SANITIZER_GO
+__attribute__((tls_model("initial-exec")))
+extern THREADLOCAL char cur_thread_placeholder[];
+INLINE ThreadState *cur_thread() {
+ return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
+}
+#endif
+
+class ThreadContext : public ThreadContextBase {
+ public:
+ explicit ThreadContext(int tid);
+ ~ThreadContext();
+ ThreadState *thr;
+ u32 creation_stack_id;
+ SyncClock sync;
+ // Epoch at which the thread had started.
+ // If we see an event from the thread stamped by an older epoch,
+ // the event is from a dead thread that shared tid with this thread.
+ u64 epoch0;
+ u64 epoch1;
+
+ // Override superclass callbacks.
+ void OnDead();
+ void OnJoined(void *arg);
+ void OnFinished();
+ void OnStarted(void *arg);
+ void OnCreated(void *arg);
+ void OnReset();
+ void OnDetached(void *arg);
+};
+
+struct RacyStacks {
+ MD5Hash hash[2];
+ bool operator==(const RacyStacks &other) const {
+ if (hash[0] == other.hash[0] && hash[1] == other.hash[1])
+ return true;
+ if (hash[0] == other.hash[1] && hash[1] == other.hash[0])
+ return true;
+ return false;
+ }
+};
+
+struct RacyAddress {
+ uptr addr_min;
+ uptr addr_max;
+};
+
+struct FiredSuppression {
+ ReportType type;
+ uptr pc;
+ Suppression *supp;
+};
+
+struct Context {
+ Context();
+
+ bool initialized;
+ bool after_multithreaded_fork;
+
+ MetaMap metamap;
+
+ Mutex report_mtx;
+ int nreported;
+ int nmissed_expected;
+ atomic_uint64_t last_symbolize_time_ns;
+
+ void *background_thread;
+ atomic_uint32_t stop_background_thread;
+
+ ThreadRegistry *thread_registry;
+
+ Vector<RacyStacks> racy_stacks;
+ Vector<RacyAddress> racy_addresses;
+ // Number of fired suppressions may be large enough.
+ InternalMmapVector<FiredSuppression> fired_suppressions;
+ DDetector *dd;
+
+ ClockAlloc clock_alloc;
+
+ Flags flags;
+
+ u64 stat[StatCnt];
+ u64 int_alloc_cnt[MBlockTypeCount];
+ u64 int_alloc_siz[MBlockTypeCount];
+};
+
+extern Context *ctx; // The one and the only global runtime context.
+
+struct ScopedIgnoreInterceptors {
+ ScopedIgnoreInterceptors() {
+#ifndef SANITIZER_GO
+ cur_thread()->ignore_interceptors++;
+#endif
+ }
+
+ ~ScopedIgnoreInterceptors() {
+#ifndef SANITIZER_GO
+ cur_thread()->ignore_interceptors--;
+#endif
+ }
+};
+
+class ScopedReport {
+ public:
+ explicit ScopedReport(ReportType typ);
+ ~ScopedReport();
+
+ void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+ const MutexSet *mset);
+ void AddStack(StackTrace stack, bool suppressable = false);
+ void AddThread(const ThreadContext *tctx, bool suppressable = false);
+ void AddThread(int unique_tid, bool suppressable = false);
+ void AddUniqueTid(int unique_tid);
+ void AddMutex(const SyncVar *s);
+ u64 AddMutex(u64 id);
+ void AddLocation(uptr addr, uptr size);
+ void AddSleep(u32 stack_id);
+ void SetCount(int count);
+
+ const ReportDesc *GetReport() const;
+
+ private:
+ ReportDesc *rep_;
+ // Symbolizer makes lots of intercepted calls. If we try to process them,
+ // at best it will cause deadlocks on internal mutexes.
+ ScopedIgnoreInterceptors ignore_interceptors_;
+
+ void AddDeadMutex(u64 id);
+
+ ScopedReport(const ScopedReport&);
+ void operator = (const ScopedReport&);
+};
+
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+ MutexSet *mset);
+
+template<typename StackTraceTy>
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+ uptr size = thr->shadow_stack_pos - thr->shadow_stack;
+ uptr start = 0;
+ if (size + !!toppc > kStackTraceMax) {
+ start = size + !!toppc - kStackTraceMax;
+ size = kStackTraceMax - !!toppc;
+ }
+ stack->Init(&thr->shadow_stack[start], size, toppc);
+}
+
+
+#if TSAN_COLLECT_STATS
+void StatAggregate(u64 *dst, u64 *src);
+void StatOutput(u64 *stat);
+#endif
+
+void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
+#if TSAN_COLLECT_STATS
+ thr->stat[typ] += n;
+#endif
+}
+void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) {
+#if TSAN_COLLECT_STATS
+ thr->stat[typ] = n;
+#endif
+}
+
+void MapShadow(uptr addr, uptr size);
+void MapThreadTrace(uptr addr, uptr size);
+void DontNeedShadowFor(uptr addr, uptr size);
+void InitializeShadowMemory();
+void InitializeInterceptors();
+void InitializeLibIgnore();
+void InitializeDynamicAnnotations();
+
+void ForkBefore(ThreadState *thr, uptr pc);
+void ForkParentAfter(ThreadState *thr, uptr pc);
+void ForkChildAfter(ThreadState *thr, uptr pc);
+
+void ReportRace(ThreadState *thr);
+bool OutputReport(ThreadState *thr, const ScopedReport &srep);
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+ StackTrace trace);
+bool IsExpectedReport(uptr addr, uptr size);
+void PrintMatchedBenignRaces();
+
+#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
+# define DPrintf Printf
+#else
+# define DPrintf(...)
+#endif
+
+#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 2
+# define DPrintf2 Printf
+#else
+# define DPrintf2(...)
+#endif
+
+u32 CurrentStackId(ThreadState *thr, uptr pc);
+ReportStack *SymbolizeStackId(u32 stack_id);
+void PrintCurrentStack(ThreadState *thr, uptr pc);
+void PrintCurrentStackSlow(uptr pc); // uses libunwind
+
+void Initialize(ThreadState *thr);
+int Finalize(ThreadState *thr);
+
+void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write);
+void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write);
+
+void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic);
+void MemoryAccessImpl(ThreadState *thr, uptr addr,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
+ u64 *shadow_mem, Shadow cur);
+void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
+ uptr size, bool is_write);
+void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
+ uptr size, uptr step, bool is_write);
+void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+ int size, bool kAccessIsWrite, bool kIsAtomic);
+
+const int kSizeLog1 = 0;
+const int kSizeLog2 = 1;
+const int kSizeLog4 = 2;
+const int kSizeLog8 = 3;
+
+void ALWAYS_INLINE MemoryRead(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
+}
+
+void ALWAYS_INLINE MemoryWrite(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false);
+}
+
+void ALWAYS_INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
+}
+
+void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
+}
+
+void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
+void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
+void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
+
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreEnd(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc);
+
+void FuncEntry(ThreadState *thr, uptr pc);
+void FuncExit(ThreadState *thr);
+
+int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
+void ThreadStart(ThreadState *thr, int tid, uptr os_id);
+void ThreadFinish(ThreadState *thr);
+int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
+void ThreadJoin(ThreadState *thr, uptr pc, int tid);
+void ThreadDetach(ThreadState *thr, uptr pc, int tid);
+void ThreadFinalize(ThreadState *thr);
+void ThreadSetName(ThreadState *thr, const char *name);
+int ThreadCount(ThreadState *thr);
+void ProcessPendingSignals(ThreadState *thr);
+
+void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
+ bool rw, bool recursive, bool linker_init);
+void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1,
+ bool try_lock = false);
+int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
+void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false);
+void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
+void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
+void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
+
+void Acquire(ThreadState *thr, uptr pc, uptr addr);
+// AcquireGlobal synchronizes the current thread with all other threads.
+// In terms of happens-before relation, it draws a HB edge from all threads
+// (where they happen to execute right now) to the current thread. We use it to
+// handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal
+// right before executing finalizers. This provides a coarse, but simple
+// approximation of the actual required synchronization.
+void AcquireGlobal(ThreadState *thr, uptr pc);
+void Release(ThreadState *thr, uptr pc, uptr addr);
+void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
+void AfterSleep(ThreadState *thr, uptr pc);
+void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
+
+// The hacky call uses custom calling convention and an assembly thunk.
+// It is considerably faster that a normal call for the caller
+// if it is not executed (it is intended for slow paths from hot functions).
+// The trick is that the call preserves all registers and the compiler
+// does not treat it as a call.
+// If it does not work for you, use normal call.
+#if !SANITIZER_DEBUG && defined(__x86_64__)
+// The caller may not create the stack frame for itself at all,
+// so we create a reserve stack frame for it (1024b must be enough).
+#define HACKY_CALL(f) \
+ __asm__ __volatile__("sub $1024, %%rsp;" \
+ CFI_INL_ADJUST_CFA_OFFSET(1024) \
+ ".hidden " #f "_thunk;" \
+ "call " #f "_thunk;" \
+ "add $1024, %%rsp;" \
+ CFI_INL_ADJUST_CFA_OFFSET(-1024) \
+ ::: "memory", "cc");
+#else
+#define HACKY_CALL(f) f()
+#endif
+
+void TraceSwitch(ThreadState *thr);
+uptr TraceTopPC(ThreadState *thr);
+uptr TraceSize();
+uptr TraceParts();
+Trace *ThreadTrace(int tid);
+
+extern "C" void __tsan_trace_switch();
+void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
+ EventType typ, u64 addr) {
+ if (!kCollectHistory)
+ return;
+ DCHECK_GE((int)typ, 0);
+ DCHECK_LE((int)typ, 7);
+ DCHECK_EQ(GetLsb(addr, 61), addr);
+ StatInc(thr, StatEvents);
+ u64 pos = fs.GetTracePos();
+ if (UNLIKELY((pos % kTracePartSize) == 0)) {
+#ifndef SANITIZER_GO
+ HACKY_CALL(__tsan_trace_switch);
+#else
+ TraceSwitch(thr);
+#endif
+ }
+ Event *trace = (Event*)GetThreadTrace(fs.tid());
+ Event *evp = &trace[pos];
+ Event ev = (u64)addr | ((u64)typ << 61);
+ *evp = ev;
+}
+
+#ifndef SANITIZER_GO
+uptr ALWAYS_INLINE HeapEnd() {
+#if SANITIZER_CAN_USE_ALLOCATOR64
+ return kHeapMemEnd + PrimaryAllocator::AdditionalSize();
+#else
+ return kHeapMemEnd;
+#endif
+}
+#endif
+
+} // namespace __tsan
+
+#endif // TSAN_RTL_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S
new file mode 100644
index 000000000000..8db62f9013a3
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S
@@ -0,0 +1,324 @@
+#include "sanitizer_common/sanitizer_asm.h"
+.section .text
+
+.hidden __tsan_trace_switch
+.globl __tsan_trace_switch_thunk
+__tsan_trace_switch_thunk:
+ CFI_STARTPROC
+ # Save scratch registers.
+ push %rax
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rax, 0)
+ push %rcx
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rcx, 0)
+ push %rdx
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdx, 0)
+ push %rsi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
+ push %rdi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
+ push %r8
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r8, 0)
+ push %r9
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r9, 0)
+ push %r10
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r10, 0)
+ push %r11
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r11, 0)
+ # Align stack frame.
+ push %rbx # non-scratch
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rbx, 0)
+ mov %rsp, %rbx # save current rsp
+ CFI_DEF_CFA_REGISTER(%rbx)
+ shr $4, %rsp # clear 4 lsb, align to 16
+ shl $4, %rsp
+
+ call __tsan_trace_switch
+
+ # Unalign stack frame back.
+ mov %rbx, %rsp # restore the original rsp
+ CFI_DEF_CFA_REGISTER(%rsp)
+ pop %rbx
+ CFI_ADJUST_CFA_OFFSET(-8)
+ # Restore scratch registers.
+ pop %r11
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %r10
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %r9
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %r8
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rsi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rdx
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rcx
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rax
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rax)
+ CFI_RESTORE(%rbx)
+ CFI_RESTORE(%rcx)
+ CFI_RESTORE(%rdx)
+ CFI_RESTORE(%rsi)
+ CFI_RESTORE(%rdi)
+ CFI_RESTORE(%r8)
+ CFI_RESTORE(%r9)
+ CFI_RESTORE(%r10)
+ CFI_RESTORE(%r11)
+ ret
+ CFI_ENDPROC
+
+.hidden __tsan_report_race
+.globl __tsan_report_race_thunk
+__tsan_report_race_thunk:
+ CFI_STARTPROC
+ # Save scratch registers.
+ push %rax
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rax, 0)
+ push %rcx
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rcx, 0)
+ push %rdx
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdx, 0)
+ push %rsi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
+ push %rdi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
+ push %r8
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r8, 0)
+ push %r9
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r9, 0)
+ push %r10
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r10, 0)
+ push %r11
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r11, 0)
+ # Align stack frame.
+ push %rbx # non-scratch
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rbx, 0)
+ mov %rsp, %rbx # save current rsp
+ CFI_DEF_CFA_REGISTER(%rbx)
+ shr $4, %rsp # clear 4 lsb, align to 16
+ shl $4, %rsp
+
+ call __tsan_report_race
+
+ # Unalign stack frame back.
+ mov %rbx, %rsp # restore the original rsp
+ CFI_DEF_CFA_REGISTER(%rsp)
+ pop %rbx
+ CFI_ADJUST_CFA_OFFSET(-8)
+ # Restore scratch registers.
+ pop %r11
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %r10
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %r9
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %r8
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rsi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rdx
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rcx
+ CFI_ADJUST_CFA_OFFSET(-8)
+ pop %rax
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rax)
+ CFI_RESTORE(%rbx)
+ CFI_RESTORE(%rcx)
+ CFI_RESTORE(%rdx)
+ CFI_RESTORE(%rsi)
+ CFI_RESTORE(%rdi)
+ CFI_RESTORE(%r8)
+ CFI_RESTORE(%r9)
+ CFI_RESTORE(%r10)
+ CFI_RESTORE(%r11)
+ ret
+ CFI_ENDPROC
+
+.hidden __tsan_setjmp
+.comm _ZN14__interception11real_setjmpE,8,8
+.globl setjmp
+.type setjmp, @function
+setjmp:
+ CFI_STARTPROC
+ // save env parameter
+ push %rdi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
+ // obtain %rsp
+#if defined(__FreeBSD__)
+ lea 8(%rsp), %rdi
+ mov %rdi, %rsi
+#else
+ lea 16(%rsp), %rdi
+ mov %rdi, %rsi
+ xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
+ rol $0x11, %rsi
+#endif
+ // call tsan interceptor
+ call __tsan_setjmp
+ // restore env parameter
+ pop %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
+ // tail jump to libc setjmp
+ movl $0, %eax
+ movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx
+ jmp *(%rdx)
+ CFI_ENDPROC
+.size setjmp, .-setjmp
+
+.comm _ZN14__interception12real__setjmpE,8,8
+.globl _setjmp
+.type _setjmp, @function
+_setjmp:
+ CFI_STARTPROC
+ // save env parameter
+ push %rdi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
+ // obtain %rsp
+#if defined(__FreeBSD__)
+ lea 8(%rsp), %rdi
+ mov %rdi, %rsi
+#else
+ lea 16(%rsp), %rdi
+ mov %rdi, %rsi
+ xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
+ rol $0x11, %rsi
+#endif
+ // call tsan interceptor
+ call __tsan_setjmp
+ // restore env parameter
+ pop %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
+ // tail jump to libc setjmp
+ movl $0, %eax
+ movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx
+ jmp *(%rdx)
+ CFI_ENDPROC
+.size _setjmp, .-_setjmp
+
+.comm _ZN14__interception14real_sigsetjmpE,8,8
+.globl sigsetjmp
+.type sigsetjmp, @function
+sigsetjmp:
+ CFI_STARTPROC
+ // save env parameter
+ push %rdi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
+ // save savesigs parameter
+ push %rsi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
+ // align stack frame
+ sub $8, %rsp
+ CFI_ADJUST_CFA_OFFSET(8)
+ // obtain %rsp
+#if defined(__FreeBSD__)
+ lea 24(%rsp), %rdi
+ mov %rdi, %rsi
+#else
+ lea 32(%rsp), %rdi
+ mov %rdi, %rsi
+ xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
+ rol $0x11, %rsi
+#endif
+ // call tsan interceptor
+ call __tsan_setjmp
+ // unalign stack frame
+ add $8, %rsp
+ CFI_ADJUST_CFA_OFFSET(-8)
+ // restore savesigs parameter
+ pop %rsi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rsi)
+ // restore env parameter
+ pop %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
+ // tail jump to libc sigsetjmp
+ movl $0, %eax
+ movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx
+ jmp *(%rdx)
+ CFI_ENDPROC
+.size sigsetjmp, .-sigsetjmp
+
+.comm _ZN14__interception16real___sigsetjmpE,8,8
+.globl __sigsetjmp
+.type __sigsetjmp, @function
+__sigsetjmp:
+ CFI_STARTPROC
+ // save env parameter
+ push %rdi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
+ // save savesigs parameter
+ push %rsi
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
+ // align stack frame
+ sub $8, %rsp
+ CFI_ADJUST_CFA_OFFSET(8)
+ // obtain %rsp
+#if defined(__FreeBSD__)
+ lea 24(%rsp), %rdi
+ mov %rdi, %rsi
+#else
+ lea 32(%rsp), %rdi
+ mov %rdi, %rsi
+ xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
+ rol $0x11, %rsi
+#endif
+ // call tsan interceptor
+ call __tsan_setjmp
+ // unalign stack frame
+ add $8, %rsp
+ CFI_ADJUST_CFA_OFFSET(-8)
+ // restore savesigs parameter
+ pop %rsi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rsi)
+ // restore env parameter
+ pop %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
+ // tail jump to libc sigsetjmp
+ movl $0, %eax
+ movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
+ jmp *(%rdx)
+ CFI_ENDPROC
+.size __sigsetjmp, .-__sigsetjmp
+
+#if defined(__FreeBSD__) || defined(__linux__)
+/* We do not need executable stack. */
+.section .note.GNU-stack,"",@progbits
+#endif
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
new file mode 100644
index 000000000000..ddf2b69bdbbc
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -0,0 +1,491 @@
+//===-- tsan_rtl_mutex.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
+#include <sanitizer_common/sanitizer_stackdepot.h>
+
+#include "tsan_rtl.h"
+#include "tsan_flags.h"
+#include "tsan_sync.h"
+#include "tsan_report.h"
+#include "tsan_symbolize.h"
+#include "tsan_platform.h"
+
+namespace __tsan {
+
+void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r);
+
+struct Callback : DDCallback {
+ ThreadState *thr;
+ uptr pc;
+
+ Callback(ThreadState *thr, uptr pc)
+ : thr(thr)
+ , pc(pc) {
+ DDCallback::pt = thr->dd_pt;
+ DDCallback::lt = thr->dd_lt;
+ }
+
+ virtual u32 Unwind() {
+ return CurrentStackId(thr, pc);
+ }
+ virtual int UniqueTid() {
+ return thr->unique_id;
+ }
+};
+
+void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexInit(&cb, &s->dd);
+ s->dd.ctx = s->GetId();
+}
+
+static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
+ uptr addr, u64 mid) {
+ // In Go, these misuses are either impossible, or detected by std lib,
+ // or false positives (e.g. unlock in a different thread).
+ if (kGoMode)
+ return;
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(typ);
+ rep.AddMutex(mid);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ rep.AddStack(trace, true);
+ rep.AddLocation(addr, 1);
+ OutputReport(thr, rep);
+}
+
+void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
+ bool rw, bool recursive, bool linker_init) {
+ DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
+ StatInc(thr, StatMutexCreate);
+ if (!linker_init && IsAppMem(addr)) {
+ CHECK(!thr->is_freeing);
+ thr->is_freeing = true;
+ MemoryWrite(thr, pc, addr, kSizeLog1);
+ thr->is_freeing = false;
+ }
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ s->is_rw = rw;
+ s->is_recursive = recursive;
+ s->is_linker_init = linker_init;
+ if (kCppMode && s->creation_stack_id == 0)
+ s->creation_stack_id = CurrentStackId(thr, pc);
+ s->mtx.Unlock();
+}
+
+void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
+ StatInc(thr, StatMutexDestroy);
+#ifndef SANITIZER_GO
+ // Global mutexes not marked as LINKER_INITIALIZED
+ // cause tons of not interesting reports, so just ignore it.
+ if (IsGlobalVar(addr))
+ return;
+#endif
+ if (IsAppMem(addr)) {
+ CHECK(!thr->is_freeing);
+ thr->is_freeing = true;
+ MemoryWrite(thr, pc, addr, kSizeLog1);
+ thr->is_freeing = false;
+ }
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ if (s == 0)
+ return;
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexDestroy(&cb, &s->dd);
+ ctx->dd->MutexInit(&cb, &s->dd);
+ }
+ bool unlock_locked = false;
+ if (flags()->report_destroy_locked
+ && s->owner_tid != SyncVar::kInvalidTid
+ && !s->is_broken) {
+ s->is_broken = true;
+ unlock_locked = true;
+ }
+ u64 mid = s->GetId();
+ u32 last_lock = s->last_lock;
+ if (!unlock_locked)
+ s->Reset(thr); // must not reset it before the report is printed
+ s->mtx.Unlock();
+ if (unlock_locked) {
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeMutexDestroyLocked);
+ rep.AddMutex(mid);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ rep.AddStack(trace);
+ FastState last(last_lock);
+ RestoreStack(last.tid(), last.epoch(), &trace, 0);
+ rep.AddStack(trace, true);
+ rep.AddLocation(addr, 1);
+ OutputReport(thr, rep);
+ }
+ if (unlock_locked) {
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ if (s != 0) {
+ s->Reset(thr);
+ s->mtx.Unlock();
+ }
+ }
+ thr->mset.Remove(mid);
+ // s will be destroyed and freed in MetaMap::FreeBlock.
+}
+
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
+ DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
+ CHECK_GT(rec, 0);
+ if (IsAppMem(addr))
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
+ bool report_double_lock = false;
+ if (s->owner_tid == SyncVar::kInvalidTid) {
+ CHECK_EQ(s->recursion, 0);
+ s->owner_tid = thr->tid;
+ s->last_lock = thr->fast_state.raw();
+ } else if (s->owner_tid == thr->tid) {
+ CHECK_GT(s->recursion, 0);
+ } else if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_double_lock = true;
+ }
+ if (s->recursion == 0) {
+ StatInc(thr, StatMutexLock);
+ AcquireImpl(thr, pc, &s->clock);
+ AcquireImpl(thr, pc, &s->read_clock);
+ } else if (!s->is_recursive) {
+ StatInc(thr, StatMutexRecLock);
+ }
+ s->recursion += rec;
+ thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
+ if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) {
+ Callback cb(thr, pc);
+ if (!try_lock)
+ ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
+ ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
+ }
+ u64 mid = s->GetId();
+ s->mtx.Unlock();
+ // Can't touch s after this point.
+ if (report_double_lock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
+}
+
+int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
+ DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
+ if (IsAppMem(addr))
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
+ int rec = 0;
+ bool report_bad_unlock = false;
+ if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) {
+ if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_bad_unlock = true;
+ }
+ } else {
+ rec = all ? s->recursion : 1;
+ s->recursion -= rec;
+ if (s->recursion == 0) {
+ StatInc(thr, StatMutexUnlock);
+ s->owner_tid = SyncVar::kInvalidTid;
+ ReleaseStoreImpl(thr, pc, &s->clock);
+ } else {
+ StatInc(thr, StatMutexRecUnlock);
+ }
+ }
+ thr->mset.Del(s->GetId(), true);
+ if (common_flags()->detect_deadlocks && s->recursion == 0 &&
+ !report_bad_unlock) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
+ }
+ u64 mid = s->GetId();
+ s->mtx.Unlock();
+ // Can't touch s after this point.
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
+ if (common_flags()->detect_deadlocks && !report_bad_unlock) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
+ return rec;
+}
+
+void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
+ DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
+ StatInc(thr, StatMutexReadLock);
+ if (IsAppMem(addr))
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
+ bool report_bad_lock = false;
+ if (s->owner_tid != SyncVar::kInvalidTid) {
+ if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_bad_lock = true;
+ }
+ }
+ AcquireImpl(thr, pc, &s->clock);
+ s->last_lock = thr->fast_state.raw();
+ thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
+ if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ Callback cb(thr, pc);
+ if (!trylock)
+ ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
+ ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
+ }
+ u64 mid = s->GetId();
+ s->mtx.ReadUnlock();
+ // Can't touch s after this point.
+ if (report_bad_lock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
+}
+
+void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
+ StatInc(thr, StatMutexReadUnlock);
+ if (IsAppMem(addr))
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
+ bool report_bad_unlock = false;
+ if (s->owner_tid != SyncVar::kInvalidTid) {
+ if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_bad_unlock = true;
+ }
+ }
+ ReleaseImpl(thr, pc, &s->read_clock);
+ if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
+ }
+ u64 mid = s->GetId();
+ s->mtx.Unlock();
+ // Can't touch s after this point.
+ thr->mset.Del(mid, false);
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
+}
+
+void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
+ if (IsAppMem(addr))
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ bool write = true;
+ bool report_bad_unlock = false;
+ if (s->owner_tid == SyncVar::kInvalidTid) {
+ // Seems to be read unlock.
+ write = false;
+ StatInc(thr, StatMutexReadUnlock);
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
+ ReleaseImpl(thr, pc, &s->read_clock);
+ } else if (s->owner_tid == thr->tid) {
+ // Seems to be write unlock.
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
+ CHECK_GT(s->recursion, 0);
+ s->recursion--;
+ if (s->recursion == 0) {
+ StatInc(thr, StatMutexUnlock);
+ s->owner_tid = SyncVar::kInvalidTid;
+ ReleaseImpl(thr, pc, &s->clock);
+ } else {
+ StatInc(thr, StatMutexRecUnlock);
+ }
+ } else if (!s->is_broken) {
+ s->is_broken = true;
+ report_bad_unlock = true;
+ }
+ thr->mset.Del(s->GetId(), write);
+ if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
+ }
+ u64 mid = s->GetId();
+ s->mtx.Unlock();
+ // Can't touch s after this point.
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
+}
+
+void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ s->owner_tid = SyncVar::kInvalidTid;
+ s->recursion = 0;
+ s->mtx.Unlock();
+}
+
+void Acquire(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
+ AcquireImpl(thr, pc, &s->clock);
+ s->mtx.ReadUnlock();
+}
+
+static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
+ ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
+ ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
+ if (tctx->status == ThreadStatusRunning)
+ thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch());
+ else
+ thr->clock.set(tctx->tid, tctx->epoch1);
+}
+
+void AcquireGlobal(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: AcquireGlobal\n", thr->tid);
+ if (thr->ignore_sync)
+ return;
+ ThreadRegistryLock l(ctx->thread_registry);
+ ctx->thread_registry->RunCallbackForEachThreadLocked(
+ UpdateClockCallback, thr);
+}
+
+void Release(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: Release %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseImpl(thr, pc, &s->clock);
+ s->mtx.Unlock();
+}
+
+void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseStoreImpl(thr, pc, &s->clock);
+ s->mtx.Unlock();
+}
+
+#ifndef SANITIZER_GO
+static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
+ ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
+ ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
+ if (tctx->status == ThreadStatusRunning)
+ thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch());
+ else
+ thr->last_sleep_clock.set(tctx->tid, tctx->epoch1);
+}
+
+void AfterSleep(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: AfterSleep %zx\n", thr->tid);
+ if (thr->ignore_sync)
+ return;
+ thr->last_sleep_stack_id = CurrentStackId(thr, pc);
+ ThreadRegistryLock l(ctx->thread_registry);
+ ctx->thread_registry->RunCallbackForEachThreadLocked(
+ UpdateSleepClockCallback, thr);
+}
+#endif
+
+void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->fast_state.epoch());
+ thr->clock.acquire(&thr->clock_cache, c);
+ StatInc(thr, StatSyncAcquire);
+}
+
+void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.release(&thr->clock_cache, c);
+ StatInc(thr, StatSyncRelease);
+}
+
+void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.ReleaseStore(&thr->clock_cache, c);
+ StatInc(thr, StatSyncRelease);
+}
+
+void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.acq_rel(&thr->clock_cache, c);
+ StatInc(thr, StatSyncAcquire);
+ StatInc(thr, StatSyncRelease);
+}
+
+void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
+ if (r == 0)
+ return;
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeDeadlock);
+ for (int i = 0; i < r->n; i++) {
+ rep.AddMutex(r->loop[i].mtx_ctx0);
+ rep.AddUniqueTid((int)r->loop[i].thr_ctx);
+ rep.AddThread((int)r->loop[i].thr_ctx);
+ }
+ uptr dummy_pc = 0x42;
+ for (int i = 0; i < r->n; i++) {
+ for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
+ u32 stk = r->loop[i].stk[j];
+ if (stk) {
+ rep.AddStack(StackDepotGet(stk), true);
+ } else {
+ // Sometimes we fail to extract the stack trace (FIXME: investigate),
+ // but we should still produce some stack trace in the report.
+ rep.AddStack(StackTrace(&dummy_pc, 1), true);
+ }
+ }
+ }
+ OutputReport(thr, rep);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
new file mode 100644
index 000000000000..dc9438e6371b
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
@@ -0,0 +1,687 @@
+//===-- tsan_rtl_report.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+#include "tsan_suppressions.h"
+#include "tsan_symbolize.h"
+#include "tsan_report.h"
+#include "tsan_sync.h"
+#include "tsan_mman.h"
+#include "tsan_flags.h"
+#include "tsan_fd.h"
+
+namespace __tsan {
+
+using namespace __sanitizer; // NOLINT
+
+static ReportStack *SymbolizeStack(StackTrace trace);
+
+void TsanCheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ // There is high probability that interceptors will check-fail as well,
+ // on the other hand there is no sense in processing interceptors
+ // since we are going to die soon.
+ ScopedIgnoreInterceptors ignore;
+ Printf("FATAL: ThreadSanitizer CHECK failed: "
+ "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
+ file, line, cond, (uptr)v1, (uptr)v2);
+ PrintCurrentStackSlow(StackTrace::GetCurrentPc());
+ Die();
+}
+
+// Can be overriden by an application/test to intercept reports.
+#ifdef TSAN_EXTERNAL_HOOKS
+bool OnReport(const ReportDesc *rep, bool suppressed);
+#else
+SANITIZER_INTERFACE_ATTRIBUTE
+bool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
+ (void)rep;
+ return suppressed;
+}
+#endif
+
+static void StackStripMain(SymbolizedStack *frames) {
+ SymbolizedStack *last_frame = nullptr;
+ SymbolizedStack *last_frame2 = nullptr;
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ last_frame2 = last_frame;
+ last_frame = cur;
+ }
+
+ if (last_frame2 == 0)
+ return;
+#ifndef SANITIZER_GO
+ const char *last = last_frame->info.function;
+ const char *last2 = last_frame2->info.function;
+ // Strip frame above 'main'
+ if (last2 && 0 == internal_strcmp(last2, "main")) {
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
+ // Strip our internal thread start routine.
+ } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) {
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
+ // Strip global ctors init.
+ } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) {
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
+ // If both are 0, then we probably just failed to symbolize.
+ } else if (last || last2) {
+ // Ensure that we recovered stack completely. Trimmed stack
+ // can actually happen if we do not instrument some code,
+ // so it's only a debug print. However we must try hard to not miss it
+ // due to our fault.
+ DPrintf("Bottom stack frame is missed\n");
+ }
+#else
+ // The last frame always point into runtime (gosched0, goexit0, runtime.main).
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
+#endif
+}
+
+ReportStack *SymbolizeStackId(u32 stack_id) {
+ if (stack_id == 0)
+ return 0;
+ StackTrace stack = StackDepotGet(stack_id);
+ if (stack.trace == nullptr)
+ return nullptr;
+ return SymbolizeStack(stack);
+}
+
+static ReportStack *SymbolizeStack(StackTrace trace) {
+ if (trace.size == 0)
+ return 0;
+ SymbolizedStack *top = nullptr;
+ for (uptr si = 0; si < trace.size; si++) {
+ const uptr pc = trace.trace[si];
+ uptr pc1 = pc;
+ // We obtain the return address, but we're interested in the previous
+ // instruction.
+ if ((pc & kExternalPCBit) == 0)
+ pc1 = StackTrace::GetPreviousInstructionPc(pc);
+ SymbolizedStack *ent = SymbolizeCode(pc1);
+ CHECK_NE(ent, 0);
+ SymbolizedStack *last = ent;
+ while (last->next) {
+ last->info.address = pc; // restore original pc for report
+ last = last->next;
+ }
+ last->info.address = pc; // restore original pc for report
+ last->next = top;
+ top = ent;
+ }
+ StackStripMain(top);
+
+ ReportStack *stack = ReportStack::New();
+ stack->frames = top;
+ return stack;
+}
+
+ScopedReport::ScopedReport(ReportType typ) {
+ ctx->thread_registry->CheckLocked();
+ void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
+ rep_ = new(mem) ReportDesc;
+ rep_->typ = typ;
+ ctx->report_mtx.Lock();
+ CommonSanitizerReportMutex.Lock();
+}
+
+ScopedReport::~ScopedReport() {
+ CommonSanitizerReportMutex.Unlock();
+ ctx->report_mtx.Unlock();
+ DestroyAndFree(rep_);
+}
+
+void ScopedReport::AddStack(StackTrace stack, bool suppressable) {
+ ReportStack **rs = rep_->stacks.PushBack();
+ *rs = SymbolizeStack(stack);
+ (*rs)->suppressable = suppressable;
+}
+
+void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+ const MutexSet *mset) {
+ void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
+ ReportMop *mop = new(mem) ReportMop;
+ rep_->mops.PushBack(mop);
+ mop->tid = s.tid();
+ mop->addr = addr + s.addr0();
+ mop->size = s.size();
+ mop->write = s.IsWrite();
+ mop->atomic = s.IsAtomic();
+ mop->stack = SymbolizeStack(stack);
+ if (mop->stack)
+ mop->stack->suppressable = true;
+ for (uptr i = 0; i < mset->Size(); i++) {
+ MutexSet::Desc d = mset->Get(i);
+ u64 mid = this->AddMutex(d.id);
+ ReportMopMutex mtx = {mid, d.write};
+ mop->mset.PushBack(mtx);
+ }
+}
+
+void ScopedReport::AddUniqueTid(int unique_tid) {
+ rep_->unique_tids.PushBack(unique_tid);
+}
+
+void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
+ for (uptr i = 0; i < rep_->threads.Size(); i++) {
+ if ((u32)rep_->threads[i]->id == tctx->tid)
+ return;
+ }
+ void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
+ ReportThread *rt = new(mem) ReportThread();
+ rep_->threads.PushBack(rt);
+ rt->id = tctx->tid;
+ rt->pid = tctx->os_id;
+ rt->running = (tctx->status == ThreadStatusRunning);
+ rt->name = internal_strdup(tctx->name);
+ rt->parent_tid = tctx->parent_tid;
+ rt->stack = 0;
+ rt->stack = SymbolizeStackId(tctx->creation_stack_id);
+ if (rt->stack)
+ rt->stack->suppressable = suppressable;
+}
+
+#ifndef SANITIZER_GO
+static ThreadContext *FindThreadByUidLocked(int unique_id) {
+ ctx->thread_registry->CheckLocked();
+ for (unsigned i = 0; i < kMaxTid; i++) {
+ ThreadContext *tctx = static_cast<ThreadContext*>(
+ ctx->thread_registry->GetThreadLocked(i));
+ if (tctx && tctx->unique_id == (u32)unique_id) {
+ return tctx;
+ }
+ }
+ return 0;
+}
+
+static ThreadContext *FindThreadByTidLocked(int tid) {
+ ctx->thread_registry->CheckLocked();
+ return static_cast<ThreadContext*>(
+ ctx->thread_registry->GetThreadLocked(tid));
+}
+
+static bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) {
+ uptr addr = (uptr)arg;
+ ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
+ if (tctx->status != ThreadStatusRunning)
+ return false;
+ ThreadState *thr = tctx->thr;
+ CHECK(thr);
+ return ((addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) ||
+ (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size));
+}
+
+ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
+ ctx->thread_registry->CheckLocked();
+ ThreadContext *tctx = static_cast<ThreadContext*>(
+ ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls,
+ (void*)addr));
+ if (!tctx)
+ return 0;
+ ThreadState *thr = tctx->thr;
+ CHECK(thr);
+ *is_stack = (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size);
+ return tctx;
+}
+#endif
+
+void ScopedReport::AddThread(int unique_tid, bool suppressable) {
+#ifndef SANITIZER_GO
+ if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid))
+ AddThread(tctx, suppressable);
+#endif
+}
+
+void ScopedReport::AddMutex(const SyncVar *s) {
+ for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
+ if (rep_->mutexes[i]->id == s->uid)
+ return;
+ }
+ void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
+ ReportMutex *rm = new(mem) ReportMutex();
+ rep_->mutexes.PushBack(rm);
+ rm->id = s->uid;
+ rm->addr = s->addr;
+ rm->destroyed = false;
+ rm->stack = SymbolizeStackId(s->creation_stack_id);
+}
+
+u64 ScopedReport::AddMutex(u64 id) {
+ u64 uid = 0;
+ u64 mid = id;
+ uptr addr = SyncVar::SplitId(id, &uid);
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ // Check that the mutex is still alive.
+ // Another mutex can be created at the same address,
+ // so check uid as well.
+ if (s && s->CheckId(uid)) {
+ mid = s->uid;
+ AddMutex(s);
+ } else {
+ AddDeadMutex(id);
+ }
+ if (s)
+ s->mtx.Unlock();
+ return mid;
+}
+
+void ScopedReport::AddDeadMutex(u64 id) {
+ for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
+ if (rep_->mutexes[i]->id == id)
+ return;
+ }
+ void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
+ ReportMutex *rm = new(mem) ReportMutex();
+ rep_->mutexes.PushBack(rm);
+ rm->id = id;
+ rm->addr = 0;
+ rm->destroyed = true;
+ rm->stack = 0;
+}
+
+void ScopedReport::AddLocation(uptr addr, uptr size) {
+ if (addr == 0)
+ return;
+#ifndef SANITIZER_GO
+ int fd = -1;
+ int creat_tid = -1;
+ u32 creat_stack = 0;
+ if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) {
+ ReportLocation *loc = ReportLocation::New(ReportLocationFD);
+ loc->fd = fd;
+ loc->tid = creat_tid;
+ loc->stack = SymbolizeStackId(creat_stack);
+ rep_->locs.PushBack(loc);
+ ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
+ if (tctx)
+ AddThread(tctx);
+ return;
+ }
+ MBlock *b = 0;
+ Allocator *a = allocator();
+ if (a->PointerIsMine((void*)addr)) {
+ void *block_begin = a->GetBlockBegin((void*)addr);
+ if (block_begin)
+ b = ctx->metamap.GetBlock((uptr)block_begin);
+ }
+ if (b != 0) {
+ ThreadContext *tctx = FindThreadByTidLocked(b->tid);
+ ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
+ loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
+ loc->heap_chunk_size = b->siz;
+ loc->tid = tctx ? tctx->tid : b->tid;
+ loc->stack = SymbolizeStackId(b->stk);
+ rep_->locs.PushBack(loc);
+ if (tctx)
+ AddThread(tctx);
+ return;
+ }
+ bool is_stack = false;
+ if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
+ ReportLocation *loc =
+ ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS);
+ loc->tid = tctx->tid;
+ rep_->locs.PushBack(loc);
+ AddThread(tctx);
+ }
+ if (ReportLocation *loc = SymbolizeData(addr)) {
+ loc->suppressable = true;
+ rep_->locs.PushBack(loc);
+ return;
+ }
+#endif
+}
+
+#ifndef SANITIZER_GO
+void ScopedReport::AddSleep(u32 stack_id) {
+ rep_->sleep = SymbolizeStackId(stack_id);
+}
+#endif
+
+void ScopedReport::SetCount(int count) {
+ rep_->count = count;
+}
+
+const ReportDesc *ScopedReport::GetReport() const {
+ return rep_;
+}
+
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+ MutexSet *mset) {
+ // This function restores stack trace and mutex set for the thread/epoch.
+ // It does so by getting stack trace and mutex set at the beginning of
+ // trace part, and then replaying the trace till the given epoch.
+ ctx->thread_registry->CheckLocked();
+ ThreadContext *tctx = static_cast<ThreadContext*>(
+ ctx->thread_registry->GetThreadLocked(tid));
+ if (tctx == 0)
+ return;
+ if (tctx->status != ThreadStatusRunning
+ && tctx->status != ThreadStatusFinished
+ && tctx->status != ThreadStatusDead)
+ return;
+ Trace* trace = ThreadTrace(tctx->tid);
+ Lock l(&trace->mtx);
+ const int partidx = (epoch / kTracePartSize) % TraceParts();
+ TraceHeader* hdr = &trace->headers[partidx];
+ if (epoch < hdr->epoch0)
+ return;
+ const u64 epoch0 = RoundDown(epoch, TraceSize());
+ const u64 eend = epoch % TraceSize();
+ const u64 ebegin = RoundDown(eend, kTracePartSize);
+ DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
+ tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
+ InternalScopedBuffer<uptr> stack(kShadowStackSize);
+ for (uptr i = 0; i < hdr->stack0.size; i++) {
+ stack[i] = hdr->stack0.trace[i];
+ DPrintf2(" #%02zu: pc=%zx\n", i, stack[i]);
+ }
+ if (mset)
+ *mset = hdr->mset0;
+ uptr pos = hdr->stack0.size;
+ Event *events = (Event*)GetThreadTrace(tid);
+ for (uptr i = ebegin; i <= eend; i++) {
+ Event ev = events[i];
+ EventType typ = (EventType)(ev >> 61);
+ uptr pc = (uptr)(ev & ((1ull << 61) - 1));
+ DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc);
+ if (typ == EventTypeMop) {
+ stack[pos] = pc;
+ } else if (typ == EventTypeFuncEnter) {
+ stack[pos++] = pc;
+ } else if (typ == EventTypeFuncExit) {
+ if (pos > 0)
+ pos--;
+ }
+ if (mset) {
+ if (typ == EventTypeLock) {
+ mset->Add(pc, true, epoch0 + i);
+ } else if (typ == EventTypeUnlock) {
+ mset->Del(pc, true);
+ } else if (typ == EventTypeRLock) {
+ mset->Add(pc, false, epoch0 + i);
+ } else if (typ == EventTypeRUnlock) {
+ mset->Del(pc, false);
+ }
+ }
+ for (uptr j = 0; j <= pos; j++)
+ DPrintf2(" #%zu: %zx\n", j, stack[j]);
+ }
+ if (pos == 0 && stack[0] == 0)
+ return;
+ pos++;
+ stk->Init(stack.data(), pos);
+}
+
+static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+ uptr addr_min, uptr addr_max) {
+ bool equal_stack = false;
+ RacyStacks hash;
+ if (flags()->suppress_equal_stacks) {
+ hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+ hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
+ for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
+ if (hash == ctx->racy_stacks[i]) {
+ DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
+ equal_stack = true;
+ break;
+ }
+ }
+ }
+ bool equal_address = false;
+ RacyAddress ra0 = {addr_min, addr_max};
+ if (flags()->suppress_equal_addresses) {
+ for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
+ RacyAddress ra2 = ctx->racy_addresses[i];
+ uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
+ uptr minend = min(ra0.addr_max, ra2.addr_max);
+ if (maxbeg < minend) {
+ DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n");
+ equal_address = true;
+ break;
+ }
+ }
+ }
+ if (equal_stack || equal_address) {
+ if (!equal_stack)
+ ctx->racy_stacks.PushBack(hash);
+ if (!equal_address)
+ ctx->racy_addresses.PushBack(ra0);
+ return true;
+ }
+ return false;
+}
+
+static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+ uptr addr_min, uptr addr_max) {
+ if (flags()->suppress_equal_stacks) {
+ RacyStacks hash;
+ hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+ hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
+ ctx->racy_stacks.PushBack(hash);
+ }
+ if (flags()->suppress_equal_addresses) {
+ RacyAddress ra0 = {addr_min, addr_max};
+ ctx->racy_addresses.PushBack(ra0);
+ }
+}
+
+bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
+ atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
+ const ReportDesc *rep = srep.GetReport();
+ Suppression *supp = 0;
+ uptr suppress_pc = 0;
+ for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
+ for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp);
+ for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
+ for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp);
+ if (suppress_pc != 0) {
+ FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
+ ctx->fired_suppressions.push_back(s);
+ }
+ {
+ bool old_is_freeing = thr->is_freeing;
+ thr->is_freeing = false;
+ bool suppressed = OnReport(rep, suppress_pc != 0);
+ thr->is_freeing = old_is_freeing;
+ if (suppressed)
+ return false;
+ }
+ PrintReport(rep);
+ ctx->nreported++;
+ if (flags()->halt_on_error)
+ internal__exit(flags()->exitcode);
+ return true;
+}
+
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+ StackTrace trace) {
+ for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
+ if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+ continue;
+ for (uptr j = 0; j < trace.size; j++) {
+ FiredSuppression *s = &ctx->fired_suppressions[k];
+ if (trace.trace[j] == s->pc) {
+ if (s->supp)
+ s->supp->hit_count++;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool IsFiredSuppression(Context *ctx,
+ const ScopedReport &srep,
+ uptr addr) {
+ for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
+ if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+ continue;
+ FiredSuppression *s = &ctx->fired_suppressions[k];
+ if (addr == s->pc) {
+ if (s->supp)
+ s->supp->hit_count++;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
+ Shadow s0(thr->racy_state[0]);
+ Shadow s1(thr->racy_state[1]);
+ CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
+ if (!s0.IsAtomic() && !s1.IsAtomic())
+ return true;
+ if (s0.IsAtomic() && s1.IsFreed())
+ return true;
+ if (s1.IsAtomic() && thr->is_freeing)
+ return true;
+ return false;
+}
+
+void ReportRace(ThreadState *thr) {
+ CheckNoLocks(thr);
+
+ // Symbolizer makes lots of intercepted calls. If we try to process them,
+ // at best it will cause deadlocks on internal mutexes.
+ ScopedIgnoreInterceptors ignore;
+
+ if (!flags()->report_bugs)
+ return;
+ if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
+ return;
+
+ bool freed = false;
+ {
+ Shadow s(thr->racy_state[1]);
+ freed = s.GetFreedAndReset();
+ thr->racy_state[1] = s.raw();
+ }
+
+ uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr);
+ uptr addr_min = 0;
+ uptr addr_max = 0;
+ {
+ uptr a0 = addr + Shadow(thr->racy_state[0]).addr0();
+ uptr a1 = addr + Shadow(thr->racy_state[1]).addr0();
+ uptr e0 = a0 + Shadow(thr->racy_state[0]).size();
+ uptr e1 = a1 + Shadow(thr->racy_state[1]).size();
+ addr_min = min(a0, a1);
+ addr_max = max(e0, e1);
+ if (IsExpectedReport(addr_min, addr_max - addr_min))
+ return;
+ }
+
+ ThreadRegistryLock l0(ctx->thread_registry);
+
+ ReportType typ = ReportTypeRace;
+ if (thr->is_vptr_access && freed)
+ typ = ReportTypeVptrUseAfterFree;
+ else if (thr->is_vptr_access)
+ typ = ReportTypeVptrRace;
+ else if (freed)
+ typ = ReportTypeUseAfterFree;
+ ScopedReport rep(typ);
+ if (IsFiredSuppression(ctx, rep, addr))
+ return;
+ const uptr kMop = 2;
+ VarSizeStackTrace traces[kMop];
+ const uptr toppc = TraceTopPC(thr);
+ ObtainCurrentStack(thr, toppc, &traces[0]);
+ if (IsFiredSuppression(ctx, rep, traces[0]))
+ return;
+ InternalScopedBuffer<MutexSet> mset2(1);
+ new(mset2.data()) MutexSet();
+ Shadow s2(thr->racy_state[1]);
+ RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
+ if (IsFiredSuppression(ctx, rep, traces[1]))
+ return;
+
+ if (HandleRacyStacks(thr, traces, addr_min, addr_max))
+ return;
+
+ for (uptr i = 0; i < kMop; i++) {
+ Shadow s(thr->racy_state[i]);
+ rep.AddMemoryAccess(addr, s, traces[i],
+ i == 0 ? &thr->mset : mset2.data());
+ }
+
+ for (uptr i = 0; i < kMop; i++) {
+ FastState s(thr->racy_state[i]);
+ ThreadContext *tctx = static_cast<ThreadContext*>(
+ ctx->thread_registry->GetThreadLocked(s.tid()));
+ if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1)
+ continue;
+ rep.AddThread(tctx);
+ }
+
+ rep.AddLocation(addr_min, addr_max - addr_min);
+
+#ifndef SANITIZER_GO
+ { // NOLINT
+ Shadow s(thr->racy_state[1]);
+ if (s.epoch() <= thr->last_sleep_clock.get(s.tid()))
+ rep.AddSleep(thr->last_sleep_stack_id);
+ }
+#endif
+
+ if (!OutputReport(thr, rep))
+ return;
+
+ AddRacyStacks(thr, traces, addr_min, addr_max);
+}
+
+void PrintCurrentStack(ThreadState *thr, uptr pc) {
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ PrintStack(SymbolizeStack(trace));
+}
+
+void PrintCurrentStackSlow(uptr pc) {
+#ifndef SANITIZER_GO
+ BufferedStackTrace *ptrace =
+ new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
+ BufferedStackTrace();
+ ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false);
+ for (uptr i = 0; i < ptrace->size / 2; i++) {
+ uptr tmp = ptrace->trace_buffer[i];
+ ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
+ ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
+ }
+ PrintStack(SymbolizeStack(*ptrace));
+#endif
+}
+
+} // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ PrintCurrentStackSlow(StackTrace::GetCurrentPc());
+}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
new file mode 100644
index 000000000000..8ed1fbf2edae
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -0,0 +1,408 @@
+//===-- tsan_rtl_thread.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "tsan_platform.h"
+#include "tsan_report.h"
+#include "tsan_sync.h"
+
+namespace __tsan {
+
+// ThreadContext implementation.
+
+ThreadContext::ThreadContext(int tid)
+ : ThreadContextBase(tid)
+ , thr()
+ , sync()
+ , epoch0()
+ , epoch1() {
+}
+
+#ifndef SANITIZER_GO
+ThreadContext::~ThreadContext() {
+}
+#endif
+
+void ThreadContext::OnDead() {
+ CHECK_EQ(sync.size(), 0);
+}
+
+void ThreadContext::OnJoined(void *arg) {
+ ThreadState *caller_thr = static_cast<ThreadState *>(arg);
+ AcquireImpl(caller_thr, 0, &sync);
+ sync.Reset(&caller_thr->clock_cache);
+}
+
+struct OnCreatedArgs {
+ ThreadState *thr;
+ uptr pc;
+};
+
+void ThreadContext::OnCreated(void *arg) {
+ thr = 0;
+ if (tid == 0)
+ return;
+ OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
+ args->thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
+ ReleaseImpl(args->thr, 0, &sync);
+ creation_stack_id = CurrentStackId(args->thr, args->pc);
+ if (reuse_count == 0)
+ StatInc(args->thr, StatThreadMaxTid);
+}
+
+void ThreadContext::OnReset() {
+ CHECK_EQ(sync.size(), 0);
+ FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
+ //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
+}
+
+void ThreadContext::OnDetached(void *arg) {
+ ThreadState *thr1 = static_cast<ThreadState*>(arg);
+ sync.Reset(&thr1->clock_cache);
+}
+
+struct OnStartedArgs {
+ ThreadState *thr;
+ uptr stk_addr;
+ uptr stk_size;
+ uptr tls_addr;
+ uptr tls_size;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ OnStartedArgs *args = static_cast<OnStartedArgs*>(arg);
+ thr = args->thr;
+ // RoundUp so that one trace part does not contain events
+ // from different threads.
+ epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
+ epoch1 = (u64)-1;
+ new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count,
+ args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
+#ifndef SANITIZER_GO
+ thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
+ thr->shadow_stack_pos = thr->shadow_stack;
+ thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
+#else
+ // Setup dynamic shadow stack.
+ const int kInitStackSize = 8;
+ thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+ kInitStackSize * sizeof(uptr));
+ thr->shadow_stack_pos = thr->shadow_stack;
+ thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+#endif
+#ifndef SANITIZER_GO
+ AllocatorThreadStart(thr);
+#endif
+ if (common_flags()->detect_deadlocks) {
+ thr->dd_pt = ctx->dd->CreatePhysicalThread();
+ thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
+ }
+ thr->fast_state.SetHistorySize(flags()->history_size);
+ // Commit switch to the new part of the trace.
+ // TraceAddEvent will reset stack0/mset0 in the new part for us.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+
+ thr->fast_synch_epoch = epoch0;
+ AcquireImpl(thr, 0, &sync);
+ StatInc(thr, StatSyncAcquire);
+ sync.Reset(&thr->clock_cache);
+ DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
+ "tls_addr=%zx tls_size=%zx\n",
+ tid, (uptr)epoch0, args->stk_addr, args->stk_size,
+ args->tls_addr, args->tls_size);
+}
+
+void ThreadContext::OnFinished() {
+ if (!detached) {
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseImpl(thr, 0, &sync);
+ }
+ epoch1 = thr->fast_state.epoch();
+
+ if (common_flags()->detect_deadlocks) {
+ ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+ ctx->dd->DestroyLogicalThread(thr->dd_lt);
+ }
+ ctx->clock_alloc.FlushCache(&thr->clock_cache);
+ ctx->metamap.OnThreadIdle(thr);
+#ifndef SANITIZER_GO
+ AllocatorThreadFinish(thr);
+#endif
+ thr->~ThreadState();
+#if TSAN_COLLECT_STATS
+ StatAggregate(ctx->stat, thr->stat);
+#endif
+ thr = 0;
+}
+
+#ifndef SANITIZER_GO
+struct ThreadLeak {
+ ThreadContext *tctx;
+ int count;
+};
+
+static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
+ Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg;
+ ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
+ if (tctx->detached || tctx->status != ThreadStatusFinished)
+ return;
+ for (uptr i = 0; i < leaks.Size(); i++) {
+ if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
+ leaks[i].count++;
+ return;
+ }
+ }
+ ThreadLeak leak = {tctx, 1};
+ leaks.PushBack(leak);
+}
+#endif
+
+#ifndef SANITIZER_GO
+static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
+ if (tctx->tid == 0) {
+ Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
+ } else {
+ Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
+ " created at:\n", tctx->tid, tctx->name);
+ PrintStack(SymbolizeStackId(tctx->creation_stack_id));
+ }
+ Printf(" One of the following ignores was not ended"
+ " (in order of probability)\n");
+ for (uptr i = 0; i < set->Size(); i++) {
+ Printf(" Ignore was enabled at:\n");
+ PrintStack(SymbolizeStackId(set->At(i)));
+ }
+ Die();
+}
+
+static void ThreadCheckIgnore(ThreadState *thr) {
+ if (ctx->after_multithreaded_fork)
+ return;
+ if (thr->ignore_reads_and_writes)
+ ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
+ if (thr->ignore_sync)
+ ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
+}
+#else
+static void ThreadCheckIgnore(ThreadState *thr) {}
+#endif
+
+void ThreadFinalize(ThreadState *thr) {
+ ThreadCheckIgnore(thr);
+#ifndef SANITIZER_GO
+ if (!flags()->report_thread_leaks)
+ return;
+ ThreadRegistryLock l(ctx->thread_registry);
+ Vector<ThreadLeak> leaks(MBlockScopedBuf);
+ ctx->thread_registry->RunCallbackForEachThreadLocked(
+ MaybeReportThreadLeak, &leaks);
+ for (uptr i = 0; i < leaks.Size(); i++) {
+ ScopedReport rep(ReportTypeThreadLeak);
+ rep.AddThread(leaks[i].tctx, true);
+ rep.SetCount(leaks[i].count);
+ OutputReport(thr, rep);
+ }
+#endif
+}
+
+int ThreadCount(ThreadState *thr) {
+ uptr result;
+ ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
+ return (int)result;
+}
+
+int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
+ StatInc(thr, StatThreadCreate);
+ OnCreatedArgs args = { thr, pc };
+ int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
+ DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
+ StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
+ return tid;
+}
+
+void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
+ uptr stk_addr = 0;
+ uptr stk_size = 0;
+ uptr tls_addr = 0;
+ uptr tls_size = 0;
+#ifndef SANITIZER_GO
+ GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
+
+ if (tid) {
+ if (stk_addr && stk_size)
+ MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
+
+ if (tls_addr && tls_size) {
+ // Check that the thr object is in tls;
+ const uptr thr_beg = (uptr)thr;
+ const uptr thr_end = (uptr)thr + sizeof(*thr);
+ CHECK_GE(thr_beg, tls_addr);
+ CHECK_LE(thr_beg, tls_addr + tls_size);
+ CHECK_GE(thr_end, tls_addr);
+ CHECK_LE(thr_end, tls_addr + tls_size);
+ // Since the thr object is huge, skip it.
+ MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
+ MemoryRangeImitateWrite(thr, /*pc=*/ 2,
+ thr_end, tls_addr + tls_size - thr_end);
+ }
+ }
+#endif
+
+ ThreadRegistry *tr = ctx->thread_registry;
+ OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
+ tr->StartThread(tid, os_id, &args);
+
+ tr->Lock();
+ thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
+ tr->Unlock();
+
+#ifndef SANITIZER_GO
+ if (ctx->after_multithreaded_fork) {
+ thr->ignore_interceptors++;
+ ThreadIgnoreBegin(thr, 0);
+ ThreadIgnoreSyncBegin(thr, 0);
+ }
+#endif
+}
+
+void ThreadFinish(ThreadState *thr) {
+ ThreadCheckIgnore(thr);
+ StatInc(thr, StatThreadFinish);
+ if (thr->stk_addr && thr->stk_size)
+ DontNeedShadowFor(thr->stk_addr, thr->stk_size);
+ if (thr->tls_addr && thr->tls_size)
+ DontNeedShadowFor(thr->tls_addr, thr->tls_size);
+ thr->is_dead = true;
+ ctx->thread_registry->FinishThread(thr->tid);
+}
+
+static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
+ uptr uid = (uptr)arg;
+ if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+ tctx->user_id = 0;
+ return true;
+ }
+ return false;
+}
+
+int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
+ int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
+ DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
+ return res;
+}
+
+void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
+ CHECK_GT(tid, 0);
+ CHECK_LT(tid, kMaxTid);
+ DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
+ ctx->thread_registry->JoinThread(tid, thr);
+}
+
+void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
+ CHECK_GT(tid, 0);
+ CHECK_LT(tid, kMaxTid);
+ ctx->thread_registry->DetachThread(tid, thr);
+}
+
+void ThreadSetName(ThreadState *thr, const char *name) {
+ ctx->thread_registry->SetThreadName(thr->tid, name);
+}
+
+void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
+ uptr size, bool is_write) {
+ if (size == 0)
+ return;
+
+ u64 *shadow_mem = (u64*)MemToShadow(addr);
+ DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
+ thr->tid, (void*)pc, (void*)addr,
+ (int)size, is_write);
+
+#if SANITIZER_DEBUG
+ if (!IsAppMem(addr)) {
+ Printf("Access to non app mem %zx\n", addr);
+ DCHECK(IsAppMem(addr));
+ }
+ if (!IsAppMem(addr + size - 1)) {
+ Printf("Access to non app mem %zx\n", addr + size - 1);
+ DCHECK(IsAppMem(addr + size - 1));
+ }
+ if (!IsShadowMem((uptr)shadow_mem)) {
+ Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
+ DCHECK(IsShadowMem((uptr)shadow_mem));
+ }
+ if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
+ Printf("Bad shadow addr %p (%zx)\n",
+ shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
+ DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
+ }
+#endif
+
+ StatInc(thr, StatMopRange);
+
+ if (*shadow_mem == kShadowRodata) {
+ // Access to .rodata section, no races here.
+ // Measurements show that it can be 10-20% of all memory accesses.
+ StatInc(thr, StatMopRangeRodata);
+ return;
+ }
+
+ FastState fast_state = thr->fast_state;
+ if (fast_state.GetIgnoreBit())
+ return;
+
+ fast_state.IncrementEpoch();
+ thr->fast_state = fast_state;
+ TraceAddEvent(thr, fast_state, EventTypeMop, pc);
+
+ bool unaligned = (addr % kShadowCell) != 0;
+
+ // Handle unaligned beginning, if any.
+ for (; addr % kShadowCell && size; addr++, size--) {
+ int const kAccessSizeLog = 0;
+ Shadow cur(fast_state);
+ cur.SetWrite(is_write);
+ cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
+ shadow_mem, cur);
+ }
+ if (unaligned)
+ shadow_mem += kShadowCnt;
+ // Handle middle part, if any.
+ for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) {
+ int const kAccessSizeLog = 3;
+ Shadow cur(fast_state);
+ cur.SetWrite(is_write);
+ cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
+ shadow_mem, cur);
+ shadow_mem += kShadowCnt;
+ }
+ // Handle ending, if any.
+ for (; size; addr++, size--) {
+ int const kAccessSizeLog = 0;
+ Shadow cur(fast_state);
+ cur.SetWrite(is_write);
+ cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
+ shadow_mem, cur);
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cc
new file mode 100644
index 000000000000..ceca3f8e8738
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cc
@@ -0,0 +1,46 @@
+//===-- tsan_stack_trace.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_stack_trace.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+
+namespace __tsan {
+
+VarSizeStackTrace::VarSizeStackTrace()
+ : StackTrace(nullptr, 0), trace_buffer(nullptr) {}
+
+VarSizeStackTrace::~VarSizeStackTrace() {
+ ResizeBuffer(0);
+}
+
+void VarSizeStackTrace::ResizeBuffer(uptr new_size) {
+ if (trace_buffer) {
+ internal_free(trace_buffer);
+ }
+ trace_buffer =
+ (new_size > 0)
+ ? (uptr *)internal_alloc(MBlockStackTrace,
+ new_size * sizeof(trace_buffer[0]))
+ : nullptr;
+ trace = trace_buffer;
+ size = new_size;
+}
+
+void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+ ResizeBuffer(cnt + !!extra_top_pc);
+ internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+ if (extra_top_pc)
+ trace_buffer[cnt] = extra_top_pc;
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.h
new file mode 100644
index 000000000000..5bf89bb7584f
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_stack_trace.h
@@ -0,0 +1,39 @@
+//===-- tsan_stack_trace.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_STACK_TRACE_H
+#define TSAN_STACK_TRACE_H
+
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+// StackTrace which calls malloc/free to allocate the buffer for
+// addresses in stack traces.
+struct VarSizeStackTrace : public StackTrace {
+ uptr *trace_buffer; // Owned.
+
+ VarSizeStackTrace();
+ ~VarSizeStackTrace();
+ void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+
+ private:
+ void ResizeBuffer(uptr new_size);
+
+ VarSizeStackTrace(const VarSizeStackTrace &);
+ void operator=(const VarSizeStackTrace &);
+};
+
+} // namespace __tsan
+
+#endif // TSAN_STACK_TRACE_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc
new file mode 100644
index 000000000000..15fa43d6f8a1
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc
@@ -0,0 +1,178 @@
+//===-- tsan_stat.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_stat.h"
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+#if TSAN_COLLECT_STATS
+
+void StatAggregate(u64 *dst, u64 *src) {
+ for (int i = 0; i < StatCnt; i++)
+ dst[i] += src[i];
+}
+
+void StatOutput(u64 *stat) {
+ stat[StatShadowNonZero] = stat[StatShadowProcessed] - stat[StatShadowZero];
+
+ static const char *name[StatCnt] = {};
+ name[StatMop] = "Memory accesses ";
+ name[StatMopRead] = " Including reads ";
+ name[StatMopWrite] = " writes ";
+ name[StatMop1] = " Including size 1 ";
+ name[StatMop2] = " size 2 ";
+ name[StatMop4] = " size 4 ";
+ name[StatMop8] = " size 8 ";
+ name[StatMopSame] = " Including same ";
+ name[StatMopIgnored] = " Including ignored ";
+ name[StatMopRange] = " Including range ";
+ name[StatMopRodata] = " Including .rodata ";
+ name[StatMopRangeRodata] = " Including .rodata range ";
+ name[StatShadowProcessed] = "Shadow processed ";
+ name[StatShadowZero] = " Including empty ";
+ name[StatShadowNonZero] = " Including non empty ";
+ name[StatShadowSameSize] = " Including same size ";
+ name[StatShadowIntersect] = " intersect ";
+ name[StatShadowNotIntersect] = " not intersect ";
+ name[StatShadowSameThread] = " Including same thread ";
+ name[StatShadowAnotherThread] = " another thread ";
+ name[StatShadowReplace] = " Including evicted ";
+
+ name[StatFuncEnter] = "Function entries ";
+ name[StatFuncExit] = "Function exits ";
+ name[StatEvents] = "Events collected ";
+
+ name[StatThreadCreate] = "Total threads created ";
+ name[StatThreadFinish] = " threads finished ";
+ name[StatThreadReuse] = " threads reused ";
+ name[StatThreadMaxTid] = " max tid ";
+ name[StatThreadMaxAlive] = " max alive threads ";
+
+ name[StatMutexCreate] = "Mutexes created ";
+ name[StatMutexDestroy] = " destroyed ";
+ name[StatMutexLock] = " lock ";
+ name[StatMutexUnlock] = " unlock ";
+ name[StatMutexRecLock] = " recursive lock ";
+ name[StatMutexRecUnlock] = " recursive unlock ";
+ name[StatMutexReadLock] = " read lock ";
+ name[StatMutexReadUnlock] = " read unlock ";
+
+ name[StatSyncCreated] = "Sync objects created ";
+ name[StatSyncDestroyed] = " destroyed ";
+ name[StatSyncAcquire] = " acquired ";
+ name[StatSyncRelease] = " released ";
+
+ name[StatClockAcquire] = "Clock acquire ";
+ name[StatClockAcquireEmpty] = " empty clock ";
+ name[StatClockAcquireFastRelease] = " fast from release-store ";
+ name[StatClockAcquireLarge] = " contains my tid ";
+ name[StatClockAcquireRepeat] = " repeated (fast) ";
+ name[StatClockAcquireFull] = " full (slow) ";
+ name[StatClockAcquiredSomething] = " acquired something ";
+ name[StatClockRelease] = "Clock release ";
+ name[StatClockReleaseResize] = " resize ";
+ name[StatClockReleaseFast1] = " fast1 ";
+ name[StatClockReleaseFast2] = " fast2 ";
+ name[StatClockReleaseSlow] = " dirty overflow (slow) ";
+ name[StatClockReleaseFull] = " full (slow) ";
+ name[StatClockReleaseAcquired] = " was acquired ";
+ name[StatClockReleaseClearTail] = " clear tail ";
+ name[StatClockStore] = "Clock release store ";
+ name[StatClockStoreResize] = " resize ";
+ name[StatClockStoreFast] = " fast ";
+ name[StatClockStoreFull] = " slow ";
+ name[StatClockStoreTail] = " clear tail ";
+ name[StatClockAcquireRelease] = "Clock acquire-release ";
+
+ name[StatAtomic] = "Atomic operations ";
+ name[StatAtomicLoad] = " Including load ";
+ name[StatAtomicStore] = " store ";
+ name[StatAtomicExchange] = " exchange ";
+ name[StatAtomicFetchAdd] = " fetch_add ";
+ name[StatAtomicFetchSub] = " fetch_sub ";
+ name[StatAtomicFetchAnd] = " fetch_and ";
+ name[StatAtomicFetchOr] = " fetch_or ";
+ name[StatAtomicFetchXor] = " fetch_xor ";
+ name[StatAtomicFetchNand] = " fetch_nand ";
+ name[StatAtomicCAS] = " compare_exchange ";
+ name[StatAtomicFence] = " fence ";
+ name[StatAtomicRelaxed] = " Including relaxed ";
+ name[StatAtomicConsume] = " consume ";
+ name[StatAtomicAcquire] = " acquire ";
+ name[StatAtomicRelease] = " release ";
+ name[StatAtomicAcq_Rel] = " acq_rel ";
+ name[StatAtomicSeq_Cst] = " seq_cst ";
+ name[StatAtomic1] = " Including size 1 ";
+ name[StatAtomic2] = " size 2 ";
+ name[StatAtomic4] = " size 4 ";
+ name[StatAtomic8] = " size 8 ";
+ name[StatAtomic16] = " size 16 ";
+
+ name[StatAnnotation] = "Dynamic annotations ";
+ name[StatAnnotateHappensBefore] = " HappensBefore ";
+ name[StatAnnotateHappensAfter] = " HappensAfter ";
+ name[StatAnnotateCondVarSignal] = " CondVarSignal ";
+ name[StatAnnotateCondVarSignalAll] = " CondVarSignalAll ";
+ name[StatAnnotateMutexIsNotPHB] = " MutexIsNotPHB ";
+ name[StatAnnotateCondVarWait] = " CondVarWait ";
+ name[StatAnnotateRWLockCreate] = " RWLockCreate ";
+ name[StatAnnotateRWLockCreateStatic] = " StatAnnotateRWLockCreateStatic ";
+ name[StatAnnotateRWLockDestroy] = " RWLockDestroy ";
+ name[StatAnnotateRWLockAcquired] = " RWLockAcquired ";
+ name[StatAnnotateRWLockReleased] = " RWLockReleased ";
+ name[StatAnnotateTraceMemory] = " TraceMemory ";
+ name[StatAnnotateFlushState] = " FlushState ";
+ name[StatAnnotateNewMemory] = " NewMemory ";
+ name[StatAnnotateNoOp] = " NoOp ";
+ name[StatAnnotateFlushExpectedRaces] = " FlushExpectedRaces ";
+ name[StatAnnotateEnableRaceDetection] = " EnableRaceDetection ";
+ name[StatAnnotateMutexIsUsedAsCondVar] = " MutexIsUsedAsCondVar ";
+ name[StatAnnotatePCQGet] = " PCQGet ";
+ name[StatAnnotatePCQPut] = " PCQPut ";
+ name[StatAnnotatePCQDestroy] = " PCQDestroy ";
+ name[StatAnnotatePCQCreate] = " PCQCreate ";
+ name[StatAnnotateExpectRace] = " ExpectRace ";
+ name[StatAnnotateBenignRaceSized] = " BenignRaceSized ";
+ name[StatAnnotateBenignRace] = " BenignRace ";
+ name[StatAnnotateIgnoreReadsBegin] = " IgnoreReadsBegin ";
+ name[StatAnnotateIgnoreReadsEnd] = " IgnoreReadsEnd ";
+ name[StatAnnotateIgnoreWritesBegin] = " IgnoreWritesBegin ";
+ name[StatAnnotateIgnoreWritesEnd] = " IgnoreWritesEnd ";
+ name[StatAnnotateIgnoreSyncBegin] = " IgnoreSyncBegin ";
+ name[StatAnnotateIgnoreSyncEnd] = " IgnoreSyncEnd ";
+ name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange ";
+ name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange ";
+ name[StatAnnotateThreadName] = " ThreadName ";
+
+ name[StatMtxTotal] = "Contentionz ";
+ name[StatMtxTrace] = " Trace ";
+ name[StatMtxThreads] = " Threads ";
+ name[StatMtxReport] = " Report ";
+ name[StatMtxSyncVar] = " SyncVar ";
+ name[StatMtxSyncTab] = " SyncTab ";
+ name[StatMtxSlab] = " Slab ";
+ name[StatMtxAtExit] = " Atexit ";
+ name[StatMtxAnnotations] = " Annotations ";
+ name[StatMtxMBlock] = " MBlock ";
+ name[StatMtxJavaMBlock] = " JavaMBlock ";
+ name[StatMtxDeadlockDetector] = " DeadlockDetector ";
+ name[StatMtxFD] = " FD ";
+
+ Printf("Statistics:\n");
+ for (int i = 0; i < StatCnt; i++)
+ Printf("%s: %16zu\n", name[i], (uptr)stat[i]);
+}
+
+#endif
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h
new file mode 100644
index 000000000000..0bd949ed1563
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h
@@ -0,0 +1,182 @@
+//===-- tsan_stat.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TSAN_STAT_H
+#define TSAN_STAT_H
+
+namespace __tsan {
+
+enum StatType {
+ // Memory access processing related stuff.
+ StatMop,
+ StatMopRead,
+ StatMopWrite,
+ StatMop1, // These must be consequtive.
+ StatMop2,
+ StatMop4,
+ StatMop8,
+ StatMopSame,
+ StatMopIgnored,
+ StatMopRange,
+ StatMopRodata,
+ StatMopRangeRodata,
+ StatShadowProcessed,
+ StatShadowZero,
+ StatShadowNonZero, // Derived.
+ StatShadowSameSize,
+ StatShadowIntersect,
+ StatShadowNotIntersect,
+ StatShadowSameThread,
+ StatShadowAnotherThread,
+ StatShadowReplace,
+
+ // Func processing.
+ StatFuncEnter,
+ StatFuncExit,
+
+ // Trace processing.
+ StatEvents,
+
+ // Threads.
+ StatThreadCreate,
+ StatThreadFinish,
+ StatThreadReuse,
+ StatThreadMaxTid,
+ StatThreadMaxAlive,
+
+ // Mutexes.
+ StatMutexCreate,
+ StatMutexDestroy,
+ StatMutexLock,
+ StatMutexUnlock,
+ StatMutexRecLock,
+ StatMutexRecUnlock,
+ StatMutexReadLock,
+ StatMutexReadUnlock,
+
+ // Synchronization.
+ StatSyncCreated,
+ StatSyncDestroyed,
+ StatSyncAcquire,
+ StatSyncRelease,
+
+ // Clocks - acquire.
+ StatClockAcquire,
+ StatClockAcquireEmpty,
+ StatClockAcquireFastRelease,
+ StatClockAcquireLarge,
+ StatClockAcquireRepeat,
+ StatClockAcquireFull,
+ StatClockAcquiredSomething,
+ // Clocks - release.
+ StatClockRelease,
+ StatClockReleaseResize,
+ StatClockReleaseFast1,
+ StatClockReleaseFast2,
+ StatClockReleaseSlow,
+ StatClockReleaseFull,
+ StatClockReleaseAcquired,
+ StatClockReleaseClearTail,
+ // Clocks - release store.
+ StatClockStore,
+ StatClockStoreResize,
+ StatClockStoreFast,
+ StatClockStoreFull,
+ StatClockStoreTail,
+ // Clocks - acquire-release.
+ StatClockAcquireRelease,
+
+ // Atomics.
+ StatAtomic,
+ StatAtomicLoad,
+ StatAtomicStore,
+ StatAtomicExchange,
+ StatAtomicFetchAdd,
+ StatAtomicFetchSub,
+ StatAtomicFetchAnd,
+ StatAtomicFetchOr,
+ StatAtomicFetchXor,
+ StatAtomicFetchNand,
+ StatAtomicCAS,
+ StatAtomicFence,
+ StatAtomicRelaxed,
+ StatAtomicConsume,
+ StatAtomicAcquire,
+ StatAtomicRelease,
+ StatAtomicAcq_Rel,
+ StatAtomicSeq_Cst,
+ StatAtomic1,
+ StatAtomic2,
+ StatAtomic4,
+ StatAtomic8,
+ StatAtomic16,
+
+ // Dynamic annotations.
+ StatAnnotation,
+ StatAnnotateHappensBefore,
+ StatAnnotateHappensAfter,
+ StatAnnotateCondVarSignal,
+ StatAnnotateCondVarSignalAll,
+ StatAnnotateMutexIsNotPHB,
+ StatAnnotateCondVarWait,
+ StatAnnotateRWLockCreate,
+ StatAnnotateRWLockCreateStatic,
+ StatAnnotateRWLockDestroy,
+ StatAnnotateRWLockAcquired,
+ StatAnnotateRWLockReleased,
+ StatAnnotateTraceMemory,
+ StatAnnotateFlushState,
+ StatAnnotateNewMemory,
+ StatAnnotateNoOp,
+ StatAnnotateFlushExpectedRaces,
+ StatAnnotateEnableRaceDetection,
+ StatAnnotateMutexIsUsedAsCondVar,
+ StatAnnotatePCQGet,
+ StatAnnotatePCQPut,
+ StatAnnotatePCQDestroy,
+ StatAnnotatePCQCreate,
+ StatAnnotateExpectRace,
+ StatAnnotateBenignRaceSized,
+ StatAnnotateBenignRace,
+ StatAnnotateIgnoreReadsBegin,
+ StatAnnotateIgnoreReadsEnd,
+ StatAnnotateIgnoreWritesBegin,
+ StatAnnotateIgnoreWritesEnd,
+ StatAnnotateIgnoreSyncBegin,
+ StatAnnotateIgnoreSyncEnd,
+ StatAnnotatePublishMemoryRange,
+ StatAnnotateUnpublishMemoryRange,
+ StatAnnotateThreadName,
+
+ // Internal mutex contentionz.
+ StatMtxTotal,
+ StatMtxTrace,
+ StatMtxThreads,
+ StatMtxReport,
+ StatMtxSyncVar,
+ StatMtxSyncTab,
+ StatMtxSlab,
+ StatMtxAnnotations,
+ StatMtxAtExit,
+ StatMtxMBlock,
+ StatMtxJavaMBlock,
+ StatMtxDeadlockDetector,
+ StatMtxFD,
+
+ // This must be the last.
+ StatCnt
+};
+
+} // namespace __tsan
+
+#endif // TSAN_STAT_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
new file mode 100644
index 000000000000..5413f04af1d2
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
@@ -0,0 +1,157 @@
+//===-- tsan_suppressions.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "tsan_suppressions.h"
+#include "tsan_rtl.h"
+#include "tsan_flags.h"
+#include "tsan_mman.h"
+#include "tsan_platform.h"
+
+// Suppressions for true/false positives in standard libraries.
+static const char *const std_suppressions =
+// Libstdc++ 4.4 has data races in std::string.
+// See http://crbug.com/181502 for an example.
+"race:^_M_rep$\n"
+"race:^_M_is_leaked$\n"
+// False positive when using std <thread>.
+// Happens because we miss atomic synchronization in libstdc++.
+// See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
+"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
+
+// Can be overriden in frontend.
+#ifndef SANITIZER_GO
+extern "C" const char *WEAK __tsan_default_suppressions() {
+ return 0;
+}
+#endif
+
+namespace __tsan {
+
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char *kSuppressionTypes[] = {
+ kSuppressionRace, kSuppressionMutex, kSuppressionThread,
+ kSuppressionSignal, kSuppressionLib, kSuppressionDeadlock};
+
+void InitializeSuppressions() {
+ CHECK_EQ(nullptr, suppression_ctx);
+ suppression_ctx = new (suppression_placeholder) // NOLINT
+ SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+ suppression_ctx->ParseFromFile(flags()->suppressions);
+#ifndef SANITIZER_GO
+ suppression_ctx->Parse(__tsan_default_suppressions());
+ suppression_ctx->Parse(std_suppressions);
+#endif
+}
+
+SuppressionContext *Suppressions() {
+ CHECK(suppression_ctx);
+ return suppression_ctx;
+}
+
+static const char *conv(ReportType typ) {
+ if (typ == ReportTypeRace)
+ return kSuppressionRace;
+ else if (typ == ReportTypeVptrRace)
+ return kSuppressionRace;
+ else if (typ == ReportTypeUseAfterFree)
+ return kSuppressionRace;
+ else if (typ == ReportTypeVptrUseAfterFree)
+ return kSuppressionRace;
+ else if (typ == ReportTypeThreadLeak)
+ return kSuppressionThread;
+ else if (typ == ReportTypeMutexDestroyLocked)
+ return kSuppressionMutex;
+ else if (typ == ReportTypeMutexDoubleLock)
+ return kSuppressionMutex;
+ else if (typ == ReportTypeMutexBadUnlock)
+ return kSuppressionMutex;
+ else if (typ == ReportTypeMutexBadReadLock)
+ return kSuppressionMutex;
+ else if (typ == ReportTypeMutexBadReadUnlock)
+ return kSuppressionMutex;
+ else if (typ == ReportTypeSignalUnsafe)
+ return kSuppressionSignal;
+ else if (typ == ReportTypeErrnoInSignal)
+ return kSuppressionNone;
+ else if (typ == ReportTypeDeadlock)
+ return kSuppressionDeadlock;
+ Printf("ThreadSanitizer: unknown report type %d\n", typ),
+ Die();
+}
+
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
+ CHECK(suppression_ctx);
+ if (!suppression_ctx->SuppressionCount() || stack == 0 ||
+ !stack->suppressable)
+ return 0;
+ const char *stype = conv(typ);
+ if (0 == internal_strcmp(stype, kSuppressionNone))
+ return 0;
+ Suppression *s;
+ for (const SymbolizedStack *frame = stack->frames; frame;
+ frame = frame->next) {
+ const AddressInfo &info = frame->info;
+ if (suppression_ctx->Match(info.function, stype, &s) ||
+ suppression_ctx->Match(info.file, stype, &s) ||
+ suppression_ctx->Match(info.module, stype, &s)) {
+ DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+ s->hit_count++;
+ *sp = s;
+ return info.address;
+ }
+ }
+ return 0;
+}
+
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
+ CHECK(suppression_ctx);
+ if (!suppression_ctx->SuppressionCount() || loc == 0 ||
+ loc->type != ReportLocationGlobal || !loc->suppressable)
+ return 0;
+ const char *stype = conv(typ);
+ if (0 == internal_strcmp(stype, kSuppressionNone))
+ return 0;
+ Suppression *s;
+ const DataInfo &global = loc->global;
+ if (suppression_ctx->Match(global.name, stype, &s) ||
+ suppression_ctx->Match(global.module, stype, &s)) {
+ DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+ s->hit_count++;
+ *sp = s;
+ return global.start;
+ }
+ return 0;
+}
+
+void PrintMatchedSuppressions() {
+ InternalMmapVector<Suppression *> matched(1);
+ CHECK(suppression_ctx);
+ suppression_ctx->GetMatched(&matched);
+ if (!matched.size())
+ return;
+ int hit_count = 0;
+ for (uptr i = 0; i < matched.size(); i++)
+ hit_count += matched[i]->hit_count;
+ Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
+ (int)internal_getpid());
+ for (uptr i = 0; i < matched.size(); i++) {
+ Printf("%d %s:%s\n", matched[i]->hit_count, matched[i]->type,
+ matched[i]->templ);
+ }
+}
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h
new file mode 100644
index 000000000000..e6d279c33a4e
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h
@@ -0,0 +1,37 @@
+//===-- tsan_suppressions.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_SUPPRESSIONS_H
+#define TSAN_SUPPRESSIONS_H
+
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "tsan_report.h"
+
+namespace __tsan {
+
+const char kSuppressionNone[] = "none";
+const char kSuppressionRace[] = "race";
+const char kSuppressionMutex[] = "mutex";
+const char kSuppressionThread[] = "thread";
+const char kSuppressionSignal[] = "signal";
+const char kSuppressionLib[] = "called_from_lib";
+const char kSuppressionDeadlock[] = "deadlock";
+
+void InitializeSuppressions();
+SuppressionContext *Suppressions();
+void PrintMatchedSuppressions();
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
+
+} // namespace __tsan
+
+#endif // TSAN_SUPPRESSIONS_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc
new file mode 100644
index 000000000000..3beb44f7ad3b
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc
@@ -0,0 +1,88 @@
+//===-- tsan_symbolize.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_symbolize.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "tsan_flags.h"
+#include "tsan_report.h"
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+void EnterSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(!thr->in_symbolizer);
+ thr->in_symbolizer = true;
+ thr->ignore_interceptors++;
+}
+
+void ExitSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(thr->in_symbolizer);
+ thr->in_symbolizer = false;
+ thr->ignore_interceptors--;
+}
+
+// May be overriden by JIT/JAVA/etc,
+// whatever produces PCs marked with kExternalPCBit.
+extern "C" bool __tsan_symbolize_external(uptr pc,
+ char *func_buf, uptr func_siz,
+ char *file_buf, uptr file_siz,
+ int *line, int *col)
+ SANITIZER_WEAK_ATTRIBUTE;
+
+bool __tsan_symbolize_external(uptr pc,
+ char *func_buf, uptr func_siz,
+ char *file_buf, uptr file_siz,
+ int *line, int *col) {
+ return false;
+}
+
+SymbolizedStack *SymbolizeCode(uptr addr) {
+ // Check if PC comes from non-native land.
+ if (addr & kExternalPCBit) {
+ // Declare static to not consume too much stack space.
+ // We symbolize reports in a single thread, so this is fine.
+ static char func_buf[1024];
+ static char file_buf[1024];
+ int line, col;
+ SymbolizedStack *frame = SymbolizedStack::New(addr);
+ if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf,
+ sizeof(file_buf), &line, &col)) {
+ frame->info.function = internal_strdup(func_buf);
+ frame->info.file = internal_strdup(file_buf);
+ frame->info.line = line;
+ frame->info.column = col;
+ }
+ return frame;
+ }
+ return Symbolizer::GetOrInit()->SymbolizePC(addr);
+}
+
+ReportLocation *SymbolizeData(uptr addr) {
+ DataInfo info;
+ if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
+ return 0;
+ ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
+ ent->global = info;
+ return ent;
+}
+
+void SymbolizeFlush() {
+ Symbolizer::GetOrInit()->Flush();
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.h
new file mode 100644
index 000000000000..b59b6cfb8341
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.h
@@ -0,0 +1,35 @@
+//===-- tsan_symbolize.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_SYMBOLIZE_H
+#define TSAN_SYMBOLIZE_H
+
+#include "tsan_defs.h"
+#include "tsan_report.h"
+
+namespace __tsan {
+
+// Denotes fake PC values that come from JIT/JAVA/etc.
+// For such PC values __tsan_symbolize_external() will be called.
+const uptr kExternalPCBit = 1ULL << 60;
+
+void EnterSymbolizer();
+void ExitSymbolizer();
+SymbolizedStack *SymbolizeCode(uptr addr);
+ReportLocation *SymbolizeData(uptr addr);
+void SymbolizeFlush();
+
+ReportStack *NewReportStackEntry(uptr addr);
+
+} // namespace __tsan
+
+#endif // TSAN_SYMBOLIZE_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.cc
new file mode 100644
index 000000000000..1041073bed51
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.cc
@@ -0,0 +1,225 @@
+//===-- tsan_sync.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "tsan_sync.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+
+namespace __tsan {
+
+void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);
+
+SyncVar::SyncVar()
+ : mtx(MutexTypeSyncVar, StatMtxSyncVar) {
+ Reset(0);
+}
+
+void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) {
+ this->addr = addr;
+ this->uid = uid;
+ this->next = 0;
+
+ creation_stack_id = 0;
+ if (kCppMode) // Go does not use them
+ creation_stack_id = CurrentStackId(thr, pc);
+ if (common_flags()->detect_deadlocks)
+ DDMutexInit(thr, pc, this);
+}
+
+void SyncVar::Reset(ThreadState *thr) {
+ uid = 0;
+ creation_stack_id = 0;
+ owner_tid = kInvalidTid;
+ last_lock = 0;
+ recursion = 0;
+ is_rw = 0;
+ is_recursive = 0;
+ is_broken = 0;
+ is_linker_init = 0;
+
+ if (thr == 0) {
+ CHECK_EQ(clock.size(), 0);
+ CHECK_EQ(read_clock.size(), 0);
+ } else {
+ clock.Reset(&thr->clock_cache);
+ read_clock.Reset(&thr->clock_cache);
+ }
+}
+
+MetaMap::MetaMap() {
+ atomic_store(&uid_gen_, 0, memory_order_relaxed);
+}
+
+void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+ u32 idx = block_alloc_.Alloc(&thr->block_cache);
+ MBlock *b = block_alloc_.Map(idx);
+ b->siz = sz;
+ b->tid = thr->tid;
+ b->stk = CurrentStackId(thr, pc);
+ u32 *meta = MemToMeta(p);
+ DCHECK_EQ(*meta, 0);
+ *meta = idx | kFlagBlock;
+}
+
+uptr MetaMap::FreeBlock(ThreadState *thr, uptr pc, uptr p) {
+ MBlock* b = GetBlock(p);
+ if (b == 0)
+ return 0;
+ uptr sz = RoundUpTo(b->siz, kMetaShadowCell);
+ FreeRange(thr, pc, p, sz);
+ return sz;
+}
+
+void MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+ u32 *meta = MemToMeta(p);
+ u32 *end = MemToMeta(p + sz);
+ if (end == meta)
+ end++;
+ for (; meta < end; meta++) {
+ u32 idx = *meta;
+ *meta = 0;
+ for (;;) {
+ if (idx == 0)
+ break;
+ if (idx & kFlagBlock) {
+ block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
+ break;
+ } else if (idx & kFlagSync) {
+ DCHECK(idx & kFlagSync);
+ SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
+ u32 next = s->next;
+ s->Reset(thr);
+ sync_alloc_.Free(&thr->sync_cache, idx & ~kFlagMask);
+ idx = next;
+ } else {
+ CHECK(0);
+ }
+ }
+ }
+}
+
+MBlock* MetaMap::GetBlock(uptr p) {
+ u32 *meta = MemToMeta(p);
+ u32 idx = *meta;
+ for (;;) {
+ if (idx == 0)
+ return 0;
+ if (idx & kFlagBlock)
+ return block_alloc_.Map(idx & ~kFlagMask);
+ DCHECK(idx & kFlagSync);
+ SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
+ idx = s->next;
+ }
+}
+
+SyncVar* MetaMap::GetOrCreateAndLock(ThreadState *thr, uptr pc,
+ uptr addr, bool write_lock) {
+ return GetAndLock(thr, pc, addr, write_lock, true);
+}
+
+SyncVar* MetaMap::GetIfExistsAndLock(uptr addr) {
+ return GetAndLock(0, 0, addr, true, false);
+}
+
+SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
+ uptr addr, bool write_lock, bool create) {
+ u32 *meta = MemToMeta(addr);
+ u32 idx0 = *meta;
+ u32 myidx = 0;
+ SyncVar *mys = 0;
+ for (;;) {
+ u32 idx = idx0;
+ for (;;) {
+ if (idx == 0)
+ break;
+ if (idx & kFlagBlock)
+ break;
+ DCHECK(idx & kFlagSync);
+ SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
+ if (s->addr == addr) {
+ if (myidx != 0) {
+ mys->Reset(thr);
+ sync_alloc_.Free(&thr->sync_cache, myidx);
+ }
+ if (write_lock)
+ s->mtx.Lock();
+ else
+ s->mtx.ReadLock();
+ return s;
+ }
+ idx = s->next;
+ }
+ if (!create)
+ return 0;
+ if (*meta != idx0) {
+ idx0 = *meta;
+ continue;
+ }
+
+ if (myidx == 0) {
+ const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
+ myidx = sync_alloc_.Alloc(&thr->sync_cache);
+ mys = sync_alloc_.Map(myidx);
+ mys->Init(thr, pc, addr, uid);
+ }
+ mys->next = idx0;
+ if (atomic_compare_exchange_strong((atomic_uint32_t*)meta, &idx0,
+ myidx | kFlagSync, memory_order_release)) {
+ if (write_lock)
+ mys->mtx.Lock();
+ else
+ mys->mtx.ReadLock();
+ return mys;
+ }
+ }
+}
+
+void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
+ // src and dst can overlap,
+ // there are no concurrent accesses to the regions (e.g. stop-the-world).
+ CHECK_NE(src, dst);
+ CHECK_NE(sz, 0);
+ uptr diff = dst - src;
+ u32 *src_meta = MemToMeta(src);
+ u32 *dst_meta = MemToMeta(dst);
+ u32 *src_meta_end = MemToMeta(src + sz);
+ uptr inc = 1;
+ if (dst > src) {
+ src_meta = MemToMeta(src + sz) - 1;
+ dst_meta = MemToMeta(dst + sz) - 1;
+ src_meta_end = MemToMeta(src) - 1;
+ inc = -1;
+ }
+ for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) {
+ CHECK_EQ(*dst_meta, 0);
+ u32 idx = *src_meta;
+ *src_meta = 0;
+ *dst_meta = idx;
+ // Patch the addresses in sync objects.
+ while (idx != 0) {
+ if (idx & kFlagBlock)
+ break;
+ CHECK(idx & kFlagSync);
+ SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
+ s->addr += diff;
+ idx = s->next;
+ }
+ }
+}
+
+void MetaMap::OnThreadIdle(ThreadState *thr) {
+ block_alloc_.FlushCache(&thr->block_cache);
+ sync_alloc_.FlushCache(&thr->sync_cache);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h
new file mode 100644
index 000000000000..574810d8a542
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h
@@ -0,0 +1,103 @@
+//===-- tsan_sync.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_SYNC_H
+#define TSAN_SYNC_H
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "tsan_defs.h"
+#include "tsan_clock.h"
+#include "tsan_mutex.h"
+#include "tsan_dense_alloc.h"
+
+namespace __tsan {
+
+struct SyncVar {
+ SyncVar();
+
+ static const int kInvalidTid = -1;
+
+ uptr addr; // overwritten by DenseSlabAlloc freelist
+ Mutex mtx;
+ u64 uid; // Globally unique id.
+ u32 creation_stack_id;
+ int owner_tid; // Set only by exclusive owners.
+ u64 last_lock;
+ int recursion;
+ bool is_rw;
+ bool is_recursive;
+ bool is_broken;
+ bool is_linker_init;
+ u32 next; // in MetaMap
+ DDMutex dd;
+ SyncClock read_clock; // Used for rw mutexes only.
+ // The clock is placed last, so that it is situated on a different cache line
+ // with the mtx. This reduces contention for hot sync objects.
+ SyncClock clock;
+
+ void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid);
+ void Reset(ThreadState *thr);
+
+ u64 GetId() const {
+ // 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits.
+ return GetLsb((u64)addr | (uid << 47), 61);
+ }
+ bool CheckId(u64 uid) const {
+ CHECK_EQ(uid, GetLsb(uid, 14));
+ return GetLsb(this->uid, 14) == uid;
+ }
+ static uptr SplitId(u64 id, u64 *uid) {
+ *uid = id >> 47;
+ return (uptr)GetLsb(id, 47);
+ }
+};
+
+/* MetaMap allows to map arbitrary user pointers onto various descriptors.
+ Currently it maps pointers to heap block descriptors and sync var descs.
+ It uses 1/2 direct shadow, see tsan_platform.h.
+*/
+class MetaMap {
+ public:
+ MetaMap();
+
+ void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz);
+ uptr FreeBlock(ThreadState *thr, uptr pc, uptr p);
+ void FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
+ MBlock* GetBlock(uptr p);
+
+ SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc,
+ uptr addr, bool write_lock);
+ SyncVar* GetIfExistsAndLock(uptr addr);
+
+ void MoveMemory(uptr src, uptr dst, uptr sz);
+
+ void OnThreadIdle(ThreadState *thr);
+
+ private:
+ static const u32 kFlagMask = 3 << 30;
+ static const u32 kFlagBlock = 1 << 30;
+ static const u32 kFlagSync = 2 << 30;
+ typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
+ typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
+ BlockAlloc block_alloc_;
+ SyncAlloc sync_alloc_;
+ atomic_uint64_t uid_gen_;
+
+ SyncVar* GetAndLock(ThreadState *thr, uptr pc, uptr addr, bool write_lock,
+ bool create);
+};
+
+} // namespace __tsan
+
+#endif // TSAN_SYNC_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h
new file mode 100644
index 000000000000..2569c7e42a47
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h
@@ -0,0 +1,74 @@
+//===-- tsan_trace.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_TRACE_H
+#define TSAN_TRACE_H
+
+#include "tsan_defs.h"
+#include "tsan_mutex.h"
+#include "tsan_stack_trace.h"
+#include "tsan_mutexset.h"
+
+namespace __tsan {
+
+const int kTracePartSizeBits = 13;
+const int kTracePartSize = 1 << kTracePartSizeBits;
+const int kTraceParts = 2 * 1024 * 1024 / kTracePartSize;
+const int kTraceSize = kTracePartSize * kTraceParts;
+
+// Must fit into 3 bits.
+enum EventType {
+ EventTypeMop,
+ EventTypeFuncEnter,
+ EventTypeFuncExit,
+ EventTypeLock,
+ EventTypeUnlock,
+ EventTypeRLock,
+ EventTypeRUnlock
+};
+
+// Represents a thread event (from most significant bit):
+// u64 typ : 3; // EventType.
+// u64 addr : 61; // Associated pc.
+typedef u64 Event;
+
+struct TraceHeader {
+#ifndef SANITIZER_GO
+ BufferedStackTrace stack0; // Start stack for the trace.
+#else
+ VarSizeStackTrace stack0;
+#endif
+ u64 epoch0; // Start epoch for the trace.
+ MutexSet mset0;
+
+ TraceHeader() : stack0(), epoch0() {}
+};
+
+struct Trace {
+ Mutex mtx;
+#ifndef SANITIZER_GO
+ // Must be last to catch overflow as paging fault.
+ // Go shadow stack is dynamically allocated.
+ uptr shadow_stack[kShadowStackSize];
+#endif
+ // Must be the last field, because we unmap the unused part in
+ // CreateThreadContext.
+ TraceHeader headers[kTraceParts];
+
+ Trace()
+ : mtx(MutexTypeTrace, StatMtxTrace) {
+ }
+};
+
+} // namespace __tsan
+
+#endif // TSAN_TRACE_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_update_shadow_word_inl.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_update_shadow_word_inl.h
new file mode 100644
index 000000000000..c80e0a88d0eb
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_update_shadow_word_inl.h
@@ -0,0 +1,65 @@
+//===-- tsan_update_shadow_word_inl.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 ThreadSanitizer (TSan), a race detector.
+//
+// Body of the hottest inner loop.
+// If we wrap this body into a function, compilers (both gcc and clang)
+// produce sligtly less efficient code.
+//===----------------------------------------------------------------------===//
+do {
+ StatInc(thr, StatShadowProcessed);
+ const unsigned kAccessSize = 1 << kAccessSizeLog;
+ u64 *sp = &shadow_mem[idx];
+ old = LoadShadow(sp);
+ if (old.IsZero()) {
+ StatInc(thr, StatShadowZero);
+ if (store_word)
+ StoreIfNotYetStored(sp, &store_word);
+ // The above StoreIfNotYetStored could be done unconditionally
+ // and it even shows 4% gain on synthetic benchmarks (r4307).
+ break;
+ }
+ // is the memory access equal to the previous?
+ if (Shadow::Addr0AndSizeAreEqual(cur, old)) {
+ StatInc(thr, StatShadowSameSize);
+ // same thread?
+ if (Shadow::TidsAreEqual(old, cur)) {
+ StatInc(thr, StatShadowSameThread);
+ if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
+ StoreIfNotYetStored(sp, &store_word);
+ break;
+ }
+ StatInc(thr, StatShadowAnotherThread);
+ if (HappensBefore(old, thr)) {
+ StoreIfNotYetStored(sp, &store_word);
+ break;
+ }
+ if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
+ break;
+ goto RACE;
+ }
+ // Do the memory access intersect?
+ if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+ StatInc(thr, StatShadowIntersect);
+ if (Shadow::TidsAreEqual(old, cur)) {
+ StatInc(thr, StatShadowSameThread);
+ break;
+ }
+ StatInc(thr, StatShadowAnotherThread);
+ if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
+ break;
+ if (HappensBefore(old, thr))
+ break;
+ goto RACE;
+ }
+ // The accesses do not intersect.
+ StatInc(thr, StatShadowNotIntersect);
+ break;
+} while (0);
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_vector.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_vector.h
new file mode 100644
index 000000000000..a7fb3fa58d54
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_vector.h
@@ -0,0 +1,127 @@
+//===-- tsan_vector.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+// Low-fat STL-like vector container.
+
+#ifndef TSAN_VECTOR_H
+#define TSAN_VECTOR_H
+
+#include "tsan_defs.h"
+#include "tsan_mman.h"
+
+namespace __tsan {
+
+template<typename T>
+class Vector {
+ public:
+ explicit Vector(MBlockType typ)
+ : typ_(typ)
+ , begin_()
+ , end_()
+ , last_() {
+ }
+
+ ~Vector() {
+ if (begin_)
+ internal_free(begin_);
+ }
+
+ void Reset() {
+ if (begin_)
+ internal_free(begin_);
+ begin_ = 0;
+ end_ = 0;
+ last_ = 0;
+ }
+
+ uptr Size() const {
+ return end_ - begin_;
+ }
+
+ T &operator[](uptr i) {
+ DCHECK_LT(i, end_ - begin_);
+ return begin_[i];
+ }
+
+ const T &operator[](uptr i) const {
+ DCHECK_LT(i, end_ - begin_);
+ return begin_[i];
+ }
+
+ T *PushBack() {
+ EnsureSize(Size() + 1);
+ T *p = &end_[-1];
+ internal_memset(p, 0, sizeof(*p));
+ return p;
+ }
+
+ T *PushBack(const T& v) {
+ EnsureSize(Size() + 1);
+ T *p = &end_[-1];
+ internal_memcpy(p, &v, sizeof(*p));
+ return p;
+ }
+
+ void PopBack() {
+ DCHECK_GT(end_, begin_);
+ end_--;
+ }
+
+ void Resize(uptr size) {
+ if (size == 0) {
+ end_ = begin_;
+ return;
+ }
+ uptr old_size = Size();
+ EnsureSize(size);
+ if (old_size < size) {
+ for (uptr i = old_size; i < size; i++)
+ internal_memset(&begin_[i], 0, sizeof(begin_[i]));
+ }
+ }
+
+ private:
+ const MBlockType typ_;
+ T *begin_;
+ T *end_;
+ T *last_;
+
+ void EnsureSize(uptr size) {
+ if (size <= Size())
+ return;
+ if (size <= (uptr)(last_ - begin_)) {
+ end_ = begin_ + size;
+ return;
+ }
+ uptr cap0 = last_ - begin_;
+ uptr cap = cap0 * 5 / 4; // 25% growth
+ if (cap == 0)
+ cap = 16;
+ if (cap < size)
+ cap = size;
+ T *p = (T*)internal_alloc(typ_, cap * sizeof(T));
+ if (cap0) {
+ internal_memcpy(p, begin_, cap0 * sizeof(T));
+ internal_free(begin_);
+ }
+ begin_ = p;
+ end_ = begin_ + size;
+ last_ = begin_ + cap;
+ }
+
+ Vector(const Vector&);
+ void operator=(const Vector&);
+};
+} // namespace __tsan
+
+#endif // #ifndef TSAN_VECTOR_H
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc
new file mode 100644
index 000000000000..a3cf22f2c626
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc
@@ -0,0 +1,105 @@
+//===-- tsan_bench.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_test_util.h"
+#include "tsan_interface.h"
+#include "tsan_defs.h"
+#include "gtest/gtest.h"
+#include <stdint.h>
+
+const int kSize = 128;
+const int kRepeat = 2*1024*1024;
+
+void noinstr(void *p) {}
+
+template<typename T, void(*__tsan_mop)(void *p)>
+static void Benchmark() {
+ volatile T data[kSize];
+ for (int i = 0; i < kRepeat; i++) {
+ for (int j = 0; j < kSize; j++) {
+ __tsan_mop((void*)&data[j]);
+ data[j]++;
+ }
+ }
+}
+
+TEST(DISABLED_BENCH, Mop1) {
+ Benchmark<uint8_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop1Read) {
+ Benchmark<uint8_t, __tsan_read1>();
+}
+
+TEST(DISABLED_BENCH, Mop1Write) {
+ Benchmark<uint8_t, __tsan_write1>();
+}
+
+TEST(DISABLED_BENCH, Mop2) {
+ Benchmark<uint16_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop2Read) {
+ Benchmark<uint16_t, __tsan_read2>();
+}
+
+TEST(DISABLED_BENCH, Mop2Write) {
+ Benchmark<uint16_t, __tsan_write2>();
+}
+
+TEST(DISABLED_BENCH, Mop4) {
+ Benchmark<uint32_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop4Read) {
+ Benchmark<uint32_t, __tsan_read4>();
+}
+
+TEST(DISABLED_BENCH, Mop4Write) {
+ Benchmark<uint32_t, __tsan_write4>();
+}
+
+TEST(DISABLED_BENCH, Mop8) {
+ Benchmark<uint8_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop8Read) {
+ Benchmark<uint64_t, __tsan_read8>();
+}
+
+TEST(DISABLED_BENCH, Mop8Write) {
+ Benchmark<uint64_t, __tsan_write8>();
+}
+
+TEST(DISABLED_BENCH, FuncCall) {
+ for (int i = 0; i < kRepeat; i++) {
+ for (int j = 0; j < kSize; j++)
+ __tsan_func_entry((void*)(uintptr_t)j);
+ for (int j = 0; j < kSize; j++)
+ __tsan_func_exit();
+ }
+}
+
+TEST(DISABLED_BENCH, MutexLocal) {
+ Mutex m;
+ ScopedThread().Create(m);
+ for (int i = 0; i < 50; i++) {
+ ScopedThread t;
+ t.Lock(m);
+ t.Unlock(m);
+ }
+ for (int i = 0; i < 16*1024*1024; i++) {
+ m.Lock();
+ m.Unlock();
+ }
+ ScopedThread().Destroy(m);
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc
new file mode 100644
index 000000000000..f21742825050
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc
@@ -0,0 +1,233 @@
+//===-- tsan_mop.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <stddef.h>
+#include <stdint.h>
+
+TEST(ThreadSanitizer, SimpleWrite) {
+ ScopedThread t;
+ MemLoc l;
+ t.Write1(l);
+}
+
+TEST(ThreadSanitizer, SimpleWriteWrite) {
+ ScopedThread t1, t2;
+ MemLoc l1, l2;
+ t1.Write1(l1);
+ t2.Write1(l2);
+}
+
+TEST(ThreadSanitizer, WriteWriteRace) {
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Write1(l);
+ t2.Write1(l, true);
+}
+
+TEST(ThreadSanitizer, ReadWriteRace) {
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Read1(l);
+ t2.Write1(l, true);
+}
+
+TEST(ThreadSanitizer, WriteReadRace) {
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Write1(l);
+ t2.Read1(l, true);
+}
+
+TEST(ThreadSanitizer, ReadReadNoRace) {
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Read1(l);
+ t2.Read1(l);
+}
+
+TEST(ThreadSanitizer, WriteThenRead) {
+ MemLoc l;
+ ScopedThread t1, t2;
+ t1.Write1(l);
+ t1.Read1(l);
+ t2.Read1(l, true);
+}
+
+TEST(ThreadSanitizer, WriteThenLockedRead) {
+ Mutex m(Mutex::RW);
+ MainThread t0;
+ t0.Create(m);
+ MemLoc l;
+ {
+ ScopedThread t1, t2;
+
+ t1.Write8(l);
+
+ t1.Lock(m);
+ t1.Read8(l);
+ t1.Unlock(m);
+
+ t2.Read8(l, true);
+ }
+ t0.Destroy(m);
+}
+
+TEST(ThreadSanitizer, LockedWriteThenRead) {
+ Mutex m(Mutex::RW);
+ MainThread t0;
+ t0.Create(m);
+ MemLoc l;
+ {
+ ScopedThread t1, t2;
+
+ t1.Lock(m);
+ t1.Write8(l);
+ t1.Unlock(m);
+
+ t1.Read8(l);
+
+ t2.Read8(l, true);
+ }
+ t0.Destroy(m);
+}
+
+
+TEST(ThreadSanitizer, RaceWithOffset) {
+ ScopedThread t1, t2;
+ {
+ MemLoc l;
+ t1.Access(l.loc(), true, 8, false);
+ t2.Access((char*)l.loc() + 4, true, 4, true);
+ }
+ {
+ MemLoc l;
+ t1.Access(l.loc(), true, 8, false);
+ t2.Access((char*)l.loc() + 7, true, 1, true);
+ }
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc() + 4, true, 4, false);
+ t2.Access((char*)l.loc() + 4, true, 2, true);
+ }
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc() + 4, true, 4, false);
+ t2.Access((char*)l.loc() + 6, true, 2, true);
+ }
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc() + 3, true, 2, false);
+ t2.Access((char*)l.loc() + 4, true, 1, true);
+ }
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc() + 1, true, 8, false);
+ t2.Access((char*)l.loc() + 3, true, 1, true);
+ }
+}
+
+TEST(ThreadSanitizer, RaceWithOffset2) {
+ ScopedThread t1, t2;
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc(), true, 4, false);
+ t2.Access((char*)l.loc() + 2, true, 1, true);
+ }
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc() + 2, true, 1, false);
+ t2.Access((char*)l.loc(), true, 4, true);
+ }
+}
+
+TEST(ThreadSanitizer, NoRaceWithOffset) {
+ ScopedThread t1, t2;
+ {
+ MemLoc l;
+ t1.Access(l.loc(), true, 4, false);
+ t2.Access((char*)l.loc() + 4, true, 4, false);
+ }
+ {
+ MemLoc l;
+ t1.Access((char*)l.loc() + 3, true, 2, false);
+ t2.Access((char*)l.loc() + 1, true, 2, false);
+ t2.Access((char*)l.loc() + 5, true, 2, false);
+ }
+}
+
+TEST(ThreadSanitizer, RaceWithDeadThread) {
+ MemLoc l;
+ ScopedThread t;
+ ScopedThread().Write1(l);
+ t.Write1(l, true);
+}
+
+TEST(ThreadSanitizer, BenignRaceOnVptr) {
+ void *vptr_storage;
+ MemLoc vptr(&vptr_storage), val;
+ vptr_storage = val.loc();
+ ScopedThread t1, t2;
+ t1.VptrUpdate(vptr, val);
+ t2.Read8(vptr);
+}
+
+TEST(ThreadSanitizer, HarmfulRaceOnVptr) {
+ void *vptr_storage;
+ MemLoc vptr(&vptr_storage), val1, val2;
+ vptr_storage = val1.loc();
+ ScopedThread t1, t2;
+ t1.VptrUpdate(vptr, val2);
+ t2.Read8(vptr, true);
+}
+
+static void foo() {
+ volatile int x = 42;
+ int x2 = x;
+ (void)x2;
+}
+
+static void bar() {
+ volatile int x = 43;
+ int x2 = x;
+ (void)x2;
+}
+
+TEST(ThreadSanitizer, ReportDeadThread) {
+ MemLoc l;
+ ScopedThread t1;
+ {
+ ScopedThread t2;
+ t2.Call(&foo);
+ t2.Call(&bar);
+ t2.Write1(l);
+ }
+ t1.Write1(l, true);
+}
+
+struct ClassWithStatic {
+ static int Data[4];
+};
+
+int ClassWithStatic::Data[4];
+
+static void foobarbaz() {}
+
+TEST(ThreadSanitizer, ReportRace) {
+ ScopedThread t1;
+ MainThread().Access(&ClassWithStatic::Data, true, 4, false);
+ t1.Call(&foobarbaz);
+ t1.Access(&ClassWithStatic::Data, true, 2, true);
+ t1.Return();
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc
new file mode 100644
index 000000000000..4d9c77961818
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc
@@ -0,0 +1,221 @@
+//===-- tsan_mutex.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "tsan_interface.h"
+#include "tsan_interface_ann.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <stdint.h>
+
+namespace __tsan {
+
+TEST(ThreadSanitizer, BasicMutex) {
+ ScopedThread t;
+ Mutex m;
+ t.Create(m);
+
+ t.Lock(m);
+ t.Unlock(m);
+
+ CHECK(t.TryLock(m));
+ t.Unlock(m);
+
+ t.Lock(m);
+ CHECK(!t.TryLock(m));
+ t.Unlock(m);
+
+ t.Destroy(m);
+}
+
+TEST(ThreadSanitizer, BasicSpinMutex) {
+ ScopedThread t;
+ Mutex m(Mutex::Spin);
+ t.Create(m);
+
+ t.Lock(m);
+ t.Unlock(m);
+
+ CHECK(t.TryLock(m));
+ t.Unlock(m);
+
+ t.Lock(m);
+ CHECK(!t.TryLock(m));
+ t.Unlock(m);
+
+ t.Destroy(m);
+}
+
+TEST(ThreadSanitizer, BasicRwMutex) {
+ ScopedThread t;
+ Mutex m(Mutex::RW);
+ t.Create(m);
+
+ t.Lock(m);
+ t.Unlock(m);
+
+ CHECK(t.TryLock(m));
+ t.Unlock(m);
+
+ t.Lock(m);
+ CHECK(!t.TryLock(m));
+ t.Unlock(m);
+
+ t.ReadLock(m);
+ t.ReadUnlock(m);
+
+ CHECK(t.TryReadLock(m));
+ t.ReadUnlock(m);
+
+ t.Lock(m);
+ CHECK(!t.TryReadLock(m));
+ t.Unlock(m);
+
+ t.ReadLock(m);
+ CHECK(!t.TryLock(m));
+ t.ReadUnlock(m);
+
+ t.ReadLock(m);
+ CHECK(t.TryReadLock(m));
+ t.ReadUnlock(m);
+ t.ReadUnlock(m);
+
+ t.Destroy(m);
+}
+
+TEST(ThreadSanitizer, Mutex) {
+ Mutex m;
+ MainThread t0;
+ t0.Create(m);
+
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Lock(m);
+ t1.Write1(l);
+ t1.Unlock(m);
+ t2.Lock(m);
+ t2.Write1(l);
+ t2.Unlock(m);
+ t2.Destroy(m);
+}
+
+TEST(ThreadSanitizer, SpinMutex) {
+ Mutex m(Mutex::Spin);
+ MainThread t0;
+ t0.Create(m);
+
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Lock(m);
+ t1.Write1(l);
+ t1.Unlock(m);
+ t2.Lock(m);
+ t2.Write1(l);
+ t2.Unlock(m);
+ t2.Destroy(m);
+}
+
+TEST(ThreadSanitizer, RwMutex) {
+ Mutex m(Mutex::RW);
+ MainThread t0;
+ t0.Create(m);
+
+ ScopedThread t1, t2, t3;
+ MemLoc l;
+ t1.Lock(m);
+ t1.Write1(l);
+ t1.Unlock(m);
+ t2.Lock(m);
+ t2.Write1(l);
+ t2.Unlock(m);
+ t1.ReadLock(m);
+ t3.ReadLock(m);
+ t1.Read1(l);
+ t3.Read1(l);
+ t1.ReadUnlock(m);
+ t3.ReadUnlock(m);
+ t2.Lock(m);
+ t2.Write1(l);
+ t2.Unlock(m);
+ t2.Destroy(m);
+}
+
+TEST(ThreadSanitizer, StaticMutex) {
+ // Emulates statically initialized mutex.
+ Mutex m;
+ m.StaticInit();
+ {
+ ScopedThread t1, t2;
+ t1.Lock(m);
+ t1.Unlock(m);
+ t2.Lock(m);
+ t2.Unlock(m);
+ }
+ MainThread().Destroy(m);
+}
+
+static void *singleton_thread(void *param) {
+ atomic_uintptr_t *singleton = (atomic_uintptr_t *)param;
+ for (int i = 0; i < 4*1024*1024; i++) {
+ int *val = (int *)atomic_load(singleton, memory_order_acquire);
+ __tsan_acquire(singleton);
+ __tsan_read4(val);
+ CHECK_EQ(*val, 42);
+ }
+ return 0;
+}
+
+TEST(DISABLED_BENCH_ThreadSanitizer, Singleton) {
+ const int kClockSize = 100;
+ const int kThreadCount = 8;
+
+ // Puff off thread's clock.
+ for (int i = 0; i < kClockSize; i++) {
+ ScopedThread t1;
+ (void)t1;
+ }
+ // Create the singleton.
+ int val = 42;
+ __tsan_write4(&val);
+ atomic_uintptr_t singleton;
+ __tsan_release(&singleton);
+ atomic_store(&singleton, (uintptr_t)&val, memory_order_release);
+ // Create reader threads.
+ pthread_t threads[kThreadCount];
+ for (int t = 0; t < kThreadCount; t++)
+ pthread_create(&threads[t], 0, singleton_thread, &singleton);
+ for (int t = 0; t < kThreadCount; t++)
+ pthread_join(threads[t], 0);
+}
+
+TEST(DISABLED_BENCH_ThreadSanitizer, StopFlag) {
+ const int kClockSize = 100;
+ const int kIters = 16*1024*1024;
+
+ // Puff off thread's clock.
+ for (int i = 0; i < kClockSize; i++) {
+ ScopedThread t1;
+ (void)t1;
+ }
+ // Create the stop flag.
+ atomic_uintptr_t flag;
+ __tsan_release(&flag);
+ atomic_store(&flag, 0, memory_order_release);
+ // Read it a lot.
+ for (int i = 0; i < kIters; i++) {
+ uptr v = atomic_load(&flag, memory_order_acquire);
+ __tsan_acquire(&flag);
+ CHECK_EQ(v, 0);
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc
new file mode 100644
index 000000000000..0caedd7207e6
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc
@@ -0,0 +1,146 @@
+//===-- tsan_posix.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <pthread.h>
+
+struct thread_key {
+ pthread_key_t key;
+ pthread_mutex_t *mtx;
+ int val;
+ int *cnt;
+ thread_key(pthread_key_t key, pthread_mutex_t *mtx, int val, int *cnt)
+ : key(key)
+ , mtx(mtx)
+ , val(val)
+ , cnt(cnt) {
+ }
+};
+
+static void thread_secific_dtor(void *v) {
+ thread_key *k = (thread_key *)v;
+ EXPECT_EQ(pthread_mutex_lock(k->mtx), 0);
+ (*k->cnt)++;
+ __tsan_write4(&k->cnt);
+ EXPECT_EQ(pthread_mutex_unlock(k->mtx), 0);
+ if (k->val == 42) {
+ delete k;
+ } else if (k->val == 43 || k->val == 44) {
+ k->val--;
+ EXPECT_EQ(pthread_setspecific(k->key, k), 0);
+ } else {
+ ASSERT_TRUE(false);
+ }
+}
+
+static void *dtors_thread(void *p) {
+ thread_key *k = (thread_key *)p;
+ EXPECT_EQ(pthread_setspecific(k->key, k), 0);
+ return 0;
+}
+
+TEST(Posix, ThreadSpecificDtors) {
+ int cnt = 0;
+ pthread_key_t key;
+ EXPECT_EQ(pthread_key_create(&key, thread_secific_dtor), 0);
+ pthread_mutex_t mtx;
+ EXPECT_EQ(pthread_mutex_init(&mtx, 0), 0);
+ pthread_t th[3];
+ thread_key *k[3];
+ k[0] = new thread_key(key, &mtx, 42, &cnt);
+ k[1] = new thread_key(key, &mtx, 43, &cnt);
+ k[2] = new thread_key(key, &mtx, 44, &cnt);
+ EXPECT_EQ(pthread_create(&th[0], 0, dtors_thread, k[0]), 0);
+ EXPECT_EQ(pthread_create(&th[1], 0, dtors_thread, k[1]), 0);
+ EXPECT_EQ(pthread_join(th[0], 0), 0);
+ EXPECT_EQ(pthread_create(&th[2], 0, dtors_thread, k[2]), 0);
+ EXPECT_EQ(pthread_join(th[1], 0), 0);
+ EXPECT_EQ(pthread_join(th[2], 0), 0);
+ EXPECT_EQ(pthread_key_delete(key), 0);
+ EXPECT_EQ(6, cnt);
+}
+
+static __thread int local_var;
+
+static void *local_thread(void *p) {
+ __tsan_write1(&local_var);
+ __tsan_write1(&p);
+ if (p == 0)
+ return 0;
+ const int kThreads = 4;
+ pthread_t th[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ EXPECT_EQ(pthread_create(&th[i], 0, local_thread,
+ (void*)((long)p - 1)), 0); // NOLINT
+ for (int i = 0; i < kThreads; i++)
+ EXPECT_EQ(pthread_join(th[i], 0), 0);
+ return 0;
+}
+
+TEST(Posix, ThreadLocalAccesses) {
+ local_thread((void*)2);
+}
+
+struct CondContext {
+ pthread_mutex_t m;
+ pthread_cond_t c;
+ int data;
+};
+
+static void *cond_thread(void *p) {
+ CondContext &ctx = *static_cast<CondContext*>(p);
+
+ EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+ EXPECT_EQ(ctx.data, 0);
+ ctx.data = 1;
+ EXPECT_EQ(pthread_cond_signal(&ctx.c), 0);
+ EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+ EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+ while (ctx.data != 2)
+ EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
+ EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+ EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+ ctx.data = 3;
+ EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
+ EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+ return 0;
+}
+
+TEST(Posix, CondBasic) {
+ CondContext ctx;
+ EXPECT_EQ(pthread_mutex_init(&ctx.m, 0), 0);
+ EXPECT_EQ(pthread_cond_init(&ctx.c, 0), 0);
+ ctx.data = 0;
+ pthread_t th;
+ EXPECT_EQ(pthread_create(&th, 0, cond_thread, &ctx), 0);
+
+ EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+ while (ctx.data != 1)
+ EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
+ ctx.data = 2;
+ EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+ EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
+
+ EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+ while (ctx.data != 3)
+ EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
+ EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+ EXPECT_EQ(pthread_join(th, 0), 0);
+ EXPECT_EQ(pthread_cond_destroy(&ctx.c), 0);
+ EXPECT_EQ(pthread_mutex_destroy(&ctx.m), 0);
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc
new file mode 100644
index 000000000000..75adc6c85ee9
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc
@@ -0,0 +1,82 @@
+//===-- tsan_string.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <string.h>
+
+namespace __tsan {
+
+TEST(ThreadSanitizer, Memcpy) {
+ char data0[7] = {1, 2, 3, 4, 5, 6, 7};
+ char data[7] = {42, 42, 42, 42, 42, 42, 42};
+ MainThread().Memcpy(data+1, data0+1, 5);
+ EXPECT_EQ(data[0], 42);
+ EXPECT_EQ(data[1], 2);
+ EXPECT_EQ(data[2], 3);
+ EXPECT_EQ(data[3], 4);
+ EXPECT_EQ(data[4], 5);
+ EXPECT_EQ(data[5], 6);
+ EXPECT_EQ(data[6], 42);
+ MainThread().Memset(data+1, 13, 5);
+ EXPECT_EQ(data[0], 42);
+ EXPECT_EQ(data[1], 13);
+ EXPECT_EQ(data[2], 13);
+ EXPECT_EQ(data[3], 13);
+ EXPECT_EQ(data[4], 13);
+ EXPECT_EQ(data[5], 13);
+ EXPECT_EQ(data[6], 42);
+}
+
+TEST(ThreadSanitizer, MemcpyRace1) {
+ char *data = new char[10];
+ char *data1 = new char[10];
+ char *data2 = new char[10];
+ ScopedThread t1, t2;
+ t1.Memcpy(data, data1, 10);
+ t2.Memcpy(data, data2, 10, true);
+}
+
+TEST(ThreadSanitizer, MemcpyRace2) {
+ char *data = new char[10];
+ char *data1 = new char[10];
+ char *data2 = new char[10];
+ ScopedThread t1, t2;
+ t1.Memcpy(data+5, data1, 1);
+ t2.Memcpy(data+3, data2, 4, true);
+}
+
+TEST(ThreadSanitizer, MemcpyRace3) {
+ char *data = new char[10];
+ char *data1 = new char[10];
+ char *data2 = new char[10];
+ ScopedThread t1, t2;
+ t1.Memcpy(data, data1, 10);
+ t2.Memcpy(data1, data2, 10, true);
+}
+
+TEST(ThreadSanitizer, MemcpyStack) {
+ char *data = new char[10];
+ char *data1 = new char[10];
+ ScopedThread t1, t2;
+ t1.Memcpy(data, data1, 10);
+ t2.Memcpy(data, data1, 10, true);
+}
+
+TEST(ThreadSanitizer, MemsetRace1) {
+ char *data = new char[10];
+ ScopedThread t1, t2;
+ t1.Memset(data, 1, 10);
+ t2.Memset(data, 2, 10, true);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc
new file mode 100644
index 000000000000..b8b9555c2bff
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc
@@ -0,0 +1,53 @@
+//===-- tsan_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+
+static void foo() {}
+static void bar() {}
+
+TEST(ThreadSanitizer, FuncCall) {
+ ScopedThread t1, t2;
+ MemLoc l;
+ t1.Write1(l);
+ t2.Call(foo);
+ t2.Call(bar);
+ t2.Write1(l, true);
+ t2.Return();
+ t2.Return();
+}
+
+// We use this function instead of main, as ISO C++ forbids taking the address
+// of main, which we need to pass inside __tsan_func_entry.
+int run_tests(int argc, char **argv) {
+ TestMutexBeforeInit(); // Mutexes must be usable before __tsan_init();
+ __tsan_init();
+ __tsan_func_entry(__builtin_return_address(0));
+ __tsan_func_entry((void*)((intptr_t)&run_tests + 1));
+
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ int res = RUN_ALL_TESTS();
+
+ __tsan_func_exit();
+ __tsan_func_exit();
+ return res;
+}
+
+const char *argv0;
+
+int main(int argc, char **argv) {
+ argv0 = argv[0];
+ return run_tests(argc, argv);
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h
new file mode 100644
index 000000000000..84d277b137f0
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h
@@ -0,0 +1,122 @@
+//===-- tsan_test_util.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 ThreadSanitizer (TSan), a race detector.
+//
+// Test utils.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_TEST_UTIL_H
+#define TSAN_TEST_UTIL_H
+
+void TestMutexBeforeInit();
+
+// A location of memory on which a race may be detected.
+class MemLoc {
+ public:
+ explicit MemLoc(int offset_from_aligned = 0);
+ explicit MemLoc(void *const real_addr) : loc_(real_addr) { }
+ ~MemLoc();
+ void *loc() const { return loc_; }
+ private:
+ void *const loc_;
+ MemLoc(const MemLoc&);
+ void operator = (const MemLoc&);
+};
+
+class Mutex {
+ public:
+ enum Type { Normal, Spin, RW };
+
+ explicit Mutex(Type type = Normal);
+ ~Mutex();
+
+ void Init();
+ void StaticInit(); // Emulates static initialization (tsan invisible).
+ void Destroy();
+ void Lock();
+ bool TryLock();
+ void Unlock();
+ void ReadLock();
+ bool TryReadLock();
+ void ReadUnlock();
+
+ private:
+ // Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever.
+ void *mtx_[128];
+ bool alive_;
+ const Type type_;
+
+ Mutex(const Mutex&);
+ void operator = (const Mutex&);
+};
+
+// A thread is started in CTOR and joined in DTOR.
+class ScopedThread {
+ public:
+ explicit ScopedThread(bool detached = false, bool main = false);
+ ~ScopedThread();
+ void Detach();
+
+ void Access(void *addr, bool is_write, int size, bool expect_race);
+ void Read(const MemLoc &ml, int size, bool expect_race = false) {
+ Access(ml.loc(), false, size, expect_race);
+ }
+ void Write(const MemLoc &ml, int size, bool expect_race = false) {
+ Access(ml.loc(), true, size, expect_race);
+ }
+ void Read1(const MemLoc &ml, bool expect_race = false) {
+ Read(ml, 1, expect_race); }
+ void Read2(const MemLoc &ml, bool expect_race = false) {
+ Read(ml, 2, expect_race); }
+ void Read4(const MemLoc &ml, bool expect_race = false) {
+ Read(ml, 4, expect_race); }
+ void Read8(const MemLoc &ml, bool expect_race = false) {
+ Read(ml, 8, expect_race); }
+ void Write1(const MemLoc &ml, bool expect_race = false) {
+ Write(ml, 1, expect_race); }
+ void Write2(const MemLoc &ml, bool expect_race = false) {
+ Write(ml, 2, expect_race); }
+ void Write4(const MemLoc &ml, bool expect_race = false) {
+ Write(ml, 4, expect_race); }
+ void Write8(const MemLoc &ml, bool expect_race = false) {
+ Write(ml, 8, expect_race); }
+
+ void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val,
+ bool expect_race = false);
+
+ void Call(void(*pc)());
+ void Return();
+
+ void Create(const Mutex &m);
+ void Destroy(const Mutex &m);
+ void Lock(const Mutex &m);
+ bool TryLock(const Mutex &m);
+ void Unlock(const Mutex &m);
+ void ReadLock(const Mutex &m);
+ bool TryReadLock(const Mutex &m);
+ void ReadUnlock(const Mutex &m);
+
+ void Memcpy(void *dst, const void *src, int size, bool expect_race = false);
+ void Memset(void *dst, int val, int size, bool expect_race = false);
+
+ private:
+ struct Impl;
+ Impl *impl_;
+ ScopedThread(const ScopedThread&); // Not implemented.
+ void operator = (const ScopedThread&); // Not implemented.
+};
+
+class MainThread : public ScopedThread {
+ public:
+ MainThread()
+ : ScopedThread(false, true) {
+ }
+};
+
+#endif // #ifndef TSAN_TEST_UTIL_H
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc
new file mode 100644
index 000000000000..9298bf051af2
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc
@@ -0,0 +1,470 @@
+
+//===-- tsan_test_util_linux.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 ThreadSanitizer (TSan), a race detector.
+//
+// Test utils, Linux and FreeBSD implementation.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "tsan_report.h"
+
+#include "gtest/gtest.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace __tsan; // NOLINT
+
+static __thread bool expect_report;
+static __thread bool expect_report_reported;
+static __thread ReportType expect_report_type;
+
+extern "C" void *__interceptor_memcpy(void*, const void*, uptr);
+extern "C" void *__interceptor_memset(void*, int, uptr);
+
+static void *BeforeInitThread(void *param) {
+ (void)param;
+ return 0;
+}
+
+static void AtExit() {
+}
+
+void TestMutexBeforeInit() {
+ // Mutexes must be usable before __tsan_init();
+ pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_unlock(&mtx);
+ pthread_mutex_destroy(&mtx);
+ pthread_t thr;
+ pthread_create(&thr, 0, BeforeInitThread, 0);
+ pthread_join(thr, 0);
+ atexit(AtExit);
+}
+
+namespace __tsan {
+bool OnReport(const ReportDesc *rep, bool suppressed) {
+ if (expect_report) {
+ if (rep->typ != expect_report_type) {
+ printf("Expected report of type %d, got type %d\n",
+ (int)expect_report_type, (int)rep->typ);
+ EXPECT_FALSE("Wrong report type");
+ return false;
+ }
+ } else {
+ EXPECT_FALSE("Unexpected report");
+ return false;
+ }
+ expect_report_reported = true;
+ return true;
+}
+} // namespace __tsan
+
+static void* allocate_addr(int size, int offset_from_aligned = 0) {
+ static uintptr_t foo;
+ static atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address.
+ const int kAlign = 16;
+ CHECK(offset_from_aligned < kAlign);
+ size = (size + 2 * kAlign) & ~(kAlign - 1);
+ uintptr_t addr = atomic_fetch_add(&uniq, size, memory_order_relaxed);
+ return (void*)(addr + offset_from_aligned);
+}
+
+MemLoc::MemLoc(int offset_from_aligned)
+ : loc_(allocate_addr(16, offset_from_aligned)) {
+}
+
+MemLoc::~MemLoc() {
+}
+
+Mutex::Mutex(Type type)
+ : alive_()
+ , type_(type) {
+}
+
+Mutex::~Mutex() {
+ CHECK(!alive_);
+}
+
+void Mutex::Init() {
+ CHECK(!alive_);
+ alive_ = true;
+ if (type_ == Normal)
+ CHECK_EQ(pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
+ else if (type_ == Spin)
+ CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
+ else if (type_ == RW)
+ CHECK_EQ(pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
+ else
+ CHECK(0);
+}
+
+void Mutex::StaticInit() {
+ CHECK(!alive_);
+ CHECK(type_ == Normal);
+ alive_ = true;
+ pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
+ memcpy(mtx_, &tmp, sizeof(tmp));
+}
+
+void Mutex::Destroy() {
+ CHECK(alive_);
+ alive_ = false;
+ if (type_ == Normal)
+ CHECK_EQ(pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
+ else if (type_ == Spin)
+ CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
+ else if (type_ == RW)
+ CHECK_EQ(pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
+}
+
+void Mutex::Lock() {
+ CHECK(alive_);
+ if (type_ == Normal)
+ CHECK_EQ(pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
+ else if (type_ == Spin)
+ CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
+ else if (type_ == RW)
+ CHECK_EQ(pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+bool Mutex::TryLock() {
+ CHECK(alive_);
+ if (type_ == Normal)
+ return pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
+ else if (type_ == Spin)
+ return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
+ else if (type_ == RW)
+ return pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
+ return false;
+}
+
+void Mutex::Unlock() {
+ CHECK(alive_);
+ if (type_ == Normal)
+ CHECK_EQ(pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
+ else if (type_ == Spin)
+ CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
+ else if (type_ == RW)
+ CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+void Mutex::ReadLock() {
+ CHECK(alive_);
+ CHECK(type_ == RW);
+ CHECK_EQ(pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+bool Mutex::TryReadLock() {
+ CHECK(alive_);
+ CHECK(type_ == RW);
+ return pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0;
+}
+
+void Mutex::ReadUnlock() {
+ CHECK(alive_);
+ CHECK(type_ == RW);
+ CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+struct Event {
+ enum Type {
+ SHUTDOWN,
+ READ,
+ WRITE,
+ VPTR_UPDATE,
+ CALL,
+ RETURN,
+ MUTEX_CREATE,
+ MUTEX_DESTROY,
+ MUTEX_LOCK,
+ MUTEX_TRYLOCK,
+ MUTEX_UNLOCK,
+ MUTEX_READLOCK,
+ MUTEX_TRYREADLOCK,
+ MUTEX_READUNLOCK,
+ MEMCPY,
+ MEMSET
+ };
+ Type type;
+ void *ptr;
+ uptr arg;
+ uptr arg2;
+ bool res;
+ bool expect_report;
+ ReportType report_type;
+
+ Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0)
+ : type(type)
+ , ptr(const_cast<void*>(ptr))
+ , arg(arg)
+ , arg2(arg2)
+ , res()
+ , expect_report()
+ , report_type() {
+ }
+
+ void ExpectReport(ReportType type) {
+ expect_report = true;
+ report_type = type;
+ }
+};
+
+struct ScopedThread::Impl {
+ pthread_t thread;
+ bool main;
+ bool detached;
+ atomic_uintptr_t event; // Event*
+
+ static void *ScopedThreadCallback(void *arg);
+ void send(Event *ev);
+ void HandleEvent(Event *ev);
+};
+
+void ScopedThread::Impl::HandleEvent(Event *ev) {
+ CHECK_EQ(expect_report, false);
+ expect_report = ev->expect_report;
+ expect_report_reported = false;
+ expect_report_type = ev->report_type;
+ switch (ev->type) {
+ case Event::READ:
+ case Event::WRITE: {
+ void (*tsan_mop)(void *addr) = 0;
+ if (ev->type == Event::READ) {
+ switch (ev->arg /*size*/) {
+ case 1: tsan_mop = __tsan_read1; break;
+ case 2: tsan_mop = __tsan_read2; break;
+ case 4: tsan_mop = __tsan_read4; break;
+ case 8: tsan_mop = __tsan_read8; break;
+ case 16: tsan_mop = __tsan_read16; break;
+ }
+ } else {
+ switch (ev->arg /*size*/) {
+ case 1: tsan_mop = __tsan_write1; break;
+ case 2: tsan_mop = __tsan_write2; break;
+ case 4: tsan_mop = __tsan_write4; break;
+ case 8: tsan_mop = __tsan_write8; break;
+ case 16: tsan_mop = __tsan_write16; break;
+ }
+ }
+ CHECK_NE(tsan_mop, 0);
+#if defined(__FreeBSD__)
+ const int ErrCode = ESOCKTNOSUPPORT;
+#else
+ const int ErrCode = ECHRNG;
+#endif
+ errno = ErrCode;
+ tsan_mop(ev->ptr);
+ CHECK_EQ(ErrCode, errno); // In no case must errno be changed.
+ break;
+ }
+ case Event::VPTR_UPDATE:
+ __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg);
+ break;
+ case Event::CALL:
+ __tsan_func_entry((void*)((uptr)ev->ptr));
+ break;
+ case Event::RETURN:
+ __tsan_func_exit();
+ break;
+ case Event::MUTEX_CREATE:
+ static_cast<Mutex*>(ev->ptr)->Init();
+ break;
+ case Event::MUTEX_DESTROY:
+ static_cast<Mutex*>(ev->ptr)->Destroy();
+ break;
+ case Event::MUTEX_LOCK:
+ static_cast<Mutex*>(ev->ptr)->Lock();
+ break;
+ case Event::MUTEX_TRYLOCK:
+ ev->res = static_cast<Mutex*>(ev->ptr)->TryLock();
+ break;
+ case Event::MUTEX_UNLOCK:
+ static_cast<Mutex*>(ev->ptr)->Unlock();
+ break;
+ case Event::MUTEX_READLOCK:
+ static_cast<Mutex*>(ev->ptr)->ReadLock();
+ break;
+ case Event::MUTEX_TRYREADLOCK:
+ ev->res = static_cast<Mutex*>(ev->ptr)->TryReadLock();
+ break;
+ case Event::MUTEX_READUNLOCK:
+ static_cast<Mutex*>(ev->ptr)->ReadUnlock();
+ break;
+ case Event::MEMCPY:
+ __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2);
+ break;
+ case Event::MEMSET:
+ __interceptor_memset(ev->ptr, ev->arg, ev->arg2);
+ break;
+ default: CHECK(0);
+ }
+ if (expect_report && !expect_report_reported) {
+ printf("Missed expected report of type %d\n", (int)ev->report_type);
+ EXPECT_FALSE("Missed expected race");
+ }
+ expect_report = false;
+}
+
+void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
+ __tsan_func_entry(__builtin_return_address(0));
+ Impl *impl = (Impl*)arg;
+ for (;;) {
+ Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire);
+ if (ev == 0) {
+ pthread_yield();
+ continue;
+ }
+ if (ev->type == Event::SHUTDOWN) {
+ atomic_store(&impl->event, 0, memory_order_release);
+ break;
+ }
+ impl->HandleEvent(ev);
+ atomic_store(&impl->event, 0, memory_order_release);
+ }
+ __tsan_func_exit();
+ return 0;
+}
+
+void ScopedThread::Impl::send(Event *e) {
+ if (main) {
+ HandleEvent(e);
+ } else {
+ CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0);
+ atomic_store(&event, (uintptr_t)e, memory_order_release);
+ while (atomic_load(&event, memory_order_acquire) != 0)
+ pthread_yield();
+ }
+}
+
+ScopedThread::ScopedThread(bool detached, bool main) {
+ impl_ = new Impl;
+ impl_->main = main;
+ impl_->detached = detached;
+ atomic_store(&impl_->event, 0, memory_order_relaxed);
+ if (!main) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, detached);
+ pthread_attr_setstacksize(&attr, 64*1024);
+ pthread_create(&impl_->thread, &attr,
+ ScopedThread::Impl::ScopedThreadCallback, impl_);
+ }
+}
+
+ScopedThread::~ScopedThread() {
+ if (!impl_->main) {
+ Event event(Event::SHUTDOWN);
+ impl_->send(&event);
+ if (!impl_->detached)
+ pthread_join(impl_->thread, 0);
+ }
+ delete impl_;
+}
+
+void ScopedThread::Detach() {
+ CHECK(!impl_->main);
+ CHECK(!impl_->detached);
+ impl_->detached = true;
+ pthread_detach(impl_->thread);
+}
+
+void ScopedThread::Access(void *addr, bool is_write,
+ int size, bool expect_race) {
+ Event event(is_write ? Event::WRITE : Event::READ, addr, size);
+ if (expect_race)
+ event.ExpectReport(ReportTypeRace);
+ impl_->send(&event);
+}
+
+void ScopedThread::VptrUpdate(const MemLoc &vptr,
+ const MemLoc &new_val,
+ bool expect_race) {
+ Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc());
+ if (expect_race)
+ event.ExpectReport(ReportTypeRace);
+ impl_->send(&event);
+}
+
+void ScopedThread::Call(void(*pc)()) {
+ Event event(Event::CALL, (void*)((uintptr_t)pc));
+ impl_->send(&event);
+}
+
+void ScopedThread::Return() {
+ Event event(Event::RETURN);
+ impl_->send(&event);
+}
+
+void ScopedThread::Create(const Mutex &m) {
+ Event event(Event::MUTEX_CREATE, &m);
+ impl_->send(&event);
+}
+
+void ScopedThread::Destroy(const Mutex &m) {
+ Event event(Event::MUTEX_DESTROY, &m);
+ impl_->send(&event);
+}
+
+void ScopedThread::Lock(const Mutex &m) {
+ Event event(Event::MUTEX_LOCK, &m);
+ impl_->send(&event);
+}
+
+bool ScopedThread::TryLock(const Mutex &m) {
+ Event event(Event::MUTEX_TRYLOCK, &m);
+ impl_->send(&event);
+ return event.res;
+}
+
+void ScopedThread::Unlock(const Mutex &m) {
+ Event event(Event::MUTEX_UNLOCK, &m);
+ impl_->send(&event);
+}
+
+void ScopedThread::ReadLock(const Mutex &m) {
+ Event event(Event::MUTEX_READLOCK, &m);
+ impl_->send(&event);
+}
+
+bool ScopedThread::TryReadLock(const Mutex &m) {
+ Event event(Event::MUTEX_TRYREADLOCK, &m);
+ impl_->send(&event);
+ return event.res;
+}
+
+void ScopedThread::ReadUnlock(const Mutex &m) {
+ Event event(Event::MUTEX_READUNLOCK, &m);
+ impl_->send(&event);
+}
+
+void ScopedThread::Memcpy(void *dst, const void *src, int size,
+ bool expect_race) {
+ Event event(Event::MEMCPY, dst, (uptr)src, size);
+ if (expect_race)
+ event.ExpectReport(ReportTypeRace);
+ impl_->send(&event);
+}
+
+void ScopedThread::Memset(void *dst, int val, int size,
+ bool expect_race) {
+ Event event(Event::MEMSET, dst, val, size);
+ if (expect_race)
+ event.ExpectReport(ReportTypeRace);
+ impl_->send(&event);
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc
new file mode 100644
index 000000000000..5646415a79b8
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc
@@ -0,0 +1,59 @@
+//===-- tsan_thread.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+
+TEST(ThreadSanitizer, ThreadSync) {
+ MainThread t0;
+ MemLoc l;
+ t0.Write1(l);
+ {
+ ScopedThread t1;
+ t1.Write1(l);
+ }
+ t0.Write1(l);
+}
+
+TEST(ThreadSanitizer, ThreadDetach1) {
+ ScopedThread t1(true);
+ MemLoc l;
+ t1.Write1(l);
+}
+
+TEST(ThreadSanitizer, ThreadDetach2) {
+ ScopedThread t1;
+ MemLoc l;
+ t1.Write1(l);
+ t1.Detach();
+}
+
+static void *thread_alot_func(void *arg) {
+ (void)arg;
+ int usleep(unsigned);
+ usleep(50);
+ return 0;
+}
+
+TEST(DISABLED_SLOW_ThreadSanitizer, ThreadALot) {
+ const int kThreads = 70000;
+ const int kAlive = 1000;
+ pthread_t threads[kAlive] = {};
+ for (int i = 0; i < kThreads; i++) {
+ if (threads[i % kAlive])
+ pthread_join(threads[i % kAlive], 0);
+ pthread_create(&threads[i % kAlive], 0, thread_alot_func, 0);
+ }
+ for (int i = 0; i < kAlive; i++) {
+ pthread_join(threads[i], 0);
+ }
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc
new file mode 100644
index 000000000000..92071827d3d8
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc
@@ -0,0 +1,432 @@
+//===-- tsan_clock_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_clock.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+#include <time.h>
+
+namespace __tsan {
+
+ClockCache cache;
+
+TEST(Clock, VectorBasic) {
+ ThreadClock clk(0);
+ ASSERT_EQ(clk.size(), 1U);
+ clk.tick();
+ ASSERT_EQ(clk.size(), 1U);
+ ASSERT_EQ(clk.get(0), 1U);
+ clk.set(3, clk.get(3) + 1);
+ ASSERT_EQ(clk.size(), 4U);
+ ASSERT_EQ(clk.get(0), 1U);
+ ASSERT_EQ(clk.get(1), 0U);
+ ASSERT_EQ(clk.get(2), 0U);
+ ASSERT_EQ(clk.get(3), 1U);
+ clk.set(3, clk.get(3) + 1);
+ ASSERT_EQ(clk.get(3), 2U);
+}
+
+TEST(Clock, ChunkedBasic) {
+ ThreadClock vector(0);
+ SyncClock chunked;
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 0U);
+ vector.acquire(&cache, &chunked);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 0U);
+ vector.release(&cache, &chunked);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 1U);
+ vector.acq_rel(&cache, &chunked);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 1U);
+ chunked.Reset(&cache);
+}
+
+TEST(Clock, AcquireRelease) {
+ ThreadClock vector1(100);
+ vector1.tick();
+ SyncClock chunked;
+ vector1.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 101U);
+ ThreadClock vector2(0);
+ vector2.acquire(&cache, &chunked);
+ ASSERT_EQ(vector2.size(), 101U);
+ ASSERT_EQ(vector2.get(0), 0U);
+ ASSERT_EQ(vector2.get(1), 0U);
+ ASSERT_EQ(vector2.get(99), 0U);
+ ASSERT_EQ(vector2.get(100), 1U);
+ chunked.Reset(&cache);
+}
+
+TEST(Clock, RepeatedAcquire) {
+ ThreadClock thr1(1);
+ thr1.tick();
+ ThreadClock thr2(2);
+ thr2.tick();
+
+ SyncClock sync;
+ thr1.ReleaseStore(&cache, &sync);
+
+ thr2.acquire(&cache, &sync);
+ thr2.acquire(&cache, &sync);
+
+ sync.Reset(&cache);
+}
+
+TEST(Clock, ManyThreads) {
+ SyncClock chunked;
+ for (unsigned i = 0; i < 100; i++) {
+ ThreadClock vector(0);
+ vector.tick();
+ vector.set(i, 1);
+ vector.release(&cache, &chunked);
+ ASSERT_EQ(i + 1, chunked.size());
+ vector.acquire(&cache, &chunked);
+ ASSERT_EQ(i + 1, vector.size());
+ }
+
+ for (unsigned i = 0; i < 100; i++)
+ ASSERT_EQ(1U, chunked.get(i));
+
+ ThreadClock vector(1);
+ vector.acquire(&cache, &chunked);
+ ASSERT_EQ(100U, vector.size());
+ for (unsigned i = 0; i < 100; i++)
+ ASSERT_EQ(1U, vector.get(i));
+
+ chunked.Reset(&cache);
+}
+
+TEST(Clock, DifferentSizes) {
+ {
+ ThreadClock vector1(10);
+ vector1.tick();
+ ThreadClock vector2(20);
+ vector2.tick();
+ {
+ SyncClock chunked;
+ vector1.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 11U);
+ vector2.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 21U);
+ chunked.Reset(&cache);
+ }
+ {
+ SyncClock chunked;
+ vector2.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 21U);
+ vector1.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 21U);
+ chunked.Reset(&cache);
+ }
+ {
+ SyncClock chunked;
+ vector1.release(&cache, &chunked);
+ vector2.acquire(&cache, &chunked);
+ ASSERT_EQ(vector2.size(), 21U);
+ chunked.Reset(&cache);
+ }
+ {
+ SyncClock chunked;
+ vector2.release(&cache, &chunked);
+ vector1.acquire(&cache, &chunked);
+ ASSERT_EQ(vector1.size(), 21U);
+ chunked.Reset(&cache);
+ }
+ }
+}
+
+TEST(Clock, Growth) {
+ {
+ ThreadClock vector(10);
+ vector.tick();
+ vector.set(5, 42);
+ SyncClock sync;
+ vector.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 11U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(1), 0ULL);
+ ASSERT_EQ(sync.get(5), 42ULL);
+ ASSERT_EQ(sync.get(9), 0ULL);
+ ASSERT_EQ(sync.get(10), 1ULL);
+ sync.Reset(&cache);
+ }
+ {
+ ThreadClock vector1(10);
+ vector1.tick();
+ ThreadClock vector2(20);
+ vector2.tick();
+ SyncClock sync;
+ vector1.release(&cache, &sync);
+ vector2.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 21U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(10), 1ULL);
+ ASSERT_EQ(sync.get(19), 0ULL);
+ ASSERT_EQ(sync.get(20), 1ULL);
+ sync.Reset(&cache);
+ }
+ {
+ ThreadClock vector(100);
+ vector.tick();
+ vector.set(5, 42);
+ vector.set(90, 84);
+ SyncClock sync;
+ vector.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 101U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(1), 0ULL);
+ ASSERT_EQ(sync.get(5), 42ULL);
+ ASSERT_EQ(sync.get(60), 0ULL);
+ ASSERT_EQ(sync.get(70), 0ULL);
+ ASSERT_EQ(sync.get(90), 84ULL);
+ ASSERT_EQ(sync.get(99), 0ULL);
+ ASSERT_EQ(sync.get(100), 1ULL);
+ sync.Reset(&cache);
+ }
+ {
+ ThreadClock vector1(10);
+ vector1.tick();
+ ThreadClock vector2(100);
+ vector2.tick();
+ SyncClock sync;
+ vector1.release(&cache, &sync);
+ vector2.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 101U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(10), 1ULL);
+ ASSERT_EQ(sync.get(99), 0ULL);
+ ASSERT_EQ(sync.get(100), 1ULL);
+ sync.Reset(&cache);
+ }
+}
+
+const uptr kThreads = 4;
+const uptr kClocks = 4;
+
+// SimpleSyncClock and SimpleThreadClock implement the same thing as
+// SyncClock and ThreadClock, but in a very simple way.
+struct SimpleSyncClock {
+ u64 clock[kThreads];
+ uptr size;
+
+ SimpleSyncClock() {
+ Reset();
+ }
+
+ void Reset() {
+ size = 0;
+ for (uptr i = 0; i < kThreads; i++)
+ clock[i] = 0;
+ }
+
+ bool verify(const SyncClock *other) const {
+ for (uptr i = 0; i < min(size, other->size()); i++) {
+ if (clock[i] != other->get(i))
+ return false;
+ }
+ for (uptr i = min(size, other->size()); i < max(size, other->size()); i++) {
+ if (i < size && clock[i] != 0)
+ return false;
+ if (i < other->size() && other->get(i) != 0)
+ return false;
+ }
+ return true;
+ }
+};
+
+struct SimpleThreadClock {
+ u64 clock[kThreads];
+ uptr size;
+ unsigned tid;
+
+ explicit SimpleThreadClock(unsigned tid) {
+ this->tid = tid;
+ size = tid + 1;
+ for (uptr i = 0; i < kThreads; i++)
+ clock[i] = 0;
+ }
+
+ void tick() {
+ clock[tid]++;
+ }
+
+ void acquire(const SimpleSyncClock *src) {
+ if (size < src->size)
+ size = src->size;
+ for (uptr i = 0; i < kThreads; i++)
+ clock[i] = max(clock[i], src->clock[i]);
+ }
+
+ void release(SimpleSyncClock *dst) const {
+ if (dst->size < size)
+ dst->size = size;
+ for (uptr i = 0; i < kThreads; i++)
+ dst->clock[i] = max(dst->clock[i], clock[i]);
+ }
+
+ void acq_rel(SimpleSyncClock *dst) {
+ acquire(dst);
+ release(dst);
+ }
+
+ void ReleaseStore(SimpleSyncClock *dst) const {
+ if (dst->size < size)
+ dst->size = size;
+ for (uptr i = 0; i < kThreads; i++)
+ dst->clock[i] = clock[i];
+ }
+
+ bool verify(const ThreadClock *other) const {
+ for (uptr i = 0; i < min(size, other->size()); i++) {
+ if (clock[i] != other->get(i))
+ return false;
+ }
+ for (uptr i = min(size, other->size()); i < max(size, other->size()); i++) {
+ if (i < size && clock[i] != 0)
+ return false;
+ if (i < other->size() && other->get(i) != 0)
+ return false;
+ }
+ return true;
+ }
+};
+
+static bool ClockFuzzer(bool printing) {
+ // Create kThreads thread clocks.
+ SimpleThreadClock *thr0[kThreads];
+ ThreadClock *thr1[kThreads];
+ unsigned reused[kThreads];
+ for (unsigned i = 0; i < kThreads; i++) {
+ reused[i] = 0;
+ thr0[i] = new SimpleThreadClock(i);
+ thr1[i] = new ThreadClock(i, reused[i]);
+ }
+
+ // Create kClocks sync clocks.
+ SimpleSyncClock *sync0[kClocks];
+ SyncClock *sync1[kClocks];
+ for (unsigned i = 0; i < kClocks; i++) {
+ sync0[i] = new SimpleSyncClock();
+ sync1[i] = new SyncClock();
+ }
+
+ // Do N random operations (acquire, release, etc) and compare results
+ // for SimpleThread/SyncClock and real Thread/SyncClock.
+ for (int i = 0; i < 10000; i++) {
+ unsigned tid = rand() % kThreads;
+ unsigned cid = rand() % kClocks;
+ thr0[tid]->tick();
+ thr1[tid]->tick();
+
+ switch (rand() % 6) {
+ case 0:
+ if (printing)
+ printf("acquire thr%d <- clk%d\n", tid, cid);
+ thr0[tid]->acquire(sync0[cid]);
+ thr1[tid]->acquire(&cache, sync1[cid]);
+ break;
+ case 1:
+ if (printing)
+ printf("release thr%d -> clk%d\n", tid, cid);
+ thr0[tid]->release(sync0[cid]);
+ thr1[tid]->release(&cache, sync1[cid]);
+ break;
+ case 2:
+ if (printing)
+ printf("acq_rel thr%d <> clk%d\n", tid, cid);
+ thr0[tid]->acq_rel(sync0[cid]);
+ thr1[tid]->acq_rel(&cache, sync1[cid]);
+ break;
+ case 3:
+ if (printing)
+ printf("rel_str thr%d >> clk%d\n", tid, cid);
+ thr0[tid]->ReleaseStore(sync0[cid]);
+ thr1[tid]->ReleaseStore(&cache, sync1[cid]);
+ break;
+ case 4:
+ if (printing)
+ printf("reset clk%d\n", cid);
+ sync0[cid]->Reset();
+ sync1[cid]->Reset(&cache);
+ break;
+ case 5:
+ if (printing)
+ printf("reset thr%d\n", tid);
+ u64 epoch = thr0[tid]->clock[tid] + 1;
+ reused[tid]++;
+ delete thr0[tid];
+ thr0[tid] = new SimpleThreadClock(tid);
+ thr0[tid]->clock[tid] = epoch;
+ delete thr1[tid];
+ thr1[tid] = new ThreadClock(tid, reused[tid]);
+ thr1[tid]->set(epoch);
+ break;
+ }
+
+ if (printing) {
+ for (unsigned i = 0; i < kThreads; i++) {
+ printf("thr%d: ", i);
+ thr1[i]->DebugDump(printf);
+ printf("\n");
+ }
+ for (unsigned i = 0; i < kClocks; i++) {
+ printf("clk%d: ", i);
+ sync1[i]->DebugDump(printf);
+ printf("\n");
+ }
+
+ printf("\n");
+ }
+
+ if (!thr0[tid]->verify(thr1[tid]) || !sync0[cid]->verify(sync1[cid])) {
+ if (!printing)
+ return false;
+ printf("differs with model:\n");
+ for (unsigned i = 0; i < kThreads; i++) {
+ printf("thr%d: clock=[", i);
+ for (uptr j = 0; j < thr0[i]->size; j++)
+ printf("%s%llu", j == 0 ? "" : ",", thr0[i]->clock[j]);
+ printf("]\n");
+ }
+ for (unsigned i = 0; i < kClocks; i++) {
+ printf("clk%d: clock=[", i);
+ for (uptr j = 0; j < sync0[i]->size; j++)
+ printf("%s%llu", j == 0 ? "" : ",", sync0[i]->clock[j]);
+ printf("]\n");
+ }
+ return false;
+ }
+ }
+
+ for (unsigned i = 0; i < kClocks; i++) {
+ sync1[i]->Reset(&cache);
+ }
+ return true;
+}
+
+TEST(Clock, Fuzzer) {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ int seed = ts.tv_sec + ts.tv_nsec;
+ printf("seed=%d\n", seed);
+ srand(seed);
+ if (!ClockFuzzer(false)) {
+ // Redo the test with the same seed, but logging operations.
+ srand(seed);
+ ClockFuzzer(true);
+ ASSERT_TRUE(false);
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
new file mode 100644
index 000000000000..e848e48c6641
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
@@ -0,0 +1,55 @@
+//===-- tsan_dense_alloc_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_dense_alloc.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <map>
+
+namespace __tsan {
+
+TEST(DenseSlabAlloc, Basic) {
+ typedef DenseSlabAlloc<int, 128, 128> Alloc;
+ typedef Alloc::Cache Cache;
+ typedef Alloc::IndexT IndexT;
+ const int N = 1000;
+
+ Alloc alloc;
+ Cache cache;
+ alloc.InitCache(&cache);
+
+ IndexT blocks[N];
+ for (int ntry = 0; ntry < 3; ntry++) {
+ for (int i = 0; i < N; i++) {
+ IndexT idx = alloc.Alloc(&cache);
+ blocks[i] = idx;
+ EXPECT_NE(idx, 0U);
+ int *v = alloc.Map(idx);
+ *v = i;
+ }
+
+ for (int i = 0; i < N; i++) {
+ IndexT idx = blocks[i];
+ int *v = alloc.Map(idx);
+ EXPECT_EQ(*v, i);
+ alloc.Free(&cache, idx);
+ }
+
+ alloc.FlushCache(&cache);
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc
new file mode 100644
index 000000000000..22610c0dc42f
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc
@@ -0,0 +1,180 @@
+//===-- tsan_flags_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_flags.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+#include <string>
+
+namespace __tsan {
+
+TEST(Flags, Basic) {
+ // At least should not crash.
+ Flags f;
+ InitializeFlags(&f, 0);
+ InitializeFlags(&f, "");
+}
+
+TEST(Flags, DefaultValues) {
+ Flags f;
+
+ f.enable_annotations = false;
+ f.exitcode = -11;
+ InitializeFlags(&f, "");
+ EXPECT_EQ(66, f.exitcode);
+ EXPECT_EQ(true, f.enable_annotations);
+}
+
+static const char *options1 =
+ " enable_annotations=0"
+ " suppress_equal_stacks=0"
+ " suppress_equal_addresses=0"
+ " report_bugs=0"
+ " report_thread_leaks=0"
+ " report_destroy_locked=0"
+ " report_mutex_bugs=0"
+ " report_signal_unsafe=0"
+ " report_atomic_races=0"
+ " force_seq_cst_atomics=0"
+ " print_benign=0"
+ " exitcode=111"
+ " halt_on_error=0"
+ " atexit_sleep_ms=222"
+ " profile_memory=qqq"
+ " flush_memory_ms=444"
+ " flush_symbolizer_ms=555"
+ " memory_limit_mb=666"
+ " stop_on_start=0"
+ " running_on_valgrind=0"
+ " history_size=5"
+ " io_sync=1"
+ " die_after_fork=true"
+ "";
+
+static const char *options2 =
+ " enable_annotations=true"
+ " suppress_equal_stacks=true"
+ " suppress_equal_addresses=true"
+ " report_bugs=true"
+ " report_thread_leaks=true"
+ " report_destroy_locked=true"
+ " report_mutex_bugs=true"
+ " report_signal_unsafe=true"
+ " report_atomic_races=true"
+ " force_seq_cst_atomics=true"
+ " print_benign=true"
+ " exitcode=222"
+ " halt_on_error=true"
+ " atexit_sleep_ms=123"
+ " profile_memory=bbbbb"
+ " flush_memory_ms=234"
+ " flush_symbolizer_ms=345"
+ " memory_limit_mb=456"
+ " stop_on_start=true"
+ " running_on_valgrind=true"
+ " history_size=6"
+ " io_sync=2"
+ " die_after_fork=false"
+ "";
+
+void VerifyOptions1(Flags *f) {
+ EXPECT_EQ(f->enable_annotations, 0);
+ EXPECT_EQ(f->suppress_equal_stacks, 0);
+ EXPECT_EQ(f->suppress_equal_addresses, 0);
+ EXPECT_EQ(f->report_bugs, 0);
+ EXPECT_EQ(f->report_thread_leaks, 0);
+ EXPECT_EQ(f->report_destroy_locked, 0);
+ EXPECT_EQ(f->report_mutex_bugs, 0);
+ EXPECT_EQ(f->report_signal_unsafe, 0);
+ EXPECT_EQ(f->report_atomic_races, 0);
+ EXPECT_EQ(f->force_seq_cst_atomics, 0);
+ EXPECT_EQ(f->print_benign, 0);
+ EXPECT_EQ(f->exitcode, 111);
+ EXPECT_EQ(f->halt_on_error, 0);
+ EXPECT_EQ(f->atexit_sleep_ms, 222);
+ EXPECT_EQ(f->profile_memory, std::string("qqq"));
+ EXPECT_EQ(f->flush_memory_ms, 444);
+ EXPECT_EQ(f->flush_symbolizer_ms, 555);
+ EXPECT_EQ(f->memory_limit_mb, 666);
+ EXPECT_EQ(f->stop_on_start, 0);
+ EXPECT_EQ(f->running_on_valgrind, 0);
+ EXPECT_EQ(f->history_size, 5);
+ EXPECT_EQ(f->io_sync, 1);
+ EXPECT_EQ(f->die_after_fork, true);
+}
+
+void VerifyOptions2(Flags *f) {
+ EXPECT_EQ(f->enable_annotations, true);
+ EXPECT_EQ(f->suppress_equal_stacks, true);
+ EXPECT_EQ(f->suppress_equal_addresses, true);
+ EXPECT_EQ(f->report_bugs, true);
+ EXPECT_EQ(f->report_thread_leaks, true);
+ EXPECT_EQ(f->report_destroy_locked, true);
+ EXPECT_EQ(f->report_mutex_bugs, true);
+ EXPECT_EQ(f->report_signal_unsafe, true);
+ EXPECT_EQ(f->report_atomic_races, true);
+ EXPECT_EQ(f->force_seq_cst_atomics, true);
+ EXPECT_EQ(f->print_benign, true);
+ EXPECT_EQ(f->exitcode, 222);
+ EXPECT_EQ(f->halt_on_error, true);
+ EXPECT_EQ(f->atexit_sleep_ms, 123);
+ EXPECT_EQ(f->profile_memory, std::string("bbbbb"));
+ EXPECT_EQ(f->flush_memory_ms, 234);
+ EXPECT_EQ(f->flush_symbolizer_ms, 345);
+ EXPECT_EQ(f->memory_limit_mb, 456);
+ EXPECT_EQ(f->stop_on_start, true);
+ EXPECT_EQ(f->running_on_valgrind, true);
+ EXPECT_EQ(f->history_size, 6);
+ EXPECT_EQ(f->io_sync, 2);
+ EXPECT_EQ(f->die_after_fork, false);
+}
+
+static const char *test_default_options;
+extern "C" const char *__tsan_default_options() {
+ return test_default_options;
+}
+
+TEST(Flags, ParseDefaultOptions) {
+ Flags f;
+
+ test_default_options = options1;
+ InitializeFlags(&f, "");
+ VerifyOptions1(&f);
+
+ test_default_options = options2;
+ InitializeFlags(&f, "");
+ VerifyOptions2(&f);
+}
+
+TEST(Flags, ParseEnvOptions) {
+ Flags f;
+
+ InitializeFlags(&f, options1);
+ VerifyOptions1(&f);
+
+ InitializeFlags(&f, options2);
+ VerifyOptions2(&f);
+}
+
+TEST(Flags, ParsePriority) {
+ Flags f;
+
+ test_default_options = options2;
+ InitializeFlags(&f, options1);
+ VerifyOptions1(&f);
+
+ test_default_options = options1;
+ InitializeFlags(&f, options2);
+ VerifyOptions2(&f);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc
new file mode 100644
index 000000000000..bfaefe648705
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc
@@ -0,0 +1,153 @@
+//===-- tsan_mman_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include <limits>
+#include <sanitizer/allocator_interface.h>
+#include "tsan_mman.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Mman, Internal) {
+ char *p = (char*)internal_alloc(MBlockScopedBuf, 10);
+ EXPECT_NE(p, (char*)0);
+ char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20);
+ EXPECT_NE(p2, (char*)0);
+ EXPECT_NE(p2, p);
+ for (int i = 0; i < 10; i++) {
+ p[i] = 42;
+ }
+ for (int i = 0; i < 20; i++) {
+ ((char*)p2)[i] = 42;
+ }
+ internal_free(p);
+ internal_free(p2);
+}
+
+TEST(Mman, User) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ char *p = (char*)user_alloc(thr, pc, 10);
+ EXPECT_NE(p, (char*)0);
+ char *p2 = (char*)user_alloc(thr, pc, 20);
+ EXPECT_NE(p2, (char*)0);
+ EXPECT_NE(p2, p);
+ EXPECT_EQ(10U, user_alloc_usable_size(p));
+ EXPECT_EQ(20U, user_alloc_usable_size(p2));
+ user_free(thr, pc, p);
+ user_free(thr, pc, p2);
+}
+
+TEST(Mman, UserRealloc) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ {
+ void *p = user_realloc(thr, pc, 0, 0);
+ // Strictly saying this is incorrect, realloc(NULL, N) is equivalent to
+ // malloc(N), thus must return non-NULL pointer.
+ EXPECT_EQ(p, (void*)0);
+ }
+ {
+ void *p = user_realloc(thr, pc, 0, 100);
+ EXPECT_NE(p, (void*)0);
+ memset(p, 0xde, 100);
+ user_free(thr, pc, p);
+ }
+ {
+ void *p = user_alloc(thr, pc, 100);
+ EXPECT_NE(p, (void*)0);
+ memset(p, 0xde, 100);
+ void *p2 = user_realloc(thr, pc, p, 0);
+ EXPECT_EQ(p2, (void*)0);
+ }
+ {
+ void *p = user_realloc(thr, pc, 0, 100);
+ EXPECT_NE(p, (void*)0);
+ memset(p, 0xde, 100);
+ void *p2 = user_realloc(thr, pc, p, 10000);
+ EXPECT_NE(p2, (void*)0);
+ for (int i = 0; i < 100; i++)
+ EXPECT_EQ(((char*)p2)[i], (char)0xde);
+ memset(p2, 0xde, 10000);
+ user_free(thr, pc, p2);
+ }
+ {
+ void *p = user_realloc(thr, pc, 0, 10000);
+ EXPECT_NE(p, (void*)0);
+ memset(p, 0xde, 10000);
+ void *p2 = user_realloc(thr, pc, p, 10);
+ EXPECT_NE(p2, (void*)0);
+ for (int i = 0; i < 10; i++)
+ EXPECT_EQ(((char*)p2)[i], (char)0xde);
+ user_free(thr, pc, p2);
+ }
+}
+
+TEST(Mman, UsableSize) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ char *p = (char*)user_alloc(thr, pc, 10);
+ char *p2 = (char*)user_alloc(thr, pc, 20);
+ EXPECT_EQ(0U, user_alloc_usable_size(NULL));
+ EXPECT_EQ(10U, user_alloc_usable_size(p));
+ EXPECT_EQ(20U, user_alloc_usable_size(p2));
+ user_free(thr, pc, p);
+ user_free(thr, pc, p2);
+ EXPECT_EQ(0U, user_alloc_usable_size((void*)0x4123));
+}
+
+TEST(Mman, Stats) {
+ ThreadState *thr = cur_thread();
+
+ uptr alloc0 = __sanitizer_get_current_allocated_bytes();
+ uptr heap0 = __sanitizer_get_heap_size();
+ uptr free0 = __sanitizer_get_free_bytes();
+ uptr unmapped0 = __sanitizer_get_unmapped_bytes();
+
+ EXPECT_EQ(10U, __sanitizer_get_estimated_allocated_size(10));
+ EXPECT_EQ(20U, __sanitizer_get_estimated_allocated_size(20));
+ EXPECT_EQ(100U, __sanitizer_get_estimated_allocated_size(100));
+
+ char *p = (char*)user_alloc(thr, 0, 10);
+ EXPECT_TRUE(__sanitizer_get_ownership(p));
+ EXPECT_EQ(10U, __sanitizer_get_allocated_size(p));
+
+ EXPECT_EQ(alloc0 + 16, __sanitizer_get_current_allocated_bytes());
+ EXPECT_GE(__sanitizer_get_heap_size(), heap0);
+ EXPECT_EQ(free0, __sanitizer_get_free_bytes());
+ EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes());
+
+ user_free(thr, 0, p);
+
+ EXPECT_EQ(alloc0, __sanitizer_get_current_allocated_bytes());
+ EXPECT_GE(__sanitizer_get_heap_size(), heap0);
+ EXPECT_EQ(free0, __sanitizer_get_free_bytes());
+ EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes());
+}
+
+TEST(Mman, CallocOverflow) {
+#if SANITIZER_DEBUG
+ // EXPECT_DEATH clones a thread with 4K stack,
+ // which is overflown by tsan memory accesses functions in debug mode.
+ return;
+#endif
+ size_t kArraySize = 4096;
+ volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
+ volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+ volatile void *p = NULL;
+ EXPECT_DEATH(p = calloc(kArraySize, kArraySize2),
+ "allocator is terminating the process instead of returning 0");
+ EXPECT_EQ(0L, p);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc
new file mode 100644
index 000000000000..cce7f073b92f
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc
@@ -0,0 +1,126 @@
+//===-- tsan_mutex_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "tsan_mutex.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+template<typename MutexType>
+class TestData {
+ public:
+ explicit TestData(MutexType *mtx)
+ : mtx_(mtx) {
+ for (int i = 0; i < kSize; i++)
+ data_[i] = 0;
+ }
+
+ void Write() {
+ Lock l(mtx_);
+ T v0 = data_[0];
+ for (int i = 0; i < kSize; i++) {
+ CHECK_EQ(data_[i], v0);
+ data_[i]++;
+ }
+ }
+
+ void Read() {
+ ReadLock l(mtx_);
+ T v0 = data_[0];
+ for (int i = 0; i < kSize; i++) {
+ CHECK_EQ(data_[i], v0);
+ }
+ }
+
+ void Backoff() {
+ volatile T data[kSize] = {};
+ for (int i = 0; i < kSize; i++) {
+ data[i]++;
+ CHECK_EQ(data[i], 1);
+ }
+ }
+
+ private:
+ typedef GenericScopedLock<MutexType> Lock;
+ static const int kSize = 64;
+ typedef u64 T;
+ MutexType *mtx_;
+ char pad_[kCacheLineSize];
+ T data_[kSize];
+};
+
+const int kThreads = 8;
+const int kWriteRate = 1024;
+#if SANITIZER_DEBUG
+const int kIters = 16*1024;
+#else
+const int kIters = 64*1024;
+#endif
+
+template<typename MutexType>
+static void *write_mutex_thread(void *param) {
+ TestData<MutexType> *data = (TestData<MutexType>*)param;
+ for (int i = 0; i < kIters; i++) {
+ data->Write();
+ data->Backoff();
+ }
+ return 0;
+}
+
+template<typename MutexType>
+static void *read_mutex_thread(void *param) {
+ TestData<MutexType> *data = (TestData<MutexType>*)param;
+ for (int i = 0; i < kIters; i++) {
+ if ((i % kWriteRate) == 0)
+ data->Write();
+ else
+ data->Read();
+ data->Backoff();
+ }
+ return 0;
+}
+
+TEST(Mutex, Write) {
+ Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
+ TestData<Mutex> data(&mtx);
+ pthread_t threads[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&threads[i], 0, write_mutex_thread<Mutex>, &data);
+ for (int i = 0; i < kThreads; i++)
+ pthread_join(threads[i], 0);
+}
+
+TEST(Mutex, ReadWrite) {
+ Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
+ TestData<Mutex> data(&mtx);
+ pthread_t threads[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&threads[i], 0, read_mutex_thread<Mutex>, &data);
+ for (int i = 0; i < kThreads; i++)
+ pthread_join(threads[i], 0);
+}
+
+TEST(Mutex, SpinWrite) {
+ SpinMutex mtx;
+ TestData<SpinMutex> data(&mtx);
+ pthread_t threads[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&threads[i], 0, write_mutex_thread<SpinMutex>, &data);
+ for (int i = 0; i < kThreads; i++)
+ pthread_join(threads[i], 0);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc
new file mode 100644
index 000000000000..335a7748cc1a
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc
@@ -0,0 +1,127 @@
+//===-- tsan_mutexset_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_mutexset.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+static void Expect(const MutexSet &mset, uptr i, u64 id, bool write, u64 epoch,
+ int count) {
+ MutexSet::Desc d = mset.Get(i);
+ EXPECT_EQ(id, d.id);
+ EXPECT_EQ(write, d.write);
+ EXPECT_EQ(epoch, d.epoch);
+ EXPECT_EQ(count, d.count);
+}
+
+TEST(MutexSet, Basic) {
+ MutexSet mset;
+ EXPECT_EQ(mset.Size(), (uptr)0);
+
+ mset.Add(1, true, 2);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ Expect(mset, 0, 1, true, 2, 1);
+ mset.Del(1, true);
+ EXPECT_EQ(mset.Size(), (uptr)0);
+
+ mset.Add(3, true, 4);
+ mset.Add(5, false, 6);
+ EXPECT_EQ(mset.Size(), (uptr)2);
+ Expect(mset, 0, 3, true, 4, 1);
+ Expect(mset, 1, 5, false, 6, 1);
+ mset.Del(3, true);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ mset.Del(5, false);
+ EXPECT_EQ(mset.Size(), (uptr)0);
+}
+
+TEST(MutexSet, DoubleAdd) {
+ MutexSet mset;
+ mset.Add(1, true, 2);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ Expect(mset, 0, 1, true, 2, 1);
+
+ mset.Add(1, true, 2);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ Expect(mset, 0, 1, true, 2, 2);
+
+ mset.Del(1, true);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ Expect(mset, 0, 1, true, 2, 1);
+
+ mset.Del(1, true);
+ EXPECT_EQ(mset.Size(), (uptr)0);
+}
+
+TEST(MutexSet, DoubleDel) {
+ MutexSet mset;
+ mset.Add(1, true, 2);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ mset.Del(1, true);
+ EXPECT_EQ(mset.Size(), (uptr)0);
+ mset.Del(1, true);
+ EXPECT_EQ(mset.Size(), (uptr)0);
+}
+
+TEST(MutexSet, Remove) {
+ MutexSet mset;
+ mset.Add(1, true, 2);
+ mset.Add(1, true, 2);
+ mset.Add(3, true, 4);
+ mset.Add(3, true, 4);
+ EXPECT_EQ(mset.Size(), (uptr)2);
+
+ mset.Remove(1);
+ EXPECT_EQ(mset.Size(), (uptr)1);
+ Expect(mset, 0, 3, true, 4, 2);
+}
+
+TEST(MutexSet, Full) {
+ MutexSet mset;
+ for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
+ mset.Add(i, true, i + 1);
+ }
+ EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
+ for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
+ Expect(mset, i, i, true, i + 1, 1);
+ }
+
+ for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
+ mset.Add(i, true, i + 1);
+ }
+ EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
+ for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
+ Expect(mset, i, i, true, i + 1, 2);
+ }
+}
+
+TEST(MutexSet, Overflow) {
+ MutexSet mset;
+ for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
+ mset.Add(i, true, i + 1);
+ mset.Add(i, true, i + 1);
+ }
+ mset.Add(100, true, 200);
+ EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
+ for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
+ if (i == 0)
+ Expect(mset, i, MutexSet::kMaxSize - 1,
+ true, MutexSet::kMaxSize, 2);
+ else if (i == MutexSet::kMaxSize - 1)
+ Expect(mset, i, 100, true, 200, 1);
+ else
+ Expect(mset, i, i, true, i + 1, 2);
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc
new file mode 100644
index 000000000000..17b17977bf86
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc
@@ -0,0 +1,78 @@
+//===-- tsan_shadow_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Shadow, FastState) {
+ Shadow s(FastState(11, 22));
+ EXPECT_EQ(s.tid(), (u64)11);
+ EXPECT_EQ(s.epoch(), (u64)22);
+ EXPECT_EQ(s.GetIgnoreBit(), false);
+ EXPECT_EQ(s.GetFreedAndReset(), false);
+ EXPECT_EQ(s.GetHistorySize(), 0);
+ EXPECT_EQ(s.addr0(), (u64)0);
+ EXPECT_EQ(s.size(), (u64)1);
+ EXPECT_EQ(s.IsWrite(), true);
+
+ s.IncrementEpoch();
+ EXPECT_EQ(s.epoch(), (u64)23);
+ s.IncrementEpoch();
+ EXPECT_EQ(s.epoch(), (u64)24);
+
+ s.SetIgnoreBit();
+ EXPECT_EQ(s.GetIgnoreBit(), true);
+ s.ClearIgnoreBit();
+ EXPECT_EQ(s.GetIgnoreBit(), false);
+
+ for (int i = 0; i < 8; i++) {
+ s.SetHistorySize(i);
+ EXPECT_EQ(s.GetHistorySize(), i);
+ }
+ s.SetHistorySize(2);
+ s.ClearHistorySize();
+ EXPECT_EQ(s.GetHistorySize(), 0);
+}
+
+TEST(Shadow, Mapping) {
+ static int global;
+ int stack;
+ void *heap = malloc(0);
+ free(heap);
+
+ CHECK(IsAppMem((uptr)&global));
+ CHECK(IsAppMem((uptr)&stack));
+ CHECK(IsAppMem((uptr)heap));
+
+ CHECK(IsShadowMem(MemToShadow((uptr)&global)));
+ CHECK(IsShadowMem(MemToShadow((uptr)&stack)));
+ CHECK(IsShadowMem(MemToShadow((uptr)heap)));
+}
+
+TEST(Shadow, Celling) {
+ u64 aligned_data[4];
+ char *data = (char*)aligned_data;
+ CHECK_EQ((uptr)data % kShadowSize, 0);
+ uptr s0 = MemToShadow((uptr)&data[0]);
+ CHECK_EQ(s0 % kShadowSize, 0);
+ for (unsigned i = 1; i < kShadowCell; i++)
+ CHECK_EQ(s0, MemToShadow((uptr)&data[i]));
+ for (unsigned i = kShadowCell; i < 2*kShadowCell; i++)
+ CHECK_EQ(s0 + kShadowSize*kShadowCnt, MemToShadow((uptr)&data[i]));
+ for (unsigned i = 2*kShadowCell; i < 3*kShadowCell; i++)
+ CHECK_EQ(s0 + 2*kShadowSize*kShadowCnt, MemToShadow((uptr)&data[i]));
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
new file mode 100644
index 000000000000..92e035d8d000
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
@@ -0,0 +1,95 @@
+//===-- tsan_stack_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_sync.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+#include <string.h>
+
+namespace __tsan {
+
+template <typename StackTraceTy>
+static void TestStackTrace(StackTraceTy *trace) {
+ ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ uptr stack[128];
+ thr.shadow_stack = &stack[0];
+ thr.shadow_stack_pos = &stack[0];
+ thr.shadow_stack_end = &stack[128];
+
+ ObtainCurrentStack(&thr, 0, trace);
+ EXPECT_EQ(0U, trace->size);
+
+ ObtainCurrentStack(&thr, 42, trace);
+ EXPECT_EQ(1U, trace->size);
+ EXPECT_EQ(42U, trace->trace[0]);
+
+ *thr.shadow_stack_pos++ = 100;
+ *thr.shadow_stack_pos++ = 101;
+ ObtainCurrentStack(&thr, 0, trace);
+ EXPECT_EQ(2U, trace->size);
+ EXPECT_EQ(100U, trace->trace[0]);
+ EXPECT_EQ(101U, trace->trace[1]);
+
+ ObtainCurrentStack(&thr, 42, trace);
+ EXPECT_EQ(3U, trace->size);
+ EXPECT_EQ(100U, trace->trace[0]);
+ EXPECT_EQ(101U, trace->trace[1]);
+ EXPECT_EQ(42U, trace->trace[2]);
+}
+
+template<typename StackTraceTy>
+static void TestTrim(StackTraceTy *trace) {
+ ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ const uptr kShadowStackSize = 2 * kStackTraceMax;
+ uptr stack[kShadowStackSize];
+ thr.shadow_stack = &stack[0];
+ thr.shadow_stack_pos = &stack[0];
+ thr.shadow_stack_end = &stack[kShadowStackSize];
+
+ for (uptr i = 0; i < kShadowStackSize; ++i)
+ *thr.shadow_stack_pos++ = 100 + i;
+
+ ObtainCurrentStack(&thr, 0, trace);
+ EXPECT_EQ(kStackTraceMax, trace->size);
+ for (uptr i = 0; i < kStackTraceMax; i++) {
+ EXPECT_EQ(100 + kStackTraceMax + i, trace->trace[i]);
+ }
+
+ ObtainCurrentStack(&thr, 42, trace);
+ EXPECT_EQ(kStackTraceMax, trace->size);
+ for (uptr i = 0; i < kStackTraceMax - 1; i++) {
+ EXPECT_EQ(101 + kStackTraceMax + i, trace->trace[i]);
+ }
+ EXPECT_EQ(42U, trace->trace[kStackTraceMax - 1]);
+}
+
+TEST(StackTrace, BasicVarSize) {
+ VarSizeStackTrace trace;
+ TestStackTrace(&trace);
+}
+
+TEST(StackTrace, BasicBuffered) {
+ BufferedStackTrace trace;
+ TestStackTrace(&trace);
+}
+
+TEST(StackTrace, TrimVarSize) {
+ VarSizeStackTrace trace;
+ TestTrim(&trace);
+}
+
+TEST(StackTrace, TrimBuffered) {
+ BufferedStackTrace trace;
+ TestTrim(&trace);
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc
new file mode 100644
index 000000000000..d3616a1a4b81
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc
@@ -0,0 +1,123 @@
+//===-- tsan_sync_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_sync.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(MetaMap, Basic) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[1] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
+ MBlock *mb = m->GetBlock((uptr)&block[0]);
+ EXPECT_NE(mb, (MBlock*)0);
+ EXPECT_EQ(mb->siz, 1 * sizeof(u64));
+ EXPECT_EQ(mb->tid, thr->tid);
+ uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
+ EXPECT_EQ(sz, 1 * sizeof(u64));
+ mb = m->GetBlock((uptr)&block[0]);
+ EXPECT_EQ(mb, (MBlock*)0);
+}
+
+TEST(MetaMap, FreeRange) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[4] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
+ m->AllocBlock(thr, 0, (uptr)&block[1], 3 * sizeof(u64));
+ MBlock *mb1 = m->GetBlock((uptr)&block[0]);
+ EXPECT_EQ(mb1->siz, 1 * sizeof(u64));
+ MBlock *mb2 = m->GetBlock((uptr)&block[1]);
+ EXPECT_EQ(mb2->siz, 3 * sizeof(u64));
+ m->FreeRange(thr, 0, (uptr)&block[0], 4 * sizeof(u64));
+ mb1 = m->GetBlock((uptr)&block[0]);
+ EXPECT_EQ(mb1, (MBlock*)0);
+ mb2 = m->GetBlock((uptr)&block[1]);
+ EXPECT_EQ(mb2, (MBlock*)0);
+}
+
+TEST(MetaMap, Sync) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[4] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 4 * sizeof(u64));
+ SyncVar *s1 = m->GetIfExistsAndLock((uptr)&block[0]);
+ EXPECT_EQ(s1, (SyncVar*)0);
+ s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
+ EXPECT_NE(s1, (SyncVar*)0);
+ EXPECT_EQ(s1->addr, (uptr)&block[0]);
+ s1->mtx.Unlock();
+ SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[1], false);
+ EXPECT_NE(s2, (SyncVar*)0);
+ EXPECT_EQ(s2->addr, (uptr)&block[1]);
+ s2->mtx.ReadUnlock();
+ m->FreeBlock(thr, 0, (uptr)&block[0]);
+ s1 = m->GetIfExistsAndLock((uptr)&block[0]);
+ EXPECT_EQ(s1, (SyncVar*)0);
+ s2 = m->GetIfExistsAndLock((uptr)&block[1]);
+ EXPECT_EQ(s2, (SyncVar*)0);
+ m->OnThreadIdle(thr);
+}
+
+TEST(MetaMap, MoveMemory) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block1[4] = {}; // fake malloc block
+ u64 block2[4] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block1[0], 3 * sizeof(u64));
+ m->AllocBlock(thr, 0, (uptr)&block1[3], 1 * sizeof(u64));
+ SyncVar *s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[0], true);
+ s1->mtx.Unlock();
+ SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[1], true);
+ s2->mtx.Unlock();
+ m->MoveMemory((uptr)&block1[0], (uptr)&block2[0], 4 * sizeof(u64));
+ MBlock *mb1 = m->GetBlock((uptr)&block1[0]);
+ EXPECT_EQ(mb1, (MBlock*)0);
+ MBlock *mb2 = m->GetBlock((uptr)&block1[3]);
+ EXPECT_EQ(mb2, (MBlock*)0);
+ mb1 = m->GetBlock((uptr)&block2[0]);
+ EXPECT_NE(mb1, (MBlock*)0);
+ EXPECT_EQ(mb1->siz, 3 * sizeof(u64));
+ mb2 = m->GetBlock((uptr)&block2[3]);
+ EXPECT_NE(mb2, (MBlock*)0);
+ EXPECT_EQ(mb2->siz, 1 * sizeof(u64));
+ s1 = m->GetIfExistsAndLock((uptr)&block1[0]);
+ EXPECT_EQ(s1, (SyncVar*)0);
+ s2 = m->GetIfExistsAndLock((uptr)&block1[1]);
+ EXPECT_EQ(s2, (SyncVar*)0);
+ s1 = m->GetIfExistsAndLock((uptr)&block2[0]);
+ EXPECT_NE(s1, (SyncVar*)0);
+ EXPECT_EQ(s1->addr, (uptr)&block2[0]);
+ s1->mtx.Unlock();
+ s2 = m->GetIfExistsAndLock((uptr)&block2[1]);
+ EXPECT_NE(s2, (SyncVar*)0);
+ EXPECT_EQ(s2->addr, (uptr)&block2[1]);
+ s2->mtx.Unlock();
+ m->FreeRange(thr, 0, (uptr)&block2[0], 4 * sizeof(u64));
+}
+
+TEST(MetaMap, ResetSync) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[1] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
+ SyncVar *s = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
+ s->Reset(thr);
+ s->mtx.Unlock();
+ uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
+ EXPECT_EQ(sz, 1 * sizeof(u64));
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc
new file mode 100644
index 000000000000..84d94dd03748
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc
@@ -0,0 +1,19 @@
+//===-- tsan_unit_test_main.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc
new file mode 100644
index 000000000000..c54ac1ee6de9
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc
@@ -0,0 +1,43 @@
+//===-- tsan_vector_test.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_vector.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Vector, Basic) {
+ Vector<int> v(MBlockScopedBuf);
+ EXPECT_EQ(v.Size(), (uptr)0);
+ v.PushBack(42);
+ EXPECT_EQ(v.Size(), (uptr)1);
+ EXPECT_EQ(v[0], 42);
+ v.PushBack(43);
+ EXPECT_EQ(v.Size(), (uptr)2);
+ EXPECT_EQ(v[0], 42);
+ EXPECT_EQ(v[1], 43);
+}
+
+TEST(Vector, Stride) {
+ Vector<int> v(MBlockScopedBuf);
+ for (int i = 0; i < 1000; i++) {
+ v.PushBack(i);
+ EXPECT_EQ(v.Size(), (uptr)(i + 1));
+ EXPECT_EQ(v[i], i);
+ }
+ for (int i = 0; i < 1000; i++) {
+ EXPECT_EQ(v[i], i);
+ }
+}
+
+} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan.syms.extra b/contrib/compiler-rt/lib/ubsan/ubsan.syms.extra
new file mode 100644
index 000000000000..7f8be694401a
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan.syms.extra
@@ -0,0 +1 @@
+__ubsan_*
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc b/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc
new file mode 100644
index 000000000000..4f2a2a9f3562
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc
@@ -0,0 +1,358 @@
+//===-- ubsan_diag.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Diagnostic reporting for the UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_diag.h"
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include <stdio.h>
+
+using namespace __ubsan;
+
+static void MaybePrintStackTrace(uptr pc, uptr bp) {
+ // We assume that flags are already parsed: InitIfNecessary
+ // will definitely be called when we print the first diagnostics message.
+ if (!flags()->print_stacktrace)
+ return;
+ // We can only use slow unwind, as we don't have any information about stack
+ // top/bottom.
+ // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
+ // fetch stack top/bottom information if we have it (e.g. if we're running
+ // under ASan).
+ if (StackTrace::WillUseFastUnwind(false))
+ return;
+ BufferedStackTrace stack;
+ stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+ stack.Print();
+}
+
+static void MaybeReportErrorSummary(Location Loc) {
+ if (!common_flags()->print_summary)
+ return;
+ // Don't try to unwind the stack trace in UBSan summaries: just use the
+ // provided location.
+ if (Loc.isSourceLocation()) {
+ SourceLocation SLoc = Loc.getSourceLocation();
+ if (!SLoc.isInvalid()) {
+ ReportErrorSummary("undefined-behavior", SLoc.getFilename(),
+ SLoc.getLine(), "");
+ return;
+ }
+ }
+ ReportErrorSummary("undefined-behavior");
+}
+
+namespace {
+class Decorator : public SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() {}
+ const char *Highlight() const { return Green(); }
+ const char *EndHighlight() const { return Default(); }
+ const char *Note() const { return Black(); }
+ const char *EndNote() const { return Default(); }
+};
+}
+
+SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) {
+ InitIfNecessary();
+ return Symbolizer::GetOrInit()->SymbolizePC(PC);
+}
+
+Diag &Diag::operator<<(const TypeDescriptor &V) {
+ return AddArg(V.getTypeName());
+}
+
+Diag &Diag::operator<<(const Value &V) {
+ if (V.getType().isSignedIntegerTy())
+ AddArg(V.getSIntValue());
+ else if (V.getType().isUnsignedIntegerTy())
+ AddArg(V.getUIntValue());
+ else if (V.getType().isFloatTy())
+ AddArg(V.getFloatValue());
+ else
+ AddArg("<unknown>");
+ return *this;
+}
+
+/// Hexadecimal printing for numbers too large for Printf to handle directly.
+static void PrintHex(UIntMax Val) {
+#if HAVE_INT128_T
+ Printf("0x%08x%08x%08x%08x",
+ (unsigned int)(Val >> 96),
+ (unsigned int)(Val >> 64),
+ (unsigned int)(Val >> 32),
+ (unsigned int)(Val));
+#else
+ UNREACHABLE("long long smaller than 64 bits?");
+#endif
+}
+
+static void renderLocation(Location Loc) {
+ InternalScopedString LocBuffer(1024);
+ switch (Loc.getKind()) {
+ case Location::LK_Source: {
+ SourceLocation SLoc = Loc.getSourceLocation();
+ if (SLoc.isInvalid())
+ LocBuffer.append("<unknown>");
+ else
+ RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+ SLoc.getColumn(), common_flags()->strip_path_prefix);
+ break;
+ }
+ case Location::LK_Memory:
+ LocBuffer.append("%p", Loc.getMemoryLocation());
+ break;
+ case Location::LK_Symbolized: {
+ const AddressInfo &Info = Loc.getSymbolizedStack()->info;
+ if (Info.file) {
+ RenderSourceLocation(&LocBuffer, Info.file, Info.line, Info.column,
+ common_flags()->strip_path_prefix);
+ } else if (Info.module) {
+ RenderModuleLocation(&LocBuffer, Info.module, Info.module_offset,
+ common_flags()->strip_path_prefix);
+ } else {
+ LocBuffer.append("%p", Info.address);
+ }
+ break;
+ }
+ case Location::LK_Null:
+ LocBuffer.append("<unknown>");
+ break;
+ }
+ Printf("%s:", LocBuffer.data());
+}
+
+static void renderText(const char *Message, const Diag::Arg *Args) {
+ for (const char *Msg = Message; *Msg; ++Msg) {
+ if (*Msg != '%') {
+ char Buffer[64];
+ unsigned I;
+ for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
+ Buffer[I] = Msg[I];
+ Buffer[I] = '\0';
+ Printf(Buffer);
+ Msg += I - 1;
+ } else {
+ const Diag::Arg &A = Args[*++Msg - '0'];
+ switch (A.Kind) {
+ case Diag::AK_String:
+ Printf("%s", A.String);
+ break;
+ case Diag::AK_Mangled: {
+ Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
+ break;
+ }
+ case Diag::AK_SInt:
+ // 'long long' is guaranteed to be at least 64 bits wide.
+ if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
+ Printf("%lld", (long long)A.SInt);
+ else
+ PrintHex(A.SInt);
+ break;
+ case Diag::AK_UInt:
+ if (A.UInt <= UINT64_MAX)
+ Printf("%llu", (unsigned long long)A.UInt);
+ else
+ PrintHex(A.UInt);
+ break;
+ case Diag::AK_Float: {
+ // FIXME: Support floating-point formatting in sanitizer_common's
+ // printf, and stop using snprintf here.
+ char Buffer[32];
+ snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
+ Printf("%s", Buffer);
+ break;
+ }
+ case Diag::AK_Pointer:
+ Printf("%p", A.Pointer);
+ break;
+ }
+ }
+ }
+}
+
+/// Find the earliest-starting range in Ranges which ends after Loc.
+static Range *upperBound(MemoryLocation Loc, Range *Ranges,
+ unsigned NumRanges) {
+ Range *Best = 0;
+ for (unsigned I = 0; I != NumRanges; ++I)
+ if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
+ (!Best ||
+ Best->getStart().getMemoryLocation() >
+ Ranges[I].getStart().getMemoryLocation()))
+ Best = &Ranges[I];
+ return Best;
+}
+
+static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) {
+ return (LHS < RHS) ? 0 : LHS - RHS;
+}
+
+static inline uptr addNoOverflow(uptr LHS, uptr RHS) {
+ const uptr Limit = (uptr)-1;
+ return (LHS > Limit - RHS) ? Limit : LHS + RHS;
+}
+
+/// Render a snippet of the address space near a location.
+static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
+ Range *Ranges, unsigned NumRanges,
+ const Diag::Arg *Args) {
+ // Show at least the 8 bytes surrounding Loc.
+ const unsigned MinBytesNearLoc = 4;
+ MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc);
+ MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc);
+ MemoryLocation OrigMin = Min;
+ for (unsigned I = 0; I < NumRanges; ++I) {
+ Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
+ Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
+ }
+
+ // If we have too many interesting bytes, prefer to show bytes after Loc.
+ const unsigned BytesToShow = 32;
+ if (Max - Min > BytesToShow)
+ Min = __sanitizer::Min(Max - BytesToShow, OrigMin);
+ Max = addNoOverflow(Min, BytesToShow);
+
+ if (!IsAccessibleMemoryRange(Min, Max - Min)) {
+ Printf("<memory cannot be printed>\n");
+ return;
+ }
+
+ // Emit data.
+ for (uptr P = Min; P != Max; ++P) {
+ unsigned char C = *reinterpret_cast<const unsigned char*>(P);
+ Printf("%s%02x", (P % 8 == 0) ? " " : " ", C);
+ }
+ Printf("\n");
+
+ // Emit highlights.
+ Printf(Decor.Highlight());
+ Range *InRange = upperBound(Min, Ranges, NumRanges);
+ for (uptr P = Min; P != Max; ++P) {
+ char Pad = ' ', Byte = ' ';
+ if (InRange && InRange->getEnd().getMemoryLocation() == P)
+ InRange = upperBound(P, Ranges, NumRanges);
+ if (!InRange && P > Loc)
+ break;
+ if (InRange && InRange->getStart().getMemoryLocation() < P)
+ Pad = '~';
+ if (InRange && InRange->getStart().getMemoryLocation() <= P)
+ Byte = '~';
+ char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
+ Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
+ }
+ Printf("%s\n", Decor.EndHighlight());
+
+ // Go over the line again, and print names for the ranges.
+ InRange = 0;
+ unsigned Spaces = 0;
+ for (uptr P = Min; P != Max; ++P) {
+ if (!InRange || InRange->getEnd().getMemoryLocation() == P)
+ InRange = upperBound(P, Ranges, NumRanges);
+ if (!InRange)
+ break;
+
+ Spaces += (P % 8) == 0 ? 2 : 1;
+
+ if (InRange && InRange->getStart().getMemoryLocation() == P) {
+ while (Spaces--)
+ Printf(" ");
+ renderText(InRange->getText(), Args);
+ Printf("\n");
+ // FIXME: We only support naming one range for now!
+ break;
+ }
+
+ Spaces += 2;
+ }
+
+ // FIXME: Print names for anything we can identify within the line:
+ //
+ // * If we can identify the memory itself as belonging to a particular
+ // global, stack variable, or dynamic allocation, then do so.
+ //
+ // * If we have a pointer-size, pointer-aligned range highlighted,
+ // determine whether the value of that range is a pointer to an
+ // entity which we can name, and if so, print that name.
+ //
+ // This needs an external symbolizer, or (preferably) ASan instrumentation.
+}
+
+Diag::~Diag() {
+ // All diagnostics should be printed under report mutex.
+ CommonSanitizerReportMutex.CheckLocked();
+ Decorator Decor;
+ Printf(Decor.Bold());
+
+ renderLocation(Loc);
+
+ switch (Level) {
+ case DL_Error:
+ Printf("%s runtime error: %s%s",
+ Decor.Warning(), Decor.EndWarning(), Decor.Bold());
+ break;
+
+ case DL_Note:
+ Printf("%s note: %s", Decor.Note(), Decor.EndNote());
+ break;
+ }
+
+ renderText(Message, Args);
+
+ Printf("%s\n", Decor.Default());
+
+ if (Loc.isMemoryLocation())
+ renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
+ NumRanges, Args);
+}
+
+ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
+ : Opts(Opts), SummaryLoc(SummaryLoc) {
+ InitIfNecessary();
+ CommonSanitizerReportMutex.Lock();
+}
+
+ScopedReport::~ScopedReport() {
+ MaybePrintStackTrace(Opts.pc, Opts.bp);
+ MaybeReportErrorSummary(SummaryLoc);
+ CommonSanitizerReportMutex.Unlock();
+ if (Opts.DieAfterReport || flags()->halt_on_error)
+ Die();
+}
+
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kVptrCheck[] = "vptr_check";
+static const char *kSuppressionTypes[] = { kVptrCheck };
+
+void __ubsan::InitializeSuppressions() {
+ CHECK_EQ(nullptr, suppression_ctx);
+ suppression_ctx = new (suppression_placeholder) // NOLINT
+ SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+ suppression_ctx->ParseFromFile(flags()->suppressions);
+}
+
+bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
+ // If .preinit_array is not used, it is possible that the UBSan runtime is not
+ // initialized.
+ if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
+ InitIfNecessary();
+ CHECK(suppression_ctx);
+ Suppression *s;
+ return suppression_ctx->Match(TypeName, kVptrCheck, &s);
+}
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_diag.h b/contrib/compiler-rt/lib/ubsan/ubsan_diag.h
new file mode 100644
index 000000000000..44dca90b7a53
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_diag.h
@@ -0,0 +1,243 @@
+//===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Diagnostics emission for Clang's undefined behavior sanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_DIAG_H
+#define UBSAN_DIAG_H
+
+#include "ubsan_value.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __ubsan {
+
+class SymbolizedStackHolder {
+ SymbolizedStack *Stack;
+
+ void clear() {
+ if (Stack)
+ Stack->ClearAll();
+ }
+
+public:
+ explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
+ : Stack(Stack) {}
+ ~SymbolizedStackHolder() { clear(); }
+ void reset(SymbolizedStack *S) {
+ if (Stack != S)
+ clear();
+ Stack = S;
+ }
+ const SymbolizedStack *get() const { return Stack; }
+};
+
+SymbolizedStack *getSymbolizedLocation(uptr PC);
+
+inline SymbolizedStack *getCallerLocation(uptr CallerPC) {
+ CHECK(CallerPC);
+ uptr PC = StackTrace::GetPreviousInstructionPc(CallerPC);
+ return getSymbolizedLocation(PC);
+}
+
+/// A location of some data within the program's address space.
+typedef uptr MemoryLocation;
+
+/// \brief Location at which a diagnostic can be emitted. Either a
+/// SourceLocation, a MemoryLocation, or a SymbolizedStack.
+class Location {
+public:
+ enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized };
+
+private:
+ LocationKind Kind;
+ // FIXME: In C++11, wrap these in an anonymous union.
+ SourceLocation SourceLoc;
+ MemoryLocation MemoryLoc;
+ const SymbolizedStack *SymbolizedLoc; // Not owned.
+
+public:
+ Location() : Kind(LK_Null) {}
+ Location(SourceLocation Loc) :
+ Kind(LK_Source), SourceLoc(Loc) {}
+ Location(MemoryLocation Loc) :
+ Kind(LK_Memory), MemoryLoc(Loc) {}
+ // SymbolizedStackHolder must outlive Location object.
+ Location(const SymbolizedStackHolder &Stack) :
+ Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {}
+
+ LocationKind getKind() const { return Kind; }
+
+ bool isSourceLocation() const { return Kind == LK_Source; }
+ bool isMemoryLocation() const { return Kind == LK_Memory; }
+ bool isSymbolizedStack() const { return Kind == LK_Symbolized; }
+
+ SourceLocation getSourceLocation() const {
+ CHECK(isSourceLocation());
+ return SourceLoc;
+ }
+ MemoryLocation getMemoryLocation() const {
+ CHECK(isMemoryLocation());
+ return MemoryLoc;
+ }
+ const SymbolizedStack *getSymbolizedStack() const {
+ CHECK(isSymbolizedStack());
+ return SymbolizedLoc;
+ }
+};
+
+/// A diagnostic severity level.
+enum DiagLevel {
+ DL_Error, ///< An error.
+ DL_Note ///< A note, attached to a prior diagnostic.
+};
+
+/// \brief Annotation for a range of locations in a diagnostic.
+class Range {
+ Location Start, End;
+ const char *Text;
+
+public:
+ Range() : Start(), End(), Text() {}
+ Range(MemoryLocation Start, MemoryLocation End, const char *Text)
+ : Start(Start), End(End), Text(Text) {}
+ Location getStart() const { return Start; }
+ Location getEnd() const { return End; }
+ const char *getText() const { return Text; }
+};
+
+/// \brief A mangled C++ name. Really just a strong typedef for 'const char*'.
+class MangledName {
+ const char *Name;
+public:
+ MangledName(const char *Name) : Name(Name) {}
+ const char *getName() const { return Name; }
+};
+
+/// \brief Representation of an in-flight diagnostic.
+///
+/// Temporary \c Diag instances are created by the handler routines to
+/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
+/// message.
+class Diag {
+ /// The location at which the problem occurred.
+ Location Loc;
+
+ /// The diagnostic level.
+ DiagLevel Level;
+
+ /// The message which will be emitted, with %0, %1, ... placeholders for
+ /// arguments.
+ const char *Message;
+
+public:
+ /// Kinds of arguments, corresponding to members of \c Arg's union.
+ enum ArgKind {
+ AK_String, ///< A string argument, displayed as-is.
+ AK_Mangled,///< A C++ mangled name, demangled before display.
+ AK_UInt, ///< An unsigned integer argument.
+ AK_SInt, ///< A signed integer argument.
+ AK_Float, ///< A floating-point argument.
+ AK_Pointer ///< A pointer argument, displayed in hexadecimal.
+ };
+
+ /// An individual diagnostic message argument.
+ struct Arg {
+ Arg() {}
+ Arg(const char *String) : Kind(AK_String), String(String) {}
+ Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {}
+ Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
+ Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
+ Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
+ Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
+
+ ArgKind Kind;
+ union {
+ const char *String;
+ UIntMax UInt;
+ SIntMax SInt;
+ FloatMax Float;
+ const void *Pointer;
+ };
+ };
+
+private:
+ static const unsigned MaxArgs = 5;
+ static const unsigned MaxRanges = 1;
+
+ /// The arguments which have been added to this diagnostic so far.
+ Arg Args[MaxArgs];
+ unsigned NumArgs;
+
+ /// The ranges which have been added to this diagnostic so far.
+ Range Ranges[MaxRanges];
+ unsigned NumRanges;
+
+ Diag &AddArg(Arg A) {
+ CHECK(NumArgs != MaxArgs);
+ Args[NumArgs++] = A;
+ return *this;
+ }
+
+ Diag &AddRange(Range A) {
+ CHECK(NumRanges != MaxRanges);
+ Ranges[NumRanges++] = A;
+ return *this;
+ }
+
+ /// \c Diag objects are not copyable.
+ Diag(const Diag &); // NOT IMPLEMENTED
+ Diag &operator=(const Diag &);
+
+public:
+ Diag(Location Loc, DiagLevel Level, const char *Message)
+ : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
+ ~Diag();
+
+ Diag &operator<<(const char *Str) { return AddArg(Str); }
+ Diag &operator<<(MangledName MN) { return AddArg(MN); }
+ Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
+ Diag &operator<<(const void *V) { return AddArg(V); }
+ Diag &operator<<(const TypeDescriptor &V);
+ Diag &operator<<(const Value &V);
+ Diag &operator<<(const Range &R) { return AddRange(R); }
+};
+
+struct ReportOptions {
+ /// If DieAfterReport is specified, UBSan will terminate the program after the
+ /// report is printed.
+ bool DieAfterReport;
+ /// pc/bp are used to unwind the stack trace.
+ uptr pc;
+ uptr bp;
+};
+
+#define GET_REPORT_OPTIONS(die_after_report) \
+ GET_CALLER_PC_BP; \
+ ReportOptions Opts = {die_after_report, pc, bp}
+
+/// \brief Instantiate this class before printing diagnostics in the error
+/// report. This class ensures that reports from different threads and from
+/// different sanitizers won't be mixed.
+class ScopedReport {
+ ReportOptions Opts;
+ Location SummaryLoc;
+
+public:
+ ScopedReport(ReportOptions Opts, Location SummaryLoc);
+ ~ScopedReport();
+};
+
+void InitializeSuppressions();
+bool IsVptrCheckSuppressed(const char *TypeName);
+
+} // namespace __ubsan
+
+#endif // UBSAN_DIAG_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc b/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc
new file mode 100644
index 000000000000..0dbffc9b102a
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc
@@ -0,0 +1,79 @@
+//===-- ubsan_flags.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+
+namespace __ubsan {
+
+static const char *MaybeCallUbsanDefaultOptions() {
+ return (&__ubsan_default_options) ? __ubsan_default_options() : "";
+}
+
+Flags ubsan_flags;
+
+void Flags::SetDefaults() {
+#define UBSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "ubsan_flags.inc"
+#undef UBSAN_FLAG
+}
+
+void RegisterUbsanFlags(FlagParser *parser, Flags *f) {
+#define UBSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "ubsan_flags.inc"
+#undef UBSAN_FLAG
+}
+
+void InitializeFlags(bool standalone) {
+ Flags *f = flags();
+ FlagParser parser;
+ RegisterUbsanFlags(&parser, f);
+
+ if (standalone) {
+ RegisterCommonFlags(&parser);
+
+ SetCommonFlagsDefaults();
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.print_summary = false;
+ OverrideCommonFlags(cf);
+ } else {
+ // Ignore common flags if not standalone.
+ // This is inconsistent with LSan, which allows common flags in LSAN_FLAGS.
+ // This is caused by undefined initialization order between ASan and UBsan,
+ // which makes it impossible to make sure that common flags from ASAN_OPTIONS
+ // have not been used (in __asan_init) before they are overwritten with flags
+ // from UBSAN_OPTIONS.
+ CommonFlags cf_ignored;
+ RegisterCommonFlags(&parser, &cf_ignored);
+ }
+
+ f->SetDefaults();
+ // Override from user-specified string.
+ parser.ParseString(MaybeCallUbsanDefaultOptions());
+ // Override from environment variable.
+ parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+ SetVerbosity(common_flags()->verbosity);
+}
+
+} // namespace __ubsan
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__ubsan_default_options() { return ""; }
+} // extern "C"
+#endif
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_flags.h b/contrib/compiler-rt/lib/ubsan/ubsan_flags.h
new file mode 100644
index 000000000000..b47f14e1e2fd
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_flags.h
@@ -0,0 +1,42 @@
+//===-- ubsan_flags.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_FLAGS_H
+#define UBSAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __ubsan {
+
+struct Flags {
+#define UBSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "ubsan_flags.inc"
+#undef UBSAN_FLAG
+
+ void SetDefaults();
+};
+
+extern Flags ubsan_flags;
+inline Flags *flags() { return &ubsan_flags; }
+
+void InitializeFlags(bool standalone);
+
+} // namespace __ubsan
+
+extern "C" {
+// Users may provide their own implementation of __ubsan_default_options to
+// override the default flag values.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__ubsan_default_options();
+} // extern "C"
+
+#endif // UBSAN_FLAGS_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc b/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc
new file mode 100644
index 000000000000..9ca31d13a9b6
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc
@@ -0,0 +1,25 @@
+//===-- ubsan_flags.inc -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UBSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_FLAG
+# error "Define UBSAN_FLAG prior to including this file!"
+#endif
+
+// UBSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+UBSAN_FLAG(bool, halt_on_error, false,
+ "Crash the program after printing the first error report")
+UBSAN_FLAG(bool, print_stacktrace, false,
+ "Include full stacktrace into an error report")
+UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
+
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc
new file mode 100644
index 000000000000..78e7508f7f93
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc
@@ -0,0 +1,421 @@
+//===-- ubsan_handlers.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Error logging entry points for the UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_handlers.h"
+#include "ubsan_diag.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+
+using namespace __sanitizer;
+using namespace __ubsan;
+
+static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
+ // If source location is already acquired, we don't need to print an error
+ // report for the second time. However, if we're in an unrecoverable handler,
+ // it's possible that location was required by concurrently running thread.
+ // In this case, we should continue the execution to ensure that any of
+ // threads will grab the report mutex and print the report before
+ // crashing the program.
+ return SLoc.isDisabled() && !Opts.DieAfterReport;
+}
+
+namespace __ubsan {
+const char *TypeCheckKinds[] = {
+ "load of", "store to", "reference binding to", "member access within",
+ "member call on", "constructor call on", "downcast of", "downcast of",
+ "upcast of", "cast to virtual base of"};
+}
+
+static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
+ ReportOptions Opts) {
+ Location Loc = Data->Loc.acquire();
+ // Use the SourceLocation from Data to track deduplication, even if 'invalid'
+ if (ignoreReport(Loc.getSourceLocation(), Opts))
+ return;
+
+ SymbolizedStackHolder FallbackLoc;
+ if (Data->Loc.isInvalid()) {
+ FallbackLoc.reset(getCallerLocation(Opts.pc));
+ Loc = FallbackLoc;
+ }
+
+ ScopedReport R(Opts, Loc);
+
+ if (!Pointer)
+ Diag(Loc, DL_Error, "%0 null pointer of type %1")
+ << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
+ else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
+ Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
+ "which requires %2 byte alignment")
+ << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
+ << Data->Alignment << Data->Type;
+ else
+ Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
+ "for an object of type %2")
+ << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+ if (Pointer)
+ Diag(Pointer, DL_Note, "pointer points here");
+}
+
+void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
+ ValueHandle Pointer) {
+ GET_REPORT_OPTIONS(false);
+ handleTypeMismatchImpl(Data, Pointer, Opts);
+}
+void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
+ ValueHandle Pointer) {
+ GET_REPORT_OPTIONS(true);
+ handleTypeMismatchImpl(Data, Pointer, Opts);
+ Die();
+}
+
+/// \brief Common diagnostic emission for various forms of integer overflow.
+template <typename T>
+static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
+ const char *Operator, T RHS,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error, "%0 integer overflow: "
+ "%1 %2 %3 cannot be represented in type %4")
+ << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
+ << Value(Data->Type, LHS) << Operator << RHS << Data->Type;
+}
+
+#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
+ void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
+ ValueHandle RHS) { \
+ GET_REPORT_OPTIONS(abort); \
+ handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
+ if (abort) Die(); \
+ }
+
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
+
+static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ if (Data->Type.isSignedIntegerTy())
+ Diag(Loc, DL_Error,
+ "negation of %0 cannot be represented in type %1; "
+ "cast to an unsigned type to negate this value to itself")
+ << Value(Data->Type, OldVal) << Data->Type;
+ else
+ Diag(Loc, DL_Error,
+ "negation of %0 cannot be represented in type %1")
+ << Value(Data->Type, OldVal) << Data->Type;
+}
+
+void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
+ ValueHandle OldVal) {
+ GET_REPORT_OPTIONS(false);
+ handleNegateOverflowImpl(Data, OldVal, Opts);
+}
+void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
+ ValueHandle OldVal) {
+ GET_REPORT_OPTIONS(true);
+ handleNegateOverflowImpl(Data, OldVal, Opts);
+ Die();
+}
+
+static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
+ ValueHandle RHS, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Value LHSVal(Data->Type, LHS);
+ Value RHSVal(Data->Type, RHS);
+ if (RHSVal.isMinusOne())
+ Diag(Loc, DL_Error,
+ "division of %0 by -1 cannot be represented in type %1")
+ << LHSVal << Data->Type;
+ else
+ Diag(Loc, DL_Error, "division by zero");
+}
+
+void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
+ ValueHandle LHS, ValueHandle RHS) {
+ GET_REPORT_OPTIONS(false);
+ handleDivremOverflowImpl(Data, LHS, RHS, Opts);
+}
+void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ GET_REPORT_OPTIONS(true);
+ handleDivremOverflowImpl(Data, LHS, RHS, Opts);
+ Die();
+}
+
+static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
+ ValueHandle LHS, ValueHandle RHS,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Value LHSVal(Data->LHSType, LHS);
+ Value RHSVal(Data->RHSType, RHS);
+ if (RHSVal.isNegative())
+ Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
+ else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
+ Diag(Loc, DL_Error,
+ "shift exponent %0 is too large for %1-bit type %2")
+ << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
+ else if (LHSVal.isNegative())
+ Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
+ else
+ Diag(Loc, DL_Error,
+ "left shift of %0 by %1 places cannot be represented in type %2")
+ << LHSVal << RHSVal << Data->LHSType;
+}
+
+void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ GET_REPORT_OPTIONS(false);
+ handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
+}
+void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
+ ShiftOutOfBoundsData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ GET_REPORT_OPTIONS(true);
+ handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
+ Die();
+}
+
+static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Value IndexVal(Data->IndexType, Index);
+ Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
+ << IndexVal << Data->ArrayType;
+}
+
+void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
+ ValueHandle Index) {
+ GET_REPORT_OPTIONS(false);
+ handleOutOfBoundsImpl(Data, Index, Opts);
+}
+void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
+ ValueHandle Index) {
+ GET_REPORT_OPTIONS(true);
+ handleOutOfBoundsImpl(Data, Index, Opts);
+ Die();
+}
+
+static void handleBuiltinUnreachableImpl(UnreachableData *Data,
+ ReportOptions Opts) {
+ ScopedReport R(Opts, Data->Loc);
+ Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
+}
+
+void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleBuiltinUnreachableImpl(Data, Opts);
+ Die();
+}
+
+static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
+ ScopedReport R(Opts, Data->Loc);
+ Diag(Data->Loc, DL_Error,
+ "execution reached the end of a value-returning function "
+ "without returning a value");
+}
+
+void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleMissingReturnImpl(Data, Opts);
+ Die();
+}
+
+static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error, "variable length array bound evaluates to "
+ "non-positive value %0")
+ << Value(Data->Type, Bound);
+}
+
+void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
+ ValueHandle Bound) {
+ GET_REPORT_OPTIONS(false);
+ handleVLABoundNotPositive(Data, Bound, Opts);
+}
+void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
+ ValueHandle Bound) {
+ GET_REPORT_OPTIONS(true);
+ handleVLABoundNotPositive(Data, Bound, Opts);
+ Die();
+}
+
+static void handleFloatCastOverflow(FloatCastOverflowData *Data,
+ ValueHandle From, ReportOptions Opts) {
+ // TODO: Add deduplication once a SourceLocation is generated for this check.
+ SymbolizedStackHolder CallerLoc(getCallerLocation(Opts.pc));
+ Location Loc = CallerLoc;
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error,
+ "value %0 is outside the range of representable values of type %2")
+ << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+}
+
+void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
+ ValueHandle From) {
+ GET_REPORT_OPTIONS(false);
+ handleFloatCastOverflow(Data, From, Opts);
+}
+void
+__ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
+ ValueHandle From) {
+ GET_REPORT_OPTIONS(true);
+ handleFloatCastOverflow(Data, From, Opts);
+ Die();
+}
+
+static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error,
+ "load of value %0, which is not a valid value for type %1")
+ << Value(Data->Type, Val) << Data->Type;
+}
+
+void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
+ ValueHandle Val) {
+ GET_REPORT_OPTIONS(false);
+ handleLoadInvalidValue(Data, Val, Opts);
+}
+void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
+ ValueHandle Val) {
+ GET_REPORT_OPTIONS(true);
+ handleLoadInvalidValue(Data, Val, Opts);
+ Die();
+}
+
+static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
+ ValueHandle Function,
+ ReportOptions Opts) {
+ SourceLocation CallLoc = Data->Loc.acquire();
+ if (ignoreReport(CallLoc, Opts))
+ return;
+
+ ScopedReport R(Opts, CallLoc);
+
+ SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
+ const char *FName = FLoc.get()->info.function;
+ if (!FName)
+ FName = "(unknown)";
+
+ Diag(CallLoc, DL_Error,
+ "call to function %0 through pointer to incorrect function type %1")
+ << FName << Data->Type;
+ Diag(FLoc, DL_Note, "%0 defined here") << FName;
+}
+
+void
+__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
+ ValueHandle Function) {
+ GET_REPORT_OPTIONS(false);
+ handleFunctionTypeMismatch(Data, Function, Opts);
+}
+
+void __ubsan::__ubsan_handle_function_type_mismatch_abort(
+ FunctionTypeMismatchData *Data, ValueHandle Function) {
+ GET_REPORT_OPTIONS(true);
+ handleFunctionTypeMismatch(Data, Function, Opts);
+ Die();
+}
+
+static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error, "null pointer returned from function declared to never "
+ "return null");
+ if (!Data->AttrLoc.isInvalid())
+ Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullReturn(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullReturn(Data, Opts);
+ Die();
+}
+
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
+ "never be null") << Data->ArgIndex;
+ if (!Data->AttrLoc.isInvalid())
+ Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullArg(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullArg(Data, Opts);
+ Die();
+}
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h
new file mode 100644
index 000000000000..87149f259607
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h
@@ -0,0 +1,145 @@
+//===-- ubsan_handlers.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Entry points to the runtime library for Clang's undefined behavior sanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_HANDLERS_H
+#define UBSAN_HANDLERS_H
+
+#include "ubsan_value.h"
+
+namespace __ubsan {
+
+struct TypeMismatchData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+ uptr Alignment;
+ unsigned char TypeCheckKind;
+};
+
+#define UNRECOVERABLE(checkname, ...) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
+ void __ubsan_handle_ ## checkname( __VA_ARGS__ );
+
+#define RECOVERABLE(checkname, ...) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
+ void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
+ void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ );
+
+/// \brief Handle a runtime type check failure, caused by either a misaligned
+/// pointer, a null pointer, or a pointer to insufficient storage for the
+/// type.
+RECOVERABLE(type_mismatch, TypeMismatchData *Data, ValueHandle Pointer)
+
+struct OverflowData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+/// \brief Handle an integer addition overflow.
+RECOVERABLE(add_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
+
+/// \brief Handle an integer subtraction overflow.
+RECOVERABLE(sub_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
+
+/// \brief Handle an integer multiplication overflow.
+RECOVERABLE(mul_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
+
+/// \brief Handle a signed integer overflow for a unary negate operator.
+RECOVERABLE(negate_overflow, OverflowData *Data, ValueHandle OldVal)
+
+/// \brief Handle an INT_MIN/-1 overflow or division by zero.
+RECOVERABLE(divrem_overflow, OverflowData *Data,
+ ValueHandle LHS, ValueHandle RHS)
+
+struct ShiftOutOfBoundsData {
+ SourceLocation Loc;
+ const TypeDescriptor &LHSType;
+ const TypeDescriptor &RHSType;
+};
+
+/// \brief Handle a shift where the RHS is out of bounds or a left shift where
+/// the LHS is negative or overflows.
+RECOVERABLE(shift_out_of_bounds, ShiftOutOfBoundsData *Data,
+ ValueHandle LHS, ValueHandle RHS)
+
+struct OutOfBoundsData {
+ SourceLocation Loc;
+ const TypeDescriptor &ArrayType;
+ const TypeDescriptor &IndexType;
+};
+
+/// \brief Handle an array index out of bounds error.
+RECOVERABLE(out_of_bounds, OutOfBoundsData *Data, ValueHandle Index)
+
+struct UnreachableData {
+ SourceLocation Loc;
+};
+
+/// \brief Handle a __builtin_unreachable which is reached.
+UNRECOVERABLE(builtin_unreachable, UnreachableData *Data)
+/// \brief Handle reaching the end of a value-returning function.
+UNRECOVERABLE(missing_return, UnreachableData *Data)
+
+struct VLABoundData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+/// \brief Handle a VLA with a non-positive bound.
+RECOVERABLE(vla_bound_not_positive, VLABoundData *Data, ValueHandle Bound)
+
+struct FloatCastOverflowData {
+ // FIXME: SourceLocation Loc;
+ const TypeDescriptor &FromType;
+ const TypeDescriptor &ToType;
+};
+
+/// \brief Handle overflow in a conversion to or from a floating-point type.
+RECOVERABLE(float_cast_overflow, FloatCastOverflowData *Data, ValueHandle From)
+
+struct InvalidValueData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+/// \brief Handle a load of an invalid value for the type.
+RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
+
+struct FunctionTypeMismatchData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+RECOVERABLE(function_type_mismatch,
+ FunctionTypeMismatchData *Data,
+ ValueHandle Val)
+
+struct NonNullReturnData {
+ SourceLocation Loc;
+ SourceLocation AttrLoc;
+};
+
+/// \brief Handle returning null from function with returns_nonnull attribute.
+RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+
+struct NonNullArgData {
+ SourceLocation Loc;
+ SourceLocation AttrLoc;
+ int ArgIndex;
+};
+
+/// \brief Handle passing null pointer to function with nonnull attribute.
+RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+
+}
+
+#endif // UBSAN_HANDLERS_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
new file mode 100644
index 000000000000..4718e6eacee2
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
@@ -0,0 +1,81 @@
+//===-- ubsan_handlers_cxx.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Error logging entry points for the UBSan runtime, which are only used for C++
+// compilations. This file is permitted to use language features which require
+// linking against a C++ ABI library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_handlers_cxx.h"
+#include "ubsan_diag.h"
+#include "ubsan_type_hash.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+
+using namespace __sanitizer;
+using namespace __ubsan;
+
+namespace __ubsan {
+ extern const char *TypeCheckKinds[];
+}
+
+static void HandleDynamicTypeCacheMiss(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
+ ReportOptions Opts) {
+ if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
+ // Just a cache miss. The type matches after all.
+ return;
+
+ // Check if error report should be suppressed.
+ DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
+ if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
+ return;
+
+ SourceLocation Loc = Data->Loc.acquire();
+ if (Loc.isDisabled())
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error,
+ "%0 address %1 which does not point to an object of type %2")
+ << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+
+ // If possible, say what type it actually points to.
+ if (!DTI.isValid())
+ Diag(Pointer, DL_Note, "object has invalid vptr")
+ << MangledName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+ else if (!DTI.getOffset())
+ Diag(Pointer, DL_Note, "object is of type %0")
+ << MangledName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
+ else
+ // FIXME: Find the type at the specified offset, and include that
+ // in the note.
+ Diag(Pointer - DTI.getOffset(), DL_Note,
+ "object is base class subobject at offset %0 within object of type %1")
+ << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
+ << MangledName(DTI.getSubobjectTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr),
+ "vptr for %2 base class of %1");
+}
+
+void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+ GET_REPORT_OPTIONS(false);
+ HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
+}
+void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+ GET_REPORT_OPTIONS(true);
+ HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
+}
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h b/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h
new file mode 100644
index 000000000000..cb1bca78b833
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h
@@ -0,0 +1,40 @@
+//===-- ubsan_handlers_cxx.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Entry points to the runtime library for Clang's undefined behavior sanitizer,
+// for C++-specific checks. This code is not linked into C binaries.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_HANDLERS_CXX_H
+#define UBSAN_HANDLERS_CXX_H
+
+#include "ubsan_value.h"
+
+namespace __ubsan {
+
+struct DynamicTypeCacheMissData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+ void *TypeInfo;
+ unsigned char TypeCheckKind;
+};
+
+/// \brief Handle a runtime type check failure, caused by an incorrect vptr.
+/// When this handler is called, all we know is that the type was not in the
+/// cache; this does not necessarily imply the existence of a bug.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __ubsan_handle_dynamic_type_cache_miss(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __ubsan_handle_dynamic_type_cache_miss_abort(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
+
+}
+
+#endif // UBSAN_HANDLERS_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_init.cc b/contrib/compiler-rt/lib/ubsan/ubsan_init.cc
new file mode 100644
index 000000000000..219273d51921
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_init.cc
@@ -0,0 +1,63 @@
+//===-- ubsan_init.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization of UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_diag.h"
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+using namespace __ubsan;
+
+static bool ubsan_inited;
+
+void __ubsan::InitIfNecessary() {
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+ // No need to lock mutex if we're initializing from preinit array.
+ static StaticSpinMutex init_mu;
+ SpinMutexLock l(&init_mu);
+#endif
+ if (LIKELY(ubsan_inited))
+ return;
+ bool standalone = false;
+ if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
+ // WARNING: If this condition holds, then either UBSan runs in a standalone
+ // mode, or initializer for another sanitizer hasn't run yet. In a latter
+ // case, another sanitizer will overwrite "SanitizerToolName" and reparse
+ // common flags. It means, that we are not allowed to *use* common flags
+ // in this function.
+ SanitizerToolName = "UndefinedBehaviorSanitizer";
+ standalone = true;
+ }
+ // Initialize UBSan-specific flags.
+ InitializeFlags(standalone);
+ InitializeSuppressions();
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+ ubsan_inited = true;
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary;
+#else
+// Use a dynamic initializer.
+class UbsanInitializer {
+ public:
+ UbsanInitializer() {
+ InitIfNecessary();
+ }
+};
+static UbsanInitializer ubsan_initializer;
+#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_init.h b/contrib/compiler-rt/lib/ubsan/ubsan_init.h
new file mode 100644
index 000000000000..18356cfca617
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_init.h
@@ -0,0 +1,24 @@
+//===-- ubsan_init.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization function for UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_INIT_H
+#define UBSAN_INIT_H
+
+namespace __ubsan {
+
+// NOTE: This function might take a lock (if .preinit_array initialization is
+// not used). It's generally a bad idea to call it on a fast path.
+void InitIfNecessary();
+
+} // namespace __ubsan
+
+#endif // UBSAN_INIT_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_type_hash.cc b/contrib/compiler-rt/lib/ubsan/ubsan_type_hash.cc
new file mode 100644
index 000000000000..a388bcc6d72e
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_type_hash.cc
@@ -0,0 +1,250 @@
+//===-- ubsan_type_hash.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of a hash table for fast checking of inheritance
+// relationships. This file is only linked into C++ compilations, and is
+// permitted to use language features which require a C++ ABI library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_type_hash.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+
+// The following are intended to be binary compatible with the definitions
+// given in the Itanium ABI. We make no attempt to be ODR-compatible with
+// those definitions, since existing ABI implementations aren't.
+
+namespace std {
+ class type_info {
+ public:
+ virtual ~type_info();
+
+ const char *__type_name;
+ };
+}
+
+namespace __cxxabiv1 {
+
+/// Type info for classes with no bases, and base class for type info for
+/// classes with bases.
+class __class_type_info : public std::type_info {
+ virtual ~__class_type_info();
+};
+
+/// Type info for classes with simple single public inheritance.
+class __si_class_type_info : public __class_type_info {
+public:
+ virtual ~__si_class_type_info();
+
+ const __class_type_info *__base_type;
+};
+
+class __base_class_type_info {
+public:
+ const __class_type_info *__base_type;
+ long __offset_flags;
+
+ enum __offset_flags_masks {
+ __virtual_mask = 0x1,
+ __public_mask = 0x2,
+ __offset_shift = 8
+ };
+};
+
+/// Type info for classes with multiple, virtual, or non-public inheritance.
+class __vmi_class_type_info : public __class_type_info {
+public:
+ virtual ~__vmi_class_type_info();
+
+ unsigned int flags;
+ unsigned int base_count;
+ __base_class_type_info base_info[1];
+};
+
+}
+
+namespace abi = __cxxabiv1;
+
+// We implement a simple two-level cache for type-checking results. For each
+// (vptr,type) pair, a hash is computed. This hash is assumed to be globally
+// unique; if it collides, we will get false negatives, but:
+// * such a collision would have to occur on the *first* bad access,
+// * the probability of such a collision is low (and for a 64-bit target, is
+// negligible), and
+// * the vptr, and thus the hash, can be affected by ASLR, so multiple runs
+// give better coverage.
+//
+// The first caching layer is a small hash table with no chaining; buckets are
+// reused as needed. The second caching layer is a large hash table with open
+// chaining. We can freely evict from either layer since this is just a cache.
+//
+// FIXME: Make these hash table accesses thread-safe. The races here are benign:
+// assuming the unsequenced loads and stores don't misbehave too badly,
+// the worst case is false negatives or poor cache behavior, not false
+// positives or crashes.
+
+/// Find a bucket to store the given hash value in.
+static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
+ static const unsigned HashTableSize = 65537;
+ static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize];
+
+ unsigned First = (V & 65535) ^ 1;
+ unsigned Probe = First;
+ for (int Tries = 5; Tries; --Tries) {
+ if (!__ubsan_vptr_hash_set[Probe] || __ubsan_vptr_hash_set[Probe] == V)
+ return &__ubsan_vptr_hash_set[Probe];
+ Probe += ((V >> 16) & 65535) + 1;
+ if (Probe >= HashTableSize)
+ Probe -= HashTableSize;
+ }
+ // FIXME: Pick a random entry from the probe sequence to evict rather than
+ // just taking the first.
+ return &__ubsan_vptr_hash_set[First];
+}
+
+/// A cache of recently-checked hashes. Mini hash table with "random" evictions.
+__ubsan::HashValue
+__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize];
+
+/// \brief Determine whether \p Derived has a \p Base base class subobject at
+/// offset \p Offset.
+static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
+ const abi::__class_type_info *Base,
+ sptr Offset) {
+ if (Derived->__type_name == Base->__type_name)
+ return Offset == 0;
+
+ if (const abi::__si_class_type_info *SI =
+ dynamic_cast<const abi::__si_class_type_info*>(Derived))
+ return isDerivedFromAtOffset(SI->__base_type, Base, Offset);
+
+ const abi::__vmi_class_type_info *VTI =
+ dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
+ if (!VTI)
+ // No base class subobjects.
+ return false;
+
+ // Look for a base class which is derived from \p Base at the right offset.
+ for (unsigned int base = 0; base != VTI->base_count; ++base) {
+ // FIXME: Curtail the recursion if this base can't possibly contain the
+ // given offset.
+ sptr OffsetHere = VTI->base_info[base].__offset_flags >>
+ abi::__base_class_type_info::__offset_shift;
+ if (VTI->base_info[base].__offset_flags &
+ abi::__base_class_type_info::__virtual_mask)
+ // For now, just punt on virtual bases and say 'yes'.
+ // FIXME: OffsetHere is the offset in the vtable of the virtual base
+ // offset. Read the vbase offset out of the vtable and use it.
+ return true;
+ if (isDerivedFromAtOffset(VTI->base_info[base].__base_type,
+ Base, Offset - OffsetHere))
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Find the derived-most dynamic base class of \p Derived at offset
+/// \p Offset.
+static const abi::__class_type_info *findBaseAtOffset(
+ const abi::__class_type_info *Derived, sptr Offset) {
+ if (!Offset)
+ return Derived;
+
+ if (const abi::__si_class_type_info *SI =
+ dynamic_cast<const abi::__si_class_type_info*>(Derived))
+ return findBaseAtOffset(SI->__base_type, Offset);
+
+ const abi::__vmi_class_type_info *VTI =
+ dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
+ if (!VTI)
+ // No base class subobjects.
+ return 0;
+
+ for (unsigned int base = 0; base != VTI->base_count; ++base) {
+ sptr OffsetHere = VTI->base_info[base].__offset_flags >>
+ abi::__base_class_type_info::__offset_shift;
+ if (VTI->base_info[base].__offset_flags &
+ abi::__base_class_type_info::__virtual_mask)
+ // FIXME: Can't handle virtual bases yet.
+ continue;
+ if (const abi::__class_type_info *Base =
+ findBaseAtOffset(VTI->base_info[base].__base_type,
+ Offset - OffsetHere))
+ return Base;
+ }
+
+ return 0;
+}
+
+namespace {
+
+struct VtablePrefix {
+ /// The offset from the vptr to the start of the most-derived object.
+ /// This should never be greater than zero, and will usually be exactly
+ /// zero.
+ sptr Offset;
+ /// The type_info object describing the most-derived class type.
+ std::type_info *TypeInfo;
+};
+VtablePrefix *getVtablePrefix(void *Object) {
+ VtablePrefix **VptrPtr = reinterpret_cast<VtablePrefix**>(Object);
+ if (!*VptrPtr)
+ return 0;
+ VtablePrefix *Prefix = *VptrPtr - 1;
+ if (Prefix->Offset > 0 || !Prefix->TypeInfo)
+ // This can't possibly be a valid vtable.
+ return 0;
+ return Prefix;
+}
+
+}
+
+bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) {
+ // A crash anywhere within this function probably means the vptr is corrupted.
+ // FIXME: Perform these checks more cautiously.
+
+ // Check whether this is something we've evicted from the cache.
+ HashValue *Bucket = getTypeCacheHashTableBucket(Hash);
+ if (*Bucket == Hash) {
+ __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash;
+ return true;
+ }
+
+ VtablePrefix *Vtable = getVtablePrefix(Object);
+ if (!Vtable)
+ return false;
+
+ // Check that this is actually a type_info object for a class type.
+ abi::__class_type_info *Derived =
+ dynamic_cast<abi::__class_type_info*>(Vtable->TypeInfo);
+ if (!Derived)
+ return false;
+
+ abi::__class_type_info *Base = (abi::__class_type_info*)Type;
+ if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset))
+ return false;
+
+ // Success. Cache this result.
+ __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash;
+ *Bucket = Hash;
+ return true;
+}
+
+__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) {
+ VtablePrefix *Vtable = getVtablePrefix(Object);
+ if (!Vtable)
+ return DynamicTypeInfo(0, 0, 0);
+ const abi::__class_type_info *ObjectType = findBaseAtOffset(
+ static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
+ -Vtable->Offset);
+ return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
+ ObjectType ? ObjectType->__type_name : "<unknown>");
+}
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_type_hash.h b/contrib/compiler-rt/lib/ubsan/ubsan_type_hash.h
new file mode 100644
index 000000000000..58ecd3de9864
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_type_hash.h
@@ -0,0 +1,63 @@
+//===-- ubsan_type_hash.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Hashing of types for Clang's undefined behavior checker.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_TYPE_HASH_H
+#define UBSAN_TYPE_HASH_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __ubsan {
+
+typedef uptr HashValue;
+
+/// \brief Information about the dynamic type of an object (extracted from its
+/// vptr).
+class DynamicTypeInfo {
+ const char *MostDerivedTypeName;
+ sptr Offset;
+ const char *SubobjectTypeName;
+
+public:
+ DynamicTypeInfo(const char *MDTN, sptr Offset, const char *STN)
+ : MostDerivedTypeName(MDTN), Offset(Offset), SubobjectTypeName(STN) {}
+
+ /// Determine whether the object had a valid dynamic type.
+ bool isValid() const { return MostDerivedTypeName; }
+ /// Get the name of the most-derived type of the object.
+ const char *getMostDerivedTypeName() const { return MostDerivedTypeName; }
+ /// Get the offset from the most-derived type to this base class.
+ sptr getOffset() const { return Offset; }
+ /// Get the name of the most-derived type at the specified offset.
+ const char *getSubobjectTypeName() const { return SubobjectTypeName; }
+};
+
+/// \brief Get information about the dynamic type of an object.
+DynamicTypeInfo getDynamicTypeInfo(void *Object);
+
+/// \brief Check whether the dynamic type of \p Object has a \p Type subobject
+/// at offset 0.
+/// \return \c true if the type matches, \c false if not.
+bool checkDynamicType(void *Object, void *Type, HashValue Hash);
+
+const unsigned VptrTypeCacheSize = 128;
+
+/// \brief A cache of the results of checkDynamicType. \c checkDynamicType would
+/// return \c true (modulo hash collisions) if
+/// \code
+/// __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] == Hash
+/// \endcode
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+HashValue __ubsan_vptr_type_cache[VptrTypeCacheSize];
+
+} // namespace __ubsan
+
+#endif // UBSAN_TYPE_HASH_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_value.cc b/contrib/compiler-rt/lib/ubsan/ubsan_value.cc
new file mode 100644
index 000000000000..ab74720f60cf
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_value.cc
@@ -0,0 +1,102 @@
+//===-- ubsan_value.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Representation of a runtime value, as marshaled from the generated code to
+// the ubsan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_value.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+using namespace __ubsan;
+
+SIntMax Value::getSIntValue() const {
+ CHECK(getType().isSignedIntegerTy());
+ if (isInlineInt()) {
+ // Val was zero-extended to ValueHandle. Sign-extend from original width
+ // to SIntMax.
+ const unsigned ExtraBits =
+ sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
+ return SIntMax(Val) << ExtraBits >> ExtraBits;
+ }
+ if (getType().getIntegerBitWidth() == 64)
+ return *reinterpret_cast<s64*>(Val);
+#if HAVE_INT128_T
+ if (getType().getIntegerBitWidth() == 128)
+ return *reinterpret_cast<s128*>(Val);
+#else
+ if (getType().getIntegerBitWidth() == 128)
+ UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
+#endif
+ UNREACHABLE("unexpected bit width");
+}
+
+UIntMax Value::getUIntValue() const {
+ CHECK(getType().isUnsignedIntegerTy());
+ if (isInlineInt())
+ return Val;
+ if (getType().getIntegerBitWidth() == 64)
+ return *reinterpret_cast<u64*>(Val);
+#if HAVE_INT128_T
+ if (getType().getIntegerBitWidth() == 128)
+ return *reinterpret_cast<u128*>(Val);
+#else
+ if (getType().getIntegerBitWidth() == 128)
+ UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
+#endif
+ UNREACHABLE("unexpected bit width");
+}
+
+UIntMax Value::getPositiveIntValue() const {
+ if (getType().isUnsignedIntegerTy())
+ return getUIntValue();
+ SIntMax Val = getSIntValue();
+ CHECK(Val >= 0);
+ return Val;
+}
+
+/// Get the floating-point value of this object, extended to a long double.
+/// These are always passed by address (our calling convention doesn't allow
+/// them to be passed in floating-point registers, so this has little cost).
+FloatMax Value::getFloatValue() const {
+ CHECK(getType().isFloatTy());
+ if (isInlineFloat()) {
+ switch (getType().getFloatBitWidth()) {
+#if 0
+ // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
+ // from '__fp16' to 'long double'.
+ case 16: {
+ __fp16 Value;
+ internal_memcpy(&Value, &Val, 4);
+ return Value;
+ }
+#endif
+ case 32: {
+ float Value;
+ internal_memcpy(&Value, &Val, 4);
+ return Value;
+ }
+ case 64: {
+ double Value;
+ internal_memcpy(&Value, &Val, 8);
+ return Value;
+ }
+ }
+ } else {
+ switch (getType().getFloatBitWidth()) {
+ case 64: return *reinterpret_cast<double*>(Val);
+ case 80: return *reinterpret_cast<long double*>(Val);
+ case 96: return *reinterpret_cast<long double*>(Val);
+ case 128: return *reinterpret_cast<long double*>(Val);
+ }
+ }
+ UNREACHABLE("unexpected floating point bit width");
+}
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_value.h b/contrib/compiler-rt/lib/ubsan/ubsan_value.h
new file mode 100644
index 000000000000..a6810844049f
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_value.h
@@ -0,0 +1,204 @@
+//===-- ubsan_value.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Representation of data which is passed from the compiler-generated calls into
+// the ubsan runtime.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_VALUE_H
+#define UBSAN_VALUE_H
+
+// For now, only support Linux, FreeBSD and Darwin. Other platforms should
+// be easy to add, and probably work as-is.
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__)
+#error "UBSan not supported for this platform!"
+#endif
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+// FIXME: Move this out to a config header.
+#if __SIZEOF_INT128__
+__extension__ typedef __int128 s128;
+__extension__ typedef unsigned __int128 u128;
+#define HAVE_INT128_T 1
+#else
+#define HAVE_INT128_T 0
+#endif
+
+
+namespace __ubsan {
+
+/// \brief Largest integer types we support.
+#if HAVE_INT128_T
+typedef s128 SIntMax;
+typedef u128 UIntMax;
+#else
+typedef s64 SIntMax;
+typedef u64 UIntMax;
+#endif
+
+/// \brief Largest floating-point type we support.
+typedef long double FloatMax;
+
+/// \brief A description of a source location. This corresponds to Clang's
+/// \c PresumedLoc type.
+class SourceLocation {
+ const char *Filename;
+ u32 Line;
+ u32 Column;
+
+public:
+ SourceLocation() : Filename(), Line(), Column() {}
+ SourceLocation(const char *Filename, unsigned Line, unsigned Column)
+ : Filename(Filename), Line(Line), Column(Column) {}
+
+ /// \brief Determine whether the source location is known.
+ bool isInvalid() const { return !Filename; }
+
+ /// \brief Atomically acquire a copy, disabling original in-place.
+ /// Exactly one call to acquire() returns a copy that isn't disabled.
+ SourceLocation acquire() {
+ u32 OldColumn = __sanitizer::atomic_exchange(
+ (__sanitizer::atomic_uint32_t *)&Column, ~u32(0),
+ __sanitizer::memory_order_relaxed);
+ return SourceLocation(Filename, Line, OldColumn);
+ }
+
+ /// \brief Determine if this Location has been disabled.
+ /// Disabled SourceLocations are invalid to use.
+ bool isDisabled() {
+ return Column == ~u32(0);
+ }
+
+ /// \brief Get the presumed filename for the source location.
+ const char *getFilename() const { return Filename; }
+ /// \brief Get the presumed line number.
+ unsigned getLine() const { return Line; }
+ /// \brief Get the column within the presumed line.
+ unsigned getColumn() const { return Column; }
+};
+
+
+/// \brief A description of a type.
+class TypeDescriptor {
+ /// A value from the \c Kind enumeration, specifying what flavor of type we
+ /// have.
+ u16 TypeKind;
+
+ /// A \c Type-specific value providing information which allows us to
+ /// interpret the meaning of a ValueHandle of this type.
+ u16 TypeInfo;
+
+ /// The name of the type follows, in a format suitable for including in
+ /// diagnostics.
+ char TypeName[1];
+
+public:
+ enum Kind {
+ /// An integer type. Lowest bit is 1 for a signed value, 0 for an unsigned
+ /// value. Remaining bits are log_2(bit width). The value representation is
+ /// the integer itself if it fits into a ValueHandle, and a pointer to the
+ /// integer otherwise.
+ TK_Integer = 0x0000,
+ /// A floating-point type. Low 16 bits are bit width. The value
+ /// representation is that of bitcasting the floating-point value to an
+ /// integer type.
+ TK_Float = 0x0001,
+ /// Any other type. The value representation is unspecified.
+ TK_Unknown = 0xffff
+ };
+
+ const char *getTypeName() const { return TypeName; }
+
+ Kind getKind() const {
+ return static_cast<Kind>(TypeKind);
+ }
+
+ bool isIntegerTy() const { return getKind() == TK_Integer; }
+ bool isSignedIntegerTy() const {
+ return isIntegerTy() && (TypeInfo & 1);
+ }
+ bool isUnsignedIntegerTy() const {
+ return isIntegerTy() && !(TypeInfo & 1);
+ }
+ unsigned getIntegerBitWidth() const {
+ CHECK(isIntegerTy());
+ return 1 << (TypeInfo >> 1);
+ }
+
+ bool isFloatTy() const { return getKind() == TK_Float; }
+ unsigned getFloatBitWidth() const {
+ CHECK(isFloatTy());
+ return TypeInfo;
+ }
+};
+
+/// \brief An opaque handle to a value.
+typedef uptr ValueHandle;
+
+
+/// \brief Representation of an operand value provided by the instrumented code.
+///
+/// This is a combination of a TypeDescriptor (which is emitted as constant data
+/// as an operand to a handler function) and a ValueHandle (which is passed at
+/// runtime when a check failure occurs).
+class Value {
+ /// The type of the value.
+ const TypeDescriptor &Type;
+ /// The encoded value itself.
+ ValueHandle Val;
+
+ /// Is \c Val a (zero-extended) integer?
+ bool isInlineInt() const {
+ CHECK(getType().isIntegerTy());
+ const unsigned InlineBits = sizeof(ValueHandle) * 8;
+ const unsigned Bits = getType().getIntegerBitWidth();
+ return Bits <= InlineBits;
+ }
+
+ /// Is \c Val a (zero-extended) integer representation of a float?
+ bool isInlineFloat() const {
+ CHECK(getType().isFloatTy());
+ const unsigned InlineBits = sizeof(ValueHandle) * 8;
+ const unsigned Bits = getType().getFloatBitWidth();
+ return Bits <= InlineBits;
+ }
+
+public:
+ Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {}
+
+ const TypeDescriptor &getType() const { return Type; }
+
+ /// \brief Get this value as a signed integer.
+ SIntMax getSIntValue() const;
+
+ /// \brief Get this value as an unsigned integer.
+ UIntMax getUIntValue() const;
+
+ /// \brief Decode this value, which must be a positive or unsigned integer.
+ UIntMax getPositiveIntValue() const;
+
+ /// Is this an integer with value -1?
+ bool isMinusOne() const {
+ return getType().isSignedIntegerTy() && getSIntValue() == -1;
+ }
+
+ /// Is this a negative integer?
+ bool isNegative() const {
+ return getType().isSignedIntegerTy() && getSIntValue() < 0;
+ }
+
+ /// \brief Get this value as a floating-point quantity.
+ FloatMax getFloatValue() const;
+};
+
+} // namespace __ubsan
+
+#endif // UBSAN_VALUE_H