]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Merge in trunk.
authormrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 6 Nov 2013 02:15:30 +0000 (02:15 +0000)
committermrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 6 Nov 2013 02:15:30 +0000 (02:15 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/wide-int@204436 138bc75d-0d04-0410-961f-82ee72b054a4

320 files changed:
ChangeLog
configure
configure.ac
gcc/ChangeLog
gcc/DATESTAMP
gcc/Makefile.in
gcc/asan.c
gcc/asan.h
gcc/builtins.def
gcc/c-family/ChangeLog
gcc/c-family/c-cppbuiltin.c
gcc/c-family/c-opts.c
gcc/c-family/c-pragma.c
gcc/c-family/c.opt
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/common.opt
gcc/config/aarch64/aarch64.c
gcc/config/arm/arm.c
gcc/config/i386/i386-c.c
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/rtemself.h
gcc/config/i386/sync.md
gcc/config/i386/t-rtems
gcc/config/i386/x86-tune.def
gcc/config/iq2000/iq2000.md
gcc/config/microblaze/microblaze.md
gcc/config/rs6000/altivec.md
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/vector.md
gcc/config/sh/sh.md
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/doc/md.texi
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/double-int.c
gcc/expr.c
gcc/final.c
gcc/fortran/ChangeLog
gcc/fortran/check.c
gcc/fortran/cpp.c
gcc/fortran/f95-lang.c
gcc/fortran/gfortran.h
gcc/fortran/lang.opt
gcc/fortran/options.c
gcc/fortran/trans-expr.c
gcc/fortran/trans-io.c
gcc/gengtype-parse.c
gcc/gimple-expr.c [new file with mode: 0644]
gcc/gimple-expr.h [new file with mode: 0644]
gcc/gimple-ssa-isolate-paths.c [new file with mode: 0644]
gcc/gimple.c
gcc/gimple.h
gcc/gimplify.c
gcc/haifa-sched.c
gcc/ipa-prop.c
gcc/loop-iv.c
gcc/loop-unswitch.c
gcc/lto-opts.c
gcc/lto-wrapper.c
gcc/omp-low.c
gcc/optabs.c
gcc/opts.c
gcc/passes.def
gcc/rtlanal.c
gcc/sanitizer.def
gcc/sched-rgn.c
gcc/sync-builtins.def
gcc/target.def
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/asan/stack-overflow-1.c
gcc/testsuite/g++.dg/asan/asan_test.cc
gcc/testsuite/g++.dg/cpp0x/gen-attrs-56.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/sync-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/openmp-simd-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/openmp-simd-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/array35.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/wdate-time.C [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/pr58978.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/pr58997.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr58984.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/openmp-simd-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/openmp-simd-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ipa/pr58492.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr38984.c
gcc/testsuite/gcc.dg/pr58981.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/superblock.c
gcc/testsuite/gcc.dg/torture/pr58941.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr58955-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr58955-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/alias-26.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr58958.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/wdate-time.c [new file with mode: 0644]
gcc/testsuite/gfortran.dg/derived_external_function_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/optional_class_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/reshape_6.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/wdate-time.F90 [new file with mode: 0644]
gcc/timevar.def
gcc/tree-dfa.c
gcc/tree-loop-distribution.c
gcc/tree-outof-ssa.c
gcc/tree-pass.h
gcc/tree-ssa-alias.c
gcc/tree-ssa-alias.h
gcc/tree-ssa.c
gcc/tree-ssa.h
gcc/tree-vrp.c
gcc/tree.c
gcc/vec.c
gcc/vec.h
libcilkrts/ChangeLog
libcilkrts/Makefile.am
libcilkrts/Makefile.in
libcpp/ChangeLog
libcpp/include/cpplib.h
libcpp/init.c
libcpp/macro.c
libgcc/ChangeLog
libgcc/config.host
libgcc/config/i386/32/sfp-machine.h
libsanitizer/ChangeLog
libsanitizer/MERGE
libsanitizer/Makefile.am
libsanitizer/Makefile.in
libsanitizer/asan/Makefile.am
libsanitizer/asan/Makefile.in
libsanitizer/asan/asan_allocator.cc [deleted file]
libsanitizer/asan/asan_allocator.h
libsanitizer/asan/asan_allocator2.cc
libsanitizer/asan/asan_dll_thunk.cc [new file with mode: 0644]
libsanitizer/asan/asan_fake_stack.cc
libsanitizer/asan/asan_fake_stack.h [new file with mode: 0644]
libsanitizer/asan/asan_flags.h
libsanitizer/asan/asan_globals.cc
libsanitizer/asan/asan_intercepted_functions.h
libsanitizer/asan/asan_interceptors.cc
libsanitizer/asan/asan_interface_internal.h
libsanitizer/asan/asan_internal.h
libsanitizer/asan/asan_linux.cc
libsanitizer/asan/asan_mac.cc
libsanitizer/asan/asan_mac.h
libsanitizer/asan/asan_malloc_linux.cc
libsanitizer/asan/asan_malloc_mac.cc
libsanitizer/asan/asan_malloc_win.cc
libsanitizer/asan/asan_mapping.h
libsanitizer/asan/asan_new_delete.cc
libsanitizer/asan/asan_poisoning.cc
libsanitizer/asan/asan_poisoning.h [new file with mode: 0644]
libsanitizer/asan/asan_posix.cc
libsanitizer/asan/asan_preinit.cc
libsanitizer/asan/asan_report.cc
libsanitizer/asan/asan_report.h
libsanitizer/asan/asan_rtl.cc
libsanitizer/asan/asan_stack.cc
libsanitizer/asan/asan_stack.h
libsanitizer/asan/asan_stats.cc
libsanitizer/asan/asan_stats.h
libsanitizer/asan/asan_thread.cc
libsanitizer/asan/asan_thread.h
libsanitizer/asan/asan_thread_registry.cc [deleted file]
libsanitizer/asan/asan_thread_registry.h [deleted file]
libsanitizer/asan/asan_win.cc
libsanitizer/asan/libtool-version
libsanitizer/configure
libsanitizer/configure.ac
libsanitizer/include/sanitizer/common_interface_defs.h
libsanitizer/include/sanitizer/dfsan_interface.h [new file with mode: 0644]
libsanitizer/include/sanitizer/linux_syscall_hooks.h [new file with mode: 0644]
libsanitizer/include/sanitizer/lsan_interface.h [new file with mode: 0644]
libsanitizer/include/sanitizer/msan_interface.h [new file with mode: 0644]
libsanitizer/interception/interception.h
libsanitizer/interception/interception_linux.cc
libsanitizer/interception/interception_linux.h
libsanitizer/lsan/Makefile.am [new file with mode: 0644]
libsanitizer/lsan/Makefile.in [new file with mode: 0644]
libsanitizer/lsan/libtool-version [new file with mode: 0644]
libsanitizer/lsan/lsan.cc [new file with mode: 0644]
libsanitizer/lsan/lsan.h [new file with mode: 0644]
libsanitizer/lsan/lsan_allocator.cc [new file with mode: 0644]
libsanitizer/lsan/lsan_allocator.h [new file with mode: 0644]
libsanitizer/lsan/lsan_common.cc [new file with mode: 0644]
libsanitizer/lsan/lsan_common.h [new file with mode: 0644]
libsanitizer/lsan/lsan_common_linux.cc [new file with mode: 0644]
libsanitizer/lsan/lsan_interceptors.cc [new file with mode: 0644]
libsanitizer/lsan/lsan_thread.cc [new file with mode: 0644]
libsanitizer/lsan/lsan_thread.h [new file with mode: 0644]
libsanitizer/merge.sh
libsanitizer/sanitizer_common/Makefile.am
libsanitizer/sanitizer_common/Makefile.in
libsanitizer/sanitizer_common/sanitizer_allocator.cc
libsanitizer/sanitizer_common/sanitizer_allocator.h
libsanitizer/sanitizer_common/sanitizer_allocator_internal.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
libsanitizer/sanitizer_common/sanitizer_common.cc
libsanitizer/sanitizer_common/sanitizer_common.h
libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc [new file with mode: 0755]
libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_flags.cc
libsanitizer/sanitizer_common/sanitizer_flags.h
libsanitizer/sanitizer_common/sanitizer_internal_defs.h
libsanitizer/sanitizer_common/sanitizer_libc.cc
libsanitizer/sanitizer_common/sanitizer_libc.h
libsanitizer/sanitizer_common/sanitizer_linux.cc
libsanitizer/sanitizer_common/sanitizer_linux.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_mac.cc
libsanitizer/sanitizer_common/sanitizer_mutex.h
libsanitizer/sanitizer_common/sanitizer_placement_new.h
libsanitizer/sanitizer_common/sanitizer_platform.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
libsanitizer/sanitizer_common/sanitizer_posix.cc
libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_printf.cc
libsanitizer/sanitizer_common/sanitizer_procmaps.h
libsanitizer/sanitizer_common/sanitizer_quarantine.h
libsanitizer/sanitizer_common/sanitizer_report_decorator.h
libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
libsanitizer/sanitizer_common/sanitizer_stackdepot.h
libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
libsanitizer/sanitizer_common/sanitizer_stacktrace.h
libsanitizer/sanitizer_common/sanitizer_stoptheworld.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_suppressions.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_suppressions.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_symbolizer.h
libsanitizer/sanitizer_common/sanitizer_symbolizer_itanium.cc [deleted file]
libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc [deleted file]
libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc [deleted file]
libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc [moved from libsanitizer/sanitizer_common/sanitizer_symbolizer.cc with 58% similarity]
libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_thread_registry.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_thread_registry.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_win.cc
libsanitizer/tsan/tsan_defs.h
libsanitizer/tsan/tsan_fd.cc
libsanitizer/tsan/tsan_flags.cc
libsanitizer/tsan/tsan_flags.h
libsanitizer/tsan/tsan_interceptors.cc
libsanitizer/tsan/tsan_interface.cc
libsanitizer/tsan/tsan_interface.h
libsanitizer/tsan/tsan_interface_ann.cc
libsanitizer/tsan/tsan_interface_ann.h
libsanitizer/tsan/tsan_interface_atomic.cc
libsanitizer/tsan/tsan_interface_inl.h
libsanitizer/tsan/tsan_interface_java.cc
libsanitizer/tsan/tsan_interface_java.h
libsanitizer/tsan/tsan_mman.cc
libsanitizer/tsan/tsan_mman.h
libsanitizer/tsan/tsan_mutex.cc
libsanitizer/tsan/tsan_mutexset.h
libsanitizer/tsan/tsan_platform.h
libsanitizer/tsan/tsan_platform_linux.cc
libsanitizer/tsan/tsan_platform_mac.cc
libsanitizer/tsan/tsan_platform_windows.cc
libsanitizer/tsan/tsan_report.cc
libsanitizer/tsan/tsan_report.h
libsanitizer/tsan/tsan_rtl.cc
libsanitizer/tsan/tsan_rtl.h
libsanitizer/tsan/tsan_rtl_mutex.cc
libsanitizer/tsan/tsan_rtl_report.cc
libsanitizer/tsan/tsan_rtl_thread.cc
libsanitizer/tsan/tsan_stat.cc
libsanitizer/tsan/tsan_stat.h
libsanitizer/tsan/tsan_suppressions.cc
libsanitizer/tsan/tsan_suppressions.h
libsanitizer/tsan/tsan_symbolize.cc
libsanitizer/tsan/tsan_symbolize.h
libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc
libsanitizer/tsan/tsan_sync.cc
libsanitizer/tsan/tsan_sync.h
libsanitizer/tsan/tsan_update_shadow_word_inl.h
libsanitizer/tsan/tsan_vector.h
libsanitizer/ubsan/ubsan_diag.cc
libsanitizer/ubsan/ubsan_value.h
libstdc++-v3/ChangeLog
libstdc++-v3/doc/xml/manual/status_cxx2011.xml
libstdc++-v3/doc/xml/manual/status_cxx2014.xml
libstdc++-v3/include/experimental/optional
libstdc++-v3/include/std/type_traits
libstdc++-v3/testsuite/20_util/add_lvalue_reference/requirements/typedefs.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/add_rvalue_reference/requirements/typedefs.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/common_type/requirements/typedefs-2.cc
libstdc++-v3/testsuite/20_util/common_type/requirements/typedefs-3.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/conditional/requirements/typedefs-2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/decay/requirements/typedefs-2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/decay/requirements/typedefs.cc
libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
libstdc++-v3/testsuite/20_util/enable_if/requirements/typedefs-2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs-1.cc
libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs-3.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs-3.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
libstdc++-v3/testsuite/20_util/remove_reference/requirements/typedefs.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/result_of/requirements/typedefs.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/underlying_type/requirements/typedefs-3.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/optional/cons/copy.cc
libstdc++-v3/testsuite/experimental/optional/cons/move.cc
libstdc++-v3/testsuite/experimental/optional/cons/value.cc
libstdc++-v3/testsuite/experimental/optional/constexpr/cons/value.cc

index 8c24d354549c0eea02b69aaf31c247add020541a..35f33673a108a94f8a20ad0d62c16d2ba2553b63 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-11-04  Balaji V. Iyer  <balaji.v.iyer@intel.com>
+
+       * configure.ac: Added libcilkrts to noconfig list when C++ is not
+       supported.
+       * configure: Regenerated.
+
 2013-11-01  Trevor Saunders  <tsaunders@mozilla.com>
 
 * MAINTAINERS (Write After Approval): Add myself.
index c95990a6f4ceb20b4f3c7488d5c2bf06294d923d..d4a82137bad55b4e5fd1eb189ba8f3ff42bcc890 100755 (executable)
--- a/configure
+++ b/configure
@@ -6630,7 +6630,7 @@ esac
 case ,${enable_languages}, in
   *,c++,*) ;;
   *)
-    noconfigdirs="$noconfigdirs target-libitm target-libsanitizer target-libvtv"
+    noconfigdirs="$noconfigdirs target-libcilkrts target-libitm target-libsanitizer target-libvtv"
     ;;
 esac
 
index 140877ffedc3ff8c415bef2eadbaa03abf9e6ea2..30190d65bea669b88e1217cee3f0607efa678319 100644 (file)
@@ -2061,7 +2061,7 @@ esac
 case ,${enable_languages}, in
   *,c++,*) ;;
   *)
-    noconfigdirs="$noconfigdirs target-libitm target-libsanitizer target-libvtv"
+    noconfigdirs="$noconfigdirs target-libcilkrts target-libitm target-libsanitizer target-libvtv"
     ;;
 esac
 
index 7e0b752c3ed486f2db6a649edeb6e0a9fa997a8c..d5c8ceb1c5ee791c972cbfcad03977fbb82278a3 100644 (file)
@@ -1,3 +1,299 @@
+2013-11-05  Ian Lance Taylor  <iant@google.com>
+
+       * config/i386/sync.md (atomic_compare_and_swap<dwi>_doubleword):
+       If possible, add .cfi directives to record change to bx.
+       * config/i386/i386.c (ix86_emit_cfi): New function.
+       * config/i386/i386-protos.h (ix86_emit_cfi): Declare.
+
+2013-11-05  Steven Bosscher  <steven@gcc.gnu.org>
+
+
+       * rtlanal.c (tablejump_p): Expect a JUMP_TABLE_DATA to always follow
+       immediately after a label for a tablejump pattern.
+
+       * config/arm/arm.c (is_jump_table): Remove.
+       (create_fix_barrier): Use tablejump_p instead.
+       (arm_reorg): Likewise.
+       (thumb1_output_casesi): Expect JUMP_TABLE_DATA to always be NEXT_INSN.
+       (thumb2_output_casesi): Likewise.
+       * config/aarch64/aarch64.c (aarch64_output_casesi): Likewise.
+       * config/sh/sh.md (casesi_worker_1, casesi_worker_2,
+       casesi_shift_media, casesi_load_media): Likewise.
+       * config/iq2000/iq2000.md: Likewise (in anonymous define_insn).
+       * config/microblaze/microblaze.md: Likewise.
+
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * doc/invoke.texi (-Wdate-time): Document.
+
+2013-11-05  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * double-int.c (lshift_double, rshift_double): Remove
+       SHIFT_COUNT_TRUNCATED handling.
+
+2013-11-05  Jeff Law  <law@redhat.com>
+
+       * Makefile.in (OBJS): Add gimple-ssa-isolate-paths.o
+       * common.opt (-fisolate-erroneous-paths): Add option and
+       documentation.
+       * gimple-ssa-isolate-paths.c: New file.
+       * gimple.c (check_loadstore): New function.
+       (infer_nonnull_range): Moved into gimple.c from tree-vrp.c
+       Verify OP is in the argument list and the argument corresponding
+       to OP is a pointer type.  Use operand_equal_p rather than
+       pointer equality when testing if OP is on the nonnull list.
+       Use check_loadstore rather than count_ptr_derefs.  Handle
+       GIMPLE_RETURN statements.
+       * tree-vrp.c (infer_nonnull_range): Remove.
+       * gimple.h (infer_nonnull_range): Declare.
+       * opts.c (default_options_table): Add OPT_fisolate_erroneous_paths.
+       * passes.def: Add pass_isolate_erroneous_paths.
+       * timevar.def (TV_ISOLATE_ERRONEOUS_PATHS): New timevar.
+       * tree-pass.h (make_pass_isolate_erroneous_paths): Declare.
+       * tree-ssa.c (struct count_ptr_d): Remove.
+       (count_ptr_derefs, count_uses_and_derefs): Remove.
+       * tree-ssa.h (count_uses_and_derefs): Remove.
+
+2013-11-05  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/58997
+       * loop-iv.c (iv_subreg): For IV_UNKNOWN_EXTEND, expect
+       get_iv_value to be in iv->mode rather than iv->extend_mode.
+       (iv_extend): Likewise.  Otherwise, if iv->extend != extend,
+       use lowpart_subreg on get_iv_value before calling simplify_gen_unary.
+       * loop-unswitch.c (may_unswitch_on): Make sure op[i] is in the right
+       mode.
+
+2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
+
+       * gimple.h: Move some prototypes to gimple-expr.h and add to include
+       list.
+       (extract_ops_from_tree, gimple_call_addr_fndecl, is_gimple_reg_type):
+       Move to gimple-expr.h.
+       * gimple-expr.h: New file.  Relocate some prototypes from gimple.h.
+       (types_compatible_p, is_gimple_reg_type, is_gimple_variable,
+       is_gimple_id, virtual_operand_p, is_gimple_addressable,
+       is_gimple_constant, extract_ops_from_tree, gimple_call_addr_fndecl):
+       Relocate here.
+       * gimple.c (extract_ops_from_tree_1, gimple_cond_get_ops_from_tree,
+       gimple_set_body, gimple_body, gimple_has_body_p, is_gimple_lvalue,
+       is_gimple_condexpr, is_gimple_addressable, is_gimple_constant,
+       is_gimple_address, is_gimple_invariant_address,
+       is_gimple_ip_invariant_address, is_gimple_min_invariant,
+       is_gimple_ip_invariant, is_gimple_variable, is_gimple_id,
+       virtual_operand_p, is_gimple_reg, is_gimple_val, is_gimple_asm_val,
+       is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr,
+       gimple_decl_printable_name, useless_type_conversion_p,
+       types_compatible_p, gimple_can_coalesce_p, copy_var_decl): Move to 
+       gimple-expr.[ch].
+       * gimple-expr.c: New File.
+       (useless_type_conversion_p, gimple_set_body, gimple_body,
+       gimple_has_body_p, gimple_decl_printable_name, copy_var_decl,
+       gimple_can_coalesce_p, extract_ops_from_tree_1, 
+       gimple_cond_get_ops_from_tree, is_gimple_lvalue, is_gimple_condexpr,
+       is_gimple_address, is_gimple_invariant_address,
+       is_gimple_ip_invariant_address, is_gimple_min_invariant,
+       is_gimple_ip_invariant, is_gimple_reg, is_gimple_val,
+       is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr,
+       is_gimple_mem_ref_addr): Relocate here.
+       * Makefile.in (OBJS): Add gimple-expr.o.
+
+2013-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * gengtype-parse.c (struct_field_seq): Support empty structs.
+
+2013-11-05  Uros Bizjak  <ubizjak@gmail.com>
+
+       * config/i386/t-rtems (MULTILIB_MATCHES): Fix option typos.
+
+2013-11-05  Uros Bizjak  <ubizjak@gmail.com>
+
+       * config/i386/i386-c.c (ix86_target_macros): Define _SOFT_FLOAT
+       for !TARGET_80387.
+       * config/i386/rtemself.h (TARGET_OS_CPP_BUILTINS): Do not define
+       _SOFT_FLOAT here.
+       (LONG_DOUBLE_TYPE_SIZE): New define.
+       (LIBGCC2_LONG_DOUBLE_TYPE_SIZE): Ditto.
+
+2013-11-05  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/58724
+       * doc/extend.texi [visibility ("visibility_type")]: Add example
+       about visibility attribute on namespace declaration.
+
+2013-11-05  Richard Biener  <rguenther@suse.de>
+
+       PR ipa/58492
+       * passes.def (all_passes): Start with pass_fixup_cfg again.
+
+2013-11-05  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/58955
+       * tree-loop-distribution.c (pg_add_dependence_edges): Fix
+       edge direction.
+
+2013-11-05  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
+
+       * config/rs6000/vector.md (vec_pack_sfix_trunc_v2df): Adjust for
+       little endian.
+       (vec_pack_ufix_trunc_v2df): Likewise.
+
+2013-11-05  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR middle-end/58981
+       * doc/md.texi (@code{movmem@var{m}}): Specify Pmode as mode of
+       pattern, instead of word_mode.
+
+       * expr.c (emit_block_move_via_movmem): Don't use mode wider than
+       Pmode for size.
+       (set_storage_via_setmem): Likewise.
+
+2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
+
+       * tree-outof-ssa.c (queue_phi_copy_p): Combine phi_ssa_name_p from
+       gimple.h and the rest of the condition in eliminate_build.
+       (eliminate_build): Call new routine.
+       * gimple.h (phi_ssa_name_p): Delete.
+
+2013-11-05  Trevor Saunders  <tsaunders@mozilla.com>
+
+       * vec.c (vec_prefix::calculate_allocation): Don't try to handle the
+       case of no prefix and reserving zero slots, because when that's the
+       case we'll never get here.
+       * vec.h (va_heap::reserve): Don't try and handle
+       vec_prefix::calculate_allocation returning zero because that should
+       never happen.
+
+2013-11-05  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/58941
+       * tree-dfa.c (get_ref_base_and_extent): Merge common code
+       in MEM_REF and TARGET_MEM_REF handling.  Make sure to
+       process trailing array detection before diving into the
+       view-converted object (and possibly apply some extra offset).
+
+2013-11-05  Joseph Myers  <joseph@codesourcery.com>
+
+       * config/i386/i386.c (ix86_float_exceptions_rounding_supported_p):
+       New function.
+       (TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P): Define.
+
+2013-11-05  Marc Glisse  <marc.glisse@inria.fr>
+
+       PR tree-optimization/58958
+       * tree-ssa-alias.c (ao_ref_init_from_ptr_and_size): Use
+       get_addr_base_and_unit_offset instead of get_ref_base_and_extent.
+
+2013-11-05  Marc Glisse  <marc.glisse@inria.fr>
+
+       * tree-ssa-alias.h (ranges_overlap_p): Handle negative offsets.
+       * tree-ssa-alias.c (ao_ref_init_from_ptr_and_size): Likewise.
+
+2013-11-05  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/58984
+       * ipa-prop.c (ipa_load_from_parm_agg_1): Add SIZE_P argument,
+       set *SIZE_P if non-NULL on success.
+       (ipa_load_from_parm_agg, ipa_analyze_indirect_call_uses): Adjust
+       callers.
+       (ipcp_transform_function): Likewise.  Punt if size of access
+       is different from TYPE_SIZE on v->value's type.
+
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * doc/invoke.texi (-fopenmp-simd): Document new option.
+       * gimplify.c (gimplify_body): Accept -fopenmp-simd.
+       * omp-low.c (execute_expand_omp, execute_lower_omp): Ditto.
+       * tree.c (attribute_value_equal): Ditto.
+
+2013-11-04  Wei Mi  <wmi@google.com>
+
+       * sched-rgn.c (add_branch_dependences): Keep insns in
+       a SCHED_GROUP at the end of BB to remain their location.
+
+2013-11-04  Wei Mi  <wmi@google.com>
+
+       * gcc/config/i386/i386.c (memory_address_length): Extract a part
+       of code to rip_relative_addr_p.
+       (rip_relative_addr_p): New Function.
+       (ix86_macro_fusion_p): Ditto.
+       (ix86_macro_fusion_pair_p): Ditto.
+       * gcc/config/i386/i386.h: Add new tune features about macro-fusion.
+       * gcc/config/i386/x86-tune.def (DEF_TUNE): Ditto.
+       * gcc/doc/tm.texi: Generated.
+       * gcc/doc/tm.texi.in: Ditto.
+       * gcc/haifa-sched.c (try_group_insn): New Function.
+       (group_insns_for_macro_fusion): Ditto.
+       (sched_init): Call group_insns_for_macro_fusion.
+       * gcc/target.def: Add two hooks: macro_fusion_p and
+       macro_fusion_pair_p.
+
+2013-11-04  Kostya Serebryany  <kcc@google.com>
+
+       Update to match the changed asan API.
+       * asan.c (asan_function_start): New function.
+       (asan_emit_stack_protection): Update the string stored in the
+       stack red zone to match new API.  Store the PC of the current
+       function in the red zone.
+       (asan_global_struct): Update the __asan_global definition to match
+       the new API.
+       (asan_add_global): Ditto.
+       * asan.h (asan_function_start): New prototype.
+       * final.c (final_start_function): Call asan_function_start.
+       * sanitizer.def (BUILT_IN_ASAN_INIT): Rename __asan_init_v1
+       to __asan_init_v3.
+
+2013-11-04  Wei Mi  <wmi@google.com>
+
+       * gcc/config/i386/i386-c.c (ix86_target_macros_internal): Separate
+       PROCESSOR_COREI7_AVX out from PROCESSOR_COREI7.
+       * gcc/config/i386/i386.c (ix86_option_override_internal): Ditto.
+       (ix86_issue_rate): Ditto.
+       (ix86_adjust_cost): Ditto.
+       (ia32_multipass_dfa_lookahead): Ditto.
+       (ix86_sched_init_global): Ditto.
+       (get_builtin_code_for_version): Ditto.
+       * gcc/config/i386/i386.h (enum target_cpu_default): Ditto.
+       (enum processor_type): Ditto.
+       * gcc/config/i386/x86-tune.def (DEF_TUNE): Ditto.
+
+2013-11-04  Vladimir Makarov  <vmakarov@redhat.com>
+
+       PR rtl-optimization/58967
+       * config/rs6000/rs6000.c (legitimate_lo_sum_address_p): Remove
+       !lra_in_progress for mode sizes bigger word.
+
+2013-11-04  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
+
+       * config/rs6000/altivec.md (vec_widen_umult_hi_v16qi): Swap
+       arguments to merge instruction for little endian.
+       (vec_widen_umult_lo_v16qi): Likewise.
+       (vec_widen_smult_hi_v16qi): Likewise.
+       (vec_widen_smult_lo_v16qi): Likewise.
+       (vec_widen_umult_hi_v8hi): Likewise.
+       (vec_widen_umult_lo_v8hi): Likewise.
+       (vec_widen_smult_hi_v8hi): Likewise.
+       (vec_widen_smult_lo_v8hi): Likewise.
+
+2013-11-04  Ian Lance Taylor  <iant@google.com>
+
+       * builtins.def (ATTR_NOTHROWCALL_LEAF_LIST): Define.
+       * sync-builtins.def: Use ATTR_NOTHROWCALL_LEAF_LIST for all sync
+       builtins that take pointers.
+       * lto-opts.c (lto_write_options): Write -fnon-call-exceptions if set.
+       * lto-wrapper.c (merge_and_complain): Collect OPT_fnon_call_exceptions.
+       (run_gcc): Pass -fnon-call-exceptions.
+
+2013-11-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * optabs.c (expand_vec_perm): Revert one incorrect line from
+       2013-10-31 change.
+
+       PR tree-optimization/58978
+       * tree-vrp.c (all_imm_uses_in_stmt_or_feed_cond): Don't modify
+       use_stmt by single_imm_use directly.  Only call single_imm_use
+       on SSA_NAMEs.
+
 2013-11-04  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/58968
 
 2013-11-04  Joseph Myers  <joseph@codesourcery.com>
 
-       * doc/cpp.texi (__GCC_IEC_559, __GCC_IEC_559_COMPLEX): Document
-       macros.
+       * doc/cpp.texi (__GCC_IEC_559, __GCC_IEC_559_COMPLEX): Document macros.
        * target.def (float_exceptions_rounding_supported_p): New hook.
        * targhooks.c (default_float_exceptions_rounding_supported_p): New
        function.
-       * targhooks.h (default_float_exceptions_rounding_supported_p):
-       Declare.
+       * targhooks.h (default_float_exceptions_rounding_supported_p): Declare.
        * doc/tm.texi.in (TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P):
        New @hook.
        * doc/tm.texi: Regenerate.
 
        Implement -fsanitize=vla-bound.
        * opts.c (common_handle_option): Handle vla-bound.
-       * sanitizer.def (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE):
-       Define.
+       * sanitizer.def (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE): Define.
        * flag-types.h (enum sanitize_code): Add SANITIZE_VLA.
        * asan.c (initialize_sanitizer_builtins): Build BT_FN_VOID_PTR_PTR.
 
index 6e5286a0dd2f2ceb23f22b42ce083aba053603b3..5a2561156748de34ac65b9e94aaaccfa895f6e12 100644 (file)
@@ -1 +1 @@
-20131104
+20131106
index 48c6be26246ad2e0e00dc6aff435ef8e56e62bff..e4436cd5d47d3d676a4c6f2ba5123b99a2761065 100644 (file)
@@ -1230,10 +1230,12 @@ OBJS = \
        ggc-common.o \
        gimple.o \
        gimple-builder.o \
+       gimple-expr.o \
        gimple-iterator.o \
        gimple-fold.o \
        gimple-low.o \
        gimple-pretty-print.o \
+       gimple-ssa-isolate-paths.o \
        gimple-ssa-strength-reduction.o \
        gimple-streamer-in.o \
        gimple-streamer-out.o \
index 5dcc981cd06450ed4dcf8d38940d9a5e534e0715..028c08e0e87e1d7c0c5b59a067d5b8ddc4e8fd8a 100644 (file)
@@ -59,11 +59,13 @@ along with GCC; see the file COPYING3.  If not see
         if ((X & 7) + N - 1 > ShadowValue)
           __asan_report_loadN(X);
    Stores are instrumented similarly, but using __asan_report_storeN functions.
-   A call too __asan_init() is inserted to the list of module CTORs.
+   A call too __asan_init_vN() is inserted to the list of module CTORs.
+   N is the version number of the AddressSanitizer API. The changes between the
+   API versions are listed in libsanitizer/asan/asan_interface_internal.h.
 
    The run-time library redefines malloc (so that redzone are inserted around
    the allocated memory) and free (so that reuse of free-ed memory is delayed),
-   provides __asan_report* and __asan_init functions.
+   provides __asan_report* and __asan_init_vN functions.
 
    Read more:
    http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
@@ -125,9 +127,11 @@ along with GCC; see the file COPYING3.  If not see
 
        where '(...){n}' means the content inside the parenthesis occurs 'n'
        times, with 'n' being the number of variables on the stack.
+     
+     3/ The following 8 bytes contain the PC of the current function which
+     will be used by the run-time library to print an error message.
 
-      3/ The following 16 bytes of the red zone have no particular
-      format.
+     4/ The following 8 bytes are reserved for internal use by the run-time.
 
    The shadow memory for that stack layout is going to look like this:
 
@@ -205,6 +209,9 @@ along with GCC; see the file COPYING3.  If not see
        // Name of the global variable.
        const void *__name;
 
+       // Name of the module where the global variable is declared.
+       const void *__module_name;
+
        // This is always set to NULL for now.
        uptr __has_dynamic_init;
      }
@@ -914,6 +921,15 @@ asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
   add_int_reg_note (jump, REG_BR_PROB, REG_BR_PROB_BASE * 80 / 100);
 }
 
+void
+asan_function_start (void)
+{
+  section *fnsec = function_section (current_function_decl);
+  switch_to_section (fnsec);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LASANPC",
+                         current_function_funcdef_no);
+}
+
 /* Insert code to protect stack vars.  The prologue sequence should be emitted
    directly, epilogue sequence returned.  BASE is the register holding the
    stack base, against which OFFSETS array offsets are relative to, OFFSETS
@@ -929,12 +945,13 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
                            int length)
 {
   rtx shadow_base, shadow_mem, ret, mem;
+  char buf[30];
   unsigned char shadow_bytes[4];
   HOST_WIDE_INT base_offset = offsets[length - 1], offset, prev_offset;
   HOST_WIDE_INT last_offset, last_size;
   int l;
   unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
-  tree str_cst;
+  tree str_cst, decl, id;
 
   if (shadow_ptr_types[0] == NULL_TREE)
     asan_init_shadow_ptr_types ();
@@ -942,11 +959,6 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
   /* First of all, prepare the description string.  */
   pretty_printer asan_pp;
 
-  if (DECL_NAME (current_function_decl))
-    pp_tree_identifier (&asan_pp, DECL_NAME (current_function_decl));
-  else
-    pp_string (&asan_pp, "<unknown>");
-  pp_space (&asan_pp);
   pp_decimal_int (&asan_pp, length / 2 - 1);
   pp_space (&asan_pp);
   for (l = length - 2; l; l -= 2)
@@ -976,6 +988,20 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
   emit_move_insn (mem, gen_int_mode (ASAN_STACK_FRAME_MAGIC, ptr_mode));
   mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
   emit_move_insn (mem, expand_normal (str_cst));
+  mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LASANPC", current_function_funcdef_no);
+  id = get_identifier (buf);
+  decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+                    VAR_DECL, id, char_type_node);
+  SET_DECL_ASSEMBLER_NAME (decl, id);
+  TREE_ADDRESSABLE (decl) = 1;
+  TREE_READONLY (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  TREE_STATIC (decl) = 1;
+  TREE_PUBLIC (decl) = 0;
+  TREE_USED (decl) = 1;
+  emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl)));
   shadow_base = expand_binop (Pmode, lshr_optab, base,
                              GEN_INT (ASAN_SHADOW_SHIFT),
                              NULL_RTX, 1, OPTAB_DIRECT);
@@ -1924,20 +1950,21 @@ transform_statements (void)
      uptr __size;
      uptr __size_with_redzone;
      const void *__name;
+     const void *__module_name;
      uptr __has_dynamic_init;
    } type.  */
 
 static tree
 asan_global_struct (void)
 {
-  static const char *field_names[5]
+  static const char *field_names[6]
     = { "__beg", "__size", "__size_with_redzone",
-       "__name", "__has_dynamic_init" };
-  tree fields[5], ret;
+       "__name", "__module_name", "__has_dynamic_init" };
+  tree fields[6], ret;
   int i;
 
   ret = make_node (RECORD_TYPE);
-  for (i = 0; i < 5; i++)
+  for (i = 0; i < 6; i++)
     {
       fields[i]
        = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
@@ -1962,21 +1989,20 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
 {
   tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
   unsigned HOST_WIDE_INT size;
-  tree str_cst, refdecl = decl;
+  tree str_cst, module_name_cst, refdecl = decl;
   vec<constructor_elt, va_gc> *vinner = NULL;
 
-  pretty_printer asan_pp;
+  pretty_printer asan_pp, module_name_pp;
 
   if (DECL_NAME (decl))
     pp_tree_identifier (&asan_pp, DECL_NAME (decl));
   else
     pp_string (&asan_pp, "<unknown>");
-  pp_space (&asan_pp);
-  pp_left_paren (&asan_pp);
-  pp_string (&asan_pp, main_input_filename);
-  pp_right_paren (&asan_pp);
   str_cst = asan_pp_string (&asan_pp);
 
+  pp_string (&module_name_pp, main_input_filename);
+  module_name_cst = asan_pp_string (&module_name_pp);
+
   if (asan_needs_local_alias (decl))
     {
       char buf[20];
@@ -2004,6 +2030,8 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
   CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
   CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
                          fold_convert (const_ptr_type_node, str_cst));
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
+                         fold_convert (const_ptr_type_node, module_name_cst));
   CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, 0));
   init = build_constructor (type, vinner);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
@@ -2158,7 +2186,7 @@ add_string_csts (void **slot, void *data)
 static GTY(()) tree asan_ctor_statements;
 
 /* Module-level instrumentation.
-   - Insert __asan_init() into the list of CTORs.
+   - Insert __asan_init_vN() into the list of CTORs.
    - TODO: insert redzones around globals.
  */
 
index 62dbe98496721c30fac2fb01929cb17543f467ef..e56468424c9236c7ec5ef4102507b60f0193f417 100644 (file)
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef TREE_ASAN
 #define TREE_ASAN
 
+extern void asan_function_start (void);
 extern void asan_finish_file (void);
 extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int);
 extern bool asan_protect_global (tree);
index e2d8849c76835f8cc13a903df73546a138a61f0b..3082548731d2e8b0191535517a993c125dcaacc6 100644 (file)
@@ -213,6 +213,12 @@ along with GCC; see the file COPYING3.  If not see
 #undef ATTR_MATHFN_FPROUNDING_STORE
 #define ATTR_MATHFN_FPROUNDING_STORE ATTR_NOTHROW_LEAF_LIST
 
+/* Define an attribute list for leaf functions that do not throw
+   exceptions normally, but may throw exceptions when using
+   -fnon-call-exceptions.  */
+#define ATTR_NOTHROWCALL_LEAF_LIST (flag_non_call_exceptions ? \
+       ATTR_LEAF_LIST : ATTR_NOTHROW_LEAF_LIST)
+
 /* Make sure 0 is not a legitimate builtin.  */
 DEF_BUILTIN_STUB(BUILT_IN_NONE, (const char *)0)
 
index 067c1341180381782f35f8604877175986f8e84d..68929521087b463f4aeee76defbb7051610e8e3d 100644 (file)
@@ -1,3 +1,21 @@
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * c.opt (-Wdate-time): New option
+       * c-opts.c (sanitize_cpp_opts): Pass on to libcpp.
+
+2013-11-05  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-cppbuiltin.c (cpp_iec_559_value): Test
+       flag_excess_precision_cmdline not flag_excess_precision.
+
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * c.opt (fopenmp-simd): New option.
+       * c-pragma.c (omp_pragmas): Move pragmas which can contain simd to ...
+       (omp_pragmas): ... this new struct.
+       (c_pp_lookup_pragma): Also walk omp_pragmas.
+       (init_pragma): Init pragmas for -fopenmp-simd.
+
 2013-11-04  Marek Polacek  <polacek@redhat.com>
 
        PR c++/58979
index 94f72eceb2e7d4dc194c7fc47b25c9fd89c16275..ec8b1834b7e1e2a42f37fb9524908549b026c0ba 100644 (file)
@@ -734,7 +734,7 @@ cpp_iec_559_value (void)
   if (flag_iso
       && !c_dialect_cxx ()
       && TARGET_FLT_EVAL_METHOD != 0
-      && flag_excess_precision != EXCESS_PRECISION_STANDARD)
+      && flag_excess_precision_cmdline != EXCESS_PRECISION_STANDARD)
     ret = 0;
 
   /* Various options are contrary to IEEE 754 semantics.  */
index 702fe1a8bdf50e086b03d5f6f2099a2822a166ed..2de5425e65473dbe303fcef8bf6392b1371478ee 100644 (file)
@@ -1198,6 +1198,7 @@ sanitize_cpp_opts (void)
 
   cpp_opts->unsigned_char = !flag_signed_char;
   cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS;
+  cpp_opts->warn_date_time = cpp_warn_date_time;
 
   /* Wlong-long is disabled by default. It is enabled by:
       [-Wpedantic | -Wtraditional] -std=[gnu|c]++98 ; or
index 8915f441d7d85c1db9e8876652ea5f9eab256044..8bda6eddfda4f69baa22c9ebd194ef9b2f3d8580 100644 (file)
@@ -1172,31 +1172,35 @@ static const struct omp_pragma_def omp_pragmas[] = {
   { "cancel", PRAGMA_OMP_CANCEL },
   { "cancellation", PRAGMA_OMP_CANCELLATION_POINT },
   { "critical", PRAGMA_OMP_CRITICAL },
-  { "declare", PRAGMA_OMP_DECLARE_REDUCTION },
-  { "distribute", PRAGMA_OMP_DISTRIBUTE },
   { "end", PRAGMA_OMP_END_DECLARE_TARGET },
   { "flush", PRAGMA_OMP_FLUSH },
-  { "for", PRAGMA_OMP_FOR },
   { "master", PRAGMA_OMP_MASTER },
   { "ordered", PRAGMA_OMP_ORDERED },
-  { "parallel", PRAGMA_OMP_PARALLEL },
   { "section", PRAGMA_OMP_SECTION },
   { "sections", PRAGMA_OMP_SECTIONS },
-  { "simd", PRAGMA_OMP_SIMD },
   { "single", PRAGMA_OMP_SINGLE },
-  { "target", PRAGMA_OMP_TARGET },
-  { "task", PRAGMA_OMP_TASK },
   { "taskgroup", PRAGMA_OMP_TASKGROUP },
   { "taskwait", PRAGMA_OMP_TASKWAIT },
   { "taskyield", PRAGMA_OMP_TASKYIELD },
-  { "teams", PRAGMA_OMP_TEAMS },
   { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
 };
+static const struct omp_pragma_def omp_pragmas_simd[] = {
+  { "declare", PRAGMA_OMP_DECLARE_REDUCTION },
+  { "distribute", PRAGMA_OMP_DISTRIBUTE },
+  { "for", PRAGMA_OMP_FOR },
+  { "parallel", PRAGMA_OMP_PARALLEL },
+  { "simd", PRAGMA_OMP_SIMD },
+  { "target", PRAGMA_OMP_TARGET },
+  { "task", PRAGMA_OMP_TASK },
+  { "teams", PRAGMA_OMP_TEAMS },
+};
 
 void
 c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
 {
   const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
+  const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd)
+                                / sizeof (*omp_pragmas);
   int i;
 
   for (i = 0; i < n_omp_pragmas; ++i)
@@ -1207,6 +1211,14 @@ c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
        return;
       }
 
+  for (i = 0; i < n_omp_pragmas_simd; ++i)
+    if (omp_pragmas_simd[i].id == id)
+      {
+       *space = "omp";
+       *name = omp_pragmas_simd[i].name;
+       return;
+      }
+
   if (id >= PRAGMA_FIRST_EXTERNAL
       && (id < PRAGMA_FIRST_EXTERNAL + registered_pp_pragmas.length ()))
     {
@@ -1359,6 +1371,16 @@ init_pragma (void)
        cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name,
                                      omp_pragmas[i].id, true, true);
     }
+  if (flag_openmp || flag_openmp_simd)
+    {
+      const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd)
+                                    / sizeof (*omp_pragmas);
+      int i;
+
+      for (i = 0; i < n_omp_pragmas_simd; ++i)
+       cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas_simd[i].name,
+                                     omp_pragmas_simd[i].id, true, true);
+    }
 
   if (!flag_preprocess_only)
     cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
index b862eb9e27608c83b49895d16cfb319a7a20d0ab..46391fa496c767f81b5ac1f5b14988179698f3ea 100644 (file)
@@ -640,6 +640,10 @@ Wpragmas
 C ObjC C++ ObjC++ Var(warn_pragmas) Init(1) Warning
 Warn about misuses of pragmas
 
+Wdate-time
+Common Var(cpp_warn_date_time) Warning
+Warn about __TIME__, __DATE__ and __TIMESTAMP__ usage
+
 Wproperty-assign-default
 ObjC ObjC++ Var(warn_property_assign_default) Init(1) Warning
 Warn if a property for an Objective-C object has no assign semantics specified
@@ -1069,6 +1073,10 @@ fopenmp
 C ObjC C++ ObjC++ Var(flag_openmp)
 Enable OpenMP (implies -frecursive in Fortran)
 
+fopenmp-simd
+C ObjC C++ ObjC++ Var(flag_openmp_simd)
+Enable OpenMP's SIMD directives
+
 foperator-names
 C++ ObjC++
 Recognize C++ keywords like \"compl\" and \"xor\"
index efb4ba88c383d406b2ca0bdb40c5e9771b63ce16..9a9eed39de56198877e695bc159698aa15b6da1a 100644 (file)
@@ -1,3 +1,10 @@
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * c-parser.c (c_parser_omp_for, c_parser_omp_parallel,
+       c_parser_omp_distribute, c_parser_omp_teams,
+       c_parser_omp_target, c_parser_omp_declare): Handle
+       -fopenmp-simd.
+
 2013-11-03  Marek Polacek  <polacek@redhat.com>
 
        * c-decl.c (grokdeclarator): Add VLA instrumentation.
index 6f52ba94e77a0a09eb1500b367a087203bb55331..c0346ffe9cc2898034aaf1d4387c0837652fbf5c 100644 (file)
@@ -11616,6 +11616,8 @@ c_parser_omp_for (location_t loc, c_parser *parser,
            cclauses = cclauses_buf;
 
          c_parser_consume_token (parser);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
          block = c_begin_compound_stmt (true);
          ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
          block = c_end_compound_stmt (loc, block, true);
@@ -11630,6 +11632,11 @@ c_parser_omp_for (location_t loc, c_parser *parser,
          return ret;
        }
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
 
   clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
   if (cclauses)
@@ -11825,6 +11832,8 @@ c_parser_omp_parallel (location_t loc, c_parser *parser,
        cclauses = cclauses_buf;
 
       c_parser_consume_token (parser);
+      if (!flag_openmp)  /* flag_openmp_simd  */
+       return c_parser_omp_for (loc, parser, p_name, mask, cclauses);
       block = c_begin_omp_parallel ();
       c_parser_omp_for (loc, parser, p_name, mask, cclauses);
       stmt
@@ -11839,6 +11848,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser,
       c_parser_skip_to_pragma_eol (parser);
       return NULL_TREE;
     }
+  else if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
   else if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
@@ -12069,6 +12083,14 @@ c_parser_omp_distribute (location_t loc, c_parser *parser,
          if (cclauses == NULL)
            cclauses = cclauses_buf;
          c_parser_consume_token (parser);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           {
+             if (simd)
+               return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+             else
+               return c_parser_omp_parallel (loc, parser, p_name, mask,
+                                             cclauses);
+           }
          block = c_begin_compound_stmt (true);
          if (simd)
            ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
@@ -12086,6 +12108,11 @@ c_parser_omp_distribute (location_t loc, c_parser *parser,
          return ret;
        }
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
 
   clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
   if (cclauses)
@@ -12134,6 +12161,8 @@ c_parser_omp_teams (location_t loc, c_parser *parser,
            cclauses = cclauses_buf;
 
          c_parser_consume_token (parser);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           return c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
          block = c_begin_compound_stmt (true);
          ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
          block = c_end_compound_stmt (loc, block, true);
@@ -12147,6 +12176,11 @@ c_parser_omp_teams (location_t loc, c_parser *parser,
          return add_stmt (ret);
        }
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
 
   clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
   if (cclauses)
@@ -12258,24 +12292,16 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context)
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
 
-      if (strcmp (p, "data") == 0)
-       {
-         c_parser_consume_token (parser);
-         c_parser_omp_target_data (loc, parser);
-         return true;
-       }
-      else if (strcmp (p, "update") == 0)
-       {
-         c_parser_consume_token (parser);
-         return c_parser_omp_target_update (loc, parser, context);
-       }
-      else if (strcmp (p, "teams") == 0)
+      if (strcmp (p, "teams") == 0)
        {
          tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
          char p_name[sizeof ("#pragma omp target teams distribute "
                              "parallel for simd")];
 
          c_parser_consume_token (parser);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           return c_parser_omp_teams (loc, parser, p_name,
+                                      OMP_TARGET_CLAUSE_MASK, cclauses);
          strcpy (p_name, "#pragma omp target");
          keep_next_level ();
          tree block = c_begin_compound_stmt (true);
@@ -12291,6 +12317,22 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context)
          add_stmt (stmt);
          return true;
        }
+      else if (!flag_openmp)  /* flag_openmp_simd  */
+       {
+         c_parser_skip_to_pragma_eol (parser);
+         return NULL_TREE;
+       }
+      else if (strcmp (p, "data") == 0)
+       {
+         c_parser_consume_token (parser);
+         c_parser_omp_target_data (loc, parser);
+         return true;
+       }
+      else if (strcmp (p, "update") == 0)
+       {
+         c_parser_consume_token (parser);
+         return c_parser_omp_target_update (loc, parser, context);
+       }
     }
 
   tree stmt = make_node (OMP_TARGET);
@@ -12918,6 +12960,11 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context)
          c_parser_omp_declare_reduction (parser, context);
          return;
        }
+      if (!flag_openmp)  /* flag_openmp_simd  */
+       {
+         c_parser_skip_to_pragma_eol (parser);
+         return;
+       }
       if (strcmp (p, "target") == 0)
        {
          c_parser_consume_token (parser);
index 3a40db203fa72073c1caed5ab89c324d693d74fa..bda479071c4e3a94bbde40300291b0330bd5dd47 100644 (file)
@@ -2109,6 +2109,12 @@ foptimize-strlen
 Common Report Var(flag_optimize_strlen) Optimization
 Enable string length optimizations on trees
 
+fisolate-erroneous-paths
+Common Report Var(flag_isolate_erroneous_paths) Optimization
+Detect paths which trigger erroneous or undefined behaviour.  Isolate those
+paths from the main control flow and turn the statement with erroneous or
+undefined behaviour into a trap.
+
 ftree-loop-distribution
 Common Report Var(flag_tree_loop_distribution) Optimization
 Enable loop distribution on trees
index 704e872fc61f3814ac9f682899fd021a06000ba4..a63798b48d0ad1fda755ecb7db046f4622a39a28 100644 (file)
@@ -4329,7 +4329,7 @@ aarch64_output_casesi (rtx *operands)
 {
   char buf[100];
   char label[100];
-  rtx diff_vec = PATTERN (next_active_insn (operands[2]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[2]));
   int index;
   static const char *const patterns[4][2] =
   {
index 654dcef4ab734a7dd368829c00a2384c8d9553ef..624cab9c1aca85ed78affcce8a0e082d6e5e1e72 100644 (file)
@@ -95,13 +95,11 @@ static bool arm_print_operand_punct_valid_p (unsigned char code);
 static const char *fp_const_from_val (REAL_VALUE_TYPE *);
 static arm_cc get_arm_condition_code (rtx);
 static HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
-static rtx is_jump_table (rtx);
 static const char *output_multi_immediate (rtx *, const char *, const char *,
                                           int, HOST_WIDE_INT);
 static const char *shift_op (rtx, HOST_WIDE_INT *);
 static struct machine_function *arm_init_machine_status (void);
 static void thumb_exit (FILE *, int);
-static rtx is_jump_table (rtx);
 static HOST_WIDE_INT get_jump_table_size (rtx);
 static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
 static Mnode *add_minipool_forward_ref (Mfix *);
@@ -15464,23 +15462,6 @@ Mfix *                 minipool_fix_tail;
 /* The fix entry for the current minipool, once it has been placed.  */
 Mfix *         minipool_barrier;
 
-/* Determines if INSN is the start of a jump table.  Returns the end
-   of the TABLE or NULL_RTX.  */
-static rtx
-is_jump_table (rtx insn)
-{
-  rtx table;
-
-  if (jump_to_label_p (insn)
-      && ((table = next_active_insn (JUMP_LABEL (insn)))
-         == next_active_insn (insn))
-      && table != NULL
-      && JUMP_TABLE_DATA_P (table))
-    return table;
-
-  return NULL_RTX;
-}
-
 #ifndef JUMP_TABLES_IN_TEXT_SECTION
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
@@ -16089,8 +16070,7 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
        count += get_attr_length (from);
 
       /* If there is a jump table, add its length.  */
-      tmp = is_jump_table (from);
-      if (tmp != NULL)
+      if (tablejump_p (from, NULL, &tmp))
        {
          count += get_jump_table_size (tmp);
 
@@ -16696,7 +16676,7 @@ arm_reorg (void)
 
          /* If the insn is a vector jump, add the size of the table
             and skip the table.  */
-         if ((table = is_jump_table (insn)) != NULL)
+         if (tablejump_p (insn, NULL, &table))
            {
              address += get_jump_table_size (table);
              insn = table;
@@ -28606,7 +28586,7 @@ arm_output_iwmmxt_tinsr (rtx *operands)
 const char *
 thumb1_output_casesi (rtx *operands)
 {
-  rtx diff_vec = PATTERN (next_active_insn (operands[0]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[0]));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
@@ -28629,7 +28609,7 @@ thumb1_output_casesi (rtx *operands)
 const char *
 thumb2_output_casesi (rtx *operands)
 {
-  rtx diff_vec = PATTERN (next_active_insn (operands[2]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[2]));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
index a6eaf8ad34a0b216ee53174dc8983e7318e7491d..1c053b1e51eb7d12547b9409a321bf8a96b940e3 100644 (file)
@@ -141,6 +141,10 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
       def_or_undef (parse_in, "__corei7");
       def_or_undef (parse_in, "__corei7__");
       break;
+    case PROCESSOR_COREI7_AVX:
+      def_or_undef (parse_in, "__corei7_avx");
+      def_or_undef (parse_in, "__corei7_avx__");
+      break;
     case PROCESSOR_HASWELL:
       def_or_undef (parse_in, "__core_avx2");
       def_or_undef (parse_in, "__core_avx2__");
@@ -238,6 +242,9 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
     case PROCESSOR_COREI7:
       def_or_undef (parse_in, "__tune_corei7__");
       break;
+    case PROCESSOR_COREI7_AVX:
+      def_or_undef (parse_in, "__tune_corei7_avx__");
+      break;
     case PROCESSOR_HASWELL:
       def_or_undef (parse_in, "__tune_core_avx2__");
       break;
@@ -467,6 +474,9 @@ ix86_target_macros (void)
       builtin_define_std ("i386");
     }
 
+  if (!TARGET_80387)
+    cpp_define (parse_in, "_SOFT_FLOAT");
+
   if (TARGET_LONG_DOUBLE_64)
     cpp_define (parse_in, "__LONG_DOUBLE_64__");
 
index 5799251404bed6e2b0f003f9f5f260f604d2b3f3..fdf9d5804df1eba19a7b51fa4599634cb5adc430 100644 (file)
@@ -143,6 +143,7 @@ extern void ix86_split_lshr (rtx *, rtx, enum machine_mode);
 extern rtx ix86_find_base_term (rtx);
 extern bool ix86_check_movabs (rtx, int);
 extern void ix86_split_idivmod (enum machine_mode, rtx[], bool);
+extern bool ix86_emit_cfi ();
 
 extern rtx assign_386_stack_local (enum machine_mode, enum ix86_stack_slot);
 extern int ix86_attr_length_immediate_default (rtx, bool);
index bc93d7f849ac376ceb82fc83aefb9ee2d1a6068c..79db0df61c6a7c4af64368f2c7600e22844885db 100644 (file)
@@ -1834,8 +1834,9 @@ const struct processor_costs *ix86_cost = &pentium_cost;
 #define m_P4_NOCONA (m_PENT4 | m_NOCONA)
 #define m_CORE2 (1<<PROCESSOR_CORE2)
 #define m_COREI7 (1<<PROCESSOR_COREI7)
+#define m_COREI7_AVX (1<<PROCESSOR_COREI7_AVX)
 #define m_HASWELL (1<<PROCESSOR_HASWELL)
-#define m_CORE_ALL (m_CORE2 | m_COREI7  | m_HASWELL)
+#define m_CORE_ALL (m_CORE2 | m_COREI7  | m_COREI7_AVX | m_HASWELL)
 #define m_ATOM (1<<PROCESSOR_ATOM)
 #define m_SLM (1<<PROCESSOR_SLM)
 
@@ -2300,6 +2301,8 @@ static const struct ptt processor_target_table[PROCESSOR_max] =
   {&core_cost, 16, 10, 16, 10, 16},
   /* Core i7  */
   {&core_cost, 16, 10, 16, 10, 16},
+  /* Core i7 avx  */
+  {&core_cost, 16, 10, 16, 10, 16},
   /* Core avx2  */
   {&core_cost, 16, 10, 16, 10, 16},
   {&generic_cost, 16, 10, 16, 10, 16},
@@ -2329,6 +2332,7 @@ static const char *const cpu_names[TARGET_CPU_DEFAULT_max] =
   "nocona",
   "core2",
   "corei7",
+  "corei7-avx",
   "core-avx2",
   "atom",
   "slm",
@@ -3017,12 +3021,12 @@ ix86_option_override_internal (bool main_args_p,
       {"corei7", PROCESSOR_COREI7, CPU_COREI7,
        PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_SSSE3
        | PTA_SSE4_1 | PTA_SSE4_2 | PTA_CX16 | PTA_POPCNT | PTA_FXSR},
-      {"corei7-avx", PROCESSOR_COREI7, CPU_COREI7,
+      {"corei7-avx", PROCESSOR_COREI7_AVX, CPU_COREI7,
        PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
        | PTA_SSSE3 | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AVX
        | PTA_CX16 | PTA_POPCNT | PTA_AES | PTA_PCLMUL
        | PTA_FXSR | PTA_XSAVE | PTA_XSAVEOPT},
-      {"core-avx-i", PROCESSOR_COREI7, CPU_COREI7,
+      {"core-avx-i", PROCESSOR_COREI7_AVX, CPU_COREI7,
        PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
        | PTA_SSSE3 | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AVX
        | PTA_CX16 | PTA_POPCNT | PTA_AES | PTA_PCLMUL | PTA_FSGSBASE
@@ -17341,6 +17345,14 @@ ix86_split_idivmod (enum machine_mode mode, rtx operands[],
   emit_label (end_label);
 }
 
+/* Whether it is OK to emit CFI directives when emitting asm code.  */
+
+bool
+ix86_emit_cfi ()
+{
+  return dwarf2out_do_cfi_asm ();
+}
+
 #define LEA_MAX_STALL (3)
 #define LEA_SEARCH_THRESHOLD (LEA_MAX_STALL << 1)
 
@@ -24520,6 +24532,42 @@ ix86_instantiate_decls (void)
       instantiate_decl_rtl (s->rtl);
 }
 \f
+/* Check whether x86 address PARTS is a pc-relative address.  */
+
+static bool
+rip_relative_addr_p (struct ix86_address *parts)
+{
+  rtx base, index, disp;
+
+  base = parts->base;
+  index = parts->index;
+  disp = parts->disp;
+
+  if (disp && !base && !index)
+    {
+      if (TARGET_64BIT)
+       {
+         rtx symbol = disp;
+
+         if (GET_CODE (disp) == CONST)
+           symbol = XEXP (disp, 0);
+         if (GET_CODE (symbol) == PLUS
+             && CONST_INT_P (XEXP (symbol, 1)))
+           symbol = XEXP (symbol, 0);
+
+         if (GET_CODE (symbol) == LABEL_REF
+             || (GET_CODE (symbol) == SYMBOL_REF
+                 && SYMBOL_REF_TLS_MODEL (symbol) == 0)
+             || (GET_CODE (symbol) == UNSPEC
+                 && (XINT (symbol, 1) == UNSPEC_GOTPCREL
+                     || XINT (symbol, 1) == UNSPEC_PCREL
+                     || XINT (symbol, 1) == UNSPEC_GOTNTPOFF)))
+           return true;
+       }
+    }
+  return false;
+}
+
 /* Calculate the length of the memory address in the instruction encoding.
    Includes addr32 prefix, does not include the one-byte modrm, opcode,
    or other prefixes.  We never generate addr32 prefix for LEA insn.  */
@@ -24591,25 +24639,8 @@ memory_address_length (rtx addr, bool lea)
   else if (disp && !base && !index)
     {
       len += 4;
-      if (TARGET_64BIT)
-       {
-         rtx symbol = disp;
-
-         if (GET_CODE (disp) == CONST)
-           symbol = XEXP (disp, 0);
-         if (GET_CODE (symbol) == PLUS
-             && CONST_INT_P (XEXP (symbol, 1)))
-           symbol = XEXP (symbol, 0);
-
-         if (GET_CODE (symbol) != LABEL_REF
-             && (GET_CODE (symbol) != SYMBOL_REF
-                 || SYMBOL_REF_TLS_MODEL (symbol) != 0)
-             && (GET_CODE (symbol) != UNSPEC
-                 || (XINT (symbol, 1) != UNSPEC_GOTPCREL
-                     && XINT (symbol, 1) != UNSPEC_PCREL
-                     && XINT (symbol, 1) != UNSPEC_GOTNTPOFF)))
-           len++;
-       }
+      if (rip_relative_addr_p (&parts))
+       len++;
     }
   else
     {
@@ -24808,6 +24839,7 @@ ix86_issue_rate (void)
 
     case PROCESSOR_CORE2:
     case PROCESSOR_COREI7:
+    case PROCESSOR_COREI7_AVX:
     case PROCESSOR_HASWELL:
       return 4;
 
@@ -25104,6 +25136,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 
     case PROCESSOR_CORE2:
     case PROCESSOR_COREI7:
+    case PROCESSOR_COREI7_AVX:
     case PROCESSOR_HASWELL:
       memory = get_attr_memory (insn);
 
@@ -25182,6 +25215,7 @@ ia32_multipass_dfa_lookahead (void)
 
     case PROCESSOR_CORE2:
     case PROCESSOR_COREI7:
+    case PROCESSOR_COREI7_AVX:
     case PROCESSOR_HASWELL:
     case PROCESSOR_ATOM:
     case PROCESSOR_SLM:
@@ -25198,6 +25232,119 @@ ia32_multipass_dfa_lookahead (void)
     }
 }
 
+/* Return true if target platform supports macro-fusion.  */
+
+static bool
+ix86_macro_fusion_p ()
+{
+  return TARGET_FUSE_CMP_AND_BRANCH;
+}
+
+/* Check whether current microarchitecture support macro fusion
+   for insn pair "CONDGEN + CONDJMP". Refer to
+   "Intel Architectures Optimization Reference Manual". */
+
+static bool
+ix86_macro_fusion_pair_p (rtx condgen, rtx condjmp)
+{
+  rtx src, dest;
+  rtx single_set = single_set (condgen);
+  enum rtx_code ccode;
+  rtx compare_set = NULL_RTX, test_if, cond;
+  rtx alu_set = NULL_RTX, addr = NULL_RTX;
+
+  if (get_attr_type (condgen) != TYPE_TEST
+      && get_attr_type (condgen) != TYPE_ICMP
+      && get_attr_type (condgen) != TYPE_INCDEC
+      && get_attr_type (condgen) != TYPE_ALU)
+    return false;
+
+  if (single_set == NULL_RTX
+      && !TARGET_FUSE_ALU_AND_BRANCH)
+    return false;
+
+  if (single_set != NULL_RTX)
+    compare_set = single_set;
+  else
+    {
+      int i;
+      rtx pat = PATTERN (condgen);
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
+         {
+           rtx set_src = SET_SRC (XVECEXP (pat, 0, i));
+           if (GET_CODE (set_src) == COMPARE)
+             compare_set = XVECEXP (pat, 0, i);
+           else
+             alu_set = XVECEXP (pat, 0, i);
+         }
+    }
+  if (compare_set == NULL_RTX)
+    return false;
+  src = SET_SRC (compare_set);
+  if (GET_CODE (src) != COMPARE)
+    return false;
+
+  /* Macro-fusion for cmp/test MEM-IMM + conditional jmp is not
+     supported.  */
+  if ((MEM_P (XEXP (src, 0))
+       && CONST_INT_P (XEXP (src, 1)))
+      || (MEM_P (XEXP (src, 1))
+         && CONST_INT_P (XEXP (src, 0))))
+    return false;
+
+  /* No fusion for RIP-relative address.  */
+  if (MEM_P (XEXP (src, 0)))
+    addr = XEXP (XEXP (src, 0), 0);
+  else if (MEM_P (XEXP (src, 1)))
+    addr = XEXP (XEXP (src, 1), 0);
+
+  if (addr) {
+    ix86_address parts;
+    int ok = ix86_decompose_address (addr, &parts);
+    gcc_assert (ok);
+
+    if (rip_relative_addr_p (&parts))
+      return false;
+  }
+
+  test_if = SET_SRC (pc_set (condjmp));
+  cond = XEXP (test_if, 0);
+  ccode = GET_CODE (cond);
+  /* Check whether conditional jump use Sign or Overflow Flags.  */
+  if (!TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS
+      && (ccode == GE
+          || ccode == GT
+         || ccode == LE
+         || ccode == LT))
+    return false;
+
+  /* Return true for TYPE_TEST and TYPE_ICMP.  */
+  if (get_attr_type (condgen) == TYPE_TEST
+      || get_attr_type (condgen) == TYPE_ICMP)
+    return true;
+
+  /* The following is the case that macro-fusion for alu + jmp.  */
+  if (!TARGET_FUSE_ALU_AND_BRANCH || !alu_set)
+    return false;
+
+  /* No fusion for alu op with memory destination operand.  */
+  dest = SET_DEST (alu_set);
+  if (MEM_P (dest))
+    return false;
+
+  /* Macro-fusion for inc/dec + unsigned conditional jump is not
+     supported.  */
+  if (get_attr_type (condgen) == TYPE_INCDEC
+      && (ccode == GEU
+         || ccode == GTU
+         || ccode == LEU
+         || ccode == LTU))
+    return false;
+
+  return true;
+}
+
 /* Try to reorder ready list to take advantage of Atom pipelined IMUL
    execution. It is applied if
    (1) IMUL instruction is on the top of list;
@@ -25822,6 +25969,7 @@ ix86_sched_init_global (FILE *dump ATTRIBUTE_UNUSED,
     {
     case PROCESSOR_CORE2:
     case PROCESSOR_COREI7:
+    case PROCESSOR_COREI7_AVX:
     case PROCESSOR_HASWELL:
       /* Do not perform multipass scheduling for pre-reload schedule
          to save compile time.  */
@@ -29672,6 +29820,10 @@ get_builtin_code_for_version (tree decl, tree *predicate_list)
              arg_str = "corei7";
              priority = P_PROC_SSE4_2;
              break;
+            case PROCESSOR_COREI7_AVX:
+              arg_str = "corei7-avx";
+              priority = P_PROC_SSE4_2;
+              break;
            case PROCESSOR_ATOM:
              arg_str = "atom";
              priority = P_PROC_SSSE3;
@@ -43375,6 +43527,18 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
   return val;
 }
 
+/* Implement TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P.  */
+
+static bool
+ix86_float_exceptions_rounding_supported_p (void)
+{
+  /* For x87 floating point with standard excess precision handling,
+     there is no adddf3 pattern (since x87 floating point only has
+     XFmode operations) so the default hook implementation gets this
+     wrong.  */
+  return TARGET_80387 || TARGET_SSE_MATH;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
@@ -43475,6 +43639,10 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
   ia32_multipass_dfa_lookahead
+#undef TARGET_SCHED_MACRO_FUSION_P
+#define TARGET_SCHED_MACRO_FUSION_P ix86_macro_fusion_p
+#undef TARGET_SCHED_MACRO_FUSION_PAIR_P
+#define TARGET_SCHED_MACRO_FUSION_PAIR_P ix86_macro_fusion_pair_p
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL ix86_function_ok_for_sibcall
@@ -43747,6 +43915,10 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
 #undef TARGET_SPILL_CLASS
 #define TARGET_SPILL_CLASS ix86_spill_class
 
+#undef TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P
+#define TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P \
+  ix86_float_exceptions_rounding_supported_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
index c979ee534a8c7897dff4c4033c57726ccf327851..9836a40b46c7429a3242740bc4e0f8b96679af5b 100644 (file)
@@ -304,6 +304,7 @@ extern const struct processor_costs ix86_size_cost;
 #define TARGET_NOCONA (ix86_tune == PROCESSOR_NOCONA)
 #define TARGET_CORE2 (ix86_tune == PROCESSOR_CORE2)
 #define TARGET_COREI7 (ix86_tune == PROCESSOR_COREI7)
+#define TARGET_COREI7_AVX (ix86_tune == PROCESSOR_COREI7_AVX)
 #define TARGET_HASWELL (ix86_tune == PROCESSOR_HASWELL)
 #define TARGET_GENERIC (ix86_tune == PROCESSOR_GENERIC)
 #define TARGET_AMDFAM10 (ix86_tune == PROCESSOR_AMDFAM10)
@@ -415,8 +416,17 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST];
        ix86_tune_features[X86_TUNE_USE_VECTOR_FP_CONVERTS]
 #define TARGET_USE_VECTOR_CONVERTS \
        ix86_tune_features[X86_TUNE_USE_VECTOR_CONVERTS]
+#define TARGET_FUSE_CMP_AND_BRANCH_32 \
+       ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_32]
+#define TARGET_FUSE_CMP_AND_BRANCH_64 \
+       ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_64]
 #define TARGET_FUSE_CMP_AND_BRANCH \
-       ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH]
+       (TARGET_64BIT ? TARGET_FUSE_CMP_AND_BRANCH_64 \
+        : TARGET_FUSE_CMP_AND_BRANCH_32)
+#define TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS \
+       ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS]
+#define TARGET_FUSE_ALU_AND_BRANCH \
+       ix86_tune_features[X86_TUNE_FUSE_ALU_AND_BRANCH]
 #define TARGET_OPT_AGU ix86_tune_features[X86_TUNE_OPT_AGU]
 #define TARGET_VECTORIZE_DOUBLE \
        ix86_tune_features[X86_TUNE_VECTORIZE_DOUBLE]
@@ -613,6 +623,7 @@ enum target_cpu_default
   TARGET_CPU_DEFAULT_nocona,
   TARGET_CPU_DEFAULT_core2,
   TARGET_CPU_DEFAULT_corei7,
+  TARGET_CPU_DEFAULT_corei7_avx,
   TARGET_CPU_DEFAULT_haswell,
   TARGET_CPU_DEFAULT_atom,
   TARGET_CPU_DEFAULT_slm,
@@ -2229,6 +2240,7 @@ enum processor_type
   PROCESSOR_NOCONA,
   PROCESSOR_CORE2,
   PROCESSOR_COREI7,
+  PROCESSOR_COREI7_AVX,
   PROCESSOR_HASWELL,
   PROCESSOR_GENERIC,
   PROCESSOR_AMDFAM10,
index 08ef18ccec54175815fb9f07ce070560bfce5094..087179191cb3fa4b314cd8973852c97439a48d5b 100644 (file)
@@ -26,7 +26,15 @@ along with GCC; see the file COPYING3.  If not see
        builtin_define ("__rtems__");           \
        builtin_define ("__USE_INIT_FINI__");   \
        builtin_assert ("system=rtems");        \
-       if (!TARGET_80387)                      \
-         builtin_define ("_SOFT_FLOAT");       \
     }                                          \
   while (0)
+
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (TARGET_80387 ? 80 : 64)
+
+#undef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
+#ifdef _SOFT_FLOAT
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
+#else
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 80
+#endif
index 9e5835662e1c690e25bd6f7c0ff6a3077e280c9d..8408a2bfe431eecea1529d2af058ff1618ec4253 100644 (file)
   const char *xchg = "xchg{<imodesuffix>}\t%%<regprefix>bx, %5";
 
   if (swap)
-    output_asm_insn (xchg, operands);
+    {
+      output_asm_insn (xchg, operands);
+      if (ix86_emit_cfi ())
+       {
+         output_asm_insn (".cfi_remember_state", operands);
+         output_asm_insn (".cfi_register\t%%<regprefix>bx, %5", operands);
+       }
+    }
   output_asm_insn ("lock{%;} %K7cmpxchg<doublemodesuffix>b\t%2", operands);
   if (swap)
-    output_asm_insn (xchg, operands);
+    {
+      output_asm_insn (xchg, operands);
+      if (ix86_emit_cfi ())
+       output_asm_insn (".cfi_restore_state", operands);
+    }
 
   return "";
 })
index 6161ec100909f02f32d160c4f59ae851b395a006..fef4c22e9c164787da9323689424571a0c26ce29 100644 (file)
 # <http://www.gnu.org/licenses/>.
 #
 
-MULTILIB_OPTIONS = mtune=i486/mtune=pentium/mtune=pentiumpro \
-msoft-float
+MULTILIB_OPTIONS = mtune=i486/mtune=pentium/mtune=pentiumpro msoft-float
 MULTILIB_DIRNAMES= m486 mpentium mpentiumpro soft-float
-MULTILIB_MATCHES = msoft-float=mno-m80387
-MULTILIB_MATCHES += mtune?pentium=mtune?k6 mtune?pentiumpro=mtune?mathlon
+MULTILIB_MATCHES = msoft-float=mno-80387
+MULTILIB_MATCHES += mtune?pentium=mtune?k6 mtune?pentiumpro=mtune?athlon
 MULTILIB_EXCEPTIONS = \
 mtune=pentium/*msoft-float* \
 mtune=pentiumpro/*msoft-float*
index 6e5d2fe0affc155db51d31903c3bebc7b27f9f1a..1a85ce266df6aecbf8f2fa55965695f882048d03 100644 (file)
@@ -92,11 +92,29 @@ DEF_TUNE (X86_TUNE_MOVX, "movx",
 DEF_TUNE (X86_TUNE_MEMORY_MISMATCH_STALL, "memory_mismatch_stall",
           m_P4_NOCONA | m_CORE_ALL | m_ATOM | m_SLM | m_AMD_MULTIPLE | m_GENERIC)
 
-/* X86_TUNE_FUSE_CMP_AND_BRANCH: Fuse a compare or test instruction
-   with a subsequent conditional jump instruction into a single
-   compare-and-branch uop.
+/* X86_TUNE_FUSE_CMP_AND_BRANCH_32: Fuse compare with a subsequent
+   conditional jump instruction for 32 bit TARGET.
    FIXME: revisit for generic.  */
-DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH, "fuse_cmp_and_branch", m_BDVER | m_CORE_ALL)
+DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_32, "fuse_cmp_and_branch_32",
+          m_CORE_ALL | m_BDVER)
+
+/* X86_TUNE_FUSE_CMP_AND_BRANCH_64: Fuse compare with a subsequent
+   conditional jump instruction for TARGET_64BIT.
+   FIXME: revisit for generic.  */
+DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_64, "fuse_cmp_and_branch_64",
+          m_COREI7 | m_COREI7_AVX | m_HASWELL | m_BDVER)
+
+/* X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS: Fuse compare with a
+   subsequent conditional jump instruction when the condition jump
+   check sign flag (SF) or overflow flag (OF).  */
+DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS, "fuse_cmp_and_branch_soflags",
+          m_COREI7 | m_COREI7_AVX | m_HASWELL | m_BDVER)
+
+/* X86_TUNE_FUSE_ALU_AND_BRANCH: Fuse alu with a subsequent conditional
+   jump instruction when the alu instruction produces the CCFLAG consumed by
+   the conditional jump instruction. */
+DEF_TUNE (X86_TUNE_FUSE_ALU_AND_BRANCH, "fuse_alu_and_branch",
+          m_COREI7_AVX | m_HASWELL)
 
 /* X86_TUNE_REASSOC_INT_TO_PARALLEL: Try to produce parallel computations
    during reassociation of integer computation.  */
@@ -300,12 +318,12 @@ DEF_TUNE (X86_TUNE_GENERAL_REGS_SSE_SPILL, "general_regs_sse_spill",
 /* X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL: Use movups for misaligned loads instead
    of a sequence loading registers by parts.  */
 DEF_TUNE (X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL, "sse_unaligned_load_optimal",
-          m_COREI7 | m_AMDFAM10 | m_BDVER | m_BTVER | m_SLM | m_GENERIC)
+          m_COREI7 | m_COREI7_AVX | m_AMDFAM10 | m_BDVER | m_BTVER | m_SLM | m_GENERIC)
 
 /* X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL: Use movups for misaligned stores instead
    of a sequence loading registers by parts.  */
 DEF_TUNE (X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL, "sse_unaligned_store_optimal",
-          m_COREI7 | m_BDVER | m_SLM | m_GENERIC)
+          m_COREI7 | m_COREI7_AVX | m_BDVER | m_SLM | m_GENERIC)
 
 /* Use packed single precision instructions where posisble.  I.e. movups instead
    of movupd.  */
index 9e61cdd5bfc692920639c32cf20097ec481cc04b..7a516c1b5083becf8d9be96bb17886ea03ba604c 100644 (file)
        (plus:SI (match_operand:SI 0 "register_operand" "d")
                 (label_ref:SI (match_operand 1 "" ""))))
    (use (label_ref:SI (match_dup 1)))]
-  "!(Pmode == DImode) && next_active_insn (insn) != 0
-   && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
-   && PREV_INSN (next_active_insn (insn)) == operands[1]"
+  "!(Pmode == DImode) && NEXT_INSN (operands[1]) != 0
+   && GET_CODE (PATTERN (NEXT_INSN (operands[1]))) == ADDR_DIFF_VEC"
   "*
 {
   return \"j\\t%0\";
index 40d273936193cc49150bdf545208166ac95d2ca6..8a526f1d2f86ceb23e2cde78ecda520031e26a90 100644 (file)
        (plus:SI (match_operand:SI 0 "register_operand" "d")
                 (label_ref:SI (match_operand 1 "" ""))))
   (use (label_ref:SI (match_dup 1)))]
- "next_active_insn (insn) != 0
-  && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
-  && PREV_INSN (next_active_insn (insn)) == operands[1]
+ "NEXT_INSN (operands[1]) != 0
+  && GET_CODE (PATTERN (NEXT_INSN (operands[1]))) == ADDR_DIFF_VEC
   && flag_pic"
   {
     output_asm_insn ("addk\t%0,%0,r20",operands);
index 37c59980ecfb896e7780e6363b744278551dccd4..697a2ad9ac1a098b337d32b07415bd7ee1c8c5d1 100644 (file)
   
   emit_insn (gen_vec_widen_umult_even_v16qi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_umult_odd_v16qi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrghh (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrghh (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrghh (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_umult_even_v16qi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_umult_odd_v16qi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrglh (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrglh (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrglh (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_smult_even_v16qi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_smult_odd_v16qi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrghh (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrghh (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrghh (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_smult_even_v16qi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_smult_odd_v16qi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrglh (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrglh (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrglh (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_umult_even_v8hi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_umult_odd_v8hi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrghw (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrghw (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrghw (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_umult_even_v8hi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_umult_odd_v8hi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrglw (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrglw (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrglw (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_smult_even_v8hi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_smult_odd_v8hi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrghw (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrghw (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrghw (operands[0], vo, ve));
   DONE;
 }")
 
   
   emit_insn (gen_vec_widen_smult_even_v8hi (ve, operands[1], operands[2]));
   emit_insn (gen_vec_widen_smult_odd_v8hi (vo, operands[1], operands[2]));
-  emit_insn (gen_altivec_vmrglw (operands[0], ve, vo));
+  if (BYTES_BIG_ENDIAN)
+    emit_insn (gen_altivec_vmrglw (operands[0], ve, vo));
+  else
+    emit_insn (gen_altivec_vmrglw (operands[0], vo, ve));
   DONE;
 }")
 
index 37de331c8b609687a61b30595276abfd916cca2a..8ca79fd79f781b950f8bf1418fdd277497ea8643 100644 (file)
@@ -6413,7 +6413,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
        return false;
       if (GET_MODE_NUNITS (mode) != 1)
        return false;
-      if (! lra_in_progress && GET_MODE_SIZE (mode) > UNITS_PER_WORD
+      if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
          && !(/* ??? Assume floating point reg based on mode?  */
               TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
               && (mode == DFmode || mode == DDmode)))
index 0a1130f7bff3155dc0545715821fb590b2834063..68214d913164b71950a699b7ca12adc741ae91d8 100644 (file)
 
   emit_insn (gen_vsx_xvcvdpsxws (r1, operands[1]));
   emit_insn (gen_vsx_xvcvdpsxws (r2, operands[2]));
-  rs6000_expand_extract_even (operands[0], r1, r2);
+
+  if (BYTES_BIG_ENDIAN)
+    rs6000_expand_extract_even (operands[0], r1, r2);
+  else
+    rs6000_expand_extract_even (operands[0], r2, r1);
+
   DONE;
 })
 
 
   emit_insn (gen_vsx_xvcvdpuxws (r1, operands[1]));
   emit_insn (gen_vsx_xvcvdpuxws (r2, operands[2]));
-  rs6000_expand_extract_even (operands[0], r1, r2);
+
+  if (BYTES_BIG_ENDIAN)
+    rs6000_expand_extract_even (operands[0], r1, r2);
+  else
+    rs6000_expand_extract_even (operands[0], r2, r1);
+
   DONE;
 })
 
index 38397f376ba673dd428a41ac07d23c6cf280c894..9bc3a9157848604e6e107844f36b312713522294 100644 (file)
@@ -10823,7 +10823,7 @@ label:
    (clobber (match_scratch:SI 3 "=X,1"))]
   "TARGET_SH1"
 {
-  rtx diff_vec = PATTERN (next_active_insn (operands[2]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[2]));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
@@ -10857,7 +10857,7 @@ label:
    (clobber (match_operand:SI 4 "" "=X,1"))]
   "TARGET_SH2 && reload_completed && flag_pic"
 {
-  rtx diff_vec = PATTERN (next_active_insn (operands[2]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[2]));
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
   switch (GET_MODE (diff_vec))
@@ -10895,7 +10895,7 @@ label:
                    UNSPEC_CASESI)))]
   "TARGET_SHMEDIA"
 {
-  rtx diff_vec = PATTERN (next_active_insn (operands[2]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[2]));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
@@ -10922,7 +10922,7 @@ label:
                      (label_ref:DI (match_operand 3 "" ""))] UNSPEC_CASESI)))]
   "TARGET_SHMEDIA"
 {
-  rtx diff_vec = PATTERN (next_active_insn (operands[3]));
+  rtx diff_vec = PATTERN (NEXT_INSN (operands[3]));
 
   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
 
index 8a3df56e63f52ce6284209007e5c3ede8cad1231..887ea61594416c5800790174091f0253bc159fb3 100644 (file)
@@ -1,3 +1,20 @@
+2013-11-05  Jason Merrill  <jason@redhat.com>
+
+       PR c++/58868
+       * decl.c (check_initializer): Don't use build_vec_init for arrays
+       of trivial type.
+
+2013-11-05  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/58724
+       * name-lookup.c (handle_namespace_attrs): Use get_attribute_name.
+
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * parser.c (cp_parser_omp_for, cp_parser_omp_parallel,
+       cp_parser_omp_distribute, cp_parser_omp_teams, cp_parser_omp_target,
+       cp_parser_omp_declare): Handle -fopenmp-simd.
+
 2013-11-04  Eric Botcazou  <ebotcazou@adacore.com>
 
        * decl2.c (cpp_check): Change type of first parameter and deal with
index 81a35004730b404c6f8e842e088c6e5660a43bd8..27eda06cc7fb3a67c5879d3151fabd12a5fb6a89 100644 (file)
@@ -5684,6 +5684,7 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
          && !(init && BRACE_ENCLOSED_INITIALIZER_P (init)
               && CP_AGGREGATE_TYPE_P (type)
               && (CLASS_TYPE_P (type)
+                  || !TYPE_NEEDS_CONSTRUCTING (type)
                   || type_has_extended_temps (type))))
        {
          init_code = build_aggr_init_full_exprs (decl, init, flags);
index 025a03cd9fa61e16a0eb979950c9fb996b921602..ced596e310a4ef3f041a26b3289d6f3c0ea8383c 100644 (file)
@@ -3571,7 +3571,7 @@ handle_namespace_attrs (tree ns, tree attributes)
 
   for (d = attributes; d; d = TREE_CHAIN (d))
     {
-      tree name = TREE_PURPOSE (d);
+      tree name = get_attribute_name (d);
       tree args = TREE_VALUE (d);
 
       if (is_attribute_p ("visibility", name))
index 06d779698f4d5fc8281dc47cbff088d4ae7eb680..e4f77e8d68c0a7d2484d57ea6e962a5630bbfeb8 100644 (file)
@@ -29133,6 +29133,9 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
            cclauses = cclauses_buf;
 
          cp_lexer_consume_token (parser->lexer);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           return cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+                                      cclauses);
          sb = begin_omp_structured_block ();
          save = cp_parser_begin_omp_structured_block (parser);
          ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
@@ -29150,6 +29153,11 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
          return ret;
        }
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      cp_parser_require_pragma_eol (parser, pragma_tok);
+      return NULL_TREE;
+    }
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
                                       cclauses == NULL);
@@ -29333,6 +29341,8 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok,
        cclauses = cclauses_buf;
 
       cp_lexer_consume_token (parser->lexer);
+      if (!flag_openmp)  /* flag_openmp_simd  */
+       return cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses);
       block = begin_omp_parallel ();
       save = cp_parser_begin_omp_structured_block (parser);
       cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses);
@@ -29348,6 +29358,11 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok,
       cp_parser_skip_to_pragma_eol (parser, pragma_tok);
       return NULL_TREE;
     }
+  else if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      cp_parser_require_pragma_eol (parser, pragma_tok);
+      return NULL_TREE;
+    }
   else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
     {
       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
@@ -29576,6 +29591,15 @@ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok,
          if (cclauses == NULL)
            cclauses = cclauses_buf;
          cp_lexer_consume_token (parser->lexer);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           {
+             if (simd)
+               return cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+                                          cclauses);
+             else
+               return cp_parser_omp_parallel (parser, pragma_tok, p_name, mask,
+                                              cclauses);
+           }
          sb = begin_omp_structured_block ();
          save = cp_parser_begin_omp_structured_block (parser);
          if (simd)
@@ -29597,6 +29621,11 @@ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok,
          return ret;
        }
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      cp_parser_require_pragma_eol (parser, pragma_tok);
+      return NULL_TREE;
+    }
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
                                       cclauses == NULL);
@@ -29652,6 +29681,9 @@ cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
            cclauses = cclauses_buf;
 
          cp_lexer_consume_token (parser->lexer);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           return cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
+                                            cclauses);
          sb = begin_omp_structured_block ();
          save = cp_parser_begin_omp_structured_block (parser);
          ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
@@ -29668,6 +29700,11 @@ cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
          return add_stmt (ret);
        }
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      cp_parser_require_pragma_eol (parser, pragma_tok);
+      return NULL_TREE;
+    }
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
                                       cclauses == NULL);
@@ -29777,18 +29814,7 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
       const char *p = IDENTIFIER_POINTER (id);
 
-      if (strcmp (p, "data") == 0)
-       {
-         cp_lexer_consume_token (parser->lexer);
-         cp_parser_omp_target_data (parser, pragma_tok);
-         return true;
-       }
-      else if (strcmp (p, "update") == 0)
-       {
-         cp_lexer_consume_token (parser->lexer);
-         return cp_parser_omp_target_update (parser, pragma_tok, context);
-       }
-      else if (strcmp (p, "teams") == 0)
+      if (strcmp (p, "teams") == 0)
        {
          tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
          char p_name[sizeof ("#pragma omp target teams distribute "
@@ -29797,6 +29823,9 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
          cp_lexer_consume_token (parser->lexer);
          strcpy (p_name, "#pragma omp target");
          keep_next_level (true);
+         if (!flag_openmp)  /* flag_openmp_simd  */
+           return cp_parser_omp_teams (parser, pragma_tok, p_name,
+                                       OMP_TARGET_CLAUSE_MASK, cclauses);
          tree sb = begin_omp_structured_block ();
          unsigned save = cp_parser_begin_omp_structured_block (parser);
          tree ret = cp_parser_omp_teams (parser, pragma_tok, p_name,
@@ -29812,6 +29841,22 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
          add_stmt (stmt);
          return true;
        }
+      else if (!flag_openmp)  /* flag_openmp_simd  */
+       {
+         cp_parser_require_pragma_eol (parser, pragma_tok);
+         return NULL_TREE;
+       }
+      else if (strcmp (p, "data") == 0)
+       {
+         cp_lexer_consume_token (parser->lexer);
+         cp_parser_omp_target_data (parser, pragma_tok);
+         return true;
+       }
+      else if (strcmp (p, "update") == 0)
+       {
+         cp_lexer_consume_token (parser->lexer);
+         return cp_parser_omp_target_update (parser, pragma_tok, context);
+       }
     }
 
   tree stmt = make_node (OMP_TARGET);
@@ -30411,6 +30456,11 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
                                           context);
          return;
        }
+      if (!flag_openmp)  /* flag_openmp_simd  */
+       {
+         cp_parser_require_pragma_eol (parser, pragma_tok);
+         return;
+       }
       if (strcmp (p, "target") == 0)
        {
          cp_lexer_consume_token (parser->lexer);
index 799ede1ec955298e26f60ce4c63728a1fecd551b..0d72819b1b0e28acf3231c6596acb2925d0fe442 100644 (file)
@@ -4275,6 +4275,12 @@ the One Definition Rule; for example, it is usually not useful to mark
 an inline method as hidden without marking the whole class as hidden.
 
 A C++ namespace declaration can also have the visibility attribute.
+
+@smallexample
+namespace nspace1 __attribute__ ((visibility ("protected")))
+@{ /* @r{Do something.} */; @}
+@end smallexample
+
 This attribute applies only to the particular namespace body, not to
 other definitions of the same namespace; it is equivalent to using
 @samp{#pragma GCC visibility} before and after the namespace
index e84bca30ab2237cda18e5d61d368747faa6a38f6..863e518b96fd32b172e2e8964fb1a090d1e2fa76 100644 (file)
@@ -168,8 +168,8 @@ in the following sections.
 @gccoptlist{-ansi  -std=@var{standard}  -fgnu89-inline @gol
 -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol
 -fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
--fhosted  -ffreestanding -fopenmp -fms-extensions -fplan9-extensions @gol
--trigraphs  -traditional  -traditional-cpp @gol
+-fhosted  -ffreestanding -fopenmp -fopenmp-simd -fms-extensions @gol
+-fplan9-extensions -trigraphs  -traditional  -traditional-cpp @gol
 -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
 -fsigned-bitfields  -fsigned-char @gol
 -funsigned-bitfields  -funsigned-char}
@@ -240,7 +240,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wno-attributes -Wno-builtin-macro-redefined @gol
 -Wc++-compat -Wc++11-compat -Wcast-align  -Wcast-qual  @gol
 -Wchar-subscripts -Wclobbered  -Wcomment -Wconditionally-supported  @gol
--Wconversion -Wcoverage-mismatch  -Wdelete-incomplete -Wno-cpp  @gol
+-Wconversion -Wcoverage-mismatch -Wdate-time -Wdelete-incomplete -Wno-cpp  @gol
 -Wno-deprecated -Wno-deprecated-declarations -Wdisabled-optimization  @gol
 -Wno-div-by-zero -Wdouble-promotion -Wempty-body  -Wenum-compare @gol
 -Wno-endif-labels -Werror  -Werror=* @gol
@@ -1839,7 +1839,16 @@ Enable handling of OpenMP directives @code{#pragma omp} in C/C++ and
 compiler generates parallel code according to the OpenMP Application
 Program Interface v4.0 @w{@uref{http://www.openmp.org/}}.  This option
 implies @option{-pthread}, and thus is only supported on targets that
-have support for @option{-pthread}.
+have support for @option{-pthread}. @option{-fopenmp} implies
+@option{-fopenmp-simd}.
+
+@item -fopenmp-simd
+@opindex fopenmp-simd
+@cindex OpenMP SIMD
+@cindex SIMD
+Enable handling of OpenMP's SIMD directives with @code{#pragma omp}
+in C/C++ and @code{!$omp} in Fortran. Other OpenMP directives
+are ignored.
 
 @item -fcilkplus
 @opindex fcilkplus
@@ -4517,6 +4526,13 @@ types. @option{-Wconversion-null} is enabled by default.
 Warn when a literal '0' is used as null pointer constant.  This can
 be useful to facilitate the conversion to @code{nullptr} in C++11.
 
+@item -Wdate-time
+@opindex Wdate-time
+@opindex Wno-date-time
+Warn when macros @code{__TIME__}, @code{__DATE__} or @code{__TIMESTAMP__}
+are encountered as they might prevent bit-wise-identical reproducable
+compilations.
+
 @item -Wdelete-incomplete @r{(C++ and Objective-C++ only)}
 @opindex Wdelete-incomplete
 @opindex Wno-delete-incomplete
index 1d26d72ab232845713d18e5a5912535f435b5194..1a06e3d6e74037f00d1fc92d4a33571762cbddbc 100644 (file)
@@ -5291,12 +5291,13 @@ are the first two operands, and both are @code{mem:BLK}s with an
 address in mode @code{Pmode}.
 
 The number of bytes to move is the third operand, in mode @var{m}.
-Usually, you specify @code{word_mode} for @var{m}.  However, if you can
+Usually, you specify @code{Pmode} for @var{m}.  However, if you can
 generate better code knowing the range of valid lengths is smaller than
-those representable in a full word, you should provide a pattern with a
+those representable in a full Pmode pointer, you should provide
+a pattern with a
 mode corresponding to the range of values you can handle efficiently
 (e.g., @code{QImode} for values in the range 0--127; note we avoid numbers
-that appear negative) and also a pattern with @code{word_mode}.
+that appear negative) and also a pattern with @code{Pmode}.
 
 The fourth operand is the known shared alignment of the source and
 destination, in the form of a @code{const_int} rtx.  Thus, if the
index b59368cf753e7c4acaafe15179f973f120b0a22c..7fdca1986907b1fa35daa1f5de2605488605cf71 100644 (file)
@@ -6574,6 +6574,17 @@ scheduling one insn causes other insns to become ready in the same
 cycle.  These other insns can then be taken into account properly.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_SCHED_MACRO_FUSION_P (void)
+This hook is used to check whether target platform supports macro fusion.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_SCHED_MACRO_FUSION_PAIR_P (rtx @var{condgen}, rtx @var{condjmp})
+This hook is used to check whether two insns could be macro fused for
+target microarchitecture. If this hook returns true for the given insn pair
+(@var{condgen} and @var{condjmp}), scheduler will put them into a sched
+group, and they will not be scheduled apart.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK (rtx @var{head}, rtx @var{tail})
 This hook is called after evaluation forward dependencies of insns in
 chain given by two parameter values (@var{head} and @var{tail}
index d3c2f9a67358239eafd948f24b9171ce656aad25..906621209755d50544b51fa1f3bd744fd9a9dd74 100644 (file)
@@ -4938,6 +4938,10 @@ them: try the first ones in this list first.
 
 @hook TARGET_SCHED_REORDER2
 
+@hook TARGET_SCHED_MACRO_FUSION_P
+
+@hook TARGET_SCHED_MACRO_FUSION_PAIR_P
+
 @hook TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK
 
 @hook TARGET_SCHED_INIT
index 32dc514a3dd1415357925d2e79558afebbaa4003..3803a63e3a9af51084e54e6a972f9269ddcb069e 100644 (file)
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"                        /* For SHIFT_COUNT_TRUNCATED.  */
+#include "tm.h"                        /* For BITS_PER_UNIT and *_BIG_ENDIAN.  */
 #include "tree.h"
 
 static int add_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
@@ -237,9 +237,6 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
              ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
              : 0);
 
-  if (SHIFT_COUNT_TRUNCATED)
-    count %= prec;
-
   if (count >= HOST_BITS_PER_DOUBLE_INT)
     {
       /* Shifting by the host word size is undefined according to the
@@ -295,9 +292,6 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
 {
   unsigned HOST_WIDE_INT signmask;
 
-  if (SHIFT_COUNT_TRUNCATED)
-    count %= prec;
-
   if (count >= HOST_BITS_PER_DOUBLE_INT)
     {
       /* Shifting by the host word size is undefined according to the
index c751004c68e4d39dcbc2a665f02e0f4a90a895e2..cb3abcdab8999b9736f7f9b3805fada82b27088a 100644 (file)
@@ -1266,11 +1266,12 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
          /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
             here because if SIZE is less than the mode mask, as it is
             returned by the macro, it will definitely be less than the
-            actual mode mask.  */
+            actual mode mask.  Since SIZE is within the Pmode address
+            space, we limit MODE to Pmode.  */
          && ((CONST_INT_P (size)
               && ((unsigned HOST_WIDE_INT) INTVAL (size)
                   <= (GET_MODE_MASK (mode) >> 1)))
-             || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD))
+             || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
        {
          struct expand_operand ops[6];
          unsigned int nops;
@@ -2849,14 +2850,15 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
       enum insn_code code = direct_optab_handler (setmem_optab, mode);
 
       if (code != CODE_FOR_nothing
-         /* We don't need MODE to be narrower than
-            BITS_PER_HOST_WIDE_INT here because if SIZE is less than
-            the mode mask, as it is returned by the macro, it will
-            definitely be less than the actual mode mask.  */
+         /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
+            here because if SIZE is less than the mode mask, as it is
+            returned by the macro, it will definitely be less than the
+            actual mode mask.  Since SIZE is within the Pmode address
+            space, we limit MODE to Pmode.  */
          && ((CONST_INT_P (size)
               && ((unsigned HOST_WIDE_INT) INTVAL (size)
                   <= (GET_MODE_MASK (mode) >> 1)))
-             || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD))
+             || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
        {
          struct expand_operand ops[6];
          unsigned int nops;
index 052103cd0ea07eaac29422fa1a84c0ba0beaa93d..f7425429b81decc73af0127cb7b80414dc9b82b2 100644 (file)
@@ -78,6 +78,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "params.h"
 #include "tree-pretty-print.h" /* for dump_function_header */
+#include "asan.h"
 #include "wide-int-print.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
@@ -1739,6 +1740,9 @@ final_start_function (rtx first, FILE *file,
 
   high_block_linenum = high_function_linenum = last_linenum;
 
+  if (flag_sanitize & SANITIZE_ADDRESS)
+    asan_function_start ();
+
   if (!DECL_IGNORED_P (current_function_decl))
     debug_hooks->begin_prologue (last_linenum, last_filename);
 
index 059b7b3528c6413a694e198e6e3662e8ea9ebaae..155a65372614d1457a8594d17afb46f6a323b1eb 100644 (file)
@@ -1,3 +1,38 @@
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * lang.opt (-Wdate-time): New option
+       * cpp.c (gfc_cpp_option_data): Add warn_date_time.
+       (gfc_cpp_init_options, gfc_cpp_handle_option,
+       gfc_cpp_post_options): Handle it and pass on to libcpp.
+
+2013-11-05  Steven G. Kargl <kargl@gcc.gnu.org>
+
+       PR fortran/58989
+       * check.c (gfc_check_reshape): ensure that shape is a constant
+       expression.
+
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * lang.opt (fopenmp-simd): New option.
+       * gfortran.h (gfc_option_t): Add gfc_flag_openmp_simd.
+       * options.c (gfc_handle_option): Handle it.
+
+2013-11-04  Ian Lance Taylor  <iant@google.com>
+
+       * f95-lang.c (ATTR_LEAF_LIST): Define.
+
+2013-11-04  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/58771
+       * trans-io.c (transfer_expr): If the backend_decl for a derived
+       type is missing, build it with gfc_typenode_for_spec.
+
+2013-11-04  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/57445
+       * trans-expr.c (gfc_conv_class_to_class): Remove spurious
+       assert.
+
 2013-10-29  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/44350
index 758639e27afaeba36c0e1d5f0c28ec912ed666fb..1508c7447241d359cbdd6881ab3e14f1e8990cac 100644 (file)
@@ -3277,7 +3277,7 @@ gfc_check_reshape (gfc_expr *source, gfc_expr *shape,
                 "than %d elements", &shape->where, GFC_MAX_DIMENSIONS);
       return false;
     }
-  else if (shape->expr_type == EXPR_ARRAY)
+  else if (shape->expr_type == EXPR_ARRAY && gfc_is_constant_expr (shape))
     {
       gfc_expr *e;
       int i, extent;
index ea53681af0c16329bc4456fd2e1798295a0fa73f..8417ddca163404953b05d8d8ba0586673756c5d4 100644 (file)
@@ -100,6 +100,7 @@ struct gfc_cpp_option_data
   const char *deps_filename_user;       /* -MF <arg> */
   int deps_missing_are_generated;       /* -MG */
   int deps_phony;                       /* -MP */
+  int warn_date_time;                   /* -Wdate-time */
 
   const char *multilib;                 /* -imultilib <dir>  */
   const char *prefix;                   /* -iprefix <dir>  */
@@ -262,6 +263,7 @@ gfc_cpp_init_options (unsigned int decoded_options_count,
   gfc_cpp_option.no_predefined = 0;
   gfc_cpp_option.standard_include_paths = 1;
   gfc_cpp_option.verbose = 0;
+  gfc_cpp_option.warn_date_time = 0;
   gfc_cpp_option.deps = 0;
   gfc_cpp_option.deps_skip_system = 0;
   gfc_cpp_option.deps_phony = 0;
@@ -359,6 +361,9 @@ gfc_cpp_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED
       gfc_cpp_option.verbose = value;
       break;
 
+    case OPT_Wdate_time:
+      gfc_cpp_option.warn_date_time = value;
+
     case OPT_A:
     case OPT_D:
     case OPT_U:
@@ -469,6 +474,7 @@ gfc_cpp_post_options (void)
   cpp_option->discard_comments_in_macro_exp = gfc_cpp_option.discard_comments_in_macro_exp;
   cpp_option->print_include_names = gfc_cpp_option.print_include_names;
   cpp_option->preprocessed = gfc_option.flag_preprocessed;
+  cpp_option->warn_date_time = gfc_cpp_option.warn_date_time;
 
   if (gfc_cpp_makedep ())
     {
index 873c137e58176aa1467d2c90c67a00135f0a3ccd..a70d60d6882a6024886fdbc78fdd8f451c98a6c5 100644 (file)
@@ -531,8 +531,9 @@ gfc_builtin_function (tree decl)
   return decl;
 }
 
-/* So far we need just these 6 attribute types.  */
+/* So far we need just these 7 attribute types.  */
 #define ATTR_NULL                      0
+#define ATTR_LEAF_LIST                 (ECF_LEAF)
 #define ATTR_NOTHROW_LEAF_LIST         (ECF_NOTHROW | ECF_LEAF)
 #define ATTR_NOTHROW_LEAF_MALLOC_LIST  (ECF_NOTHROW | ECF_LEAF | ECF_MALLOC)
 #define ATTR_CONST_NOTHROW_LEAF_LIST   (ECF_NOTHROW | ECF_LEAF | ECF_CONST)
index b28edd80002f151f64acc829e9fd22ff28510aaf..af5e68c13ab6e218e603803916decfa4b0d6b32a 100644 (file)
@@ -2286,6 +2286,7 @@ typedef struct
   int flag_cray_pointer;
   int flag_d_lines;
   int gfc_flag_openmp;
+  int gfc_flag_openmp_simd;
   int flag_sign_zero;
   int flag_stack_arrays;
   int flag_module_private;
index 4f7993433d49e5b712b4f168bab288def97389b3..5e09cbd1459223c71044256e2e35d30eaca6d735 100644 (file)
@@ -213,6 +213,10 @@ Wc-binding-type
 Fortran Warning
 Warn if the type of a variable might be not interoperable with C
 
+Wdate-time
+Fortran
+; Documented in C
+
 Wcharacter-truncation
 Fortran Warning
 Warn about truncated character expressions
@@ -517,6 +521,10 @@ fopenmp
 Fortran
 ; Documented in C
 
+fopenmp-simd
+Fortran
+; Documented in C
+
 fpack-derived
 Fortran
 Try to lay out derived types as compactly as possible
index 6e4e7c11696718e1ef3132973454267688eedfb1..e05528a922311b4d88e215f109d41c34e30ffc4b 100644 (file)
@@ -836,6 +836,10 @@ gfc_handle_option (size_t scode, const char *arg, int value,
       gfc_option.gfc_flag_openmp = value;
       break;
 
+    case OPT_fopenmp_simd:
+      gfc_option.gfc_flag_openmp_simd = value;
+      break;
+
     case OPT_ffree_line_length_none:
       gfc_option.free_line_length = 0;
       break;
index c38a79ada77e723f62853de7c1c17cc0ee86b290..59434bdb1b2d9042d3b8853982dbf4868b381fde 100644 (file)
@@ -737,7 +737,6 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
     gfc_add_modify (&parmse->post, vptr,
                    fold_convert (TREE_TYPE (vptr), ctree));
 
-  gcc_assert (!optional || (optional && !copyback));
   if (optional)
     {
       tree tmp2;
@@ -7771,7 +7770,7 @@ is_runtime_conformable (gfc_expr *expr1, gfc_expr *expr2)
              e1 = a->expr;
              if (e1->rank > 0 && !is_runtime_conformable (expr1, e1))
                return false;
-           }    
+           }
          return true;
        }
       else if (expr2->value.function.isym
index fd5642209d215b27b71c1236d778faa2e485bdd3..1b500b51d31c66149d6413ff95fdea3673109be3 100644 (file)
@@ -243,16 +243,16 @@ gfc_trans_io_runtime_check (tree cond, tree var, int error_code,
 
   /* The code to generate the error.  */
   gfc_start_block (&block);
-  
+
   arg1 = gfc_build_addr_expr (NULL_TREE, var);
-  
+
   arg2 = build_int_cst (integer_type_node, error_code),
-  
+
   asprintf (&message, "%s", _(msgid));
   arg3 = gfc_build_addr_expr (pchar_type_node,
                              gfc_build_localized_cstring_const (message));
   free (message);
-  
+
   tmp = build_call_expr_loc (input_location,
                         gfor_fndecl_generate_error, 3, arg1, arg2, arg3);
 
@@ -521,7 +521,7 @@ set_parameter_value (stmtblock_t *block, tree var, enum iofield type,
       gfc_trans_io_runtime_check (cond, var, LIBERROR_BAD_UNIT,
                               "Unit number in I/O statement too small",
                               &se.pre);
-    
+
       /* UNIT numbers should be less than the max.  */
       val = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].huge, 4);
       cond = fold_build2_loc (input_location, GT_EXPR, boolean_type_node,
@@ -1000,7 +1000,7 @@ gfc_trans_open (gfc_code * code)
   if (p->convert)
     mask |= set_string (&block, &post_block, var, IOPARM_open_convert,
                        p->convert);
-                       
+
   if (p->newunit)
     mask |= set_parameter_ref (&block, &post_block, var, IOPARM_open_newunit,
                               p->newunit);
@@ -1234,7 +1234,7 @@ gfc_trans_inquire (gfc_code * code)
     {
       mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_exist,
                                 p->exist);
-    
+
       if (p->unit && !p->iostat)
        {
          p->iostat = create_dummy_iostat ();
@@ -1322,7 +1322,7 @@ gfc_trans_inquire (gfc_code * code)
   if (p->pad)
     mask |= set_string (&block, &post_block, var, IOPARM_inquire_pad,
                        p->pad);
-  
+
   if (p->convert)
     mask |= set_string (&block, &post_block, var, IOPARM_inquire_convert,
                        p->convert);
@@ -1547,7 +1547,7 @@ transfer_namelist_element (stmtblock_t * block, const char * var_name,
   tree dtype;
   tree dt_parm_addr;
   tree decl = NULL_TREE;
-  int n_dim; 
+  int n_dim;
   int itype;
   int rank = 0;
 
@@ -2029,7 +2029,7 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr, gfc_code * code)
       ts->type = BT_INTEGER;
       ts->kind = gfc_index_integer_kind;
     }
-  
+
   kind = ts->kind;
   function = NULL;
   arg2 = NULL;
@@ -2111,7 +2111,7 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr, gfc_code * code)
            function = iocall[IOCALL_X_CHARACTER_WIDE];
          else
            function = iocall[IOCALL_X_CHARACTER_WIDE_WRITE];
-           
+
          tmp = gfc_build_addr_expr (NULL_TREE, dt_parm);
          tmp = build_call_expr_loc (input_location,
                                 function, 4, tmp, addr_expr, arg2, arg3);
@@ -2146,6 +2146,12 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr, gfc_code * code)
       expr = build_fold_indirect_ref_loc (input_location,
                                      expr);
 
+      /* Make sure that the derived type has been built.  An external
+        function, if only referenced in an io statement, requires this
+        check (see PR58771).  */
+      if (ts->u.derived->backend_decl == NULL_TREE)
+       tmp = gfc_typenode_for_spec (ts);
+
       for (c = ts->u.derived->components; c; c = c->next)
        {
          field = c->backend_decl;
index 9fb554c628e4d7f601bbc16f73c570599f3ebe18..0a588226f6439fd63320c16cf6d13b9259d7931a 100644 (file)
@@ -774,7 +774,7 @@ declarator (type_p ty, const char **namep, options_p *optsp,
    (
    type bitfield ';'
    | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
-   )+
+   )*
 
    Knows that such declarations must end with a close brace (or,
    erroneously, at EOF).
@@ -788,7 +788,7 @@ struct_field_seq (void)
   const char *name;
   bool another;
 
-  do
+  while (token () != '}' && token () != EOF_TOKEN)
     {
       ty = type (&opts, true);
 
@@ -831,7 +831,6 @@ struct_field_seq (void)
        }
       while (another);
     }
-  while (token () != '}' && token () != EOF_TOKEN);
   return nreverse_pairs (f);
 }
 
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
new file mode 100644 (file)
index 0000000..c74d929
--- /dev/null
@@ -0,0 +1,721 @@
+/* Gimple decl, type, and expression support functions.
+
+   Copyright (C) 2007-2013 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "gimple.h"
+#include "demangle.h"
+
+/* ----- Type related -----  */
+
+/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
+   useless type conversion, otherwise return false.
+
+   This function implicitly defines the middle-end type system.  With
+   the notion of 'a < b' meaning that useless_type_conversion_p (a, b)
+   holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds,
+   the following invariants shall be fulfilled:
+
+     1) useless_type_conversion_p is transitive.
+       If a < b and b < c then a < c.
+
+     2) useless_type_conversion_p is not symmetric.
+       From a < b does not follow a > b.
+
+     3) Types define the available set of operations applicable to values.
+       A type conversion is useless if the operations for the target type
+       is a subset of the operations for the source type.  For example
+       casts to void* are useless, casts from void* are not (void* can't
+       be dereferenced or offsetted, but copied, hence its set of operations
+       is a strict subset of that of all other data pointer types).  Casts
+       to const T* are useless (can't be written to), casts from const T*
+       to T* are not.  */
+
+bool
+useless_type_conversion_p (tree outer_type, tree inner_type)
+{
+  /* Do the following before stripping toplevel qualifiers.  */
+  if (POINTER_TYPE_P (inner_type)
+      && POINTER_TYPE_P (outer_type))
+    {
+      /* Do not lose casts between pointers to different address spaces.  */
+      if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
+         != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
+       return false;
+    }
+
+  /* From now on qualifiers on value types do not matter.  */
+  inner_type = TYPE_MAIN_VARIANT (inner_type);
+  outer_type = TYPE_MAIN_VARIANT (outer_type);
+
+  if (inner_type == outer_type)
+    return true;
+
+  /* If we know the canonical types, compare them.  */
+  if (TYPE_CANONICAL (inner_type)
+      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
+    return true;
+
+  /* Changes in machine mode are never useless conversions unless we
+     deal with aggregate types in which case we defer to later checks.  */
+  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
+      && !AGGREGATE_TYPE_P (inner_type))
+    return false;
+
+  /* If both the inner and outer types are integral types, then the
+     conversion is not necessary if they have the same mode and
+     signedness and precision, and both or neither are boolean.  */
+  if (INTEGRAL_TYPE_P (inner_type)
+      && INTEGRAL_TYPE_P (outer_type))
+    {
+      /* Preserve changes in signedness or precision.  */
+      if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
+         || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+       return false;
+
+      /* Preserve conversions to/from BOOLEAN_TYPE if types are not
+        of precision one.  */
+      if (((TREE_CODE (inner_type) == BOOLEAN_TYPE)
+          != (TREE_CODE (outer_type) == BOOLEAN_TYPE))
+         && TYPE_PRECISION (outer_type) != 1)
+       return false;
+
+      /* We don't need to preserve changes in the types minimum or
+        maximum value in general as these do not generate code
+        unless the types precisions are different.  */
+      return true;
+    }
+
+  /* Scalar floating point types with the same mode are compatible.  */
+  else if (SCALAR_FLOAT_TYPE_P (inner_type)
+          && SCALAR_FLOAT_TYPE_P (outer_type))
+    return true;
+
+  /* Fixed point types with the same mode are compatible.  */
+  else if (FIXED_POINT_TYPE_P (inner_type)
+          && FIXED_POINT_TYPE_P (outer_type))
+    return true;
+
+  /* We need to take special care recursing to pointed-to types.  */
+  else if (POINTER_TYPE_P (inner_type)
+          && POINTER_TYPE_P (outer_type))
+    {
+      /* Do not lose casts to function pointer types.  */
+      if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
+          || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
+         && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
+              || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
+       return false;
+
+      /* We do not care for const qualification of the pointed-to types
+        as const qualification has no semantic value to the middle-end.  */
+
+      /* Otherwise pointers/references are equivalent.  */
+      return true;
+    }
+
+  /* Recurse for complex types.  */
+  else if (TREE_CODE (inner_type) == COMPLEX_TYPE
+          && TREE_CODE (outer_type) == COMPLEX_TYPE)
+    return useless_type_conversion_p (TREE_TYPE (outer_type),
+                                     TREE_TYPE (inner_type));
+
+  /* Recurse for vector types with the same number of subparts.  */
+  else if (TREE_CODE (inner_type) == VECTOR_TYPE
+          && TREE_CODE (outer_type) == VECTOR_TYPE
+          && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
+    return useless_type_conversion_p (TREE_TYPE (outer_type),
+                                     TREE_TYPE (inner_type));
+
+  else if (TREE_CODE (inner_type) == ARRAY_TYPE
+          && TREE_CODE (outer_type) == ARRAY_TYPE)
+    {
+      /* Preserve string attributes.  */
+      if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type))
+       return false;
+
+      /* Conversions from array types with unknown extent to
+        array types with known extent are not useless.  */
+      if (!TYPE_DOMAIN (inner_type)
+         && TYPE_DOMAIN (outer_type))
+       return false;
+
+      /* Nor are conversions from array types with non-constant size to
+         array types with constant size or to different size.  */
+      if (TYPE_SIZE (outer_type)
+         && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST
+         && (!TYPE_SIZE (inner_type)
+             || TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST
+             || !tree_int_cst_equal (TYPE_SIZE (outer_type),
+                                     TYPE_SIZE (inner_type))))
+       return false;
+
+      /* Check conversions between arrays with partially known extents.
+        If the array min/max values are constant they have to match.
+        Otherwise allow conversions to unknown and variable extents.
+        In particular this declares conversions that may change the
+        mode to BLKmode as useless.  */
+      if (TYPE_DOMAIN (inner_type)
+         && TYPE_DOMAIN (outer_type)
+         && TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type))
+       {
+         tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type));
+         tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type));
+         tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type));
+         tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type));
+
+         /* After gimplification a variable min/max value carries no
+            additional information compared to a NULL value.  All that
+            matters has been lowered to be part of the IL.  */
+         if (inner_min && TREE_CODE (inner_min) != INTEGER_CST)
+           inner_min = NULL_TREE;
+         if (outer_min && TREE_CODE (outer_min) != INTEGER_CST)
+           outer_min = NULL_TREE;
+         if (inner_max && TREE_CODE (inner_max) != INTEGER_CST)
+           inner_max = NULL_TREE;
+         if (outer_max && TREE_CODE (outer_max) != INTEGER_CST)
+           outer_max = NULL_TREE;
+
+         /* Conversions NULL / variable <- cst are useless, but not
+            the other way around.  */
+         if (outer_min
+             && (!inner_min
+                 || !tree_int_cst_equal (inner_min, outer_min)))
+           return false;
+         if (outer_max
+             && (!inner_max
+                 || !tree_int_cst_equal (inner_max, outer_max)))
+           return false;
+       }
+
+      /* Recurse on the element check.  */
+      return useless_type_conversion_p (TREE_TYPE (outer_type),
+                                       TREE_TYPE (inner_type));
+    }
+
+  else if ((TREE_CODE (inner_type) == FUNCTION_TYPE
+           || TREE_CODE (inner_type) == METHOD_TYPE)
+          && TREE_CODE (inner_type) == TREE_CODE (outer_type))
+    {
+      tree outer_parm, inner_parm;
+
+      /* If the return types are not compatible bail out.  */
+      if (!useless_type_conversion_p (TREE_TYPE (outer_type),
+                                     TREE_TYPE (inner_type)))
+       return false;
+
+      /* Method types should belong to a compatible base class.  */
+      if (TREE_CODE (inner_type) == METHOD_TYPE
+         && !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type),
+                                        TYPE_METHOD_BASETYPE (inner_type)))
+       return false;
+
+      /* A conversion to an unprototyped argument list is ok.  */
+      if (!prototype_p (outer_type))
+       return true;
+
+      /* If the unqualified argument types are compatible the conversion
+        is useless.  */
+      if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type))
+       return true;
+
+      for (outer_parm = TYPE_ARG_TYPES (outer_type),
+          inner_parm = TYPE_ARG_TYPES (inner_type);
+          outer_parm && inner_parm;
+          outer_parm = TREE_CHAIN (outer_parm),
+          inner_parm = TREE_CHAIN (inner_parm))
+       if (!useless_type_conversion_p
+              (TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)),
+               TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm))))
+         return false;
+
+      /* If there is a mismatch in the number of arguments the functions
+        are not compatible.  */
+      if (outer_parm || inner_parm)
+       return false;
+
+      /* Defer to the target if necessary.  */
+      if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type))
+       return comp_type_attributes (outer_type, inner_type) != 0;
+
+      return true;
+    }
+
+  /* For aggregates we rely on TYPE_CANONICAL exclusively and require
+     explicit conversions for types involving to be structurally
+     compared types.  */
+  else if (AGGREGATE_TYPE_P (inner_type)
+          && TREE_CODE (inner_type) == TREE_CODE (outer_type))
+    return false;
+
+  return false;
+}
+
+
+/* ----- Decl related -----  */
+
+/* Set sequence SEQ to be the GIMPLE body for function FN.  */
+
+void
+gimple_set_body (tree fndecl, gimple_seq seq)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+  if (fn == NULL)
+    {
+      /* If FNDECL still does not have a function structure associated
+        with it, then it does not make sense for it to receive a
+        GIMPLE body.  */
+      gcc_assert (seq == NULL);
+    }
+  else
+    fn->gimple_body = seq;
+}
+
+
+/* Return the body of GIMPLE statements for function FN.  After the
+   CFG pass, the function body doesn't exist anymore because it has
+   been split up into basic blocks.  In this case, it returns
+   NULL.  */
+
+gimple_seq
+gimple_body (tree fndecl)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+  return fn ? fn->gimple_body : NULL;
+}
+
+/* Return true when FNDECL has Gimple body either in unlowered
+   or CFG form.  */
+bool
+gimple_has_body_p (tree fndecl)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+  return (gimple_body (fndecl) || (fn && fn->cfg));
+}
+
+/* Return a printable name for symbol DECL.  */
+
+const char *
+gimple_decl_printable_name (tree decl, int verbosity)
+{
+  if (!DECL_NAME (decl))
+    return NULL;
+
+  if (DECL_ASSEMBLER_NAME_SET_P (decl))
+    {
+      const char *str, *mangled_str;
+      int dmgl_opts = DMGL_NO_OPTS;
+
+      if (verbosity >= 2)
+       {
+         dmgl_opts = DMGL_VERBOSE
+                     | DMGL_ANSI
+                     | DMGL_GNU_V3
+                     | DMGL_RET_POSTFIX;
+         if (TREE_CODE (decl) == FUNCTION_DECL)
+           dmgl_opts |= DMGL_PARAMS;
+       }
+
+      mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      str = cplus_demangle_v3 (mangled_str, dmgl_opts);
+      return (str) ? str : mangled_str;
+    }
+
+  return IDENTIFIER_POINTER (DECL_NAME (decl));
+}
+
+
+/* Create a new VAR_DECL and copy information from VAR to it.  */
+
+tree
+copy_var_decl (tree var, tree name, tree type)
+{
+  tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type);
+
+  TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
+  TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
+  DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
+  DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
+  DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
+  DECL_CONTEXT (copy) = DECL_CONTEXT (var);
+  TREE_NO_WARNING (copy) = TREE_NO_WARNING (var);
+  TREE_USED (copy) = 1;
+  DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
+  DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var);
+
+  return copy;
+}
+
+/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for
+   coalescing together, false otherwise.
+
+   This must stay consistent with var_map_base_init in tree-ssa-live.c.  */
+
+bool
+gimple_can_coalesce_p (tree name1, tree name2)
+{
+  /* First check the SSA_NAME's associated DECL.  We only want to
+     coalesce if they have the same DECL or both have no associated DECL.  */
+  tree var1 = SSA_NAME_VAR (name1);
+  tree var2 = SSA_NAME_VAR (name2);
+  var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE;
+  var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE;
+  if (var1 != var2)
+    return false;
+
+  /* Now check the types.  If the types are the same, then we should
+     try to coalesce V1 and V2.  */
+  tree t1 = TREE_TYPE (name1);
+  tree t2 = TREE_TYPE (name2);
+  if (t1 == t2)
+    return true;
+
+  /* If the types are not the same, check for a canonical type match.  This
+     (for example) allows coalescing when the types are fundamentally the
+     same, but just have different names. 
+
+     Note pointer types with different address spaces may have the same
+     canonical type.  Those are rejected for coalescing by the
+     types_compatible_p check.  */
+  if (TYPE_CANONICAL (t1)
+      && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)
+      && types_compatible_p (t1, t2))
+    return true;
+
+  return false;
+}
+
+
+/* ----- Expression related -----  */
+
+/* Extract the operands and code for expression EXPR into *SUBCODE_P,
+   *OP1_P, *OP2_P and *OP3_P respectively.  */
+
+void
+extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p,
+                        tree *op2_p, tree *op3_p)
+{
+  enum gimple_rhs_class grhs_class;
+
+  *subcode_p = TREE_CODE (expr);
+  grhs_class = get_gimple_rhs_class (*subcode_p);
+
+  if (grhs_class == GIMPLE_TERNARY_RHS)
+    {
+      *op1_p = TREE_OPERAND (expr, 0);
+      *op2_p = TREE_OPERAND (expr, 1);
+      *op3_p = TREE_OPERAND (expr, 2);
+    }
+  else if (grhs_class == GIMPLE_BINARY_RHS)
+    {
+      *op1_p = TREE_OPERAND (expr, 0);
+      *op2_p = TREE_OPERAND (expr, 1);
+      *op3_p = NULL_TREE;
+    }
+  else if (grhs_class == GIMPLE_UNARY_RHS)
+    {
+      *op1_p = TREE_OPERAND (expr, 0);
+      *op2_p = NULL_TREE;
+      *op3_p = NULL_TREE;
+    }
+  else if (grhs_class == GIMPLE_SINGLE_RHS)
+    {
+      *op1_p = expr;
+      *op2_p = NULL_TREE;
+      *op3_p = NULL_TREE;
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND.  */
+
+void
+gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
+                               tree *lhs_p, tree *rhs_p)
+{
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
+             || TREE_CODE (cond) == TRUTH_NOT_EXPR
+             || is_gimple_min_invariant (cond)
+             || SSA_VAR_P (cond));
+
+  extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
+
+  /* Canonicalize conditionals of the form 'if (!VAL)'.  */
+  if (*code_p == TRUTH_NOT_EXPR)
+    {
+      *code_p = EQ_EXPR;
+      gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
+      *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
+    }
+  /* Canonicalize conditionals of the form 'if (VAL)'  */
+  else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
+    {
+      *code_p = NE_EXPR;
+      gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
+      *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
+    }
+}
+
+/*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
+
+bool
+is_gimple_lvalue (tree t)
+{
+  return (is_gimple_addressable (t)
+         || TREE_CODE (t) == WITH_SIZE_EXPR
+         /* These are complex lvalues, but don't have addresses, so they
+            go here.  */
+         || TREE_CODE (t) == BIT_FIELD_REF);
+}
+
+/*  Return true if T is a GIMPLE condition.  */
+
+bool
+is_gimple_condexpr (tree t)
+{
+  return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
+                               && !tree_could_throw_p (t)
+                               && is_gimple_val (TREE_OPERAND (t, 0))
+                               && is_gimple_val (TREE_OPERAND (t, 1))));
+}
+
+/* Return true if T is a gimple address.  */
+
+bool
+is_gimple_address (const_tree t)
+{
+  tree op;
+
+  if (TREE_CODE (t) != ADDR_EXPR)
+    return false;
+
+  op = TREE_OPERAND (t, 0);
+  while (handled_component_p (op))
+    {
+      if ((TREE_CODE (op) == ARRAY_REF
+          || TREE_CODE (op) == ARRAY_RANGE_REF)
+         && !is_gimple_val (TREE_OPERAND (op, 1)))
+           return false;
+
+      op = TREE_OPERAND (op, 0);
+    }
+
+  if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF)
+    return true;
+
+  switch (TREE_CODE (op))
+    {
+    case PARM_DECL:
+    case RESULT_DECL:
+    case LABEL_DECL:
+    case FUNCTION_DECL:
+    case VAR_DECL:
+    case CONST_DECL:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Return true if T is a gimple invariant address.  */
+
+bool
+is_gimple_invariant_address (const_tree t)
+{
+  const_tree op;
+
+  if (TREE_CODE (t) != ADDR_EXPR)
+    return false;
+
+  op = strip_invariant_refs (TREE_OPERAND (t, 0));
+  if (!op)
+    return false;
+
+  if (TREE_CODE (op) == MEM_REF)
+    {
+      const_tree op0 = TREE_OPERAND (op, 0);
+      return (TREE_CODE (op0) == ADDR_EXPR
+             && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
+                 || decl_address_invariant_p (TREE_OPERAND (op0, 0))));
+    }
+
+  return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
+}
+
+/* Return true if T is a gimple invariant address at IPA level
+   (so addresses of variables on stack are not allowed).  */
+
+bool
+is_gimple_ip_invariant_address (const_tree t)
+{
+  const_tree op;
+
+  if (TREE_CODE (t) != ADDR_EXPR)
+    return false;
+
+  op = strip_invariant_refs (TREE_OPERAND (t, 0));
+  if (!op)
+    return false;
+
+  if (TREE_CODE (op) == MEM_REF)
+    {
+      const_tree op0 = TREE_OPERAND (op, 0);
+      return (TREE_CODE (op0) == ADDR_EXPR
+             && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
+                 || decl_address_ip_invariant_p (TREE_OPERAND (op0, 0))));
+    }
+
+  return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
+}
+
+/* Return true if T is a GIMPLE minimal invariant.  It's a restricted
+   form of function invariant.  */
+
+bool
+is_gimple_min_invariant (const_tree t)
+{
+  if (TREE_CODE (t) == ADDR_EXPR)
+    return is_gimple_invariant_address (t);
+
+  return is_gimple_constant (t);
+}
+
+/* Return true if T is a GIMPLE interprocedural invariant.  It's a restricted
+   form of gimple minimal invariant.  */
+
+bool
+is_gimple_ip_invariant (const_tree t)
+{
+  if (TREE_CODE (t) == ADDR_EXPR)
+    return is_gimple_ip_invariant_address (t);
+
+  return is_gimple_constant (t);
+}
+
+/* Return true if T is a non-aggregate register variable.  */
+
+bool
+is_gimple_reg (tree t)
+{
+  if (virtual_operand_p (t))
+    return false;
+
+  if (TREE_CODE (t) == SSA_NAME)
+    return true;
+
+  if (!is_gimple_variable (t))
+    return false;
+
+  if (!is_gimple_reg_type (TREE_TYPE (t)))
+    return false;
+
+  /* A volatile decl is not acceptable because we can't reuse it as
+     needed.  We need to copy it into a temp first.  */
+  if (TREE_THIS_VOLATILE (t))
+    return false;
+
+  /* We define "registers" as things that can be renamed as needed,
+     which with our infrastructure does not apply to memory.  */
+  if (needs_to_live_in_memory (t))
+    return false;
+
+  /* Hard register variables are an interesting case.  For those that
+     are call-clobbered, we don't know where all the calls are, since
+     we don't (want to) take into account which operations will turn
+     into libcalls at the rtl level.  For those that are call-saved,
+     we don't currently model the fact that calls may in fact change
+     global hard registers, nor do we examine ASM_CLOBBERS at the tree
+     level, and so miss variable changes that might imply.  All around,
+     it seems safest to not do too much optimization with these at the
+     tree level at all.  We'll have to rely on the rtl optimizers to
+     clean this up, as there we've got all the appropriate bits exposed.  */
+  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+    return false;
+
+  /* Complex and vector values must have been put into SSA-like form.
+     That is, no assignments to the individual components.  */
+  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+    return DECL_GIMPLE_REG_P (t);
+
+  return true;
+}
+
+
+/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
+
+bool
+is_gimple_val (tree t)
+{
+  /* Make loads from volatiles and memory vars explicit.  */
+  if (is_gimple_variable (t)
+      && is_gimple_reg_type (TREE_TYPE (t))
+      && !is_gimple_reg (t))
+    return false;
+
+  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
+}
+
+/* Similarly, but accept hard registers as inputs to asm statements.  */
+
+bool
+is_gimple_asm_val (tree t)
+{
+  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+    return true;
+
+  return is_gimple_val (t);
+}
+
+/* Return true if T is a GIMPLE minimal lvalue.  */
+
+bool
+is_gimple_min_lval (tree t)
+{
+  if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
+    return false;
+  return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF);
+}
+
+/* Return true if T is a valid function operand of a CALL_EXPR.  */
+
+bool
+is_gimple_call_addr (tree t)
+{
+  return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
+}
+
+/* Return true if T is a valid address operand of a MEM_REF.  */
+
+bool
+is_gimple_mem_ref_addr (tree t)
+{
+  return (is_gimple_reg (t)
+         || TREE_CODE (t) == INTEGER_CST
+         || (TREE_CODE (t) == ADDR_EXPR
+             && (CONSTANT_CLASS_P (TREE_OPERAND (t, 0))
+                 || decl_address_invariant_p (TREE_OPERAND (t, 0)))));
+}
diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h
new file mode 100644 (file)
index 0000000..aad558c
--- /dev/null
@@ -0,0 +1,171 @@
+/* Header file for gimple decl, type and expressions.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_GIMPLE_EXPR_H
+#define GCC_GIMPLE_EXPR_H
+
+extern bool useless_type_conversion_p (tree, tree);
+
+extern void gimple_set_body (tree, gimple_seq);
+extern gimple_seq gimple_body (tree);
+extern bool gimple_has_body_p (tree);
+extern const char *gimple_decl_printable_name (tree, int);
+extern tree copy_var_decl (tree, tree, tree);
+extern bool gimple_can_coalesce_p (tree, tree);
+
+extern void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *,
+                                    tree *);
+extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *,
+                                          tree *);
+extern bool is_gimple_lvalue (tree);
+extern bool is_gimple_condexpr (tree);
+extern bool is_gimple_address (const_tree);
+extern bool is_gimple_invariant_address (const_tree);
+extern bool is_gimple_ip_invariant_address (const_tree);
+extern bool is_gimple_min_invariant (const_tree);
+extern bool is_gimple_ip_invariant (const_tree);
+extern bool is_gimple_reg (tree);
+extern bool is_gimple_val (tree);
+extern bool is_gimple_asm_val (tree);
+extern bool is_gimple_min_lval (tree);
+extern bool is_gimple_call_addr (tree);
+extern bool is_gimple_mem_ref_addr (tree);
+
+/* Return true if a conversion from either type of TYPE1 and TYPE2
+   to the other is not required.  Otherwise return false.  */
+
+static inline bool
+types_compatible_p (tree type1, tree type2)
+{
+  return (type1 == type2
+         || (useless_type_conversion_p (type1, type2)
+             && useless_type_conversion_p (type2, type1)));
+}
+
+/* Return true if TYPE is a suitable type for a scalar register variable.  */
+
+static inline bool
+is_gimple_reg_type (tree type)
+{
+  return !AGGREGATE_TYPE_P (type);
+}
+
+/* Return true if T is a variable.  */
+
+static inline bool
+is_gimple_variable (tree t)
+{
+  return (TREE_CODE (t) == VAR_DECL
+         || TREE_CODE (t) == PARM_DECL
+         || TREE_CODE (t) == RESULT_DECL
+         || TREE_CODE (t) == SSA_NAME);
+}
+
+/*  Return true if T is a GIMPLE identifier (something with an address).  */
+
+static inline bool
+is_gimple_id (tree t)
+{
+  return (is_gimple_variable (t)
+         || TREE_CODE (t) == FUNCTION_DECL
+         || TREE_CODE (t) == LABEL_DECL
+         || TREE_CODE (t) == CONST_DECL
+         /* Allow string constants, since they are addressable.  */
+         || TREE_CODE (t) == STRING_CST);
+}
+
+/* Return true if OP, an SSA name or a DECL is a virtual operand.  */
+
+static inline bool
+virtual_operand_p (tree op)
+{
+  if (TREE_CODE (op) == SSA_NAME)
+    {
+      op = SSA_NAME_VAR (op);
+      if (!op)
+       return false;
+    }
+
+  if (TREE_CODE (op) == VAR_DECL)
+    return VAR_DECL_IS_VIRTUAL_OPERAND (op);
+
+  return false;
+}
+
+/*  Return true if T is something whose address can be taken.  */
+
+static inline bool
+is_gimple_addressable (tree t)
+{
+  return (is_gimple_id (t) || handled_component_p (t)
+         || TREE_CODE (t) == MEM_REF);
+}
+
+/* Return true if T is a valid gimple constant.  */
+
+static inline bool
+is_gimple_constant (const_tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case STRING_CST:
+    case COMPLEX_CST:
+    case VECTOR_CST:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* A wrapper around extract_ops_from_tree_1, for callers which expect
+   to see only a maximum of two operands.  */
+
+static inline void
+extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0,
+                      tree *op1)
+{
+  tree op2;
+  extract_ops_from_tree_1 (expr, code, op0, op1, &op2);
+  gcc_assert (op2 == NULL_TREE);
+}
+
+/* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL
+   associated with the callee if known.  Otherwise return NULL_TREE.  */
+
+static inline tree
+gimple_call_addr_fndecl (const_tree fn)
+{
+  if (fn && TREE_CODE (fn) == ADDR_EXPR)
+    {
+      tree fndecl = TREE_OPERAND (fn, 0);
+      if (TREE_CODE (fndecl) == MEM_REF
+         && TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR
+         && integer_zerop (TREE_OPERAND (fndecl, 1)))
+       fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0);
+      if (TREE_CODE (fndecl) == FUNCTION_DECL)
+       return fndecl;
+    }
+  return NULL_TREE;
+}
+
+#endif /* GCC_GIMPLE_EXPR_H */
diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c
new file mode 100644 (file)
index 0000000..4868867
--- /dev/null
@@ -0,0 +1,325 @@
+/* Detect paths through the CFG which can never be executed in a conforming
+   program and isolate them.
+
+   Copyright (C) 2013
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "flags.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "tree-ssa.h"
+#include "tree-ssanames.h"
+#include "gimple-ssa.h"
+#include "tree-ssa-operands.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "cfgloop.h"
+#include "tree-pass.h"
+
+
+static bool cfg_altered;
+
+/* Insert a trap before SI and remove SI and all statements after SI.  */
+
+static void
+insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p)
+{
+  gimple_seq seq = NULL;
+  gimple stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  gimple_seq_add_stmt (&seq, stmt);
+  gsi_insert_before (si_p, seq, GSI_SAME_STMT);
+
+  /* Now delete all remaining statements in this block.  */
+  for (; !gsi_end_p (*si_p);)
+    {
+      stmt = gsi_stmt (*si_p);
+      unlink_stmt_vdef (stmt);
+      gsi_remove (si_p, true);
+      release_defs (stmt);
+    }
+}
+
+/* BB when reached via incoming edge E will exhibit undefined behaviour
+   at STMT.  Isolate and optimize the path which exhibits undefined
+   behaviour.
+
+   Isolation is simple.  Duplicate BB and redirect E to BB'.
+
+   Optimization is simple as well.  Replace STMT in BB' with an
+   unconditional trap and remove all outgoing edges from BB'.
+
+   DUPLICATE is a pre-existing duplicate, use it as BB' if it exists.
+
+   Return BB'.  */
+
+basic_block
+isolate_path (basic_block bb, basic_block duplicate, edge e, gimple stmt)
+{
+  gimple_stmt_iterator si, si2;
+  edge_iterator ei;
+  edge e2;
+  
+
+  /* First duplicate BB if we have not done so already and remove all
+     the duplicate's outgoing edges as duplicate is going to unconditionally
+     trap.  Removing the outgoing edges is both an optimization and ensures
+     we don't need to do any PHI node updates.  */
+  if (!duplicate)
+    {
+      duplicate = duplicate_block (bb, NULL, NULL);
+      for (ei = ei_start (duplicate->succs); (e2 = ei_safe_edge (ei)); )
+       remove_edge (e2);
+    }
+
+  /* Complete the isolation step by redirecting E to reach DUPLICATE.  */
+  e2 = redirect_edge_and_branch (e, duplicate);
+  if (e2)
+    flush_pending_stmts (e2);
+
+
+  /* There may be more than one statement in DUPLICATE which exhibits
+     undefined behaviour.  Ultimately we want the first such statement in
+     DUPLCIATE so that we're able to delete as much code as possible.
+
+     So each time we discover undefined behaviour in DUPLICATE, search for
+     the statement which triggers undefined behaviour.  If found, then
+     transform the statement into a trap and delete everything after the
+     statement.  If not found, then this particular instance was subsumed by
+     an earlier instance of undefined behaviour and there's nothing to do. 
+
+     This is made more complicated by the fact that we have STMT, which is in
+     BB rather than in DUPLICATE.  So we set up two iterators, one for each
+     block and walk forward looking for STMT in BB, advancing each iterator at
+     each step.
+
+     When we find STMT the second iterator should point to STMT's equivalent in
+     duplicate.  If DUPLICATE ends before STMT is found in BB, then there's
+     nothing to do. 
+
+     Ignore labels and debug statements.  */
+  si = gsi_start_nondebug_after_labels_bb (bb);
+  si2 = gsi_start_nondebug_after_labels_bb (duplicate);
+  while (!gsi_end_p (si) && !gsi_end_p (si2) && gsi_stmt (si) != stmt)
+    {
+      gsi_next_nondebug (&si);
+      gsi_next_nondebug (&si2);
+    }
+
+  /* This would be an indicator that we never found STMT in BB, which should
+     never happen.  */
+  gcc_assert (!gsi_end_p (si));
+
+  /* If we did not run to the end of DUPLICATE, then SI points to STMT and
+     SI2 points to the duplicate of STMT in DUPLICATE.  Insert a trap
+     before SI2 and remove SI2 and all trailing statements.  */
+  if (!gsi_end_p (si2))
+    insert_trap_and_remove_trailing_statements (&si2);
+
+  return duplicate;
+}
+
+/* Search the function for statements which, if executed, would cause
+   the program to fault such as a dereference of a NULL pointer.
+
+   Such a program can't be valid if such a statement was to execute
+   according to ISO standards.
+
+   We detect explicit NULL pointer dereferences as well as those implied
+   by a PHI argument having a NULL value which unconditionally flows into
+   a dereference in the same block as the PHI.
+
+   In the former case we replace the offending statement with an
+   unconditional trap and eliminate the outgoing edges from the statement's
+   basic block.  This may expose secondary optimization opportunities.
+
+   In the latter case, we isolate the path(s) with the NULL PHI 
+   feeding the dereference.  We can then replace the offending statement
+   and eliminate the outgoing edges in the duplicate.  Again, this may
+   expose secondary optimization opportunities.
+
+   A warning for both cases may be advisable as well.
+
+   Other statically detectable violations of the ISO standard could be
+   handled in a similar way, such as out-of-bounds array indexing.  */
+
+static unsigned int
+gimple_ssa_isolate_erroneous_paths (void)
+{
+  basic_block bb;
+
+  initialize_original_copy_tables ();
+
+  /* Search all the blocks for edges which, if traversed, will
+     result in undefined behaviour.  */
+  cfg_altered = false;
+  FOR_EACH_BB (bb)
+    {
+      gimple_stmt_iterator si;
+
+      /* First look for a PHI which sets a pointer to NULL and which
+        is then dereferenced within BB.  This is somewhat overly
+        conservative, but probably catches most of the interesting
+        cases.   */
+      for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
+       {
+         gimple phi = gsi_stmt (si);
+         tree lhs = gimple_phi_result (phi);
+
+         /* If the result is not a pointer, then there is no need to
+            examine the arguments.  */
+         if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
+           continue;
+
+         /* PHI produces a pointer result.  See if any of the PHI's
+            arguments are NULL. 
+
+            When we remove an edge, we want to reprocess the current
+            index, hence the ugly way we update I for each iteration.  */
+         basic_block duplicate = NULL;
+         for (unsigned i = 0, next_i = 0;
+              i < gimple_phi_num_args (phi);
+              i = next_i)
+           {
+             tree op = gimple_phi_arg_def (phi, i);
+
+             next_i = i + 1;
+       
+             if (!integer_zerop (op))
+               continue;
+
+             edge e = gimple_phi_arg_edge (phi, i);
+             imm_use_iterator iter;
+             gimple use_stmt;
+
+             /* We've got a NULL PHI argument.  Now see if the
+                PHI's result is dereferenced within BB.  */
+             FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+               {
+                 /* We only care about uses in BB.  Catching cases in
+                    in other blocks would require more complex path
+                    isolation code.  */
+                 if (gimple_bb (use_stmt) != bb)
+                   continue;
+
+                 if (infer_nonnull_range (use_stmt, lhs))
+                   {
+                     duplicate = isolate_path (bb, duplicate,
+                                               e, use_stmt);
+
+                     /* When we remove an incoming edge, we need to
+                        reprocess the Ith element.  */
+                     next_i = i;
+                     cfg_altered = true;
+                   }
+               }
+           }
+       }
+
+      /* Now look at the statements in the block and see if any of
+        them explicitly dereference a NULL pointer.  This happens
+        because of jump threading and constant propagation.  */
+      for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+       {
+         gimple stmt = gsi_stmt (si);
+
+         /* By passing null_pointer_node, we can use infer_nonnull_range
+            to detect explicit NULL pointer dereferences and other uses
+            where a non-NULL value is required.  */
+         if (infer_nonnull_range (stmt, null_pointer_node))
+           {
+             insert_trap_and_remove_trailing_statements (&si);
+
+             /* And finally, remove all outgoing edges from BB.  */
+             edge e;
+             for (edge_iterator ei = ei_start (bb->succs);
+                  (e = ei_safe_edge (ei)); )
+               remove_edge (e);
+
+             /* Ignore any more operands on this statement and
+                continue the statement iterator (which should
+                terminate its loop immediately.  */
+             cfg_altered = true;
+             break;
+           }
+       }
+    }
+  free_original_copy_tables ();
+
+  /* We scramble the CFG and loop structures a bit, clean up 
+     appropriately.  We really should incrementally update the
+     loop structures, in theory it shouldn't be that hard.  */
+  if (cfg_altered)
+    {
+      free_dominance_info (CDI_DOMINATORS);
+      free_dominance_info (CDI_POST_DOMINATORS);
+      loops_state_set (LOOPS_NEED_FIXUP);
+      return TODO_cleanup_cfg | TODO_update_ssa;
+    }
+  return 0;
+}
+
+static bool
+gate_isolate_erroneous_paths (void)
+{
+  /* If we do not have a suitable builtin function for the trap statement,
+     then do not perform the optimization.  */
+  return (flag_isolate_erroneous_paths != 0
+         && builtin_decl_explicit (BUILT_IN_TRAP) != NULL);
+}
+
+namespace {
+const pass_data pass_data_isolate_erroneous_paths =
+{
+  GIMPLE_PASS, /* type */
+  "isolate-paths", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_ISOLATE_ERRONEOUS_PATHS, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_verify_ssa, /* todo_flags_finish */
+};
+
+class pass_isolate_erroneous_paths : public gimple_opt_pass
+{
+public:
+  pass_isolate_erroneous_paths (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_isolate_erroneous_paths, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_isolate_erroneous_paths (m_ctxt); }
+  bool gate () { return gate_isolate_erroneous_paths (); }
+  unsigned int execute () { return gimple_ssa_isolate_erroneous_paths (); }
+
+}; // class pass_uncprop
+}
+
+gimple_opt_pass *
+make_pass_isolate_erroneous_paths (gcc::context *ctxt)
+{
+  return new pass_isolate_erroneous_paths (ctxt);
+}
index da7be0c4f4e8d1e3214eb699cc89401ff74aa1a5..bd69fa647ec9ce69fa6aee9fb812696d7e669d79 100644 (file)
@@ -386,47 +386,6 @@ gimple_call_get_nobnd_arg_index (const_gimple gs, unsigned index)
 }
 
 
-/* Extract the operands and code for expression EXPR into *SUBCODE_P,
-   *OP1_P, *OP2_P and *OP3_P respectively.  */
-
-void
-extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p,
-                        tree *op2_p, tree *op3_p)
-{
-  enum gimple_rhs_class grhs_class;
-
-  *subcode_p = TREE_CODE (expr);
-  grhs_class = get_gimple_rhs_class (*subcode_p);
-
-  if (grhs_class == GIMPLE_TERNARY_RHS)
-    {
-      *op1_p = TREE_OPERAND (expr, 0);
-      *op2_p = TREE_OPERAND (expr, 1);
-      *op3_p = TREE_OPERAND (expr, 2);
-    }
-  else if (grhs_class == GIMPLE_BINARY_RHS)
-    {
-      *op1_p = TREE_OPERAND (expr, 0);
-      *op2_p = TREE_OPERAND (expr, 1);
-      *op3_p = NULL_TREE;
-    }
-  else if (grhs_class == GIMPLE_UNARY_RHS)
-    {
-      *op1_p = TREE_OPERAND (expr, 0);
-      *op2_p = NULL_TREE;
-      *op3_p = NULL_TREE;
-    }
-  else if (grhs_class == GIMPLE_SINGLE_RHS)
-    {
-      *op1_p = expr;
-      *op2_p = NULL_TREE;
-      *op3_p = NULL_TREE;
-    }
-  else
-    gcc_unreachable ();
-}
-
-
 /* Build a GIMPLE_ASSIGN statement.
 
    LHS of the assignment.
@@ -526,37 +485,6 @@ gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs,
   return p;
 }
 
-
-/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND.  */
-
-void
-gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
-                               tree *lhs_p, tree *rhs_p)
-{
-  gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
-             || TREE_CODE (cond) == TRUTH_NOT_EXPR
-             || is_gimple_min_invariant (cond)
-             || SSA_VAR_P (cond));
-
-  extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
-
-  /* Canonicalize conditionals of the form 'if (!VAL)'.  */
-  if (*code_p == TRUTH_NOT_EXPR)
-    {
-      *code_p = EQ_EXPR;
-      gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
-      *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
-    }
-  /* Canonicalize conditionals of the form 'if (VAL)'  */
-  else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
-    {
-      *code_p = NE_EXPR;
-      gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
-      *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
-    }
-}
-
-
 /* Build a GIMPLE_COND statement from the conditional expression tree
    COND.  T_LABEL and F_LABEL are as in gimple_build_cond.  */
 
@@ -1906,45 +1834,6 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
 }
 
 
-/* Set sequence SEQ to be the GIMPLE body for function FN.  */
-
-void
-gimple_set_body (tree fndecl, gimple_seq seq)
-{
-  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
-  if (fn == NULL)
-    {
-      /* If FNDECL still does not have a function structure associated
-        with it, then it does not make sense for it to receive a
-        GIMPLE body.  */
-      gcc_assert (seq == NULL);
-    }
-  else
-    fn->gimple_body = seq;
-}
-
-
-/* Return the body of GIMPLE statements for function FN.  After the
-   CFG pass, the function body doesn't exist anymore because it has
-   been split up into basic blocks.  In this case, it returns
-   NULL.  */
-
-gimple_seq
-gimple_body (tree fndecl)
-{
-  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
-  return fn ? fn->gimple_body : NULL;
-}
-
-/* Return true when FNDECL has Gimple body either in unlowered
-   or CFG form.  */
-bool
-gimple_has_body_p (tree fndecl)
-{
-  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
-  return (gimple_body (fndecl) || (fn && fn->cfg));
-}
-
 /* Return true if calls C1 and C2 are known to go to the same function.  */
 
 bool
@@ -2602,325 +2491,6 @@ const unsigned char gimple_rhs_class_table[] = {
 #undef DEFTREECODE
 #undef END_OF_BASE_TREE_CODES
 
-/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi.  */
-
-/* Validation of GIMPLE expressions.  */
-
-/*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
-
-bool
-is_gimple_lvalue (tree t)
-{
-  return (is_gimple_addressable (t)
-         || TREE_CODE (t) == WITH_SIZE_EXPR
-         /* These are complex lvalues, but don't have addresses, so they
-            go here.  */
-         || TREE_CODE (t) == BIT_FIELD_REF);
-}
-
-/*  Return true if T is a GIMPLE condition.  */
-
-bool
-is_gimple_condexpr (tree t)
-{
-  return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
-                               && !tree_could_throw_p (t)
-                               && is_gimple_val (TREE_OPERAND (t, 0))
-                               && is_gimple_val (TREE_OPERAND (t, 1))));
-}
-
-/*  Return true if T is something whose address can be taken.  */
-
-bool
-is_gimple_addressable (tree t)
-{
-  return (is_gimple_id (t) || handled_component_p (t)
-         || TREE_CODE (t) == MEM_REF);
-}
-
-/* Return true if T is a valid gimple constant.  */
-
-bool
-is_gimple_constant (const_tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case INTEGER_CST:
-    case REAL_CST:
-    case FIXED_CST:
-    case STRING_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-      return true;
-
-    default:
-      return false;
-    }
-}
-
-/* Return true if T is a gimple address.  */
-
-bool
-is_gimple_address (const_tree t)
-{
-  tree op;
-
-  if (TREE_CODE (t) != ADDR_EXPR)
-    return false;
-
-  op = TREE_OPERAND (t, 0);
-  while (handled_component_p (op))
-    {
-      if ((TREE_CODE (op) == ARRAY_REF
-          || TREE_CODE (op) == ARRAY_RANGE_REF)
-         && !is_gimple_val (TREE_OPERAND (op, 1)))
-           return false;
-
-      op = TREE_OPERAND (op, 0);
-    }
-
-  if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF)
-    return true;
-
-  switch (TREE_CODE (op))
-    {
-    case PARM_DECL:
-    case RESULT_DECL:
-    case LABEL_DECL:
-    case FUNCTION_DECL:
-    case VAR_DECL:
-    case CONST_DECL:
-      return true;
-
-    default:
-      return false;
-    }
-}
-
-/* Return true if T is a gimple invariant address.  */
-
-bool
-is_gimple_invariant_address (const_tree t)
-{
-  const_tree op;
-
-  if (TREE_CODE (t) != ADDR_EXPR)
-    return false;
-
-  op = strip_invariant_refs (TREE_OPERAND (t, 0));
-  if (!op)
-    return false;
-
-  if (TREE_CODE (op) == MEM_REF)
-    {
-      const_tree op0 = TREE_OPERAND (op, 0);
-      return (TREE_CODE (op0) == ADDR_EXPR
-             && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
-                 || decl_address_invariant_p (TREE_OPERAND (op0, 0))));
-    }
-
-  return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
-}
-
-/* Return true if T is a gimple invariant address at IPA level
-   (so addresses of variables on stack are not allowed).  */
-
-bool
-is_gimple_ip_invariant_address (const_tree t)
-{
-  const_tree op;
-
-  if (TREE_CODE (t) != ADDR_EXPR)
-    return false;
-
-  op = strip_invariant_refs (TREE_OPERAND (t, 0));
-  if (!op)
-    return false;
-
-  if (TREE_CODE (op) == MEM_REF)
-    {
-      const_tree op0 = TREE_OPERAND (op, 0);
-      return (TREE_CODE (op0) == ADDR_EXPR
-             && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
-                 || decl_address_ip_invariant_p (TREE_OPERAND (op0, 0))));
-    }
-
-  return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
-}
-
-/* Return true if T is a GIMPLE minimal invariant.  It's a restricted
-   form of function invariant.  */
-
-bool
-is_gimple_min_invariant (const_tree t)
-{
-  if (TREE_CODE (t) == ADDR_EXPR)
-    return is_gimple_invariant_address (t);
-
-  return is_gimple_constant (t);
-}
-
-/* Return true if T is a GIMPLE interprocedural invariant.  It's a restricted
-   form of gimple minimal invariant.  */
-
-bool
-is_gimple_ip_invariant (const_tree t)
-{
-  if (TREE_CODE (t) == ADDR_EXPR)
-    return is_gimple_ip_invariant_address (t);
-
-  return is_gimple_constant (t);
-}
-
-/* Return true if T is a variable.  */
-
-bool
-is_gimple_variable (tree t)
-{
-  return (TREE_CODE (t) == VAR_DECL
-         || TREE_CODE (t) == PARM_DECL
-         || TREE_CODE (t) == RESULT_DECL
-         || TREE_CODE (t) == SSA_NAME);
-}
-
-/*  Return true if T is a GIMPLE identifier (something with an address).  */
-
-bool
-is_gimple_id (tree t)
-{
-  return (is_gimple_variable (t)
-         || TREE_CODE (t) == FUNCTION_DECL
-         || TREE_CODE (t) == LABEL_DECL
-         || TREE_CODE (t) == CONST_DECL
-         /* Allow string constants, since they are addressable.  */
-         || TREE_CODE (t) == STRING_CST);
-}
-
-/* Return true if OP, an SSA name or a DECL is a virtual operand.  */
-
-bool
-virtual_operand_p (tree op)
-{
-  if (TREE_CODE (op) == SSA_NAME)
-    {
-      op = SSA_NAME_VAR (op);
-      if (!op)
-       return false;
-    }
-
-  if (TREE_CODE (op) == VAR_DECL)
-    return VAR_DECL_IS_VIRTUAL_OPERAND (op);
-
-  return false;
-}
-
-
-/* Return true if T is a non-aggregate register variable.  */
-
-bool
-is_gimple_reg (tree t)
-{
-  if (virtual_operand_p (t))
-    return false;
-
-  if (TREE_CODE (t) == SSA_NAME)
-    return true;
-
-  if (!is_gimple_variable (t))
-    return false;
-
-  if (!is_gimple_reg_type (TREE_TYPE (t)))
-    return false;
-
-  /* A volatile decl is not acceptable because we can't reuse it as
-     needed.  We need to copy it into a temp first.  */
-  if (TREE_THIS_VOLATILE (t))
-    return false;
-
-  /* We define "registers" as things that can be renamed as needed,
-     which with our infrastructure does not apply to memory.  */
-  if (needs_to_live_in_memory (t))
-    return false;
-
-  /* Hard register variables are an interesting case.  For those that
-     are call-clobbered, we don't know where all the calls are, since
-     we don't (want to) take into account which operations will turn
-     into libcalls at the rtl level.  For those that are call-saved,
-     we don't currently model the fact that calls may in fact change
-     global hard registers, nor do we examine ASM_CLOBBERS at the tree
-     level, and so miss variable changes that might imply.  All around,
-     it seems safest to not do too much optimization with these at the
-     tree level at all.  We'll have to rely on the rtl optimizers to
-     clean this up, as there we've got all the appropriate bits exposed.  */
-  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
-    return false;
-
-  /* Complex and vector values must have been put into SSA-like form.
-     That is, no assignments to the individual components.  */
-  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
-      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
-    return DECL_GIMPLE_REG_P (t);
-
-  return true;
-}
-
-
-/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
-
-bool
-is_gimple_val (tree t)
-{
-  /* Make loads from volatiles and memory vars explicit.  */
-  if (is_gimple_variable (t)
-      && is_gimple_reg_type (TREE_TYPE (t))
-      && !is_gimple_reg (t))
-    return false;
-
-  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
-}
-
-/* Similarly, but accept hard registers as inputs to asm statements.  */
-
-bool
-is_gimple_asm_val (tree t)
-{
-  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
-    return true;
-
-  return is_gimple_val (t);
-}
-
-/* Return true if T is a GIMPLE minimal lvalue.  */
-
-bool
-is_gimple_min_lval (tree t)
-{
-  if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
-    return false;
-  return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF);
-}
-
-/* Return true if T is a valid function operand of a CALL_EXPR.  */
-
-bool
-is_gimple_call_addr (tree t)
-{
-  return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
-}
-
-/* Return true if T is a valid address operand of a MEM_REF.  */
-
-bool
-is_gimple_mem_ref_addr (tree t)
-{
-  return (is_gimple_reg (t)
-         || TREE_CODE (t) == INTEGER_CST
-         || (TREE_CODE (t) == ADDR_EXPR
-             && (CONSTANT_CLASS_P (TREE_OPERAND (t, 0))
-                 || decl_address_invariant_p (TREE_OPERAND (t, 0)))));
-}
-
-
 /* Given a memory reference expression T, return its base address.
    The base address of a memory reference expression is the main
    object being referenced.  For instance, the base address for
@@ -3642,37 +3212,6 @@ gimple_ior_addresses_taken (bitmap addresses_taken, gimple stmt)
 }
 
 
-/* Return a printable name for symbol DECL.  */
-
-const char *
-gimple_decl_printable_name (tree decl, int verbosity)
-{
-  if (!DECL_NAME (decl))
-    return NULL;
-
-  if (DECL_ASSEMBLER_NAME_SET_P (decl))
-    {
-      const char *str, *mangled_str;
-      int dmgl_opts = DMGL_NO_OPTS;
-
-      if (verbosity >= 2)
-       {
-         dmgl_opts = DMGL_VERBOSE
-                     | DMGL_ANSI
-                     | DMGL_GNU_V3
-                     | DMGL_RET_POSTFIX;
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           dmgl_opts |= DMGL_PARAMS;
-       }
-
-      mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-      str = cplus_demangle_v3 (mangled_str, dmgl_opts);
-      return (str) ? str : mangled_str;
-    }
-
-  return IDENTIFIER_POINTER (DECL_NAME (decl));
-}
-
 /* Return TRUE iff stmt is a call to a built-in function.  */
 
 bool
@@ -3763,261 +3302,6 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
   return false;
 }
 
-
-/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
-   useless type conversion, otherwise return false.
-
-   This function implicitly defines the middle-end type system.  With
-   the notion of 'a < b' meaning that useless_type_conversion_p (a, b)
-   holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds,
-   the following invariants shall be fulfilled:
-
-     1) useless_type_conversion_p is transitive.
-       If a < b and b < c then a < c.
-
-     2) useless_type_conversion_p is not symmetric.
-       From a < b does not follow a > b.
-
-     3) Types define the available set of operations applicable to values.
-       A type conversion is useless if the operations for the target type
-       is a subset of the operations for the source type.  For example
-       casts to void* are useless, casts from void* are not (void* can't
-       be dereferenced or offsetted, but copied, hence its set of operations
-       is a strict subset of that of all other data pointer types).  Casts
-       to const T* are useless (can't be written to), casts from const T*
-       to T* are not.  */
-
-bool
-useless_type_conversion_p (tree outer_type, tree inner_type)
-{
-  /* Do the following before stripping toplevel qualifiers.  */
-  if (POINTER_TYPE_P (inner_type)
-      && POINTER_TYPE_P (outer_type))
-    {
-      /* Do not lose casts between pointers to different address spaces.  */
-      if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
-         != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
-       return false;
-    }
-
-  /* From now on qualifiers on value types do not matter.  */
-  inner_type = TYPE_MAIN_VARIANT (inner_type);
-  outer_type = TYPE_MAIN_VARIANT (outer_type);
-
-  if (inner_type == outer_type)
-    return true;
-
-  /* If we know the canonical types, compare them.  */
-  if (TYPE_CANONICAL (inner_type)
-      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
-    return true;
-
-  /* Changes in machine mode are never useless conversions unless we
-     deal with aggregate types in which case we defer to later checks.  */
-  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
-      && !AGGREGATE_TYPE_P (inner_type))
-    return false;
-
-  /* If both the inner and outer types are integral types, then the
-     conversion is not necessary if they have the same mode and
-     signedness and precision, and both or neither are boolean.  */
-  if (INTEGRAL_TYPE_P (inner_type)
-      && INTEGRAL_TYPE_P (outer_type))
-    {
-      /* Preserve changes in signedness or precision.  */
-      if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
-         || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
-       return false;
-
-      /* Preserve conversions to/from BOOLEAN_TYPE if types are not
-        of precision one.  */
-      if (((TREE_CODE (inner_type) == BOOLEAN_TYPE)
-          != (TREE_CODE (outer_type) == BOOLEAN_TYPE))
-         && TYPE_PRECISION (outer_type) != 1)
-       return false;
-
-      /* We don't need to preserve changes in the types minimum or
-        maximum value in general as these do not generate code
-        unless the types precisions are different.  */
-      return true;
-    }
-
-  /* Scalar floating point types with the same mode are compatible.  */
-  else if (SCALAR_FLOAT_TYPE_P (inner_type)
-          && SCALAR_FLOAT_TYPE_P (outer_type))
-    return true;
-
-  /* Fixed point types with the same mode are compatible.  */
-  else if (FIXED_POINT_TYPE_P (inner_type)
-          && FIXED_POINT_TYPE_P (outer_type))
-    return true;
-
-  /* We need to take special care recursing to pointed-to types.  */
-  else if (POINTER_TYPE_P (inner_type)
-          && POINTER_TYPE_P (outer_type))
-    {
-      /* Do not lose casts to function pointer types.  */
-      if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
-          || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
-         && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
-              || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
-       return false;
-
-      /* We do not care for const qualification of the pointed-to types
-        as const qualification has no semantic value to the middle-end.  */
-
-      /* Otherwise pointers/references are equivalent.  */
-      return true;
-    }
-
-  /* Recurse for complex types.  */
-  else if (TREE_CODE (inner_type) == COMPLEX_TYPE
-          && TREE_CODE (outer_type) == COMPLEX_TYPE)
-    return useless_type_conversion_p (TREE_TYPE (outer_type),
-                                     TREE_TYPE (inner_type));
-
-  /* Recurse for vector types with the same number of subparts.  */
-  else if (TREE_CODE (inner_type) == VECTOR_TYPE
-          && TREE_CODE (outer_type) == VECTOR_TYPE
-          && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
-    return useless_type_conversion_p (TREE_TYPE (outer_type),
-                                     TREE_TYPE (inner_type));
-
-  else if (TREE_CODE (inner_type) == ARRAY_TYPE
-          && TREE_CODE (outer_type) == ARRAY_TYPE)
-    {
-      /* Preserve string attributes.  */
-      if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type))
-       return false;
-
-      /* Conversions from array types with unknown extent to
-        array types with known extent are not useless.  */
-      if (!TYPE_DOMAIN (inner_type)
-         && TYPE_DOMAIN (outer_type))
-       return false;
-
-      /* Nor are conversions from array types with non-constant size to
-         array types with constant size or to different size.  */
-      if (TYPE_SIZE (outer_type)
-         && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST
-         && (!TYPE_SIZE (inner_type)
-             || TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST
-             || !tree_int_cst_equal (TYPE_SIZE (outer_type),
-                                     TYPE_SIZE (inner_type))))
-       return false;
-
-      /* Check conversions between arrays with partially known extents.
-        If the array min/max values are constant they have to match.
-        Otherwise allow conversions to unknown and variable extents.
-        In particular this declares conversions that may change the
-        mode to BLKmode as useless.  */
-      if (TYPE_DOMAIN (inner_type)
-         && TYPE_DOMAIN (outer_type)
-         && TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type))
-       {
-         tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type));
-         tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type));
-         tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type));
-         tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type));
-
-         /* After gimplification a variable min/max value carries no
-            additional information compared to a NULL value.  All that
-            matters has been lowered to be part of the IL.  */
-         if (inner_min && TREE_CODE (inner_min) != INTEGER_CST)
-           inner_min = NULL_TREE;
-         if (outer_min && TREE_CODE (outer_min) != INTEGER_CST)
-           outer_min = NULL_TREE;
-         if (inner_max && TREE_CODE (inner_max) != INTEGER_CST)
-           inner_max = NULL_TREE;
-         if (outer_max && TREE_CODE (outer_max) != INTEGER_CST)
-           outer_max = NULL_TREE;
-
-         /* Conversions NULL / variable <- cst are useless, but not
-            the other way around.  */
-         if (outer_min
-             && (!inner_min
-                 || !tree_int_cst_equal (inner_min, outer_min)))
-           return false;
-         if (outer_max
-             && (!inner_max
-                 || !tree_int_cst_equal (inner_max, outer_max)))
-           return false;
-       }
-
-      /* Recurse on the element check.  */
-      return useless_type_conversion_p (TREE_TYPE (outer_type),
-                                       TREE_TYPE (inner_type));
-    }
-
-  else if ((TREE_CODE (inner_type) == FUNCTION_TYPE
-           || TREE_CODE (inner_type) == METHOD_TYPE)
-          && TREE_CODE (inner_type) == TREE_CODE (outer_type))
-    {
-      tree outer_parm, inner_parm;
-
-      /* If the return types are not compatible bail out.  */
-      if (!useless_type_conversion_p (TREE_TYPE (outer_type),
-                                     TREE_TYPE (inner_type)))
-       return false;
-
-      /* Method types should belong to a compatible base class.  */
-      if (TREE_CODE (inner_type) == METHOD_TYPE
-         && !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type),
-                                        TYPE_METHOD_BASETYPE (inner_type)))
-       return false;
-
-      /* A conversion to an unprototyped argument list is ok.  */
-      if (!prototype_p (outer_type))
-       return true;
-
-      /* If the unqualified argument types are compatible the conversion
-        is useless.  */
-      if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type))
-       return true;
-
-      for (outer_parm = TYPE_ARG_TYPES (outer_type),
-          inner_parm = TYPE_ARG_TYPES (inner_type);
-          outer_parm && inner_parm;
-          outer_parm = TREE_CHAIN (outer_parm),
-          inner_parm = TREE_CHAIN (inner_parm))
-       if (!useless_type_conversion_p
-              (TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)),
-               TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm))))
-         return false;
-
-      /* If there is a mismatch in the number of arguments the functions
-        are not compatible.  */
-      if (outer_parm || inner_parm)
-       return false;
-
-      /* Defer to the target if necessary.  */
-      if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type))
-       return comp_type_attributes (outer_type, inner_type) != 0;
-
-      return true;
-    }
-
-  /* For aggregates we rely on TYPE_CANONICAL exclusively and require
-     explicit conversions for types involving to be structurally
-     compared types.  */
-  else if (AGGREGATE_TYPE_P (inner_type)
-          && TREE_CODE (inner_type) == TREE_CODE (outer_type))
-    return false;
-
-  return false;
-}
-
-/* Return true if a conversion from either type of TYPE1 and TYPE2
-   to the other is not required.  Otherwise return false.  */
-
-bool
-types_compatible_p (tree type1, tree type2)
-{
-  return (type1 == type2
-         || (useless_type_conversion_p (type1, type2)
-             && useless_type_conversion_p (type2, type1)));
-}
-
 /* Dump bitmap SET (assumed to contain VAR_DECLs) to FILE.  */
 
 void
@@ -4042,45 +3326,6 @@ dump_decl_set (FILE *file, bitmap set)
     fprintf (file, "NIL");
 }
 
-/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for
-   coalescing together, false otherwise.
-
-   This must stay consistent with var_map_base_init in tree-ssa-live.c.  */
-
-bool
-gimple_can_coalesce_p (tree name1, tree name2)
-{
-  /* First check the SSA_NAME's associated DECL.  We only want to
-     coalesce if they have the same DECL or both have no associated DECL.  */
-  tree var1 = SSA_NAME_VAR (name1);
-  tree var2 = SSA_NAME_VAR (name2);
-  var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE;
-  var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE;
-  if (var1 != var2)
-    return false;
-
-  /* Now check the types.  If the types are the same, then we should
-     try to coalesce V1 and V2.  */
-  tree t1 = TREE_TYPE (name1);
-  tree t2 = TREE_TYPE (name2);
-  if (t1 == t2)
-    return true;
-
-  /* If the types are not the same, check for a canonical type match.  This
-     (for example) allows coalescing when the types are fundamentally the
-     same, but just have different names. 
-
-     Note pointer types with different address spaces may have the same
-     canonical type.  Those are rejected for coalescing by the
-     types_compatible_p check.  */
-  if (TYPE_CANONICAL (t1)
-      && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)
-      && types_compatible_p (t1, t2))
-    return true;
-
-  return false;
-}
-
 /* Return true when CALL is a call stmt that definitely doesn't
    free any memory or makes it unavailable otherwise.  */
 bool
@@ -4103,23 +3348,83 @@ nonfreeing_call_p (gimple call)
   return false;
 }
 
-/* Create a new VAR_DECL and copy information from VAR to it.  */
+/* Callback for walk_stmt_load_store_ops.
+   Return TRUE if OP will dereference the tree stored in DATA, FALSE
+   otherwise.
 
-tree
-copy_var_decl (tree var, tree name, tree type)
+   This routine only makes a superficial check for a dereference.  Thus
+   it must only be used if it is safe to return a false negative.  */
+static bool
+check_loadstore (gimple stmt ATTRIBUTE_UNUSED, tree op, void *data)
 {
-  tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type);
-
-  TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
-  TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
-  DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
-  DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
-  DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
-  DECL_CONTEXT (copy) = DECL_CONTEXT (var);
-  TREE_NO_WARNING (copy) = TREE_NO_WARNING (var);
-  TREE_USED (copy) = 1;
-  DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
-  DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var);
+  if ((TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF)
+      && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
+    return true;
+  return false;
+}
 
-  return copy;
+/* If OP can be inferred to be non-zero after STMT executes, return true.  */
+
+bool
+infer_nonnull_range (gimple stmt, tree op)
+{
+  /* We can only assume that a pointer dereference will yield
+     non-NULL if -fdelete-null-pointer-checks is enabled.  */
+  if (!flag_delete_null_pointer_checks
+      || !POINTER_TYPE_P (TREE_TYPE (op))
+      || gimple_code (stmt) == GIMPLE_ASM)
+    return false;
+
+  if (walk_stmt_load_store_ops (stmt, (void *)op,
+                               check_loadstore, check_loadstore))
+    return true;
+
+  if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
+    {
+      tree fntype = gimple_call_fntype (stmt);
+      tree attrs = TYPE_ATTRIBUTES (fntype);
+      for (; attrs; attrs = TREE_CHAIN (attrs))
+       {
+         attrs = lookup_attribute ("nonnull", attrs);
+
+         /* If "nonnull" wasn't specified, we know nothing about
+            the argument.  */
+         if (attrs == NULL_TREE)
+           return false;
+
+         /* If "nonnull" applies to all the arguments, then ARG
+            is non-null if it's in the argument list.  */
+         if (TREE_VALUE (attrs) == NULL_TREE)
+           {
+             for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
+               {
+                 if (operand_equal_p (op, gimple_call_arg (stmt, i), 0)
+                     && POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (stmt, i))))
+                   return true;
+               }
+             return false;
+           }
+
+         /* Now see if op appears in the nonnull list.  */
+         for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t))
+           {
+             int idx = TREE_INT_CST_LOW (TREE_VALUE (t)) - 1;
+             tree arg = gimple_call_arg (stmt, idx);
+             if (operand_equal_p (op, arg, 0))
+               return true;
+           }
+       }
+    }
+
+  /* If this function is marked as returning non-null, then we can
+     infer OP is non-null if it is used in the return statement.  */
+  if (gimple_code (stmt) == GIMPLE_RETURN
+      && gimple_return_retval (stmt)
+      && operand_equal_p (gimple_return_retval (stmt), op, 0)
+      && lookup_attribute ("returns_nonnull",
+                          TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+    return true;
+
+  return false;
 }
index b34424c18d3560aa2a410fb57e44953255c3d7fc..a548a5b45e83fbefd8e91df2559cb7564e0c0038 100644 (file)
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "gimple-fold.h"
 #include "tree-eh.h"
+#include "gimple-expr.h"
 
 typedef gimple gimple_seq_node;
 
@@ -745,8 +746,6 @@ gimple gimple_build_return (tree);
 gimple gimple_build_assign_stat (tree, tree MEM_STAT_DECL);
 #define gimple_build_assign(l,r) gimple_build_assign_stat (l, r MEM_STAT_INFO)
 
-void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *, tree *);
-
 gimple
 gimple_build_assign_with_ops (enum tree_code, tree,
                              tree, tree CXX_MEM_STAT_INFO);
@@ -809,9 +808,6 @@ gimple gimple_build_predict (enum br_predictor, enum prediction);
 enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
 void sort_case_labels (vec<tree> );
 void preprocess_case_label_vec_for_gimple (vec<tree> , tree, tree *);
-void gimple_set_body (tree, gimple_seq);
-gimple_seq gimple_body (tree);
-bool gimple_has_body_p (tree);
 gimple_seq gimple_seq_alloc (void);
 void gimple_seq_free (gimple_seq);
 void gimple_seq_add_seq (gimple_seq *, gimple_seq);
@@ -832,7 +828,6 @@ tree gimple_get_lhs (const_gimple);
 void gimple_set_lhs (gimple, tree);
 void gimple_replace_lhs (gimple, tree);
 gimple gimple_copy (gimple);
-void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *, tree *);
 gimple gimple_build_cond_from_tree (tree, tree, tree);
 void gimple_cond_set_condition_from_tree (gimple, tree);
 bool gimple_has_side_effects (const_gimple);
@@ -844,48 +839,6 @@ bool empty_body_p (gimple_seq);
 unsigned get_gimple_rhs_num_ops (enum tree_code);
 #define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
 gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
-const char *gimple_decl_printable_name (tree, int);
-
-/* Returns true iff T is a virtual ssa name decl.  */
-extern bool virtual_operand_p (tree);
-/* Returns true iff T is a scalar register variable.  */
-extern bool is_gimple_reg (tree);
-/* Returns true iff T is any sort of variable.  */
-extern bool is_gimple_variable (tree);
-/* Returns true iff T is any sort of symbol.  */
-extern bool is_gimple_id (tree);
-/* Returns true iff T is a variable or an INDIRECT_REF (of a variable).  */
-extern bool is_gimple_min_lval (tree);
-/* Returns true iff T is something whose address can be taken.  */
-extern bool is_gimple_addressable (tree);
-/* Returns true iff T is any valid GIMPLE lvalue.  */
-extern bool is_gimple_lvalue (tree);
-
-/* Returns true iff T is a GIMPLE address.  */
-bool is_gimple_address (const_tree);
-/* Returns true iff T is a GIMPLE invariant address.  */
-bool is_gimple_invariant_address (const_tree);
-/* Returns true iff T is a GIMPLE invariant address at interprocedural
-   level.  */
-bool is_gimple_ip_invariant_address (const_tree);
-/* Returns true iff T is a valid GIMPLE constant.  */
-bool is_gimple_constant (const_tree);
-/* Returns true iff T is a GIMPLE restricted function invariant.  */
-extern bool is_gimple_min_invariant (const_tree);
-/* Returns true iff T is a GIMPLE restricted interprecodural invariant.  */
-extern bool is_gimple_ip_invariant (const_tree);
-/* Returns true iff T is a GIMPLE rvalue.  */
-extern bool is_gimple_val (tree);
-/* Returns true iff T is a GIMPLE asm statement input.  */
-extern bool is_gimple_asm_val (tree);
-/* Returns true iff T is a valid address operand of a MEM_REF.  */
-bool is_gimple_mem_ref_addr (tree);
-
-/* Returns true iff T is a valid if-statement condition.  */
-extern bool is_gimple_condexpr (tree);
-
-/* Returns true iff T is a valid call address expression.  */
-extern bool is_gimple_call_addr (tree);
 
 /* Return TRUE iff stmt is a call to a built-in function.  */
 extern bool is_gimple_builtin_call (gimple stmt);
@@ -906,8 +859,6 @@ extern bool gimple_ior_addresses_taken (bitmap, gimple);
 extern bool gimple_call_builtin_p (gimple, enum built_in_class);
 extern bool gimple_call_builtin_p (gimple, enum built_in_function);
 extern bool gimple_asm_clobbers_memory_p (const_gimple);
-extern bool useless_type_conversion_p (tree, tree);
-extern bool types_compatible_p (tree, tree);
 
 /* In gimplify.c  */
 extern tree create_tmp_var_raw (tree, const char *);
@@ -1086,9 +1037,8 @@ extern tree gimple_boolify (tree);
 extern gimple_predicate rhs_predicate_for (tree);
 extern tree canonicalize_cond_expr_cond (tree);
 extern void dump_decl_set (FILE *, bitmap);
-extern bool gimple_can_coalesce_p (tree, tree);
 extern bool nonfreeing_call_p (gimple);
-extern tree copy_var_decl (tree, tree, tree);
+extern bool infer_nonnull_range (gimple, tree);
 
 /* In trans-mem.c.  */
 extern void diagnose_tm_safe_errors (tree);
@@ -2042,18 +1992,6 @@ gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
   gimple_assign_set_rhs_with_ops_1 (gsi, code, op1, op2, NULL);
 }
 
-/* A wrapper around extract_ops_from_tree_1, for callers which expect
-   to see only a maximum of two operands.  */
-
-static inline void
-extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0,
-                      tree *op1)
-{
-  tree op2;
-  extract_ops_from_tree_1 (expr, code, op0, op1, &op2);
-  gcc_assert (op2 == NULL_TREE);
-}
-
 /* Returns true if GS is a nontemporal move.  */
 
 static inline bool
@@ -2316,25 +2254,6 @@ gimple_call_set_internal_fn (gimple gs, enum internal_fn fn)
 }
 
 
-/* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL
-   associated with the callee if known.  Otherwise return NULL_TREE.  */
-
-static inline tree
-gimple_call_addr_fndecl (const_tree fn)
-{
-  if (fn && TREE_CODE (fn) == ADDR_EXPR)
-    {
-      tree fndecl = TREE_OPERAND (fn, 0);
-      if (TREE_CODE (fndecl) == MEM_REF
-         && TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR
-         && integer_zerop (TREE_OPERAND (fndecl, 1)))
-       fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0);
-      if (TREE_CODE (fndecl) == FUNCTION_DECL)
-       return fndecl;
-    }
-  return NULL_TREE;
-}
-
 /* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it.
    Otherwise return NULL.  This function is analogous to
    get_callee_fndecl in tree land.  */
@@ -3633,19 +3552,6 @@ gimple_phi_set_arg (gimple gs, unsigned index, struct phi_arg_d * phiarg)
   gs->gimple_phi.args[index] = *phiarg;
 }
 
-/* PHI nodes should contain only ssa_names and invariants.  A test
-   for ssa_name is definitely simpler; don't let invalid contents
-   slip in in the meantime.  */
-
-static inline bool
-phi_ssa_name_p (const_tree t)
-{
-  if (TREE_CODE (t) == SSA_NAME)
-    return true;
-  gcc_checking_assert (is_gimple_min_invariant (t));
-  return false;
-}
-
 /* Return the PHI nodes for basic block BB, or NULL if there are no
    PHI nodes.  */
 
@@ -5398,14 +5304,6 @@ gimple_expr_type (const_gimple stmt)
     return void_type_node;
 }
 
-/* Return true if TYPE is a suitable type for a scalar register variable.  */
-
-static inline bool
-is_gimple_reg_type (tree type)
-{
-  return !AGGREGATE_TYPE_P (type);
-}
-
 /* Return a new iterator pointing to GIMPLE_SEQ's first statement.  */
 
 static inline gimple_stmt_iterator
index 21dc7cad156918de572526e58f8cd98081247892..58cb533ab94cf756022c7915d530978396e3ad6c 100644 (file)
@@ -8867,7 +8867,7 @@ gimplify_body (tree fndecl, bool do_parms)
       nonlocal_vlas = NULL;
     }
 
-  if (flag_openmp && gimplify_omp_ctxp)
+  if ((flag_openmp || flag_openmp_simd) && gimplify_omp_ctxp)
     {
       delete_omp_context (gimplify_omp_ctxp);
       gimplify_omp_ctxp = NULL;
index aab5748f67b6d1e4474e81dc38ec91d7892ba6ca..ab21d0d481b5fd9dc7d962fc08ef5611c20380b4 100644 (file)
@@ -6519,6 +6519,50 @@ setup_sched_dump (void)
                ? stderr : dump_file);
 }
 
+/* Try to group comparison and the following conditional jump INSN if
+   they're already adjacent. This is to prevent scheduler from scheduling
+   them apart.  */
+
+static void
+try_group_insn (rtx insn)
+{
+  unsigned int condreg1, condreg2;
+  rtx cc_reg_1;
+  rtx prev;
+
+  if (!any_condjump_p (insn))
+    return;
+
+  targetm.fixed_condition_code_regs (&condreg1, &condreg2);
+  cc_reg_1 = gen_rtx_REG (CCmode, condreg1);
+  prev = prev_nonnote_nondebug_insn (insn);
+  if (!reg_referenced_p (cc_reg_1, PATTERN (insn))
+      || !prev
+      || !modified_in_p (cc_reg_1, prev))
+    return;
+
+  /* Different microarchitectures support macro fusions for different
+     combinations of insn pairs.  */
+  if (!targetm.sched.macro_fusion_pair_p
+      || !targetm.sched.macro_fusion_pair_p (prev, insn))
+    return;
+
+  SCHED_GROUP_P (insn) = 1;
+}
+
+/* If the last cond jump and the cond register defining insn are consecutive
+   before scheduling, we want them to be in a schedule group. This is good
+   for performance on microarchitectures supporting macro-fusion.  */
+
+static void
+group_insns_for_macro_fusion ()
+{
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    try_group_insn (BB_END (bb));
+}
+
 /* Initialize some global state for the scheduler.  This function works
    with the common data shared between all the schedulers.  It is called
    from the scheduler specific initialization routine.  */
@@ -6645,6 +6689,11 @@ sched_init (void)
     }
 
   curr_state = xmalloc (dfa_state_size);
+
+  /* Group compare and branch insns for macro-fusion.  */
+  if (targetm.sched.macro_fusion_p
+      && targetm.sched.macro_fusion_p ())
+    group_insns_for_macro_fusion ();
 }
 
 static void haifa_init_only_bb (basic_block, basic_block);
index 9761d6e0a999c835fbd6406dec7c604df4f852a3..c1531589d0ce142058aeebc3ace6a7fccdd8b377 100644 (file)
@@ -852,7 +852,7 @@ static bool
 ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor_t> descriptors,
                          struct param_analysis_info *parms_ainfo, gimple stmt,
                          tree op, int *index_p, HOST_WIDE_INT *offset_p,
-                         bool *by_ref_p)
+                         HOST_WIDE_INT *size_p, bool *by_ref_p)
 {
   int index;
   HOST_WIDE_INT size, max_size;
@@ -870,6 +870,8 @@ ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor_t> descriptors,
        {
          *index_p = index;
          *by_ref_p = false;
+         if (size_p)
+           *size_p = size;
          return true;
        }
       return false;
@@ -912,6 +914,8 @@ ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor_t> descriptors,
     {
       *index_p = index;
       *by_ref_p = true;
+      if (size_p)
+       *size_p = size;
       return true;
     }
   return false;
@@ -926,7 +930,7 @@ ipa_load_from_parm_agg (struct ipa_node_params *info, gimple stmt,
                        bool *by_ref_p)
 {
   return ipa_load_from_parm_agg_1 (info->descriptors, NULL, stmt, op, index_p,
-                                  offset_p, by_ref_p);
+                                  offset_p, NULL, by_ref_p);
 }
 
 /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result
@@ -1826,7 +1830,7 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
   if (gimple_assign_single_p (def)
       && ipa_load_from_parm_agg_1 (info->descriptors, parms_ainfo, def,
                                   gimple_assign_rhs1 (def), &index, &offset,
-                                  &by_ref))
+                                  NULL, &by_ref))
     {
       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
       cs->indirect_info->offset = offset;
@@ -4566,7 +4570,7 @@ ipcp_transform_function (struct cgraph_node *node)
        struct ipa_agg_replacement_value *v;
        gimple stmt = gsi_stmt (gsi);
        tree rhs, val, t;
-       HOST_WIDE_INT offset;
+       HOST_WIDE_INT offset, size;
        int index;
        bool by_ref, vce;
 
@@ -4593,13 +4597,15 @@ ipcp_transform_function (struct cgraph_node *node)
          continue;
 
        if (!ipa_load_from_parm_agg_1 (descriptors, parms_ainfo, stmt,
-                                      rhs, &index, &offset, &by_ref))
+                                      rhs, &index, &offset, &size, &by_ref))
          continue;
        for (v = aggval; v; v = v->next)
          if (v->index == index
              && v->offset == offset)
            break;
-       if (!v || v->by_ref != by_ref)
+       if (!v
+           || v->by_ref != by_ref
+           || tree_low_cst (TYPE_SIZE (TREE_TYPE (v->value)), 0) != size)
          continue;
 
        gcc_checking_assert (is_gimple_ip_invariant (v->value));
index 60d5043d67afc7ae771631a4b91a068502c115be..6b5f82b16b1ab0c59323d8d303e13ae64a9893ae 100644 (file)
@@ -436,7 +436,9 @@ iv_subreg (struct rtx_iv *iv, enum machine_mode mode)
       && !iv->first_special)
     {
       rtx val = get_iv_value (iv, const0_rtx);
-      val = lowpart_subreg (mode, val, iv->extend_mode);
+      val = lowpart_subreg (mode, val,
+                           iv->extend == IV_UNKNOWN_EXTEND
+                           ? iv->mode : iv->extend_mode);
 
       iv->base = val;
       iv->extend = IV_UNKNOWN_EXTEND;
@@ -476,8 +478,14 @@ iv_extend (struct rtx_iv *iv, enum iv_extend_code extend, enum machine_mode mode
       && !iv->first_special)
     {
       rtx val = get_iv_value (iv, const0_rtx);
+      if (iv->extend_mode != iv->mode
+         && iv->extend != IV_UNKNOWN_EXTEND
+         && iv->extend != extend)
+       val = lowpart_subreg (iv->mode, val, iv->extend_mode);
       val = simplify_gen_unary (iv_extend_to_rtx_code (extend), mode,
-                               val, iv->extend_mode);
+                               val,
+                               iv->extend == extend
+                               ? iv->extend_mode : iv->mode);
       iv->base = val;
       iv->extend = IV_UNKNOWN_EXTEND;
       iv->mode = iv->extend_mode = mode;
index 3bdb10a4373f1b2a08f11bb78e24d1448f6a05b6..219c943545b11e4f478a3b3c2569ff5599027c56 100644 (file)
@@ -191,6 +191,7 @@ may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
   if (!test)
     return NULL_RTX;
 
+  mode = VOIDmode;
   for (i = 0; i < 2; i++)
     {
       op[i] = XEXP (test, i);
@@ -205,11 +206,15 @@ may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
        return NULL_RTX;
 
       op[i] = get_iv_value (&iv, const0_rtx);
+      if (iv.extend != IV_UNKNOWN_EXTEND
+         && iv.mode != iv.extend_mode)
+       op[i] = lowpart_subreg (iv.mode, op[i], iv.extend_mode);
+      if (mode == VOIDmode)
+       mode = iv.mode;
+      else
+       gcc_assert (mode == iv.mode);
     }
 
-  mode = GET_MODE (op[0]);
-  if (mode == VOIDmode)
-    mode = GET_MODE (op[1]);
   if (GET_MODE_CLASS (mode) == MODE_CC)
     {
       if (at != BB_END (bb))
index 0a63f89c88275e5d920edce7abe036f61eec9129..c9d4e03d00c787b004274a378e61a5bd84724001 100644 (file)
@@ -77,7 +77,7 @@ lto_write_options (void)
 
   obstack_init (&temporary_obstack);
 
-  /* Output options that affect GIMPLE IL semantics and are implicitely
+  /* Output options that affect GIMPLE IL semantics and are implicitly
      enabled by the frontend.
      This for now includes an explicit set of options that we also handle
      explicitly in lto-wrapper.c.  In the end the effects on GIMPLE IL
@@ -88,8 +88,13 @@ lto_write_options (void)
   if (global_options.x_flag_exceptions)
     append_to_collect_gcc_options (&temporary_obstack, &first_p,
                                   "-fexceptions");
+  /* -fnon-call-exceptions changes the generation of exception
+      regions.  It is enabled implicitly by the Go frontend.  */
+  if (global_options.x_flag_non_call_exceptions)
+    append_to_collect_gcc_options (&temporary_obstack, &first_p,
+                                  "-fnon-call-exceptions");
 
-  /* Output explicitely passed options.  */
+  /* Output explicitly passed options.  */
   for (i = 1; i < save_decoded_options_count; ++i)
     {
       struct cl_decoded_option *option = &save_decoded_options[i];
index 755993ca634e01552612ce36ceaef7689da23054..57978c883d4146de60d85020e0195ababeefc651 100644 (file)
@@ -409,6 +409,7 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
        case OPT_fpie:
        case OPT_fcommon:
        case OPT_fexceptions:
+       case OPT_fnon_call_exceptions:
        case OPT_fgnu_tm:
          /* Do what the old LTO code did - collect exactly one option
             setting per OPT code, we pick the first we encounter.
@@ -573,6 +574,7 @@ run_gcc (unsigned argc, char *argv[])
        case OPT_fpie:
        case OPT_fcommon:
        case OPT_fexceptions:
+       case OPT_fnon_call_exceptions:
        case OPT_fgnu_tm:
        case OPT_freg_struct_return:
        case OPT_fpcc_struct_return:
index ad0c609622b293cbfd3047b64887b6610bf3850d..8e4727cac75abac4dd200eeef36e7d307428c551 100644 (file)
@@ -8229,7 +8229,7 @@ execute_expand_omp (void)
 static bool
 gate_expand_omp (void)
 {
-  return (flag_openmp != 0 && !seen_error ());
+  return ((flag_openmp != 0 || flag_openmp_simd != 0) && !seen_error ());
 }
 
 namespace {
@@ -10050,7 +10050,7 @@ execute_lower_omp (void)
 
   /* This pass always runs, to provide PROP_gimple_lomp.
      But there is nothing to do unless -fopenmp is given.  */
-  if (flag_openmp == 0)
+  if (flag_openmp == 0 && flag_openmp_simd == 0)
     return 0;
 
   all_contexts = splay_tree_new (splay_tree_compare_pointers, 0,
index d6e49c9272c9fee6b91f63baf74b7dffc597b17d..a9b0c1985577734a6b85427bfa59c9be18ffb6e8 100644 (file)
@@ -6670,7 +6670,7 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
        }
       tmp = gen_rtx_CONST_VECTOR (qimode, vec);
       sel = gen_lowpart (qimode, sel);
-      sel = expand_vec_perm (qimode, gen_reg_rtx (qimode), sel, tmp, NULL);
+      sel = expand_vec_perm (qimode, sel, sel, tmp, NULL);
       gcc_assert (sel != NULL);
 
       /* Add the byte offset to each byte element.  */
index 4db20f038d94a1398950b161c2275e3af073183f..3a939ac92b9bb1d03044957268c85f1b3e3f6c4d 100644 (file)
@@ -493,6 +493,7 @@ static const struct default_options default_options_table[] =
     { OPT_LEVELS_2_PLUS, OPT_fvect_cost_model_, NULL, VECT_COST_MODEL_CHEAP },
     { OPT_LEVELS_2_PLUS_SPEED_ONLY, OPT_foptimize_strlen, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fhoist_adjacent_loads, NULL, 1 },
+    { OPT_LEVELS_2_PLUS, OPT_fisolate_erroneous_paths, NULL, 1 },
 
     /* -O3 optimizations.  */
     { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
index 31ce11381d8703cbebc8876f8ade8917bfdf2d64..1e2c4dc00ca0e0151946c0229c502920367d52c8 100644 (file)
@@ -126,6 +126,7 @@ along with GCC; see the file COPYING3.  If not see
   /* These passes are run after IPA passes on every function that is being
      output to the assembler file.  */
   INSERT_PASSES_AFTER (all_passes)
+  NEXT_PASS (pass_fixup_cfg);
   NEXT_PASS (pass_lower_eh_dispatch);
   NEXT_PASS (pass_all_optimizations);
   PUSH_INSERT_PASSES_WITHIN (pass_all_optimizations)
@@ -166,9 +167,16 @@ along with GCC; see the file COPYING3.  If not see
         is removed, and this place fits nicely.  Remember this when
         trying to move or duplicate pass_dominator somewhere earlier.  */
       NEXT_PASS (pass_dominator);
+      /* At this point the majority of const/copy propagations
+        are exposed.  Go ahead and identify paths that should never
+        be executed in a conforming program and isolate those paths.
+
+        This will expose more degenerate PHIs in the main path and
+        expose more PRE/DOM optimization opportunities.  */
+      NEXT_PASS (pass_isolate_erroneous_paths);
       /* The only const/copy propagation opportunities left after
-        DOM should be due to degenerate PHI nodes.  So rather than
-        run the full propagators, run a specialized pass which
+        DOM and erroneous path isolation should be due to degenerate PHI nodes.
+        So rather than run the full propagators, run a specialized pass which
         only examines PHIs to discover const/copy propagation
         opportunities.  */
       NEXT_PASS (pass_phi_only_cprop);
index 12a5ce715535e455bfbacaeba8e951bf8b0d0d0b..a0a31a6c2f66de29212e6609164b8c191669a1c4 100644 (file)
@@ -2742,10 +2742,9 @@ tablejump_p (const_rtx insn, rtx *labelp, rtx *tablep)
 
   label = JUMP_LABEL (insn);
   if (label != NULL_RTX && !ANY_RETURN_P (label)
-      && (table = next_active_insn (label)) != NULL_RTX
+      && (table = NEXT_INSN (label)) != NULL_RTX
       && JUMP_TABLE_DATA_P (table))
     {
-      gcc_assert (table == NEXT_INSN (label));
       if (labelp)
        *labelp = label;
       if (tablep)
index c7c780929b81cdf7833cc6e2801e5eb07f3933fb..0f45e9eead479b82076d9c9cbc3a07ee408af68b 100644 (file)
@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3.  If not see
    for other FEs by asan.c.  */
 
 /* Address Sanitizer */
-DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v1",
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v3",
                      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 /* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
    relies on this order.  */
index bf9b10df3a99caf0c3133070f7bc591d66bf372d..73a236b5929a3e08e3cdbfa7f23fa35533f6d976 100644 (file)
@@ -2443,6 +2443,8 @@ add_branch_dependences (rtx head, rtx tail)
      cc0 setters remain at the end because they can't be moved away from
      their cc0 user.
 
+     Predecessors of SCHED_GROUP_P instructions at the end remain at the end.
+
      COND_EXEC insns cannot be moved past a branch (see e.g. PR17808).
 
      Insns setting TARGET_CLASS_LIKELY_SPILLED_P registers (usually return
@@ -2465,7 +2467,8 @@ add_branch_dependences (rtx head, rtx tail)
 #endif
                 || (!reload_completed
                     && sets_likely_spilled (PATTERN (insn)))))
-        || NOTE_P (insn))
+        || NOTE_P (insn)
+        || (last != 0 && SCHED_GROUP_P (last)))
     {
       if (!NOTE_P (insn))
        {
index 4f7a22f8a6516c2ea595bf26ed64b216c3ff29e1..3176f9b197a2fd5f5ae1884142097cb728fc6973 100644 (file)
@@ -29,559 +29,565 @@ along with GCC; see the file COPYING3.  If not see
    "_1" through "_16" versions, plus some extra casts.  */
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_ADD_N, "__sync_fetch_and_add",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_ADD_1, "__sync_fetch_and_add_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_ADD_2, "__sync_fetch_and_add_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_ADD_4, "__sync_fetch_and_add_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_ADD_8, "__sync_fetch_and_add_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_ADD_16, "__sync_fetch_and_add_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_SUB_N, "__sync_fetch_and_sub",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_SUB_1, "__sync_fetch_and_sub_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_SUB_2, "__sync_fetch_and_sub_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_SUB_4, "__sync_fetch_and_sub_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_SUB_8, "__sync_fetch_and_sub_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_SUB_16, "__sync_fetch_and_sub_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_OR_N, "__sync_fetch_and_or",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_OR_1, "__sync_fetch_and_or_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_OR_2, "__sync_fetch_and_or_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_OR_4, "__sync_fetch_and_or_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_OR_8, "__sync_fetch_and_or_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_OR_16, "__sync_fetch_and_or_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_AND_N, "__sync_fetch_and_and",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_AND_1, "__sync_fetch_and_and_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_AND_2, "__sync_fetch_and_and_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_AND_4, "__sync_fetch_and_and_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_AND_8, "__sync_fetch_and_and_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_AND_16, "__sync_fetch_and_and_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_XOR_N, "__sync_fetch_and_xor",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_XOR_1, "__sync_fetch_and_xor_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_XOR_2, "__sync_fetch_and_xor_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_XOR_4, "__sync_fetch_and_xor_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_XOR_8, "__sync_fetch_and_xor_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_XOR_16, "__sync_fetch_and_xor_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_NAND_N, "__sync_fetch_and_nand",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_NAND_1, "__sync_fetch_and_nand_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_NAND_2, "__sync_fetch_and_nand_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_NAND_4, "__sync_fetch_and_nand_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_NAND_8, "__sync_fetch_and_nand_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_FETCH_AND_NAND_16, "__sync_fetch_and_nand_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_ADD_AND_FETCH_N, "__sync_add_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_add_and_fetch_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_add_and_fetch_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_add_and_fetch_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_add_and_fetch_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_ADD_AND_FETCH_16, "__sync_add_and_fetch_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SUB_AND_FETCH_N, "__sync_sub_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SUB_AND_FETCH_1, "__sync_sub_and_fetch_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SUB_AND_FETCH_2, "__sync_sub_and_fetch_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SUB_AND_FETCH_4, "__sync_sub_and_fetch_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SUB_AND_FETCH_8, "__sync_sub_and_fetch_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SUB_AND_FETCH_16, "__sync_sub_and_fetch_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_OR_AND_FETCH_N, "__sync_or_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_OR_AND_FETCH_1, "__sync_or_and_fetch_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_OR_AND_FETCH_2, "__sync_or_and_fetch_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_OR_AND_FETCH_4, "__sync_or_and_fetch_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_OR_AND_FETCH_8, "__sync_or_and_fetch_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_OR_AND_FETCH_16, "__sync_or_and_fetch_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_AND_AND_FETCH_N, "__sync_and_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_AND_AND_FETCH_1, "__sync_and_and_fetch_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_AND_AND_FETCH_2, "__sync_and_and_fetch_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_AND_AND_FETCH_4, "__sync_and_and_fetch_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_AND_AND_FETCH_8, "__sync_and_and_fetch_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_AND_AND_FETCH_16, "__sync_and_and_fetch_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_XOR_AND_FETCH_N, "__sync_xor_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_XOR_AND_FETCH_1, "__sync_xor_and_fetch_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_XOR_AND_FETCH_2, "__sync_xor_and_fetch_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_XOR_AND_FETCH_4, "__sync_xor_and_fetch_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_XOR_AND_FETCH_8, "__sync_xor_and_fetch_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_XOR_AND_FETCH_16, "__sync_xor_and_fetch_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_NAND_AND_FETCH_N, "__sync_nand_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_NAND_AND_FETCH_1, "__sync_nand_and_fetch_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_NAND_AND_FETCH_2, "__sync_nand_and_fetch_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_NAND_AND_FETCH_4, "__sync_nand_and_fetch_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_NAND_AND_FETCH_8, "__sync_nand_and_fetch_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_NAND_AND_FETCH_16, "__sync_nand_and_fetch_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N,
                  "__sync_bool_compare_and_swap",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1,
                  "__sync_bool_compare_and_swap_1",
-                 BT_FN_BOOL_VPTR_I1_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_I1_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2,
                  "__sync_bool_compare_and_swap_2",
-                 BT_FN_BOOL_VPTR_I2_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_I2_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4,
                  "__sync_bool_compare_and_swap_4",
-                 BT_FN_BOOL_VPTR_I4_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_I4_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8,
                  "__sync_bool_compare_and_swap_8",
-                 BT_FN_BOOL_VPTR_I8_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_I8_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16,
                  "__sync_bool_compare_and_swap_16",
-                 BT_FN_BOOL_VPTR_I16_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_I16_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N,
                  "__sync_val_compare_and_swap",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1,
                  "__sync_val_compare_and_swap_1",
-                 BT_FN_I1_VPTR_I1_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2,
                  "__sync_val_compare_and_swap_2",
-                 BT_FN_I2_VPTR_I2_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4,
                  "__sync_val_compare_and_swap_4",
-                 BT_FN_I4_VPTR_I4_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8,
                  "__sync_val_compare_and_swap_8",
-                 BT_FN_I8_VPTR_I8_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16,
                  "__sync_val_compare_and_swap_16",
-                 BT_FN_I16_VPTR_I16_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_TEST_AND_SET_N,
                  "__sync_lock_test_and_set",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_TEST_AND_SET_1,
                  "__sync_lock_test_and_set_1",
-                 BT_FN_I1_VPTR_I1, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_TEST_AND_SET_2,
                  "__sync_lock_test_and_set_2",
-                 BT_FN_I2_VPTR_I2, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_TEST_AND_SET_4,
                  "__sync_lock_test_and_set_4",
-                 BT_FN_I4_VPTR_I4, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_TEST_AND_SET_8,
                  "__sync_lock_test_and_set_8",
-                 BT_FN_I8_VPTR_I8, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_TEST_AND_SET_16,
                  "__sync_lock_test_and_set_16",
-                 BT_FN_I16_VPTR_I16, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_RELEASE_N, "__sync_lock_release",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_RELEASE_1, "__sync_lock_release_1",
-                 BT_FN_VOID_VPTR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_RELEASE_2, "__sync_lock_release_2",
-                 BT_FN_VOID_VPTR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_RELEASE_4, "__sync_lock_release_4",
-                 BT_FN_VOID_VPTR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_RELEASE_8, "__sync_lock_release_8",
-                 BT_FN_VOID_VPTR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_RELEASE_16, "__sync_lock_release_16",
-                 BT_FN_VOID_VPTR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SYNCHRONIZE, "__sync_synchronize",
-                 BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID, ATTR_NOTHROWCALL_LEAF_LIST)
 
 /* __sync* builtins for the C++ memory model.  */
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_TEST_AND_SET, "__atomic_test_and_set",
-                 BT_FN_BOOL_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_CLEAR, "__atomic_clear", BT_FN_VOID_VPTR_INT,
-                 ATTR_NOTHROW_LEAF_LIST)
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE,
                  "__atomic_exchange",
-                 BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_N,
                  "__atomic_exchange_n",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_1,
                  "__atomic_exchange_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_2,
                  "__atomic_exchange_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_4,
                  "__atomic_exchange_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_8,
                  "__atomic_exchange_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_16,
                  "__atomic_exchange_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD,
                  "__atomic_load",
-                 BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT,
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_N,
                  "__atomic_load_n",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_1,
                  "__atomic_load_1",
-                 BT_FN_I1_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_CONST_VPTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_2,
                  "__atomic_load_2",
-                 BT_FN_I2_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_CONST_VPTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_4,
                  "__atomic_load_4",
-                 BT_FN_I4_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_CONST_VPTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_8,
                  "__atomic_load_8",
-                 BT_FN_I8_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_CONST_VPTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_16,
                  "__atomic_load_16",
-                 BT_FN_I16_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_CONST_VPTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE,
                  "__atomic_compare_exchange",
                  BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT,
-                 ATTR_NOTHROW_LEAF_LIST)
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N,
                  "__atomic_compare_exchange_n",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1,
                  "__atomic_compare_exchange_1",
-                 BT_FN_BOOL_VPTR_PTR_I1_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_PTR_I1_BOOL_INT_INT,
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2,
                  "__atomic_compare_exchange_2",
-                 BT_FN_BOOL_VPTR_PTR_I2_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_PTR_I2_BOOL_INT_INT,
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4,
                  "__atomic_compare_exchange_4",
-                 BT_FN_BOOL_VPTR_PTR_I4_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_PTR_I4_BOOL_INT_INT,
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8,
                  "__atomic_compare_exchange_8",
-                 BT_FN_BOOL_VPTR_PTR_I8_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_PTR_I8_BOOL_INT_INT,
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16,
                  "__atomic_compare_exchange_16",
-                 BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT,
+                 ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE,
                  "__atomic_store",
-                 BT_FN_VOID_SIZE_VPTR_PTR_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_SIZE_VPTR_PTR_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_N,
                  "__atomic_store_n",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_1,
                  "__atomic_store_1",
-                 BT_FN_VOID_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_2,
                  "__atomic_store_2",
-                 BT_FN_VOID_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_4,
                  "__atomic_store_4",
-                 BT_FN_VOID_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_8,
                  "__atomic_store_8",
-                 BT_FN_VOID_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_16,
                  "__atomic_store_16",
-                 BT_FN_VOID_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_N,
                  "__atomic_add_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_1,
                  "__atomic_add_fetch_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_2,
                  "__atomic_add_fetch_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_4,
                  "__atomic_add_fetch_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_8,
                  "__atomic_add_fetch_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_16,
                  "__atomic_add_fetch_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_N,
                  "__atomic_sub_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_1,
                  "__atomic_sub_fetch_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_2,
                  "__atomic_sub_fetch_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_4,
                  "__atomic_sub_fetch_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_8,
                  "__atomic_sub_fetch_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_16,
                  "__atomic_sub_fetch_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_N,
                  "__atomic_and_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_1,
                  "__atomic_and_fetch_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_2,
                  "__atomic_and_fetch_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_4,
                  "__atomic_and_fetch_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_8,
                  "__atomic_and_fetch_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_16,
                  "__atomic_and_fetch_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_N,
                  "__atomic_nand_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_1,
                  "__atomic_nand_fetch_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_2,
                  "__atomic_nand_fetch_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_4,
                  "__atomic_nand_fetch_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_8,
                  "__atomic_nand_fetch_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_16,
                  "__atomic_nand_fetch_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_N,
                  "__atomic_xor_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_1,
                  "__atomic_xor_fetch_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_2,
                  "__atomic_xor_fetch_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_4,
                  "__atomic_xor_fetch_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_8,
                  "__atomic_xor_fetch_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_16,
                  "__atomic_xor_fetch_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_N,
                  "__atomic_or_fetch",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_1,
                  "__atomic_or_fetch_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_2,
                  "__atomic_or_fetch_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_4,
                  "__atomic_or_fetch_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_8,
                  "__atomic_or_fetch_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_16,
                  "__atomic_or_fetch_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_N,
                  "__atomic_fetch_add",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_1,
                  "__atomic_fetch_add_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_2,
                  "__atomic_fetch_add_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_4,
                  "__atomic_fetch_add_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_8,
                  "__atomic_fetch_add_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_16,
                  "__atomic_fetch_add_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_N,
                  "__atomic_fetch_sub",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_1,
                  "__atomic_fetch_sub_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_2,
                  "__atomic_fetch_sub_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_4,
                  "__atomic_fetch_sub_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_8,
                  "__atomic_fetch_sub_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_16,
                  "__atomic_fetch_sub_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_N,
                  "__atomic_fetch_and",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_1,
                  "__atomic_fetch_and_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_2,
                  "__atomic_fetch_and_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_4,
                  "__atomic_fetch_and_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_8,
                  "__atomic_fetch_and_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_16,
                  "__atomic_fetch_and_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_N,
                  "__atomic_fetch_nand",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_1,
                  "__atomic_fetch_nand_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_2,
                  "__atomic_fetch_nand_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_4,
                  "__atomic_fetch_nand_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_8,
                  "__atomic_fetch_nand_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_16,
                  "__atomic_fetch_nand_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_N,
                  "__atomic_fetch_xor",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_1,
                  "__atomic_fetch_xor_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_2,
                  "__atomic_fetch_xor_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_4,
                  "__atomic_fetch_xor_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_8,
                  "__atomic_fetch_xor_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_16,
                  "__atomic_fetch_xor_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_N,
                  "__atomic_fetch_or",
-                 BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_1,
                  "__atomic_fetch_or_1",
-                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_2,
                  "__atomic_fetch_or_2",
-                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_4,
                  "__atomic_fetch_or_4",
-                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_8,
                  "__atomic_fetch_or_8",
-                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_16,
                  "__atomic_fetch_or_16",
-                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST)
+                 BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROWCALL_LEAF_LIST)
 
 DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE,
                  "__atomic_always_lock_free",
index dda75374ec7eb632d8c4d94a5857d1250f3bbfce..23aec383953189577f502013e309bfe5dc550483 100644 (file)
@@ -1041,6 +1041,19 @@ scheduling one insn causes other insns to become ready in the same\n\
 cycle.  These other insns can then be taken into account properly.",
  int, (FILE *file, int verbose, rtx *ready, int *n_readyp, int clock), NULL)
 
+DEFHOOK
+(macro_fusion_p,
+ "This hook is used to check whether target platform supports macro fusion.",
+ bool, (void), NULL)
+
+DEFHOOK
+(macro_fusion_pair_p,
+ "This hook is used to check whether two insns could be macro fused for\n\
+target microarchitecture. If this hook returns true for the given insn pair\n\
+(@var{condgen} and @var{condjmp}), scheduler will put them into a sched\n\
+group, and they will not be scheduled apart.",
+ bool, (rtx condgen, rtx condjmp), NULL)
+
 /* The following member value is a pointer to a function called
    after evaluation forward dependencies of insns in chain given
    by two parameter values (head and tail correspondingly).  */
index 1f487d7f82245e99244b6c9aac481487b372d23f..9b5a538e6f725bd5457bab58da7702f3bddf3222 100644 (file)
@@ -1,3 +1,107 @@
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * g++.dg/warn/wdate-time.C: New.
+       * gcc.dg/wdate-time.c: New.
+       * gfortran.dg/wdate-time.F90: New.
+
+2013-11-05  Steven G. Kargl <kargl@gcc.gnu.org>
+
+       PR fortran/58989
+       * gfortran.dg/reshape_6.f90: New test.
+
+2013-10-05  Jeff Law  <law@redhat.com>
+
+       * gcc.dg/pr38984.c: Add -fno-isolate-erroneous-paths.
+       * gcc.dg/tree-ssa/isolate-1.c: New test.
+       * gcc.dg/tree-ssa/isolate-2.c: New test.
+       * gcc.dg/tree-ssa/isolate-3.c: New test.
+       * gcc.dg/tree-ssa/isolate-4.c: New test.
+
+2013-11-05  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/58997
+       * gcc.c-torture/compile/pr58997.c: New test.
+
+2013-11-05  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/58724
+       * g++.dg/cpp0x/gen-attrs-56.C: New.
+
+2013-11-05  Richard Biener  <rguenther@suse.de>
+
+       PR ipa/58492
+       * gcc.dg/ipa/pr58492.c: New testcase.
+
+2013-11-05  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/58955
+       * gcc.dg/torture/pr58955-1.c: New testcase.
+       * gcc.dg/torture/pr58955-2.c: Likewise.
+
+2013-11-05  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR middle-end/58981
+       * gcc.dg/pr58981.c: New test.
+
+2013-11-05  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/58941
+       * gcc.dg/torture/pr58941.c: New testcase.
+
+2013-11-05  Marc Glisse  <marc.glisse@inria.fr>
+
+       PR tree-optimization/58958
+       * gcc.dg/tree-ssa/pr58958.c: New file.
+
+2013-11-05  Marc Glisse  <marc.glisse@inria.fr>
+
+       * gcc.dg/tree-ssa/alias-26.c: New file.
+
+2013-11-05  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/58984
+       * gcc.c-torture/execute/pr58984.c: New test.
+
+2013-11-05  Andreas Schwab  <schwab@suse.de>
+
+       * g++.dg/ext/sync-4.C: Require sync_long_long_runtime support.
+
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * g++.dg/gomp/openmp-simd-1.C: New.
+       * g++.dg/gomp/openmp-simd-2.C: New.
+       * gcc.dg/gomp/openmp-simd-1.c: New.
+       * gcc.dg/gomp/openmp-simd-2.c: New.
+
+2013-11-04  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * gcc.dg/superblock.c: Require scheduling support.
+
+2013-11-04  Kostya Serebryany  <kcc@google.com>
+
+       * g++.dg/asan/asan_test.cc: Update the test
+       to match the fresh asan run-time.
+       * c-c++-common/asan/stack-overflow-1.c: Ditto.
+
+2013-11-04  Ian Lance Taylor  <iant@google.com>
+
+       * g++.dg/ext/sync-4.C: New test.
+
+2013-11-04  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/58771
+       * gfortran.dg/derived_external_function_1.f90 : New test
+
+2013-11-04  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/58978
+       * gcc.c-torture/compile/pr58978.c: New test.
+
+2013-11-04  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/57445
+       * gfortran.dg/optional_class_1.f90 : New test
+
 2013-11-04  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/58968
index 5f563561935d0c5be5143e78daafeb50a685d3ed..c71765097104f16c5a95b7eca2d66a7a1c2ecc6a 100644 (file)
@@ -19,4 +19,5 @@ int main() {
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*stack-overflow-1.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is\[^\n\r]*frame <main>" } */
+/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
+/* { dg-output "\[^\n\r]*in main.*stack-overflow-1.c.*(\n|\r\n|\r)" */
index 76b6e693498d5624c79635596659a0352eb6b7f8..2df8c62cbb1157dd4024b1426a55e69c875f70b3 100644 (file)
@@ -204,16 +204,6 @@ TEST(AddressSanitizer, BitFieldNegativeTest) {
   delete Ident(x);
 }
 
-TEST(AddressSanitizer, OutOfMemoryTest) {
-  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
-  EXPECT_EQ(0, realloc(0, size));
-  EXPECT_EQ(0, realloc(0, ~Ident(0)));
-  EXPECT_EQ(0, malloc(size));
-  EXPECT_EQ(0, malloc(~Ident(0)));
-  EXPECT_EQ(0, calloc(1, size));
-  EXPECT_EQ(0, calloc(1, ~Ident(0)));
-}
-
 #if ASAN_NEEDS_SEGV
 namespace {
 
@@ -497,42 +487,6 @@ TEST(AddressSanitizer, ManyStackObjectsTest) {
   EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
 }
 
-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");
-}
-
 NOINLINE void LongJmpFunc1(jmp_buf buf) {
   // create three red zones for these two stack objects.
   int a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-56.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-56.C
new file mode 100644 (file)
index 0000000..f331ed3
--- /dev/null
@@ -0,0 +1,5 @@
+// PR c++/58724
+// { dg-do compile { target c++11 } }
+
+namespace foo __attribute__((visibility("default"))) {}
+namespace bar [[gnu::visibility("default")]] {}
diff --git a/gcc/testsuite/g++.dg/ext/sync-4.C b/gcc/testsuite/g++.dg/ext/sync-4.C
new file mode 100644 (file)
index 0000000..14ed273
--- /dev/null
@@ -0,0 +1,122 @@
+/* { dg-do run { target hppa*-*-hpux* *-*-linux* *-*-gnu* powerpc*-*-darwin* *-*-darwin[912]* } } */
+/* { dg-require-effective-target sync_long_long_runtime } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -O2" } */
+
+/* Verify that the builtin functions are correctly marked as trapping
+   when using -fnon-call-exceptions.  */
+
+#include <stdlib.h>
+#include <signal.h>
+
+typedef int int32_t __attribute__ ((mode (SI)));
+typedef int int64_t __attribute__ ((mode (DI)));
+
+#define FN(IDX, RET, CALL)                                     \
+static RET f ## IDX (void *p) __attribute__ ((noinline));      \
+static RET                                                     \
+f ## IDX (void *p)                                             \
+{                                                              \
+  return CALL;                                                 \
+}                                                              \
+static void                                                    \
+t ## IDX ()                                                    \
+{                                                              \
+  try                                                          \
+    {                                                          \
+      f ## IDX(0);                                             \
+    }                                                          \
+  catch (...)                                                  \
+    {                                                          \
+      return;                                                  \
+    }                                                          \
+  abort();                                                     \
+}
+
+FN(1, int64_t, (__sync_fetch_and_add((int64_t*)p, 1)))
+FN(2, int64_t, (__sync_fetch_and_sub((int64_t*)p, 1)))
+FN(3, int64_t, (__sync_fetch_and_or((int64_t*)p, 1)))
+FN(4, int64_t, (__sync_fetch_and_and((int64_t*)p, 1)))
+FN(5, int64_t, (__sync_fetch_and_xor((int64_t*)p, 1)))
+FN(6, int64_t, (__sync_fetch_and_nand((int64_t*)p, 1)))
+
+FN( 7, int64_t, (__sync_add_and_fetch((int64_t*)p, 1)))
+FN( 8, int64_t, (__sync_sub_and_fetch((int64_t*)p, 1)))
+FN( 9, int64_t, (__sync_or_and_fetch((int64_t*)p, 1)))
+FN(10, int64_t, (__sync_and_and_fetch((int64_t*)p, 1)))
+FN(11, int64_t, (__sync_xor_and_fetch((int64_t*)p, 1)))
+FN(12, int64_t, (__sync_nand_and_fetch((int64_t*)p, 1)))
+
+FN(13, bool, (__sync_bool_compare_and_swap((int64_t*)p, 1, 2)))
+FN(14, int64_t, (__sync_val_compare_and_swap((int64_t*)p, 1, 2)))
+
+FN(15, int64_t, (__sync_lock_test_and_set((int64_t*)p, 1)))
+FN(16, void, (__sync_lock_release((int64_t*)p)))
+
+FN(17, bool, (__atomic_test_and_set((int64_t*)p, __ATOMIC_SEQ_CST)))
+FN(18, void, (__atomic_clear((int64_t*)p, __ATOMIC_SEQ_CST)))
+
+FN(19, void, (__atomic_exchange((int64_t*)p, (int64_t*)0, (int64_t*)0, __ATOMIC_SEQ_CST)))
+FN(20, int64_t, (__atomic_exchange_n((int64_t*)p, 1, 2)))
+
+FN(21, void, (__atomic_load((int64_t*)p, (int64_t*)0, __ATOMIC_SEQ_CST)))
+FN(22, int64_t, (__atomic_load_n((int64_t*)p, __ATOMIC_SEQ_CST)))
+
+FN(23, bool, (__atomic_compare_exchange((int64_t*)p, (int64_t*)0, (int64_t*)0, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)))
+FN(24, bool, (__atomic_compare_exchange_n((int64_t*)p, (int64_t*)0, 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)))
+
+FN(25, void, (__atomic_store((int64_t*)p, (int64_t*)0, __ATOMIC_SEQ_CST)))
+FN(26, void, (__atomic_store_n((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+
+FN(27, int64_t, (__atomic_add_fetch((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(28, int64_t, (__atomic_sub_fetch((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(29, int64_t, (__atomic_and_fetch((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(30, int64_t, (__atomic_nand_fetch((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(31, int64_t, (__atomic_xor_fetch((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(32, int64_t, (__atomic_or_fetch((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+
+FN(33, int64_t, (__atomic_fetch_add((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(34, int64_t, (__atomic_fetch_sub((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(35, int64_t, (__atomic_fetch_and((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(36, int64_t, (__atomic_fetch_nand((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(37, int64_t, (__atomic_fetch_xor((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+FN(38, int64_t, (__atomic_fetch_or((int64_t*)p, 1, __ATOMIC_SEQ_CST)))
+
+static void
+handler(int)
+{
+  sigset_t clear;
+
+  sigfillset (&clear);
+  sigprocmask (SIG_UNBLOCK, &clear, NULL);
+  throw 0;
+}
+
+int
+main ()
+{
+  signal (SIGSEGV, handler);
+  signal (SIGBUS, handler);
+
+  t1();
+  t2();
+  t3();
+  t4();
+  t5();
+  t6();
+  t7();
+  t8();
+  t9();
+  t10();
+  t11();
+  t12();
+  t13();
+  t14();
+  t15();
+  t16();
+  t17();
+  t18();
+  t19();
+  t20();
+
+  exit(0);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/openmp-simd-1.C b/gcc/testsuite/g++.dg/gomp/openmp-simd-1.C
new file mode 100644 (file)
index 0000000..fedb186
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp-simd -fdump-tree-original" } */
+
+#pragma omp declare simd
+float bar(float b) {
+  return b*b;
+}
+
+void foo(int n, float *a, float *b)
+{
+  int i; 
+#pragma omp simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "pragma omp simd" 9 "original" } } */
+/* { dg-final { scan-tree-dump-not "omp for" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp distribute" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp teams" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp target" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/openmp-simd-2.C b/gcc/testsuite/g++.dg/gomp/openmp-simd-2.C
new file mode 100644 (file)
index 0000000..e31c1eb
--- /dev/null
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp-simd -fdump-tree-original" } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+  int i, u = 0;
+  struct S s, t;
+  s.s = 0; t.s = 0;
+  #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u)
+  for (i = 0; i < 1024; i++)
+    {
+      int x = a[i];
+      s.s += x;
+      t.s += x;
+      u += x;
+    }
+  if (t.s != s.s || u != s.s)
+    abort ();
+  return s.s;
+}
+
+
+void bar(int n, float *a, float *b)
+{
+  int i; 
+#pragma omp parallel for simd num_threads(4) safelen(64)
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "Function void omp declare reduction operator\\+" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "Function void omp declare reduction foo" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "pragma omp simd reduction\\(u\\) reduction\\(t\\) reduction\\(\\+:s\\) aligned\\(a:32\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "pragma omp simd safelen\\(64\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp for" "original" } } */
diff --git a/gcc/testsuite/g++.dg/init/array35.C b/gcc/testsuite/g++.dg/init/array35.C
new file mode 100644 (file)
index 0000000..6ce6d5c
--- /dev/null
@@ -0,0 +1,3 @@
+// PR c++/58868
+
+static struct { const int i; } a[] = { 1 };
diff --git a/gcc/testsuite/g++.dg/warn/wdate-time.C b/gcc/testsuite/g++.dg/warn/wdate-time.C
new file mode 100644 (file)
index 0000000..040dd99
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-Wdate-time" } */
+
+const char time[] = __TIME__;  /* { dg-warning "might prevent reproduce builds" }  */
+const char date[] = __DATE__;  /* { dg-warning "might prevent reproduce builds" }  */
+const char timestamp[] = __TIMESTAMP__;  /* { dg-warning "might prevent reproduce builds" }  */
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr58978.c b/gcc/testsuite/gcc.c-torture/compile/pr58978.c
new file mode 100644 (file)
index 0000000..721801d
--- /dev/null
@@ -0,0 +1,16 @@
+/* PR tree-optimization/58978 */
+
+int
+foo (int x)
+{
+  switch (x)
+    {
+    case 0:
+    case 1:
+    case 9:
+      break;
+    default:
+      __builtin_unreachable ();
+    }
+  return x;
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr58997.c b/gcc/testsuite/gcc.c-torture/compile/pr58997.c
new file mode 100644 (file)
index 0000000..2c7a0f8
--- /dev/null
@@ -0,0 +1,19 @@
+/* PR rtl-optimization/58997 */
+
+int a, b, c, e;
+short d;
+char h;
+
+void
+foo ()
+{
+  while (b)
+    {
+      d = a ? c : 1 % a;
+      c = d;
+      h = d;
+      if (!h)
+       while (e)
+         ;
+    }
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr58984.c b/gcc/testsuite/gcc.c-torture/execute/pr58984.c
new file mode 100644 (file)
index 0000000..e0f7669
--- /dev/null
@@ -0,0 +1,57 @@
+/* PR tree-optimization/58984 */
+
+struct S { int f0 : 8; int : 6; int f1 : 5; };
+struct T { char f0; int : 6; int f1 : 5; };
+
+int a, *c = &a, e, n, b, m;
+
+static int
+foo (struct S p)
+{
+  const unsigned short *f[36];
+  for (; e < 2; e++)
+    {
+      const unsigned short **i = &f[0];
+      *c ^= 1;
+      if (p.f1)
+       {
+         *i = 0;
+         return b;
+       }
+    }
+  return 0;
+}
+
+static int
+bar (struct T p)
+{
+  const unsigned short *f[36];
+  for (; e < 2; e++)
+    {
+      const unsigned short **i = &f[0];
+      *c ^= 1;
+      if (p.f1)
+       {
+         *i = 0;
+         return b;
+       }
+    }
+  return 0;
+}
+
+int
+main ()
+{
+  struct S o = { 1, 1 };
+  foo (o);
+  m = n || o.f0;
+  if (a != 1)
+    __builtin_abort ();
+  e = 0;
+  struct T p = { 1, 1 };
+  bar (p);
+  m |= n || p.f0;
+  if (a != 0)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/openmp-simd-1.c b/gcc/testsuite/gcc.dg/gomp/openmp-simd-1.c
new file mode 100644 (file)
index 0000000..fedb186
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp-simd -fdump-tree-original" } */
+
+#pragma omp declare simd
+float bar(float b) {
+  return b*b;
+}
+
+void foo(int n, float *a, float *b)
+{
+  int i; 
+#pragma omp simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "pragma omp simd" 9 "original" } } */
+/* { dg-final { scan-tree-dump-not "omp for" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp distribute" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp teams" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp target" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */
diff --git a/gcc/testsuite/gcc.dg/gomp/openmp-simd-2.c b/gcc/testsuite/gcc.dg/gomp/openmp-simd-2.c
new file mode 100644 (file)
index 0000000..e668068
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp-simd -fdump-tree-original" } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+  int i, u = 0;
+  struct S s, t;
+  s.s = 0; t.s = 0;
+  #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u)
+  for (i = 0; i < 1024; i++)
+    {
+      int x = a[i];
+      s.s += x;
+      t.s += x;
+      u += x;
+    }
+  if (t.s != s.s || u != s.s)
+    abort ();
+  return s.s;
+}
+
+
+void bar(int n, float *a, float *b)
+{
+  int i; 
+#pragma omp parallel for simd num_threads(4) safelen(64)
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "pragma omp simd reduction\\(u\\) reduction\\(t\\) reduction\\(\\+:s\\) aligned\\(a:32\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "pragma omp simd safelen\\(64\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp for" "original" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/pr58492.c b/gcc/testsuite/gcc.dg/ipa/pr58492.c
new file mode 100644 (file)
index 0000000..79958d5
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fipa-pta" } */
+
+void f(int p, short q)
+{
+  f(0, 0);
+}
index 11f1e7f211a695531c9c0925aa7ec719ebd985c7..0c031805ea80fa5a16d434a3fa2666d42a973cfc 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-delete-null-pointer-checks -fdump-tree-optimized" }
+/* { dg-options "-O2 -fno-delete-null-pointer-checks -fdump-tree-optimized -fno-isolate-erroneous-paths" }
  * */
 
 int f(int *p)
diff --git a/gcc/testsuite/gcc.dg/pr58981.c b/gcc/testsuite/gcc.dg/pr58981.c
new file mode 100644 (file)
index 0000000..1c8293e
--- /dev/null
@@ -0,0 +1,55 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-minline-all-stringops" { target { i?86-*-* x86_64-*-* } } } */
+
+extern void abort (void);
+
+#define MAX_OFFSET (sizeof (long long))
+#define MAX_COPY (8 * sizeof (long long))
+#define MAX_EXTRA (sizeof (long long))
+
+#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA)
+
+static union {
+  char buf[MAX_LENGTH];
+  long long align_int;
+  long double align_fp;
+} u;
+
+char A[MAX_LENGTH];
+
+int
+main ()
+{
+  int off, len, i;
+  char *p, *q;
+
+  for (i = 0; i < MAX_LENGTH; i++)
+    A[i] = 'A';
+
+  for (off = 0; off < MAX_OFFSET; off++)
+    for (len = 1; len < MAX_COPY; len++)
+      {
+       for (i = 0; i < MAX_LENGTH; i++)
+         u.buf[i] = 'a';
+
+       p = __builtin_memcpy (u.buf + off, A, len);
+       if (p != u.buf + off)
+         abort ();
+
+       q = u.buf;
+       for (i = 0; i < off; i++, q++)
+         if (*q != 'a')
+           abort ();
+
+       for (i = 0; i < len; i++, q++)
+         if (*q != 'A')
+           abort ();
+
+       for (i = 0; i < MAX_EXTRA; i++, q++)
+         if (*q != 'a')
+           abort ();
+      }
+
+  return 0;
+}
index 2b9aedfdac4808f2369888ec91d47b7e37e7631f..272d161f058c731740838156ba6f970ea89519dd 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fno-asynchronous-unwind-tables -fsched2-use-superblocks -fdump-rtl-sched2 -fdump-rtl-bbro" } */
+/* { dg-require-effective-target scheduling } */
 
 typedef int aligned __attribute__ ((aligned (64)));
 extern void abort (void);
diff --git a/gcc/testsuite/gcc.dg/torture/pr58941.c b/gcc/testsuite/gcc.dg/torture/pr58941.c
new file mode 100644 (file)
index 0000000..c0eea07
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+typedef struct {
+    int msgLength;
+    unsigned char data[1000];
+} SMsg;
+
+typedef struct {
+    int dummy;
+    int d[0];
+} SData;
+
+int condition = 3;
+
+int main()
+{
+  SMsg msg;
+  SData *pData = (SData*)(msg.data);
+  unsigned int i = 0;
+  for (i = 0; i < 1; i++)
+    {
+      pData->d[i] = 0;
+      if(condition & 1)
+       pData->d[i] |= 0x55;
+      if(condition & 2)
+       pData->d[i] |= 0xaa;
+    }
+  if (pData->d[0] != 0xff)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr58955-1.c b/gcc/testsuite/gcc.dg/torture/pr58955-1.c
new file mode 100644 (file)
index 0000000..a79f42f
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+int a, b, c, d[4] = { 0, 0, 0, 1 };
+
+int
+main ()
+{
+  for (; a < 4; a++)
+    {
+      int e = d[a];
+      for (c = 1; c < 1; c++);
+      b = e;
+      d[a] = 0;
+    }
+  if (b != 1)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr58955-2.c b/gcc/testsuite/gcc.dg/torture/pr58955-2.c
new file mode 100644 (file)
index 0000000..a43860e
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+int a, b[10];
+
+int
+main ()
+{
+  for (; a < 2; a++)
+    {
+      b[a] = 1;
+      b[a + 1] = 0;
+    }
+  if (b[1] != 1)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-26.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-26.c
new file mode 100644 (file)
index 0000000..a1eb8f7
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+void f (const char *c, int *i)
+{
+  *i = 42;
+  __builtin_memcpy (i - 1, c, sizeof (int));
+  if (*i != 42) __builtin_abort();
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c
new file mode 100644 (file)
index 0000000..6b779b4
--- /dev/null
@@ -0,0 +1,58 @@
+
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+
+
+struct demangle_component
+{
+
+  int type;
+  int zzz;
+
+};
+
+
+struct d_info
+{
+  struct demangle_component *comps;
+  int next_comp;
+  int num_comps;
+};
+
+
+static struct demangle_component *
+d_make_empty (struct d_info *di)
+{
+  struct demangle_component *p;
+
+  if (di->next_comp >= di->num_comps)
+    return ((void *)0);
+  p = &di->comps[di->next_comp];
+  return p;
+}
+
+
+
+struct demangle_component *
+d_type (struct d_info *di)
+{
+   struct demangle_component *ret;
+   ret = d_make_empty (di);
+   ret->type = 42;
+   ret->zzz = -1;
+   return ret;
+}
+
+/* We're testing two aspects of isolation here.  First that isolation
+   occurs, second that if we have two null dereferences in a block that
+   that we delete everything from the first dereferece to the end of the
+   block, regardless of which comes first in the immediate use iterator.  */
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+
+
+
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c
new file mode 100644 (file)
index 0000000..290b44c
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */
+
+
+int z;
+int y;
+
+int * foo(int a) __attribute__((returns_nonnull));
+int * bar(void) __attribute__((returns_nonnull));
+
+int *
+foo(int a)
+
+{
+  switch (a)
+    {
+      case 0:
+        return &z;
+      default:
+        return (int *)0;
+    }
+}
+
+
+int *
+bar (void)
+{
+  return 0;
+}
+
+/* We testing that the path isolation code can take advantage of the
+   returns non-null attribute to isolate a path where NULL flows into
+   a return statement.  We test this twice, once where the NULL flows
+   from a PHI, the second with an explicit return 0 in the IL.
+
+   We also verify that after isolation phi-cprop simplifies the
+   return statement so that it returns &z directly.
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "return &z;" 1 "phicprop1"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+/* { dg-final { cleanup-tree-dump "phicprop1" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c
new file mode 100644 (file)
index 0000000..7dddd80
--- /dev/null
@@ -0,0 +1,65 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+
+
+typedef long unsigned int size_t;
+extern void *memset (void *__s, int __c, size_t __n)
+  __attribute__ ((__nothrow__, __leaf__)) __attribute__ ((__nonnull__ (1)));
+struct rtx_def;
+typedef struct rtx_def *rtx;
+typedef struct VEC_rtx_base
+
+{
+  unsigned num;
+  unsigned alloc;
+  rtx vec[1];
+} VEC_rtx_base;
+static __inline__ rtx *
+VEC_rtx_base_address (VEC_rtx_base * vec_)
+{
+  return vec_ ? vec_->vec : 0;
+}
+typedef struct VEC_rtx_gc
+{
+  VEC_rtx_base base;
+} VEC_rtx_gc;
+
+static __inline__ void
+VEC_rtx_gc_safe_grow (VEC_rtx_gc ** vec_, int size_, const char *file_,
+                      unsigned line_, const char *function_)
+{
+  ((*vec_) ? &(*vec_)->base : 0)->num = size_;
+} 
+
+static __inline__ void
+VEC_rtx_gc_safe_grow_cleared (VEC_rtx_gc ** vec_, int size_,
+                              const char *file_, unsigned line_,
+                              const char *function_, int oldsize)
+{
+  VEC_rtx_gc_safe_grow (vec_, size_, file_, line_, function_);
+  memset (&(VEC_rtx_base_address ((*vec_) ? &(*vec_)->base : 0))[oldsize], 0,
+          sizeof (rtx) * (size_ - oldsize));
+}
+
+static VEC_rtx_gc *reg_base_value;
+void
+init_alias_analysis (void)
+{
+  unsigned int maxreg = max_reg_num ();
+  (VEC_rtx_gc_safe_grow_cleared
+   (&(reg_base_value), maxreg, "../../../gcc-4.6.0/gcc/alias.c", 2755,
+    __FUNCTION__, arf ()));
+}
+
+
+
+/* This is an example of how a NULL pointer dereference can show up
+   without a PHI.  Note VEC_rtx_gcc_safe_grow.  If an earlier pass
+   (such as VRP) isolates the NULL path for some reason or another
+   we end up with an explicit NULL dereference in the IL.  Yes, it
+   started with a PHI, but by the time the path isolation code runs
+   its explicit in the IL.  */
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c
new file mode 100644 (file)
index 0000000..6937d25
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */
+
+
+extern void foo(void *) __attribute__ ((__nonnull__ (1)));
+
+int z;
+
+void
+com (int a)
+{
+    foo (a == 42 ? &z  : (void *) 0);
+}
+
+void
+bar (void)
+{
+  foo ((void *)0);
+}
+
+/* We testing that the path isolation code can take advantage of the
+   returns non-null attribute to isolate a path where NULL flows into
+   a return statement.
+
+   We also verify that after isolation phi-cprop simplifies the
+   return statement so that it returns &z directly.
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "foo .&z.;" 1 "phicprop1"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+/* { dg-final { cleanup-tree-dump "phicprop1" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr58958.c b/gcc/testsuite/gcc.dg/tree-ssa/pr58958.c
new file mode 100644 (file)
index 0000000..faf377f
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+double a[10];
+int f(int n){
+  a[3]=9;
+  __builtin_memset(&a[n],3,sizeof(double));
+  return a[3]==9;
+}
+
+/* { dg-final { scan-tree-dump " == 9" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/wdate-time.c b/gcc/testsuite/gcc.dg/wdate-time.c
new file mode 100644 (file)
index 0000000..040dd99
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-Wdate-time" } */
+
+const char time[] = __TIME__;  /* { dg-warning "might prevent reproduce builds" }  */
+const char date[] = __DATE__;  /* { dg-warning "might prevent reproduce builds" }  */
+const char timestamp[] = __TIMESTAMP__;  /* { dg-warning "might prevent reproduce builds" }  */
diff --git a/gcc/testsuite/gfortran.dg/derived_external_function_1.f90 b/gcc/testsuite/gfortran.dg/derived_external_function_1.f90
new file mode 100644 (file)
index 0000000..7421c4c
--- /dev/null
@@ -0,0 +1,27 @@
+! { dg-do run }
+!
+! PR fortran/58771
+!
+! Contributed by Vittorio Secca  <zeccav@gmail.com>
+!
+! ICEd on the write statement with f() because the derived type backend
+! declaration not built.
+!
+module m
+  type t
+    integer(4) g
+  end type
+end
+
+type(t) function f() result(ff)
+  use m
+  ff%g = 42
+end
+
+  use m
+  character (20) :: line1, line2
+  type(t)  f
+  write (line1, *) f()
+  write (line2, *) 42_4
+  if (line1 .ne. line2) call abort
+end
diff --git a/gcc/testsuite/gfortran.dg/optional_class_1.f90 b/gcc/testsuite/gfortran.dg/optional_class_1.f90
new file mode 100644 (file)
index 0000000..589fc60
--- /dev/null
@@ -0,0 +1,45 @@
+! { dg-do run }
+!
+! PR fortran/57445
+!
+! Contributed by Tobias Burnus  <burnus@gcc.gnu.org>
+!
+! Spurious assert was added at revision 192495
+!
+module m
+  implicit none
+  type t
+    integer :: i
+  end type t
+contains
+  subroutine opt(xa, xc, xaa, xca)
+    type(t),  allocatable, intent(out), optional :: xa
+    class(t), allocatable, intent(out), optional :: xc
+    type(t),  allocatable, intent(out), optional :: xaa(:)
+    class(t), allocatable, intent(out), optional :: xca(:)
+    if (present (xca)) call foo_opt(xca=xca)
+  end subroutine opt
+  subroutine foo_opt(xa, xc, xaa, xca)
+    type(t),  allocatable, intent(out), optional :: xa
+    class(t), allocatable, intent(out), optional :: xc
+    type(t),  allocatable, intent(out), optional :: xaa(:)
+    class(t), allocatable, intent(out), optional :: xca(:)
+    if (present (xca)) then
+      if (allocated (xca)) deallocate (xca)
+      allocate (xca(3), source = [t(9),t(99),t(999)])
+    end if
+  end subroutine foo_opt
+end module m
+  use m
+  class(t), allocatable :: xca(:)
+  allocate (xca(1), source = t(42))
+  select type (xca)
+    type is (t)
+      if (any (xca%i .ne. [42])) call abort
+  end select
+  call opt (xca = xca)
+  select type (xca)
+    type is (t)
+      if (any (xca%i .ne. [9,99,999])) call abort
+  end select
+end
diff --git a/gcc/testsuite/gfortran.dg/reshape_6.f90 b/gcc/testsuite/gfortran.dg/reshape_6.f90
new file mode 100644 (file)
index 0000000..149f31e
--- /dev/null
@@ -0,0 +1,19 @@
+! { dg-do compile }
+! PR fortran/58989
+!
+program test
+
+  real(8), dimension(4,4) :: fluxes
+  real(8), dimension(2,2,2,2) :: f
+  integer, dimension(3) :: dmmy 
+  integer, parameter :: indx(4)=(/2,2,2,2/)
+
+  fluxes = 1
+
+  dmmy = (/2,2,2/)
+
+  f = reshape(fluxes,(/dmmy,2/))  ! Caused an ICE
+  f = reshape(fluxes,(/2,2,2,2/)) ! Works as expected
+  f = reshape(fluxes,indx)        ! Works as expected
+
+end program test
diff --git a/gcc/testsuite/gfortran.dg/wdate-time.F90 b/gcc/testsuite/gfortran.dg/wdate-time.F90
new file mode 100644 (file)
index 0000000..f3a4f46
--- /dev/null
@@ -0,0 +1,6 @@
+! { dg-do compile }
+! { dg-options "-Wdate-time" }
+print *, __TIMESTAMP__  ! { dg-warning "might prevent reproduce builds" }
+print *, __TIME__  ! { dg-warning "might prevent reproduce builds" }
+print *, __DATE__  ! { dg-warning "might prevent reproduce builds" }
+end
index 66d61aecc4daca5758ac5a0c213d9839b9378c83..afdadb878a7e9290665d65812770685f29cacd15 100644 (file)
@@ -144,6 +144,7 @@ DEFTIMEVAR (TV_TREE_SSA_INCREMENTAL  , "tree SSA incremental")
 DEFTIMEVAR (TV_TREE_OPS                     , "tree operand scan")
 DEFTIMEVAR (TV_TREE_SSA_DOMINATOR_OPTS   , "dominator optimization")
 DEFTIMEVAR (TV_TREE_SRA              , "tree SRA")
+DEFTIMEVAR (TV_ISOLATE_ERRONEOUS_PATHS    , "isolate eroneous paths")
 DEFTIMEVAR (TV_TREE_CCP                     , "tree CCP")
 DEFTIMEVAR (TV_TREE_PHI_CPROP       , "tree PHI const/copy prop")
 DEFTIMEVAR (TV_TREE_SPLIT_EDGES      , "tree split crit edges")
index 13b27599aea995875e14bd7b86d06ab9c67b0566..47413f2e2fee2851b2c5fd2ff57a8202f940707c 100644 (file)
@@ -389,7 +389,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
   offset_int bit_offset = 0;
   HOST_WIDE_INT hbit_offset;
   bool seen_variable_array_ref = false;
-  tree base_type;
 
   /* First get the final access size from just the outermost expression.  */
   if (TREE_CODE (exp) == COMPONENT_REF)
@@ -420,8 +419,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
      and find the ultimate containing object.  */
   while (1)
     {
-      base_type = TREE_TYPE (exp);
-
       switch (TREE_CODE (exp))
        {
        case BIT_FIELD_REF:
@@ -545,7 +542,38 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
        case VIEW_CONVERT_EXPR:
          break;
 
+       case TARGET_MEM_REF:
+         /* Via the variable index or index2 we can reach the
+            whole object.  Still hand back the decl here.  */
+         if (TREE_CODE (TMR_BASE (exp)) == ADDR_EXPR
+             && (TMR_INDEX (exp) || TMR_INDEX2 (exp)))
+           {
+             exp = TREE_OPERAND (TMR_BASE (exp), 0);
+             bit_offset = 0;
+             maxsize = -1;
+             goto done;
+           }
+         /* Fallthru.  */
        case MEM_REF:
+         /* We need to deal with variable arrays ending structures such as
+            struct { int length; int a[1]; } x;           x.a[d]
+            struct { struct { int a; int b; } a[1]; } x;  x.a[d].a
+            struct { struct { int a[1]; } a[1]; } x;      x.a[0][d], x.a[d][0]
+            struct { int len; union { int a[1]; struct X x; } u; } x; x.u.a[d]
+            where we do not know maxsize for variable index accesses to
+            the array.  The simplest way to conservatively deal with this
+            is to punt in the case that offset + maxsize reaches the
+            base type boundary.  This needs to include possible trailing
+            padding that is there for alignment purposes.  */
+         if (seen_variable_array_ref
+             && maxsize != -1
+             && (!bit_offset.fits_shwi ()
+                 || !tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (exp)))
+                 || (bit_offset.to_shwi () + maxsize
+                     == (signed) tree_to_uhwi
+                           (TYPE_SIZE (TREE_TYPE (exp))))))
+           maxsize = -1;
+
          /* Hand back the decl for MEM[&decl, off].  */
          if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
            {
@@ -566,44 +594,23 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
            }
          goto done;
 
-       case TARGET_MEM_REF:
-         /* Hand back the decl for MEM[&decl, off].  */
-         if (TREE_CODE (TMR_BASE (exp)) == ADDR_EXPR)
-           {
-             /* Via the variable index or index2 we can reach the
-                whole object.  */
-             if (TMR_INDEX (exp) || TMR_INDEX2 (exp))
-               {
-                 exp = TREE_OPERAND (TMR_BASE (exp), 0);
-                 bit_offset = 0;
-                 maxsize = -1;
-                 goto done;
-               }
-             if (integer_zerop (TMR_OFFSET (exp)))
-               exp = TREE_OPERAND (TMR_BASE (exp), 0);
-             else
-               {
-                 offset_int off = mem_ref_offset (exp);
-                 off = wi::lshift (off, (BITS_PER_UNIT == 8
-                                         ? 3 : exact_log2 (BITS_PER_UNIT)));
-                 off += bit_offset;
-                 if (wi::fits_shwi_p (off))
-                   {
-                     bit_offset = off;
-                     exp = TREE_OPERAND (TMR_BASE (exp), 0);
-                   }
-               }
-           }
-         goto done;
-
        default:
          goto done;
        }
 
       exp = TREE_OPERAND (exp, 0);
     }
- done:
 
+  /* We need to deal with variable arrays ending structures.  */
+  if (seen_variable_array_ref
+      && maxsize != -1
+      && (!bit_offset.fits_shwi ()
+         || !tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (exp)))
+         || (bit_offset.to_shwi () + maxsize
+             == (signed) tree_to_uhwi (TYPE_SIZE (TREE_TYPE (exp))))))
+    maxsize = -1;
+
+ done:
   if (!wi::fits_shwi_p (bit_offset))
     {
       *poffset = 0;
@@ -615,24 +622,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
 
   hbit_offset = bit_offset.to_shwi ();
 
-  /* We need to deal with variable arrays ending structures such as
-       struct { int length; int a[1]; } x;           x.a[d]
-       struct { struct { int a; int b; } a[1]; } x;  x.a[d].a
-       struct { struct { int a[1]; } a[1]; } x;      x.a[0][d], x.a[d][0]
-       struct { int len; union { int a[1]; struct X x; } u; } x; x.u.a[d]
-     where we do not know maxsize for variable index accesses to
-     the array.  The simplest way to conservatively deal with this
-     is to punt in the case that offset + maxsize reaches the
-     base type boundary.  This needs to include possible trailing padding
-     that is there for alignment purposes.  */
-
-  if (seen_variable_array_ref
-      && maxsize != -1
-      && (!tree_fits_uhwi_p (TYPE_SIZE (base_type))
-         || (hbit_offset + maxsize
-             == (signed) tree_to_uhwi (TYPE_SIZE (base_type)))))
-    maxsize = -1;
-
   /* In case of a decl or constant base object we can do better.  */
 
   if (DECL_P (exp))
index 79884bf4272621fcb556ed38afec54899ab991d5..4f9b848847a9718c3b6bfac07d7eab34aa209b0a 100644 (file)
@@ -1324,7 +1324,7 @@ pg_add_dependence_edges (struct graph *rdg, vec<loop_p> loops, int dir,
   for (int ii = 0; drs1.iterate (ii, &dr1); ++ii)
     for (int jj = 0; drs2.iterate (jj, &dr2); ++jj)
       {
-       int this_dir = 1;
+       int this_dir = -1;
        ddr_p ddr;
        /* Re-shuffle data-refs to be in dominator order.  */
        if (rdg_vertex_for_stmt (rdg, DR_STMT (dr1))
index 1e982857e14122e55751ddb8dd569ecc05268602..4dc3f9e4a8d9cf8ac26eb877cb9861f79899dc4e 100644 (file)
@@ -548,6 +548,23 @@ eliminate_name (elim_graph g, int T)
   elim_graph_add_node (g, T);
 }
 
+/* Return true if this phi argument T should have a copy queued when using
+   var_map MAP.  PHI nodes should contain only ssa_names and invariants.  A
+   test for ssa_name is definitely simpler, but don't let invalid contents
+   slip through in the meantime.  */
+
+static inline bool
+queue_phi_copy_p (var_map map, tree t)
+{
+  if (TREE_CODE (t) == SSA_NAME)
+    { 
+      if (var_to_partition (map, t) == NO_PARTITION)
+        return true;
+      return false;
+    }
+  gcc_checking_assert (is_gimple_min_invariant (t));
+  return true;
+}
 
 /* Build elimination graph G for basic block BB on incoming PHI edge
    G->e.  */
@@ -577,9 +594,7 @@ eliminate_build (elim_graph g)
       /* If this argument is a constant, or a SSA_NAME which is being
         left in SSA form, just queue a copy to be emitted on this
         edge.  */
-      if (!phi_ssa_name_p (Ti)
-         || (TREE_CODE (Ti) == SSA_NAME
-             && var_to_partition (g->map, Ti) == NO_PARTITION))
+      if (queue_phi_copy_p (g->map, Ti))
         {
          /* Save constant copies until all other copies have been emitted
             on this edge.  */
index c4d09fe0821fa1a3d9fd795ba7413ff78439513f..3aeaeeb114b3e294b14139283be671f574f74353 100644 (file)
@@ -425,6 +425,7 @@ extern gimple_opt_pass *make_pass_sink_code (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
index 1a58ce722ed4593009d82789de169e10a7058528..a0c4ce3cb57b7d21dd40a19c26719fedad8eae7e 100644 (file)
@@ -559,14 +559,14 @@ ao_ref_alias_set (ao_ref *ref)
 }
 
 /* Init an alias-oracle reference representation from a gimple pointer
-   PTR and a gimple size SIZE in bytes.  If SIZE is NULL_TREE the the
+   PTR and a gimple size SIZE in bytes.  If SIZE is NULL_TREE then the
    size is assumed to be unknown.  The access is assumed to be only
    to or after of the pointer target, not before it.  */
 
 void
 ao_ref_init_from_ptr_and_size (ao_ref *ref, tree ptr, tree size)
 {
-  HOST_WIDE_INT t1, t2, extra_offset = 0;
+  HOST_WIDE_INT t, extra_offset = 0;
   ref->ref = NULL_TREE;
   if (TREE_CODE (ptr) == SSA_NAME)
     {
@@ -576,17 +576,26 @@ ao_ref_init_from_ptr_and_size (ao_ref *ref, tree ptr, tree size)
        ptr = gimple_assign_rhs1 (stmt);
       else if (is_gimple_assign (stmt)
               && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
-              && tree_fits_shwi_p (gimple_assign_rhs2 (stmt))
-              && (t1 = int_cst_value (gimple_assign_rhs2 (stmt))) >= 0)
+              && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST)
        {
          ptr = gimple_assign_rhs1 (stmt);
-         extra_offset = BITS_PER_UNIT * t1;
+         extra_offset = BITS_PER_UNIT
+                        * int_cst_value (gimple_assign_rhs2 (stmt));
        }
     }
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
-    ref->base = get_ref_base_and_extent (TREE_OPERAND (ptr, 0),
-                                        &ref->offset, &t1, &t2);
+    {
+      ref->base = get_addr_base_and_unit_offset (TREE_OPERAND (ptr, 0), &t);
+      if (ref->base)
+       ref->offset = BITS_PER_UNIT * t;
+      else
+       {
+         size = NULL_TREE;
+         ref->offset = 0;
+         ref->base = get_base_address (TREE_OPERAND (ptr, 0));
+       }
+    }
   else
     {
       ref->base = build2 (MEM_REF, char_type_node,
index 831cffebecba627b0831f1394f4cef20b0d80744..581cd82a5f368cfeccc37ec73d6cb0efb2142fa9 100644 (file)
@@ -146,18 +146,18 @@ extern GTY(()) struct pt_solution ipa_escaped_pt;
    range is open-ended.  Otherwise return false.  */
 
 static inline bool
-ranges_overlap_p (unsigned HOST_WIDE_INT pos1,
+ranges_overlap_p (HOST_WIDE_INT pos1,
                  unsigned HOST_WIDE_INT size1,
-                 unsigned HOST_WIDE_INT pos2,
+                 HOST_WIDE_INT pos2,
                  unsigned HOST_WIDE_INT size2)
 {
   if (pos1 >= pos2
       && (size2 == (unsigned HOST_WIDE_INT)-1
-         || pos1 < (pos2 + size2)))
+         || pos1 < (pos2 + (HOST_WIDE_INT) size2)))
     return true;
   if (pos2 >= pos1
       && (size1 == (unsigned HOST_WIDE_INT)-1
-         || pos2 < (pos1 + size1)))
+         || pos2 < (pos1 + (HOST_WIDE_INT) size1)))
     return true;
 
   return false;
index 9072ce11673921409ae16cf91f79c1010af5c65a..585df718221f7cbf31c865083b13d52de32cf6de 100644 (file)
@@ -236,100 +236,6 @@ flush_pending_stmts (edge e)
   redirect_edge_var_map_clear (e);
 }
 
-
-/* Data structure used to count the number of dereferences to PTR
-   inside an expression.  */
-struct count_ptr_d
-{
-  tree ptr;
-  unsigned num_stores;
-  unsigned num_loads;
-};
-
-
-/* Helper for count_uses_and_derefs.  Called by walk_tree to look for
-   (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
-
-static tree
-count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
-{
-  struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data;
-  struct count_ptr_d *count_p = (struct count_ptr_d *) wi_p->info;
-
-  /* Do not walk inside ADDR_EXPR nodes.  In the expression &ptr->fld,
-     pointer 'ptr' is *not* dereferenced, it is simply used to compute
-     the address of 'fld' as 'ptr + offsetof(fld)'.  */
-  if (TREE_CODE (*tp) == ADDR_EXPR)
-    {
-      *walk_subtrees = 0;
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (*tp) == MEM_REF && TREE_OPERAND (*tp, 0) == count_p->ptr)
-    {
-      if (wi_p->is_lhs)
-       count_p->num_stores++;
-      else
-       count_p->num_loads++;
-    }
-
-  return NULL_TREE;
-}
-
-
-/* Count the number of direct and indirect uses for pointer PTR in
-   statement STMT.  The number of direct uses is stored in
-   *NUM_USES_P.  Indirect references are counted separately depending
-   on whether they are store or load operations.  The counts are
-   stored in *NUM_STORES_P and *NUM_LOADS_P.  */
-
-void
-count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p,
-                      unsigned *num_loads_p, unsigned *num_stores_p)
-{
-  ssa_op_iter i;
-  tree use;
-
-  *num_uses_p = 0;
-  *num_loads_p = 0;
-  *num_stores_p = 0;
-
-  /* Find out the total number of uses of PTR in STMT.  */
-  FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
-    if (use == ptr)
-      (*num_uses_p)++;
-
-  /* Now count the number of indirect references to PTR.  This is
-     truly awful, but we don't have much choice.  There are no parent
-     pointers inside INDIRECT_REFs, so an expression like
-     '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to
-     find all the indirect and direct uses of x_1 inside.  The only
-     shortcut we can take is the fact that GIMPLE only allows
-     INDIRECT_REFs inside the expressions below.  */
-  if (is_gimple_assign (stmt)
-      || gimple_code (stmt) == GIMPLE_RETURN
-      || gimple_code (stmt) == GIMPLE_ASM
-      || is_gimple_call (stmt))
-    {
-      struct walk_stmt_info wi;
-      struct count_ptr_d count;
-
-      count.ptr = ptr;
-      count.num_stores = 0;
-      count.num_loads = 0;
-
-      memset (&wi, 0, sizeof (wi));
-      wi.info = &count;
-      walk_gimple_op (stmt, count_ptr_derefs, &wi);
-
-      *num_stores_p = count.num_stores;
-      *num_loads_p = count.num_loads;
-    }
-
-  gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p);
-}
-
-
 /* Replace the LHS of STMT, an assignment, either a GIMPLE_ASSIGN or a
    GIMPLE_CALL, with NLHS, in preparation for modifying the RHS to an
    expression with a different value.
index ab1c920ff837e5cbd257846c4012bb7561856e10..89ea5c64c76583101e11a70a2268dab5117f78b3 100644 (file)
@@ -39,8 +39,6 @@ extern edge_var_map_vector *redirect_edge_var_map_vector (edge);
 extern void redirect_edge_var_map_destroy (void);
 extern edge ssa_redirect_edge (edge, basic_block);
 extern void flush_pending_stmts (edge);
-extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *,
-                                  unsigned *);
 extern void gimple_replace_ssa_lhs (gimple, tree);
 extern tree target_for_debug_bind (tree);
 extern void insert_debug_temp_for_var_def (gimple_stmt_iterator *, tree);
index 03fb075193d51503e03320646260c17dbd8ca8eb..6c3f988b991bfc826d573a8763394e34eab8e54a 100644 (file)
@@ -4402,57 +4402,6 @@ fp_predicate (gimple stmt)
   return FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)));
 }
 
-
-/* If OP can be inferred to be non-zero after STMT executes, return true.  */
-
-static bool
-infer_nonnull_range (gimple stmt, tree op)
-{
-  /* We can only assume that a pointer dereference will yield
-     non-NULL if -fdelete-null-pointer-checks is enabled.  */
-  if (!flag_delete_null_pointer_checks
-      || !POINTER_TYPE_P (TREE_TYPE (op))
-      || gimple_code (stmt) == GIMPLE_ASM)
-    return false;
-
-  unsigned num_uses, num_loads, num_stores;
-
-  count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
-  if (num_loads + num_stores > 0)
-    return true;
-
-  if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
-    {
-      tree fntype = gimple_call_fntype (stmt);
-      tree attrs = TYPE_ATTRIBUTES (fntype);
-      for (; attrs; attrs = TREE_CHAIN (attrs))
-       {
-         attrs = lookup_attribute ("nonnull", attrs);
-
-         /* If "nonnull" wasn't specified, we know nothing about
-            the argument.  */
-         if (attrs == NULL_TREE)
-           return false;
-
-         /* If "nonnull" applies to all the arguments, then ARG
-            is non-null.  */
-         if (TREE_VALUE (attrs) == NULL_TREE)
-           return true;
-
-         /* Now see if op appears in the nonnull list.  */
-         for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t))
-           {
-             int idx = tree_to_shwi (TREE_VALUE (t)) - 1;
-             tree arg = gimple_call_arg (stmt, idx);
-             if (op == arg)
-               return true;
-           }
-       }
-    }
-
-  return false;
-}
-
 /* If the range of values taken by OP can be inferred after STMT executes,
    return the comparison code (COMP_CODE_P) and value (VAL_P) that
    describes the inferred range.  Return true if a range could be
@@ -6399,13 +6348,14 @@ all_imm_uses_in_stmt_or_feed_cond (tree var, gimple stmt, basic_block cond_bb)
   FOR_EACH_IMM_USE_FAST (use_p, iter, var)
     if (USE_STMT (use_p) != stmt)
       {
-       gimple use_stmt = USE_STMT (use_p);
+       gimple use_stmt = USE_STMT (use_p), use_stmt2;
        if (is_gimple_debug (use_stmt))
          continue;
        while (is_gimple_assign (use_stmt)
+              && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
               && single_imm_use (gimple_assign_lhs (use_stmt),
-                                 &use2_p, &use_stmt))
-         ;
+                                 &use2_p, &use_stmt2))
+         use_stmt = use_stmt2;
        if (gimple_code (use_stmt) != GIMPLE_COND
            || gimple_bb (use_stmt) != cond_bb)
          return false;
index 133dbb16da9117f15877a7ae9d4f3056ae1225cf..562c0107c751503033dbe6f2d061743391561c16 100644 (file)
@@ -4825,7 +4825,7 @@ attribute_value_equal (const_tree attr1, const_tree attr2)
     return (simple_cst_list_equal (TREE_VALUE (attr1),
                                   TREE_VALUE (attr2)) == 1);
 
-  if (flag_openmp
+  if ((flag_openmp || flag_openmp_simd)
       && TREE_VALUE (attr1) && TREE_VALUE (attr2)
       && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
       && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
index f3c331507d55212ba8249ad03d082d6f33065f56..78252e0d0887df079b3461fb6947ee518d628231 100644 (file)
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -187,9 +187,7 @@ vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve,
       num = pfx->m_num;
     }
   else if (!reserve)
-    /* If there's no vector, and we've not requested anything, then we
-       will create a NULL vector.  */
-    return 0;
+    gcc_unreachable ();
 
   /* We must have run out of room.  */
   gcc_assert (alloc - num < reserve);
index f97e022f24a5c06c341ccc7e4ee78c4f7a0d86d1..b1ebda44f5e17049d9f27da7f4523191a3b86f5c 100644 (file)
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -283,11 +283,7 @@ va_heap::reserve (vec<T, va_heap, vl_embed> *&v, unsigned reserve, bool exact
 {
   unsigned alloc
     = vec_prefix::calculate_allocation (v ? &v->m_vecpfx : 0, reserve, exact);
-  if (!alloc)
-    {
-      release (v);
-      return;
-    }
+  gcc_assert (alloc);
 
   if (GATHER_STATISTICS && v)
     v->m_vecpfx.release_overhead ();
index a21f1429a71a4be066fc7fec61eb9f334885030d..024eda5723149baa510a28198959fad82347e9f0 100644 (file)
@@ -1,3 +1,9 @@
+2013-11-04  Balaji V. Iyer  <balaji.v.iyer@intel.com>
+
+       PR bootstrap/58951
+       * Makefile.am (AM_LDFLAGS): Removed -ldl flag.
+       * Makefile.in: Regenerate.
+
 2013-11-04  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * runtime/os-unix.c [__sun__ && __svr4__]: Include <sched.h>.
index a3b07efb68b47e3940641df5bb69ddacc42623e5..1a8bafaa1f3c611256d849e41009ed866b45e540 100644 (file)
@@ -45,7 +45,7 @@ GENERAL_FLAGS += -fcilkplus
 
 AM_CFLAGS = $(GENERAL_FLAGS) -std=c99
 AM_CPPFLAGS = $(GENERAL_FLAGS)
-AM_LDFLAGS = -lpthread -ldl
+AM_LDFLAGS = -lpthread 
 
 # May be used by toolexeclibdir.
 gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
index 9f459cccf16ebe81705d8696550fea3b39964e09..a35eb7b63bc545b15cdbf68a9e2cc23eeb601bce 100644 (file)
@@ -349,7 +349,7 @@ GENERAL_FLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/runtime \
        -D_Cilk_for=for -fcilkplus
 AM_CFLAGS = $(GENERAL_FLAGS) -std=c99
 AM_CPPFLAGS = $(GENERAL_FLAGS)
-AM_LDFLAGS = -lpthread -ldl
+AM_LDFLAGS = -lpthread 
 
 # May be used by toolexeclibdir.
 gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
index 2e98e34887e7f09be9deac3075ba2d7083f8cb5b..670affd90e763c55811d520e50e01adb3ed48dd1 100644 (file)
@@ -1,6 +1,14 @@
+2013-11-05  Tobias Burnus  <burnus@net-b.de>
+
+       * include/cpplib.h (CPP_W_DATE_TIME): Added.
+       (cpp_options): Add warn_date_time.
+       * init.c (cpp_create_reader): Init it.
+       * macro.c (_cpp_builtin_macro_text): Warn when
+       __DATE__/__TIME__/__TIMESTAMP__ is used.
+
 2013-10-31  Edward Smith-Rowland  <3dw4rd@verizon.net>
 
-        Implement C++14 digit separators.
+       Implement C++14 digit separators.
        * include/cpplib.h (cpp_options): Add digit_separators flag.
        * internal.h (DIGIT_SEP(c)): New macro.
        * expr.c (cpp_classify_number): Check improper placement of digit sep;
index 34ad6c30c8ee9aec17944761fd71631beab85f35..02927d4c6cbe826664de373a4715148609720dc2 100644 (file)
@@ -337,6 +337,9 @@ struct cpp_options
   /* Nonzero means warn if slash-star appears in a comment.  */
   unsigned char warn_comments;
 
+  /* Nonzero means to warn about __DATA__, __TIME__ and __TIMESTAMP__ usage.   */
+  unsigned char warn_date_time;
+
   /* Nonzero means warn if a user-supplied include directory does not
      exist.  */
   unsigned char warn_missing_include_dirs;
@@ -925,7 +928,8 @@ enum {
   CPP_W_NORMALIZE,
   CPP_W_INVALID_PCH,
   CPP_W_WARNING_DIRECTIVE,
-  CPP_W_LITERAL_SUFFIX
+  CPP_W_LITERAL_SUFFIX,
+  CPP_W_DATE_TIME
 };
 
 /* Output a diagnostic of some kind.  */
index 97aa6cdd45fa408f64c9594694d9825bde6e4198..67444301590b503a19c3965be7e4131b990b49cc 100644 (file)
@@ -193,6 +193,7 @@ cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
   CPP_OPTION (pfile, canonical_system_headers)
       = ENABLE_CANONICAL_SYSTEM_HEADERS;
   CPP_OPTION (pfile, ext_numeric_literals) = 1;
+  CPP_OPTION (pfile, warn_date_time) = 0;
 
   /* Default CPP arithmetic to something sensible for the host for the
      benefit of dumb users like fix-header.  */
index 6d46027e4ea4a0e36ff0b98d18ee071917ddf7cf..3a1728d66636f4e9c4958fd5220bac41df650aec 100644 (file)
@@ -232,6 +232,10 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node)
 
     case BT_TIMESTAMP:
       {
+       if (CPP_OPTION (pfile, warn_date_time))
+         cpp_warning (pfile, CPP_W_DATE_TIME, "Macro \"%s\" might prevent "
+                      "reproduce builds", NODE_NAME (node));
+
        cpp_buffer *pbuffer = cpp_get_buffer (pfile);
        if (pbuffer->timestamp == NULL)
          {
@@ -325,6 +329,9 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node)
 
     case BT_DATE:
     case BT_TIME:
+      if (CPP_OPTION (pfile, warn_date_time))
+       cpp_warning (pfile, CPP_W_DATE_TIME, "Macro \"%s\" might prevent "
+                    "reproduce builds", NODE_NAME (node));
       if (pfile->date == NULL)
        {
          /* Allocate __DATE__ and __TIME__ strings from permanent
index 30b53c94ea88ffe9faa14e792e52a24f1708b304..41bf1c55ff46e121c203d6f435ca55f171a4e44f 100644 (file)
@@ -1,3 +1,12 @@
+2013-11-05  Uros Bizjak  <ubizjak@gmail.com>
+
+       * config/i386/32/sfp-machine.h (_FP_MUL_MEAT_S): Define.
+       (_FP_MUL_MEAT_D): Ditto.
+       (_FP_DIV_MEAT_S): Ditto.
+       (_FP_DIV_MEAT_D): Ditto.
+       * config.host (i[34567]86-*-rtems*): Remove i386/t-softfp, add
+       t-softfp-sfdf and t-softfp to tmake_file.
+
 2013-11-03  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/crtfastmath.c: Compile only for !_SOFT_FLOAT.
index 905b816b0dd4f13136042630c7587065901c3038..325ed84ad90ea0479d9861ac4954b905c41f28d0 100644 (file)
@@ -564,7 +564,7 @@ i[34567]86-*-nto-qnx*)
        extra_parts=crtbegin.o
        ;;
 i[34567]86-*-rtems*)
-       tmake_file="$tmake_file i386/t-softfp i386/t-crtstuff"
+       tmake_file="$tmake_file i386/t-crtstuff t-softfp-sfdf t-softfp"
        extra_parts="$extra_parts crti.o crtn.o"
        ;;
 i[34567]86-*-solaris2* | x86_64-*-solaris2.1[0-9]*)
index 143296d69ff189da4ed0bb6426b9b3575285cf29..b9eb16633ebcb8f1a1cdbb10364e29a2519efc20 100644 (file)
             "g" ((USItype) (y0)))
 
 
+#define _FP_MUL_MEAT_S(R,X,Y)                          \
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)                          \
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
 #define _FP_MUL_MEAT_Q(R,X,Y)                          \
   _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
 
+#define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_loop(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv(D,R,X,Y)
 #define _FP_DIV_MEAT_Q(R,X,Y)   _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
 
 #define _FP_NANFRAC_S          _FP_QNANBIT_S
index 9d33782441e74f27846fcce02982307053dcf17d..c7871e3295fe84e88682043f57efbd5db2aca117 100644 (file)
@@ -1,3 +1,19 @@
+2013-11-04  Kostya Serebryany  <kcc@google.com>
+
+       * All source files: Merge from upstream r191666.
+       * merge.sh: Added lsan.
+       * configure.ac (AC_CONFIG_FILES): Added lsan.
+       * Makefile.am (SUBDIRS): Added lsan.
+       * sanitizer_common/Makefile.am (sanitizer_common_files): Added new fles.
+       * asan/Makefile.am (asan_files): Added new files.
+       (libasan_la_LIBADD): Added a dependency on lsan.
+       * lsan/Makefile.am: New file.
+       * asan/Makefile.in: Regenerate.
+       * lsan/Makefile.in: Regenerate.
+       * Makefile.in: Regenerate.
+       * configure: Regenerate.
+       * sanitizer_common/Makefile.in: Regenerate.
+
 2013-09-20  Alan Modra  <amodra@gmail.com>
 
        * configure: Regenerate.
index 28d1e49ab773ecd764aa1034f10b26ac260f2964..0431b147a16bc7af0e8f6fde6393c3d03aef6fec 100644 (file)
@@ -1,4 +1,4 @@
-175733
+191666
 
 The first line of this file holds the svn revision number of the
 last merge done from the master library sources.
index 739c33babbeb76b772a120413b01e48cda1d66f6..15c11ecb2d72cf55d2fd7220afabd97d3757db13 100644 (file)
@@ -1,13 +1,13 @@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 
 if TSAN_SUPPORTED
-SUBDIRS = interception sanitizer_common asan tsan ubsan
+SUBDIRS = interception sanitizer_common lsan asan tsan ubsan
 else
-SUBDIRS = interception sanitizer_common asan ubsan
+SUBDIRS = interception sanitizer_common lsan asan ubsan
 endif
 
 if USING_MAC_INTERPOSE
-SUBDIRS = sanitizer_common asan ubsan
+SUBDIRS = sanitizer_common lsan asan ubsan
 endif
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
index 286cea611380f20fceb60061859dfcae4440a3c3..47a8771c7831caa347430d7b74aea8070425e2a0 100644 (file)
@@ -76,7 +76,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
        $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = interception sanitizer_common asan ubsan tsan
+DIST_SUBDIRS = interception sanitizer_common lsan asan ubsan tsan
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
 AR = @AR@
@@ -209,9 +209,9 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
-@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan ubsan
-@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan ubsan
-@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan ubsan
+@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common lsan asan ubsan
+@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common lsan asan tsan ubsan
+@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common lsan asan ubsan
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
index f7847db36471bd19f1d892631ec08ca3fcff1889..8764007ca4517fe365d379edf2ea265a01c75bdb 100644 (file)
@@ -15,32 +15,31 @@ toolexeclib_LTLIBRARIES = libasan.la
 nodist_toolexeclib_HEADERS = libasan_preinit.o
 
 asan_files = \
-       asan_allocator.cc \
        asan_allocator2.cc \
-       asan_interceptors.cc \
-       asan_mac.cc \
-       asan_malloc_mac.cc \
-       asan_new_delete.cc \
-       asan_posix.cc \
-       asan_rtl.cc \
-       asan_stats.cc \
-       asan_thread_registry.cc \
+       asan_dll_thunk.cc \
        asan_fake_stack.cc \
        asan_globals.cc \
+       asan_interceptors.cc \
        asan_linux.cc \
+       asan_mac.cc \
        asan_malloc_linux.cc \
+       asan_malloc_mac.cc \
        asan_malloc_win.cc \
+       asan_new_delete.cc \
        asan_poisoning.cc \
+       asan_posix.cc \
        asan_report.cc \
+       asan_rtl.cc \
        asan_stack.cc \
+       asan_stats.cc \
        asan_thread.cc \
        asan_win.cc
 
 libasan_la_SOURCES = $(asan_files)
 if USING_MAC_INTERPOSE
-libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la
+libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/lsan/libsanitizer_lsan.la
 else
-libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la
+libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/lsan/libsanitizer_lsan.la $(top_builddir)/interception/libinterception.la
 endif
 libasan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS)
 
index 1db6fa3da719545e96fc78404bdcfa364f64e588..be8b879b54952442481fff7aae6a2f797253409c 100644 (file)
@@ -81,17 +81,18 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
 LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 @USING_MAC_INTERPOSE_FALSE@libasan_la_DEPENDENCIES = $(top_builddir)/sanitizer_common/libsanitizer_common.la \
+@USING_MAC_INTERPOSE_FALSE@    $(top_builddir)/lsan/libsanitizer_lsan.la \
 @USING_MAC_INTERPOSE_FALSE@    $(top_builddir)/interception/libinterception.la \
 @USING_MAC_INTERPOSE_FALSE@    $(am__DEPENDENCIES_1)
 @USING_MAC_INTERPOSE_TRUE@libasan_la_DEPENDENCIES = $(top_builddir)/sanitizer_common/libsanitizer_common.la \
+@USING_MAC_INTERPOSE_TRUE@     $(top_builddir)/lsan/libsanitizer_lsan.la \
 @USING_MAC_INTERPOSE_TRUE@     $(am__DEPENDENCIES_1)
-am__objects_1 = asan_allocator.lo asan_allocator2.lo \
-       asan_interceptors.lo asan_mac.lo asan_malloc_mac.lo \
-       asan_new_delete.lo asan_posix.lo asan_rtl.lo asan_stats.lo \
-       asan_thread_registry.lo asan_fake_stack.lo asan_globals.lo \
-       asan_linux.lo asan_malloc_linux.lo asan_malloc_win.lo \
-       asan_poisoning.lo asan_report.lo asan_stack.lo asan_thread.lo \
-       asan_win.lo
+am__objects_1 = asan_allocator2.lo asan_dll_thunk.lo \
+       asan_fake_stack.lo asan_globals.lo asan_interceptors.lo \
+       asan_linux.lo asan_mac.lo asan_malloc_linux.lo \
+       asan_malloc_mac.lo asan_malloc_win.lo asan_new_delete.lo \
+       asan_poisoning.lo asan_posix.lo asan_report.lo asan_rtl.lo \
+       asan_stack.lo asan_stats.lo asan_thread.lo asan_win.lo
 am_libasan_la_OBJECTS = $(am__objects_1)
 libasan_la_OBJECTS = $(am_libasan_la_OBJECTS)
 libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -260,32 +261,33 @@ ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 toolexeclib_LTLIBRARIES = libasan.la
 nodist_toolexeclib_HEADERS = libasan_preinit.o
 asan_files = \
-       asan_allocator.cc \
        asan_allocator2.cc \
-       asan_interceptors.cc \
-       asan_mac.cc \
-       asan_malloc_mac.cc \
-       asan_new_delete.cc \
-       asan_posix.cc \
-       asan_rtl.cc \
-       asan_stats.cc \
-       asan_thread_registry.cc \
+       asan_dll_thunk.cc \
        asan_fake_stack.cc \
        asan_globals.cc \
+       asan_interceptors.cc \
        asan_linux.cc \
+       asan_mac.cc \
        asan_malloc_linux.cc \
+       asan_malloc_mac.cc \
        asan_malloc_win.cc \
+       asan_new_delete.cc \
        asan_poisoning.cc \
+       asan_posix.cc \
        asan_report.cc \
+       asan_rtl.cc \
        asan_stack.cc \
+       asan_stats.cc \
        asan_thread.cc \
        asan_win.cc
 
 libasan_la_SOURCES = $(asan_files)
 @USING_MAC_INTERPOSE_FALSE@libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la \
+@USING_MAC_INTERPOSE_FALSE@    $(top_builddir)/lsan/libsanitizer_lsan.la \
 @USING_MAC_INTERPOSE_FALSE@    $(top_builddir)/interception/libinterception.la \
 @USING_MAC_INTERPOSE_FALSE@    $(LIBSTDCXX_RAW_CXX_LDFLAGS)
 @USING_MAC_INTERPOSE_TRUE@libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la \
+@USING_MAC_INTERPOSE_TRUE@     $(top_builddir)/lsan/libsanitizer_lsan.la \
 @USING_MAC_INTERPOSE_TRUE@     $(LIBSTDCXX_RAW_CXX_LDFLAGS)
 libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` -lpthread -ldl
 
@@ -402,8 +404,8 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_allocator.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_allocator2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_dll_thunk.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_fake_stack.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors.Plo@am__quote@
@@ -420,7 +422,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stack.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stats.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread_registry.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win.Plo@am__quote@
 
 .cc.o:
diff --git a/libsanitizer/asan/asan_allocator.cc b/libsanitizer/asan/asan_allocator.cc
deleted file mode 100644 (file)
index 4e97ff5..0000000
+++ /dev/null
@@ -1,811 +0,0 @@
-//===-- asan_allocator.cc -------------------------------------------------===//
-//
-// 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.
-// Evey piece of memory (AsanChunk) allocated by the allocator
-// has a left redzone of REDZONE bytes and
-// a right redzone such that the end of the chunk is aligned by REDZONE
-// (i.e. the right redzone is between 0 and REDZONE-1).
-// The left redzone is always poisoned.
-// The right redzone is poisoned on malloc, the body is poisoned on free.
-// Once freed, a chunk is moved to a quarantine (fifo list).
-// After quarantine, a chunk is returned to freelists.
-//
-// The left redzone contains ASan's internal data and the stack trace of
-// the malloc call.
-// Once freed, the body of the chunk contains the stack trace of the free call.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_allocator.h"
-
-#if ASAN_ALLOCATOR_VERSION == 1
-#include "asan_interceptors.h"
-#include "asan_internal.h"
-#include "asan_mapping.h"
-#include "asan_stats.h"
-#include "asan_report.h"
-#include "asan_thread.h"
-#include "asan_thread_registry.h"
-#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_atomic.h"
-#include "sanitizer_common/sanitizer_mutex.h"
-
-namespace __asan {
-
-#define REDZONE ((uptr)(flags()->redzone))
-static const uptr kMinAllocSize = REDZONE * 2;
-static const u64 kMaxAvailableRam = 128ULL << 30;  // 128G
-static const uptr kMaxThreadLocalQuarantine = 1 << 20;  // 1M
-
-static const uptr kMinMmapSize = (ASAN_LOW_MEMORY) ? 4UL << 17 : 4UL << 20;
-static const uptr kMaxSizeForThreadLocalFreeList =
-    (ASAN_LOW_MEMORY) ? 1 << 15 : 1 << 17;
-
-// Size classes less than kMallocSizeClassStep are powers of two.
-// All other size classes are multiples of kMallocSizeClassStep.
-static const uptr kMallocSizeClassStepLog = 26;
-static const uptr kMallocSizeClassStep = 1UL << kMallocSizeClassStepLog;
-
-static const uptr kMaxAllowedMallocSize =
-    (SANITIZER_WORDSIZE == 32) ? 3UL << 30 : 8UL << 30;
-
-static inline uptr SizeClassToSize(u8 size_class) {
-  CHECK(size_class < kNumberOfSizeClasses);
-  if (size_class <= kMallocSizeClassStepLog) {
-    return 1UL << size_class;
-  } else {
-    return (size_class - kMallocSizeClassStepLog) * kMallocSizeClassStep;
-  }
-}
-
-static inline u8 SizeToSizeClass(uptr size) {
-  u8 res = 0;
-  if (size <= kMallocSizeClassStep) {
-    uptr rounded = RoundUpToPowerOfTwo(size);
-    res = Log2(rounded);
-  } else {
-    res = ((size + kMallocSizeClassStep - 1) / kMallocSizeClassStep)
-        + kMallocSizeClassStepLog;
-  }
-  CHECK(res < kNumberOfSizeClasses);
-  CHECK(size <= SizeClassToSize(res));
-  return res;
-}
-
-// Given REDZONE bytes, we need to mark first size bytes
-// as addressable and the rest REDZONE-size bytes as unaddressable.
-static void PoisonHeapPartialRightRedzone(uptr mem, uptr size) {
-  CHECK(size <= REDZONE);
-  CHECK(IsAligned(mem, REDZONE));
-  CHECK(IsPowerOfTwo(SHADOW_GRANULARITY));
-  CHECK(IsPowerOfTwo(REDZONE));
-  CHECK(REDZONE >= SHADOW_GRANULARITY);
-  PoisonShadowPartialRightRedzone(mem, size, REDZONE,
-                                  kAsanHeapRightRedzoneMagic);
-}
-
-static u8 *MmapNewPagesAndPoisonShadow(uptr size) {
-  CHECK(IsAligned(size, GetPageSizeCached()));
-  u8 *res = (u8*)MmapOrDie(size, __FUNCTION__);
-  PoisonShadow((uptr)res, size, kAsanHeapLeftRedzoneMagic);
-  if (flags()->debug) {
-    Printf("ASAN_MMAP: [%p, %p)\n", res, res + size);
-  }
-  return res;
-}
-
-// 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.
-//
-// The pseudo state CHUNK_MEMALIGN is used to mark that the address is not
-// the beginning of a AsanChunk (in which the actual chunk resides at
-// this - this->used_size).
-//
-// The magic numbers for the enum values are taken randomly.
-enum {
-  CHUNK_AVAILABLE  = 0x57,
-  CHUNK_ALLOCATED  = 0x32,
-  CHUNK_QUARANTINE = 0x19,
-  CHUNK_MEMALIGN   = 0xDC
-};
-
-struct ChunkBase {
-  // First 8 bytes.
-  uptr  chunk_state : 8;
-  uptr  alloc_tid   : 24;
-  uptr  size_class  : 8;
-  uptr  free_tid    : 24;
-
-  // Second 8 bytes.
-  uptr alignment_log : 8;
-  uptr alloc_type    : 2;
-  uptr used_size : FIRST_32_SECOND_64(32, 54);  // Size requested by the user.
-
-  // This field may overlap with the user area and thus should not
-  // be used while the chunk is in CHUNK_ALLOCATED state.
-  AsanChunk *next;
-
-  // Typically the beginning of the user-accessible memory is 'this'+REDZONE
-  // and is also aligned by REDZONE. However, if the memory is allocated
-  // by memalign, the alignment might be higher and the user-accessible memory
-  // starts at the first properly aligned address after 'this'.
-  uptr Beg() { return RoundUpTo((uptr)this + 1, 1 << alignment_log); }
-  uptr Size() { return SizeClassToSize(size_class); }
-  u8 SizeClass() { return size_class; }
-};
-
-struct AsanChunk: public ChunkBase {
-  u32 *compressed_alloc_stack() {
-    return (u32*)((uptr)this + sizeof(ChunkBase));
-  }
-  u32 *compressed_free_stack() {
-    return (u32*)((uptr)this + Max((uptr)REDZONE, (uptr)sizeof(ChunkBase)));
-  }
-
-  // The left redzone after the ChunkBase is given to the alloc stack trace.
-  uptr compressed_alloc_stack_size() {
-    if (REDZONE < sizeof(ChunkBase)) return 0;
-    return (REDZONE - sizeof(ChunkBase)) / sizeof(u32);
-  }
-  uptr compressed_free_stack_size() {
-    if (REDZONE < sizeof(ChunkBase)) return 0;
-    return (REDZONE) / sizeof(u32);
-  }
-};
-
-uptr AsanChunkView::Beg() { return chunk_->Beg(); }
-uptr AsanChunkView::End() { return Beg() + UsedSize(); }
-uptr AsanChunkView::UsedSize() { return chunk_->used_size; }
-uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
-uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
-
-void AsanChunkView::GetAllocStack(StackTrace *stack) {
-  StackTrace::UncompressStack(stack, chunk_->compressed_alloc_stack(),
-                              chunk_->compressed_alloc_stack_size());
-}
-
-void AsanChunkView::GetFreeStack(StackTrace *stack) {
-  StackTrace::UncompressStack(stack, chunk_->compressed_free_stack(),
-                              chunk_->compressed_free_stack_size());
-}
-
-static AsanChunk *PtrToChunk(uptr ptr) {
-  AsanChunk *m = (AsanChunk*)(ptr - REDZONE);
-  if (m->chunk_state == CHUNK_MEMALIGN) {
-    m = (AsanChunk*)((uptr)m - m->used_size);
-  }
-  return m;
-}
-
-void AsanChunkFifoList::PushList(AsanChunkFifoList *q) {
-  CHECK(q->size() > 0);
-  size_ += q->size();
-  append_back(q);
-  q->clear();
-}
-
-void AsanChunkFifoList::Push(AsanChunk *n) {
-  push_back(n);
-  size_ += n->Size();
-}
-
-// Interesting performance observation: this function takes up to 15% of overal
-// allocator time. That's because *first_ has been evicted from cache long time
-// ago. Not sure if we can or want to do anything with this.
-AsanChunk *AsanChunkFifoList::Pop() {
-  CHECK(first_);
-  AsanChunk *res = front();
-  size_ -= res->Size();
-  pop_front();
-  return res;
-}
-
-// All pages we ever allocated.
-struct PageGroup {
-  uptr beg;
-  uptr end;
-  uptr size_of_chunk;
-  uptr last_chunk;
-  bool InRange(uptr addr) {
-    return addr >= beg && addr < end;
-  }
-};
-
-class MallocInfo {
- public:
-  explicit MallocInfo(LinkerInitialized x) : mu_(x) { }
-
-  AsanChunk *AllocateChunks(u8 size_class, uptr n_chunks) {
-    AsanChunk *m = 0;
-    AsanChunk **fl = &free_lists_[size_class];
-    {
-      BlockingMutexLock lock(&mu_);
-      for (uptr i = 0; i < n_chunks; i++) {
-        if (!(*fl)) {
-          *fl = GetNewChunks(size_class);
-        }
-        AsanChunk *t = *fl;
-        *fl = t->next;
-        t->next = m;
-        CHECK(t->chunk_state == CHUNK_AVAILABLE);
-        m = t;
-      }
-    }
-    return m;
-  }
-
-  void SwallowThreadLocalMallocStorage(AsanThreadLocalMallocStorage *x,
-                                       bool eat_free_lists) {
-    CHECK(flags()->quarantine_size > 0);
-    BlockingMutexLock lock(&mu_);
-    AsanChunkFifoList *q = &x->quarantine_;
-    if (q->size() > 0) {
-      quarantine_.PushList(q);
-      while (quarantine_.size() > (uptr)flags()->quarantine_size) {
-        QuarantinePop();
-      }
-    }
-    if (eat_free_lists) {
-      for (uptr size_class = 0; size_class < kNumberOfSizeClasses;
-           size_class++) {
-        AsanChunk *m = x->free_lists_[size_class];
-        while (m) {
-          AsanChunk *t = m->next;
-          m->next = free_lists_[size_class];
-          free_lists_[size_class] = m;
-          m = t;
-        }
-        x->free_lists_[size_class] = 0;
-      }
-    }
-  }
-
-  void BypassThreadLocalQuarantine(AsanChunk *chunk) {
-    BlockingMutexLock lock(&mu_);
-    quarantine_.Push(chunk);
-  }
-
-  AsanChunk *FindChunkByAddr(uptr addr) {
-    BlockingMutexLock lock(&mu_);
-    return FindChunkByAddrUnlocked(addr);
-  }
-
-  uptr AllocationSize(uptr ptr) {
-    if (!ptr) return 0;
-    BlockingMutexLock lock(&mu_);
-
-    // Make sure this is our chunk and |ptr| actually points to the beginning
-    // of the allocated memory.
-    AsanChunk *m = FindChunkByAddrUnlocked(ptr);
-    if (!m || m->Beg() != ptr) return 0;
-
-    if (m->chunk_state == CHUNK_ALLOCATED) {
-      return m->used_size;
-    } else {
-      return 0;
-    }
-  }
-
-  void ForceLock() {
-    mu_.Lock();
-  }
-
-  void ForceUnlock() {
-    mu_.Unlock();
-  }
-
-  void PrintStatus() {
-    BlockingMutexLock lock(&mu_);
-    uptr malloced = 0;
-
-    Printf(" MallocInfo: in quarantine: %zu malloced: %zu; ",
-           quarantine_.size() >> 20, malloced >> 20);
-    for (uptr j = 1; j < kNumberOfSizeClasses; j++) {
-      AsanChunk *i = free_lists_[j];
-      if (!i) continue;
-      uptr t = 0;
-      for (; i; i = i->next) {
-        t += i->Size();
-      }
-      Printf("%zu:%zu ", j, t >> 20);
-    }
-    Printf("\n");
-  }
-
-  PageGroup *FindPageGroup(uptr addr) {
-    BlockingMutexLock lock(&mu_);
-    return FindPageGroupUnlocked(addr);
-  }
-
- private:
-  PageGroup *FindPageGroupUnlocked(uptr addr) {
-    int n = atomic_load(&n_page_groups_, memory_order_relaxed);
-    // If the page groups are not sorted yet, sort them.
-    if (n_sorted_page_groups_ < n) {
-      SortArray((uptr*)page_groups_, n);
-      n_sorted_page_groups_ = n;
-    }
-    // Binary search over the page groups.
-    int beg = 0, end = n;
-    while (beg < end) {
-      int med = (beg + end) / 2;
-      uptr g = (uptr)page_groups_[med];
-      if (addr > g) {
-        // 'g' points to the end of the group, so 'addr'
-        // may not belong to page_groups_[med] or any previous group.
-        beg = med + 1;
-      } else {
-        // 'addr' may belong to page_groups_[med] or a previous group.
-        end = med;
-      }
-    }
-    if (beg >= n)
-      return 0;
-    PageGroup *g = page_groups_[beg];
-    CHECK(g);
-    if (g->InRange(addr))
-      return g;
-    return 0;
-  }
-
-  // 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 or a chunk from quarantine.
-    if (left_chunk->chunk_state == CHUNK_AVAILABLE &&
-        right_chunk->chunk_state != CHUNK_AVAILABLE)
-      return right_chunk;
-    if (right_chunk->chunk_state == CHUNK_AVAILABLE &&
-        left_chunk->chunk_state != CHUNK_AVAILABLE)
-      return left_chunk;
-    // 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;
-  }
-
-  AsanChunk *FindChunkByAddrUnlocked(uptr addr) {
-    PageGroup *g = FindPageGroupUnlocked(addr);
-    if (!g) return 0;
-    CHECK(g->size_of_chunk);
-    uptr offset_from_beg = addr - g->beg;
-    uptr this_chunk_addr = g->beg +
-        (offset_from_beg / g->size_of_chunk) * g->size_of_chunk;
-    CHECK(g->InRange(this_chunk_addr));
-    AsanChunk *m = (AsanChunk*)this_chunk_addr;
-    CHECK(m->chunk_state == CHUNK_ALLOCATED ||
-          m->chunk_state == CHUNK_AVAILABLE ||
-          m->chunk_state == CHUNK_QUARANTINE);
-    sptr offset = 0;
-    AsanChunkView m_view(m);
-    if (m_view.AddrIsInside(addr, 1, &offset))
-      return m;
-
-    if (m_view.AddrIsAtRight(addr, 1, &offset)) {
-      if (this_chunk_addr == g->last_chunk)  // rightmost chunk
-        return m;
-      uptr right_chunk_addr = this_chunk_addr + g->size_of_chunk;
-      CHECK(g->InRange(right_chunk_addr));
-      return ChooseChunk(addr, m, (AsanChunk*)right_chunk_addr);
-    } else {
-      CHECK(m_view.AddrIsAtLeft(addr, 1, &offset));
-      if (this_chunk_addr == g->beg)  // leftmost chunk
-        return m;
-      uptr left_chunk_addr = this_chunk_addr - g->size_of_chunk;
-      CHECK(g->InRange(left_chunk_addr));
-      return ChooseChunk(addr, (AsanChunk*)left_chunk_addr, m);
-    }
-  }
-
-  void QuarantinePop() {
-    CHECK(quarantine_.size() > 0);
-    AsanChunk *m = quarantine_.Pop();
-    CHECK(m);
-    // if (F_v >= 2) Printf("MallocInfo::pop %p\n", m);
-
-    CHECK(m->chunk_state == CHUNK_QUARANTINE);
-    m->chunk_state = CHUNK_AVAILABLE;
-    PoisonShadow((uptr)m, m->Size(), kAsanHeapLeftRedzoneMagic);
-    CHECK(m->alloc_tid >= 0);
-    CHECK(m->free_tid >= 0);
-
-    uptr size_class = m->SizeClass();
-    m->next = free_lists_[size_class];
-    free_lists_[size_class] = m;
-
-    // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-    thread_stats.real_frees++;
-    thread_stats.really_freed += m->used_size;
-    thread_stats.really_freed_redzones += m->Size() - m->used_size;
-    thread_stats.really_freed_by_size[m->SizeClass()]++;
-  }
-
-  // Get a list of newly allocated chunks.
-  AsanChunk *GetNewChunks(u8 size_class) {
-    uptr size = SizeClassToSize(size_class);
-    CHECK(IsPowerOfTwo(kMinMmapSize));
-    CHECK(size < kMinMmapSize || (size % kMinMmapSize) == 0);
-    uptr mmap_size = Max(size, kMinMmapSize);
-    uptr n_chunks = mmap_size / size;
-    CHECK(n_chunks * size == mmap_size);
-    uptr PageSize = GetPageSizeCached();
-    if (size < PageSize) {
-      // Size is small, just poison the last chunk.
-      n_chunks--;
-    } else {
-      // Size is large, allocate an extra page at right and poison it.
-      mmap_size += PageSize;
-    }
-    CHECK(n_chunks > 0);
-    u8 *mem = MmapNewPagesAndPoisonShadow(mmap_size);
-
-    // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-    thread_stats.mmaps++;
-    thread_stats.mmaped += mmap_size;
-    thread_stats.mmaped_by_size[size_class] += n_chunks;
-
-    AsanChunk *res = 0;
-    for (uptr i = 0; i < n_chunks; i++) {
-      AsanChunk *m = (AsanChunk*)(mem + i * size);
-      m->chunk_state = CHUNK_AVAILABLE;
-      m->size_class = size_class;
-      m->next = res;
-      res = m;
-    }
-    PageGroup *pg = (PageGroup*)(mem + n_chunks * size);
-    // This memory is already poisoned, no need to poison it again.
-    pg->beg = (uptr)mem;
-    pg->end = pg->beg + mmap_size;
-    pg->size_of_chunk = size;
-    pg->last_chunk = (uptr)(mem + size * (n_chunks - 1));
-    int idx = atomic_fetch_add(&n_page_groups_, 1, memory_order_relaxed);
-    CHECK(idx < (int)ARRAY_SIZE(page_groups_));
-    page_groups_[idx] = pg;
-    return res;
-  }
-
-  AsanChunk *free_lists_[kNumberOfSizeClasses];
-  AsanChunkFifoList quarantine_;
-  BlockingMutex mu_;
-
-  PageGroup *page_groups_[kMaxAvailableRam / kMinMmapSize];
-  atomic_uint32_t n_page_groups_;
-  int n_sorted_page_groups_;
-};
-
-static MallocInfo malloc_info(LINKER_INITIALIZED);
-
-void AsanThreadLocalMallocStorage::CommitBack() {
-  malloc_info.SwallowThreadLocalMallocStorage(this, true);
-}
-
-AsanChunkView FindHeapChunkByAddress(uptr address) {
-  return AsanChunkView(malloc_info.FindChunkByAddr(address));
-}
-
-static u8 *Allocate(uptr alignment, uptr size, StackTrace *stack,
-                    AllocType alloc_type) {
-  __asan_init();
-  CHECK(stack);
-  if (size == 0) {
-    size = 1;  // TODO(kcc): do something smarter
-  }
-  CHECK(IsPowerOfTwo(alignment));
-  uptr rounded_size = RoundUpTo(size, REDZONE);
-  uptr needed_size = rounded_size + REDZONE;
-  if (alignment > REDZONE) {
-    needed_size += alignment;
-  }
-  CHECK(IsAligned(needed_size, REDZONE));
-  if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
-    Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
-           (void*)size);
-    return 0;
-  }
-
-  u8 size_class = SizeToSizeClass(needed_size);
-  uptr size_to_allocate = SizeClassToSize(size_class);
-  CHECK(size_to_allocate >= kMinAllocSize);
-  CHECK(size_to_allocate >= needed_size);
-  CHECK(IsAligned(size_to_allocate, REDZONE));
-
-  if (flags()->verbosity >= 3) {
-    Printf("Allocate align: %zu size: %zu class: %u real: %zu\n",
-         alignment, size, size_class, size_to_allocate);
-  }
-
-  AsanThread *t = asanThreadRegistry().GetCurrent();
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-  // Statistics
-  thread_stats.mallocs++;
-  thread_stats.malloced += size;
-  thread_stats.malloced_redzones += size_to_allocate - size;
-  thread_stats.malloced_by_size[size_class]++;
-
-  AsanChunk *m = 0;
-  if (!t || size_to_allocate >= kMaxSizeForThreadLocalFreeList) {
-    // get directly from global storage.
-    m = malloc_info.AllocateChunks(size_class, 1);
-    thread_stats.malloc_large++;
-  } else {
-    // get from the thread-local storage.
-    AsanChunk **fl = &t->malloc_storage().free_lists_[size_class];
-    if (!*fl) {
-      uptr n_new_chunks = kMaxSizeForThreadLocalFreeList / size_to_allocate;
-      *fl = malloc_info.AllocateChunks(size_class, n_new_chunks);
-      thread_stats.malloc_small_slow++;
-    }
-    m = *fl;
-    *fl = (*fl)->next;
-  }
-  CHECK(m);
-  CHECK(m->chunk_state == CHUNK_AVAILABLE);
-  m->chunk_state = CHUNK_ALLOCATED;
-  m->alloc_type = alloc_type;
-  m->next = 0;
-  CHECK(m->Size() == size_to_allocate);
-  uptr addr = (uptr)m + REDZONE;
-  CHECK(addr <= (uptr)m->compressed_free_stack());
-
-  if (alignment > REDZONE && (addr & (alignment - 1))) {
-    addr = RoundUpTo(addr, alignment);
-    CHECK((addr & (alignment - 1)) == 0);
-    AsanChunk *p = (AsanChunk*)(addr - REDZONE);
-    p->chunk_state = CHUNK_MEMALIGN;
-    p->used_size = (uptr)p - (uptr)m;
-    m->alignment_log = Log2(alignment);
-    CHECK(m->Beg() == addr);
-  } else {
-    m->alignment_log = Log2(REDZONE);
-  }
-  CHECK(m == PtrToChunk(addr));
-  m->used_size = size;
-  CHECK(m->Beg() == addr);
-  m->alloc_tid = t ? t->tid() : 0;
-  m->free_tid   = kInvalidTid;
-  StackTrace::CompressStack(stack, m->compressed_alloc_stack(),
-                                m->compressed_alloc_stack_size());
-  PoisonShadow(addr, rounded_size, 0);
-  if (size < rounded_size) {
-    PoisonHeapPartialRightRedzone(addr + rounded_size - REDZONE,
-                                  size & (REDZONE - 1));
-  }
-  if (size <= (uptr)(flags()->max_malloc_fill_size)) {
-    REAL(memset)((void*)addr, 0, rounded_size);
-  }
-  return (u8*)addr;
-}
-
-static void Deallocate(u8 *ptr, StackTrace *stack, AllocType alloc_type) {
-  if (!ptr) return;
-  CHECK(stack);
-
-  if (flags()->debug) {
-    CHECK(malloc_info.FindPageGroup((uptr)ptr));
-  }
-
-  // Printf("Deallocate %p\n", ptr);
-  AsanChunk *m = PtrToChunk((uptr)ptr);
-
-  // Flip the chunk_state atomically to avoid race on double-free.
-  u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
-                                       memory_order_acq_rel);
-
-  if (old_chunk_state == CHUNK_QUARANTINE) {
-    ReportDoubleFree((uptr)ptr, stack);
-  } else if (old_chunk_state != CHUNK_ALLOCATED) {
-    ReportFreeNotMalloced((uptr)ptr, stack);
-  }
-  CHECK(old_chunk_state == CHUNK_ALLOCATED);
-  if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
-    ReportAllocTypeMismatch((uptr)ptr, stack,
-                            (AllocType)m->alloc_type, (AllocType)alloc_type);
-  // With REDZONE==16 m->next is in the user area, otherwise it should be 0.
-  CHECK(REDZONE <= 16 || !m->next);
-  CHECK(m->free_tid == kInvalidTid);
-  CHECK(m->alloc_tid >= 0);
-  AsanThread *t = asanThreadRegistry().GetCurrent();
-  m->free_tid = t ? t->tid() : 0;
-  StackTrace::CompressStack(stack, m->compressed_free_stack(),
-                                m->compressed_free_stack_size());
-  uptr rounded_size = RoundUpTo(m->used_size, REDZONE);
-  PoisonShadow((uptr)ptr, rounded_size, kAsanHeapFreeMagic);
-
-  // Statistics.
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-  thread_stats.frees++;
-  thread_stats.freed += m->used_size;
-  thread_stats.freed_by_size[m->SizeClass()]++;
-
-  CHECK(m->chunk_state == CHUNK_QUARANTINE);
-
-  if (t) {
-    AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
-    ms->quarantine_.Push(m);
-
-    if (ms->quarantine_.size() > kMaxThreadLocalQuarantine) {
-      malloc_info.SwallowThreadLocalMallocStorage(ms, false);
-    }
-  } else {
-    malloc_info.BypassThreadLocalQuarantine(m);
-  }
-}
-
-static u8 *Reallocate(u8 *old_ptr, uptr new_size,
-                           StackTrace *stack) {
-  CHECK(old_ptr && new_size);
-
-  // Statistics.
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-  thread_stats.reallocs++;
-  thread_stats.realloced += new_size;
-
-  AsanChunk *m = PtrToChunk((uptr)old_ptr);
-  CHECK(m->chunk_state == CHUNK_ALLOCATED);
-  uptr old_size = m->used_size;
-  uptr memcpy_size = Min(new_size, old_size);
-  u8 *new_ptr = Allocate(0, new_size, stack, FROM_MALLOC);
-  if (new_ptr) {
-    CHECK(REAL(memcpy) != 0);
-    REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
-    Deallocate(old_ptr, stack, FROM_MALLOC);
-  }
-  return new_ptr;
-}
-
-}  // namespace __asan
-
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-// Provide default (no-op) implementation of malloc hooks.
-extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_malloc_hook(void *ptr, uptr size) {
-  (void)ptr;
-  (void)size;
-}
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_free_hook(void *ptr) {
-  (void)ptr;
-}
-}  // extern "C"
-#endif
-
-namespace __asan {
-
-void InitializeAllocator() { }
-
-void PrintInternalAllocatorStats() {
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
-                    AllocType alloc_type) {
-  void *ptr = (void*)Allocate(alignment, size, stack, alloc_type);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
-  ASAN_FREE_HOOK(ptr);
-  Deallocate((u8*)ptr, stack, alloc_type);
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void *asan_malloc(uptr size, StackTrace *stack) {
-  void *ptr = (void*)Allocate(0, size, stack, FROM_MALLOC);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
-  if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
-  void *ptr = (void*)Allocate(0, nmemb * size, stack, FROM_MALLOC);
-  if (ptr)
-    REAL(memset)(ptr, 0, nmemb * size);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-void *asan_realloc(void *p, uptr size, StackTrace *stack) {
-  if (p == 0) {
-    void *ptr = (void*)Allocate(0, size, stack, FROM_MALLOC);
-    ASAN_MALLOC_HOOK(ptr, size);
-    return ptr;
-  } else if (size == 0) {
-    ASAN_FREE_HOOK(p);
-    Deallocate((u8*)p, stack, FROM_MALLOC);
-    return 0;
-  }
-  return Reallocate((u8*)p, size, stack);
-}
-
-void *asan_valloc(uptr size, StackTrace *stack) {
-  void *ptr = (void*)Allocate(GetPageSizeCached(), size, stack, FROM_MALLOC);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-void *asan_pvalloc(uptr size, StackTrace *stack) {
-  uptr PageSize = GetPageSizeCached();
-  size = RoundUpTo(size, PageSize);
-  if (size == 0) {
-    // pvalloc(0) should allocate one page.
-    size = PageSize;
-  }
-  void *ptr = (void*)Allocate(PageSize, size, stack, FROM_MALLOC);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
-                          StackTrace *stack) {
-  void *ptr = Allocate(alignment, size, stack, FROM_MALLOC);
-  CHECK(IsAligned((uptr)ptr, alignment));
-  ASAN_MALLOC_HOOK(ptr, size);
-  *memptr = ptr;
-  return 0;
-}
-
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
-  CHECK(stack);
-  if (ptr == 0) return 0;
-  uptr usable_size = malloc_info.AllocationSize((uptr)ptr);
-  if (flags()->check_malloc_usable_size && (usable_size == 0)) {
-    ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
-  }
-  return usable_size;
-}
-
-uptr asan_mz_size(const void *ptr) {
-  return malloc_info.AllocationSize((uptr)ptr);
-}
-
-void asan_mz_force_lock() {
-  malloc_info.ForceLock();
-}
-
-void asan_mz_force_unlock() {
-  malloc_info.ForceUnlock();
-}
-
-}  // namespace __asan
-
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan;  // NOLINT
-
-// ASan allocator doesn't reserve extra bytes, so normally we would
-// just return "size".
-uptr __asan_get_estimated_allocated_size(uptr size) {
-  if (size == 0) return 1;
-  return Min(size, kMaxAllowedMallocSize);
-}
-
-bool __asan_get_ownership(const void *p) {
-  return malloc_info.AllocationSize((uptr)p) > 0;
-}
-
-uptr __asan_get_allocated_size(const void *p) {
-  if (p == 0) return 0;
-  uptr allocated_size = malloc_info.AllocationSize((uptr)p);
-  // Die if p is not malloced or if it is already freed.
-  if (allocated_size == 0) {
-    GET_STACK_TRACE_FATAL_HERE;
-    ReportAsanGetAllocatedSizeNotOwned((uptr)p, &stack);
-  }
-  return allocated_size;
-}
-#endif  // ASAN_ALLOCATOR_VERSION
index df2f520c41a4847f461110bf5e7de536174e4ca6..1f83dcd6780005ad2a727c7415f3dd512d07777b 100644 (file)
@@ -7,7 +7,7 @@
 //
 // This file is a part of AddressSanitizer, an address sanity checker.
 //
-// ASan-private header for asan_allocator.cc.
+// ASan-private header for asan_allocator2.cc.
 //===----------------------------------------------------------------------===//
 
 #ifndef ASAN_ALLOCATOR_H
 #include "asan_interceptors.h"
 #include "sanitizer_common/sanitizer_list.h"
 
-// We are in the process of transitioning from the old allocator (version 1)
-// to a new one (version 2). The change is quite intrusive so both allocators
-// will co-exist in the source base for a while. The actual allocator is chosen
-// at build time by redefining this macro.
-#ifndef ASAN_ALLOCATOR_VERSION
-# if (ASAN_LINUX && !ASAN_ANDROID) || ASAN_MAC || ASAN_WINDOWS
-#  define ASAN_ALLOCATOR_VERSION 2
-# else
-#  define ASAN_ALLOCATOR_VERSION 1
-# endif
-#endif  // ASAN_ALLOCATOR_VERSION
-
 namespace __asan {
 
 enum AllocType {
@@ -101,109 +89,17 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
 
 struct AsanThreadLocalMallocStorage {
   explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
-#if ASAN_ALLOCATOR_VERSION == 1
-      : quarantine_(x)
-#endif
       { }
   AsanThreadLocalMallocStorage() {
     CHECK(REAL(memset));
     REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
   }
 
-#if ASAN_ALLOCATOR_VERSION == 1
-  AsanChunkFifoList quarantine_;
-  AsanChunk *free_lists_[kNumberOfSizeClasses];
-#else
   uptr quarantine_cache[16];
   uptr allocator2_cache[96 * (512 * 8 + 16)];  // Opaque.
-#endif
   void CommitBack();
 };
 
-// Fake stack frame contains local variables of one function.
-// This struct should fit into a stack redzone (32 bytes).
-struct FakeFrame {
-  uptr magic;  // Modified by the instrumented code.
-  uptr descr;  // Modified by the instrumented code.
-  FakeFrame *next;
-  u64 real_stack     : 48;
-  u64 size_minus_one : 16;
-};
-
-struct FakeFrameFifo {
- public:
-  void FifoPush(FakeFrame *node);
-  FakeFrame *FifoPop();
- private:
-  FakeFrame *first_, *last_;
-};
-
-class FakeFrameLifo {
- public:
-  void LifoPush(FakeFrame *node) {
-    node->next = top_;
-    top_ = node;
-  }
-  void LifoPop() {
-    CHECK(top_);
-    top_ = top_->next;
-  }
-  FakeFrame *top() { return top_; }
- private:
-  FakeFrame *top_;
-};
-
-// 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 poped 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.
-// We can not rely on __asan_stack_free being called on every function exit,
-// so we maintain a lifo list of all current fake frames and update it on every
-// call to __asan_stack_malloc.
-class FakeStack {
- public:
-  FakeStack();
-  explicit FakeStack(LinkerInitialized) {}
-  void Init(uptr stack_size);
-  void StopUsingFakeStack() { alive_ = false; }
-  void Cleanup();
-  uptr AllocateStack(uptr size, uptr real_stack);
-  static void OnFree(uptr ptr, uptr size, uptr real_stack);
-  // Return the bottom of the maped region.
-  uptr AddrIsInFakeStack(uptr addr);
-  bool StackSize() { return stack_size_; }
-
- private:
-  static const uptr kMinStackFrameSizeLog = 9;  // Min frame is 512B.
-  static const uptr kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
-  static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
-  static const uptr kNumberOfSizeClasses =
-      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
-
-  bool AddrIsInSizeClass(uptr addr, uptr size_class);
-
-  // Each size class should be large enough to hold all frames.
-  uptr ClassMmapSize(uptr size_class);
-
-  uptr ClassSize(uptr size_class) {
-    return 1UL << (size_class + kMinStackFrameSizeLog);
-  }
-
-  void DeallocateFrame(FakeFrame *fake_frame);
-
-  uptr ComputeSizeClass(uptr alloc_size);
-  void AllocateOneSizeClass(uptr size_class);
-
-  uptr stack_size_;
-  bool   alive_;
-
-  uptr allocated_size_classes_[kNumberOfSizeClasses];
-  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
-  FakeFrameLifo call_stack_;
-};
-
 void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
                     AllocType alloc_type);
 void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
index 1ff120e555c74eeb00a0f5946e70437570bc29bb..34aad11ed75205a8f6ed1247c630a24b608844e4 100644 (file)
 // This variant uses the allocator from sanitizer_common, i.e. the one shared
 // with ThreadSanitizer and MemorySanitizer.
 //
-// Status: under development, not enabled by default yet.
 //===----------------------------------------------------------------------===//
 #include "asan_allocator.h"
-#if ASAN_ALLOCATOR_VERSION == 2
 
 #include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_allocator.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 {
 
@@ -32,7 +32,7 @@ struct AsanMapUnmapCallback {
   void OnMap(uptr p, uptr size) const {
     PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
     // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.mmaps++;
     thread_stats.mmaped += size;
   }
@@ -47,7 +47,7 @@ struct AsanMapUnmapCallback {
     uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
     FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
     // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.munmaps++;
     thread_stats.munmaped += size;
   }
@@ -56,18 +56,23 @@ struct AsanMapUnmapCallback {
 #if SANITIZER_WORDSIZE == 64
 #if defined(__powerpc64__)
 const uptr kAllocatorSpace =  0xa0000000000ULL;
+const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
 #else
 const uptr kAllocatorSpace = 0x600000000000ULL;
+const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
 #endif
-const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
 typedef DefaultSizeClassMap SizeClassMap;
 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
     SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
 #elif SANITIZER_WORDSIZE == 32
 static const u64 kAddressSpaceSize = 1ULL << 32;
 typedef CompactSizeClassMap SizeClassMap;
+static const uptr kRegionSizeLog = 20;
+static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
 typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
-  SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+  SizeClassMap, kRegionSizeLog,
+  FlatByteMap<kFlatByteMapSize>,
+  AsanMapUnmapCallback> PrimaryAllocator;
 #endif
 
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
@@ -139,14 +144,15 @@ static uptr ComputeRZLog(uptr user_requested_size) {
 // ChunkBase consists of ChunkHeader and other bytes that overlap with user
 // memory.
 
-// If a memory chunk is allocated by memalign and we had to increase the
-// allocation size to achieve the proper alignment, then we store this magic
+// 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  H H U U U U U U
-//   M -- magic value kMemalignMagic
+// 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 kMemalignMagic = 0xCC6E96B9;
+static const uptr kAllocBegMagic = 0xCC6E96B9;
 
 struct ChunkHeader {
   // 1-st 8 bytes.
@@ -157,6 +163,7 @@ struct ChunkHeader {
   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
@@ -167,7 +174,6 @@ struct ChunkHeader {
 
 struct ChunkBase : ChunkHeader {
   // Header2, intersects with user memory.
-  AsanChunk *next;
   u32 free_context_id;
 };
 
@@ -188,7 +194,8 @@ struct AsanChunk: ChunkBase {
       return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
     return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
   }
-  // We store the alloc/free stack traces in the chunk itself.
+  // If we don't use stack depot, we store the alloc/free stack traces
+  // in the chunk itself.
   u32 *AllocStackBeg() {
     return (u32*)(Beg() - RZLog2Size(rz_log));
   }
@@ -204,6 +211,9 @@ struct AsanChunk: ChunkBase {
     uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
     return (available - kChunkHeader2Size) / sizeof(u32);
   }
+  bool AddrIsInside(uptr addr) {
+    return (addr >= Beg()) && (addr < Beg() + UsedSize());
+  }
 };
 
 uptr AsanChunkView::Beg() { return chunk_->Beg(); }
@@ -257,22 +267,25 @@ struct QuarantineCallback {
   }
 
   void Recycle(AsanChunk *m) {
-    CHECK(m->chunk_state == CHUNK_QUARANTINE);
-    m->chunk_state = CHUNK_AVAILABLE;
+    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 (m->from_memalign) {
-      uptr *memalign_magic = reinterpret_cast<uptr *>(p);
-      CHECK_EQ(memalign_magic[0], kMemalignMagic);
-      CHECK_EQ(memalign_magic[1], reinterpret_cast<uptr>(m));
+    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 = asanThreadRegistry().GetCurrentThreadStats();
+    AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.real_frees++;
     thread_stats.really_freed += m->UsedSize();
 
@@ -296,9 +309,10 @@ void InitializeAllocator() {
 }
 
 static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
-                      AllocType alloc_type) {
+                      AllocType alloc_type, bool can_fill) {
   if (!asan_inited)
     __asan_init();
+  Flags &fl = *flags();
   CHECK(stack);
   const uptr min_alignment = SHADOW_GRANULARITY;
   if (alignment < min_alignment)
@@ -314,9 +328,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
   CHECK(IsPowerOfTwo(alignment));
   uptr rz_log = ComputeRZLog(size);
   uptr rz_size = RZLog2Size(rz_log);
-  uptr rounded_size = RoundUpTo(size, alignment);
-  if (rounded_size < kChunkHeader2Size)
-    rounded_size = kChunkHeader2Size;
+  uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
   uptr needed_size = rounded_size + rz_size;
   if (alignment > min_alignment)
     needed_size += alignment;
@@ -331,10 +343,10 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
   if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
     Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
            (void*)size);
-    return 0;
+    return AllocatorReturnNull();
   }
 
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   void *allocated;
   if (t) {
     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
@@ -345,8 +357,6 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
     allocated = allocator.Allocate(cache, needed_size, 8, false);
   }
   uptr alloc_beg = reinterpret_cast<uptr>(allocated);
-  // Clear the first allocated word (an old kMemalignMagic may still be there).
-  reinterpret_cast<uptr *>(alloc_beg)[0] = 0;
   uptr alloc_end = alloc_beg + needed_size;
   uptr beg_plus_redzone = alloc_beg + rz_size;
   uptr user_beg = beg_plus_redzone;
@@ -356,7 +366,6 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
   CHECK_LE(user_end, alloc_end);
   uptr chunk_beg = user_beg - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
-  m->chunk_state = CHUNK_ALLOCATED;
   m->alloc_type = alloc_type;
   m->rz_log = rz_log;
   u32 alloc_tid = t ? t->tid() : 0;
@@ -364,11 +373,10 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
   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 (m->from_memalign) {
-    CHECK_LE(beg_plus_redzone + 2 * sizeof(uptr), user_beg);
-    uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
-    memalign_magic[0] = kMemalignMagic;
-    memalign_magic[1] = chunk_beg;
+  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);
@@ -382,7 +390,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
     meta[1] = chunk_beg;
   }
 
-  if (flags()->use_stack_depot) {
+  if (fl.use_stack_depot) {
     m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
   } else {
     m->alloc_context_id = 0;
@@ -394,12 +402,12 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
   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 && flags()->poison_heap) {
+  if (size != size_rounded_down_to_granularity && fl.poison_heap) {
     u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
     *shadow = size & (SHADOW_GRANULARITY - 1);
   }
 
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+  AsanStats &thread_stats = GetCurrentThreadStats();
   thread_stats.mallocs++;
   thread_stats.malloced += size;
   thread_stats.malloced_redzones += needed_size - size;
@@ -409,26 +417,43 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
     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;
 }
 
-static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
-  uptr p = reinterpret_cast<uptr>(ptr);
-  if (p == 0) return;
-  ASAN_FREE_HOOK(ptr);
-  uptr chunk_beg = p - kChunkHeaderSize;
-  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+  if (chunk_state == CHUNK_QUARANTINE)
+    ReportDoubleFree((uptr)ptr, stack);
+  else
+    ReportFreeNotMalloced((uptr)ptr, stack);
+}
 
+static void AtomicallySetQuarantineFlag(AsanChunk *m,
+                                        void *ptr, StackTrace *stack) {
+  u8 old_chunk_state = CHUNK_ALLOCATED;
   // Flip the chunk_state atomically to avoid race on double-free.
-  u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
-                                       memory_order_relaxed);
+  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.
+static void QuarantineChunk(AsanChunk *m, void *ptr,
+                            StackTrace *stack, AllocType alloc_type) {
+  CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
 
-  if (old_chunk_state == CHUNK_QUARANTINE)
-    ReportDoubleFree((uptr)ptr, stack);
-  else if (old_chunk_state != CHUNK_ALLOCATED)
-    ReportFreeNotMalloced((uptr)ptr, stack);
-  CHECK(old_chunk_state == CHUNK_ALLOCATED);
   if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
     ReportAllocTypeMismatch((uptr)ptr, stack,
                             (AllocType)m->alloc_type, (AllocType)alloc_type);
@@ -436,7 +461,7 @@ static void Deallocate(void *ptr, StackTrace *stack, 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 = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   m->free_tid = t ? t->tid() : 0;
   if (flags()->use_stack_depot) {
     m->free_context_id = StackDepotPut(stack->trace, stack->size);
@@ -444,13 +469,12 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
     m->free_context_id = 0;
     StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
   }
-  CHECK(m->chunk_state == CHUNK_QUARANTINE);
   // Poison the region.
   PoisonShadow(m->Beg(),
                RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
                kAsanHeapFreeMagic);
 
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+  AsanStats &thread_stats = GetCurrentThreadStats();
   thread_stats.frees++;
   thread_stats.freed += m->UsedSize();
 
@@ -468,57 +492,67 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
   }
 }
 
+static void Deallocate(void *ptr, StackTrace *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);
+  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);
+}
+
 static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *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 = asanThreadRegistry().GetCurrentThreadStats();
+  AsanStats &thread_stats = GetCurrentThreadStats();
   thread_stats.reallocs++;
   thread_stats.realloced += new_size;
 
-  CHECK(m->chunk_state == CHUNK_ALLOCATED);
-  uptr old_size = m->UsedSize();
-  uptr memcpy_size = Min(new_size, old_size);
-  void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC);
+  void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
   if (new_ptr) {
-    CHECK(REAL(memcpy) != 0);
+    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, stack, FROM_MALLOC);
   }
   return new_ptr;
 }
 
-static AsanChunk *GetAsanChunkByAddr(uptr p) {
-  void *ptr = reinterpret_cast<void *>(p);
-  uptr alloc_beg = reinterpret_cast<uptr>(allocator.GetBlockBegin(ptr));
+// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+static AsanChunk *GetAsanChunk(void *alloc_beg) {
   if (!alloc_beg) return 0;
-  uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
-  if (memalign_magic[0] == kMemalignMagic) {
-    AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
-    CHECK(m->from_memalign);
-    return m;
-  }
-  if (!allocator.FromPrimary(ptr)) {
-    uptr *meta = reinterpret_cast<uptr *>(
-        allocator.GetMetaData(reinterpret_cast<void *>(alloc_beg)));
+  if (!allocator.FromPrimary(alloc_beg)) {
+    uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
     AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
     return m;
   }
-  uptr actual_size = allocator.GetActuallyAllocatedSize(ptr);
-  CHECK_LE(actual_size, SizeClassMap::kMaxSize);
-  // We know the actually allocted size, but we don't know the redzone size.
-  // Just try all possible redzone sizes.
-  for (u32 rz_log = 0; rz_log < 8; rz_log++) {
-    u32 rz_size = RZLog2Size(rz_log);
-    uptr max_possible_size = actual_size - rz_size;
-    if (ComputeRZLog(max_possible_size) != rz_log)
-      continue;
-    return reinterpret_cast<AsanChunk *>(
-        alloc_beg + rz_size - kChunkHeaderSize);
-  }
-  return 0;
+  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);
+}
+
+static 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.
+static AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
+  void *alloc_beg =
+      allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
+  return GetAsanChunk(alloc_beg);
 }
 
 static uptr AllocationSize(uptr p) {
@@ -583,33 +617,33 @@ void PrintInternalAllocatorStats() {
   allocator.PrintStats();
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
 void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
                     AllocType alloc_type) {
-  return Allocate(size, alignment, stack, alloc_type);
+  return Allocate(size, alignment, stack, alloc_type, true);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
 void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
   Deallocate(ptr, stack, alloc_type);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
 void *asan_malloc(uptr size, StackTrace *stack) {
-  return Allocate(size, 8, stack, FROM_MALLOC);
+  return Allocate(size, 8, stack, FROM_MALLOC, true);
 }
 
 void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
-  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
-  void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
-  if (ptr)
+  if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+    return AllocatorReturnNull();
+  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 *asan_realloc(void *p, uptr size, StackTrace *stack) {
   if (p == 0)
-    return Allocate(size, 8, stack, FROM_MALLOC);
+    return Allocate(size, 8, stack, FROM_MALLOC, true);
   if (size == 0) {
     Deallocate(p, stack, FROM_MALLOC);
     return 0;
@@ -618,7 +652,7 @@ void *asan_realloc(void *p, uptr size, StackTrace *stack) {
 }
 
 void *asan_valloc(uptr size, StackTrace *stack) {
-  return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC);
+  return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
 }
 
 void *asan_pvalloc(uptr size, StackTrace *stack) {
@@ -628,12 +662,12 @@ void *asan_pvalloc(uptr size, StackTrace *stack) {
     // pvalloc(0) should allocate one page.
     size = PageSize;
   }
-  return Allocate(size, PageSize, stack, FROM_MALLOC);
+  return Allocate(size, PageSize, stack, FROM_MALLOC, true);
 }
 
 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
                         StackTrace *stack) {
-  void *ptr = Allocate(size, alignment, stack, FROM_MALLOC);
+  void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
   CHECK(IsAligned((uptr)ptr, alignment));
   *memptr = ptr;
   return 0;
@@ -664,6 +698,86 @@ void asan_mz_force_unlock() {
 
 }  // namespace __asan
 
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+void LockAllocator() {
+  __asan::allocator.ForceLock();
+}
+
+void UnlockAllocator() {
+  __asan::allocator.ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+  *begin = (uptr)&__asan::allocator;
+  *end = *begin + sizeof(__asan::allocator);
+}
+
+uptr PointsIntoChunk(void* p) {
+  uptr addr = reinterpret_cast<uptr>(p);
+  __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
+  if (!m) return 0;
+  uptr chunk = m->Beg();
+  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
+    return chunk;
+  return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+  __asan::AsanChunk *m =
+      __asan::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();
+}
+
+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::allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+  uptr addr = reinterpret_cast<uptr>(p);
+  __asan::AsanChunk *m = __asan::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
 
@@ -693,17 +807,14 @@ uptr __asan_get_allocated_size(const void *p) {
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 // Provide default (no-op) implementation of malloc hooks.
 extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 void __asan_malloc_hook(void *ptr, uptr size) {
   (void)ptr;
   (void)size;
 }
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 void __asan_free_hook(void *ptr) {
   (void)ptr;
 }
 }  // extern "C"
 #endif
-
-
-#endif  // ASAN_ALLOCATOR_VERSION
diff --git a/libsanitizer/asan/asan_dll_thunk.cc b/libsanitizer/asan/asan_dll_thunk.cc
new file mode 100644 (file)
index 0000000..26e1944
--- /dev/null
@@ -0,0 +1,194 @@
+//===-- asan_dll_thunk.cc -------------------------------------------------===//
+//
+// 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
+
+// ----------------- 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;
+}
+
+#define WRAP_V_V(name)                                                         \
+  extern "C" void name() {                                                     \
+    typedef void (*fntype)();                                                  \
+    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
+    fn();                                                                      \
+  }
+
+#define WRAP_V_W(name)                                                         \
+  extern "C" void name(void *arg) {                                            \
+    typedef void (*fntype)(void *arg);                                         \
+    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
+    fn(arg);                                                                   \
+  }
+
+#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);                                                            \
+  }
+
+#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);                                                      \
+  }
+
+#define WRAP_W_V(name)                                                         \
+  extern "C" void *name() {                                                    \
+    typedef void *(*fntype)();                                                 \
+    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
+    return fn();                                                               \
+  }
+
+#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);                                                            \
+  }
+
+#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);                                                     \
+  }
+
+#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);                                               \
+  }
+
+#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);                                         \
+  }
+
+#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);                                   \
+  }
+
+#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);                             \
+  }
+// }}}
+
+// ----------------- ASan own interface functions --------------------
+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_v3() {
+    typedef void (*fntype)();
+    static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
+    fn();
+    __asan_option_detect_stack_use_after_return =
+        (__asan_should_detect_stack_use_after_return() != 0);
+  }
+}
+
+WRAP_V_W(__asan_report_store1)
+WRAP_V_W(__asan_report_store2)
+WRAP_V_W(__asan_report_store4)
+WRAP_V_W(__asan_report_store8)
+WRAP_V_W(__asan_report_store16)
+WRAP_V_WW(__asan_report_store_n)
+
+WRAP_V_W(__asan_report_load1)
+WRAP_V_W(__asan_report_load2)
+WRAP_V_W(__asan_report_load4)
+WRAP_V_W(__asan_report_load8)
+WRAP_V_W(__asan_report_load16)
+WRAP_V_WW(__asan_report_load_n)
+
+WRAP_V_WW(__asan_register_globals)
+WRAP_V_WW(__asan_unregister_globals)
+
+WRAP_W_WW(__asan_stack_malloc_0)
+WRAP_W_WW(__asan_stack_malloc_1)
+WRAP_W_WW(__asan_stack_malloc_2)
+WRAP_W_WW(__asan_stack_malloc_3)
+WRAP_W_WW(__asan_stack_malloc_4)
+WRAP_W_WW(__asan_stack_malloc_5)
+WRAP_W_WW(__asan_stack_malloc_6)
+WRAP_W_WW(__asan_stack_malloc_7)
+WRAP_W_WW(__asan_stack_malloc_8)
+WRAP_W_WW(__asan_stack_malloc_9)
+WRAP_W_WW(__asan_stack_malloc_10)
+
+WRAP_V_WWW(__asan_stack_free_0)
+WRAP_V_WWW(__asan_stack_free_1)
+WRAP_V_WWW(__asan_stack_free_2)
+WRAP_V_WWW(__asan_stack_free_4)
+WRAP_V_WWW(__asan_stack_free_5)
+WRAP_V_WWW(__asan_stack_free_6)
+WRAP_V_WWW(__asan_stack_free_7)
+WRAP_V_WWW(__asan_stack_free_8)
+WRAP_V_WWW(__asan_stack_free_9)
+WRAP_V_WWW(__asan_stack_free_10)
+
+// 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)
+
+// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
+
+#endif // ASAN_DLL_THUNK
index 1fc0415750bac09b0e73732f90d2fe83abda8479..b9cce88f34f97fddd325ef282eea80c6e0cdef3e 100644 (file)
 // FakeStack is used to detect use-after-return bugs.
 //===----------------------------------------------------------------------===//
 #include "asan_allocator.h"
+#include "asan_poisoning.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 
 namespace __asan {
 
-FakeStack::FakeStack() {
-  CHECK(REAL(memset) != 0);
-  REAL(memset)(this, 0, sizeof(*this));
+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;
+  } else {
+    // The size class is too big, it's cheaper to poison only size bytes.
+    PoisonShadow(ptr, size, static_cast<u8>(magic));
+  }
 }
 
-bool FakeStack::AddrIsInSizeClass(uptr addr, uptr size_class) {
-  uptr mem = allocated_size_classes_[size_class];
-  uptr size = ClassMmapSize(size_class);
-  bool res = mem && addr >= mem && addr < mem + size;
+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;
+  FakeStack *res = reinterpret_cast<FakeStack *>(
+      MmapOrDie(RequiredSize(stack_size_log), "FakeStack"));
+  res->stack_size_log_ = stack_size_log;
+  if (flags()->verbosity) {
+    u8 *p = reinterpret_cast<u8 *>(res);
+    Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n",
+           GetCurrentTidOrInvalid(), p,
+           p + FakeStack::RequiredSize(stack_size_log), stack_size_log);
+  }
   return res;
 }
 
-uptr FakeStack::AddrIsInFakeStack(uptr addr) {
-  for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
-    if (AddrIsInSizeClass(addr, i)) return allocated_size_classes_[i];
-  }
-  return 0;
+void FakeStack::Destroy() {
+  PoisonAll(0);
+  UnmapOrDie(this, RequiredSize(stack_size_log_));
 }
 
-// We may want to compute this during compilation.
-inline uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
-  uptr rounded_size = RoundUpToPowerOfTwo(alloc_size);
-  uptr log = Log2(rounded_size);
-  CHECK(alloc_size <= (1UL << log));
-  if (!(alloc_size > (1UL << (log-1)))) {
-    Printf("alloc_size %zu log %zu\n", alloc_size, log);
-  }
-  CHECK(alloc_size > (1UL << (log-1)));
-  uptr res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog;
-  CHECK(res < kNumberOfSizeClasses);
-  CHECK(ClassSize(res) >= rounded_size);
-  return res;
+void FakeStack::PoisonAll(u8 magic) {
+  PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
+               magic);
 }
 
-void FakeFrameFifo::FifoPush(FakeFrame *node) {
-  CHECK(node);
-  node->next = 0;
-  if (first_ == 0 && last_ == 0) {
-    first_ = last_ = node;
-  } else {
-    CHECK(first_);
-    CHECK(last_);
-    last_->next = node;
-    last_ = node;
+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.
 }
 
-FakeFrame *FakeFrameFifo::FifoPop() {
-  CHECK(first_ && last_ && "Exhausted fake stack");
-  FakeFrame *res = 0;
-  if (first_ == last_) {
-    res = first_;
-    first_ = last_ = 0;
-  } else {
-    res = first_;
-    first_ = first_->next;
-  }
-  return res;
+uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
+  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);
+  return base + pos * BytesInSizeClass(class_id);
 }
 
-void FakeStack::Init(uptr stack_size) {
-  stack_size_ = stack_size;
-  alive_ = true;
+void FakeStack::HandleNoReturn() {
+  needs_gc_ = true;
 }
 
-void FakeStack::Cleanup() {
-  alive_ = false;
-  for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
-    uptr mem = allocated_size_classes_[i];
-    if (mem) {
-      PoisonShadow(mem, ClassMmapSize(i), 0);
-      allocated_size_classes_[i] = 0;
-      UnmapOrDie((void*)mem, ClassMmapSize(i));
+// 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;
 }
 
-uptr FakeStack::ClassMmapSize(uptr size_class) {
-  return RoundUpToPowerOfTwo(stack_size_);
-}
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+static THREADLOCAL FakeStack *fake_stack_tls;
 
-void FakeStack::AllocateOneSizeClass(uptr size_class) {
-  CHECK(ClassMmapSize(size_class) >= GetPageSizeCached());
-  uptr new_mem = (uptr)MmapOrDie(
-      ClassMmapSize(size_class), __FUNCTION__);
-  // Printf("T%d new_mem[%zu]: %p-%p mmap %zu\n",
-  //       asanThreadRegistry().GetCurrent()->tid(),
-  //       size_class, new_mem, new_mem + ClassMmapSize(size_class),
-  //       ClassMmapSize(size_class));
-  uptr i;
-  for (i = 0; i < ClassMmapSize(size_class);
-       i += ClassSize(size_class)) {
-    size_classes_[size_class].FifoPush((FakeFrame*)(new_mem + i));
-  }
-  CHECK(i == ClassMmapSize(size_class));
-  allocated_size_classes_[size_class] = new_mem;
+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();
 }
 
-uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
-  if (!alive_) return real_stack;
-  CHECK(size <= kMaxStackMallocSize && size > 1);
-  uptr size_class = ComputeSizeClass(size);
-  if (!allocated_size_classes_[size_class]) {
-    AllocateOneSizeClass(size_class);
-  }
-  FakeFrame *fake_frame = size_classes_[size_class].FifoPop();
-  CHECK(fake_frame);
-  fake_frame->size_minus_one = size - 1;
-  fake_frame->real_stack = real_stack;
-  while (FakeFrame *top = call_stack_.top()) {
-    if (top->real_stack > real_stack) break;
-    call_stack_.LifoPop();
-    DeallocateFrame(top);
-  }
-  call_stack_.LifoPush(fake_frame);
-  uptr ptr = (uptr)fake_frame;
-  PoisonShadow(ptr, size, 0);
-  return ptr;
+static FakeStack *GetFakeStackFast() {
+  if (FakeStack *fs = GetTLSFakeStack())
+    return fs;
+  if (!__asan_option_detect_stack_use_after_return)
+    return 0;
+  return GetFakeStack();
 }
 
-void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
-  CHECK(alive_);
-  uptr size = fake_frame->size_minus_one + 1;
-  uptr size_class = ComputeSizeClass(size);
-  CHECK(allocated_size_classes_[size_class]);
-  uptr ptr = (uptr)fake_frame;
-  CHECK(AddrIsInSizeClass(ptr, size_class));
-  CHECK(AddrIsInSizeClass(ptr + size - 1, size_class));
-  size_classes_[size_class].FifoPush(fake_frame);
+ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) {
+  FakeStack *fs = GetFakeStackFast();
+  if (!fs) return real_stack;
+  FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
+  if (!ff)
+    return real_stack;  // Out of fake stack, return the real one.
+  uptr ptr = reinterpret_cast<uptr>(ff);
+  SetShadow(ptr, size, class_id, 0);
+  return ptr;
 }
 
-void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
-  FakeFrame *fake_frame = (FakeFrame*)ptr;
-  CHECK(fake_frame->magic = kRetiredStackFrameMagic);
-  CHECK(fake_frame->descr != 0);
-  CHECK(fake_frame->size_minus_one == size - 1);
-  PoisonShadow(ptr, size, kAsanStackAfterReturnMagic);
+ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
+  if (ptr == real_stack)
+    return;
+  FakeStack::Deallocate(ptr, class_id);
+  SetShadow(ptr, size, class_id, kMagic8);
 }
 
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
-using namespace __asan;  // NOLINT
-
-uptr __asan_stack_malloc(uptr size, uptr real_stack) {
-  if (!flags()->use_fake_stack) return real_stack;
-  AsanThread *t = asanThreadRegistry().GetCurrent();
-  if (!t) {
-    // TSD is gone, use the real stack.
-    return real_stack;
+#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id)                       \
+  extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr                                \
+  __asan_stack_malloc_##class_id(uptr size, uptr real_stack) {                 \
+    return __asan::OnMalloc(class_id, size, real_stack);                       \
+  }                                                                            \
+  extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id(  \
+      uptr ptr, uptr size, uptr real_stack) {                                  \
+    __asan::OnFree(ptr, class_id, size, real_stack);                           \
   }
-  uptr ptr = t->fake_stack().AllocateStack(size, real_stack);
-  // Printf("__asan_stack_malloc %p %zu %p\n", ptr, size, real_stack);
-  return ptr;
-}
 
-void __asan_stack_free(uptr ptr, uptr size, uptr real_stack) {
-  if (!flags()->use_fake_stack) return;
-  if (ptr != real_stack) {
-    FakeStack::OnFree(ptr, size, real_stack);
-  }
-}
+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)
diff --git a/libsanitizer/asan/asan_fake_stack.h b/libsanitizer/asan/asan_fake_stack.h
new file mode 100644 (file)
index 0000000..4287497
--- /dev/null
@@ -0,0 +1,167 @@
+//===-- asan_fake_stack.h ---------------------------------------*- C++ -*-===//
+//
+// 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();
+
+  // 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);
+
+  // 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);
+
+ 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
index b880896c7a3ae9e2457209a15e88c2bfa2f2a0c5..c115997ff29d4c3414c6cae7f541328e4d15d037 100644 (file)
@@ -30,8 +30,6 @@ struct Flags {
   // Lower value may reduce memory usage but increase the chance of
   // false negatives.
   int  quarantine_size;
-  // If set, uses in-process symbolizer from common sanitizer runtime.
-  bool symbolize;
   // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
   int  verbosity;
   // Size (in bytes) of redzones around heap objects.
@@ -45,8 +43,6 @@ struct Flags {
   int  report_globals;
   // If set, attempts to catch initialization order issues.
   bool check_initialization_order;
-  // Max number of stack frames kept for each allocation/deallocation.
-  int  malloc_context_size;
   // If set, uses custom wrappers and replacements for libc string functions
   // to find more errors.
   bool replace_str;
@@ -54,11 +50,13 @@ struct Flags {
   bool replace_intrin;
   // Used on Mac only.
   bool mac_ignore_invalid_free;
-  // ASan allocator flag. See asan_allocator.cc.
-  bool use_fake_stack;
-  // ASan allocator flag. Sets the maximal size of allocation request
-  // that would return memory filled with zero bytes.
-  int  max_malloc_fill_size;
+  // Enables stack-use-after-return checking at run-time.
+  bool detect_stack_use_after_return;
+  // The minimal fake stack size log.
+  int uar_stack_size_log;
+  // ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes
+  // that will be filled with malloc_fill_byte on malloc.
+  int max_malloc_fill_size, malloc_fill_byte;
   // Override exit status if something was reported.
   int  exitcode;
   // If set, user may manually mark memory regions as poisoned or unpoisoned.
@@ -69,6 +67,8 @@ struct Flags {
   int  sleep_before_dying;
   // If set, registers ASan custom segv handler.
   bool handle_segv;
+  // If set, allows user register segv handler even if ASan registers one.
+  bool allow_user_segv_handler;
   // If set, uses alternate stack for signal handling.
   bool use_sigaltstack;
   // Allow the users to work around the bug in Nvidia drivers prior to 295.*.
@@ -89,18 +89,10 @@ struct Flags {
   // Allow the tool to re-exec the program. This may interfere badly with the
   // debugger.
   bool allow_reexec;
-  // Strips this prefix from file paths in error reports.
-  const char *strip_path_prefix;
   // If set, prints not only thread creation stacks for threads in error report,
   // but also thread creation stacks for threads that created those threads,
   // etc. up to main thread.
   bool print_full_thread_history;
-  // ASan will write logs to "log_path.pid" instead of stderr.
-  const char *log_path;
-  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
-  bool fast_unwind_on_fatal;
-  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
-  bool fast_unwind_on_malloc;
   // Poison (or not) the heap memory on [de]allocation. Zero value is useful
   // for benchmarking the allocator or instrumentator.
   bool poison_heap;
@@ -108,9 +100,18 @@ struct Flags {
   bool alloc_dealloc_mismatch;
   // Use stack depot instead of storing stacks in the redzones.
   bool use_stack_depot;
+  // If true, assume that memcmp(p1, p2, n) always reads n bytes before
+  // comparing p1 and p2.
+  bool strict_memcmp;
+  // If true, assume that dynamic initializers can never access globals from
+  // other modules, even if the latter are already initialized.
+  bool strict_init_order;
 };
 
-Flags *flags();
+extern Flags asan_flags_dont_use_directly;
+inline Flags *flags() {
+  return &asan_flags_dont_use_directly;
+}
 void InitializeFlags(Flags *f, const char *env);
 
 }  // namespace __asan
index 7093c445588693259e4a84283422cc21d42984b7..96985af71a9fb71b97e204956144c102ee7ff28a 100644 (file)
 #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"
 
 namespace __asan {
 
@@ -30,15 +33,26 @@ struct ListOfGlobals {
 static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
 static LowLevelAllocator allocator_for_globals;
 static ListOfGlobals *list_of_all_globals;
-static ListOfGlobals *list_of_dynamic_init_globals;
 
-void PoisonRedZones(const Global &g)  {
+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;
+
+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);
-  PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
-               kAsanGlobalRedzoneMagic);
+  FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+                   kAsanGlobalRedzoneMagic);
   if (g.size != aligned_size) {
-    // partial right redzone
-    PoisonShadowPartialRightRedzone(
+    FastPoisonShadowPartialRightRedzone(
         g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
         g.size % SHADOW_GRANULARITY,
         SHADOW_GRANULARITY,
@@ -46,6 +60,12 @@ void PoisonRedZones(const Global &g)  {
   }
 }
 
+static void ReportGlobal(const Global &g, const char *prefix) {
+  Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+         prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
+         g.module_name, g.has_dynamic_init);
+}
+
 bool DescribeAddressIfGlobal(uptr addr, uptr size) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
@@ -53,8 +73,7 @@ bool DescribeAddressIfGlobal(uptr addr, uptr size) {
   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     const Global &g = *l->g;
     if (flags()->report_globals >= 2)
-      Report("Search Global: beg=%p size=%zu name=%s\n",
-             (void*)g.beg, g.size, (char*)g.name);
+      ReportGlobal(g, "Search");
     res |= DescribeAddressRelativeToGlobal(addr, size, g);
   }
   return res;
@@ -66,24 +85,26 @@ bool DescribeAddressIfGlobal(uptr addr, uptr size) {
 static void RegisterGlobal(const Global *g) {
   CHECK(asan_inited);
   if (flags()->report_globals >= 2)
-    Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
-           (void*)g->beg, g->size, g->size_with_redzone, g->name,
-           g->has_dynamic_init);
+    ReportGlobal(*g, "Added");
   CHECK(flags()->report_globals);
   CHECK(AddrIsInMem(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  PoisonRedZones(*g);
+  if (flags()->poison_heap)
+    PoisonRedZones(*g);
   ListOfGlobals *l =
       (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
   l->g = g;
   l->next = list_of_all_globals;
   list_of_all_globals = l;
   if (g->has_dynamic_init) {
-    l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
-    l->g = g;
-    l->next = list_of_dynamic_init_globals;
-    list_of_dynamic_init_globals = l;
+    if (dynamic_init_globals == 0) {
+      void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
+      dynamic_init_globals = new(mem)
+          VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
+    }
+    DynInitGlobal dyn_global = { *g, false };
+    dynamic_init_globals->push_back(dyn_global);
   }
 }
 
@@ -93,34 +114,26 @@ static void UnregisterGlobal(const Global *g) {
   CHECK(AddrIsInMem(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  PoisonShadow(g->beg, g->size_with_redzone, 0);
+  if (flags()->poison_heap)
+    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.
 }
 
-// Poison all shadow memory for a single global.
-static void PoisonGlobalAndRedzones(const Global *g) {
-  CHECK(asan_inited);
-  CHECK(flags()->check_initialization_order);
-  CHECK(AddrIsInMem(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  if (flags()->report_globals >= 3)
-    Printf("DynInitPoison  : %s\n", g->name);
-  PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
-}
-
-static void UnpoisonGlobal(const Global *g) {
-  CHECK(asan_inited);
-  CHECK(flags()->check_initialization_order);
-  CHECK(AddrIsInMem(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  if (flags()->report_globals >= 3)
-    Printf("DynInitUnpoison: %s\n", g->name);
-  PoisonShadow(g->beg, g->size_with_redzone, 0);
-  PoisonRedZones(*g);
+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);
+  }
 }
 
 }  // namespace __asan
@@ -151,31 +164,47 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) {
 // 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(uptr first_addr, uptr last_addr) {
-  if (!flags()->check_initialization_order) return;
-  CHECK(list_of_dynamic_init_globals);
+void __asan_before_dynamic_init(const char *module_name) {
+  if (!flags()->check_initialization_order ||
+      !flags()->poison_heap)
+    return;
+  bool strict_init_order = flags()->strict_init_order;
+  CHECK(dynamic_init_globals);
+  CHECK(module_name);
+  CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
-  bool from_current_tu = false;
-  // The list looks like:
-  // a => ... => b => last_addr => ... => first_addr => c => ...
-  // The globals of the current TU reside between last_addr and first_addr.
-  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
-    if (l->g->beg == last_addr)
-      from_current_tu = true;
-    if (!from_current_tu)
-      PoisonGlobalAndRedzones(l->g);
-    if (l->g->beg == first_addr)
-      from_current_tu = false;
+  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;
   }
-  CHECK(!from_current_tu);
 }
 
 // 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) return;
+  if (!flags()->check_initialization_order ||
+      !flags()->poison_heap)
+    return;
+  CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
-  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
-    UnpoisonGlobal(l->g);
+  // 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);
+    }
+  }
 }
index ed75c4284397edec1ef90e205441188a34e8d450..19b53363a5b7cb0c31a1d1efb245fe10f064022e 100644 (file)
 #ifndef ASAN_INTERCEPTED_FUNCTIONS_H
 #define ASAN_INTERCEPTED_FUNCTIONS_H
 
-#include "asan_internal.h"
-#include "interception/interception.h"
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 
-#include <stdarg.h>
-#include <stddef.h>
-
-using __sanitizer::uptr;
-
 // Use macro to describe if specific function should be
 // intercepted on a given platform.
-#if !defined(_WIN32)
+#if !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
 # define ASAN_INTERCEPT__LONGJMP 1
 # define ASAN_INTERCEPT_STRDUP 1
-# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 1
 # define ASAN_INTERCEPT_INDEX 1
 # define ASAN_INTERCEPT_PTHREAD_CREATE 1
 # define ASAN_INTERCEPT_MLOCKX 1
@@ -35,290 +27,51 @@ using __sanitizer::uptr;
 # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
 # define ASAN_INTERCEPT__LONGJMP 0
 # define ASAN_INTERCEPT_STRDUP 0
-# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 0
 # define ASAN_INTERCEPT_INDEX 0
 # define ASAN_INTERCEPT_PTHREAD_CREATE 0
 # define ASAN_INTERCEPT_MLOCKX 0
 #endif
 
-#if defined(__linux__)
+#if SANITIZER_LINUX
 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
 #else
 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
 #endif
 
-#if !defined(__APPLE__)
+#if !SANITIZER_MAC
 # define ASAN_INTERCEPT_STRNLEN 1
 #else
 # define ASAN_INTERCEPT_STRNLEN 0
 #endif
 
-#if defined(__linux__) && !defined(ANDROID)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
 # define ASAN_INTERCEPT_SWAPCONTEXT 1
 #else
 # define ASAN_INTERCEPT_SWAPCONTEXT 0
 #endif
 
-#if !defined(ANDROID) && !defined(_WIN32)
+#if !SANITIZER_ANDROID && !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
 #else
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
 #endif
 
-#if !defined(_WIN32)
+#if !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT_SIGLONGJMP 1
 #else
 # define ASAN_INTERCEPT_SIGLONGJMP 0
 #endif
 
-#if ASAN_HAS_EXCEPTIONS && !defined(_WIN32)
+#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT___CXA_THROW 1
 #else
 # define ASAN_INTERCEPT___CXA_THROW 0
 #endif
 
-#define INTERPOSE_FUNCTION(function) \
-    { reinterpret_cast<const uptr>(WRAP(function)), \
-      reinterpret_cast<const uptr>(function) }
-
-#define INTERPOSE_FUNCTION_2(function, wrapper) \
-    { reinterpret_cast<const uptr>(wrapper), \
-      reinterpret_cast<const uptr>(function) }
-
-struct interpose_substitution {
-  const uptr replacement;
-  const uptr original;
-};
-
-#define INTERPOSER(func) __attribute__((used)) \
-const interpose_substitution substitution_##func[] \
-    __attribute__((section("__DATA, __interpose"))) = { \
-  INTERPOSE_FUNCTION(func), \
-}
-
-#define INTERPOSER_2(func, wrapper) __attribute__((used)) \
-const interpose_substitution substitution_##func[] \
-    __attribute__((section("__DATA, __interpose"))) = { \
-  INTERPOSE_FUNCTION_2(func, wrapper), \
-}
-
-
-#define DECLARE_FUNCTION_AND_WRAPPER(ret_type, func, ...) \
-  ret_type func(__VA_ARGS__); \
-  ret_type WRAP(func)(__VA_ARGS__); \
-  INTERPOSER(func)
-
-// Use extern declarations of intercepted functions on Mac and Windows
-// to avoid including system headers.
-#if defined(__APPLE__) || (defined(_WIN32) && !defined(_DLL))
-extern "C" {
-// signal.h
-# if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
-struct sigaction;
-DECLARE_FUNCTION_AND_WRAPPER(int, sigaction, int sig,
-              const struct sigaction *act,
-              struct sigaction *oldact);
-DECLARE_FUNCTION_AND_WRAPPER(void*, signal, int signum, void *handler);
-# endif
-
-// setjmp.h
-DECLARE_FUNCTION_AND_WRAPPER(void, longjmp, void *env, int value);
-# if ASAN_INTERCEPT__LONGJMP
-DECLARE_FUNCTION_AND_WRAPPER(void, _longjmp, void *env, int value);
-# endif
-# if ASAN_INTERCEPT_SIGLONGJMP
-DECLARE_FUNCTION_AND_WRAPPER(void, siglongjmp, void *env, int value);
-# endif
-# if ASAN_INTERCEPT___CXA_THROW
-DECLARE_FUNCTION_AND_WRAPPER(void, __cxa_throw, void *a, void *b, void *c);
-# endif
-
-// string.h / strings.h
-DECLARE_FUNCTION_AND_WRAPPER(int, memcmp,
-                             const void *a1, const void *a2, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(void*, memmove,
-                             void *to, const void *from, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(void*, memcpy,
-                             void *to, const void *from, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(void*, memset, void *block, int c, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(char*, strchr, const char *str, int c);
-DECLARE_FUNCTION_AND_WRAPPER(char*, strcat,  /* NOLINT */
-                             char *to, const char* from);
-DECLARE_FUNCTION_AND_WRAPPER(char*, strncat,
-                             char *to, const char* from, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(char*, strcpy,  /* NOLINT */
-                             char *to, const char* from);
-DECLARE_FUNCTION_AND_WRAPPER(char*, strncpy,
-                             char *to, const char* from, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(int, strcmp, const char *s1, const char* s2);
-DECLARE_FUNCTION_AND_WRAPPER(int, strncmp,
-                             const char *s1, const char* s2, uptr size);
-DECLARE_FUNCTION_AND_WRAPPER(uptr, strlen, const char *s);
-# if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-DECLARE_FUNCTION_AND_WRAPPER(int, strcasecmp, const char *s1, const char *s2);
-DECLARE_FUNCTION_AND_WRAPPER(int, strncasecmp,
-                             const char *s1, const char *s2, uptr n);
-# endif
-# if ASAN_INTERCEPT_STRDUP
-DECLARE_FUNCTION_AND_WRAPPER(char*, strdup, const char *s);
-# endif
-# if ASAN_INTERCEPT_STRNLEN
-DECLARE_FUNCTION_AND_WRAPPER(uptr, strnlen, const char *s, uptr maxlen);
-# endif
-# if ASAN_INTERCEPT_INDEX
-char* index(const char *string, int c);
-INTERPOSER_2(index, WRAP(strchr));
-# endif
-
-// stdlib.h
-DECLARE_FUNCTION_AND_WRAPPER(int, atoi, const char *nptr);
-DECLARE_FUNCTION_AND_WRAPPER(long, atol, const char *nptr);  // NOLINT
-DECLARE_FUNCTION_AND_WRAPPER(long, strtol, const char *nptr, char **endptr, int base);  // NOLINT
-# if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
-DECLARE_FUNCTION_AND_WRAPPER(long long, atoll, const char *nptr);  // NOLINT
-DECLARE_FUNCTION_AND_WRAPPER(long long, strtoll, const char *nptr, char **endptr, int base);  // NOLINT
-# endif
-
-// unistd.h
-# if SANITIZER_INTERCEPT_READ
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, read, int fd, void *buf, SIZE_T count);
-# endif
-# if SANITIZER_INTERCEPT_PREAD
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pread, int fd, void *buf,
-                             SIZE_T count, OFF_T offset);
-# endif
-# if SANITIZER_INTERCEPT_PREAD64
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pread64, int fd, void *buf,
-                             SIZE_T count, OFF64_T offset);
-# endif
-
-# if SANITIZER_INTERCEPT_WRITE
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, write, int fd, void *ptr, SIZE_T count);
-# endif
-# if SANITIZER_INTERCEPT_PWRITE
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite,
-                             int fd, void *ptr, SIZE_T count, OFF_T offset);
-# endif
-
-# if ASAN_INTERCEPT_MLOCKX
-// mlock/munlock
-DECLARE_FUNCTION_AND_WRAPPER(int, mlock, const void *addr, SIZE_T len);
-DECLARE_FUNCTION_AND_WRAPPER(int, munlock, const void *addr, SIZE_T len);
-DECLARE_FUNCTION_AND_WRAPPER(int, mlockall, int flags);
-DECLARE_FUNCTION_AND_WRAPPER(int, munlockall, void);
-# endif
-
-// Windows threads.
-# if defined(_WIN32)
-__declspec(dllimport)
-void* __stdcall CreateThread(void *sec, uptr st, void* start,
-                             void *arg, DWORD fl, DWORD *id);
-# endif
-// Posix threads.
-# if ASAN_INTERCEPT_PTHREAD_CREATE
-DECLARE_FUNCTION_AND_WRAPPER(int, pthread_create,
-                             void *thread, void *attr,
-                             void *(*start_routine)(void*), void *arg);
-# endif
-
-# if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
-DECLARE_FUNCTION_AND_WRAPPER(void *, localtime, unsigned long *timep);
-DECLARE_FUNCTION_AND_WRAPPER(void *, localtime_r, unsigned long *timep,
-                             void *result);
-DECLARE_FUNCTION_AND_WRAPPER(void *, gmtime, unsigned long *timep);
-DECLARE_FUNCTION_AND_WRAPPER(void *, gmtime_r, unsigned long *timep,
-                             void *result);
-DECLARE_FUNCTION_AND_WRAPPER(char *, ctime, unsigned long *timep);
-DECLARE_FUNCTION_AND_WRAPPER(char *, ctime_r, unsigned long *timep,
-                             char *result);
-DECLARE_FUNCTION_AND_WRAPPER(char *, asctime, void *tm);
-DECLARE_FUNCTION_AND_WRAPPER(char *, asctime_r, void *tm, char *result);
-# endif
-
-// stdio.h
-# if SANITIZER_INTERCEPT_SCANF
-DECLARE_FUNCTION_AND_WRAPPER(int, vscanf, const char *format, va_list ap);
-DECLARE_FUNCTION_AND_WRAPPER(int, vsscanf, const char *str, const char *format,
-                             va_list ap);
-DECLARE_FUNCTION_AND_WRAPPER(int, vfscanf, void *stream, const char *format,
-                             va_list ap);
-DECLARE_FUNCTION_AND_WRAPPER(int, scanf, const char *format, ...);
-DECLARE_FUNCTION_AND_WRAPPER(int, fscanf,
-                             void* stream, const char *format, ...);
-DECLARE_FUNCTION_AND_WRAPPER(int, sscanf,  // NOLINT
-                             const char *str, const char *format, ...);
-# endif
-
-# if defined(__APPLE__)
-typedef void* pthread_workqueue_t;
-typedef void* pthread_workitem_handle_t;
-
-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);
-
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async_f,
-                             dispatch_queue_t dq,
-                             void *ctxt, dispatch_function_t func);
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_sync_f,
-                             dispatch_queue_t dq,
-                             void *ctxt, dispatch_function_t func);
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after_f,
-                             dispatch_time_t when, dispatch_queue_t dq,
-                             void *ctxt, dispatch_function_t func);
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_barrier_async_f,
-                             dispatch_queue_t dq,
-                             void *ctxt, dispatch_function_t func);
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async_f,
-                             dispatch_group_t group, dispatch_queue_t dq,
-                             void *ctxt, dispatch_function_t func);
-
-#  if !defined(MISSING_BLOCKS_SUPPORT)
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async,
-                             dispatch_group_t dg,
-                             dispatch_queue_t dq, void (^work)(void));
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async,
-                             dispatch_queue_t dq, void (^work)(void));
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after,
-                             dispatch_queue_t dq, void (^work)(void));
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_event_handler,
-                             dispatch_source_t ds, void (^work)(void));
-DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_cancel_handler,
-                             dispatch_source_t ds, void (^work)(void));
-#  endif  // MISSING_BLOCKS_SUPPORT
-
-typedef void malloc_zone_t;
-typedef size_t vm_size_t;
-DECLARE_FUNCTION_AND_WRAPPER(malloc_zone_t *, malloc_create_zone,
-                             vm_size_t start_size, unsigned flags);
-DECLARE_FUNCTION_AND_WRAPPER(malloc_zone_t *, malloc_default_zone, void);
-DECLARE_FUNCTION_AND_WRAPPER(
-    malloc_zone_t *, malloc_default_purgeable_zone, void);
-DECLARE_FUNCTION_AND_WRAPPER(void, malloc_make_purgeable, void *ptr);
-DECLARE_FUNCTION_AND_WRAPPER(int, malloc_make_nonpurgeable, void *ptr);
-DECLARE_FUNCTION_AND_WRAPPER(void, malloc_set_zone_name,
-                             malloc_zone_t *zone, const char *name);
-DECLARE_FUNCTION_AND_WRAPPER(void *, malloc, size_t size);
-DECLARE_FUNCTION_AND_WRAPPER(void, free, void *ptr);
-DECLARE_FUNCTION_AND_WRAPPER(void *, realloc, void *ptr, size_t size);
-DECLARE_FUNCTION_AND_WRAPPER(void *, calloc, size_t nmemb, size_t size);
-DECLARE_FUNCTION_AND_WRAPPER(void *, valloc, size_t size);
-DECLARE_FUNCTION_AND_WRAPPER(size_t, malloc_good_size, size_t size);
-DECLARE_FUNCTION_AND_WRAPPER(int, posix_memalign,
-                             void **memptr, size_t alignment, size_t size);
-#if 0
-DECLARE_FUNCTION_AND_WRAPPER(void, _malloc_fork_prepare, void);
-DECLARE_FUNCTION_AND_WRAPPER(void, _malloc_fork_parent, void);
-DECLARE_FUNCTION_AND_WRAPPER(void, _malloc_fork_child, void);
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT___CXA_ATEXIT 1
+#else
+# define ASAN_INTERCEPT___CXA_ATEXIT 0
 #endif
 
-
-
-# endif  // __APPLE__
-}  // extern "C"
-#endif  // defined(__APPLE__) || (defined(_WIN32) && !defined(_DLL))
-
 #endif  // ASAN_INTERCEPTED_FUNCTIONS_H
index 064fc6261b02ed7a54a1944a9aadd36a5945487c..6fa968da0a38ff0caaa9172993a87bccf72efb73 100644 (file)
 #include "asan_intercepted_functions.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_registry.h"
 #include "interception/interception.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
@@ -42,15 +42,16 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
 #define ACCESS_MEMORY_RANGE(offset, size, isWrite) do {                 \
     uptr __offset = (uptr)(offset);                                     \
     uptr __size = (uptr)(size);                                         \
+    uptr __bad = 0;                                                     \
     if (!QuickCheckForUnpoisonedRegion(__offset, __size) &&             \
-        __asan_region_is_poisoned(__offset, __size)) {                  \
+        (__bad = __asan_region_is_poisoned(__offset, __size))) {        \
       GET_CURRENT_PC_BP_SP;                                             \
-      __asan_report_error(pc, bp, sp, __offset, isWrite, __size);       \
+      __asan_report_error(pc, bp, sp, __bad, isWrite, __size);          \
     }                                                                   \
   } while (0)
 
 #define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
-#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true);
+#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true)
 
 // Behavior of functions like "memcpy" or "strcpy" is undefined
 // if memory intervals overlap. We report error in this case.
@@ -86,9 +87,9 @@ static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
 }
 
 void SetThreadName(const char *name) {
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   if (t)
-    t->summary()->set_name(name);
+    asanThreadRegistry().SetThreadName(t->tid(), name);
 }
 
 }  // namespace __asan
@@ -96,40 +97,76 @@ void SetThreadName(const char *name) {
 // ---------------------- Wrappers ---------------- {{{1
 using namespace __asan;  // NOLINT
 
+DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
+
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+  do {                                                \
+  } while (false)
 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
   ASAN_WRITE_RANGE(ptr, size)
 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
-  do {                                           \
-    ctx = 0;                                     \
-    (void)ctx;                                   \
-    ENSURE_ASAN_INITED();                        \
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)              \
+  do {                                                        \
+    if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \
+    ctx = 0;                                                  \
+    (void) ctx;                                               \
+    ENSURE_ASAN_INITED();                                     \
+  } 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_FD_ACQUIRE(ctx, fd) do { } while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+  do {                                       \
+  } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+  do {                                        \
+  } while (false)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
 static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
   AsanThread *t = (AsanThread*)arg;
-  asanThreadRegistry().SetCurrent(t);
-  return t->ThreadStart();
+  SetCurrentThread(t);
+  return t->ThreadStart(GetTid());
 }
 
 #if ASAN_INTERCEPT_PTHREAD_CREATE
+extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
+
 INTERCEPTOR(int, pthread_create, void *thread,
     void *attr, void *(*start_routine)(void*), void *arg) {
+  EnsureMainThreadIDIsCorrect();
+  // Strict init-order checking in thread-hostile.
+  if (flags()->strict_init_order)
+    StopInitOrderChecking();
   GET_STACK_TRACE_THREAD;
-  u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
-  AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
-  asanThreadRegistry().RegisterThread(t);
+  int detached = 0;
+  if (attr != 0)
+    pthread_attr_getdetachstate(attr, &detached);
+
+  u32 current_tid = GetCurrentTidOrInvalid();
+  AsanThread *t = AsanThread::Create(start_routine, arg);
+  CreateThreadContextArgs args = { t, &stack };
+  asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
   return REAL(pthread_create)(thread, attr, asan_thread_start, t);
 }
 #endif  // ASAN_INTERCEPT_PTHREAD_CREATE
 
 #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
 INTERCEPTOR(void*, signal, int signum, void *handler) {
-  if (!AsanInterceptsSignal(signum)) {
+  if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
     return REAL(signal)(signum, handler);
   }
   return 0;
@@ -137,15 +174,15 @@ INTERCEPTOR(void*, signal, int signum, void *handler) {
 
 INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
                             struct sigaction *oldact) {
-  if (!AsanInterceptsSignal(signum)) {
+  if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
     return REAL(sigaction)(signum, act, oldact);
   }
   return 0;
 }
-#elif ASAN_POSIX
+#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);
+    struct sigaction *oldact)
 #endif  // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
 
 #if ASAN_INTERCEPT_SWAPCONTEXT
@@ -215,13 +252,15 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
 // Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
 // All functions return 0 (success).
 static void MlockIsUnsupported() {
-  static bool printed = 0;
+  static bool printed = false;
   if (printed) return;
   printed = true;
-  Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+  if (flags()->verbosity > 0) {
+    Printf("INFO: AddressSanitizer ignores "
+           "mlock/mlockall/munlock/munlockall\n");
+  }
 }
 
-extern "C" {
 INTERCEPTOR(int, mlock, const void *addr, uptr len) {
   MlockIsUnsupported();
   return 0;
@@ -241,36 +280,56 @@ INTERCEPTOR(int, munlockall, void) {
   MlockIsUnsupported();
   return 0;
 }
-}  // extern "C"
 
 static inline int CharCmp(unsigned char c1, unsigned char c2) {
   return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
 }
 
-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, memcmp, const void *a1, const void *a2, uptr size) {
   if (!asan_inited) return internal_memcmp(a1, a2, size);
   ENSURE_ASAN_INITED();
-  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;
+  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(a1, size);
+      ASAN_READ_RANGE(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(s1, Min(i + 1, size));
+      ASAN_READ_RANGE(s2, Min(i + 1, size));
+      return CharCmp(c1, c2);
+    }
   }
-  ASAN_READ_RANGE(s1, Min(i + 1, size));
-  ASAN_READ_RANGE(s2, Min(i + 1, size));
-  return CharCmp(c1, c2);
+  return REAL(memcmp(a1, a2, size));
 }
 
+#define MEMMOVE_BODY { \
+  if (!asan_inited) return internal_memmove(to, from, size); \
+  if (asan_init_is_running) { \
+    return REAL(memmove)(to, from, size); \
+  } \
+  ENSURE_ASAN_INITED(); \
+  if (flags()->replace_intrin) { \
+    ASAN_READ_RANGE(from, size); \
+    ASAN_WRITE_RANGE(to, size); \
+  } \
+  return internal_memmove(to, from, size); \
+}
+
+INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY
+
 INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
+#if !SANITIZER_MAC
   if (!asan_inited) return internal_memcpy(to, from, size);
   // memcpy is called during __asan_init() from the internals
   // of printf(...).
@@ -287,24 +346,19 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
     ASAN_READ_RANGE(from, size);
     ASAN_WRITE_RANGE(to, size);
   }
-  // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
+  // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8, so
+  // calling REAL(memcpy) here leads to infinite recursion.
   // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
   return internal_memcpy(to, from, size);
-}
-
-INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
-  if (!asan_inited) return internal_memmove(to, from, size);
-  if (asan_init_is_running) {
-    return REAL(memmove)(to, from, size);
-  }
-  ENSURE_ASAN_INITED();
-  if (flags()->replace_intrin) {
-    ASAN_READ_RANGE(from, size);
-    ASAN_WRITE_RANGE(to, size);
-  }
-  // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
-  // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
-  return internal_memmove(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.
+  MEMMOVE_BODY
+#endif  // !SANITIZER_MAC
 }
 
 INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
@@ -341,7 +395,12 @@ INTERCEPTOR(char*, strchr, const char *str, int c) {
 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
 
@@ -383,26 +442,8 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
   return REAL(strncat)(to, from, size);
 }
 
-INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
-  if (!asan_inited) return internal_strcmp(s1, s2);
-  if (asan_init_is_running) {
-    return REAL(strcmp)(s1, s2);
-  }
-  ENSURE_ASAN_INITED();
-  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;
-  }
-  ASAN_READ_RANGE(s1, i + 1);
-  ASAN_READ_RANGE(s2, i + 1);
-  return CharCmp(c1, c2);
-}
-
 INTERCEPTOR(char*, strcpy, char *to, const char *from) {  // NOLINT
-#if defined(__APPLE__)
+#if SANITIZER_MAC
   if (!asan_inited) return REAL(strcpy)(to, from);  // NOLINT
 #endif
   // strcpy is called from malloc_default_purgeable_zone()
@@ -422,21 +463,16 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) {  // NOLINT
 
 #if ASAN_INTERCEPT_STRDUP
 INTERCEPTOR(char*, strdup, const char *s) {
-#if defined(__APPLE__)
-  // FIXME: because internal_strdup() uses InternalAlloc(), which currently
-  // just calls malloc() on Mac, we can't use internal_strdup() with the
-  // dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc
-  // starts using mmap() instead.
-  // See also http://code.google.com/p/address-sanitizer/issues/detail?id=123.
-  if (!asan_inited) return REAL(strdup)(s);
-#endif
   if (!asan_inited) return internal_strdup(s);
   ENSURE_ASAN_INITED();
+  uptr length = REAL(strlen)(s);
   if (flags()->replace_str) {
-    uptr length = REAL(strlen)(s);
     ASAN_READ_RANGE(s, length + 1);
   }
-  return REAL(strdup)(s);
+  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
 
@@ -455,54 +491,13 @@ INTERCEPTOR(uptr, strlen, const char *s) {
   return length;
 }
 
-#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
-  ENSURE_ASAN_INITED();
-  unsigned char c1, c2;
-  uptr i;
-  for (i = 0; ; i++) {
-    c1 = (unsigned char)s1[i];
-    c2 = (unsigned char)s2[i];
-    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
-  }
-  ASAN_READ_RANGE(s1, i + 1);
-  ASAN_READ_RANGE(s2, i + 1);
-  return CharCaseCmp(c1, c2);
-}
-
-INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, uptr n) {
-  ENSURE_ASAN_INITED();
-  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;
-  }
-  ASAN_READ_RANGE(s1, Min(i + 1, n));
-  ASAN_READ_RANGE(s2, Min(i + 1, n));
-  return CharCaseCmp(c1, c2);
-}
-#endif  // ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-
-INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
-  if (!asan_inited) return internal_strncmp(s1, s2, size);
-  // strncmp is called from malloc_default_purgeable_zone()
-  // in __asan::ReplaceSystemAlloc() on Mac.
-  if (asan_init_is_running) {
-    return REAL(strncmp)(s1, s2, size);
-  }
-  ENSURE_ASAN_INITED();
-  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;
+INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
+  uptr length = REAL(wcslen)(s);
+  if (!asan_init_is_running) {
+    ENSURE_ASAN_INITED();
+    ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
   }
-  ASAN_READ_RANGE(s1, Min(i + 1, size));
-  ASAN_READ_RANGE(s2, Min(i + 1, size));
-  return CharCmp(c1, c2);
+  return length;
 }
 
 INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
@@ -532,7 +527,7 @@ static inline bool IsValidStrtolBase(int base) {
 }
 
 static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
-  CHECK(endptr != 0);
+  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.
@@ -563,7 +558,7 @@ INTERCEPTOR(long, strtol, const char *nptr,  // NOLINT
 }
 
 INTERCEPTOR(int, atoi, const char *nptr) {
-#if defined(__APPLE__)
+#if SANITIZER_MAC
   if (!asan_inited) return REAL(atoi)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -582,7 +577,7 @@ INTERCEPTOR(int, atoi, const char *nptr) {
 }
 
 INTERCEPTOR(long, atol, const char *nptr) {  // NOLINT
-#if defined(__APPLE__)
+#if SANITIZER_MAC
   if (!asan_inited) return REAL(atol)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -631,22 +626,47 @@ INTERCEPTOR(long long, atoll, const char *nptr) {  // NOLINT
 }
 #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) {
+  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 !SANITIZER_MAC
 #define ASAN_INTERCEPT_FUNC(name) do { \
       if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
         Report("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
 
-#if defined(_WIN32)
+#if SANITIZER_WINDOWS
 INTERCEPTOR_WINAPI(DWORD, CreateThread,
                    void* security, uptr stack_size,
                    DWORD (__stdcall *start_routine)(void*), void* arg,
-                   DWORD flags, void* tid) {
+                   DWORD thr_flags, void* tid) {
+  // Strict init-order checking in thread-hostile.
+  if (flags()->strict_init_order)
+    StopInitOrderChecking();
   GET_STACK_TRACE_THREAD;
-  u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
-  AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
-  asanThreadRegistry().RegisterThread(t);
+  u32 current_tid = GetCurrentTidOrInvalid();
+  AsanThread *t = AsanThread::Create(start_routine, arg);
+  CreateThreadContextArgs args = { t, &stack };
+  bool detached = false;  // FIXME: how can we determine it on Windows?
+  asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
   return REAL(CreateThread)(security, stack_size,
-                            asan_thread_start, t, flags, tid);
+                            asan_thread_start, t, thr_flags, tid);
 }
 
 namespace __asan {
@@ -663,9 +683,6 @@ void InitializeAsanInterceptors() {
   static bool was_called_once;
   CHECK(was_called_once == false);
   was_called_once = true;
-#if defined(__APPLE__)
-  return;
-#else
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
   // Intercept mem* functions.
@@ -679,16 +696,11 @@ void InitializeAsanInterceptors() {
   // Intercept str* functions.
   ASAN_INTERCEPT_FUNC(strcat);  // NOLINT
   ASAN_INTERCEPT_FUNC(strchr);
-  ASAN_INTERCEPT_FUNC(strcmp);
   ASAN_INTERCEPT_FUNC(strcpy);  // NOLINT
   ASAN_INTERCEPT_FUNC(strlen);
+  ASAN_INTERCEPT_FUNC(wcslen);
   ASAN_INTERCEPT_FUNC(strncat);
-  ASAN_INTERCEPT_FUNC(strncmp);
   ASAN_INTERCEPT_FUNC(strncpy);
-#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-  ASAN_INTERCEPT_FUNC(strcasecmp);
-  ASAN_INTERCEPT_FUNC(strncasecmp);
-#endif
 #if ASAN_INTERCEPT_STRDUP
   ASAN_INTERCEPT_FUNC(strdup);
 #endif
@@ -741,15 +753,19 @@ void InitializeAsanInterceptors() {
   ASAN_INTERCEPT_FUNC(pthread_create);
 #endif
 
+  // Intercept atexit function.
+#if ASAN_INTERCEPT___CXA_ATEXIT
+  ASAN_INTERCEPT_FUNC(__cxa_atexit);
+#endif
+
   // Some Windows-specific interceptors.
-#if defined(_WIN32)
+#if SANITIZER_WINDOWS
   InitializeWindowsInterceptors();
 #endif
 
   if (flags()->verbosity > 0) {
     Report("AddressSanitizer: libc interceptors initialized\n");
   }
-#endif  // __APPLE__
 }
 
 }  // namespace __asan
index 2fd58b856bcf974b0403aac268965b005710380d..7deed9f46073e4088dc346379265f9acad657dde 100644 (file)
@@ -23,8 +23,13 @@ extern "C" {
   // Everytime the asan ABI changes we also change the version number in this
   // name. Objects build with incompatible asan ABI version
   // will not link with run-time.
-  void __asan_init_v1() SANITIZER_INTERFACE_ATTRIBUTE;
-  #define __asan_init __asan_init_v1
+  // 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).
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
+  #define __asan_init __asan_init_v3
 
   // This structure describes an instrumented global variable.
   struct __asan_global {
@@ -32,102 +37,92 @@ extern "C" {
     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.
   };
 
   // These two functions should be called by the instrumented code.
   // 'globals' is an array of structures describing 'n' globals.
-  void __asan_register_globals(__asan_global *globals, uptr n)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_unregister_globals(__asan_global *globals, uptr n)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  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
-  // run, respectively.  They should be called with parameters describing all
-  // dynamically initialized globals defined in the calling TU.
-  void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_after_dynamic_init()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // These two functions are used by the instrumented code in the
-  // use-after-return mode. __asan_stack_malloc allocates size bytes of
-  // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
-  // the real stack region.
-  uptr __asan_stack_malloc(uptr size, uptr real_stack)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  // 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.
-  void __asan_poison_stack_memory(uptr addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_unpoison_stack_memory(uptr addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  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.
-  void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return();
 
-  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;
+  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);
 
-  bool __asan_address_is_poisoned(void const volatile *addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE
+  bool __asan_address_is_poisoned(void const volatile *addr);
 
-  uptr __asan_region_is_poisoned(uptr beg, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_region_is_poisoned(uptr beg, uptr size);
 
-  void __asan_describe_address(uptr addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_describe_address(uptr addr);
 
+  SANITIZER_INTERFACE_ATTRIBUTE
   void __asan_report_error(uptr pc, uptr bp, uptr sp,
-                           uptr addr, bool is_write, uptr access_size)
-    SANITIZER_INTERFACE_ATTRIBUTE;
+                           uptr addr, bool is_write, uptr access_size);
 
-  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_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*));
 
-  /* OPTIONAL */ void __asan_on_error()
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  /* OPTIONAL */ void __asan_on_error();
 
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
   /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
-                                       int out_size)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
-
-  uptr __asan_get_estimated_allocated_size(uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  bool __asan_get_ownership(const void *p)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  uptr __asan_get_allocated_size(const void *p)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  uptr __asan_get_current_allocated_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  uptr __asan_get_heap_size()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  uptr __asan_get_free_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  uptr __asan_get_unmapped_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_print_accumulated_stats()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
-  /* OPTIONAL */ const char* __asan_default_options()
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
-
-  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
-  /* OPTIONAL */ void __asan_free_hook(void *ptr)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+                                       int out_size);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_estimated_allocated_size(uptr size);
+
+  SANITIZER_INTERFACE_ATTRIBUTE bool __asan_get_ownership(const void *p);
+  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p);
+  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes();
+  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size();
+  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes();
+  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes();
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
+
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  /* OPTIONAL */ const char* __asan_default_options();
+
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size);
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  /* OPTIONAL */ void __asan_free_hook(void *ptr);
+
+  // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
+  SANITIZER_INTERFACE_ATTRIBUTE
+  extern int __asan_option_detect_stack_use_after_return;
 }  // extern "C"
 
 #endif  // ASAN_INTERFACE_INTERNAL_H
index 1ccbf10864781a3c76c29cc1051f8e238c930e9a..b5b48708090c9d9313e559b8856a8a4ec7c251e0 100644 (file)
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
-#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
-# error "This operating system is not supported by AddressSanitizer"
-#endif
-
 #define ASAN_DEFAULT_FAILURE_EXITCODE 1
 
-#if defined(__linux__)
-# define ASAN_LINUX   1
-#else
-# define ASAN_LINUX   0
-#endif
-
-#if defined(__APPLE__)
-# define ASAN_MAC     1
-#else
-# define ASAN_MAC     0
-#endif
-
-#if defined(_WIN32)
-# define ASAN_WINDOWS 1
-#else
-# define ASAN_WINDOWS 0
-#endif
-
-#if defined(__ANDROID__) || defined(ANDROID)
-# define ASAN_ANDROID 1
-#else
-# define ASAN_ANDROID 0
-#endif
-
-
-#define ASAN_POSIX (ASAN_LINUX || ASAN_MAC)
-
 #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
 # error "The AddressSanitizer run-time should not be"
         " instrumented by AddressSanitizer"
@@ -61,7 +30,7 @@
 
 // If set, asan will install its own SEGV signal handler.
 #ifndef ASAN_NEEDS_SEGV
-# if ASAN_ANDROID == 1
+# if SANITIZER_ANDROID == 1
 #  define ASAN_NEEDS_SEGV 0
 # else
 #  define ASAN_NEEDS_SEGV 1
@@ -90,7 +59,7 @@
 #endif
 
 #ifndef ASAN_USE_PREINIT_ARRAY
-# define ASAN_USE_PREINIT_ARRAY (ASAN_LINUX && !ASAN_ANDROID)
+# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
 #endif
 
 // All internal functions in asan reside inside the __asan namespace
@@ -121,6 +90,7 @@ void UnsetAlternateSignalStack();
 void InstallSignalHandlers();
 void ReadContextStack(void *context, uptr *stack, uptr *ssize);
 void AsanPlatformThreadInit();
+void StopInitOrderChecking();
 
 // Wrapper for TLS/TSD.
 void AsanTSDInit(void (*destructor)(void *tsd));
@@ -129,24 +99,14 @@ void AsanTSDSet(void *tsd);
 
 void AppendToErrorMessageBuffer(const char *buffer);
 
-// asan_poisoning.cc
-// 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);
-
 // Platfrom-specific options.
-#ifdef __APPLE__
+#if SANITIZER_MAC
 bool PlatformHasDifferentMemcpyAndMemmove();
 # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
     (PlatformHasDifferentMemcpyAndMemmove())
 #else
 # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
 
 // Add convenient macro for interface functions that may be represented as
 // weak hooks.
index a030fcd397298696c078488fa51a14e50c95b8f1..10c6175092bba7ed8320cca4d6b8c32980e5665d 100644 (file)
@@ -9,12 +9,13 @@
 //
 // Linux-specific details.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
@@ -29,7 +30,7 @@
 #include <unistd.h>
 #include <unwind.h>
 
-#if !ASAN_ANDROID
+#if !SANITIZER_ANDROID
 // FIXME: where to get ucontext on Android?
 #include <sys/ucontext.h>
 #endif
@@ -48,7 +49,7 @@ void *AsanDoesNotSupportStaticLinkage() {
 }
 
 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
-#if ASAN_ANDROID
+#if SANITIZER_ANDROID
   *pc = *sp = *bp = 0;
 #elif defined(__arm__)
   ucontext_t *ucontext = (ucontext_t*)context;
@@ -86,6 +87,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
   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
@@ -99,25 +105,7 @@ void AsanPlatformThreadInit() {
   // Nothing here for now.
 }
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
-#if defined(__arm__) || \
-    defined(__powerpc__) || defined(__powerpc64__) || \
-    defined(__sparc__)
-  fast = false;
-#endif
-  if (!fast)
-    return stack->SlowUnwindStack(pc, max_s);
-  stack->size = 0;
-  stack->trace[0] = pc;
-  if (max_s > 1) {
-    stack->max_size = max_s;
-    if (!asan_inited) return;
-    if (AsanThread *t = asanThreadRegistry().GetCurrent())
-      stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
-  }
-}
-
-#if !ASAN_ANDROID
+#if !SANITIZER_ANDROID
 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
   ucontext_t *ucp = (ucontext_t*)context;
   *stack = (uptr)ucp->uc_stack.ss_sp;
@@ -131,4 +119,4 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
 
 }  // namespace __asan
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
index dd2657df1e25277506bc30eb252435690c872426..4b28c1422cd9fb6e39f4bd68f54ff7bf2e703826 100644 (file)
@@ -10,7 +10,8 @@
 // Mac-specific details.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
 
 #include "asan_interceptors.h"
 #include "asan_internal.h"
@@ -18,7 +19,7 @@
 #include "asan_mapping.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
+#include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 #include <crt_externs.h>  // for _NSGetArgv
@@ -50,15 +51,17 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
 # endif  // SANITIZER_WORDSIZE
 }
 
-int GetMacosVersion() {
+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(sysctl(mib, 2, 0, &len, 0, 0) != -1);
-  CHECK(len < maxlen);
-  CHECK(sysctl(mib, 2, version, &len, 0, 0) != -1);
+  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': {
@@ -66,6 +69,7 @@ int GetMacosVersion() {
         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;
         default: return MACOS_VERSION_UNKNOWN;
       }
     }
@@ -73,6 +77,18 @@ int GetMacosVersion() {
   }
 }
 
+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;
+}
+
 bool PlatformHasDifferentMemcpyAndMemmove() {
   // On OS X 10.7 memcpy() and memmove() are both resolved
   // into memmove$VARIANT$sse42.
@@ -227,18 +243,6 @@ bool AsanInterceptsSignal(int signum) {
 void AsanPlatformThreadInit() {
 }
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
-  (void)fast;
-  stack->size = 0;
-  stack->trace[0] = pc;
-  if ((max_s) > 1) {
-    stack->max_size = max_s;
-    if (!asan_inited) return;
-    if (AsanThread *t = asanThreadRegistry().GetCurrent())
-      stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
-  }
-}
-
 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
   UNIMPLEMENTED();
 }
@@ -286,32 +290,16 @@ typedef struct {
   u32 parent_tid;
 } asan_block_context_t;
 
-// We use extern declarations of libdispatch functions here instead
-// of including <dispatch/dispatch.h>. This header is not present on
-// Mac OS X Leopard and eariler, and although we don't expect ASan to
-// work on legacy systems, it's bad to break the build of
-// LLVM compiler-rt there.
-extern "C" {
-void dispatch_async_f(dispatch_queue_t dq, void *ctxt,
-                      dispatch_function_t func);
-void dispatch_sync_f(dispatch_queue_t dq, void *ctxt,
-                     dispatch_function_t func);
-void dispatch_after_f(dispatch_time_t when, dispatch_queue_t dq, void *ctxt,
-                      dispatch_function_t func);
-void dispatch_barrier_async_f(dispatch_queue_t dq, void *ctxt,
-                              dispatch_function_t func);
-void dispatch_group_async_f(dispatch_group_t group, dispatch_queue_t dq,
-                            void *ctxt, dispatch_function_t func);
-}  // extern "C"
-
-static ALWAYS_INLINE
+ALWAYS_INLINE
 void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   if (!t) {
-    t = AsanThread::Create(parent_tid, 0, 0, stack);
-    asanThreadRegistry().RegisterThread(t);
+    t = AsanThread::Create(0, 0);
+    CreateThreadContextArgs args = { t, stack };
+    asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
     t->Init();
-    asanThreadRegistry().SetCurrent(t);
+    asanThreadRegistry().StartThread(t->tid(), 0, 0);
+    SetCurrentThread(t);
   }
 }
 
@@ -345,7 +333,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
       (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
   asan_ctxt->block = ctxt;
   asan_ctxt->func = func;
-  asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+  asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
   return asan_ctxt;
 }
 
@@ -411,7 +399,7 @@ 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 = asanThreadRegistry().GetCurrentTidOrInvalid(); \
+  int parent_tid = GetCurrentTidOrInvalid(); \
   asan_block = ^(void) { \
     GET_STACK_TRACE_THREAD; \
     asan_register_worker_thread(parent_tid, &stack); \
@@ -449,4 +437,4 @@ INTERCEPTOR(void, dispatch_source_set_event_handler,
 }
 #endif
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
index 2c162fb0c397f58c2ad1384d896dc8d71d4bb5f8..2d1d4b0bfb33d6e11309659a281763171a89fb1b 100644 (file)
@@ -34,12 +34,14 @@ typedef struct __CFRuntimeBase {
 #endif
 } CFRuntimeBase;
 
-enum {
-  MACOS_VERSION_UNKNOWN = 0,
+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_MOUNTAIN_LION,
+  MACOS_VERSION_MAVERICKS
 };
 
 // Used by asan_malloc_mac.cc and asan_mac.cc
@@ -47,7 +49,7 @@ extern "C" void __CFInitialize();
 
 namespace __asan {
 
-int GetMacosVersion();
+MacosVersion GetMacosVersion();
 void MaybeReplaceCFAllocator();
 
 }  // namespace __asan
index 18e6a3be865ce82b131a883680d23fc18c6d95ae..97691fcd361e1c95b347466dcc5c0bc772cc8596 100644 (file)
 // We simply define functions like malloc, free, realloc, etc.
 // They will replace the corresponding libc functions automagically.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_stack.h"
-#include "asan_thread_registry.h"
 
-#if ASAN_ANDROID
+#if SANITIZER_ANDROID
 DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
 DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
 DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
@@ -144,4 +145,4 @@ INTERCEPTOR(void, malloc_stats, void) {
   __asan_print_accumulated_stats();
 }
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
index 3ae6c59465093c31dac1f66231cb509b536719aa..342e806e3b67e494b643000cf938256cfad2f3db 100644 (file)
 // Mac-specific malloc interception.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#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"
@@ -24,7 +26,6 @@
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
-#include "asan_thread_registry.h"
 
 // Similar code is used in Google Perftools,
 // http://code.google.com/p/google-perftools.
@@ -40,10 +41,19 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
                              vm_size_t start_size, unsigned zone_flags) {
   if (!asan_inited) __asan_init();
   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_malloc(sizeof(asan_zone), &stack);
+      (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;
 }
 
@@ -282,7 +292,7 @@ void mi_force_unlock(malloc_zone_t *zone) {
 
 void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
   AsanMallocStats malloc_stats;
-  asanThreadRegistry().FillMallocStatistics(&malloc_stats);
+  FillMallocStatistics(&malloc_stats);
   CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
   internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
 }
@@ -344,4 +354,4 @@ void ReplaceSystemMalloc() {
 }
 }  // namespace __asan
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
index 437079f5d1dd84819665f3c3a3a0612cc42156b6..cabf8cd254c80abee43cd77a6bbdb201358fe28d 100644 (file)
@@ -9,7 +9,9 @@
 //
 // Windows-specific malloc interception.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
@@ -28,11 +30,13 @@ using namespace __asan;  // NOLINT
 // revisited in the future.
 
 extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
 void free(void *ptr) {
   GET_STACK_TRACE_FREE;
   return asan_free(ptr, &stack, FROM_MALLOC);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void _free_dbg(void* ptr, int) {
   free(ptr);
 }
@@ -41,38 +45,46 @@ void cfree(void *ptr) {
   CHECK(!"cfree() should not be used on Windows?");
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void *malloc(size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_malloc(size, &stack);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void* _malloc_dbg(size_t size, int , const char*, int) {
   return malloc(size);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void *calloc(size_t nmemb, size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_calloc(nmemb, size, &stack);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
   return calloc(n, size);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
   return calloc(nmemb, size);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void *realloc(void *ptr, size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_realloc(ptr, size, &stack);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void *_realloc_dbg(void *ptr, size_t size, int) {
   CHECK(!"_realloc_dbg should not exist!");
   return 0;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 void* _recalloc(void* p, size_t n, size_t elem_size) {
   if (!p)
     return calloc(n, elem_size);
@@ -82,6 +94,7 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
   return realloc(p, size);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 size_t _msize(void *ptr) {
   GET_STACK_TRACE_MALLOC;
   return asan_malloc_usable_size(ptr, &stack);
index 9b4dd35f1eb52098ab37a36ee488a6c95c9a2db4..fd5c2039bcac46c44dc5b632e6caa04bfa7be962 100644 (file)
 // || `[0x24000000, 0x27ffffff]` || ShadowGap  ||
 // || `[0x20000000, 0x23ffffff]` || LowShadow  ||
 // || `[0x00000000, 0x1fffffff]` || LowMem     ||
+//
+// Default Linux/MIPS mapping:
+// || `[0x2aaa8000, 0xffffffff]` || HighMem    ||
+// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
+// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap  ||
+// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow  ||
+// || `[0x00000000, 0x0aaa7fff]` || LowMem     ||
+
+static const u64 kDefaultShadowScale = 3;
+static const u64 kDefaultShadowOffset32 = 1ULL << 29;
+static const u64 kDefaultShadowOffset64 = 1ULL << 44;
+static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000;  // < 2G.
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
 
 #if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
 extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
@@ -54,22 +68,23 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
 # define SHADOW_SCALE (__asan_mapping_scale)
 # define SHADOW_OFFSET (__asan_mapping_offset)
 #else
-# if ASAN_ANDROID
-#  define SHADOW_SCALE (3)
+# define SHADOW_SCALE kDefaultShadowScale
+# if SANITIZER_ANDROID
 #  define SHADOW_OFFSET (0)
 # else
-#  define SHADOW_SCALE (3)
 #  if SANITIZER_WORDSIZE == 32
-#   define SHADOW_OFFSET (1 << 29)
+#   if defined(__mips__)
+#     define SHADOW_OFFSET kMIPS32_ShadowOffset32
+#   else
+#     define SHADOW_OFFSET kDefaultShadowOffset32
+#   endif
 #  else
 #   if defined(__powerpc64__)
-#    define SHADOW_OFFSET (1ULL << 41)
+#    define SHADOW_OFFSET kPPC64_ShadowOffset64
+#   elif SANITIZER_MAC
+#    define SHADOW_OFFSET kDefaultShadowOffset64
 #   else
-#    if ASAN_MAC
-#     define SHADOW_OFFSET (1ULL << 44)
-#    else
-#     define SHADOW_OFFSET 0x7fff8000ULL
-#    endif
+#    define SHADOW_OFFSET kDefaultShort64bitShadowOffset
 #   endif
 #  endif
 # endif
@@ -131,7 +146,6 @@ static uptr kHighMemEnd = 0x7fffffffffffULL;
 static uptr kMidMemBeg =    0x3000000000ULL;
 static uptr kMidMemEnd =    0x4fffffffffULL;
 #else
-SANITIZER_INTERFACE_ATTRIBUTE
 extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;  // Initialized in __asan_init.
 #endif
 
index fd47eee42058e79bb33a672d3b5daac7f9b9342b..beac8cdbdd5ecea8843b4ae18807f6c71f038bae 100644 (file)
@@ -27,7 +27,7 @@ using namespace __asan;  // NOLINT
 
 // On Android new() goes through malloc interceptors.
 // See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !ASAN_ANDROID
+#if !SANITIZER_ANDROID
 
 // Fake std::nothrow_t to avoid including <new>.
 namespace std {
@@ -38,6 +38,14 @@ struct nothrow_t {};
   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
 INTERCEPTOR_ATTRIBUTE
 void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
 INTERCEPTOR_ATTRIBUTE
@@ -49,10 +57,26 @@ INTERCEPTOR_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
 INTERCEPTOR_ATTRIBUTE
 void operator delete(void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); }
 INTERCEPTOR_ATTRIBUTE
@@ -64,4 +88,19 @@ INTERCEPTOR_ATTRIBUTE
 void operator delete[](void *ptr, std::nothrow_t const&)
 { OPERATOR_DELETE_BODY(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
+
 #endif
index 7e930034bef0cdcd17c4d7462de0135e7e5266f7..b967acded636979e27d4f57a467bae2b554388ba 100644 (file)
@@ -10,9 +10,7 @@
 // Shadow memory poisoning by ASan RTL and by user application.
 //===----------------------------------------------------------------------===//
 
-#include "asan_interceptors.h"
-#include "asan_internal.h"
-#include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 namespace __asan {
@@ -20,11 +18,11 @@ namespace __asan {
 void PoisonShadow(uptr addr, uptr size, u8 value) {
   if (!flags()->poison_heap) return;
   CHECK(AddrIsAlignedByGranularity(addr));
+  CHECK(AddrIsInMem(addr));
   CHECK(AddrIsAlignedByGranularity(addr + size));
-  uptr shadow_beg = MemToShadow(addr);
-  uptr shadow_end = MemToShadow(addr + size - SHADOW_GRANULARITY) + 1;
-  CHECK(REAL(memset) != 0);
-  REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+  CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
+  CHECK(REAL(memset));
+  FastPoisonShadow(addr, size, value);
 }
 
 void PoisonShadowPartialRightRedzone(uptr addr,
@@ -33,20 +31,10 @@ void PoisonShadowPartialRightRedzone(uptr addr,
                                      u8 value) {
   if (!flags()->poison_heap) return;
   CHECK(AddrIsAlignedByGranularity(addr));
-  u8 *shadow = (u8*)MemToShadow(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 {
-      *shadow = size - i;  // first size-i bytes are addressable
-    }
-  }
+  CHECK(AddrIsInMem(addr));
+  FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value);
 }
 
-
 struct ShadowSegmentEndpoint {
   u8 *chunk;
   s8 offset;  // in [0, SHADOW_GRANULARITY)
@@ -179,6 +167,55 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
   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;
+}
+
 // 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) {
diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h
new file mode 100644 (file)
index 0000000..866c0a5
--- /dev/null
@@ -0,0 +1,57 @@
+//===-- asan_poisoning.h ----------------------------------------*- C++ -*-===//
+//
+// 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"
+
+namespace __asan {
+
+// 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(flags()->poison_heap);
+  uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
+  uptr shadow_end = MEM_TO_SHADOW(
+      aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
+  REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+}
+
+ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
+    uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
+  DCHECK(flags()->poison_heap);
+  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 = static_cast<u8>(size - i);
+    }
+  }
+}
+
+}  // namespace __asan
index 177b84ae67fb009e00a2ba24c544ebb088f6d35e..a210a810036ec1a7834f2bc342e9b82e17fd70ec 100644 (file)
@@ -9,14 +9,15 @@
 //
 // Posix-specific details.
 //===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "asan_internal.h"
 #include "asan_interceptors.h"
 #include "asan_mapping.h"
 #include "asan_report.h"
 #include "asan_stack.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
@@ -40,7 +41,7 @@ static void MaybeInstallSigaction(int signum,
   sigact.sa_sigaction = handler;
   sigact.sa_flags = SA_SIGINFO;
   if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
-  CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
+  CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
   if (flags()->verbosity >= 1) {
     Report("Installed the sigaction for signal %d\n", signum);
   }
@@ -57,7 +58,7 @@ static void     ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
 
 void SetAlternateSignalStack() {
   stack_t altstack, oldstack;
-  CHECK(0 == sigaltstack(0, &oldstack));
+  CHECK_EQ(0, sigaltstack(0, &oldstack));
   // If the alternate stack is already in place, do nothing.
   if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
   // TODO(glider): the mapped stack should have the MAP_STACK flag in the
@@ -67,10 +68,10 @@ void SetAlternateSignalStack() {
   altstack.ss_sp = base;
   altstack.ss_flags = 0;
   altstack.ss_size = kAltStackSize;
-  CHECK(0 == sigaltstack(&altstack, 0));
+  CHECK_EQ(0, sigaltstack(&altstack, 0));
   if (flags()->verbosity > 0) {
     Report("Alternative stack for T%d set: [%p,%p)\n",
-           asanThreadRegistry().GetCurrentTidOrInvalid(),
+           GetCurrentTidOrInvalid(),
            altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
   }
 }
@@ -80,7 +81,7 @@ void UnsetAlternateSignalStack() {
   altstack.ss_sp = 0;
   altstack.ss_flags = SS_DISABLE;
   altstack.ss_size = 0;
-  CHECK(0 == sigaltstack(&altstack, &oldstack));
+  CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
   UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
 }
 
@@ -100,7 +101,7 @@ static bool tsd_key_inited = false;
 void AsanTSDInit(void (*destructor)(void *tsd)) {
   CHECK(!tsd_key_inited);
   tsd_key_inited = true;
-  CHECK(0 == pthread_key_create(&tsd_key, destructor));
+  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
 }
 
 void *AsanTSDGet() {
@@ -115,4 +116,4 @@ void AsanTSDSet(void *tsd) {
 
 }  // namespace __asan
 
-#endif  // __linux__ || __APPLE_
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
index 40309fa389de2395ce2af8bbdeaf0cbed6a6ebee..31042401536dfdced13f03d013a9cab9fd8766c4 100644 (file)
   // On Linux, we force __asan_init to be called before anyone else
   // by placing it into .preinit_array section.
   // FIXME: do we have anything like this on Mac?
+  // The symbol is called __local_asan_preinit, because it's not intended to be
+  // exported.
   __attribute__((section(".preinit_array"), used))
-  void (*__asan_preinit)(void) =__asan_init;
-#elif defined(_WIN32) && defined(_DLL)
+  void (*__local_asan_preinit)(void) = __asan_init;
+#elif SANITIZER_WINDOWS && defined(_DLL)
   // On Windows, when using dynamic CRT (/MD), we can put a pointer
   // to __asan_init into the global list of C initializers.
   // See crt0dat.c in the CRT sources for the details.
index 13e94c421b5d08dc705a47b33502c76a76e506dc..8f11ff4eac333146275125789898524557a9e1f1 100644 (file)
@@ -15,8 +15,8 @@
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 
@@ -42,15 +42,6 @@ void AppendToErrorMessageBuffer(const char *buffer) {
 }
 
 // ---------------------- Decorator ------------------------------ {{{1
-bool PrintsToTtyCached() {
-  static int cached = 0;
-  static bool prints_to_tty;
-  if (!cached) {  // Ok wrt threads since we are printing only from one thread.
-    prints_to_tty = PrintsToTty();
-    cached = 1;
-  }
-  return prints_to_tty;
-}
 class Decorator: private __sanitizer::AnsiColorDecorator {
  public:
   Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
@@ -111,7 +102,7 @@ static void PrintShadowBytes(const char *before, u8 *bytes,
   for (uptr i = 0; i < n; i++) {
     u8 *p = bytes + i;
     const char *before = p == guilty ? "[" :
-        p - 1 == guilty ? "" : " ";
+        (p - 1 == guilty && i != 0) ? "" : " ";
     const char *after = p == guilty ? "]" : "";
     PrintShadowByte(before, *p, after);
   }
@@ -123,12 +114,12 @@ static void PrintLegend() {
          "application bytes):\n", (int)SHADOW_GRANULARITY);
   PrintShadowByte("  Addressable:           ", 0);
   Printf("  Partially addressable: ");
-  for (uptr i = 1; i < SHADOW_GRANULARITY; i++)
+  for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
     PrintShadowByte("", i, " ");
   Printf("\n");
   PrintShadowByte("  Heap left redzone:     ", kAsanHeapLeftRedzoneMagic);
-  PrintShadowByte("  Heap righ redzone:     ", kAsanHeapRightRedzoneMagic);
-  PrintShadowByte("  Freed Heap region:     ", kAsanHeapFreeMagic);
+  PrintShadowByte("  Heap right redzone:    ", kAsanHeapRightRedzoneMagic);
+  PrintShadowByte("  Freed heap region:     ", kAsanHeapFreeMagic);
   PrintShadowByte("  Stack left redzone:    ", kAsanStackLeftRedzoneMagic);
   PrintShadowByte("  Stack mid redzone:     ", kAsanStackMidRedzoneMagic);
   PrintShadowByte("  Stack right redzone:   ", kAsanStackRightRedzoneMagic);
@@ -173,19 +164,34 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_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.
+  return (name[0] == '_' && name[1] == 'Z' && &getSymbolizer)
+             ? getSymbolizer()->Demangle(name)
+             : name;
+}
+
 // Check if the global is a zero-terminated ASCII string. If so, print it.
 static void PrintGlobalNameIfASCII(const __asan_global &g) {
   for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
-    if (!IsASCII(*(unsigned char*)p)) return;
+    unsigned char c = *(unsigned char*)p;
+    if (c == '\0' || !IsASCII(c)) return;
   }
-  if (*(char*)(g.beg + g.size - 1) != 0) return;
-  Printf("  '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
+  if (*(char*)(g.beg + g.size - 1) != '\0') return;
+  Printf("  '%s' is ascii string '%s'\n",
+         MaybeDemangleGlobalName(g.name), (char*)g.beg);
 }
 
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
@@ -206,8 +212,8 @@ bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
     // Can it happen?
     Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
   }
-  Printf(" of global variable '%s' (0x%zx) of size %zu\n",
-             g.name, g.beg, g.size);
+  Printf(" of global variable '%s' from '%s' (0x%zx) of size %zu\n",
+             MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size);
   Printf("%s", d.EndLocation());
   PrintGlobalNameIfASCII(g);
   return true;
@@ -234,57 +240,149 @@ bool DescribeAddressIfShadow(uptr addr) {
   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);
+}
+
+void PrintAccessAndVarIntersection(const char *var_name,
+                                   uptr var_beg, uptr var_size,
+                                   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";
+  }
+  Printf("    [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name);
+  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.
+    Printf("%s <== Memory access at offset %zd %s this variable%s\n",
+           d.Location(), addr, pos_descr, d.EndLocation());
+  } else {
+    Printf("\n");
+  }
+}
+
+struct StackVarDescr {
+  uptr beg;
+  uptr size;
+  const char *name_pos;
+  uptr name_len;
+};
+
 bool DescribeAddressIfStack(uptr addr, uptr access_size) {
-  AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
+  AsanThread *t = FindThreadByStackAddress(addr);
   if (!t) return false;
-  const sptr kBufSize = 4095;
+  const uptr kBufSize = 4095;
   char buf[kBufSize];
   uptr offset = 0;
-  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
+  uptr frame_pc = 0;
+  char tname[128];
+  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
+
+#ifdef __powerpc64__
+  // On PowerPC64, 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.
+  frame_pc = *reinterpret_cast<uptr *>(frame_pc);
+#endif
+
   // This string is created by the compiler and has the following form:
-  // "FunctioName n alloc_1 alloc_2 ... alloc_n"
+  // "n alloc_1 alloc_2 ... alloc_n"
   // where alloc_i looks like "offset size len ObjectName ".
   CHECK(frame_descr);
-  // Report the function name and the offset.
-  const char *name_end = internal_strchr(frame_descr, ' ');
-  CHECK(name_end);
-  buf[0] = 0;
-  internal_strncat(buf, frame_descr,
-                   Min(kBufSize,
-                       static_cast<sptr>(name_end - frame_descr)));
   Decorator d;
   Printf("%s", d.Location());
-  Printf("Address %p is located at offset %zu "
-             "in frame <%s> of T%d's stack:\n",
-             (void*)addr, offset, Demangle(buf), t->tid());
+  Printf("Address %p is located in stack of thread T%d%s "
+         "at offset %zu in frame\n",
+         addr, t->tid(),
+         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
+         offset);
+  // 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).
+  StackTrace alloca_stack;
+  alloca_stack.trace[0] = frame_pc + 16;
+  alloca_stack.size = 1;
   Printf("%s", d.EndLocation());
+  PrintStack(&alloca_stack);
   // Report the number of stack objects.
   char *p;
-  uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
-  CHECK(n_objects > 0);
+  uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
+  CHECK_GT(n_objects, 0);
   Printf("  This frame has %zu object(s):\n", n_objects);
+
   // Report all objects in this frame.
+  InternalScopedBuffer<StackVarDescr> vars(n_objects);
   for (uptr i = 0; i < n_objects; i++) {
     uptr beg, size;
-    sptr len;
-    beg  = internal_simple_strtoll(p, &p, 10);
-    size = internal_simple_strtoll(p, &p, 10);
-    len  = internal_simple_strtoll(p, &p, 10);
-    if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
+    uptr len;
+    beg  = (uptr)internal_simple_strtoll(p, &p, 10);
+    size = (uptr)internal_simple_strtoll(p, &p, 10);
+    len  = (uptr)internal_simple_strtoll(p, &p, 10);
+    if (beg == 0 || size == 0 || *p != ' ') {
       Printf("AddressSanitizer can't parse the stack frame "
                  "descriptor: |%s|\n", frame_descr);
       break;
     }
     p++;
-    buf[0] = 0;
-    internal_strncat(buf, p, Min(kBufSize, len));
+    vars[i].beg = beg;
+    vars[i].size = size;
+    vars[i].name_pos = p;
+    vars[i].name_len = len;
     p += len;
-    Printf("    [%zu, %zu) '%s'\n", beg, beg + size, buf);
+  }
+  for (uptr i = 0; i < n_objects; i++) {
+    buf[0] = 0;
+    internal_strncat(buf, vars[i].name_pos,
+                     static_cast<uptr>(Min(kBufSize, vars[i].name_len)));
+    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(buf, vars[i].beg, vars[i].size,
+                                  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"
              "      (longjmp and C++ exceptions *are* supported)\n");
-  DescribeThread(t->summary());
+  DescribeThread(t);
   return true;
 }
 
@@ -312,65 +410,43 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
   Printf("%s", d.EndLocation());
 }
 
-// Return " (thread_name) " or an empty string if the name is empty.
-const char *ThreadNameWithParenthesis(AsanThreadSummary *t, char buff[],
-                                      uptr buff_len) {
-  const char *name = t->name();
-  if (*name == 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 "";
-  AsanThreadSummary *t = asanThreadRegistry().FindByTid(tid);
-  return ThreadNameWithParenthesis(t, buff, buff_len);
-}
-
 void DescribeHeapAddress(uptr addr, uptr access_size) {
   AsanChunkView chunk = FindHeapChunkByAddress(addr);
   if (!chunk.IsValid()) return;
   DescribeAccessToHeapChunk(chunk, addr, access_size);
   CHECK(chunk.AllocTid() != kInvalidTid);
-  AsanThreadSummary *alloc_thread =
-      asanThreadRegistry().FindByTid(chunk.AllocTid());
+  asanThreadRegistry().CheckLocked();
+  AsanThreadContext *alloc_thread =
+      GetThreadContextByTidLocked(chunk.AllocTid());
   StackTrace alloc_stack;
   chunk.GetAllocStack(&alloc_stack);
-  AsanThread *t = asanThreadRegistry().GetCurrent();
-  CHECK(t);
   char tname[128];
   Decorator d;
+  AsanThreadContext *free_thread = 0;
   if (chunk.FreeTid() != kInvalidTid) {
-    AsanThreadSummary *free_thread =
-        asanThreadRegistry().FindByTid(chunk.FreeTid());
+    free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
     Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
-           free_thread->tid(),
+           free_thread->tid,
            ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
            d.EndAllocation());
     StackTrace free_stack;
     chunk.GetFreeStack(&free_stack);
     PrintStack(&free_stack);
     Printf("%spreviously allocated by thread T%d%s here:%s\n",
-           d.Allocation(), alloc_thread->tid(),
+           d.Allocation(), alloc_thread->tid,
            ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
            d.EndAllocation());
-    PrintStack(&alloc_stack);
-    DescribeThread(t->summary());
-    DescribeThread(free_thread);
-    DescribeThread(alloc_thread);
   } else {
     Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
-           alloc_thread->tid(),
+           alloc_thread->tid,
            ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
            d.EndAllocation());
-    PrintStack(&alloc_stack);
-    DescribeThread(t->summary());
-    DescribeThread(alloc_thread);
   }
+  PrintStack(&alloc_stack);
+  DescribeThread(GetCurrentThread());
+  if (free_thread)
+    DescribeThread(free_thread);
+  DescribeThread(alloc_thread);
 }
 
 void DescribeAddress(uptr addr, uptr access_size) {
@@ -388,26 +464,27 @@ void DescribeAddress(uptr addr, uptr access_size) {
 
 // ------------------- Thread description -------------------- {{{1
 
-void DescribeThread(AsanThreadSummary *summary) {
-  CHECK(summary);
+void DescribeThread(AsanThreadContext *context) {
+  CHECK(context);
+  asanThreadRegistry().CheckLocked();
   // No need to announce the main thread.
-  if (summary->tid() == 0 || summary->announced()) {
+  if (context->tid == 0 || context->announced) {
     return;
   }
-  summary->set_announced(true);
+  context->announced = true;
   char tname[128];
-  Printf("Thread T%d%s", summary->tid(),
-         ThreadNameWithParenthesis(summary->tid(), tname, sizeof(tname)));
+  Printf("Thread T%d%s", context->tid,
+         ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
   Printf(" created by T%d%s here:\n",
-         summary->parent_tid(),
-         ThreadNameWithParenthesis(summary->parent_tid(),
+         context->parent_tid,
+         ThreadNameWithParenthesis(context->parent_tid,
                                    tname, sizeof(tname)));
-  PrintStack(summary->stack());
+  PrintStack(&context->stack);
   // Recursively described parent thread if needed.
   if (flags()->print_full_thread_history) {
-    AsanThreadSummary *parent_summary =
-        asanThreadRegistry().FindByTid(summary->parent_tid());
-    DescribeThread(parent_summary);
+    AsanThreadContext *parent_context =
+        GetThreadContextByTidLocked(context->parent_tid);
+    DescribeThread(parent_context);
   }
 }
 
@@ -426,7 +503,7 @@ class ScopedInErrorReport {
       // they are defined as no-return.
       Report("AddressSanitizer: while reporting a bug found another one."
                  "Ignoring.\n");
-      u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+      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
@@ -438,24 +515,20 @@ class ScopedInErrorReport {
       internal__exit(flags()->exitcode);
     }
     ASAN_ON_ERROR();
-    reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+    // 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");
-    if (reporting_thread_tid != kInvalidTid) {
-      // We started reporting an error message. Stop using the fake stack
-      // in case we call an instrumented function from a symbolizer.
-      AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
-      CHECK(curr_thread);
-      curr_thread->fake_stack().StopUsingFakeStack();
-    }
   }
   // Destructor is NORETURN, as functions that report errors are.
   NORETURN ~ScopedInErrorReport() {
     // Make sure the current thread is announced.
-    AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
-    if (curr_thread) {
-      DescribeThread(curr_thread->summary());
-    }
+    DescribeThread(GetCurrentThread());
     // Print memory stats.
     if (flags()->print_stats)
       __asan_print_accumulated_stats();
@@ -469,13 +542,15 @@ class ScopedInErrorReport {
 
 static void ReportSummary(const char *error_type, StackTrace *stack) {
   if (!stack->size) return;
-  if (IsSymbolizerAvailable()) {
+  if (&getSymbolizer && getSymbolizer()->IsAvailable()) {
     AddressInfo ai;
     // Currently, we include the first stack frame into the report summary.
     // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
-    SymbolizeCode(stack->trace[0], &ai, 1);
+    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+    getSymbolizer()->SymbolizeCode(pc, &ai, 1);
     ReportErrorSummary(error_type,
-                       StripPathPrefix(ai.file, flags()->strip_path_prefix),
+                       StripPathPrefix(ai.file,
+                                       common_flags()->strip_path_prefix),
                        ai.line, ai.function);
   }
   // FIXME: do we need to print anything at all if there is no symbolizer?
@@ -488,7 +563,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
   Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
              " (pc %p sp %p bp %p T%d)\n",
              (void*)addr, (void*)pc, (void*)sp, (void*)bp,
-             asanThreadRegistry().GetCurrentTidOrInvalid());
+             GetCurrentTidOrInvalid());
   Printf("%s", d.EndWarning());
   Printf("AddressSanitizer can not provide additional info.\n");
   GET_STACK_TRACE_FATAL(pc, bp);
@@ -500,7 +575,13 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
-  Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr);
+  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());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
@@ -511,8 +592,11 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *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\n", addr);
+             "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());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
@@ -678,7 +762,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
              bug_descr, (void*)addr, pc, bp, sp);
   Printf("%s", d.EndWarning());
 
-  u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+  u32 curr_tid = GetCurrentTidOrInvalid();
   char tname[128];
   Printf("%s%s of size %zu at %p thread T%d%s%s\n",
          d.Access(),
@@ -712,6 +796,6 @@ void __asan_describe_address(uptr addr) {
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 // Provide default implementation of __asan_on_error that does nothing
 // and may be overriden by user.
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
 void __asan_on_error() {}
 #endif
index 13724dab9eead8a17444f81e8a10bfffd31ef293..afe7673304cb1433cde85f25d7e6a769aa9caf5a 100644 (file)
@@ -27,7 +27,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size);
 // Determines memory type on its own.
 void DescribeAddress(uptr addr, uptr access_size);
 
-void DescribeThread(AsanThreadSummary *summary);
+void DescribeThread(AsanThreadContext *context);
 
 // Different kinds of error reports.
 void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
index 6ddb01329adf501622c8b82c21632c4c3d5c97cd..67327611e84c135785011779e2ae4b424e5e9bf8 100644 (file)
 //===----------------------------------------------------------------------===//
 #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_thread.h"
-#include "asan_thread_registry.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.
 
 namespace __asan {
 
@@ -62,13 +66,9 @@ static void AsanCheckFailed(const char *file, int line, const char *cond,
 }
 
 // -------------------------- Flags ------------------------- {{{1
-static const int kDeafultMallocContextSize = 30;
-
-static Flags asan_flags;
+static const int kDefaultMallocContextSize = 30;
 
-Flags *flags() {
-  return &asan_flags;
-}
+Flags asan_flags_dont_use_directly;  // use via flags().
 
 static const char *MaybeCallAsanDefaultOptions() {
   return (&__asan_default_options) ? __asan_default_options() : "";
@@ -86,28 +86,32 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
 }
 
 static void ParseFlagsFromString(Flags *f, const char *str) {
+  ParseCommonFlagsFromString(str);
+  CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
+
   ParseFlag(str, &f->quarantine_size, "quarantine_size");
-  ParseFlag(str, &f->symbolize, "symbolize");
   ParseFlag(str, &f->verbosity, "verbosity");
   ParseFlag(str, &f->redzone, "redzone");
-  CHECK(f->redzone >= 16);
+  CHECK_GE(f->redzone, 16);
   CHECK(IsPowerOfTwo(f->redzone));
 
   ParseFlag(str, &f->debug, "debug");
   ParseFlag(str, &f->report_globals, "report_globals");
-  ParseFlag(str, &f->check_initialization_order, "initialization_order");
-  ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
-  CHECK((uptr)f->malloc_context_size <= kStackTraceMax);
+  ParseFlag(str, &f->check_initialization_order, "check_initialization_order");
 
   ParseFlag(str, &f->replace_str, "replace_str");
   ParseFlag(str, &f->replace_intrin, "replace_intrin");
   ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
-  ParseFlag(str, &f->use_fake_stack, "use_fake_stack");
+  ParseFlag(str, &f->detect_stack_use_after_return,
+            "detect_stack_use_after_return");
+  ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log");
   ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
+  ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte");
   ParseFlag(str, &f->exitcode, "exitcode");
   ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
   ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
   ParseFlag(str, &f->handle_segv, "handle_segv");
+  ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
   ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
   ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
   ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
@@ -116,37 +120,47 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
   ParseFlag(str, &f->print_legend, "print_legend");
   ParseFlag(str, &f->atexit, "atexit");
   ParseFlag(str, &f->disable_core, "disable_core");
-  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
   ParseFlag(str, &f->allow_reexec, "allow_reexec");
   ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
-  ParseFlag(str, &f->log_path, "log_path");
-  ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
-  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
   ParseFlag(str, &f->poison_heap, "poison_heap");
   ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
   ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
+  ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
+  ParseFlag(str, &f->strict_init_order, "strict_init_order");
 }
 
 void InitializeFlags(Flags *f, const char *env) {
-  internal_memset(f, 0, sizeof(*f));
+  CommonFlags *cf = common_flags();
+  cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
+  cf->symbolize = true;
+  cf->malloc_context_size = kDefaultMallocContextSize;
+  cf->fast_unwind_on_fatal = false;
+  cf->fast_unwind_on_malloc = true;
+  cf->strip_path_prefix = "";
+  cf->handle_ioctl = false;
+  cf->log_path = 0;
+  cf->detect_leaks = false;
+  cf->leak_check_at_exit = true;
 
+  internal_memset(f, 0, sizeof(*f));
   f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
-  f->symbolize = false;
   f->verbosity = 0;
-  f->redzone = ASAN_ALLOCATOR_VERSION == 2 ? 16 : (ASAN_LOW_MEMORY) ? 64 : 128;
+  f->redzone = 16;
   f->debug = false;
   f->report_globals = 1;
-  f->check_initialization_order = true;
-  f->malloc_context_size = kDeafultMallocContextSize;
+  f->check_initialization_order = false;
   f->replace_str = true;
   f->replace_intrin = true;
   f->mac_ignore_invalid_free = false;
-  f->use_fake_stack = true;
-  f->max_malloc_fill_size = 0;
+  f->detect_stack_use_after_return = false;  // Also needs the compiler flag.
+  f->uar_stack_size_log = 0;
+  f->max_malloc_fill_size = 0x1000;  // By default, fill only the first 4K.
+  f->malloc_fill_byte = 0xbe;
   f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
   f->allow_user_poisoning = true;
   f->sleep_before_dying = 0;
   f->handle_segv = ASAN_NEEDS_SEGV;
+  f->allow_user_segv_handler = false;
   f->use_sigaltstack = false;
   f->check_malloc_usable_size = true;
   f->unmap_shadow_on_exit = false;
@@ -155,15 +169,15 @@ void InitializeFlags(Flags *f, const char *env) {
   f->print_legend = true;
   f->atexit = false;
   f->disable_core = (SANITIZER_WORDSIZE == 64);
-  f->strip_path_prefix = "";
   f->allow_reexec = true;
   f->print_full_thread_history = true;
-  f->log_path = 0;
-  f->fast_unwind_on_fatal = false;
-  f->fast_unwind_on_malloc = true;
   f->poison_heap = true;
-  f->alloc_dealloc_mismatch = true;
-  f->use_stack_depot = true;  // Only affects allocator2.
+  // Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
+  // TODO(glider,timurrrr): Fix known issues and enable this back.
+  f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
+  f->use_stack_depot = true;
+  f->strict_memcmp = true;
+  f->strict_init_order = false;
 
   // Override from compile definition.
   ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
@@ -177,6 +191,20 @@ void InitializeFlags(Flags *f, const char *env) {
 
   // Override from command line.
   ParseFlagsFromString(f, env);
+
+#if !CAN_SANITIZE_LEAKS
+  if (cf->detect_leaks) {
+    Report("%s: detect_leaks is not supported on this platform.\n",
+           SanitizerToolName);
+    cf->detect_leaks = false;
+  }
+#endif
+
+  if (cf->detect_leaks && !f->use_stack_depot) {
+    Report("%s: detect_leaks is ignored (requires use_stack_depot).\n",
+           SanitizerToolName);
+    cf->detect_leaks = false;
+  }
 }
 
 // -------------------------- Globals --------------------- {{{1
@@ -197,8 +225,8 @@ void ShowStatsAndAbort() {
 // ---------------------- mmap -------------------- {{{1
 // Reserve memory range [beg, end].
 static void ReserveShadowMemoryRange(uptr beg, uptr end) {
-  CHECK((beg % GetPageSizeCached()) == 0);
-  CHECK(((end + 1) % GetPageSizeCached()) == 0);
+  CHECK_EQ((beg % GetPageSizeCached()), 0);
+  CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
   uptr size = end - beg + 1;
   void *res = MmapFixedNoReserve(beg, size);
   if (res != (void*)beg) {
@@ -281,9 +309,7 @@ static NOINLINE void force_interface_symbols() {
     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 28: __asan_stack_free(0, 0, 0); break;
-    case 29: __asan_stack_malloc(0, 0); break;
-    case 30: __asan_before_dynamic_init(0, 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;
@@ -304,22 +330,12 @@ static void asan_atexit() {
 
 static void InitializeHighMemEnd() {
 #if !ASAN_FIXED_MAPPING
-#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__)
-  // FIXME:
-  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
-  // We somehow need to figure our 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.
-  kHighMemEnd = (1ULL << 44) - 1;  // 0x00000fffffffffffUL
-# else
-  kHighMemEnd = (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
-# endif
-#else  // SANITIZER_WORDSIZE == 32
-  kHighMemEnd = (1ULL << 32) - 1;  // 0xffffffff;
-#endif  // SANITIZER_WORDSIZE
+  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) {
@@ -361,7 +377,9 @@ static void PrintAddressSpaceLayout() {
   }
   Printf("\n");
   Printf("red_zone=%zu\n", (uptr)flags()->redzone);
-  Printf("malloc_context_size=%zu\n", (uptr)flags()->malloc_context_size);
+  Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20);
+  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);
@@ -380,7 +398,7 @@ using namespace __asan;  // NOLINT
 
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 const char* __asan_default_options() { return ""; }
 }  // extern "C"
 #endif
@@ -393,12 +411,28 @@ int NOINLINE __asan_set_error_exit_code(int exit_code) {
 
 void NOINLINE __asan_handle_no_return() {
   int local_stack;
-  AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+  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)) {
@@ -424,7 +458,9 @@ void __asan_init() {
   // initialization steps look at flags().
   const char *options = GetEnv("ASAN_OPTIONS");
   InitializeFlags(flags(), options);
-  __sanitizer_set_report_path(flags()->log_path);
+  __sanitizer_set_report_path(common_flags()->log_path);
+  __asan_option_detect_stack_use_after_return =
+      flags()->detect_stack_use_after_return;
 
   if (flags()->verbosity && options) {
     Report("Parsed ASAN_OPTIONS: %s\n", options);
@@ -447,12 +483,12 @@ void __asan_init() {
   ReplaceOperatorsNewAndDelete();
 
   uptr shadow_start = kLowShadowBeg;
-  if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
-  uptr shadow_end = kHighShadowEnd;
+  if (kLowShadowBeg)
+    shadow_start -= GetMmapGranularity();
   bool full_shadow_is_available =
-      MemoryRangeIsAvailable(shadow_start, shadow_end);
+      MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
 
-#if ASAN_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
+#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
   if (!full_shadow_is_available) {
     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
@@ -476,7 +512,7 @@ void __asan_init() {
     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
   } else if (kMidMemBeg &&
       MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
-      MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) {
+      MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
     CHECK(kLowShadowBeg != kLowShadowEnd);
     // mmap the low shadow plus at least one page at the left.
     ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
@@ -496,12 +532,16 @@ void __asan_init() {
   }
 
   InstallSignalHandlers();
+
+  AsanTSDInit(AsanThread::TSDDtor);
+  // Allocator should be initialized before starting external symbolizer, as
+  // fork() on Mac locks the allocator.
+  InitializeAllocator();
+
   // Start symbolizer process if necessary.
-  if (flags()->symbolize) {
-    const char *external_symbolizer = GetEnv("ASAN_SYMBOLIZER_PATH");
-    if (external_symbolizer) {
-      InitializeExternalSymbolizer(external_symbolizer);
-    }
+  if (common_flags()->symbolize && &getSymbolizer) {
+    getSymbolizer()
+        ->InitializeExternal(common_flags()->external_symbolizer_path);
   }
 
   // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
@@ -509,11 +549,24 @@ void __asan_init() {
   asan_inited = 1;
   asan_init_is_running = false;
 
-  asanThreadRegistry().Init();
-  asanThreadRegistry().GetMain()->ThreadStart();
+  InitTlsSize();
+
+  // Create main thread.
+  AsanThread *main_thread = AsanThread::Create(0, 0);
+  CreateThreadContextArgs create_main_args = { main_thread, 0 };
+  u32 main_tid = asanThreadRegistry().CreateThread(
+      0, true, 0, &create_main_args);
+  CHECK_EQ(0, main_tid);
+  SetCurrentThread(main_thread);
+  main_thread->ThreadStart(internal_getpid());
   force_interface_symbols();  // no-op.
 
-  InitializeAllocator();
+#if CAN_SANITIZE_LEAKS
+  __lsan::InitCommonLsan();
+  if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
+    Atexit(__lsan::DoLeakCheck);
+  }
+#endif  // CAN_SANITIZE_LEAKS
 
   if (flags()->verbosity) {
     Report("AddressSanitizer Init done\n");
index 999cbfba757dae858efa0e8069ac815261339e1a..749525186421c7236a0bd8cab4f4cbf1a968b4cb 100644 (file)
@@ -12,6 +12,7 @@
 #include "asan_internal.h"
 #include "asan_flags.h"
 #include "asan_stack.h"
+#include "sanitizer_common/sanitizer_flags.h"
 
 namespace __asan {
 
@@ -22,8 +23,8 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
 }
 
 void PrintStack(StackTrace *stack) {
-  stack->PrintStack(stack->trace, stack->size, flags()->symbolize,
-                    flags()->strip_path_prefix, MaybeCallAsanSymbolize);
+  stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize,
+                    common_flags()->strip_path_prefix, MaybeCallAsanSymbolize);
 }
 
 }  // namespace __asan
@@ -33,8 +34,8 @@ void PrintStack(StackTrace *stack) {
 // Provide default implementation of __asan_symbolize that does nothing
 // and may be overriden by user if he wants to use his own symbolization.
 // ASan on Windows has its own implementation of this.
-#if !defined(_WIN32) && !SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
+#if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
 bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
   return false;
 }
index 6a5ffc934cca84b22c8f07d860c467a15f1cac60..3c0ac31f6c640aa130e4c4efa1a148b5f16528ed 100644 (file)
 #ifndef ASAN_STACK_H
 #define ASAN_STACK_H
 
-#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "asan_flags.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 
 namespace __asan {
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast);
 void PrintStack(StackTrace *stack);
 
 }  // namespace __asan
@@ -25,10 +26,24 @@ void PrintStack(StackTrace *stack);
 // 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.
-// fast_unwind is currently unused.
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast)     \
-  StackTrace stack;                                             \
-  GetStackTrace(&stack, max_s, pc, bp, fast)
+#if SANITIZER_WINDOWS
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
+  StackTrace stack;                                         \
+  GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast)
+#else
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast)                \
+  StackTrace stack;                                                        \
+  {                                                                        \
+    AsanThread *t;                                                         \
+    stack.size = 0;                                                        \
+    if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) {    \
+      uptr stack_top = t->stack_top();                                     \
+      uptr stack_bottom = t->stack_bottom();                               \
+      ScopedUnwinding unwind_scope(t);                                     \
+      GetStackTrace(&stack, max_s, pc, bp, stack_top, stack_bottom, fast); \
+    }                                                                      \
+  }
+#endif  // SANITIZER_WINDOWS
 
 // 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
@@ -40,24 +55,24 @@ void PrintStack(StackTrace *stack);
 
 #define GET_STACK_TRACE_FATAL(pc, bp)                                 \
   GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp,              \
-                                 flags()->fast_unwind_on_fatal)
+                                 common_flags()->fast_unwind_on_fatal)
 
-#define GET_STACK_TRACE_FATAL_HERE                           \
-  GET_STACK_TRACE(kStackTraceMax, 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_THREAD                              \
+#define GET_STACK_TRACE_THREAD                                    \
   GET_STACK_TRACE(kStackTraceMax, true)
 
-#define GET_STACK_TRACE_MALLOC                             \
-  GET_STACK_TRACE(flags()->malloc_context_size,            \
-                  flags()->fast_unwind_on_malloc)
+#define GET_STACK_TRACE_MALLOC                                    \
+  GET_STACK_TRACE(common_flags()->malloc_context_size,            \
+                  common_flags()->fast_unwind_on_malloc)
 
 #define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
 
 #define PRINT_CURRENT_STACK()                    \
   {                                              \
     GET_STACK_TRACE(kStackTraceMax,              \
-      flags()->fast_unwind_on_fatal);            \
+      common_flags()->fast_unwind_on_fatal);     \
     PrintStack(&stack);                          \
   }
 
index 935b33e20acd22352133dea8c1044a8795af3d32..71c8582e81c37c0ce71c468f4bbc1ca2e2b32be2 100644 (file)
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_stats.h"
-#include "asan_thread_registry.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_mutex.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 
 namespace __asan {
 
 AsanStats::AsanStats() {
-  CHECK(REAL(memset) != 0);
+  Clear();
+}
+
+void AsanStats::Clear() {
+  CHECK(REAL(memset));
   REAL(memset)(this, 0, sizeof(AsanStats));
 }
 
@@ -51,11 +56,73 @@ void AsanStats::Print() {
              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;
-  asanThreadRegistry().GetAccumulatedStats(&stats);
+  GetAccumulatedStats(&stats);
   // Use lock to keep reports from mixing up.
   BlockingMutexLock lock(&print_lock);
   stats.Print();
@@ -71,15 +138,33 @@ static void PrintAccumulatedStats() {
 using namespace __asan;  // NOLINT
 
 uptr __asan_get_current_allocated_bytes() {
-  return asanThreadRegistry().GetCurrentAllocatedBytes();
+  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 __asan_get_heap_size() {
-  return asanThreadRegistry().GetHeapSize();
+  AsanStats stats;
+  GetAccumulatedStats(&stats);
+  return stats.mmaped - stats.munmaped;
 }
 
 uptr __asan_get_free_bytes() {
-  return asanThreadRegistry().GetFreeBytes();
+  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 __asan_get_unmapped_bytes() {
index fd27451aef25699f495d824ebb26a69ec9f7b5da..2f964f8d052e57f89d60a4c35d463de74c1b4d9a 100644 (file)
@@ -50,10 +50,17 @@ struct AsanStats {
   // Default ctor for thread-local stats.
   AsanStats();
 
-  // Prints formatted stats to stderr.
-  void Print();
+  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;
@@ -62,6 +69,8 @@ struct AsanMallocStats {
   uptr size_allocated;
 };
 
+void FillMallocStatistics(AsanMallocStats *malloc_stats);
+
 }  // namespace __asan
 
 #endif  // ASAN_STATS_H
index 02f49dd59ef9fbb19960605a1ed64e4ac8aea8a1..1da714c60132b6a0ece04e37481282cdaf7e2807 100644 (file)
 //===----------------------------------------------------------------------===//
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
+#include "asan_poisoning.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "asan_mapping.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "lsan/lsan_common.h"
 
 namespace __asan {
 
-AsanThread::AsanThread(LinkerInitialized x)
-    : fake_stack_(x),
-      malloc_storage_(x),
-      stats_(x) { }
+// AsanThreadContext implementation.
 
-AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
-                               void *arg, StackTrace *stack) {
+void AsanThreadContext::OnCreated(void *arg) {
+  CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
+  if (args->stack) {
+    internal_memcpy(&stack, args->stack, sizeof(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 ThreadContextBase *GetAsanThreadContext(u32 tid) {
+  void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
+  return new(mem) 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) {
   uptr PageSize = GetPageSizeCached();
   uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
   AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
   thread->start_routine_ = start_routine;
   thread->arg_ = arg;
-
-  const uptr kSummaryAllocSize = PageSize;
-  CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
-  AsanThreadSummary *summary =
-      (AsanThreadSummary*)MmapOrDie(PageSize, "AsanThreadSummary");
-  summary->Init(parent_tid, stack);
-  summary->set_thread(thread);
-  thread->set_summary(summary);
+  thread->context_ = 0;
 
   return thread;
 }
 
-void AsanThreadSummary::TSDDtor(void *tsd) {
-  AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
-  if (flags()->verbosity >= 1) {
-    Report("T%d TSDDtor\n", summary->tid());
-  }
-  if (summary->thread()) {
-    summary->thread()->Destroy();
-  }
+void AsanThread::TSDDtor(void *tsd) {
+  AsanThreadContext *context = (AsanThreadContext*)tsd;
+  if (flags()->verbosity >= 1)
+    Report("T%d TSDDtor\n", context->tid);
+  if (context->thread)
+    context->thread->Destroy();
 }
 
 void AsanThread::Destroy() {
@@ -58,41 +94,68 @@ void AsanThread::Destroy() {
     Report("T%d exited\n", tid());
   }
 
-  asanThreadRegistry().UnregisterThread(this);
-  CHECK(summary()->thread() == 0);
+  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.
-  ClearShadowForThreadStack();
-  fake_stack().Cleanup();
+  ClearShadowForThreadStackAndTLS();
+  DeleteFakeStack();
   uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
   UnmapOrDie(this, size);
 }
 
+// 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 successfull, it initilizes 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));
+    if (flags()->uar_stack_size_log)
+      stack_size_log = static_cast<uptr>(flags()->uar_stack_size_log);
+    fake_stack_ = FakeStack::Create(stack_size_log);
+    SetTLSFakeStack(fake_stack_);
+    return fake_stack_;
+  }
+  return 0;
+}
+
 void AsanThread::Init() {
-  SetThreadStackTopAndBottom();
+  SetThreadStackAndTls();
   CHECK(AddrIsInMem(stack_bottom_));
   CHECK(AddrIsInMem(stack_top_ - 1));
-  ClearShadowForThreadStack();
+  ClearShadowForThreadStackAndTLS();
   if (flags()->verbosity >= 1) {
     int local = 0;
     Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
            tid(), (void*)stack_bottom_, (void*)stack_top_,
            stack_top_ - stack_bottom_, &local);
   }
-  fake_stack_.Init(stack_size());
+  fake_stack_ = 0;  // Will be initialized lazily if needed.
   AsanPlatformThreadInit();
 }
 
-thread_return_t AsanThread::ThreadStart() {
+thread_return_t AsanThread::ThreadStart(uptr os_id) {
   Init();
+  asanThreadRegistry().StartThread(tid(), os_id, 0);
   if (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(tid() == 0);
+    CHECK_EQ(tid(), 0);
     return 0;
   }
 
@@ -105,24 +168,33 @@ thread_return_t AsanThread::ThreadStart() {
   return res;
 }
 
-void AsanThread::SetThreadStackTopAndBottom() {
-  GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
+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::ClearShadowForThreadStack() {
+void AsanThread::ClearShadowForThreadStackAndTLS() {
   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
+  if (tls_begin_ != tls_end_)
+    PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
 }
 
-const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
+const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
+                                           uptr *frame_pc) {
   uptr bottom = 0;
   if (AddrIsInStack(addr)) {
     bottom = stack_bottom();
-  } else {
-    bottom = fake_stack().AddrIsInFakeStack(addr);
+  } else if (has_fake_stack()) {
+    bottom = fake_stack()->AddrIsInFakeStack(addr);
     CHECK(bottom);
     *offset = addr - bottom;
+    *frame_pc = ((uptr*)bottom)[2];
     return  (const char *)((uptr*)bottom)[1];
   }
   uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1);  // align addr.
@@ -147,7 +219,104 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
   uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
   CHECK(ptr[0] == kCurrentStackFrameMagic);
   *offset = addr - (uptr)ptr;
+  *frame_pc = ptr[2];
   return (const char*)ptr[1];
 }
 
+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());
+  if (flags()->verbosity >= 2) {
+    Report("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();
+}
 }  // 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::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+      __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+  if (!context) return false;
+  __asan::AsanThread *t = context->thread;
+  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 LockThreadRegistry() {
+  __asan::asanThreadRegistry().Lock();
+}
+
+void UnlockThreadRegistry() {
+  __asan::asanThreadRegistry().Unlock();
+}
+
+void EnsureMainThreadIDIsCorrect() {
+  __asan::EnsureMainThreadIDIsCorrect();
+}
+}  // namespace __lsan
index f385ec35fcda30421b39fbbb859d0b0923ae1794..f21971ff4307befc33e6cdc7dceeb5b3279f63a5 100644 (file)
 
 #include "asan_allocator.h"
 #include "asan_internal.h"
+#include "asan_fake_stack.h"
 #include "asan_stack.h"
 #include "asan_stats.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 AsanThreadSummary {
+class AsanThreadContext : public ThreadContextBase {
  public:
-  explicit AsanThreadSummary(LinkerInitialized) { }  // for T0.
-  void Init(u32 parent_tid, StackTrace *stack) {
-    parent_tid_ = parent_tid;
-    announced_ = false;
-    tid_ = kInvalidTid;
-    if (stack) {
-      internal_memcpy(&stack_, stack, sizeof(*stack));
-    }
-    thread_ = 0;
-    name_[0] = 0;
+  explicit AsanThreadContext(int tid)
+      : ThreadContextBase(tid),
+        announced(false),
+        thread(0) {
+    internal_memset(&stack, 0, sizeof(stack));
   }
-  u32 tid() { return tid_; }
-  void set_tid(u32 tid) { tid_ = tid; }
-  u32 parent_tid() { return parent_tid_; }
-  bool announced() { return announced_; }
-  void set_announced(bool announced) { announced_ = announced; }
-  StackTrace *stack() { return &stack_; }
-  AsanThread *thread() { return thread_; }
-  void set_thread(AsanThread *thread) { thread_ = thread; }
-  static void TSDDtor(void *tsd);
-  void set_name(const char *name) {
-    internal_strncpy(name_, name, sizeof(name_) - 1);
-  }
-  const char *name() { return name_; }
+  bool announced;
+  StackTrace stack;
+  AsanThread *thread;
 
- private:
-  u32 tid_;
-  u32 parent_tid_;
-  bool announced_;
-  StackTrace stack_;
-  AsanThread *thread_;
-  char name_[128];
+  void OnCreated(void *arg);
+  void OnFinished();
 };
 
-// AsanThreadSummary objects are never freed, so we need many of them.
-COMPILER_CHECK(sizeof(AsanThreadSummary) <= 4094);
+// AsanThreadContext objects are never freed, so we need many of them.
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096);
 
 // AsanThread are stored in TSD and destroyed when the thread dies.
 class AsanThread {
  public:
-  explicit AsanThread(LinkerInitialized);  // for T0.
-  static AsanThread *Create(u32 parent_tid, thread_callback_t start_routine,
-                            void *arg, StackTrace *stack);
+  static AsanThread *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();
+  thread_return_t ThreadStart(uptr os_id);
 
   uptr stack_top() { return stack_top_; }
   uptr stack_bottom() { return stack_bottom_; }
-  uptr stack_size() { return stack_top_ - stack_bottom_; }
-  u32 tid() { return summary_->tid(); }
-  AsanThreadSummary *summary() { return summary_; }
-  void set_summary(AsanThreadSummary *summary) { summary_ = summary; }
+  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; }
 
-  const char *GetFrameNameByAddr(uptr addr, uptr *offset);
+  const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
 
   bool AddrIsInStack(uptr addr) {
     return addr >= stack_bottom_ && addr < stack_top_;
   }
 
-  FakeStack &fake_stack() { return fake_stack_; }
+  void DeleteFakeStack() {
+    if (!fake_stack_) return;
+    FakeStack *t = fake_stack_;
+    fake_stack_ = 0;
+    SetTLSFakeStack(0);
+    t->Destroy();
+  }
+
+  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; }
+
   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
   AsanStats &stats() { return stats_; }
 
  private:
-  void SetThreadStackTopAndBottom();
-  void ClearShadowForThreadStack();
-  AsanThreadSummary *summary_;
+  AsanThread() : unwinding(false) {}
+  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_;
+  FakeStack *fake_stack_;
   AsanThreadLocalMallocStorage malloc_storage_;
   AsanStats stats_;
+  bool unwinding;
 };
 
+// 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;
+};
+
+struct CreateThreadContextArgs {
+  AsanThread *thread;
+  StackTrace *stack;
+};
+
+// 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/libsanitizer/asan/asan_thread_registry.cc b/libsanitizer/asan/asan_thread_registry.cc
deleted file mode 100644 (file)
index 8fda9b6..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-//===-- asan_thread_registry.cc -------------------------------------------===//
-//
-// 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.
-//
-// AsanThreadRegistry-related code. AsanThreadRegistry is a container
-// for summaries of all created threads.
-//===----------------------------------------------------------------------===//
-
-#include "asan_stack.h"
-#include "asan_thread.h"
-#include "asan_thread_registry.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-namespace __asan {
-
-static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED);
-
-AsanThreadRegistry &asanThreadRegistry() {
-  return asan_thread_registry;
-}
-
-AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
-    : main_thread_(x),
-      main_thread_summary_(x),
-      accumulated_stats_(x),
-      max_malloced_memory_(x),
-      mu_(x) { }
-
-void AsanThreadRegistry::Init() {
-  AsanTSDInit(AsanThreadSummary::TSDDtor);
-  main_thread_.set_summary(&main_thread_summary_);
-  main_thread_summary_.set_thread(&main_thread_);
-  RegisterThread(&main_thread_);
-  SetCurrent(&main_thread_);
-  // At this point only one thread exists.
-  inited_ = true;
-}
-
-void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
-  BlockingMutexLock lock(&mu_);
-  u32 tid = n_threads_;
-  n_threads_++;
-  CHECK(n_threads_ < kMaxNumberOfThreads);
-
-  AsanThreadSummary *summary = thread->summary();
-  CHECK(summary != 0);
-  summary->set_tid(tid);
-  thread_summaries_[tid] = summary;
-}
-
-void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
-  BlockingMutexLock lock(&mu_);
-  FlushToAccumulatedStatsUnlocked(&thread->stats());
-  AsanThreadSummary *summary = thread->summary();
-  CHECK(summary);
-  summary->set_thread(0);
-}
-
-AsanThread *AsanThreadRegistry::GetMain() {
-  return &main_thread_;
-}
-
-AsanThread *AsanThreadRegistry::GetCurrent() {
-  AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
-  if (!summary) {
-#if ASAN_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.
-    AsanThread* thread = FindThreadByStackAddress((uptr)&summary);
-    if (thread && thread->tid() == 0) {
-      SetCurrent(thread);
-      return thread;
-    }
-#endif
-    return 0;
-  }
-  return summary->thread();
-}
-
-void AsanThreadRegistry::SetCurrent(AsanThread *t) {
-  CHECK(t->summary());
-  if (flags()->verbosity >= 2) {
-    Report("SetCurrent: %p for thread %p\n",
-           t->summary(), (void*)GetThreadSelf());
-  }
-  // Make sure we do not reset the current AsanThread.
-  CHECK(AsanTSDGet() == 0);
-  AsanTSDSet(t->summary());
-  CHECK(AsanTSDGet() == t->summary());
-}
-
-AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
-  AsanThread *t = GetCurrent();
-  return (t) ? t->stats() : main_thread_.stats();
-}
-
-void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_));
-}
-
-uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  uptr malloced = accumulated_stats_.malloced;
-  uptr freed = accumulated_stats_.freed;
-  // Return sane value if malloced < freed due to racy
-  // way we update accumulated stats.
-  return (malloced > freed) ? malloced - freed : 1;
-}
-
-uptr AsanThreadRegistry::GetHeapSize() {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  return accumulated_stats_.mmaped - accumulated_stats_.munmaped;
-}
-
-uptr AsanThreadRegistry::GetFreeBytes() {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  uptr total_free = accumulated_stats_.mmaped
-                  - accumulated_stats_.munmaped
-                  + accumulated_stats_.really_freed
-                  + accumulated_stats_.really_freed_redzones;
-  uptr total_used = accumulated_stats_.malloced
-                  + accumulated_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;
-}
-
-// Return several stats counters with a single call to
-// UpdateAccumulatedStatsUnlocked().
-void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  malloc_stats->blocks_in_use = accumulated_stats_.mallocs;
-  malloc_stats->size_in_use = accumulated_stats_.malloced;
-  malloc_stats->max_size_in_use = max_malloced_memory_;
-  malloc_stats->size_allocated = accumulated_stats_.mmaped;
-}
-
-AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
-  CHECK(tid < n_threads_);
-  CHECK(thread_summaries_[tid]);
-  return thread_summaries_[tid];
-}
-
-AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) {
-  BlockingMutexLock lock(&mu_);
-  for (u32 tid = 0; tid < n_threads_; tid++) {
-    AsanThread *t = thread_summaries_[tid]->thread();
-    if (!t || !(t->fake_stack().StackSize())) continue;
-    if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
-      return t;
-    }
-  }
-  return 0;
-}
-
-void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
-  for (u32 tid = 0; tid < n_threads_; tid++) {
-    AsanThread *t = thread_summaries_[tid]->thread();
-    if (t != 0) {
-      FlushToAccumulatedStatsUnlocked(&t->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_ < accumulated_stats_.malloced) {
-    max_malloced_memory_ = accumulated_stats_.malloced;
-  }
-}
-
-void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
-  // AsanStats consists of variables of type uptr only.
-  uptr *dst = (uptr*)&accumulated_stats_;
-  uptr *src = (uptr*)stats;
-  uptr num_fields = sizeof(AsanStats) / sizeof(uptr);
-  for (uptr i = 0; i < num_fields; i++) {
-    dst[i] += src[i];
-    src[i] = 0;
-  }
-}
-
-}  // namespace __asan
diff --git a/libsanitizer/asan/asan_thread_registry.h b/libsanitizer/asan/asan_thread_registry.h
deleted file mode 100644 (file)
index 8c3d0c8..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-//===-- asan_thread_registry.h ----------------------------------*- C++ -*-===//
-//
-// 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_registry.cc
-//===----------------------------------------------------------------------===//
-
-#ifndef ASAN_THREAD_REGISTRY_H
-#define ASAN_THREAD_REGISTRY_H
-
-#include "asan_stack.h"
-#include "asan_stats.h"
-#include "asan_thread.h"
-#include "sanitizer_common/sanitizer_mutex.h"
-
-namespace __asan {
-
-// Stores summaries of all created threads, returns current thread,
-// thread by tid, thread by stack address. There is a single instance
-// of AsanThreadRegistry for the whole program.
-// AsanThreadRegistry is thread-safe.
-class AsanThreadRegistry {
- public:
-  explicit AsanThreadRegistry(LinkerInitialized);
-  void Init();
-  void RegisterThread(AsanThread *thread);
-  void UnregisterThread(AsanThread *thread);
-
-  AsanThread *GetMain();
-  // Get the current thread. May return 0.
-  AsanThread *GetCurrent();
-  void SetCurrent(AsanThread *t);
-
-  u32 GetCurrentTidOrInvalid() {
-    if (!inited_) return 0;
-    AsanThread *t = GetCurrent();
-    return t ? t->tid() : kInvalidTid;
-  }
-
-  // Returns stats for GetCurrent(), or stats for
-  // T0 if GetCurrent() returns 0.
-  AsanStats &GetCurrentThreadStats();
-  // Flushes all thread-local stats to accumulated stats, and makes
-  // a copy of accumulated stats.
-  void GetAccumulatedStats(AsanStats *stats);
-  uptr GetCurrentAllocatedBytes();
-  uptr GetHeapSize();
-  uptr GetFreeBytes();
-  void FillMallocStatistics(AsanMallocStats *malloc_stats);
-
-  AsanThreadSummary *FindByTid(u32 tid);
-  AsanThread *FindThreadByStackAddress(uptr addr);
-
- private:
-  void UpdateAccumulatedStatsUnlocked();
-  // Adds values of all counters in "stats" to accumulated stats,
-  // and fills "stats" with zeroes.
-  void FlushToAccumulatedStatsUnlocked(AsanStats *stats);
-
-  static const u32 kMaxNumberOfThreads = (1 << 22);  // 4M
-  AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads];
-  AsanThread main_thread_;
-  AsanThreadSummary main_thread_summary_;
-  AsanStats accumulated_stats_;
-  // Required for malloc_zone_statistics() on OS X. This can't be stored in
-  // per-thread AsanStats.
-  uptr max_malloced_memory_;
-  u32 n_threads_;
-  BlockingMutex mu_;
-  bool inited_;
-};
-
-// Returns a single instance of registry.
-AsanThreadRegistry &asanThreadRegistry();
-
-}  // namespace __asan
-
-#endif  // ASAN_THREAD_REGISTRY_H
index 6acfeebc8bfe0dac7d2ddbad0f45e1f14e5fa4bf..ed785b69281cb8a7338fdae0f6cf21fd72803bda 100644 (file)
@@ -9,7 +9,9 @@
 //
 // Windows-specific details.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 #include <windows.h>
 
 #include <dbghelp.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 {
 
 // ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
@@ -28,30 +38,6 @@ static BlockingMutex dbghelp_lock(LINKER_INITIALIZED);
 static bool dbghelp_initialized = false;
 #pragma comment(lib, "dbghelp.lib")
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
-  (void)fast;
-  stack->max_size = max_s;
-  void *tmp[kStackTraceMax];
-
-  // FIXME: CaptureStackBackTrace might be too slow for us.
-  // FIXME: Compare with StackWalk64.
-  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
-  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
-  uptr offset = 0;
-  // Skip the RTL frames by searching for the PC in the stacktrace.
-  // FIXME: this doesn't work well for the malloc/free stacks yet.
-  for (uptr i = 0; i < cs_ret; i++) {
-    if (pc != (uptr)tmp[i])
-      continue;
-    offset = i;
-    break;
-  }
-
-  stack->size = cs_ret - offset;
-  for (uptr i = 0; i < stack->size; i++)
-    stack->trace[i] = (uptr)tmp[i + offset];
-}
-
 // ---------------------- TSD ---------------- {{{1
 static bool tsd_key_inited = false;
 
index 204fdd2d8e5fe21a5a9f9e23d6a6cf17d353362a..9a16cf5784486506302954f6050ea5159eae9a2e 100644 (file)
@@ -1,6 +1,6 @@
-# This file is used to maintain libtool version info for libmudflap.  See
+# This file is used to maintain libtool version info for libasan.  See
 # the libtool manual to understand the meaning of the fields.  This is
 # a separate file so that version updates don't involve re-running
 # automake.
 # CURRENT:REVISION:AGE
-0:0:0
+1:0:0
index 5d393ca42f3b74563fd5264bb6b89e4695293ddc..5e425d1d9e3b06e1abfa0f9c1cb3e9d69b53f725 100755 (executable)
@@ -14549,7 +14549,7 @@ fi
 ac_config_files="$ac_config_files Makefile"
 
 
-ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile asan/Makefile ubsan/Makefile"
+ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile lsan/Makefile asan/Makefile ubsan/Makefile"
 
 
 if test "x$TSAN_SUPPORTED" = "xyes"; then
@@ -15679,6 +15679,7 @@ do
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "interception/Makefile") CONFIG_FILES="$CONFIG_FILES interception/Makefile" ;;
     "sanitizer_common/Makefile") CONFIG_FILES="$CONFIG_FILES sanitizer_common/Makefile" ;;
+    "lsan/Makefile") CONFIG_FILES="$CONFIG_FILES lsan/Makefile" ;;
     "asan/Makefile") CONFIG_FILES="$CONFIG_FILES asan/Makefile" ;;
     "ubsan/Makefile") CONFIG_FILES="$CONFIG_FILES ubsan/Makefile" ;;
     "tsan/Makefile") CONFIG_FILES="$CONFIG_FILES tsan/Makefile" ;;
@@ -17026,6 +17027,17 @@ _EOF
  ;;
     "sanitizer_common/Makefile":F) cat > vpsed$$ << \_EOF
 s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+   sed -f vpsed$$ $ac_file > tmp$$
+   mv tmp$$ $ac_file
+   rm vpsed$$
+   echo 'MULTISUBDIR =' >> $ac_file
+   ml_norecursion=yes
+   . ${multi_basedir}/config-ml.in
+   { ml_norecursion=; unset ml_norecursion;}
+ ;;
+    "lsan/Makefile":F) cat > vpsed$$ << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
 _EOF
    sed -f vpsed$$ $ac_file > tmp$$
    mv tmp$$ $ac_file
index 5919da613045bdc3f717ae6f19455a677ceb31c7..0b2d8132fb655c2ec3db2c20e91a0a170869ffba 100644 (file)
@@ -89,7 +89,7 @@ AM_CONDITIONAL(USING_MAC_INTERPOSE, $MAC_INTERPOSE)
 
 AC_CONFIG_FILES([Makefile])
 
-AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan ubsan], [DIR/Makefile ]),
+AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common lsan asan ubsan], [DIR/Makefile ]),
   [cat > vpsed$$ << \_EOF
 s!`test -f '$<' || echo '$(srcdir)/'`!!
 _EOF
index c218b5b565414e158a428f4595e148ff87cbe026..a7db2ff1c123b11a2dd9ac2a5af7152c79fec17d 100644 (file)
@@ -39,6 +39,16 @@ extern "C" {
   // 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);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
new file mode 100644 (file)
index 0000000..dd93848
--- /dev/null
@@ -0,0 +1,85 @@
+//===-- dfsan_interface.h -------------------------------------------------===//
+//
+// 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;
+};
+
+/// 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);
+
+#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/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
new file mode 100644 (file)
index 0000000..6cd7d76
--- /dev/null
@@ -0,0 +1,3067 @@
+//===-- linux_syscall_hooks.h ---------------------------------------------===//
+//
+// 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)(pos))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \
+  __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf),     \
+                                        (long)(count), (long)(pos))
+#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/libsanitizer/include/sanitizer/lsan_interface.h b/libsanitizer/include/sanitizer/lsan_interface.h
new file mode 100644 (file)
index 0000000..ec9c730
--- /dev/null
@@ -0,0 +1,50 @@
+//===-- sanitizer/lsan_interface.h ------------------------------*- C++ -*-===//
+//
+// 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);
+  // 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();
+  // 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();
+#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/libsanitizer/include/sanitizer/msan_interface.h b/libsanitizer/include/sanitizer/msan_interface.h
new file mode 100644 (file)
index 0000000..f531cf3
--- /dev/null
@@ -0,0 +1,160 @@
+//===-- msan_interface.h --------------------------------------------------===//
+//
+// 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
+
+#if __has_feature(memory_sanitizer)
+  /* Returns a string describing a stack origin.
+     Return NULL if the origin is invalid, or is not a stack origin. */
+  const char *__msan_get_origin_descr_if_stack(uint32_t id);
+
+
+  /* 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 memory region fully uninitialized (without changing its contents). */
+  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);
+
+  /* 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 stdout in a human-readable
+     format. */
+  void __msan_print_shadow(const volatile void *x, size_t size);
+
+  /* Print current function arguments shadow and origin to stdout in a
+     human-readable format. */
+  void __msan_print_param_shadow();
+
+  /* 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();
+
+
+  /***********************************/
+  /* Allocator statistics interface. */
+
+  /* Returns the estimated number of bytes that will be reserved by allocator
+     for request of "size" bytes. If Msan allocator can't allocate that much
+     memory, returns the maximal possible allocation size, otherwise returns
+     "size". */
+  size_t __msan_get_estimated_allocated_size(size_t size);
+
+  /* Returns true if p was returned by the Msan allocator and
+     is not yet freed. */
+  int __msan_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 __msan_get_allocated_size(const volatile void *p);
+
+  /* Number of bytes, allocated and not yet freed by the application. */
+  size_t __msan_get_current_allocated_bytes();
+
+  /* Number of bytes, mmaped by msan 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 __msan_get_heap_size();
+
+  /* Number of bytes, mmaped by msan 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 __msan_get_free_bytes()
+     later. */
+  size_t __msan_get_free_bytes();
+
+  /* Number of bytes in unmapped pages, that are released to OS. Currently,
+     always returns 0. */
+  size_t __msan_get_unmapped_bytes();
+
+  /* Malloc hooks that may be optionally provided by user.
+     __msan_malloc_hook(ptr, size) is called immediately after
+       allocation of "size" bytes, which returned "ptr".
+     __msan_free_hook(ptr) is called immediately before
+       deallocation of "ptr". */
+  void __msan_malloc_hook(const volatile void *ptr, size_t size);
+  void __msan_free_hook(const volatile void *ptr);
+
+#else  // __has_feature(memory_sanitizer)
+
+#define __msan_get_origin_descr_if_stack(id) ((const char*)0)
+#define __msan_set_origin(a, size, origin)
+#define __msan_get_origin(a) ((uint32_t)-1)
+#define __msan_get_track_origins() (0)
+#define __msan_get_umr_origin() ((uint32_t)-1)
+#define __msan_unpoison(a, size)
+#define __msan_poison(a, size)
+#define __msan_partial_poison(data, shadow, size)
+#define __msan_test_shadow(x, size) ((intptr_t)-1)
+#define __msan_set_exit_code(exit_code)
+#define __msan_set_expect_umr(expect_umr)
+#define __msan_print_shadow(x, size)
+#define __msan_print_param_shadow()
+#define __msan_has_dynamic_component() (0)
+#define __msan_allocated_memory(data, size)
+
+#endif   // __has_feature(memory_sanitizer)
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif
index c4c5026c7ed7757430159db08020e6138d78f7c9..71740c5c40375e632e3aae73a1184b6fb40b085a 100644 (file)
 
 // 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;
-// 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.
-// Mac and Linux/x86-64 are special.
-#if defined(__APPLE__) || (defined(__linux__) && defined(__x86_64__))
-typedef __sanitizer::u64 OFF_T;
-#else
-typedef __sanitizer::uptr OFF_T;
-#endif
-typedef __sanitizer::u64  OFF64_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.
+//         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.
@@ -55,15 +48,20 @@ typedef __sanitizer::u64  OFF64_T;
 //      3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double)
 //          to a header file.
 
-// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or
+// 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
+//        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
-//           DEFINE_REAL(int, foo, const char *bar, double baz) in your
+//           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
@@ -73,6 +71,7 @@ typedef __sanitizer::u64  OFF64_T;
 // 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
@@ -82,12 +81,43 @@ typedef __sanitizer::u64  OFF64_T;
 // 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)
 # if defined(_DLL)  // DLL CRT
 #  define WRAP(x) x
@@ -98,7 +128,10 @@ typedef __sanitizer::u64  OFF64_T;
 #  define WRAPPER_NAME(x) "wrap_"#x
 #  define INTERCEPTOR_ATTRIBUTE
 # endif
-# define DECLARE_WRAPPER(ret_type, func, ...)
+# 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__);
 #else
 # define WRAP(x) __interceptor_ ## x
 # define WRAPPER_NAME(x) "__interceptor_" #x
@@ -142,6 +175,7 @@ typedef __sanitizer::u64  OFF64_T;
 # 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__) \
@@ -149,13 +183,36 @@ typedef __sanitizer::u64  OFF64_T;
   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(ret_type, func, __VA_ARGS__) \
+    DECLARE_WRAPPER_WINAPI(ret_type, func, __VA_ARGS__) \
     extern "C" \
     INTERCEPTOR_ATTRIBUTE \
     ret_type __stdcall WRAP(func)(__VA_ARGS__)
@@ -181,8 +238,6 @@ typedef unsigned long uptr;  // NOLINT
 # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
 #elif defined(__APPLE__)
 # include "interception_mac.h"
-# define OVERRIDE_FUNCTION(old_func, new_func) \
-    OVERRIDE_FUNCTION_MAC(old_func, new_func)
 # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
 #else  // defined(_WIN32)
 # include "interception_win.h"
index 4929a7fce49a9f145fab171cbe71365ad9e51b61..0a8df474ab49752bbd616cddab43c04598f96b31 100644 (file)
@@ -13,7 +13,6 @@
 #ifdef __linux__
 #include "interception.h"
 
-#include <stddef.h>  // for NULL
 #include <dlfcn.h>   // for dlsym
 
 namespace __interception {
@@ -22,6 +21,13 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
   *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
 
 
index 7940ef257c87eb28040371dd264e245917667923..fbbfecbe0373930cdf3dab78495786ed63075b1b 100644 (file)
@@ -23,6 +23,7 @@ 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(func) \
@@ -31,5 +32,11 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
           (::__interception::uptr)&(func), \
           (::__interception::uptr)&WRAP(func))
 
+#if !defined(__ANDROID__)  // android does not have dlvsym
+#define INTERCEPT_FUNCTION_VER(func, symver) \
+    ::__interception::real_##func = (func##_f)(unsigned long) \
+        ::__interception::GetFuncAddrVer(#func, #symver)
+#endif  // !defined(__ANDROID__)
+
 #endif  // INTERCEPTION_LINUX_H
 #endif  // __linux__
diff --git a/libsanitizer/lsan/Makefile.am b/libsanitizer/lsan/Makefile.am
new file mode 100644 (file)
index 0000000..5c8726f
--- /dev/null
@@ -0,0 +1,60 @@
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
+# May be used by toolexeclibdir.
+gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
+AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
+AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+ACLOCAL_AMFLAGS = -I m4
+
+noinst_LTLIBRARIES = libsanitizer_lsan.la
+
+sanitizer_lsan_files = \
+       lsan_common.cc \
+       lsan_common_linux.cc
+
+libsanitizer_lsan_la_SOURCES = $(sanitizer_lsan_files)
+
+# Work around what appears to be a GNU make bug handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+       "AR_FLAGS=$(AR_FLAGS)" \
+       "CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+       "CFLAGS=$(CFLAGS)" \
+       "CXXFLAGS=$(CXXFLAGS)" \
+       "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+       "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+       "INSTALL=$(INSTALL)" \
+       "INSTALL_DATA=$(INSTALL_DATA)" \
+       "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+       "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+       "JC1FLAGS=$(JC1FLAGS)" \
+       "LDFLAGS=$(LDFLAGS)" \
+       "LIBCFLAGS=$(LIBCFLAGS)" \
+       "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+       "MAKE=$(MAKE)" \
+       "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+       "PICFLAG=$(PICFLAG)" \
+       "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+       "SHELL=$(SHELL)" \
+       "RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+       "exec_prefix=$(exec_prefix)" \
+       "infodir=$(infodir)" \
+       "libdir=$(libdir)" \
+       "prefix=$(prefix)" \
+       "includedir=$(includedir)" \
+       "AR=$(AR)" \
+       "AS=$(AS)" \
+       "LD=$(LD)" \
+       "LIBCFLAGS=$(LIBCFLAGS)" \
+       "NM=$(NM)" \
+       "PICFLAG=$(PICFLAG)" \
+       "RANLIB=$(RANLIB)" \
+       "DESTDIR=$(DESTDIR)"
+
+MAKEOVERRIDES=
+
+## ################################################################
+
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
new file mode 100644 (file)
index 0000000..e01f65b
--- /dev/null
@@ -0,0 +1,514 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = lsan
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
+       $(top_srcdir)/../config/depstand.m4 \
+       $(top_srcdir)/../config/lead-dot.m4 \
+       $(top_srcdir)/../config/libstdc++-raw-cxx.m4 \
+       $(top_srcdir)/../config/multi.m4 \
+       $(top_srcdir)/../config/override.m4 \
+       $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+       $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+       $(top_srcdir)/acinclude.m4 $(top_srcdir)/../libtool.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsanitizer_lsan_la_LIBADD =
+am__objects_1 = lsan_common.lo lsan_common_linux.lo
+am_libsanitizer_lsan_la_OBJECTS = $(am__objects_1)
+libsanitizer_lsan_la_OBJECTS = $(am_libsanitizer_lsan_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = $(libsanitizer_lsan_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSTDCXX_RAW_CXX_CXXFLAGS = @LIBSTDCXX_RAW_CXX_CXXFLAGS@
+LIBSTDCXX_RAW_CXX_LDFLAGS = @LIBSTDCXX_RAW_CXX_LDFLAGS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_noncanonical = @target_noncanonical@
+target_os = @target_os@
+target_vendor = @target_vendor@
+toolexecdir = @toolexecdir@
+toolexeclibdir = @toolexeclibdir@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
+
+# May be used by toolexeclibdir.
+gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
+       -Wno-long-long -fPIC -fno-builtin -fno-exceptions \
+       -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
+       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+ACLOCAL_AMFLAGS = -I m4
+noinst_LTLIBRARIES = libsanitizer_lsan.la
+sanitizer_lsan_files = \
+       lsan_common.cc \
+       lsan_common_linux.cc
+
+libsanitizer_lsan_la_SOURCES = $(sanitizer_lsan_files)
+
+# Work around what appears to be a GNU make bug handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+       "AR_FLAGS=$(AR_FLAGS)" \
+       "CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+       "CFLAGS=$(CFLAGS)" \
+       "CXXFLAGS=$(CXXFLAGS)" \
+       "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+       "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+       "INSTALL=$(INSTALL)" \
+       "INSTALL_DATA=$(INSTALL_DATA)" \
+       "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+       "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+       "JC1FLAGS=$(JC1FLAGS)" \
+       "LDFLAGS=$(LDFLAGS)" \
+       "LIBCFLAGS=$(LIBCFLAGS)" \
+       "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+       "MAKE=$(MAKE)" \
+       "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+       "PICFLAG=$(PICFLAG)" \
+       "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+       "SHELL=$(SHELL)" \
+       "RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+       "exec_prefix=$(exec_prefix)" \
+       "infodir=$(infodir)" \
+       "libdir=$(libdir)" \
+       "prefix=$(prefix)" \
+       "includedir=$(includedir)" \
+       "AR=$(AR)" \
+       "AS=$(AS)" \
+       "LD=$(LD)" \
+       "LIBCFLAGS=$(LIBCFLAGS)" \
+       "NM=$(NM)" \
+       "PICFLAG=$(PICFLAG)" \
+       "RANLIB=$(RANLIB)" \
+       "DESTDIR=$(DESTDIR)"
+
+MAKEOVERRIDES = 
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lsan/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign lsan/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+       -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+       @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libsanitizer_lsan.la: $(libsanitizer_lsan_la_OBJECTS) $(libsanitizer_lsan_la_DEPENDENCIES) 
+       $(CXXLINK)  $(libsanitizer_lsan_la_OBJECTS) $(libsanitizer_lsan_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common_linux.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@  $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@  $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@  $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@  $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-tags dvi dvi-am html html-am info info-am install \
+       install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsanitizer/lsan/libtool-version b/libsanitizer/lsan/libtool-version
new file mode 100644 (file)
index 0000000..204fdd2
--- /dev/null
@@ -0,0 +1,6 @@
+# This file is used to maintain libtool version info for libmudflap.  See
+# the libtool manual to understand the meaning of the fields.  This is
+# a separate file so that version updates don't involve re-running
+# automake.
+# CURRENT:REVISION:AGE
+0:0:0
diff --git a/libsanitizer/lsan/lsan.cc b/libsanitizer/lsan/lsan.cc
new file mode 100644 (file)
index 0000000..500da50
--- /dev/null
@@ -0,0 +1,63 @@
+//=-- lsan.cc -------------------------------------------------------------===//
+//
+// 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_stacktrace.h"
+#include "lsan_allocator.h"
+#include "lsan_common.h"
+#include "lsan_thread.h"
+
+namespace __lsan {
+
+static void InitializeCommonFlags() {
+  CommonFlags *cf = common_flags();
+  cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+  cf->symbolize = true;
+  cf->strip_path_prefix = "";
+  cf->fast_unwind_on_malloc = true;
+  cf->malloc_context_size = 30;
+  cf->detect_leaks = true;
+  cf->leak_check_at_exit = true;
+
+  ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS"));
+}
+
+void Init() {
+  static bool inited;
+  if (inited)
+    return;
+  inited = true;
+  SanitizerToolName = "LeakSanitizer";
+  InitializeCommonFlags();
+  InitializeAllocator();
+  InitTlsSize();
+  InitializeInterceptors();
+  InitializeThreadRegistry();
+  u32 tid = ThreadCreate(0, 0, true);
+  CHECK_EQ(tid, 0);
+  ThreadStart(tid, GetTid());
+  SetCurrentThread(tid);
+
+  // Start symbolizer process if necessary.
+  if (common_flags()->symbolize) {
+    getSymbolizer()
+        ->InitializeExternal(common_flags()->external_symbolizer_path);
+  }
+
+  InitCommonLsan();
+  if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
+    Atexit(DoLeakCheck);
+}
+
+}  // namespace __lsan
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
new file mode 100644 (file)
index 0000000..18ff5da
--- /dev/null
@@ -0,0 +1,21 @@
+//=-- lsan.h --------------------------------------------------------------===//
+//
+// 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"
+
+namespace __lsan {
+
+void Init();
+void InitializeInterceptors();
+
+}  // namespace __lsan
diff --git a/libsanitizer/lsan/lsan_allocator.cc b/libsanitizer/lsan/lsan_allocator.cc
new file mode 100644 (file)
index 0000000..66af603
--- /dev/null
@@ -0,0 +1,191 @@
+//=-- lsan_allocator.cc ---------------------------------------------------===//
+//
+// 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_internal_defs.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_common.h"
+
+namespace __lsan {
+
+static const uptr kMaxAllowedMallocSize = 8UL << 30;
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
+
+struct ChunkMetadata {
+  bool allocated : 8;  // Must be first.
+  ChunkTag tag : 2;
+  uptr requested_size : 54;
+  u32 stack_trace_id;
+};
+
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
+        sizeof(ChunkMetadata), CompactSizeClassMap> PrimaryAllocator;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+          SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static THREADLOCAL AllocatorCache cache;
+
+void InitializeAllocator() {
+  allocator.Init();
+}
+
+void AllocatorThreadFinish() {
+  allocator.SwallowCache(&cache);
+}
+
+static ChunkMetadata *Metadata(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.trace, stack.size);
+  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, cleared);
+  RegisterAllocation(stack, p, size);
+  return p;
+}
+
+void Deallocate(void *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(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 && addr < chunk + m->requested_size)
+    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
diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
new file mode 100644 (file)
index 0000000..61ea865
--- /dev/null
@@ -0,0 +1,37 @@
+//=-- lsan_allocator.h ----------------------------------------------------===//
+//
+// 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(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/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc
new file mode 100644 (file)
index 0000000..ce82430
--- /dev/null
@@ -0,0 +1,577 @@
+//=-- lsan_common.cc ------------------------------------------------------===//
+//
+// 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_placement_new.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.
+BlockingMutex global_mutex(LINKER_INITIALIZED);
+
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+
+Flags lsan_flags;
+
+static void InitializeFlags() {
+  Flags *f = flags();
+  // Default values.
+  f->report_objects = false;
+  f->resolution = 0;
+  f->max_leaks = 0;
+  f->exitcode = 23;
+  f->suppressions="";
+  f->use_registers = true;
+  f->use_globals = true;
+  f->use_stacks = true;
+  f->use_tls = true;
+  f->use_unaligned = false;
+  f->verbosity = 0;
+  f->log_pointers = false;
+  f->log_threads = false;
+
+  const char *options = GetEnv("LSAN_OPTIONS");
+  if (options) {
+    ParseFlag(options, &f->use_registers, "use_registers");
+    ParseFlag(options, &f->use_globals, "use_globals");
+    ParseFlag(options, &f->use_stacks, "use_stacks");
+    ParseFlag(options, &f->use_tls, "use_tls");
+    ParseFlag(options, &f->use_unaligned, "use_unaligned");
+    ParseFlag(options, &f->report_objects, "report_objects");
+    ParseFlag(options, &f->resolution, "resolution");
+    CHECK_GE(&f->resolution, 0);
+    ParseFlag(options, &f->max_leaks, "max_leaks");
+    CHECK_GE(&f->max_leaks, 0);
+    ParseFlag(options, &f->verbosity, "verbosity");
+    ParseFlag(options, &f->log_pointers, "log_pointers");
+    ParseFlag(options, &f->log_threads, "log_threads");
+    ParseFlag(options, &f->exitcode, "exitcode");
+    ParseFlag(options, &f->suppressions, "suppressions");
+  }
+}
+
+SuppressionContext *suppression_ctx;
+
+void InitializeSuppressions() {
+  CHECK(!suppression_ctx);
+  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
+  suppression_ctx = new(placeholder_) SuppressionContext;
+  char *suppressions_from_file;
+  uptr buffer_size;
+  if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file,
+                       &buffer_size, 1 << 26 /* max_len */))
+    suppression_ctx->Parse(suppressions_from_file);
+  if (flags()->suppressions[0] && !buffer_size) {
+    Printf("LeakSanitizer: failed to read suppressions file '%s'\n",
+           flags()->suppressions);
+    Die();
+  }
+  if (&__lsan_default_suppressions)
+    suppression_ctx->Parse(__lsan_default_suppressions());
+}
+
+void InitCommonLsan() {
+  InitializeFlags();
+  InitializeSuppressions();
+  InitializePlatformSpecificModules();
+}
+
+class Decorator: private __sanitizer::AnsiColorDecorator {
+ public:
+  Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+  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;
+#ifdef __x86_64__
+  // Accept only canonical form user-space addresses.
+  return ((p >> 47) == 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();
+  if (flags()->log_pointers)
+    Report("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;
+    LsanMetadata m(chunk);
+    // Reachable beats ignored beats leaked.
+    if (m.tag() == kReachable) continue;
+    if (m.tag() == kIgnored && tag != kReachable) continue;
+    m.set_tag(tag);
+    if (flags()->log_pointers)
+      Report("%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);
+  }
+}
+
+// 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));
+    if (flags()->log_threads) Report("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.
+      if (flags()->log_threads)
+        Report("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) {
+      if (flags()->log_threads)
+        Report("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.
+        if (flags()->log_threads)
+          Report("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);
+    }
+
+    if (flags()->use_tls) {
+      if (flags()->log_threads) Report("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 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(GetPageSizeCached());
+
+  if (flags()->use_globals)
+    ProcessGlobalRegions(&frontier);
+  ProcessThreads(suspended_threads, &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.
+  ProcessPlatformSpecificAllocations(&frontier);
+  FloodFillTag(&frontier, kReachable);
+
+  if (flags()->log_pointers)
+    Report("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.
+  if (flags()->log_pointers)
+    Report("Scanning leaked chunks.\n");
+  ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */);
+}
+
+static void PrintStackTraceById(u32 stack_trace_id) {
+  CHECK(stack_trace_id);
+  uptr size = 0;
+  const uptr *trace = StackDepotGet(stack_trace_id, &size);
+  StackTrace::PrintStack(trace, size, common_flags()->symbolize,
+                         common_flags()->strip_path_prefix, 0);
+}
+
+// ForEachChunk callback. Aggregates 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) {
+    uptr resolution = flags()->resolution;
+    if (resolution > 0) {
+      uptr size = 0;
+      const uptr *trace = StackDepotGet(m.stack_trace_id(), &size);
+      size = Min(size, resolution);
+      leak_report->Add(StackDepotPut(trace, size), m.requested_size(), m.tag());
+    } else {
+      leak_report->Add(m.stack_trace_id(), m.requested_size(), m.tag());
+    }
+  }
+}
+
+// ForEachChunkCallback. Prints addresses of unreachable chunks.
+static void PrintLeakedCb(uptr chunk, void *arg) {
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (!m.allocated()) return;
+  if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
+    Printf("%s leaked %zu byte object at %p.\n",
+           m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly",
+           m.requested_size(), chunk);
+  }
+}
+
+static void PrintMatchedSuppressions() {
+  InternalMmapVector<Suppression *> matched(1);
+  suppression_ctx->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);
+}
+
+static void PrintLeaked() {
+  Printf("\n");
+  Printf("Reporting individual objects:\n");
+  ForEachChunk(PrintLeakedCb, 0 /* arg */);
+}
+
+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);
+  CHECK(param->leak_report.IsEmpty());
+  ClassifyAllChunks(suspended_threads);
+  ForEachChunk(CollectLeaksCb, &param->leak_report);
+  if (!param->leak_report.IsEmpty() && flags()->report_objects)
+    PrintLeaked();
+  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();
+  }
+  uptr have_unsuppressed = param.leak_report.ApplySuppressions();
+  if (have_unsuppressed) {
+    Decorator d;
+    Printf("\n"
+           "================================================================="
+           "\n");
+    Printf("%s", d.Error());
+    Report("ERROR: LeakSanitizer: detected memory leaks\n");
+    Printf("%s", d.End());
+    param.leak_report.PrintLargest(flags()->max_leaks);
+  }
+  if (have_unsuppressed || (flags()->verbosity >= 1)) {
+    PrintMatchedSuppressions();
+    param.leak_report.PrintSummary();
+  }
+  if (have_unsuppressed && flags()->exitcode)
+    internal__exit(flags()->exitcode);
+}
+
+static Suppression *GetSuppressionForAddr(uptr addr) {
+  static const uptr kMaxAddrFrames = 16;
+  InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
+  for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
+  uptr addr_frames_num =
+      getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames);
+  for (uptr i = 0; i < addr_frames_num; i++) {
+    Suppression* s;
+    if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
+        suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s) ||
+        suppression_ctx->Match(addr_frames[i].module, SuppressionLeak, &s))
+      return s;
+  }
+  return 0;
+}
+
+static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
+  uptr size = 0;
+  const uptr *trace = StackDepotGet(stack_trace_id, &size);
+  for (uptr i = 0; i < size; i++) {
+    Suppression *s =
+        GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(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::Add(). 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::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) {
+  CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
+  bool is_directly_leaked = (tag == kDirectlyLeaked);
+  for (uptr 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;
+      return;
+    }
+  if (leaks_.size() == kMaxLeaksConsidered) return;
+  Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id,
+                is_directly_leaked, /* is_suppressed */ false };
+  leaks_.push_back(leak);
+}
+
+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::PrintLargest(uptr num_leaks_to_print) {
+  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 = 0;
+  for (uptr i = 0; i < leaks_.size(); i++)
+    if (!leaks_[i].is_suppressed) unsuppressed_count++;
+  if (num_leaks_to_print > 0 && num_leaks_to_print < unsuppressed_count)
+    Printf("The %zu largest leak(s):\n", num_leaks_to_print);
+  InternalSort(&leaks_, leaks_.size(), LeakComparator);
+  uptr leaks_printed = 0;
+  Decorator d;
+  for (uptr i = 0; i < leaks_.size(); i++) {
+    if (leaks_[i].is_suppressed) continue;
+    Printf("%s", d.Leak());
+    Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
+           leaks_[i].is_directly_leaked ? "Direct" : "Indirect",
+           leaks_[i].total_size, leaks_[i].hit_count);
+    Printf("%s", d.End());
+    PrintStackTraceById(leaks_[i].stack_trace_id);
+    Printf("\n");
+    leaks_printed++;
+    if (leaks_printed == num_leaks_to_print) break;
+  }
+  if (leaks_printed < unsuppressed_count) {
+    uptr remaining = unsuppressed_count - leaks_printed;
+    Printf("Omitting %zu more leak(s).\n", remaining);
+  }
+}
+
+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;
+  }
+  const int kMaxSummaryLength = 128;
+  InternalScopedBuffer<char> summary(kMaxSummaryLength);
+  internal_snprintf(summary.data(), kMaxSummaryLength,
+                    "LeakSanitizer: %zu byte(s) leaked in %zu allocation(s).",
+                    bytes, allocations);
+  __sanitizer_report_error_summary(summary.data());
+}
+
+uptr LeakReport::ApplySuppressions() {
+  uptr unsuppressed_count = 0;
+  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;
+    } else {
+    unsuppressed_count++;
+    }
+  }
+  return unsuppressed_count;
+}
+}  // 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
+  // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
+  // locked.
+  BlockingMutexLock l(&global_mutex);
+  IgnoreObjectResult res = IgnoreObjectLocked(p);
+  if (res == kIgnoreObjectInvalid && flags()->verbosity >= 2)
+    Report("__lsan_ignore_object(): no heap object found at %p", p);
+  if (res == kIgnoreObjectAlreadyIgnored && flags()->verbosity >= 2)
+    Report("__lsan_ignore_object(): "
+           "heap object at %p is already being ignored\n", p);
+  if (res == kIgnoreObjectSuccess && flags()->verbosity >= 3)
+    Report("__lsan_ignore_object(): ignoring heap object at %p\n", p);
+#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) {
+    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/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
new file mode 100644 (file)
index 0000000..7906ecb
--- /dev/null
@@ -0,0 +1,174 @@
+//=-- lsan_common.h -------------------------------------------------------===//
+//
+// 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__)
+#define CAN_SANITIZE_LEAKS 1
+#else
+#define CAN_SANITIZE_LEAKS 0
+#endif
+
+namespace __lsan {
+
+// Chunk tags.
+enum ChunkTag {
+  kDirectlyLeaked = 0,  // default
+  kIndirectlyLeaked = 1,
+  kReachable = 2,
+  kIgnored = 3
+};
+
+struct Flags {
+  uptr pointer_alignment() const {
+    return use_unaligned ? 1 : sizeof(uptr);
+  }
+
+  // Print addresses of leaked objects after main leak report.
+  bool report_objects;
+  // Aggregate two objects into one leak if this many stack frames match. If
+  // zero, the entire stack trace must match.
+  int resolution;
+  // The number of leaks reported.
+  int max_leaks;
+  // If nonzero kill the process with this exit code upon finding leaks.
+  int exitcode;
+  // Suppressions file name.
+  const char* suppressions;
+
+  // Flags controlling the root set of reachable memory.
+  // Global variables (.data and .bss).
+  bool use_globals;
+  // Thread stacks.
+  bool use_stacks;
+  // Thread registers.
+  bool use_registers;
+  // TLS and thread-specific storage.
+  bool use_tls;
+
+  // Consider unaligned pointers valid.
+  bool use_unaligned;
+
+  // User-visible verbosity.
+  int verbosity;
+
+  // Debug logging.
+  bool log_pointers;
+  bool log_threads;
+};
+
+extern Flags lsan_flags;
+inline Flags *flags() { return &lsan_flags; }
+
+struct Leak {
+  uptr hit_count;
+  uptr total_size;
+  u32 stack_trace_id;
+  bool is_directly_leaked;
+  bool is_suppressed;
+};
+
+// Aggregates leaks by stack trace prefix.
+class LeakReport {
+ public:
+  LeakReport() : leaks_(1) {}
+  void Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag);
+  void PrintLargest(uptr max_leaks);
+  void PrintSummary();
+  bool IsEmpty() { return leaks_.size() == 0; }
+  uptr ApplySuppressions();
+ private:
+  InternalMmapVector<Leak> leaks_;
+};
+
+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();
+
+// 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();
+// 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);
+// 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/libsanitizer/lsan/lsan_common_linux.cc b/libsanitizer/lsan/lsan_common_linux.cc
new file mode 100644 (file)
index 0000000..80d2459
--- /dev/null
@@ -0,0 +1,139 @@
+//=-- lsan_common_linux.cc ------------------------------------------------===//
+//
+// 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_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)
+    Report("LeakSanitizer: Dynamic linker not found. "
+           "TLS will not be handled correctly.\n");
+  else if (num_matches > 1)
+    Report("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) {
+  // 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);
+  uptr size = 0;
+  const uptr *trace = map->Get(stack_id, &size);
+  // The top frame is our malloc/calloc/etc. The next frame is the caller.
+  if (size >= 2)
+    return 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.
+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/libsanitizer/lsan/lsan_interceptors.cc b/libsanitizer/lsan/lsan_interceptors.cc
new file mode 100644 (file)
index 0000000..40ddc77
--- /dev/null
@@ -0,0 +1,279 @@
+//=-- lsan_interceptors.cc ------------------------------------------------===//
+//
+// 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 GET_STACK_TRACE                                                      \
+  StackTrace stack;                                                          \
+  {                                                                          \
+    uptr stack_top = 0, stack_bottom = 0;                                    \
+    ThreadContext *t;                                                        \
+    bool fast = common_flags()->fast_unwind_on_malloc;                       \
+    if (fast && (t = CurrentThreadContext())) {                              \
+      stack_top = t->stack_end();                                            \
+      stack_bottom = t->stack_begin();                                       \
+    }                                                                        \
+    GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size,  \
+                  StackTrace::GetCurrentPc(),                                \
+                  GET_CURRENT_FRAME(), stack_top, stack_bottom, fast);       \
+  }
+
+///// Malloc/free interceptors. /////
+
+const bool kAlwaysClearMemory = true;
+
+namespace std {
+  struct nothrow_t;
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Allocate(stack, size, 1, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, free, void *p) {
+  Init();
+  Deallocate(p);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+  Init();
+  GET_STACK_TRACE;
+  size *= nmemb;
+  return Allocate(stack, size, 1, true);
+}
+
+INTERCEPTOR(void*, realloc, void *q, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Reallocate(stack, q, size, 1);
+}
+
+INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
+  // FIXME: Return ENOMEM if user requested more than max alloc size.
+  return 0;
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  if (size == 0)
+    size = GetPageSizeCached();
+  return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+  Init();
+  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) {
+  Init();
+  GET_STACK_TRACE;
+  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("free");
+
+#define OPERATOR_NEW_BODY                              \
+  Init();                                              \
+  GET_STACK_TRACE;                                     \
+  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 \
+  Init();                    \
+  Deallocate(ptr);
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) { 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("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;
+};
+
+// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
+const uptr kPthreadDestructorIterations = 4;
+
+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();
+  atomic_store(&p->tid, 0, memory_order_release);
+  SetCurrentThread(tid);
+  ThreadStart(tid, GetTid());
+  return callback(param);
+}
+
+INTERCEPTOR(int, pthread_create, void *th, void *attr,
+            void *(*callback)(void *), void *param) {
+  Init();
+  EnsureMainThreadIDIsCorrect();
+  __sanitizer_pthread_attr_t myattr;
+  if (attr == 0) {
+    pthread_attr_init(&myattr);
+    attr = &myattr;
+  }
+  AdjustStackSizeLinux(attr, 0);
+  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) {
+  Init();
+  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/libsanitizer/lsan/lsan_thread.cc b/libsanitizer/lsan/lsan_thread.cc
new file mode 100644 (file)
index 0000000..c260972
--- /dev/null
@@ -0,0 +1,154 @@
+//=-- lsan_thread.cc ------------------------------------------------------===//
+//
+// 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 LockThreadRegistry() {
+  thread_registry->Lock();
+}
+
+void UnlockThreadRegistry() {
+  thread_registry->Unlock();
+}
+
+}  // namespace __lsan
diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h
new file mode 100644 (file)
index 0000000..cd13fdb
--- /dev/null
@@ -0,0 +1,51 @@
+//=-- lsan_thread.h -------------------------------------------------------===//
+//
+// 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
index 23748a701bbd706feaf6c945dc9da8ec334bb682..aae8eb41f7d07f0403fa4f624f664c2b06d75836 100755 (executable)
@@ -66,6 +66,7 @@ CUR_REV=$(get_current_rev)
 echo Current upstream revision: $CUR_REV
 merge include/sanitizer include/sanitizer
 merge lib/asan asan
+merge lib/lsan lsan
 merge lib/tsan/rtl tsan
 merge lib/sanitizer_common sanitizer_common
 merge lib/interception interception
index c53a3c6bfc5ae65932eef75c144fbc4106afb3b8..6cd51187ccb72fe7d182e12653220e2c9213d00b 100644 (file)
@@ -11,23 +11,27 @@ ACLOCAL_AMFLAGS = -I m4
 noinst_LTLIBRARIES = libsanitizer_common.la
 
 sanitizer_common_files = \
-        sanitizer_allocator.cc \
-        sanitizer_common.cc \
-        sanitizer_flags.cc \
-        sanitizer_libc.cc \
-        sanitizer_linux.cc \
-        sanitizer_mac.cc \
+       sanitizer_allocator.cc \
+       sanitizer_common.cc \
+       sanitizer_common_libcdep.cc \
+       sanitizer_flags.cc \
+       sanitizer_libc.cc \
+       sanitizer_linux.cc \
+       sanitizer_linux_libcdep.cc \
+       sanitizer_mac.cc \
+       sanitizer_platform_limits_linux.cc \
        sanitizer_platform_limits_posix.cc \
-        sanitizer_posix.cc \
-        sanitizer_printf.cc \
-        sanitizer_stackdepot.cc \
-        sanitizer_stacktrace.cc \
-        sanitizer_symbolizer.cc \
-       sanitizer_symbolizer_itanium.cc \
-        sanitizer_symbolizer_linux.cc \
-        sanitizer_symbolizer_mac.cc \
-        sanitizer_symbolizer_win.cc \
-        sanitizer_win.cc
+       sanitizer_posix.cc \
+       sanitizer_posix_libcdep.cc \
+       sanitizer_printf.cc \
+       sanitizer_stackdepot.cc \
+       sanitizer_stacktrace.cc \
+       sanitizer_stoptheworld_linux_libcdep.cc \
+       sanitizer_suppressions.cc \
+       sanitizer_symbolizer_posix_libcdep.cc \
+       sanitizer_symbolizer_win.cc \
+       sanitizer_thread_registry.cc \
+       sanitizer_win.cc
 
 libsanitizer_common_la_SOURCES = $(sanitizer_common_files) 
 
index a3030836d35f4bc7e02ea2c21a9e129c9b5e8469..68c9849e1690d81867c15ce824a46cb4432c202f 100644 (file)
@@ -56,12 +56,17 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libsanitizer_common_la_LIBADD =
 am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
-       sanitizer_flags.lo sanitizer_libc.lo sanitizer_linux.lo \
-       sanitizer_mac.lo sanitizer_platform_limits_posix.lo \
-       sanitizer_posix.lo sanitizer_printf.lo sanitizer_stackdepot.lo \
-       sanitizer_stacktrace.lo sanitizer_symbolizer.lo \
-       sanitizer_symbolizer_itanium.lo sanitizer_symbolizer_linux.lo \
-       sanitizer_symbolizer_mac.lo sanitizer_symbolizer_win.lo \
+       sanitizer_common_libcdep.lo sanitizer_flags.lo \
+       sanitizer_libc.lo sanitizer_linux.lo \
+       sanitizer_linux_libcdep.lo sanitizer_mac.lo \
+       sanitizer_platform_limits_linux.lo \
+       sanitizer_platform_limits_posix.lo sanitizer_posix.lo \
+       sanitizer_posix_libcdep.lo sanitizer_printf.lo \
+       sanitizer_stackdepot.lo sanitizer_stacktrace.lo \
+       sanitizer_stoptheworld_linux_libcdep.lo \
+       sanitizer_suppressions.lo \
+       sanitizer_symbolizer_posix_libcdep.lo \
+       sanitizer_symbolizer_win.lo sanitizer_thread_registry.lo \
        sanitizer_win.lo
 am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
 libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
@@ -223,23 +228,27 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
 ACLOCAL_AMFLAGS = -I m4
 noinst_LTLIBRARIES = libsanitizer_common.la
 sanitizer_common_files = \
-        sanitizer_allocator.cc \
-        sanitizer_common.cc \
-        sanitizer_flags.cc \
-        sanitizer_libc.cc \
-        sanitizer_linux.cc \
-        sanitizer_mac.cc \
+       sanitizer_allocator.cc \
+       sanitizer_common.cc \
+       sanitizer_common_libcdep.cc \
+       sanitizer_flags.cc \
+       sanitizer_libc.cc \
+       sanitizer_linux.cc \
+       sanitizer_linux_libcdep.cc \
+       sanitizer_mac.cc \
+       sanitizer_platform_limits_linux.cc \
        sanitizer_platform_limits_posix.cc \
-        sanitizer_posix.cc \
-        sanitizer_printf.cc \
-        sanitizer_stackdepot.cc \
-        sanitizer_stacktrace.cc \
-        sanitizer_symbolizer.cc \
-       sanitizer_symbolizer_itanium.cc \
-        sanitizer_symbolizer_linux.cc \
-        sanitizer_symbolizer_mac.cc \
-        sanitizer_symbolizer_win.cc \
-        sanitizer_win.cc
+       sanitizer_posix.cc \
+       sanitizer_posix_libcdep.cc \
+       sanitizer_printf.cc \
+       sanitizer_stackdepot.cc \
+       sanitizer_stacktrace.cc \
+       sanitizer_stoptheworld_linux_libcdep.cc \
+       sanitizer_suppressions.cc \
+       sanitizer_symbolizer_posix_libcdep.cc \
+       sanitizer_symbolizer_win.cc \
+       sanitizer_thread_registry.cc \
+       sanitizer_win.cc
 
 libsanitizer_common_la_SOURCES = $(sanitizer_common_files) 
 
@@ -336,20 +345,24 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_linux.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_posix.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_printf.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_itanium.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_linux.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stoptheworld_linux_libcdep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_suppressions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_posix_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_registry.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win.Plo@am__quote@
 
 .cc.o:
index a54de9d6f9a61bcfeb75770198e66da6f930f316..9d38e9429ac6f8b2374d369864f69154bef99251 100644 (file)
 //
 // This file is shared between AddressSanitizer and ThreadSanitizer
 // run-time libraries.
-// This allocator that is used inside run-times.
+// This allocator is used inside run-times.
 //===----------------------------------------------------------------------===//
+#include "sanitizer_allocator.h"
+#include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 
-// FIXME: We should probably use more low-level allocator that would
-// mmap some pages and split them into chunks to fulfill requests.
-#if defined(__linux__) && !defined(__ANDROID__)
-extern "C" void *__libc_malloc(__sanitizer::uptr size);
+namespace __sanitizer {
+
+// ThreadSanitizer for Go uses libc malloc/free.
+#if defined(SANITIZER_GO)
+# 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  // __linux__ && !ANDROID
-# include <stdlib.h>
-# define LIBC_MALLOC malloc
-# define LIBC_FREE free
-#endif  // __linux__ && !ANDROID
+#  define LIBC_MALLOC __libc_malloc
+#  define LIBC_FREE __libc_free
+# else
+#  include <stdlib.h>
+#  define LIBC_MALLOC malloc
+#  define LIBC_FREE free
+# endif
 
-namespace __sanitizer {
+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();
+      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) {
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
   if (size + sizeof(u64) < size)
     return 0;
-  void *p = LIBC_MALLOC(size + sizeof(u64));
+  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) {
+void InternalFree(void *addr, InternalAllocatorCache *cache) {
   if (addr == 0)
     return;
   addr = (char*)addr - sizeof(u64);
-  CHECK_EQ(((u64*)addr)[0], kBlockMagic);
+  CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
   ((u64*)addr)[0] = 0;
-  LIBC_FREE(addr);
+  RawInternalFree(addr, cache);
 }
 
 // LowLevelAllocator
@@ -79,4 +138,14 @@ bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
   return (max / size) < n;
 }
 
+void *AllocatorReturnNull() {
+  if (common_flags()->allocator_may_return_null)
+    return 0;
+  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);
+  return 0;
+}
+
 }  // namespace __sanitizer
index 889281216fc79215ec6a708f4647b2d50af89a0d..505fa5b8837218ecfc68cb87c8d1eac14a097c33 100644 (file)
 
 namespace __sanitizer {
 
+// Depending on allocator_may_return_null either return 0 or crash.
+void *AllocatorReturnNull();
+
 // 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 8 classes: 256 + i * 32 (i = 1 to 8).
-// Next 8 classes: 512 + i * 64 (i = 1 to 8).
+// Next 4 classes: 256 + i * 64  (i = 1 to 4).
+// Next 4 classes: 512 + i * 128 (i = 1 to 4).
 // ...
-// Next 8 classes: 2^k + i * 2^(k-3) (i = 1 to 8).
+// 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 12% and 6%
+//   - 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:
@@ -59,46 +62,51 @@ namespace __sanitizer {
 // 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: 288 diff: +32 12% l 8 cached: 227 65376; id 17
-// c18 => s: 320 diff: +32 11% l 8 cached: 204 65280; id 18
-// c19 => s: 352 diff: +32 10% l 8 cached: 186 65472; id 19
-// c20 => s: 384 diff: +32 09% l 8 cached: 170 65280; id 20
-// c21 => s: 416 diff: +32 08% l 8 cached: 157 65312; id 21
-// c22 => s: 448 diff: +32 07% l 8 cached: 146 65408; id 22
-// c23 => s: 480 diff: +32 07% l 8 cached: 136 65280; id 23
+// 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
+//
+// ...
 //
-// c24 => s: 512 diff: +32 06% l 9 cached: 128 65536; id 24
-// c25 => s: 576 diff: +64 12% l 9 cached: 113 65088; id 25
-// c26 => s: 640 diff: +64 11% l 9 cached: 102 65280; id 26
-// c27 => s: 704 diff: +64 10% l 9 cached: 93 65472; id 27
-// c28 => s: 768 diff: +64 09% l 9 cached: 85 65280; id 28
-// c29 => s: 832 diff: +64 08% l 9 cached: 78 64896; id 29
-// c30 => s: 896 diff: +64 07% l 9 cached: 73 65408; id 30
-// c31 => s: 960 diff: +64 07% l 9 cached: 68 65280; id 31
+// 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
 //
-// c32 => s: 1024 diff: +64 06% l 10 cached: 64 65536; id 32
+// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52
 
-template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog,
-          uptr kMinBatchClassT>
+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 = 3;
+  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 kMinBatchClass = kMinBatchClassT;
-  static const uptr kMaxSize = 1 << kMaxSizeLog;
+  static const uptr kMaxSize = 1UL << kMaxSizeLog;
   static const uptr kNumClasses =
       kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
   COMPILER_CHECK(kNumClasses >= 32 && kNumClasses <= 256);
@@ -141,7 +149,7 @@ class SizeClassMap {
         Printf("\n");
       uptr d = s - prev_s;
       uptr p = prev_s ? (d * 100 / prev_s) : 0;
-      uptr l = MostSignificantSetBitIndex(s);
+      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",
@@ -152,10 +160,16 @@ class SizeClassMap {
     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);
@@ -173,24 +187,11 @@ class SizeClassMap {
       if (c > 0)
         CHECK_LT(Size(c-1), s);
     }
-
-    // TransferBatch for kMinBatchClass must fit into the block itself.
-    const uptr batch_size = sizeof(TransferBatch)
-        - sizeof(void*)  // NOLINT
-            * (kMaxNumCached - MaxCached(kMinBatchClass));
-    CHECK_LE(batch_size, Size(kMinBatchClass));
-    // TransferBatch for kMinBatchClass-1 must not fit into the block itself.
-    const uptr batch_size1 = sizeof(TransferBatch)
-        - sizeof(void*)  // NOLINT
-            * (kMaxNumCached - MaxCached(kMinBatchClass - 1));
-    CHECK_GT(batch_size1, Size(kMinBatchClass - 1));
   }
 };
 
-typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(25, 28)>
-    DefaultSizeClassMap;
-typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(17, 20)>
-    CompactSizeClassMap;
+typedef SizeClassMap<17, 128, 16> DefaultSizeClassMap;
+typedef SizeClassMap<17, 64,  14> CompactSizeClassMap;
 template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
 
 // Memory allocator statistics
@@ -279,6 +280,9 @@ struct NoOpMapUnmapCallback {
   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
@@ -339,25 +343,28 @@ class SizeClassAllocator64 {
 
   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(void *p) {
+  static bool PointerIsMine(const void *p) {
     return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
   }
 
-  static uptr GetSizeClass(void *p) {
+  static uptr GetSizeClass(const void *p) {
     return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClassesRounded;
   }
 
-  void *GetBlockBegin(void *p) {
+  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);
@@ -371,7 +378,7 @@ class SizeClassAllocator64 {
 
   uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
 
-  void *GetMetaData(void *p) {
+  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);
@@ -430,6 +437,22 @@ class SizeClassAllocator64 {
     }
   }
 
+  // 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);
+      }
+    }
+  }
+
   typedef SizeClassMap SizeClassMapT;
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
   static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -471,11 +494,12 @@ class SizeClassAllocator64 {
   }
 
   static uptr GetChunkIdx(uptr chunk, uptr size) {
-    u32 offset = chunk % kRegionSize;
+    uptr offset = chunk % kRegionSize;
     // Here we divide by a non-constant. This is costly.
-    // We require that kRegionSize is at least 2^32 so that offset is 32-bit.
-    // We save 2x by using 32-bit div, but may need to use a 256-way switch.
-    return offset / (u32)size;
+    // 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,
@@ -513,14 +537,14 @@ class SizeClassAllocator64 {
       region->mapped_meta += map_size;
     }
     CHECK_LE(region->allocated_meta, region->mapped_meta);
-    if (region->allocated_user + region->allocated_meta > kRegionSize) {
-      Printf("Out of memory. Dying.\n");
+    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 (class_id < SizeClassMap::kMinBatchClass)
+      if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
         b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
       else
         b = (Batch*)(region_beg + beg_idx);
@@ -532,12 +556,37 @@ class SizeClassAllocator64 {
       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];
+};
+
+// FIXME: Also implement TwoLevelByteMap.
+
 // 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.
@@ -549,7 +598,7 @@ class SizeClassAllocator64 {
 //   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
-// an u8 array possible_regions[kNumPossibleRegions] to store the size classes.
+// 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.
@@ -560,16 +609,19 @@ class SizeClassAllocator64 {
 // 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, MapUnmapCallback> ThisT;
+      SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
   typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
 
   void Init() {
-    state_ = reinterpret_cast<State *>(MapWithCallback(sizeof(State)));
+    possible_regions.TestOnlyInit();
+    internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
   }
 
   void *MapWithCallback(uptr size) {
@@ -589,7 +641,7 @@ class SizeClassAllocator32 {
       alignment <= SizeClassMap::kMaxSize;
   }
 
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     CHECK(PointerIsMine(p));
     uptr mem = reinterpret_cast<uptr>(p);
     uptr beg = ComputeRegionBeg(mem);
@@ -617,18 +669,19 @@ class SizeClassAllocator32 {
     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(void *p) {
+  bool PointerIsMine(const void *p) {
     return GetSizeClass(p) != 0;
   }
 
-  uptr GetSizeClass(void *p) {
-    return state_->possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
+  uptr GetSizeClass(const void *p) {
+    return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
   }
 
-  void *GetBlockBegin(void *p) {
+  void *GetBlockBegin(const void *p) {
     CHECK(PointerIsMine(p));
     uptr mem = reinterpret_cast<uptr>(p);
     uptr beg = ComputeRegionBeg(mem);
@@ -650,16 +703,15 @@ class SizeClassAllocator32 {
     // No need to lock here.
     uptr res = 0;
     for (uptr i = 0; i < kNumPossibleRegions; i++)
-      if (state_->possible_regions[i])
+      if (possible_regions[i])
         res += kRegionSize;
     return res;
   }
 
   void TestOnlyUnmap() {
     for (uptr i = 0; i < kNumPossibleRegions; i++)
-      if (state_->possible_regions[i])
+      if (possible_regions[i])
         UnmapWithCallback((i * kRegionSize), kRegionSize);
-    UnmapWithCallback(reinterpret_cast<uptr>(state_), sizeof(State));
   }
 
   // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
@@ -676,6 +728,23 @@ class SizeClassAllocator32 {
     }
   }
 
+  // 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() {
   }
 
@@ -683,7 +752,6 @@ class SizeClassAllocator32 {
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
 
  private:
-  static const uptr kRegionSizeLog = SANITIZER_WORDSIZE == 64 ? 24 : 20;
   static const uptr kRegionSize = 1 << kRegionSizeLog;
   static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
 
@@ -711,14 +779,13 @@ class SizeClassAllocator32 {
     MapUnmapCallback().OnMap(res, kRegionSize);
     stat->Add(AllocatorStatMmapped, kRegionSize);
     CHECK_EQ(0U, (res & (kRegionSize - 1)));
-    CHECK_EQ(0U, state_->possible_regions[ComputeRegionId(res)]);
-    state_->possible_regions[ComputeRegionId(res)] = class_id;
+    possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
     return res;
   }
 
   SizeClassInfo *GetSizeClassInfo(uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
-    return &state_->size_class_info_array[class_id];
+    return &size_class_info_array[class_id];
   }
 
   void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
@@ -730,7 +797,7 @@ class SizeClassAllocator32 {
     Batch *b = 0;
     for (uptr i = reg; i < reg + n_chunks * size; i += size) {
       if (b == 0) {
-        if (class_id < SizeClassMap::kMinBatchClass)
+        if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
           b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
         else
           b = (Batch*)i;
@@ -738,19 +805,19 @@ class SizeClassAllocator32 {
       }
       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)
+    if (b) {
+      CHECK_GT(b->count, 0);
       sci->free_list.push_back(b);
+    }
   }
 
-  struct State {
-    u8 possible_regions[kNumPossibleRegions];
-    SizeClassInfo size_class_info_array[kNumClasses];
-  };
-  State *state_;
+  ByteMap possible_regions;
+  SizeClassInfo size_class_info_array[kNumClasses];
 };
 
 // Objects of this type should be used as local caches for SizeClassAllocator64
@@ -788,8 +855,12 @@ struct SizeClassAllocatorLocalCache {
   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_.Add(AllocatorStatFreed, 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;
@@ -815,7 +886,7 @@ struct SizeClassAllocatorLocalCache {
   AllocatorStats stats_;
 
   void InitCache() {
-    if (per_class_[0].max_count)
+    if (per_class_[1].max_count)
       return;
     for (uptr i = 0; i < kNumClasses; i++) {
       PerClass *c = &per_class_[i];
@@ -831,7 +902,7 @@ struct SizeClassAllocatorLocalCache {
     for (uptr i = 0; i < b->count; i++)
       c->batch[i] = b->batch[i];
     c->count = b->count;
-    if (class_id < SizeClassMap::kMinBatchClass)
+    if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
       Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
   }
 
@@ -839,7 +910,7 @@ struct SizeClassAllocatorLocalCache {
     InitCache();
     PerClass *c = &per_class_[class_id];
     Batch *b;
-    if (class_id < SizeClassMap::kMinBatchClass)
+    if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
       b = (Batch*)Allocate(allocator, SizeClassMap::ClassID(sizeof(Batch)));
     else
       b = (Batch*)c->batch[0];
@@ -850,6 +921,7 @@ struct SizeClassAllocatorLocalCache {
     }
     b->count = cnt;
     c->count -= cnt;
+    CHECK_GT(b->count, 0);
     allocator->DeallocateBatch(&stats_, class_id, b);
   }
 };
@@ -870,7 +942,7 @@ class LargeMmapAllocator {
     uptr map_size = RoundUpMapSize(size);
     if (alignment > page_size_)
       map_size += alignment;
-    if (map_size < size) return 0;  // Overflow.
+    if (map_size < size) return AllocatorReturnNull();  // Overflow.
     uptr map_beg = reinterpret_cast<uptr>(
         MmapOrDie(map_size, "LargeMmapAllocator"));
     MapUnmapCallback().OnMap(map_beg, map_size);
@@ -889,6 +961,7 @@ class LargeMmapAllocator {
     {
       SpinMutexLock l(&mutex_);
       uptr idx = n_chunks_++;
+      chunks_sorted_ = false;
       CHECK_LT(idx, kMaxNumChunks);
       h->chunk_idx = idx;
       chunks_[idx] = h;
@@ -912,6 +985,7 @@ class LargeMmapAllocator {
       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->Add(AllocatorStatFreed, h->map_size);
@@ -932,7 +1006,7 @@ class LargeMmapAllocator {
     return res;
   }
 
-  bool PointerIsMine(void *p) {
+  bool PointerIsMine(const void *p) {
     return GetBlockBegin(p) != 0;
   }
 
@@ -941,13 +1015,16 @@ class LargeMmapAllocator {
   }
 
   // At least page_size_/2 metadata bytes is available.
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     // Too slow: CHECK_EQ(p, GetBlockBegin(p));
-    CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
+    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(void *ptr) {
+  void *GetBlockBegin(const void *ptr) {
     uptr p = reinterpret_cast<uptr>(ptr);
     SpinMutexLock l(&mutex_);
     uptr nearest_chunk = 0;
@@ -964,7 +1041,49 @@ class LargeMmapAllocator {
     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)
+    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) {
+    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);
   }
@@ -992,6 +1111,13 @@ class LargeMmapAllocator {
     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 {
@@ -1002,13 +1128,15 @@ class LargeMmapAllocator {
   };
 
   Header *GetHeader(uptr p) {
-    CHECK_EQ(p % page_size_, 0);
+    CHECK(IsAligned(p, page_size_));
     return reinterpret_cast<Header*>(p - page_size_);
   }
-  Header *GetHeader(void *p) { return GetHeader(reinterpret_cast<uptr>(p)); }
+  Header *GetHeader(const void *p) {
+    return GetHeader(reinterpret_cast<uptr>(p));
+  }
 
   void *GetUser(Header *h) {
-    CHECK_EQ((uptr)h % page_size_, 0);
+    CHECK(IsAligned((uptr)h, page_size_));
     return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
   }
 
@@ -1019,6 +1147,8 @@ class LargeMmapAllocator {
   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;
@@ -1047,7 +1177,7 @@ class CombinedAllocator {
     if (size == 0)
       size = 1;
     if (size + alignment < size)
-      return 0;
+      return AllocatorReturnNull();
     if (alignment > 8)
       size = RoundUpTo(size, alignment);
     void *res;
@@ -1098,18 +1228,26 @@ class CombinedAllocator {
     return primary_.PointerIsMine(p);
   }
 
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     if (primary_.PointerIsMine(p))
       return primary_.GetMetaData(p);
     return secondary_.GetMetaData(p);
   }
 
-  void *GetBlockBegin(void *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);
@@ -1155,6 +1293,13 @@ class CombinedAllocator {
     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_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
new file mode 100644 (file)
index 0000000..c033b96
--- /dev/null
@@ -0,0 +1,62 @@
+//===-- sanitizer_allocator_internal.h -------------------------- C++ -----===//
+//
+// 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;
+#if SANITIZER_WORDSIZE == 32
+static const u64 kInternalAllocatorSize = (1ULL << 32);
+static const uptr kInternalAllocatorRegionSizeLog = 20;
+#else
+static const u64 kInternalAllocatorSize = (1ULL << 47);
+static const uptr kInternalAllocatorRegionSizeLog = 24;
+#endif
+static const uptr kInternalAllocatorFlatByteMapSize =
+    kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef SizeClassAllocator32<
+    kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
+    kInternalAllocatorRegionSizeLog,
+    FlatByteMap<kInternalAllocatorFlatByteMapSize> > PrimaryInternalAllocator;
+
+typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
+    InternalAllocatorCache;
+
+// We don't want our internal allocator to do any map/unmap operations.
+struct CrashOnMapUnmap {
+  void OnMap(uptr p, uptr size) const {
+    RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!");
+  }
+  void OnUnmap(uptr p, uptr size) const {
+    RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!");
+  }
+};
+
+typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
+                          LargeMmapAllocator<CrashOnMapUnmap> >
+    InternalAllocator;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
+void InternalFree(void *p, InternalAllocatorCache *cache = 0);
+InternalAllocator *internal_allocator();
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_ALLOCATOR_INTERNAL_H
index bb4611d51e64e049b508aaaa060856e961080e49..88819e32a73705c6e58ac26a045f847ba7aa7c7a 100644 (file)
@@ -39,7 +39,17 @@ INLINE typename T::Type atomic_load(
       | 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.
+  // FIXME:
+  // 64-bit atomic operations are not atomic on 32-bit platforms.
+  // The implementation lacks necessary memory fences on ARM/PPC.
+  // We would like to use compiler builtin atomic operations,
+  // but they are mostly broken:
+  // - 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'
   if (mo == memory_order_relaxed) {
     v = a->val_dont_use;
   } else {
@@ -55,7 +65,6 @@ 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 {
@@ -111,12 +120,14 @@ INLINE bool atomic_compare_exchange_strong(volatile T *a,
 
 template<typename T>
 INLINE bool atomic_compare_exchange_weak(volatile T *a,
-                                           typename T::Type *cmp,
-                                           typename T::Type xchg,
-                                           memory_order mo) {
+                                         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
index 919e24f3b11ac47d3fdaa7d152ffa01ebcb9d3d8..dac7c19199b97f5bf7fde211941e7cd2a360c4d8 100644 (file)
@@ -132,6 +132,27 @@ INLINE u16 atomic_exchange(volatile atomic_uint16_t *a,
   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,
@@ -147,9 +168,9 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
 
 template<typename T>
 INLINE bool atomic_compare_exchange_weak(volatile T *a,
-                                           typename T::Type *cmp,
-                                           typename T::Type xchg,
-                                           memory_order mo) {
+                                         typename T::Type *cmp,
+                                         typename T::Type xchg,
+                                         memory_order mo) {
   return atomic_compare_exchange_strong(a, cmp, xchg, mo);
 }
 
index f8d2d0e3fe5cff068868f4be089761d15aceadbb..f689df421aa83ba3ec7d3b46b04958b1fb012c7d 100644 (file)
@@ -15,6 +15,7 @@
 namespace __sanitizer {
 
 const char *SanitizerToolName = "SanitizerTool";
+uptr SanitizerVerbosity = 0;
 
 uptr GetPageSizeCached() {
   static uptr PageSize;
@@ -23,22 +24,29 @@ uptr GetPageSizeCached() {
   return PageSize;
 }
 
-static bool log_to_file = false;  // Set to true by __sanitizer_set_report_path
 
 // By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
 // isn't equal to the current PID, try to obtain file descriptor by opening
 // file "report_path_prefix.<PID>".
-static fd_t report_fd = kStderrFd;
-static char report_path_prefix[4096];  // Set via __sanitizer_set_report_path.
+fd_t report_fd = kStderrFd;
+
+// Set via __sanitizer_set_report_path.
+bool log_to_file = false;
+char report_path_prefix[sizeof(report_path_prefix)];
+
 // PID of process that opened |report_fd|. If a fork() occurs, the PID of the
 // child thread will be different from |report_fd_pid|.
-static int report_fd_pid = 0;
+uptr report_fd_pid = 0;
 
-static void (*DieCallback)(void);
-void SetDieCallback(void (*callback)(void)) {
+static DieCallbackType DieCallback;
+void SetDieCallback(DieCallbackType callback) {
   DieCallback = callback;
 }
 
+DieCallbackType GetDieCallback() {
+  return DieCallback;
+}
+
 void NORETURN Die() {
   if (DieCallback) {
     DieCallback();
@@ -61,41 +69,6 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
   Die();
 }
 
-static void MaybeOpenReportFile() {
-  if (!log_to_file || (report_fd_pid == GetPid())) return;
-  InternalScopedBuffer<char> report_path_full(4096);
-  internal_snprintf(report_path_full.data(), report_path_full.size(),
-                    "%s.%d", report_path_prefix, GetPid());
-  fd_t fd = OpenFile(report_path_full.data(), true);
-  if (fd == kInvalidFd) {
-    report_fd = kStderrFd;
-    log_to_file = false;
-    Report("ERROR: Can't open file: %s\n", report_path_full.data());
-    Die();
-  }
-  if (report_fd != kInvalidFd) {
-    // We're in the child. Close the parent's log.
-    internal_close(report_fd);
-  }
-  report_fd = fd;
-  report_fd_pid = GetPid();
-}
-
-bool PrintsToTty() {
-  MaybeOpenReportFile();
-  return internal_isatty(report_fd);
-}
-
-void RawWrite(const char *buffer) {
-  static const char *kRawWriteError = "RawWrite can't output requested buffer!";
-  uptr length = (uptr)internal_strlen(buffer);
-  MaybeOpenReportFile();
-  if (length != internal_write(report_fd, buffer, length)) {
-    internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
-    Die();
-  }
-}
-
 uptr ReadFileToBuffer(const char *file_name, char **buff,
                       uptr *buff_size, uptr max_len) {
   uptr PageSize = GetPageSizeCached();
@@ -105,8 +78,9 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
   *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) {
-    fd_t fd = OpenFile(file_name, /*write*/ false);
-    if (fd == kInvalidFd) return 0;
+    uptr openrv = OpenFile(file_name, /*write*/ false);
+    if (internal_iserror(openrv)) return 0;
+    fd_t fd = openrv;
     UnmapOrDie(*buff, *buff_size);
     *buff = (char*)MmapOrDie(size, __FUNCTION__);
     *buff_size = size;
@@ -128,45 +102,15 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
   return read_len;
 }
 
-// We don't want to use std::sort to avoid including <algorithm>, as
-// we may end up with two implementation of std::sort - one in instrumented
-// code, and the other in runtime.
-// qsort() from stdlib won't work as it calls malloc(), which results
-// in deadlock in ASan allocator.
-// We re-implement in-place sorting w/o recursion as straightforward heapsort.
+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) {
-  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 (array[j] > array[p])
-        Swap(array[j], array[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(array[0], array[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 && array[left] > array[max_ind])
-        max_ind = left;
-      if (right < i && array[right] > array[max_ind])
-        max_ind = right;
-      if (max_ind != j)
-        Swap(array[j], array[max_ind]);
-      else
-        break;
-    }
-  }
+  InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
 }
 
 // We want to map a chunk of address space aligned to 'alignment'.
@@ -200,6 +144,27 @@ void ReportErrorSummary(const char *error_type, const char *file,
   __sanitizer_report_error_summary(buff.data());
 }
 
+LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
+  full_name_ = internal_strdup(module_name);
+  base_address_ = base_address;
+  n_ranges_ = 0;
+}
+
+void LoadedModule::addAddressRange(uptr beg, uptr end) {
+  CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
+  ranges_[n_ranges_].beg = beg;
+  ranges_[n_ranges_].end = end;
+  n_ranges_++;
+}
+
+bool LoadedModule::containsAddress(uptr address) const {
+  for (uptr i = 0; i < n_ranges_; i++) {
+    if (ranges_[i].beg <= address && address < ranges_[i].end)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace __sanitizer
 
 using namespace __sanitizer;  // NOLINT
index d2782b6c9dce0d22b7e5469182c09113c34f7a66..417f71f987cd779e0653e766d32d53856ea91d92 100644 (file)
@@ -15,6 +15,7 @@
 #define SANITIZER_COMMON_H
 
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
 #include "sanitizer_mutex.h"
 
 namespace __sanitizer {
@@ -30,17 +31,22 @@ const uptr kCacheLineSize = 128;
 const uptr kCacheLineSize = 64;
 #endif
 
+const uptr kMaxPathLength = 512;
+
 extern const char *SanitizerToolName;  // Can be changed by the tool.
+extern uptr SanitizerVerbosity;
 
 uptr GetPageSize();
 uptr GetPageSizeCached();
 uptr GetMmapGranularity();
+uptr GetMaxVirtualAddress();
 // Threads
-int GetPid();
 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);
@@ -54,10 +60,6 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
 void FlushUnneededShadowMemory(uptr addr, uptr size);
 
-// Internal allocator
-void *InternalAlloc(uptr size);
-void InternalFree(void *p);
-
 // InternalScopedBuffer can be used instead of large stack arrays to
 // keep frame size low.
 // FIXME: use InternalAlloc instead of MmapOrDie once
@@ -103,13 +105,20 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
 // IO
 void RawWrite(const char *buffer);
 bool PrintsToTty();
+// Caching version of PrintsToTty(). Not thread-safe.
+bool PrintsToTtyCached();
 void Printf(const char *format, ...);
 void Report(const char *format, ...);
 void SetPrintfAndReportCallback(void (*callback)(const char *));
 // Can be used to prevent mixing error reports from different sanitizers.
 extern StaticSpinMutex CommonSanitizerReportMutex;
+void MaybeOpenReportFile();
+extern fd_t report_fd;
+extern bool log_to_file;
+extern char report_path_prefix[4096];
+extern uptr report_fd_pid;
 
-fd_t OpenFile(const char *filename, bool write);
+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',
@@ -126,23 +135,29 @@ void DisableCoreDumper();
 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);
 void PrepareForSandboxing();
 
+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);
 
 // Exit
 void NORETURN Abort();
 void NORETURN Die();
-void NORETURN SANITIZER_INTERFACE_ATTRIBUTE
+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.
@@ -154,7 +169,9 @@ bool SanitizerGetThreadName(char *name, int max_len);
 
 // Specific tools may override behavior of "Die" and "CheckFailed" functions
 // to do tool-specific job.
-void SetDieCallback(void (*callback)(void));
+typedef void (*DieCallbackType)(void);
+void SetDieCallback(DieCallbackType);
+DieCallbackType GetDieCallback();
 typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
                                        u64, u64);
 void SetCheckFailedCallback(CheckFailedCallbackType callback);
@@ -166,7 +183,7 @@ void ReportErrorSummary(const char *error_type, const char *file,
                         int line, const char *function);
 
 // Math
-#if defined(_WIN32) && !defined(__clang__)
+#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
@@ -178,9 +195,9 @@ unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);  /
 #endif
 
 INLINE uptr MostSignificantSetBitIndex(uptr x) {
-  CHECK(x != 0);
+  CHECK_NE(x, 0U);
   unsigned long up;  // NOLINT
-#if !defined(_WIN32) || defined(__clang__)
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
   up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
 #elif defined(_WIN64)
   _BitScanReverse64(&up, x);
@@ -219,7 +236,7 @@ INLINE bool IsAligned(uptr a, uptr alignment) {
 
 INLINE uptr Log2(uptr x) {
   CHECK(IsPowerOfTwo(x));
-#if !defined(_WIN32) || defined(__clang__)
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
   return __builtin_ctzl(x);
 #elif defined(_WIN64)
   unsigned long ret;  // NOLINT
@@ -260,6 +277,160 @@ INLINE int ToLower(int c) {
 # define FIRST_32_SECOND_64(a, b) (a)
 #endif
 
+// 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 InternalMmapVector {
+ public:
+  explicit InternalMmapVector(uptr initial_capacity) {
+    CHECK_GT(initial_capacity, 0);
+    capacity_ = initial_capacity;
+    size_ = 0;
+    data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVector");
+  }
+  ~InternalMmapVector() {
+    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_;
+  }
+
+ 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;
+  }
+  // Disallow evil constructors.
+  InternalMmapVector(const InternalMmapVector&);
+  void operator=(const InternalMmapVector&);
+
+  T *data_;
+  uptr capacity_;
+  uptr size_;
+};
+
+// 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 addAddressRange(uptr beg, uptr end);
+  bool containsAddress(uptr address) const;
+
+  const char *full_name() const { return full_name_; }
+  uptr base_address() const { return base_address_; }
+
+ private:
+  struct AddressRange {
+    uptr beg;
+    uptr end;
+  };
+  char *full_name_;
+  uptr base_address_;
+  static const uptr kMaxNumberOfAddressRanges = 6;
+  AddressRange ranges_[kMaxNumberOfAddressRanges];
+  uptr n_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);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_COMMON_H
index af27603ebdde3741993bf2067e02c357dd3f8018..17ef72e0c98cf693a263ccbfc39548ac14b70b82 100644 (file)
 
 #include <stdarg.h>
 
-#ifdef _WIN32
+#if SANITIZER_WINDOWS
 #define va_copy(dst, src) ((dst) = (src))
 #endif // _WIN32
 
+#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) {
+  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 INTERCEPT_FUNCTION(strcmp)
+#define INIT_STRNCMP 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 INTERCEPT_FUNCTION(strcasecmp)
+#define INIT_STRNCASECMP INTERCEPT_FUNCTION(strncasecmp)
+#else
+#define INIT_STRCASECMP
+#define INIT_STRNCASECMP
+#endif
+
+#if SANITIZER_INTERCEPT_FREXP
+INTERCEPTOR(double, frexp, double x, int *exp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp);
+  double res = REAL(frexp)(x, exp);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+  return res;
+}
+
+#define INIT_FREXP 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);
+  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);
+  long double res = REAL(frexpl)(x, exp);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+  return res;
+}
+
+#define INIT_FREXPF_FREXPL                       \
+  INTERCEPT_FUNCTION(frexpf);                    \
+  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;
@@ -74,6 +221,51 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
 #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);
+  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 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);
+  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 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);
+  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 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;
@@ -81,6 +273,7 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
   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;
@@ -123,6 +316,51 @@ INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
 #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);
+  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 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);
+  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 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);
+  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 INTERCEPT_FUNCTION(pwritev64)
+#else
+#define INIT_PWRITEV64
+#endif
+
 #if SANITIZER_INTERCEPT_PRCTL
 INTERCEPTOR(int, prctl, int option,
             unsigned long arg2, unsigned long arg3,   // NOLINT
@@ -144,6 +382,24 @@ INTERCEPTOR(int, prctl, int option,
 #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 res = REAL(time)(t);
+  if (t && res != (unsigned long)-1) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t));
+  }
+  return res;
+}
+#define INIT_TIME                                \
+  INTERCEPT_FUNCTION(time);
+#else
+#define INIT_TIME
+#endif // SANITIZER_INTERCEPT_TIME
+
+
 #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
 INTERCEPTOR(void *, localtime, unsigned long *timep) {
   void *ctx;
@@ -279,9 +535,9 @@ VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
 #define SCANF_INTERCEPTOR_IMPL(name, vname, ...)                               \
   {                                                                            \
     void *ctx;                                                                 \
-    COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__);                          \
     va_list ap;                                                                \
     va_start(ap, format);                                                      \
+    COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap);                     \
     int res = vname(__VA_ARGS__, ap);                                          \
     va_end(ap);                                                                \
     return res;                                                                \
@@ -307,31 +563,1659 @@ INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
 SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
 #endif
 
-#define INIT_SCANF                                                             \
-  INTERCEPT_FUNCTION(scanf);                                                   \
-  INTERCEPT_FUNCTION(sscanf);                                                  \
-  INTERCEPT_FUNCTION(fscanf);                                                  \
-  INTERCEPT_FUNCTION(vscanf);                                                  \
-  INTERCEPT_FUNCTION(vsscanf);                                                 \
-  INTERCEPT_FUNCTION(vfscanf);                                                 \
-  INTERCEPT_FUNCTION(__isoc99_scanf);                                          \
-  INTERCEPT_FUNCTION(__isoc99_sscanf);                                         \
-  INTERCEPT_FUNCTION(__isoc99_fscanf);                                         \
-  INTERCEPT_FUNCTION(__isoc99_vscanf);                                         \
-  INTERCEPT_FUNCTION(__isoc99_vsscanf);                                        \
-  INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#endif
 
+#if SANITIZER_INTERCEPT_SCANF
+#define INIT_SCANF             \
+  INTERCEPT_FUNCTION(scanf);   \
+  INTERCEPT_FUNCTION(sscanf);  \
+  INTERCEPT_FUNCTION(fscanf);  \
+  INTERCEPT_FUNCTION(vscanf);  \
+  INTERCEPT_FUNCTION(vsscanf); \
+  INTERCEPT_FUNCTION(vfscanf);
 #else
 #define INIT_SCANF
 #endif
 
-#define SANITIZER_COMMON_INTERCEPTORS_INIT                                     \
-  INIT_READ;                                                                   \
-  INIT_PREAD;                                                                  \
-  INIT_PREAD64;                                                                \
-  INIT_PRCTL;                                                                  \
-  INIT_WRITE;                                                                  \
-  INIT_PWRITE;                                                                 \
-  INIT_PWRITE64;                                                               \
-  INIT_LOCALTIME_AND_FRIENDS;                                                  \
-  INIT_SCANF;
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+#define INIT_ISOC99_SCANF               \
+  INTERCEPT_FUNCTION(__isoc99_scanf);   \
+  INTERCEPT_FUNCTION(__isoc99_sscanf);  \
+  INTERCEPT_FUNCTION(__isoc99_fscanf);  \
+  INTERCEPT_FUNCTION(__isoc99_vscanf);  \
+  INTERCEPT_FUNCTION(__isoc99_vsscanf); \
+  INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#else
+#define INIT_ISOC99_SCANF
+#endif
+
+#if SANITIZER_INTERCEPT_IOCTL
+#include "sanitizer_common_interceptors_ioctl.inc"
+INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
+  void *ctx;
+  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);
+
+  const ioctl_desc *desc = ioctl_lookup(request);
+  if (!desc)
+    Printf("WARNING: unknown ioctl %x\n", request);
+
+  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();    \
+  INTERCEPT_FUNCTION(ioctl);
+#else
+#define INIT_IOCTL
+#endif
+
+
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+INTERCEPTOR(void *, getpwnam, const char *name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  void *res = REAL(getpwnam)(name);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+  return res;
+}
+INTERCEPTOR(void *, getpwuid, u32 uid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
+  void *res = REAL(getpwuid)(uid);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+  return res;
+}
+INTERCEPTOR(void *, getgrnam, const char *name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  void *res = REAL(getgrnam)(name);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+  return res;
+}
+INTERCEPTOR(void *, getgrgid, u32 gid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
+  void *res = REAL(getgrgid)(gid);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+  return res;
+}
+#define INIT_GETPWNAM_AND_FRIENDS                  \
+  INTERCEPT_FUNCTION(getpwnam);                    \
+  INTERCEPT_FUNCTION(getpwuid);                    \
+  INTERCEPT_FUNCTION(getgrnam);                    \
+  INTERCEPT_FUNCTION(getgrgid);
+#else
+#define INIT_GETPWNAM_AND_FRIENDS
+#endif
+
+
+#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
+  int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+INTERCEPTOR(int, getgrnam_r, const char *name, void *grp,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
+  int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+#define INIT_GETPWNAM_R_AND_FRIENDS                \
+  INTERCEPT_FUNCTION(getpwnam_r);                  \
+  INTERCEPT_FUNCTION(getpwuid_r);                  \
+  INTERCEPT_FUNCTION(getgrnam_r);                  \
+  INTERCEPT_FUNCTION(getgrgid_r);
+#else
+#define INIT_GETPWNAM_R_AND_FRIENDS
+#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);
+  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);
+  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                         \
+  INTERCEPT_FUNCTION(clock_getres);                \
+  INTERCEPT_FUNCTION(clock_gettime);               \
+  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);
+  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);
+  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                             \
+  INTERCEPT_FUNCTION(getitimer);                   \
+  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 THREADLOCAL void* glob_ctx;
+
+static void wrapped_gl_closedir(void *dir) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+  pglob_copy->gl_closedir(dir);
+}
+
+static void *wrapped_gl_readdir(void *dir) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+  return pglob_copy->gl_readdir(dir);
+}
+
+static void *wrapped_gl_opendir(const char *s) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, 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(glob_ctx, 2);
+  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, 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(glob_ctx, 2);
+  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, 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;
+    glob_ctx = ctx;
+  }
+  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;
+  glob_ctx = 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;
+    glob_ctx = ctx;
+  }
+  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;
+  glob_ctx = 0;
+  if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+  return res;
+}
+#define INIT_GLOB           \
+  INTERCEPT_FUNCTION(glob); \
+  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);
+  int res = REAL(wait)(status);
+  if (res != -1 && status)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+  return res;
+}
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
+  int options) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
+  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);
+  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);
+  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;
+}
+INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
+  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_WAIT                                \
+  INTERCEPT_FUNCTION(wait);                      \
+  INTERCEPT_FUNCTION(waitid);                    \
+  INTERCEPT_FUNCTION(waitpid);                   \
+  INTERCEPT_FUNCTION(wait3);                     \
+  INTERCEPT_FUNCTION(wait4);
+#else
+#define INIT_WAIT
+#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.
+  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.
+  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                                \
+  INTERCEPT_FUNCTION(inet_ntop);                 \
+  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);
+  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 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);
+  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 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));
+  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 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
+  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 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;
+  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 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) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostent);
+  struct __sanitizer_hostent *res = REAL(gethostent)();
+  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           \
+  INTERCEPT_FUNCTION(gethostent);    \
+  INTERCEPT_FUNCTION(gethostbyaddr); \
+  INTERCEPT_FUNCTION(gethostbyname); \
+  INTERCEPT_FUNCTION(gethostbyname2);
+#else
+#define INIT_GETHOSTBYNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME_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);
+  int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+
+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);
+  int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
+                                  h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+
+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);
+  int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+
+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);
+  int res =
+      REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+#define INIT_GETHOSTBYNAME_R           \
+  INTERCEPT_FUNCTION(gethostent_r);    \
+  INTERCEPT_FUNCTION(gethostbyaddr_r); \
+  INTERCEPT_FUNCTION(gethostbyname_r); \
+  INTERCEPT_FUNCTION(gethostbyname2_r);
+#else
+#define INIT_GETHOSTBYNAME_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));
+  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 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;
+  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 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;
+  if (addrlen) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+    addrlen0 = *addrlen;
+  }
+  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 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);
+  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);
+  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);
+  long double res = REAL(modfl)(x, iptr);
+  if (iptr) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+  }
+  return res;
+}
+#define INIT_MODF            \
+  INTERCEPT_FUNCTION(modf);  \
+  INTERCEPT_FUNCTION(modff); \
+  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)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name,
+                                   REAL(strlen)((char *)msg->msg_name) + 1);
+  if (msg->msg_iov)
+    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)
+    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);
+  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);
+  }
+  return res;
+}
+#define INIT_RECVMSG 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;
+  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 INTERCEPT_FUNCTION(getpeername);
+#else
+#define INIT_GETPEERNAME
+#endif
+
+#if SANITIZER_INTERCEPT_SYSINFO
+INTERCEPTOR(int, sysinfo, void *info) {
+  void *ctx;
+  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 INTERCEPT_FUNCTION(sysinfo);
+#else
+#define INIT_SYSINFO
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR
+INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
+  __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);
+  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           \
+  INTERCEPT_FUNCTION(readdir); \
+  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);
+  __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);
+  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           \
+  INTERCEPT_FUNCTION(readdir64); \
+  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);
+    }
+  }
+
+  uptr res = REAL(ptrace)(request, pid, addr, data);
+
+  if (!res && data) {
+    // Note that PEEK* requests assing 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_getregset) {
+      __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len);
+    }
+  }
+  return res;
+}
+
+#define INIT_PTRACE           \
+  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           \
+  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);
+  char *res = REAL(getcwd)(buf, size);
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT_GETCWD           \
+  INTERCEPT_FUNCTION(getcwd);
+#else
+#define INIT_GETCWD
+#endif
+
+#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
+INTERCEPTOR(char *, get_current_dir_name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name);
+  char *res = REAL(get_current_dir_name)();
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+
+#define INIT_GET_CURRENT_DIR_NAME           \
+  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);
+  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);
+  INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
+  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  return res;
+}
+
+#define INIT_STRTOIMAX           \
+  INTERCEPT_FUNCTION(strtoimax); \
+  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);
+  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);
+  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           \
+  INTERCEPT_FUNCTION(mbstowcs); \
+  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);
+  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 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);
+  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);
+  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           \
+  INTERCEPT_FUNCTION(wcstombs); \
+  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);
+  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 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);
+  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 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 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 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);
+  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 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);
+  int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
+  if (mask && !res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
+  return res;
+}
+#define INIT_SCHED_GETAFFINITY INTERCEPT_FUNCTION(sched_getaffinity);
+#else
+#define INIT_SCHED_GETAFFINITY
+#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_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT_STRERROR 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);
+  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 INTERCEPT_FUNCTION(strerror_r);
+#else
+#define INIT_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 void *scandir_ctx;
+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(scandir_ctx, 1);
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, 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(scandir_ctx, 2);
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, a, sizeof(*a));
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *a, (*a)->d_reclen);
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, b, sizeof(*b));
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *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);
+  CHECK_EQ(0, scandir_ctx);
+  scandir_ctx = ctx;
+  scandir_filter = filter;
+  scandir_compar = compar;
+  int res = REAL(scandir)(dirp, namelist, filter ? wrapped_scandir_filter : 0,
+                          compar ? wrapped_scandir_compar : 0);
+  scandir_ctx = 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 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 void *scandir64_ctx;
+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(scandir64_ctx, 1);
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, 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(scandir64_ctx, 2);
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, a, sizeof(*a));
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *a, (*a)->d_reclen);
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, b, sizeof(*b));
+  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *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);
+  CHECK_EQ(0, scandir64_ctx);
+  scandir64_ctx = ctx;
+  scandir64_filter = filter;
+  scandir64_compar = compar;
+  int res =
+      REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0,
+                      compar ? wrapped_scandir64_compar : 0);
+  scandir64_ctx = 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 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);
+  int res = REAL(getgroups)(size, lst);
+  if (res && lst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
+  return res;
+}
+#define INIT_GETGROUPS 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 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 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);
+  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 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
+  int res = REAL(sigwait)(set, sig);
+  if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
+  return res;
+}
+#define INIT_SIGWAIT 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
+  int res = REAL(sigwaitinfo)(set, info);
+  if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+  return res;
+}
+#define INIT_SIGWAITINFO 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
+  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 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);
+  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);
+  int res = REAL(sigfillset)(set);
+  if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+  return res;
+}
+#define INIT_SIGSETOPS             \
+  INTERCEPT_FUNCTION(sigemptyset); \
+  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);
+  int res = REAL(sigpending)(set);
+  if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+  return res;
+}
+#define INIT_SIGPENDING 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
+  int res = REAL(sigprocmask)(how, set, oldset);
+  if (!res && oldset)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+  return res;
+}
+#define INIT_SIGPROCMASK 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);
+  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));
+  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           \
+  INTERCEPT_FUNCTION(backtrace); \
+  INTERCEPT_FUNCTION(backtrace_symbols);
+#else
+#define INIT_BACKTRACE
+#endif
+
+#define SANITIZER_COMMON_INTERCEPTORS_INIT \
+  INIT_STRCMP;                             \
+  INIT_STRNCMP;                            \
+  INIT_STRCASECMP;                         \
+  INIT_STRNCASECMP;                        \
+  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_SCANF;                              \
+  INIT_ISOC99_SCANF;                       \
+  INIT_FREXP;                              \
+  INIT_FREXPF_FREXPL;                      \
+  INIT_GETPWNAM_AND_FRIENDS;               \
+  INIT_GETPWNAM_R_AND_FRIENDS;             \
+  INIT_CLOCK_GETTIME;                      \
+  INIT_GETITIMER;                          \
+  INIT_TIME;                               \
+  INIT_GLOB;                               \
+  INIT_WAIT;                               \
+  INIT_INET;                               \
+  INIT_PTHREAD_GETSCHEDPARAM;              \
+  INIT_GETADDRINFO;                        \
+  INIT_GETNAMEINFO;                        \
+  INIT_GETSOCKNAME;                        \
+  INIT_GETHOSTBYNAME;                      \
+  INIT_GETHOSTBYNAME_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_STRERROR;                           \
+  INIT_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;
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
new file mode 100755 (executable)
index 0000000..50db0d7
--- /dev/null
@@ -0,0 +1,566 @@
+//===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===//
+//
+// 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. Those are currently marked as WRITE.
+  enum {
+    NONE,
+    READ,
+    WRITE,
+    CUSTOM
+  } type : 2;
+  unsigned size : 30;
+  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) || SANITIZER_MAC
+  _(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
+  if ((req & ~0x3fff001fU) == IOCTL_EVIOCGBIT)
+    return IOCTL_EVIOCGBIT;
+  if ((req & ~0x3fU) == IOCTL_EVIOCGABS)
+    return IOCTL_EVIOCGABS;
+  if ((req & ~0x3fU) == 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 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 & ~0x3fff0000U);
+  // 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::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) {
+    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) {
+    // 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;
+}
index 5b761382d3e31453037aa0f2642e04e0eb939bc4..2660dada2bebfa388c9af7254291866ce1379c72 100644 (file)
@@ -276,7 +276,7 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
   CHECK_GT(n_inputs, 0);
   const char *p = format;
 
-  while (*p && n_inputs) {
+  while (*p) {
     ScanfDirective dir;
     p = scanf_parse_next(p, allowGnuMalloc, &dir);
     if (!p)
@@ -299,6 +299,8 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
     void *argp = va_arg(aq, void *);
     if (dir.convSpecifier != 'n')
       --n_inputs;
+    if (n_inputs < 0)
+      break;
     if (size == SSS_STRLEN) {
       size = internal_strlen((const char *)argp) + 1;
     }
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
new file mode 100644 (file)
index 0000000..215a61d
--- /dev/null
@@ -0,0 +1,35 @@
+//===-- sanitizer_common_libcdep.cc ---------------------------------------===//
+//
+// 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"
+
+namespace __sanitizer {
+
+bool PrintsToTty() {
+  MaybeOpenReportFile();
+  return internal_isatty(report_fd) != 0;
+}
+
+bool PrintsToTtyCached() {
+  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
+  // printing on Windows.
+  if (SANITIZER_WINDOWS)
+    return 0;
+
+  static int cached = 0;
+  static bool prints_to_tty;
+  if (!cached) {  // Not thread-safe.
+    prints_to_tty = PrintsToTty();
+    cached = 1;
+  }
+  return prints_to_tty;
+}
+}  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
new file mode 100644 (file)
index 0000000..bc097c8
--- /dev/null
@@ -0,0 +1,2732 @@
+//===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===//
+//
+// 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_FD_CLOSE(fd)
+//          Called before closing file descriptor 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_FD_CLOSE
+# define COMMON_SYSCALL_FD_CLOSE(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);
+  }
+}
+
+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);
+  }
+}
+
+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) {}
+
+POST_SYSCALL(capget)(long res, void *header, void *dataptr) {
+  if (res >= 0) {
+    if (header) POST_WRITE(header, __user_cap_header_struct_sz);
+    if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz);
+  }
+}
+
+PRE_SYSCALL(capset)(void *header, const void *data) {
+  if (data) PRE_READ(data, __user_cap_data_struct_sz);
+}
+
+POST_SYSCALL(capset)(long res, void *header, const void *data) {
+  if (res >= 0) {
+    if (header) POST_WRITE(header, __user_cap_header_struct_sz);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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 (res >= 0) {
+    if (value) POST_WRITE(value, size);
+  }
+}
+
+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 (res >= 0) {
+    if (value) POST_WRITE(value, size);
+  }
+}
+
+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 (res >= 0) {
+    if (value) POST_WRITE(value, size);
+  }
+}
+
+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 (res >= 0) {
+    if (list) POST_WRITE(list, size);
+  }
+}
+
+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 (res >= 0) {
+    if (list) POST_WRITE(list, size);
+  }
+}
+
+PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {}
+
+POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) {
+  if (res >= 0) {
+    if (list) POST_WRITE(list, size);
+  }
+}
+
+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) {}
+
+POST_SYSCALL(io_setup)(long res, long nr_reqs, void *ctx) {
+  if (res >= 0) {
+    if (ctx) POST_WRITE(ctx, sizeof(long));
+  }
+}
+
+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, void *events,
+                          void *timeout) {
+  if (timeout) PRE_READ(timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
+                           void *events, void *timeout) {
+  if (res >= 0) {
+    if (events) POST_WRITE(events, res * struct_io_event_sz);
+    if (timeout) POST_WRITE(timeout, struct_timespec_sz);
+  }
+}
+
+PRE_SYSCALL(io_submit)(long, long arg1, void *arg2) {}
+
+POST_SYSCALL(io_submit)(long res, long, long arg1, void *arg2) {}
+
+PRE_SYSCALL(io_cancel)(long ctx_id, void *iocb, void *result) {}
+
+POST_SYSCALL(io_cancel)(long res, long ctx_id, void *iocb, void *result) {
+  if (res >= 0) {
+    if (iocb) POST_WRITE(iocb, struct_iocb_sz);
+    if (result) POST_WRITE(result, struct_io_event_sz);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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(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, struct_shmid_ds_sz);
+  }
+}
+
+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(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) {}
+
+POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {}
+
+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)(void *attr_uptr, long pid, long cpu, long group_fd,
+                             long flags) {}
+
+POST_SYSCALL(perf_event_open)(long res, void *attr_uptr, long pid, long cpu,
+                              long group_fd, long flags) {
+  if (res >= 0) {
+    if (attr_uptr) POST_WRITE(attr_uptr, struct_perf_event_attr_sz);
+  }
+}
+
+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
index 2152c7bdff4db54b4a5e685b43ba544154e1bb85..06ac5435b9d6536b7e5341f6015f02d55f854abf 100644 (file)
 
 namespace __sanitizer {
 
+CommonFlags common_flags_dont_use_directly;
+
+void ParseCommonFlagsFromString(const char *str) {
+  CommonFlags *f = common_flags();
+  ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
+  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
+  ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
+  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
+  ParseFlag(str, &f->symbolize, "symbolize");
+  ParseFlag(str, &f->handle_ioctl, "handle_ioctl");
+  ParseFlag(str, &f->log_path, "log_path");
+  ParseFlag(str, &f->detect_leaks, "detect_leaks");
+  ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit");
+  ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null");
+}
+
 static bool GetFlagValue(const char *env, const char *name,
                          const char **value, int *value_length) {
   if (env == 0)
     return false;
-  const char *pos = internal_strstr(env, name);
-  const char *end;
-  if (pos == 0)
-    return false;
+  const char *pos = 0;
+  for (;;) {
+    pos = internal_strstr(env, name);
+    if (pos == 0)
+      return false;
+    if (pos != env && ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) {
+      // Seems to be middle of another flag name or value.
+      env = pos + 1;
+      continue;
+    }
+    break;
+  }
   pos += internal_strlen(name);
+  const char *end;
   if (pos[0] != '=') {
     end = pos;
   } else {
@@ -75,7 +100,7 @@ void ParseFlag(const char *env, int *flag, const char *name) {
   int value_length;
   if (!GetFlagValue(env, name, &value, &value_length))
     return;
-  *flag = internal_atoll(value);
+  *flag = static_cast<int>(internal_atoll(value));
 }
 
 static LowLevelAllocator allocator_for_flags;
index 1b9bf5bffdb29a674136f8b29c6184dddf45bb95..62aa96bbb69923eecc5beae4110c170344edb448 100644 (file)
@@ -20,6 +20,41 @@ void ParseFlag(const char *env, bool *flag, const char *name);
 void ParseFlag(const char *env, int *flag, const char *name);
 void ParseFlag(const char *env, const char **flag, const char *name);
 
+struct CommonFlags {
+  // If set, use the online symbolizer from common sanitizer runtime.
+  bool symbolize;
+  // Path to external symbolizer.
+  const char *external_symbolizer_path;
+  // Strips this prefix from file paths in error reports.
+  const char *strip_path_prefix;
+  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
+  bool fast_unwind_on_fatal;
+  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
+  bool fast_unwind_on_malloc;
+  // Intercept and handle ioctl requests.
+  bool handle_ioctl;
+  // Max number of stack frames kept for each allocation/deallocation.
+  int malloc_context_size;
+  // Write logs to "log_path.pid" instead of stderr.
+  const char *log_path;
+  // Enable memory leak detection.
+  bool detect_leaks;
+  // 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.
+  bool leak_check_at_exit;
+  // If false, the allocator will crash instead of returning 0 on out-of-memory.
+  bool allocator_may_return_null;
+};
+
+extern CommonFlags common_flags_dont_use_directly;
+
+inline CommonFlags *common_flags() {
+  return &common_flags_dont_use_directly;
+}
+
+void ParseCommonFlagsFromString(const char *str);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FLAGS_H
index 577c9a9c17fcbbe9e84365a3572eac7899b69088..cc9233cad5f91ff5383d350a97a4ee8370ab259a 100644 (file)
 #ifndef SANITIZER_DEFS_H
 #define SANITIZER_DEFS_H
 
-#if defined(_WIN32)
-// FIXME find out what we need on Windows. __declspec(dllexport) ?
-# define SANITIZER_INTERFACE_ATTRIBUTE
+#include "sanitizer_platform.h"
+
+// 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
@@ -23,7 +26,7 @@
 # define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
 #endif
 
-#ifdef __linux__
+#if SANITIZER_LINUX && !defined(SANITIZER_GO)
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 1
 #else
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 0
@@ -64,29 +67,39 @@ 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.
+// Mac and Linux/x86-64 are special.
+#if SANITIZER_MAC || (SANITIZER_LINUX && defined(__x86_64__))
+typedef u64 OFF_T;
+#else
+typedef uptr OFF_T;
+#endif
+typedef u64  OFF64_T;
 }  // namespace __sanitizer
 
 extern "C" {
   // Tell the tools to write their reports to "path.<pid>" instead of stderr.
-  void __sanitizer_set_report_path(const char *path)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __sanitizer_set_report_path(const char *path);
 
   // Tell the tools to write their reports to given file descriptor instead of
   // stderr.
-  void __sanitizer_set_report_fd(int fd)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __sanitizer_set_report_fd(int fd);
 
   // 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(void *reserved)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  void __sanitizer_sandbox_on_notify(void *reserved);
 
   // 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)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  void __sanitizer_report_error_summary(const char *error_summary);
 }  // extern "C"
 
 
@@ -95,13 +108,13 @@ using namespace __sanitizer;  // NOLINT
 // This header should NOT include any other headers to avoid portability issues.
 
 // Common defs.
-#define INLINE static inline
+#define INLINE inline
 #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
 #define WEAK SANITIZER_WEAK_ATTRIBUTE
 
 // Platform-specific defs.
 #if defined(_MSC_VER)
-# define ALWAYS_INLINE __declspec(forceinline)
+# define ALWAYS_INLINE __forceinline
 // FIXME(timurrrr): do we need this on Windows?
 # define ALIAS(x)
 # define ALIGNED(x) __declspec(align(x))
@@ -116,8 +129,10 @@ using namespace __sanitizer;  // NOLINT
 # define USED
 # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
 #else  // _MSC_VER
-# define ALWAYS_INLINE __attribute__((always_inline))
+# 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))
@@ -136,7 +151,15 @@ using namespace __sanitizer;  // NOLINT
 # endif
 #endif  // _MSC_VER
 
-#if defined(_WIN32)
+// 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
@@ -155,6 +178,9 @@ 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
@@ -259,10 +285,12 @@ extern "C" void* _ReturnAddress(void);
 # define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
 #endif
 
-#define HANDLE_EINTR(res, f) {                               \
-  do {                                                                  \
-    res = (f);                                                         \
-  } while (res == -1 && errno == EINTR); \
+#define HANDLE_EINTR(res, f)                                       \
+  {                                                                \
+    int rverrno;                                                   \
+    do {                                                           \
+      res = (f);                                                   \
+    } while (internal_iserror(res, &rverrno) && rverrno == EINTR); \
   }
 
 #endif  // SANITIZER_DEFS_H
index c57128a54cbd06641cab81db1f5cdea57503aed8..2a75e431b31d30dd0a8e87b52119e61520a4ab98 100644 (file)
@@ -8,6 +8,7 @@
 // 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"
 
@@ -122,6 +123,13 @@ char* internal_strchr(const char *s, int c) {
   }
 }
 
+char *internal_strchrnul(const char *s, int c) {
+  char *res = internal_strchr(s, c);
+  if (!res)
+    res = (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++) {
@@ -149,8 +157,7 @@ char *internal_strncpy(char *dst, const char *src, uptr n) {
   uptr i;
   for (i = 0; i < n && src[i]; i++)
     dst[i] = src[i];
-  for (; i < n; i++)
-    dst[i] = '\0';
+  internal_memset(dst + i, '\0', n - i);
   return dst;
 }
 
index 16239413356f88eb4171803bff00a40ac594ce10..f90ffcc679a7c850c64855cf4a393cc7aa626b9f 100644 (file)
@@ -30,6 +30,7 @@ void *internal_memmove(void *dest, const void *src, 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);
@@ -51,36 +52,46 @@ bool mem_is_zero(const char *mem, uptr size);
 
 
 // Memory
-void *internal_mmap(void *addr, uptr length, int prot, int flags,
-                    int fd, u64 offset);
-int internal_munmap(void *addr, uptr length);
+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;
-int internal_close(fd_t fd);
+uptr internal_close(fd_t fd);
 int internal_isatty(fd_t fd);
 
 // Use __sanitizer::OpenFile() instead.
-fd_t internal_open(const char *filename, int flags);
-fd_t internal_open(const char *filename, int flags, u32 mode);
+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);
 
 // OS
 uptr internal_filesize(fd_t fd);  // -1 on error.
-int internal_stat(const char *path, void *buf);
-int internal_lstat(const char *path, void *buf);
-int internal_fstat(fd_t fd, void *buf);
-int internal_dup2(int oldfd, int newfd);
+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);
 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();
 
 // Threading
-int internal_sched_yield();
+uptr internal_sched_yield();
+
+// Error handling
+bool internal_iserror(uptr retval, int *rverrno = 0);
 
 }  // namespace __sanitizer
 
index 1ab6f780fa33c064b73f4688f207654e4cd35b23..666f15b4ed60d817974f069650b03f383b6eca84 100644 (file)
@@ -9,29 +9,48 @@
 // run-time libraries and implements linux-specific functions from
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_common.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"
 
+#include <asm/param.h>
+#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 <sys/prctl.h>
 #include <unistd.h>
 #include <unwind.h>
-#include <errno.h>
+
+#if !SANITIZER_ANDROID
+#include <sys/signal.h>
+#endif
+
+// <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;
@@ -48,165 +67,158 @@ const int FUTEX_WAKE = 1;
 
 namespace __sanitizer {
 
+#ifdef __x86_64__
+#include "sanitizer_syscall_linux_x86_64.inc"
+#else
+#include "sanitizer_syscall_generic.inc"
+#endif
+
 // --------------- sanitizer_libc.h
-void *internal_mmap(void *addr, uptr length, int prot, int flags,
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                     int fd, u64 offset) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
+  return internal_syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
 #else
-  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
+  return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
 #endif
 }
 
-int internal_munmap(void *addr, uptr length) {
-  return syscall(__NR_munmap, addr, length);
+uptr internal_munmap(void *addr, uptr length) {
+  return internal_syscall(__NR_munmap, addr, length);
 }
 
-int internal_close(fd_t fd) {
-  return syscall(__NR_close, fd);
+uptr internal_close(fd_t fd) {
+  return internal_syscall(__NR_close, fd);
 }
 
-fd_t internal_open(const char *filename, int flags) {
-  return syscall(__NR_open, filename, flags);
+uptr internal_open(const char *filename, int flags) {
+  return internal_syscall(__NR_open, filename, flags);
 }
 
-fd_t internal_open(const char *filename, int flags, u32 mode) {
-  return syscall(__NR_open, filename, flags, mode);
+uptr internal_open(const char *filename, int flags, u32 mode) {
+  return internal_syscall(__NR_open, filename, flags, mode);
 }
 
-fd_t OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, bool write) {
   return internal_open(filename,
       write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
 }
 
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
+  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, buf, count));
   return res;
 }
 
 uptr internal_write(fd_t fd, const void *buf, uptr count) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
+  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, buf, count));
   return res;
 }
 
-int internal_stat(const char *path, void *buf) {
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS
+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
+
+uptr internal_stat(const char *path, void *buf) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return syscall(__NR_stat, path, buf);
+  return internal_syscall(__NR_stat, path, buf);
 #else
-  return syscall(__NR_stat64, path, buf);
+  struct stat64 buf64;
+  int res = internal_syscall(__NR_stat64, path, &buf64);
+  stat64_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #endif
 }
 
-int internal_lstat(const char *path, void *buf) {
+uptr internal_lstat(const char *path, void *buf) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return syscall(__NR_lstat, path, buf);
+  return internal_syscall(__NR_lstat, path, buf);
 #else
-  return syscall(__NR_lstat64, path, buf);
+  struct stat64 buf64;
+  int res = internal_syscall(__NR_lstat64, path, &buf64);
+  stat64_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #endif
 }
 
-int internal_fstat(fd_t fd, void *buf) {
+uptr internal_fstat(fd_t fd, void *buf) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return syscall(__NR_fstat, fd, buf);
+  return internal_syscall(__NR_fstat, fd, buf);
 #else
-  return syscall(__NR_fstat64, fd, buf);
+  struct stat64 buf64;
+  int res = internal_syscall(__NR_fstat64, fd, &buf64);
+  stat64_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #endif
 }
 
 uptr internal_filesize(fd_t fd) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
   struct stat st;
-#else
-  struct stat64 st;
-#endif
   if (internal_fstat(fd, &st))
     return -1;
   return (uptr)st.st_size;
 }
 
-int internal_dup2(int oldfd, int newfd) {
-  return syscall(__NR_dup2, oldfd, newfd);
+uptr internal_dup2(int oldfd, int newfd) {
+  return internal_syscall(__NR_dup2, oldfd, newfd);
 }
 
 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
-  return (uptr)syscall(__NR_readlink, path, buf, bufsize);
+  return internal_syscall(__NR_readlink, path, buf, bufsize);
+}
+
+uptr internal_unlink(const char *path) {
+  return internal_syscall(__NR_unlink, path);
 }
 
-int internal_sched_yield() {
-  return syscall(__NR_sched_yield);
+uptr internal_sched_yield() {
+  return internal_syscall(__NR_sched_yield);
 }
 
 void internal__exit(int exitcode) {
-  syscall(__NR_exit_group, exitcode);
+  internal_syscall(__NR_exit_group, exitcode);
   Die();  // Unreachable.
 }
 
+uptr internal_execve(const char *filename, char *const argv[],
+                     char *const envp[]) {
+  return internal_syscall(__NR_execve, filename, argv, envp);
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
   struct stat st;
-  if (syscall(__NR_stat, filename, &st))
+  if (internal_stat(filename, &st))
     return false;
-#else
-  struct stat64 st;
-  if (syscall(__NR_stat64, filename, &st))
-    return false;
-#endif
   // Sanity check: filename is a regular file.
   return S_ISREG(st.st_mode);
 }
 
 uptr GetTid() {
-  return syscall(__NR_gettid);
-}
-
-void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
-                                uptr *stack_bottom) {
-  static const uptr kMaxThreadStackSize = 256 * (1 << 20);  // 256M
-  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;
-    uptr start, end, offset;
-    uptr prev_end = 0;
-    while (proc_maps.Next(&start, &end, &offset, 0, 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;
-  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
-  uptr stacksize = 0;
-  void *stackaddr = 0;
-  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
-  pthread_attr_destroy(&attr);
+  return internal_syscall(__NR_gettid);
+}
 
-  *stack_top = (uptr)stackaddr + stacksize;
-  *stack_bottom = (uptr)stackaddr;
-  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
+u64 NanoTime() {
+  kernel_timeval tv = {};
+  internal_syscall(__NR_gettimeofday, &tv, 0);
+  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
 }
 
 // Like getenv, but reads env directly from /proc and does not use libc.
@@ -237,21 +249,11 @@ const char *GetEnv(const char *name) {
   return 0;  // Not found.
 }
 
-#ifdef __GLIBC__
-
 extern "C" {
-  extern void *__libc_stack_end;
-}
-
-static void GetArgsAndEnv(char ***argv, char ***envp) {
-  uptr *stack_end = (uptr *)__libc_stack_end;
-  int argc = *stack_end;
-  *argv = (char**)(stack_end + 1);
-  *envp = (char**)(stack_end + argc + 2);
+  SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
 }
 
-#else  // __GLIBC__
-
+#if !SANITIZER_GO
 static void ReadNullSepFileToArray(const char *path, char ***arr,
                                    int arr_size) {
   char *buff;
@@ -270,20 +272,32 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
   }
   (*arr)[count] = 0;
 }
+#endif
 
-static void GetArgsAndEnv(char ***argv, char ***envp) {
-  static const int kMaxArgv = 2000, kMaxEnvp = 2000;
-  ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
-  ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
+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
 }
 
-#endif  // __GLIBC__
-
 void ReExec() {
   char **argv, **envp;
   GetArgsAndEnv(&argv, &envp);
-  execve("/proc/self/exe", argv, envp);
-  Printf("execve failed, errno %d\n", errno);
+  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();
 }
 
@@ -293,6 +307,10 @@ void PrepareForSandboxing() {
   // 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
+  getSymbolizer()->PrepareForSandboxing();
+#endif
 }
 
 // ----------------- sanitizer_procmaps.h
@@ -300,18 +318,22 @@ void PrepareForSandboxing() {
 ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
 StaticSpinMutex MemoryMappingLayout::cache_lock_;  // Linker initialized.
 
-MemoryMappingLayout::MemoryMappingLayout() {
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
   proc_self_maps_.len =
       ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
                        &proc_self_maps_.mmaped_size, 1 << 26);
-  if (proc_self_maps_.mmaped_size == 0) {
-    LoadFromCache();
-    CHECK_GT(proc_self_maps_.len, 0);
+  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);
   }
-  // internal_write(2, proc_self_maps_.data, proc_self_maps_.len);
   Reset();
   // FIXME: in the future we may want to cache the mappings on demand only.
-  CacheMemoryMappings();
+  if (cache_enabled)
+    CacheMemoryMappings();
 }
 
 MemoryMappingLayout::~MemoryMappingLayout() {
@@ -373,7 +395,7 @@ static uptr ParseHex(char **str) {
   return x;
 }
 
-static bool IsOnOf(char c, char c1, char c2) {
+static bool IsOneOf(char c, char c1, char c2) {
   return c == c1 || c == c2;
 }
 
@@ -381,8 +403,33 @@ static bool IsDecimal(char c) {
   return c >= '0' && c <= '9';
 }
 
+static bool IsHex(char c) {
+  return (c >= '0' && c <= '9')
+      || (c >= 'a' && c <= 'f');
+}
+
+static uptr ReadHex(const char *p) {
+  uptr v = 0;
+  for (; IsHex(p[0]); p++) {
+    if (p[0] >= '0' && p[0] <= '9')
+      v = v * 16 + p[0] - '0';
+    else
+      v = v * 16 + p[0] - 'a' + 10;
+  }
+  return v;
+}
+
+static uptr ReadDecimal(const char *p) {
+  uptr v = 0;
+  for (; IsDecimal(p[0]); p++)
+    v = v * 10 + p[0] - '0';
+  return v;
+}
+
+
 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
-                               char filename[], uptr filename_size) {
+                               char filename[], uptr filename_size,
+                               uptr *protection) {
   char *last = proc_self_maps_.data + proc_self_maps_.len;
   if (current_ >= last) return false;
   uptr dummy;
@@ -397,10 +444,22 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
   CHECK_EQ(*current_++, '-');
   *end = ParseHex(&current_);
   CHECK_EQ(*current_++, ' ');
-  CHECK(IsOnOf(*current_++, '-', 'r'));
-  CHECK(IsOnOf(*current_++, '-', 'w'));
-  CHECK(IsOnOf(*current_++, '-', 'x'));
-  CHECK(IsOnOf(*current_++, 's', 'p'));
+  uptr local_protection = 0;
+  CHECK(IsOneOf(*current_, '-', 'r'));
+  if (*current_++ == 'r')
+    local_protection |= kProtectionRead;
+  CHECK(IsOneOf(*current_, '-', 'w'));
+  if (*current_++ == 'w')
+    local_protection |= kProtectionWrite;
+  CHECK(IsOneOf(*current_, '-', 'x'));
+  if (*current_++ == 'x')
+    local_protection |= kProtectionExecute;
+  CHECK(IsOneOf(*current_, 's', 'p'));
+  if (*current_++ == 's')
+    local_protection |= kProtectionShared;
+  if (protection) {
+    *protection = local_protection;
+  }
   CHECK_EQ(*current_++, ' ');
   *offset = ParseHex(&current_);
   CHECK_EQ(*current_++, ' ');
@@ -432,87 +491,35 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
 // Gets the object name and the offset by walking MemoryMappingLayout.
 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
                                                  char filename[],
-                                                 uptr filename_size) {
-  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
-}
-
-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
-}
-
-#ifndef SANITIZER_GO
-//------------------------- SlowUnwindStack -----------------------------------
-#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
-}
-
-_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
-  StackTrace *b = (StackTrace*)param;
-  CHECK(b->size < b->max_size);
-  uptr pc = Unwind_GetIP(ctx);
-  b->trace[b->size++] = pc;
-  if (b->size == b->max_size) return UNWIND_STOP;
-  return UNWIND_CONTINUE;
-}
-
-static bool MatchPc(uptr cur_pc, uptr trace_pc) {
-  return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
-}
-
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
-  this->size = 0;
-  this->max_size = max_depth;
-  if (max_depth > 1) {
-    _Unwind_Backtrace(Unwind_Trace, this);
-    // We need to pop a few frames so that pc is on top.
-    // trace[0] belongs to the current function so we always pop it.
-    int to_pop = 1;
-    /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
-    else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
-    else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
-    else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
-    else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
-    this->PopStackFrames(to_pop);
+                                                 uptr filename_size,
+                                                 uptr *protection) {
+  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
+                                       protection);
+}
+
+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 = ReadHex(pos);
+      for (; *pos != '/' && *pos > '\n'; pos++) {}
+      file = *pos == '/';
+    } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
+      for (; *pos < '0' || *pos > '9'; pos++) {}
+      uptr rss = ReadDecimal(pos) * 1024;
+      cb(start, rss, file, stats, stats_size);
+    }
+    while (*pos++ != '\n') {}
   }
-  this->trace[0] = pc;
+  UnmapOrDie(smaps, smaps_cap);
 }
 
-#endif  // #ifndef SANITIZER_GO
-
 enum MutexState {
   MtxUnlocked = 0,
   MtxLocked = 1,
@@ -523,12 +530,16 @@ BlockingMutex::BlockingMutex(LinkerInitialized) {
   CHECK_EQ(owner_, 0);
 }
 
+BlockingMutex::BlockingMutex() {
+  internal_memset(this, 0, sizeof(*this));
+}
+
 void BlockingMutex::Lock() {
   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)
-    syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+    internal_syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
 }
 
 void BlockingMutex::Unlock() {
@@ -536,9 +547,281 @@ void BlockingMutex::Unlock() {
   u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
   CHECK_NE(v, MtxUnlocked);
   if (v == MtxSleeping)
-    syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
+    internal_syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
+}
+
+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 {
+  unsigned long      d_ino;
+  unsigned long      d_off;
+  unsigned short     d_reclen;
+  char               d_name[256];
+};
+
+// Syscall wrappers.
+uptr internal_ptrace(int request, int pid, void *addr, void *data) {
+  return internal_syscall(__NR_ptrace, request, pid, addr, data);
+}
+
+uptr internal_waitpid(int pid, int *status, int options) {
+  return internal_syscall(__NR_wait4, pid, status, options, 0 /* rusage */);
+}
+
+uptr internal_getpid() {
+  return internal_syscall(__NR_getpid);
+}
+
+uptr internal_getppid() {
+  return internal_syscall(__NR_getppid);
+}
+
+uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
+  return internal_syscall(__NR_getdents, fd, dirp, count);
+}
+
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
+  return internal_syscall(__NR_lseek, fd, offset, whence);
+}
+
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
+  return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
+}
+
+uptr internal_sigaltstack(const struct sigaltstack *ss,
+                         struct sigaltstack *oss) {
+  return internal_syscall(__NR_sigaltstack, ss, oss);
+}
+
+// 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 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) {
+  uptr module_name_len = internal_readlink(
+      "/proc/self/exe", buf, buf_len);
+  int readlink_error;
+  if (internal_iserror(module_name_len, &readlink_error)) {
+    if (proc_self_exe_cache_len) {
+      // If available, use the cached module name.
+      CHECK_LE(proc_self_exe_cache_len, buf_len);
+      internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
+      module_name_len = internal_strlen(proc_self_exe_cache_str);
+    } else {
+      // 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);
+    buf[module_name_len] = '\0';
+  }
+  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)) {
+  typedef ElfW(Phdr) Elf_Phdr;
+  typedef ElfW(Ehdr) Elf_Ehdr;
+  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__)
+// 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(void *);
+  ((void **)child_stack)[0] = (void *)(uptr)fn;
+  ((void **)child_stack)[1] = arg;
+  __asm__ __volatile__(
+                       /* %rax = syscall(%rax = __NR_clone,
+                        *                %rdi = flags,
+                        *                %rsi = child_stack,
+                        *                %rdx = parent_tidptr,
+                        *                %r8  = new_tls,
+                        *                %r10 = child_tidptr)
+                        */
+                       "movq   %6,%%r8\n"
+                       "movq   %7,%%r10\n"
+                       ".cfi_endproc\n"
+                       "syscall\n"
+
+                       /* if (%rax != 0)
+                        *   return;
+                        */
+                       "testq  %%rax,%%rax\n"
+                       "jnz    1f\n"
+
+                       /* In the child. Terminate unwind chain. */
+                       ".cfi_startproc\n"
+                       ".cfi_undefined %%rip;\n"
+                       "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"(__NR_clone), "i"(__NR_exit),
+                         "S"(child_stack),
+                         "D"(flags),
+                         "d"(parent_tidptr),
+                         "r"(newtls),
+                         "r"(child_tidptr)
+                       : "rsp", "memory", "r8", "r10", "r11", "rcx");
+  return res;
+}
+#endif  // defined(__x86_64__)
 }  // namespace __sanitizer
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
new file mode 100644 (file)
index 0000000..5bbf479
--- /dev/null
@@ -0,0 +1,81 @@
+//===-- sanitizer_linux.h ---------------------------------------*- C++ -*-===//
+//
+// 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_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.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_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
+uptr internal_sigaltstack(const struct sigaltstack* ss,
+                          struct sigaltstack* oss);
+#ifdef __x86_64__
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+                    int *parent_tidptr, void *newtls, int *child_tidptr);
+#endif
+
+// 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_;
+};
+
+void AdjustStackSizeLinux(void *attr, int verbosity);
+
+// 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_LINUX
+#endif  // SANITIZER_LINUX_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
new file mode 100644 (file)
index 0000000..7d6c639
--- /dev/null
@@ -0,0 +1,351 @@
+//===-- sanitizer_linux_libcdep.cc ----------------------------------------===//
+//
+// 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_LINUX
+
+#include "sanitizer_common.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <unwind.h>
+
+#if !SANITIZER_ANDROID
+#include <elf.h>
+#include <link.h>
+#endif
+
+namespace __sanitizer {
+
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+                                uptr *stack_bottom) {
+  static const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb
+  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;
+  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
+  uptr stacksize = 0;
+  void *stackaddr = 0;
+  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;
+}
+
+// Does not compile for Go because dlsym() requires -ldl
+#ifndef 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
+}
+
+#ifndef SANITIZER_GO
+//------------------------- SlowUnwindStack -----------------------------------
+#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
+}
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+  StackTrace *b = (StackTrace*)param;
+  CHECK(b->size < b->max_size);
+  uptr pc = Unwind_GetIP(ctx);
+  b->trace[b->size++] = pc;
+  if (b->size == b->max_size) return UNWIND_STOP;
+  return UNWIND_CONTINUE;
+}
+
+static bool MatchPc(uptr cur_pc, uptr trace_pc) {
+  return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
+}
+
+void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+  this->size = 0;
+  this->max_size = max_depth;
+  if (max_depth > 1) {
+    _Unwind_Backtrace(Unwind_Trace, this);
+    // We need to pop a few frames so that pc is on top.
+    // trace[0] belongs to the current function so we always pop it.
+    int to_pop = 1;
+    /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
+    else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
+    else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
+    else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
+    else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
+    this->PopStackFrames(to_pop);
+  }
+  this->trace[0] = pc;
+}
+
+#endif  // !SANITIZER_GO
+
+static uptr g_tls_size;
+
+#ifdef __i386__
+# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
+#else
+# define DL_INTERNAL_FUNCTION
+#endif
+
+void InitTlsSize() {
+#if !defined(SANITIZER_GO) && !SANITIZER_ANDROID
+  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
+}
+
+uptr GetTlsSize() {
+  return g_tls_size;
+}
+
+#if defined(__x86_64__) || defined(__i386__)
+// sizeof(struct thread) from glibc.
+// There has been a report of this being different on glibc 2.11 and 2.13. We
+// don't know when this change happened, so 2.14 is a conservative estimate.
+#if __GLIBC_PREREQ(2, 14)
+const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304);
+#else
+const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1168, 2304);
+#endif
+
+uptr ThreadDescriptorSize() {
+  return kThreadDescriptorSize;
+}
+
+// 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;
+#ifdef __i386__
+  asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+#else
+  asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+#endif
+  return descr_addr;
+}
+#endif  // defined(__x86_64__) || defined(__i386__)
+
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+                          uptr *tls_addr, uptr *tls_size) {
+#ifndef SANITIZER_GO
+#if defined(__x86_64__) || defined(__i386__)
+  *tls_addr = ThreadSelf();
+  *tls_size = GetTlsSize();
+  *tls_addr -= *tls_size;
+  *tls_addr += kThreadDescriptorSize;
+#else
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif
+
+  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;
+    }
+  }
+#else  // SANITIZER_GO
+  *stk_addr = 0;
+  *stk_size = 0;
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif  // SANITIZER_GO
+}
+
+void AdjustStackSizeLinux(void *attr_, int verbosity) {
+  pthread_attr_t *attr = (pthread_attr_t *)attr_;
+  uptr stackaddr = 0;
+  size_t stacksize = 0;
+  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 (verbosity && stacksize != 0)
+        Printf("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) {
+  return 0;
+}
+#else  // SANITIZER_ANDROID
+typedef ElfW(Phdr) Elf_Phdr;
+
+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;
+  InternalScopedBuffer<char> module_name(kMaxPathLength);
+  module_name.data()[0] = '\0';
+  if (data->first) {
+    data->first = false;
+    // First module is the binary itself.
+    ReadBinaryName(module_name.data(), module_name.size());
+  } else if (info->dlpi_name) {
+    internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
+  }
+  if (module_name.data()[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;
+      cur_module->addAddressRange(cur_beg, cur_end);
+    }
+  }
+  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
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_LINUX
index d7885bb350963b1911a8f46631b1ce93745d4e5f..fa146b5b4e8a49c0f6ccba399828bebfe7e6d489 100644 (file)
@@ -10,7 +10,9 @@
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#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
@@ -21,6 +23,7 @@
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 
 #include <crt_externs.h>  // for _NSGetEnviron
 #include <sys/types.h>
 #include <unistd.h>
 #include <libkern/OSAtomic.h>
+#include <errno.h>
 
 namespace __sanitizer {
 
+#include "sanitizer_syscall_generic.inc"
+
 // ---------------------- sanitizer_libc.h
-void *internal_mmap(void *addr, size_t length, int prot, int flags,
-                    int fd, u64 offset) {
-  return mmap(addr, length, prot, flags, fd, offset);
+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);
 }
 
-int internal_munmap(void *addr, uptr length) {
+uptr internal_munmap(void *addr, uptr length) {
   return munmap(addr, length);
 }
 
-int internal_close(fd_t fd) {
+uptr internal_close(fd_t fd) {
   return close(fd);
 }
 
-fd_t internal_open(const char *filename, int flags) {
+uptr internal_open(const char *filename, int flags) {
   return open(filename, flags);
 }
 
-fd_t internal_open(const char *filename, int flags, u32 mode) {
+uptr internal_open(const char *filename, int flags, u32 mode) {
   return open(filename, flags, mode);
 }
 
-fd_t OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, bool write) {
   return internal_open(filename,
       write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
 }
@@ -73,15 +79,15 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
   return write(fd, buf, count);
 }
 
-int internal_stat(const char *path, void *buf) {
+uptr internal_stat(const char *path, void *buf) {
   return stat(path, (struct stat *)buf);
 }
 
-int internal_lstat(const char *path, void *buf) {
+uptr internal_lstat(const char *path, void *buf) {
   return lstat(path, (struct stat *)buf);
 }
 
-int internal_fstat(fd_t fd, void *buf) {
+uptr internal_fstat(fd_t fd, void *buf) {
   return fstat(fd, (struct stat *)buf);
 }
 
@@ -92,7 +98,7 @@ uptr internal_filesize(fd_t fd) {
   return (uptr)st.st_size;
 }
 
-int internal_dup2(int oldfd, int newfd) {
+uptr internal_dup2(int oldfd, int newfd) {
   return dup2(oldfd, newfd);
 }
 
@@ -100,7 +106,7 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
   return readlink(path, buf, bufsize);
 }
 
-int internal_sched_yield() {
+uptr internal_sched_yield() {
   return sched_yield();
 }
 
@@ -108,6 +114,10 @@ void internal__exit(int exitcode) {
   _exit(exitcode);
 }
 
+uptr internal_getpid() {
+  return getpid();
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
   struct stat st;
@@ -159,9 +169,13 @@ void PrepareForSandboxing() {
   // Nothing here for now.
 }
 
+uptr GetPageSize() {
+  return sysconf(_SC_PAGESIZE);
+}
+
 // ----------------- sanitizer_procmaps.h
 
-MemoryMappingLayout::MemoryMappingLayout() {
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
   Reset();
 }
 
@@ -214,7 +228,9 @@ void MemoryMappingLayout::LoadFromCache() {
 template<u32 kLCSegment, typename SegmentCommand>
 bool MemoryMappingLayout::NextSegmentLoad(
     uptr *start, uptr *end, uptr *offset,
-    char filename[], uptr filename_size) {
+    char filename[], uptr filename_size, uptr *protection) {
+  if (protection)
+    UNIMPLEMENTED();
   const char* lc = current_load_cmd_addr_;
   current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
   if (((const load_command *)lc)->cmd == kLCSegment) {
@@ -239,7 +255,8 @@ bool MemoryMappingLayout::NextSegmentLoad(
 }
 
 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
-                               char filename[], uptr filename_size) {
+                               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;
@@ -271,14 +288,14 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
 #ifdef MH_MAGIC_64
         case MH_MAGIC_64: {
           if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
-                  start, end, offset, filename, filename_size))
+                  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))
+                  start, end, offset, filename, filename_size, protection))
             return true;
           break;
         }
@@ -292,18 +309,24 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
 
 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
                                                  char filename[],
-                                                 uptr filename_size) {
-  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
+                                                 uptr filename_size,
+                                                 uptr *protection) {
+  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
+                                       protection);
 }
 
 BlockingMutex::BlockingMutex(LinkerInitialized) {
   // We assume that OS_SPINLOCK_INIT is zero
 }
 
+BlockingMutex::BlockingMutex() {
+  internal_memset(this, 0, sizeof(*this));
+}
+
 void BlockingMutex::Lock() {
   CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
-  CHECK(OS_SPINLOCK_INIT == 0);
-  CHECK(owner_ != (uptr)pthread_self());
+  CHECK_EQ(OS_SPINLOCK_INIT, 0);
+  CHECK_NE(owner_, (uptr)pthread_self());
   OSSpinLockLock((OSSpinLock*)&opaque_storage_);
   CHECK(!owner_);
   owner_ = (uptr)pthread_self();
@@ -315,6 +338,69 @@ void BlockingMutex::Unlock() {
   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);
+  memory_mapping.Reset();
+  uptr cur_beg, cur_end, cur_offset;
+  InternalScopedBuffer<char> module_name(kMaxPathLength);
+  uptr n_modules = 0;
+  for (uptr i = 0;
+       n_modules < max_modules &&
+           memory_mapping.Next(&cur_beg, &cur_end, &cur_offset,
+                               module_name.data(), module_name.size(), 0);
+       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);
+  }
+  return n_modules;
+}
+
 }  // namespace __sanitizer
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
index 27009118e62fb9b9611106ce249811ed023a388c..b35011462793bae10cd0139d227b8abd8590a99f 100644 (file)
@@ -68,8 +68,10 @@ class SpinMutex : public StaticSpinMutex {
 class BlockingMutex {
  public:
   explicit BlockingMutex(LinkerInitialized);
+  BlockingMutex();
   void Lock();
   void Unlock();
+  void CheckLocked();
  private:
   uptr opaque_storage_[10];
   uptr owner_;  // for debugging
index e32d65702df07de10c95d7a262d5a65c7a4f64f4..310327fd8f0b5220b15d0cb74fa87790cac4a099 100644 (file)
@@ -17,7 +17,7 @@
 #include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
-#if (SANITIZER_WORDSIZE == 64) || defined(__APPLE__)
+#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
 typedef uptr operator_new_ptr_type;
 #else
 typedef u32 operator_new_ptr_type;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
new file mode 100644 (file)
index 0000000..2270709
--- /dev/null
@@ -0,0 +1,44 @@
+//===-- sanitizer_platform.h ------------------------------------*- C++ -*-===//
+//
+// 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(__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(__APPLE__)
+# define SANITIZER_MAC     1
+#else
+# define SANITIZER_MAC     0
+#endif
+
+#if defined(_WIN32)
+# define SANITIZER_WINDOWS 1
+#else
+# define SANITIZER_WINDOWS 0
+#endif
+
+#if defined(__ANDROID__) || defined(ANDROID)
+# define SANITIZER_ANDROID 1
+#else
+# define SANITIZER_ANDROID 0
+#endif
+
+#define SANITIZER_POSIX (SANITIZER_LINUX || SANITIZER_MAC)
+
+#endif // SANITIZER_PLATFORM_H
index 9b40c0cc523b71abb7f31443d88f8074b5254038..e0199482f1060de4430af28a44e409c83a7ff46e 100644 (file)
 // given library functions on a given platform.
 //
 //===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
+#define SANITIZER_PLATFORM_INTERCEPTORS_H
 
 #include "sanitizer_internal_defs.h"
 
-#if !defined(_WIN32)
+#if !SANITIZER_WINDOWS
 # define SI_NOT_WINDOWS 1
 # include "sanitizer_platform_limits_posix.h"
 #else
 # define SI_NOT_WINDOWS 0
 #endif
 
-#if defined(__linux__) && !defined(ANDROID)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
 # define SI_LINUX_NOT_ANDROID 1
 #else
 # define SI_LINUX_NOT_ANDROID 0
 #endif
 
-#if defined(__linux__)
+#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
+
+# define SANITIZER_INTERCEPT_STRCMP 1
+# define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+
 # 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_PRCTL   SI_LINUX_NOT_ANDROID
+#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_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_SCANF SI_NOT_WINDOWS
 # define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
+
+# 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_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_CLOCK_GETTIME 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_LINUX
+# define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX
+# 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))  // NOLINT
+# define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX
+# 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_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX
+# define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
+# 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_MAC || 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_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
+
+#endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
new file mode 100644 (file)
index 0000000..fbea596
--- /dev/null
@@ -0,0 +1,45 @@
+//===-- sanitizer_platform_limits_linux.cc --------------------------------===//
+//
+// 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
+
+// This header seems to contain the definitions of _kernel_ stat* structs.
+#include <asm/stat.h>
+#include <linux/aio_abi.h>
+
+#if !SANITIZER_ANDROID
+#include <linux/perf_event.h>
+#endif
+
+namespace __sanitizer {
+  unsigned struct___old_kernel_stat_sz = sizeof(struct __old_kernel_stat);
+  unsigned struct_kernel_stat_sz = sizeof(struct stat);
+  unsigned struct_io_event_sz = sizeof(struct io_event);
+  unsigned struct_iocb_sz = sizeof(struct iocb);
+
+#ifndef _LP64
+  unsigned struct_kernel_stat64_sz = sizeof(struct stat64);
+#else
+  unsigned struct_kernel_stat64_sz = 0;
+#endif
+
+#if !SANITIZER_ANDROID
+  unsigned struct_perf_event_attr_sz = sizeof(struct perf_event_attr);
+#endif
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_LINUX
index c4be1aa42da0c9361665f210666815b6094a22cc..971a19314d872c75a2c5cd6292659a69ffdfb6c3 100644 (file)
 // Sizes and layouts of platform-specific POSIX data structures.
 //===----------------------------------------------------------------------===//
 
-#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform_limits_posix.h"
 
+#include <arpa/inet.h>
 #include <dirent.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.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/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_LINUX
+#include <utime.h>
+#include <sys/mount.h>
+#include <sys/ptrace.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_ANDROID
+#include <sys/ucontext.h>
+#include <wordexp.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <glob.h>
+#include <mqueue.h>
+#include <net/if_ppp.h>
+#include <netax25/ax25.h>
+#include <netipx/ipx.h>
+#include <netrom/netrom.h>
+#include <scsi/scsi.h>
+#include <sys/mtio.h>
+#include <sys/kd.h>
+#include <sys/shm.h>
+#include <sys/timex.h>
+#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>
+#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 defined(__linux__)
+#if SANITIZER_LINUX
+#include <link.h>
 #include <sys/vfs.h>
 #include <sys/epoll.h>
-#endif // __linux__
+// #include <asm/stat.h>
+#include <linux/capability.h>
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_MAC
+#include <netinet/ip_mroute.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#endif
 
 namespace __sanitizer {
   unsigned struct_utsname_sz = sizeof(struct utsname);
@@ -35,34 +116,768 @@ namespace __sanitizer {
   unsigned struct_stat64_sz = sizeof(struct stat64);
   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 pid_t_sz = sizeof(pid_t);
+  unsigned timeval_sz = sizeof(timeval);
+  unsigned uid_t_sz = sizeof(uid_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_ANDROID
+  unsigned ucontext_t_sz = sizeof(ucontext_t);
+#endif // !SANITIZER_ANDROID
 
-#if defined(__linux__)
+#if SANITIZER_LINUX
   unsigned struct_rlimit_sz = sizeof(struct rlimit);
-  unsigned struct_dirent_sz = sizeof(struct dirent);
   unsigned struct_statfs_sz = sizeof(struct statfs);
   unsigned struct_epoll_event_sz = sizeof(struct epoll_event);
-#endif // __linux__
+  unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
+  unsigned struct_timespec_sz = sizeof(struct timespec);
+  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_utimbuf_sz = sizeof(struct utimbuf);
+  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);
+  unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+  unsigned struct_ustat_sz = sizeof(struct ustat);
+#endif // SANITIZER_LINUX
 
-#if defined(__linux__) && !defined(__ANDROID__)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
   unsigned struct_statfs64_sz = sizeof(struct statfs64);
-#endif // __linux__ && !__ANDROID__
+  unsigned struct_timex_sz = sizeof(struct timex);
+  unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
+  unsigned struct_shmid_ds_sz = sizeof(struct shmid_ds);
+  unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-  void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx) {
-    return ((struct msghdr *)msg)->msg_iov[idx].iov_base;
-  }
+  uptr sig_ign = (uptr)SIG_IGN;
+  uptr sig_dfl = (uptr)SIG_DFL;
+  uptr sa_siginfo = (uptr)SA_SIGINFO;
 
-  uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx) {
-    return ((struct msghdr *)msg)->msg_iov[idx].iov_len;
-  }
+#if SANITIZER_LINUX
+  int e_tabsz = (int)E_TABSZ;
+#endif
 
-  uptr __sanitizer_get_msghdr_iovlen(void* msg) {
-    return ((struct msghdr *)msg)->msg_iovlen;
-  }
+  int af_inet = (int)AF_INET;
+  int af_inet6 = (int)AF_INET6;
 
-  uptr __sanitizer_get_socklen_t(void* socklen_ptr) {
-    return *(socklen_t*)socklen_ptr;
+  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_ANDROID
+  int glob_nomatch = GLOB_NOMATCH;
+  int glob_altdirfunc = GLOB_ALTDIRFUNC;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+      (defined(__i386) || defined (__x86_64))  // NOLINT
+  unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
+  unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
+#if __WORDSIZE == 64
+  unsigned struct_user_fpxregs_struct_sz = 0;
+#else
+  unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
+#endif
+
+  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_getsiginfo = PTRACE_GETSIGINFO;
+  int ptrace_setsiginfo = 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
+#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);
+#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_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_midi_info_sz = sizeof(struct midi_info);
+  unsigned struct_mtget_sz = sizeof(struct mtget);
+  unsigned struct_mtop_sz = sizeof(struct mtop);
+  unsigned struct_mtpos_sz = sizeof(struct mtpos);
+  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_termio_sz = sizeof(struct termio);
+  unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
+  unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
+  unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
+  unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+  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_ppp_stats_sz = sizeof(struct ppp_stats);
+  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
+
+#if !SANITIZER_ANDROID
+  unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+  unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+#endif
+
+  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_ANDROID) || SANITIZER_MAC
+  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_MTIOCGET = MTIOCGET;
+  unsigned IOCTL_MTIOCPOS = MTIOCPOS;
+  unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+  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
+  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
+  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_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_ACTIVATE = VT_ACTIVATE;
+  unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
+  unsigned IOCTL_VT_GETMODE = VT_GETMODE;
+  unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
+  unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
+  unsigned IOCTL_VT_RELDISP = VT_RELDISP;
+  unsigned IOCTL_VT_RESIZE = VT_RESIZE;
+  unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
+  unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
+  unsigned IOCTL_VT_SETMODE = VT_SETMODE;
+  unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
+#endif
+#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_SCRNMAP = GIO_SCRNMAP;
+  unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP;
+  unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP;
+  unsigned IOCTL_KDADDIO = KDADDIO;
+  unsigned IOCTL_KDDELIO = KDDELIO;
+  unsigned IOCTL_KDDISABIO = KDDISABIO;
+  unsigned IOCTL_KDENABIO = KDENABIO;
+  unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE;
+  unsigned IOCTL_KDGETLED = KDGETLED;
+  unsigned IOCTL_KDGETMODE = KDGETMODE;
+  unsigned IOCTL_KDGKBDIACR = KDGKBDIACR;
+  unsigned IOCTL_KDGKBENT = KDGKBENT;
+  unsigned IOCTL_KDGKBLED = KDGKBLED;
+  unsigned IOCTL_KDGKBMETA = KDGKBMETA;
+  unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+  unsigned IOCTL_KDGKBSENT = KDGKBSENT;
+  unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+  unsigned IOCTL_KDMAPDISP = KDMAPDISP;
+  unsigned IOCTL_KDMKTONE = KDMKTONE;
+  unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE;
+  unsigned IOCTL_KDSETLED = KDSETLED;
+  unsigned IOCTL_KDSETMODE = KDSETMODE;
+  unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT;
+  unsigned IOCTL_KDSKBDIACR = KDSKBDIACR;
+  unsigned IOCTL_KDSKBENT = KDSKBENT;
+  unsigned IOCTL_KDSKBLED = KDSKBLED;
+  unsigned IOCTL_KDSKBMETA = KDSKBMETA;
+  unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+  unsigned IOCTL_KDSKBSENT = KDSKBSENT;
+  unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP;
+  unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+  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_SCRNMAP = PIO_SCRNMAP;
+  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_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+  unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
+  unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
+  unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
+  unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
+  unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
+#endif
 }  // namespace __sanitizer
 
-#endif  // __linux__ || __APPLE__
+#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))
+
+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
+// 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);
+
+COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
+#endif
+
+#if SANITIZER_LINUX && !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);
+#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);
+CHECK_TYPE_SIZE(__kernel_old_uid_t);
+CHECK_TYPE_SIZE(__kernel_old_gid_t);
+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
+
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
index dd53da94be6b7c71dca511c5e923158895b70fa3..007b4ec7b96dd15d76ba12a8fc3811a2b39d0910 100644 (file)
 #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
 #define SANITIZER_PLATFORM_LIMITS_POSIX_H
 
+#include "sanitizer_platform.h"
+
 namespace __sanitizer {
   extern unsigned struct_utsname_sz;
   extern unsigned struct_stat_sz;
   extern unsigned struct_stat64_sz;
   extern unsigned struct_rusage_sz;
   extern unsigned struct_tm_sz;
+  extern unsigned struct_passwd_sz;
+  extern unsigned struct_group_sz;
+  extern unsigned siginfo_t_sz;
+  extern unsigned struct_itimerval_sz;
+  extern unsigned pthread_t_sz;
+  extern unsigned pid_t_sz;
+  extern unsigned timeval_sz;
+  extern unsigned uid_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;
+
+#if !SANITIZER_ANDROID
+  extern unsigned ucontext_t_sz;
+#endif // !SANITIZER_ANDROID
+
+#if SANITIZER_LINUX
+  extern unsigned struct___old_kernel_stat_sz;
+  extern unsigned struct_kernel_stat_sz;
+  extern unsigned struct_kernel_stat64_sz;
+  extern unsigned struct_io_event_sz;
+  extern unsigned struct_iocb_sz;
+  extern unsigned struct_utimbuf_sz;
+  extern unsigned struct_new_utsname_sz;
+  extern unsigned struct_old_utsname_sz;
+  extern unsigned struct_oldold_utsname_sz;
+  extern unsigned struct_msqid_ds_sz;
+  extern unsigned struct_shmid_ds_sz;
+  extern unsigned struct_mq_attr_sz;
+  extern unsigned struct_perf_event_attr_sz;
+  extern unsigned struct_timex_sz;
+  extern unsigned struct_ustat_sz;
 
-#if defined(__linux__)
   extern unsigned struct_rlimit_sz;
-  extern unsigned struct_dirent_sz;
   extern unsigned struct_statfs_sz;
   extern unsigned struct_epoll_event_sz;
-#endif // __linux__
+  extern unsigned struct_sysinfo_sz;
+  extern unsigned struct_timespec_sz;
+  extern unsigned __user_cap_header_struct_sz;
+  extern unsigned __user_cap_data_struct_sz;
+  const unsigned old_sigset_t_sz = sizeof(unsigned long);
+  const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
+
+  struct __sanitizer___sysctl_args {
+    int *name;
+    int nlen;
+    void *oldval;
+    uptr *oldlenp;
+    void *newval;
+    uptr newlen;
+    unsigned long ___unused[4];
+  };
+#endif // SANITIZER_LINUX
 
-#if defined(__linux__) && !defined(__ANDROID__)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned struct_rlimit64_sz;
   extern unsigned struct_statfs64_sz;
-#endif // __linux__ && !__ANDROID__
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+  struct __sanitizer_iovec {
+    void  *iov_base;
+    uptr iov_len;
+  };
+
+#if SANITIZER_MAC
+  typedef unsigned long __sanitizer_pthread_key_t;
+#else
+  typedef unsigned __sanitizer_pthread_key_t;
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_MAC
+  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_ANDROID
+  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
+
+#if SANITIZER_LINUX
+#ifdef _LP64
+  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
+  typedef unsigned short __sanitizer___kernel_old_uid_t;
+  typedef unsigned short __sanitizer___kernel_old_gid_t;
+  typedef long __sanitizer___kernel_off_t;
+  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)];
+  };
+#endif
+
+  struct __sanitizer_sigaction {
+    union {
+      void (*sa_handler)(int sig);
+      void (*sa_sigaction)(int sig, void *siginfo, void *uctx);
+    };
+    __sanitizer_sigset_t sa_mask;
+    int sa_flags;
+#if SANITIZER_LINUX
+    void (*sa_restorer)();
+#endif
+  };
+
+  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
+  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
+    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;
+  };
 
-  void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx);
-  uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx);
-  uptr __sanitizer_get_msghdr_iovlen(void* msg);
-  uptr __sanitizer_get_socklen_t(void* socklen_ptr);
+  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
+  typedef unsigned __sanitizer_nfds_t;
+#else
+  typedef unsigned long __sanitizer_nfds_t;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  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 *);
+  };
+
+  extern int glob_nomatch;
+  extern int glob_altdirfunc;
+#endif
+
+  extern unsigned path_max;
+
+  struct __sanitizer_wordexp_t {
+    uptr we_wordc;
+    char **we_wordv;
+    uptr we_offs;
+  };
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+      (defined(__i386) || defined (__x86_64))  // NOLINT
+  extern unsigned struct_user_regs_struct_sz;
+  extern unsigned struct_user_fpregs_struct_sz;
+  extern unsigned struct_user_fpxregs_struct_sz;
+
+  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;
+#endif
+
+  // ioctl arguments
+  struct __sanitizer_ifconf {
+    int ifc_len;
+    union {
+      void *ifcu_req;
+    } ifc_ifcu;
+#if SANITIZER_MAC
+  } __attribute__((packed));
+#else
+  };
+#endif
+
+#define IOC_SIZE(nr) (((nr) >> 16) & 0x3fff)
+
+  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_copr_buffer_sz;
+  extern unsigned struct_copr_debug_buf_sz;
+  extern unsigned struct_copr_msg_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_midi_info_sz;
+  extern unsigned struct_mtget_sz;
+  extern unsigned struct_mtop_sz;
+  extern unsigned struct_mtpos_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_termio_sz;
+  extern unsigned struct_vt_consize_sz;
+  extern unsigned struct_vt_mode_sz;
+  extern unsigned struct_vt_sizes_sz;
+  extern unsigned struct_vt_stat_sz;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  extern unsigned struct_audio_buf_info_sz;
+  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_ppp_stats_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
+
+#if !SANITIZER_ANDROID
+  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 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_ANDROID) || SANITIZER_MAC
+  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_MTIOCGET;
+  extern unsigned IOCTL_MTIOCPOS;
+  extern unsigned IOCTL_MTIOCTOP;
+  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_SIOCADDRT;
+  extern unsigned IOCTL_SIOCDARP;
+  extern unsigned IOCTL_SIOCDELRT;
+  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_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_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_ACTIVATE;
+  extern unsigned IOCTL_VT_DISALLOCATE;
+  extern unsigned IOCTL_VT_GETMODE;
+  extern unsigned IOCTL_VT_GETSTATE;
+  extern unsigned IOCTL_VT_OPENQRY;
+  extern unsigned IOCTL_VT_RELDISP;
+  extern unsigned IOCTL_VT_RESIZE;
+  extern unsigned IOCTL_VT_RESIZEX;
+  extern unsigned IOCTL_VT_SENDSIG;
+  extern unsigned IOCTL_VT_SETMODE;
+  extern unsigned IOCTL_VT_WAITACTIVE;
+#endif
+#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_SCRNMAP;
+  extern unsigned IOCTL_GIO_UNIMAP;
+  extern unsigned IOCTL_GIO_UNISCRNMAP;
+  extern unsigned IOCTL_KDADDIO;
+  extern unsigned IOCTL_KDDELIO;
+  extern unsigned IOCTL_KDDISABIO;
+  extern unsigned IOCTL_KDENABIO;
+  extern unsigned IOCTL_KDGETKEYCODE;
+  extern unsigned IOCTL_KDGETLED;
+  extern unsigned IOCTL_KDGETMODE;
+  extern unsigned IOCTL_KDGKBDIACR;
+  extern unsigned IOCTL_KDGKBENT;
+  extern unsigned IOCTL_KDGKBLED;
+  extern unsigned IOCTL_KDGKBMETA;
+  extern unsigned IOCTL_KDGKBMODE;
+  extern unsigned IOCTL_KDGKBSENT;
+  extern unsigned IOCTL_KDGKBTYPE;
+  extern unsigned IOCTL_KDMAPDISP;
+  extern unsigned IOCTL_KDMKTONE;
+  extern unsigned IOCTL_KDSETKEYCODE;
+  extern unsigned IOCTL_KDSETLED;
+  extern unsigned IOCTL_KDSETMODE;
+  extern unsigned IOCTL_KDSIGACCEPT;
+  extern unsigned IOCTL_KDSKBDIACR;
+  extern unsigned IOCTL_KDSKBENT;
+  extern unsigned IOCTL_KDSKBLED;
+  extern unsigned IOCTL_KDSKBMETA;
+  extern unsigned IOCTL_KDSKBMODE;
+  extern unsigned IOCTL_KDSKBSENT;
+  extern unsigned IOCTL_KDUNMAPDISP;
+  extern unsigned IOCTL_KIOCSOUND;
+  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_SCRNMAP;
+  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
 }  // namespace __sanitizer
 
 #endif
index 1c6ff0a2ebbed04c025a9ff5291916432dbfb984..6d999e919613502f150ec92b562e3ff012e8f538 100644 (file)
@@ -9,53 +9,49 @@
 // run-time libraries and implements POSIX-specific functions from
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
 
-#include <errno.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <sys/mman.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 namespace __sanitizer {
 
 // ------------- sanitizer_common.h
-uptr GetPageSize() {
-  return sysconf(_SC_PAGESIZE);
-}
-
 uptr GetMmapGranularity() {
   return GetPageSize();
 }
 
-int GetPid() {
-  return getpid();
-}
-
-u32 GetUid() {
-  return getuid();
-}
-
-uptr GetThreadSelf() {
-  return (uptr)pthread_self();
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__powerpc64__)
+  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
+  // We somehow need to figure our 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.
+  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
+# else
+  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
+# endif
+#else  // SANITIZER_WORDSIZE == 32
+  // FIXME: We can probably lower this on Android?
+  return (1ULL << 32) - 1;  // 0xffffffff;
+#endif  // SANITIZER_WORDSIZE
 }
 
 void *MmapOrDie(uptr size, const char *mem_type) {
   size = RoundUpTo(size, GetPageSizeCached());
-  void *res = internal_mmap(0, size,
+  uptr res = internal_mmap(0, size,
                             PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANON, -1, 0);
-  if (res == (void*)-1) {
+  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.
@@ -64,18 +60,18 @@ void *MmapOrDie(uptr size, const char *mem_type) {
       Die();
     }
     recursion_count++;
-    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
-           SanitizerToolName, size, size, mem_type, strerror(errno));
+    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
+           SanitizerToolName, size, size, mem_type, reserrno);
     DumpProcessMap();
     CHECK("unable to mmap" && 0);
   }
-  return res;
+  return (void *)res;
 }
 
 void UnmapOrDie(void *addr, uptr size) {
   if (!addr || !size) return;
-  int res = internal_munmap(addr, size);
-  if (res != 0) {
+  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);
@@ -84,54 +80,53 @@ void UnmapOrDie(void *addr, uptr size) {
 
 void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
   uptr PageSize = GetPageSizeCached();
-  void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
+  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);
-  if (p == (void*)-1)
+  int reserrno;
+  if (internal_iserror(p, &reserrno))
     Report("ERROR: "
            "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           SanitizerToolName, size, size, fixed_addr, errno);
-  return p;
+           SanitizerToolName, size, size, fixed_addr, reserrno);
+  return (void *)p;
 }
 
 void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
   uptr PageSize = GetPageSizeCached();
-  void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
+  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
       RoundUpTo(size, PageSize),
       PROT_READ | PROT_WRITE,
       MAP_PRIVATE | MAP_ANON | MAP_FIXED,
       -1, 0);
-  if (p == (void*)-1) {
+  int reserrno;
+  if (internal_iserror(p, &reserrno)) {
     Report("ERROR:"
            " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           SanitizerToolName, size, size, fixed_addr, errno);
+           SanitizerToolName, size, size, fixed_addr, reserrno);
     CHECK("unable to mmap" && 0);
   }
-  return p;
+  return (void *)p;
 }
 
 void *Mprotect(uptr fixed_addr, uptr size) {
-  return internal_mmap((void*)fixed_addr, size,
-                       PROT_NONE,
-                       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
-                       -1, 0);
-}
-
-void FlushUnneededShadowMemory(uptr addr, uptr size) {
-  madvise((void*)addr, size, MADV_DONTNEED);
+  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) {
-  fd_t fd = OpenFile(file_name, false);
-  CHECK_NE(fd, kInvalidFd);
+  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());
-  void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
-  return (map == MAP_FAILED) ? 0 : map;
+  uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  return internal_iserror(map) ? 0 : (void *)map;
 }
 
 
@@ -147,10 +142,11 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
 // several worker threads on Mac, which aren't expected to map big chunks of
 // memory).
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
-  MemoryMappingLayout procmaps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   uptr start, end;
-  while (procmaps.Next(&start, &end,
-                       /*offset*/0, /*filename*/0, /*filename_size*/0)) {
+  while (proc_maps.Next(&start, &end,
+                        /*offset*/0, /*filename*/0, /*filename_size*/0,
+                        /*protection*/0)) {
     if (!IntervalsAreSeparate(start, end, range_start, range_end))
       return false;
   }
@@ -158,13 +154,13 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
 }
 
 void DumpProcessMap() {
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   uptr start, end;
   const sptr kBufSize = 4095;
   char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
   Report("Process memory map follows:\n");
   while (proc_maps.Next(&start, &end, /* file_offset */0,
-                        filename, kBufSize)) {
+                        filename, kBufSize, /* protection */0)) {
     Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
   }
   Report("End of process memory map.\n");
@@ -175,54 +171,77 @@ const char *GetPwd() {
   return GetEnv("PWD");
 }
 
-void DisableCoreDumper() {
-  struct rlimit nocore;
-  nocore.rlim_cur = 0;
-  nocore.rlim_max = 0;
-  setrlimit(RLIMIT_CORE, &nocore);
-}
-
-bool StackSizeIsUnlimited() {
-  struct rlimit rlim;
-  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
-  return (rlim.rlim_cur == (uptr)-1);
+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 SetStackSizeLimitInBytes(uptr limit) {
-  struct rlimit rlim;
-  rlim.rlim_cur = limit;
-  rlim.rlim_max = limit;
-  if (setrlimit(RLIMIT_STACK, &rlim)) {
-    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
+void MaybeOpenReportFile() {
+  if (!log_to_file || (report_fd_pid == internal_getpid())) return;
+  InternalScopedBuffer<char> report_path_full(4096);
+  internal_snprintf(report_path_full.data(), report_path_full.size(),
+                    "%s.%d", report_path_prefix, internal_getpid());
+  uptr openrv = OpenFile(report_path_full.data(), true);
+  if (internal_iserror(openrv)) {
+    report_fd = kStderrFd;
+    log_to_file = false;
+    Report("ERROR: Can't open file: %s\n", report_path_full.data());
     Die();
   }
-  CHECK(!StackSizeIsUnlimited());
-}
-
-void SleepForSeconds(int seconds) {
-  sleep(seconds);
-}
-
-void SleepForMillis(int millis) {
-  usleep(millis * 1000);
-}
-
-void Abort() {
-  abort();
+  if (report_fd != kInvalidFd) {
+    // We're in the child. Close the parent's log.
+    internal_close(report_fd);
+  }
+  report_fd = openrv;
+  report_fd_pid = internal_getpid();
 }
 
-int Atexit(void (*function)(void)) {
-#ifndef SANITIZER_GO
-  return atexit(function);
-#else
-  return 0;
-#endif
+void RawWrite(const char *buffer) {
+  static const char *kRawWriteError =
+      "RawWrite can't output requested buffer!\n";
+  uptr length = (uptr)internal_strlen(buffer);
+  MaybeOpenReportFile();
+  if (length != internal_write(report_fd, buffer, length)) {
+    internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
+    Die();
+  }
 }
 
-int internal_isatty(fd_t fd) {
-  return isatty(fd);
+bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
+  uptr s, e, off, prot;
+  InternalMmapVector<char> fn(4096);
+  fn.push_back(0);
+  MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+  while (proc_maps.Next(&s, &e, &off, &fn[0], fn.capacity(), &prot)) {
+    if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
+        && internal_strcmp(module, &fn[0]) == 0) {
+      *start = s;
+      *end = e;
+      return true;
+    }
+  }
+  return false;
 }
 
 }  // namespace __sanitizer
 
-#endif  // __linux__ || __APPLE_
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
new file mode 100644 (file)
index 0000000..3d4f92d
--- /dev/null
@@ -0,0 +1,114 @@
+//===-- sanitizer_posix_libcdep.cc ----------------------------------------===//
+//
+// 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_LINUX || SANITIZER_MAC
+#include "sanitizer_common.h"
+#include "sanitizer_stacktrace.h"
+
+#include <errno.h>
+#include <pthread.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 DisableCoreDumper() {
+  struct rlimit nocore;
+  nocore.rlim_cur = 0;
+  nocore.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &nocore);
+}
+
+bool StackSizeIsUnlimited() {
+  struct rlimit rlim;
+  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
+  return (rlim.rlim_cur == (uptr)-1);
+}
+
+void SetStackSizeLimitInBytes(uptr limit) {
+  struct rlimit rlim;
+  rlim.rlim_cur = limit;
+  rlim.rlim_max = limit;
+  if (setrlimit(RLIMIT_STACK, &rlim)) {
+    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
+    Die();
+  }
+  CHECK(!StackSizeIsUnlimited());
+}
+
+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
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+                   uptr stack_top, uptr stack_bottom, bool fast) {
+#if !SANITIZER_CAN_FAST_UNWIND
+  fast = false;
+#endif
+#if SANITIZER_MAC
+  // Always unwind fast on Mac.
+  (void)fast;
+#else
+  if (!fast)
+    return stack->SlowUnwindStack(pc, max_s);
+#endif  // SANITIZER_MAC
+  stack->size = 0;
+  stack->trace[0] = pc;
+  if (max_s > 1) {
+    stack->max_size = max_s;
+    stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
+  }
+}
+#endif  // SANITIZER_GO
+
+}  // namespace __sanitizer
+
+#endif
index 8298f12bd7b85583ca8324f94c2c2cdf3ebbfc5b..d7ce9736b247e28b041d37d2f0bd1cf2e371b809 100644 (file)
 #include <stdio.h>
 #include <stdarg.h>
 
+#if SANITIZER_WINDOWS && !defined(va_copy)
+# define va_copy(dst, src) ((dst) = (src))
+#endif
+
 namespace __sanitizer {
 
 StaticSpinMutex CommonSanitizerReportMutex;
@@ -32,45 +36,60 @@ static int AppendChar(char **buff, const char *buff_end, char c) {
 }
 
 // Appends number in a given base to buffer. If its length is less than
-// "minimal_num_length", it is padded with leading zeroes.
-static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
-                          u8 base, u8 minimal_num_length) {
+// |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];
-  uptr pos = 0;
+  int pos = 0;
   do {
-    RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
-    num_buffer[pos++] = num % base;
-    num /= base;
-  } while (num > 0);
+    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;
   }
-  int result = 0;
-  while (pos-- > 0) {
-    uptr digit = num_buffer[pos];
+  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) {
-  int result = 0;
-  if (num < 0) {
-    result += AppendChar(buff, buff_end, '-');
-    num = -num;
-    if (minimal_num_length)
-      --minimal_num_length;
-  }
-  result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length);
-  return result;
+                               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, const char *s) {
@@ -87,14 +106,14 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
   int result = 0;
   result += AppendString(buff, buff_end, "0x");
   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
-                           (SANITIZER_WORDSIZE == 64) ? 12 : 8);
+                           (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
   return result;
 }
 
 int VSNPrintf(char *buff, int buff_length,
               const char *format, va_list args) {
   static const char *kPrintfFormatsHelp =
-    "Supported Printf formats: %(0[0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
+    "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];
@@ -106,11 +125,11 @@ int VSNPrintf(char *buff, int buff_length,
       continue;
     }
     cur++;
-    bool have_width = (*cur == '0');
+    bool have_width = (*cur >= '0' && *cur <= '9');
+    bool pad_with_zero = (*cur == '0');
     int width = 0;
     if (have_width) {
       while (*cur >= '0' && *cur <= '9') {
-        have_width = true;
         width = width * 10 + *cur++ - '0';
       }
     }
@@ -126,7 +145,8 @@ int VSNPrintf(char *buff, int buff_length,
         dval = have_ll ? va_arg(args, s64)
              : have_z ? va_arg(args, sptr)
              : va_arg(args, int);
-        result += AppendSignedDecimal(&buff, buff_end, dval, width);
+        result += AppendSignedDecimal(&buff, buff_end, dval, width,
+                                      pad_with_zero);
         break;
       }
       case 'u':
@@ -135,7 +155,7 @@ int VSNPrintf(char *buff, int buff_length,
              : have_z ? va_arg(args, uptr)
              : va_arg(args, unsigned);
         result += AppendUnsigned(&buff, buff_end, uval,
-                                 (*cur == 'u') ? 10 : 16, width);
+                                 (*cur == 'u') ? 10 : 16, width, pad_with_zero);
         break;
       }
       case 'p': {
@@ -173,17 +193,86 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) {
   PrintfAndReportCallback = callback;
 }
 
-void Printf(const char *format, ...) {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+// Can be overriden in frontend.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void OnPrint(const char *str);
+#endif
+
+static void CallPrintfAndReportCallback(const char *str) {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+  if (&OnPrint != NULL)
+    OnPrint(str);
+#endif
+  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;
-  InternalScopedBuffer<char> buffer(kLen);
+  // |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);
+  CallPrintfAndReportCallback(buffer);
+  // If we had mapped any memory, clean up.
+  if (buffer != local_buffer)
+    UnmapOrDie((void *)buffer, buffer_size);
+  va_end(args2);
+}
+
+void Printf(const char *format, ...) {
   va_list args;
   va_start(args, format);
-  int needed_length = VSNPrintf(buffer.data(), kLen, format, args);
+  SharedPrintfCode(false, format, args);
+  va_end(args);
+}
+
+// Like Printf, but prints the current PID before the output string.
+void Report(const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  SharedPrintfCode(true, format, args);
   va_end(args);
-  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
-  RawWrite(buffer.data());
-  if (PrintfAndReportCallback)
-    PrintfAndReportCallback(buffer.data());
 }
 
 // Writes at most "length" symbols to "buffer" (including trailing '\0').
@@ -198,22 +287,4 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
   return needed_length;
 }
 
-// Like Printf, but prints the current PID before the output string.
-void Report(const char *format, ...) {
-  const int kLen = 16 * 1024;
-  InternalScopedBuffer<char> buffer(kLen);
-  int needed_length = internal_snprintf(buffer.data(),
-                                        kLen, "==%d== ", GetPid());
-  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
-  va_list args;
-  va_start(args, format);
-  needed_length += VSNPrintf(buffer.data() + needed_length,
-                             kLen - needed_length, format, args);
-  va_end(args);
-  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
-  RawWrite(buffer.data());
-  if (PrintfAndReportCallback)
-    PrintfAndReportCallback(buffer.data());
-}
-
 }  // namespace __sanitizer
index 400fd7a8bc4ab00d1f60515ec69be269044d94d7..87887f6b74b1257d4bf8029b8890ba7e33ec2dae 100644 (file)
 
 namespace __sanitizer {
 
-#ifdef _WIN32
+#if SANITIZER_WINDOWS
 class MemoryMappingLayout {
  public:
-  MemoryMappingLayout() {}
+  explicit MemoryMappingLayout(bool cache_enabled) {
+    (void)cache_enabled;
+  }
   bool GetObjectNameAndOffset(uptr addr, uptr *offset,
-                              char filename[], uptr filename_size) {
+                              char filename[], uptr filename_size,
+                              uptr *protection) {
     UNIMPLEMENTED();
   }
 };
 
-#else  // _WIN32
-#if defined(__linux__)
+#else  // SANITIZER_WINDOWS
+#if SANITIZER_LINUX
 struct ProcSelfMapsBuff {
   char *data;
   uptr mmaped_size;
   uptr len;
 };
-#endif  // defined(__linux__)
+#endif  // SANITIZER_LINUX
 
 class MemoryMappingLayout {
  public:
-  MemoryMappingLayout();
+  explicit MemoryMappingLayout(bool cache_enabled);
   bool Next(uptr *start, uptr *end, uptr *offset,
-            char filename[], uptr filename_size);
+            char filename[], uptr filename_size, uptr *protection);
   void Reset();
   // Gets the object file name and the offset in that object for a given
   // address 'addr'. Returns true on success.
   bool GetObjectNameAndOffset(uptr addr, uptr *offset,
-                              char filename[], uptr filename_size);
+                              char filename[], uptr filename_size,
+                              uptr *protection);
   // 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();
   ~MemoryMappingLayout();
 
+  // 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();
   // Default implementation of GetObjectNameAndOffset.
   // Quite slow, because it iterates through the whole process map for each
   // lookup.
   bool IterateForObjectNameAndOffset(uptr addr, uptr *offset,
-                                     char filename[], uptr filename_size) {
+                                     char filename[], uptr filename_size,
+                                     uptr *protection) {
     Reset();
     uptr start, end, file_offset;
-    for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size);
+    for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size,
+                         protection);
          i++) {
       if (addr >= start && addr < end) {
         // Don't subtract 'start' for the first entry:
@@ -84,17 +96,18 @@ class MemoryMappingLayout {
     return false;
   }
 
-# if defined __linux__
+# if SANITIZER_LINUX
   ProcSelfMapsBuff proc_self_maps_;
   char *current_;
 
   // Static mappings cache.
   static ProcSelfMapsBuff cached_proc_self_maps_;
   static StaticSpinMutex cache_lock_;  // protects cached_proc_self_maps_.
-# elif defined __APPLE__
+# elif SANITIZER_MAC
   template<u32 kLCSegment, typename SegmentCommand>
   bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
-                       char filename[], uptr filename_size);
+                       char filename[], uptr filename_size,
+                       uptr *protection);
   int current_image_;
   u32 current_magic_;
   u32 current_filetype_;
@@ -103,7 +116,18 @@ class MemoryMappingLayout {
 # endif
 };
 
-#endif  // _WIN32
+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);
+
+#endif  // SANITIZER_WINDOWS
 
 }  // namespace __sanitizer
 
index f3ad91a9cc21aa1a76535453acd2dc51ff3cdb67..7f567f97d7c5f58c7c135befb8690d9242e79f72 100644 (file)
@@ -145,7 +145,9 @@ class QuarantineCache {
       return 0;
     QuarantineBatch *b = list_.front();
     list_.pop_front();
-    SizeAdd(-b->size);
+    // FIXME: should probably add SizeSub method?
+    // See https://code.google.com/p/thread-sanitizer/issues/detail?id=20
+    SizeAdd(0 - b->size);
     return b;
   }
 
index cabf08e6082a302d2ef008c9648d5af362d5cd85..c6e79ad0c7c546124df5fa7416e68c166af73f9e 100644 (file)
@@ -17,6 +17,8 @@
 
 namespace __sanitizer {
 class AnsiColorDecorator {
+  // FIXME: This is not portable. It assumes the special strings are printed to
+  // stdout, which is not the case on Windows (see SetConsoleTextAttribute()).
  public:
   explicit AnsiColorDecorator(bool use_ansi_colors) : ansi_(use_ansi_colors) { }
   const char *Bold()    const { return ansi_ ? "\033[1m" : ""; }
index 2e22155fa7523bb5618e88ee23b77d9597723625..e8d9f01e7f931a276f19d048f82963d27dd9e090 100644 (file)
@@ -199,4 +199,38 @@ const uptr *StackDepotGet(u32 id, uptr *size) {
   return 0;
 }
 
+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 < kTabSize; idx++) {
+    atomic_uintptr_t *p = &depot.tab[idx];
+    uptr v = atomic_load(p, memory_order_consume);
+    StackDesc *s = (StackDesc*)(v & ~1);
+    for (; s; s = s->link) {
+      IdDescPair pair = {s->id, s};
+      map_.push_back(pair);
+    }
+  }
+  InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
+}
+
+const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) {
+  if (!map_.size()) return 0;
+  IdDescPair pair = {id, 0};
+  uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
+                                  IdDescPair::IdComparator);
+  if (idx > map_.size()) {
+    *size = 0;
+    return 0;
+  }
+  StackDesc *desc = map_[idx].desc;
+  *size = desc->size;
+  return desc->stack;
+}
+
 }  // namespace __sanitizer
index bf73cf14aad29e8ceec89d97792d3c3e2d275a0b..c2c04ef9d64b6e87d3344badc9bf0ac633087433 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef SANITIZER_STACKDEPOT_H
 #define SANITIZER_STACKDEPOT_H
 
+#include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
@@ -29,6 +30,31 @@ struct StackDepotStats {
 
 StackDepotStats *StackDepotGetStats();
 
+struct StackDesc;
+
+// 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();
+  const uptr *Get(u32 id, uptr *size);
+
+ private:
+  struct IdDescPair {
+    u32 id;
+    StackDesc *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
index e14ea447264a88da5754b802258793d7bace6a96..4e7972424dc25bf8a355d98346712f77e0cc401b 100644 (file)
@@ -18,8 +18,9 @@ namespace __sanitizer {
 const char *StripPathPrefix(const char *filepath,
                             const char *strip_file_prefix) {
   if (filepath == 0) return 0;
-  if (filepath == internal_strstr(filepath, strip_file_prefix))
-    return filepath + internal_strlen(strip_file_prefix);
+  const char *prefix_beg = internal_strstr(filepath, strip_file_prefix);
+  if (prefix_beg)
+    return prefix_beg + internal_strlen(strip_file_prefix);
   return filepath;
 }
 
@@ -62,7 +63,7 @@ static void PrintModuleAndOffset(const char *module, uptr offset,
 void StackTrace::PrintStack(const uptr *addr, uptr size,
                             bool symbolize, const char *strip_file_prefix,
                             SymbolizeCallback symbolize_callback ) {
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
   InternalScopedBuffer<AddressInfo> addr_frames(64);
   uptr frame_num = 0;
@@ -83,10 +84,10 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
         frame_num++;
       }
     }
-    if (symbolize && addr_frames_num == 0) {
+    if (symbolize && addr_frames_num == 0 && &getSymbolizer) {
       // Use our own (online) symbolizer, if necessary.
-      addr_frames_num = SymbolizeCode(pc, addr_frames.data(),
-                                      addr_frames.size());
+      addr_frames_num = getSymbolizer()->SymbolizeCode(
+          pc, addr_frames.data(), addr_frames.size());
       for (uptr j = 0; j < addr_frames_num; j++) {
         AddressInfo &info = addr_frames[j];
         PrintStackFramePrefix(frame_num, pc);
@@ -111,7 +112,8 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
       PrintStackFramePrefix(frame_num, pc);
       uptr offset;
       if (proc_maps.GetObjectNameAndOffset(pc, &offset,
-                                           buff.data(), buff.size())) {
+                                           buff.data(), buff.size(),
+                                           /* protection */0)) {
         PrintModuleAndOffset(buff.data(), offset, strip_file_prefix);
       }
       Printf("\n");
@@ -130,10 +132,12 @@ void StackTrace::FastUnwindStack(uptr pc, uptr bp,
   size = 1;
   uhwptr *frame = (uhwptr *)bp;
   uhwptr *prev_frame = frame - 1;
+  if (stack_top < 4096) return;  // Sanity check for stack top.
   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
   while (frame > prev_frame &&
          frame < (uhwptr *)stack_top - 2 &&
          frame > (uhwptr *)stack_bottom &&
+         IsAligned((uptr)frame, sizeof(*frame)) &&
          size < max_size) {
     uhwptr pc1 = frame[1];
     if (pc1 != pc) {
index fd0c4671a61fbc2c7fad702e1b25d70ae208b2d6..1f05753d20777ab49d09f12ba12a6e7c45c45b51 100644 (file)
@@ -17,6 +17,15 @@ namespace __sanitizer {
 
 static const uptr kStackTraceMax = 256;
 
+#if SANITIZER_LINUX && (defined(__arm__) || \
+    defined(__powerpc__) || defined(__powerpc64__) || \
+    defined(__sparc__) || \
+    defined(__mips__))
+#define SANITIZER_CAN_FAST_UNWIND 0
+#else
+#define SANITIZER_CAN_FAST_UNWIND 1
+#endif
+
 struct StackTrace {
   typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
                                      int out_size);
@@ -49,8 +58,10 @@ struct StackTrace {
   static uptr GetCurrentPc();
   static uptr GetPreviousInstructionPc(uptr pc);
 
+  SANITIZER_INTERFACE_ATTRIBUTE
   static uptr CompressStack(StackTrace *stack,
                             u32 *compressed, uptr size);
+  SANITIZER_INTERFACE_ATTRIBUTE
   static void UncompressStack(StackTrace *stack,
                               u32 *compressed, uptr size);
 };
@@ -59,6 +70,9 @@ struct StackTrace {
 const char *StripPathPrefix(const char *filepath,
                             const char *strip_file_prefix);
 
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+                   uptr stack_top, uptr stack_bottom, bool fast);
+
 }  // namespace __sanitizer
 
 // Use this macro if you want to print stack trace with the caller
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h b/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h
new file mode 100644 (file)
index 0000000..b1241da
--- /dev/null
@@ -0,0 +1,66 @@
+//===-- sanitizer_stoptheworld.h --------------------------------*- C++ -*-===//
+//
+// 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/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
new file mode 100644 (file)
index 0000000..4f44a03
--- /dev/null
@@ -0,0 +1,450 @@
+//===-- sanitizer_stoptheworld_linux_libcdep.cc ---------------------------===//
+//
+// 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__)
+
+#include "sanitizer_stoptheworld.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
+
+#include "sanitizer_common.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 avoid the use of libc for two reasons:
+// 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.
+//
+// We deal with this by replacing libc calls with calls to our own
+// implementations defined in sanitizer_libc.h and sanitizer_linux.h. However,
+// there are still some libc functions which are used here:
+//
+// * All of the system calls ultimately go through the libc syscall() function.
+// We're operating under the assumption that syscall()'s implementation does
+// not acquire any locks or use any thread-local data (except for the errno
+// variable, which we handle separately).
+//
+// * We lack custom implementations of sigfillset() and sigaction(), so we use
+// the libc versions instead. The same assumptions as above apply.
+//
+// * It is safe to call libc functions before the cloned thread is spawned or
+// after it has exited. The following functions are used in this manner:
+// sigdelset()
+// sigprocmask()
+
+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 thread_id) {
+  // 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(thread_id))
+    return false;
+  int pterrno;
+  if (internal_iserror(internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL),
+                       &pterrno)) {
+    // Either the thread is dead, or something prevented us from attaching.
+    // Log this event and move on.
+    Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
+    return false;
+  } else {
+    if (SanitizerVerbosity > 0)
+      Report("Attached to thread %d.\n", thread_id);
+    // The thread is not guaranteed to stop before ptrace returns, so we must
+    // wait on it.
+    uptr waitpid_status;
+    HANDLE_EINTR(waitpid_status, internal_waitpid(thread_id, NULL, __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.
+      Report("Waiting on thread %d failed, detaching (errno %d).\n", thread_id,
+             wperrno);
+      internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
+      return false;
+    }
+    suspended_threads_list_.Append(thread_id);
+    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)) {
+      if (SanitizerVerbosity > 0)
+        Report("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.
+      Report("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;
+
+// Signals that should not be blocked (this is used in the parent thread as well
+// as the tracer thread).
+static const int kUnblockedSignals[] = { 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 finished its
+  // preparations.
+  BlockingMutex mutex;
+};
+
+static DieCallbackType old_die_callback;
+
+// Signal handler to wake up suspended threads when the tracer thread dies.
+void TracerThreadSignalHandler(int signum, siginfo_t *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;
+
+  // Wait for the parent thread to finish preparations.
+  tracer_thread_argument->mutex.Lock();
+  tracer_thread_argument->mutex.Unlock();
+
+  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 fatal signals. Other signals should be blocked by
+  // the mask we inherited from the caller thread.
+  for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
+       signal_index++) {
+    struct sigaction new_sigaction;
+    internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
+    new_sigaction.sa_sigaction = TracerThreadSignalHandler;
+    new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
+    sigfillset(&new_sigaction.sa_mask);
+    sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
+  }
+
+  int exit_code = 0;
+  if (!thread_suspender.SuspendAllThreads()) {
+    Report("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;
+  }
+  thread_suspender_instance = NULL;
+  handler_stack.ss_flags = SS_DISABLE;
+  internal_sigaltstack(&handler_stack, 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_;
+};
+
+NOINLINE static void WipeStack() {
+  char arr[256];
+  internal_memset(arr, 0, sizeof(arr));
+}
+
+// We have a limitation on the stack frame size, so some stuff had to be moved
+// into globals.
+static sigset_t blocked_sigset;
+static sigset_t old_sigset;
+static struct sigaction old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
+
+class StopTheWorldScope {
+ public:
+  StopTheWorldScope() {
+    // Glibc's sigaction() has a side-effect where it copies garbage stack
+    // values into oldact, which can cause false negatives in LSan. As a quick
+    // workaround we zero some stack space here.
+    WipeStack();
+    // Block all signals that can be blocked safely, and install
+    // default handlers for the remaining signals.
+    // We cannot allow user-defined handlers to run while the ThreadSuspender
+    // thread is active, because they could conceivably call some libc functions
+    // which modify errno (which is shared between the two threads).
+    sigfillset(&blocked_sigset);
+    for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
+         signal_index++) {
+      // Remove the signal from the set of blocked signals.
+      sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
+      // Install the default handler.
+      struct sigaction new_sigaction;
+      internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
+      new_sigaction.sa_handler = SIG_DFL;
+      sigfillset(&new_sigaction.sa_mask);
+      sigaction(kUnblockedSignals[signal_index], &new_sigaction,
+                      &old_sigactions[signal_index]);
+    }
+    int sigprocmask_status =
+        sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
+    CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
+    // 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);
+    old_die_callback = GetDieCallback();
+  }
+
+  ~StopTheWorldScope() {
+    SetDieCallback(old_die_callback);
+    // Restore the dumpable flag.
+    if (!process_was_dumpable_)
+      internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+    // Restore the signal handlers.
+    for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
+         signal_index++) {
+      sigaction(kUnblockedSignals[signal_index],
+                &old_sigactions[signal_index], NULL);
+    }
+    sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
+  }
+
+ private:
+  int process_was_dumpable_;
+};
+
+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;
+  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();
+  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 */);
+  int local_errno = 0;
+  if (internal_iserror(tracer_pid, &local_errno)) {
+    Report("Failed spawning a tracer thread (errno %d).\n", local_errno);
+    tracer_thread_argument.mutex.Unlock();
+  } else {
+    // 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))
+      Report("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)) {
+    Report("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__)
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
new file mode 100644 (file)
index 0000000..d8e8976
--- /dev/null
@@ -0,0 +1,146 @@
+//===-- sanitizer_suppressions.cc -----------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code shared between TSan and LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_suppressions.h"
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+static const char *const kTypeStrings[SuppressionTypeCount] = {
+  "none", "race", "mutex", "thread", "signal", "leak"
+};
+
+bool TemplateMatch(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;
+}
+
+bool SuppressionContext::Match(const char *str, SuppressionType type,
+                               Suppression **s) {
+  can_parse_ = false;
+  uptr i;
+  for (i = 0; i < suppressions_.size(); i++)
+    if (type == suppressions_[i].type &&
+        TemplateMatch(suppressions_[i].templ, str))
+      break;
+  if (i == suppressions_.size()) return false;
+  *s = &suppressions_[i];
+  return true;
+}
+
+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 < SuppressionTypeCount; type++) {
+        const char *next_char = StripPrefix(line, kTypeStrings[type]);
+        if (next_char && *next_char == ':') {
+          line = ++next_char;
+          break;
+        }
+      }
+      if (type == SuppressionTypeCount) {
+        Printf("%s: failed to parse suppressions\n", SanitizerToolName);
+        Die();
+      }
+      Suppression s;
+      s.type = static_cast<SuppressionType>(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);
+    }
+    if (end[0] == 0)
+      break;
+    line = end + 1;
+  }
+}
+
+uptr SuppressionContext::SuppressionCount() {
+  return suppressions_.size();
+}
+
+void SuppressionContext::GetMatched(
+    InternalMmapVector<Suppression *> *matched) {
+  for (uptr i = 0; i < suppressions_.size(); i++)
+    if (suppressions_[i].hit_count)
+      matched->push_back(&suppressions_[i]);
+}
+
+const char *SuppressionTypeString(SuppressionType t) {
+  CHECK(t < SuppressionTypeCount);
+  return kTypeStrings[t];
+}
+
+}  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.h b/libsanitizer/sanitizer_common/sanitizer_suppressions.h
new file mode 100644 (file)
index 0000000..9a0d87b
--- /dev/null
@@ -0,0 +1,58 @@
+//===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code shared between TSan and LSan.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SUPPRESSIONS_H
+#define SANITIZER_SUPPRESSIONS_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+enum SuppressionType {
+  SuppressionNone,
+  SuppressionRace,
+  SuppressionMutex,
+  SuppressionThread,
+  SuppressionSignal,
+  SuppressionLeak,
+  SuppressionTypeCount
+};
+
+struct Suppression {
+  SuppressionType type;
+  char *templ;
+  unsigned hit_count;
+  uptr weight;
+};
+
+class SuppressionContext {
+ public:
+  SuppressionContext() : suppressions_(1), can_parse_(true) {}
+  void Parse(const char *str);
+  bool Match(const char* str, SuppressionType type, Suppression **s);
+  uptr SuppressionCount();
+  void GetMatched(InternalMmapVector<Suppression *> *matched);
+
+ private:
+  InternalMmapVector<Suppression> suppressions_;
+  bool can_parse_;
+
+  friend class SuppressionContextTest;
+};
+
+const char *SuppressionTypeString(SuppressionType t);
+
+// Exposed for testing.
+bool TemplateMatch(char *templ, const char *str);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SUPPRESSIONS_H
index 751806e84722f47188f03932374f215c9c70cfef..2c84773eebc1b198d67d8012212dba363c020987 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef SANITIZER_SYMBOLIZER_H
 #define SANITIZER_SYMBOLIZER_H
 
+#include "sanitizer_allocator_internal.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 // WARNING: Do not include system headers here. See details above.
@@ -40,8 +41,14 @@ struct AddressInfo {
   AddressInfo() {
     internal_memset(this, 0, sizeof(AddressInfo));
   }
+
   // Deletes all strings and sets all fields to zero.
-  void Clear();
+  void Clear() {
+    InternalFree(module);
+    InternalFree(function);
+    InternalFree(file);
+    internal_memset(this, 0, sizeof(AddressInfo));
+  }
 
   void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
                                 uptr mod_offset) {
@@ -60,52 +67,39 @@ struct DataInfo {
   uptr size;
 };
 
-// Fills at most "max_frames" elements of "frames" with descriptions
-// for a given address (in all inlined functions). Returns the number
-// of descriptions actually filled.
-// This function should NOT be called from two threads simultaneously.
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
-bool SymbolizeData(uptr address, DataInfo *info);
-
-bool IsSymbolizerAvailable();
-
-// Attempts to demangle the provided C++ mangled name.
-const char *Demangle(const char *Name);
-
-// Starts external symbolizer program in a subprocess. Sanitizer communicates
-// with external symbolizer via pipes.
-bool InitializeExternalSymbolizer(const char *path_to_symbolizer);
-
-class LoadedModule {
+class SymbolizerInterface {
  public:
-  LoadedModule(const char *module_name, uptr base_address);
-  void addAddressRange(uptr beg, uptr end);
-  bool containsAddress(uptr address) const;
-
-  const char *full_name() const { return full_name_; }
-  uptr base_address() const { return base_address_; }
-
- private:
-  struct AddressRange {
-    uptr beg;
-    uptr end;
-  };
-  char *full_name_;
-  uptr base_address_;
-  static const uptr kMaxNumberOfAddressRanges = 6;
-  AddressRange ranges_[kMaxNumberOfAddressRanges];
-  uptr n_ranges_;
+  // Fills at most "max_frames" elements of "frames" with descriptions
+  // for a given address (in all inlined functions). Returns the number
+  // of descriptions actually filled.
+  virtual uptr SymbolizeCode(uptr address, AddressInfo *frames,
+                             uptr max_frames) {
+    return 0;
+  }
+  virtual bool SymbolizeData(uptr address, DataInfo *info) {
+    return false;
+  }
+  virtual bool IsAvailable() {
+    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() {}
+  // Starts external symbolizer program in a subprocess. Sanitizer communicates
+  // with external symbolizer via pipes. If path_to_symbolizer is NULL or empty,
+  // tries to look for llvm-symbolizer in PATH.
+  virtual bool InitializeExternal(const char *path_to_symbolizer) {
+    return false;
+  }
 };
 
-// Creates external symbolizer connected via pipe, user should write
-// to output_fd and read from input_fd.
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                               int *input_fd, int *output_fd);
-
-// OS-dependent function that fills array with descriptions of at most
-// "max_modules" currently loaded modules. Returns the number of
-// initialized modules.
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules);
+// Returns platform-specific implementation of SymbolizerInterface. It can't be
+// used from multiple threads simultaneously.
+SANITIZER_WEAK_ATTRIBUTE SymbolizerInterface *getSymbolizer();
 
 }  // namespace __sanitizer
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_itanium.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_itanium.cc
deleted file mode 100644 (file)
index b356f9a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-//===-- sanitizer_symbolizer_itanium.cc -----------------------------------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between the sanitizer run-time libraries.
-// Itanium C++ ABI-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-#if defined(__APPLE__) || defined(__linux__)
-
-#include "sanitizer_symbolizer.h"
-
-#include <stdlib.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" char *__cxa_demangle(const char *mangled, char *buffer,
-                                  size_t *length, int *status)
-    SANITIZER_WEAK_ATTRIBUTE;
-}
-
-const char *__sanitizer::Demangle(const char *MangledName) {
-  // 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 =
-          __cxxabiv1::__cxa_demangle(MangledName, 0, 0, 0))
-      return Demangled;
-
-  return MangledName;
-}
-
-#endif  // __APPLE__ || __linux__
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc
deleted file mode 100644 (file)
index 01f1e45..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-//===-- sanitizer_symbolizer_linux.cc -------------------------------------===//
-//
-// 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.
-// Linux-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-#ifdef __linux__
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_symbolizer.h"
-
-#include <elf.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#if !defined(__ANDROID__) && !defined(ANDROID)
-#include <link.h>
-#endif
-
-namespace __sanitizer {
-
-static const int kSymbolizerStartupTimeMillis = 10;
-
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                               int *input_fd, int *output_fd) {
-  if (!FileExists(path_to_symbolizer)) {
-    Report("WARNING: invalid path to external symbolizer!\n");
-    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);
-
-  int pid = 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 = getdtablesize(); fd > 2; fd--)
-      internal_close(fd);
-    execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
-    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;
-}
-
-#if defined(__ANDROID__) || defined(ANDROID)
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  UNIMPLEMENTED();
-}
-#else  // ANDROID
-typedef ElfW(Phdr) Elf_Phdr;
-
-struct DlIteratePhdrData {
-  LoadedModule *modules;
-  uptr current_n;
-  uptr max_n;
-};
-
-static const uptr kMaxPathLength = 512;
-
-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;
-  InternalScopedBuffer<char> module_name(kMaxPathLength);
-  module_name.data()[0] = '\0';
-  if (data->current_n == 0) {
-    // First module is the binary itself.
-    uptr module_name_len = internal_readlink(
-        "/proc/self/exe", module_name.data(), module_name.size());
-    CHECK_NE(module_name_len, (uptr)-1);
-    CHECK_LT(module_name_len, module_name.size());
-    module_name[module_name_len] = '\0';
-  } else if (info->dlpi_name) {
-    internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
-  }
-  if (module_name.data()[0] == '\0')
-    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;
-      cur_module->addAddressRange(cur_beg, cur_end);
-    }
-  }
-  return 0;
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  CHECK(modules);
-  DlIteratePhdrData data = {modules, 0, max_modules};
-  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
-  return data.current_n;
-}
-#endif  // ANDROID
-
-}  // namespace __sanitizer
-
-#endif  // __linux__
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc
deleted file mode 100644 (file)
index a1b931b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
-//
-// 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.
-// Mac-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-#ifdef __APPLE__
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_symbolizer.h"
-
-namespace __sanitizer {
-
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                               int *input_fd, int *output_fd) {
-  UNIMPLEMENTED();
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  UNIMPLEMENTED();
-}
-
-}  // namespace __sanitizer
-
-#endif  // __APPLE__
similarity index 58%
rename from libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
rename to libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index 2c9cb2b0a55d4a2e18362a1405f265f60afc703e..34063081c77c0f50459f48fa9f8e602b3b107e75 100644 (file)
@@ -1,4 +1,4 @@
-//===-- sanitizer_symbolizer.cc -------------------------------------------===//
+//===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===//
 //
 // 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_symbolizer.h for details.
+// 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_internal_defs.h"
+#include "sanitizer_linux.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_symbolizer.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 {
 
-void AddressInfo::Clear() {
-  InternalFree(module);
-  InternalFree(function);
-  InternalFree(file);
-  internal_memset(this, 0, sizeof(AddressInfo));
+// 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;
 }
 
-LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
-  full_name_ = internal_strdup(module_name);
-  base_address_ = base_address;
-  n_ranges_ = 0;
-}
+#if defined(__x86_64__)
+static const char* const kSymbolizerArch = "--default-arch=x86_64";
+#elif defined(__i386__)
+static const char* const kSymbolizerArch = "--default-arch=i386";
+#elif defined(__powerpc64__)
+static const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#else
+static const char* const kSymbolizerArch = "--default-arch=unknown";
+#endif
+
+static const int kSymbolizerStartupTimeMillis = 10;
+
+// Creates external symbolizer connected via pipe, user should write
+// to output_fd and read from input_fd.
+static bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
+                                      int *input_fd, int *output_fd) {
+  if (!FileExists(path_to_symbolizer)) {
+    Report("WARNING: invalid path to external symbolizer!\n");
+    return false;
+  }
 
-void LoadedModule::addAddressRange(uptr beg, uptr end) {
-  CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
-  ranges_[n_ranges_].beg = beg;
-  ranges_[n_ranges_].end = end;
-  n_ranges_++;
-}
+  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);
+
+  int pid = 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 = getdtablesize(); fd > 2; fd--)
+      internal_close(fd);
+    execl(path_to_symbolizer, path_to_symbolizer, kSymbolizerArch, (char*)0);
+    internal__exit(1);
+  }
 
-bool LoadedModule::containsAddress(uptr address) const {
-  for (uptr i = 0; i < n_ranges_; i++) {
-    if (ranges_[i].beg <= address && address < ranges_[i].end)
-      return true;
+  // 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 false;
+
+  return true;
 }
 
 // Extracts the prefix of "str" that consists of any characters not
@@ -109,7 +217,7 @@ class ExternalSymbolizer {
 
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
     CHECK(module_name);
-    internal_snprintf(buffer_, kBufferSize, "%s%s 0x%zx\n",
+    internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
                       is_data ? "DATA " : "", module_name, module_offset);
     if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
       return 0;
@@ -126,6 +234,9 @@ class ExternalSymbolizer {
     return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
   }
 
+  void Flush() {
+  }
+
  private:
   bool readFromSymbolizer(char *buffer, uptr max_length) {
     if (max_length == 0)
@@ -176,17 +287,23 @@ static LowLevelAllocator symbolizer_allocator;  // Linker initialized.
 
 #if SANITIZER_SUPPORTS_WEAK_HOOKS
 extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
                                 char *Buffer, int MaxLength);
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+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() {
     if (__sanitizer_symbolize_code != 0 &&
         __sanitizer_symbolize_data != 0) {
@@ -195,6 +312,7 @@ class 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;
@@ -203,10 +321,34 @@ class InternalSymbolizer {
     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
@@ -217,11 +359,15 @@ class InternalSymbolizer {
   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 Symbolizer {
+class Symbolizer : public SymbolizerInterface {
+  // This class has no constructor, as global constructors are forbidden in
+  // sanitizer_common. It should be linker initialized instead.
  public:
   uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
     if (max_frames == 0)
@@ -303,7 +449,12 @@ class Symbolizer {
     return true;
   }
 
-  bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
+  bool InitializeExternal(const char *path_to_symbolizer) {
+    if (!path_to_symbolizer || path_to_symbolizer[0] == '\0') {
+      path_to_symbolizer = FindPathToBinary("llvm-symbolizer");
+      if (!path_to_symbolizer)
+        return false;
+    }
     int input_fd, output_fd;
     if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
       return false;
@@ -313,17 +464,37 @@ class Symbolizer {
     return true;
   }
 
-  bool IsSymbolizerAvailable() {
+  bool IsAvailable() {
     if (internal_symbolizer_ == 0)
       internal_symbolizer_ = InternalSymbolizer::get();
     return internal_symbolizer_ || external_symbolizer_;
   }
 
+  void Flush() {
+    if (internal_symbolizer_)
+      internal_symbolizer_->Flush();
+    if (external_symbolizer_)
+      external_symbolizer_->Flush();
+  }
+
+  const char *Demangle(const char *name) {
+    if (IsAvailable() && internal_symbolizer_ != 0)
+      return internal_symbolizer_->Demangle(name);
+    return DemangleCXXABI(name);
+  }
+
+  void PrepareForSandboxing() {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+    // Cache /proc/self/exe on Linux.
+    CacheBinaryName();
+#endif
+  }
+
  private:
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
     // First, try to use internal symbolizer.
-    if (internal_symbolizer_ == 0) {
-      internal_symbolizer_ = InternalSymbolizer::get();
+    if (!IsAvailable()) {
+      return 0;
     }
     if (internal_symbolizer_) {
       return internal_symbolizer_->SendCommand(is_data, module_name,
@@ -353,21 +524,35 @@ class Symbolizer {
   }
 
   LoadedModule *FindModuleForAddress(uptr address) {
-    if (modules_ == 0) {
+    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);
-      CHECK_GT(n_modules_, 0);
+      n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
+                                    /* filter */ 0);
+      // FIXME: Return this check when GetListOfModules is implemented on Mac.
+      // 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;
   }
+
   void ReportExternalSymbolizerError(const char *msg) {
     // Don't use atomics here for now, as SymbolizeCode can't be called
     // from multiple threads anyway.
@@ -382,27 +567,29 @@ class Symbolizer {
   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_;
 
   ExternalSymbolizer *external_symbolizer_;  // Leaked.
   InternalSymbolizer *internal_symbolizer_;  // Leaked.
 };
 
-static Symbolizer symbolizer;  // Linker initialized.
-
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
-  return symbolizer.SymbolizeCode(address, frames, max_frames);
-}
-
-bool SymbolizeData(uptr address, DataInfo *info) {
-  return symbolizer.SymbolizeData(address, info);
-}
-
-bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
-  return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
-}
-
-bool IsSymbolizerAvailable() {
-  return symbolizer.IsSymbolizerAvailable();
+static ALIGNED(64) char symbolizer_placeholder[sizeof(Symbolizer)];
+static Symbolizer *symbolizer;
+
+SymbolizerInterface *getSymbolizer() {
+  static atomic_uint8_t initialized;
+  static StaticSpinMutex init_mu;
+  if (atomic_load(&initialized, memory_order_acquire) == 0) {
+    SpinMutexLock l(&init_mu);
+    if (atomic_load(&initialized, memory_order_relaxed) == 0) {
+      symbolizer = new(symbolizer_placeholder) Symbolizer();
+      atomic_store(&initialized, 1, memory_order_release);
+    }
+  }
+  return symbolizer;
 }
 
 }  // namespace __sanitizer
+
+#endif  // SANITIZER_POSIX
index ad0053234f06def454a8fecefeaef9aaa61b7637..44801f39b313e1fe70f7c4248a66687c54d55993 100644 (file)
@@ -9,25 +9,18 @@
 // run-time libraries.
 // Windows-specific implementation of symbolizer parts.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
-#include <windows.h>
 
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                               int *input_fd, int *output_fd) {
-  UNIMPLEMENTED();
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  UNIMPLEMENTED();
-};
+static SymbolizerInterface win_symbolizer;  // Linker initialized.
 
-const char *Demangle(const char *MangledName) {
-  return MangledName;
+SymbolizerInterface *getSymbolizer() {
+  return &win_symbolizer;
 }
 
 }  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc b/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc
new file mode 100644 (file)
index 0000000..6b2c915
--- /dev/null
@@ -0,0 +1,22 @@
+//===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define internal_syscall syscall
+
+bool internal_iserror(uptr retval, int *rverrno) {
+  if (retval == (uptr)-1) {
+    if (rverrno)
+      *rverrno = errno;
+    return true;
+  } else {
+    return false;
+  }
+}
diff --git a/libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
new file mode 100644 (file)
index 0000000..4f405d9
--- /dev/null
@@ -0,0 +1,85 @@
+//===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+static uptr internal_syscall(u64 nr) {
+  u64 retval;
+  asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11");
+  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");
+  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");
+  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");
+  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");
+  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");
+  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");
+  return retval;
+}
+
+bool internal_iserror(uptr retval, int *rverrno) {
+  if (retval >= (uptr)-4095) {
+    if (rverrno)
+      *rverrno = -retval;
+    return true;
+  }
+  return false;
+}
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
new file mode 100644 (file)
index 0000000..e639430
--- /dev/null
@@ -0,0 +1,277 @@
+//===-- sanitizer_thread_registry.cc --------------------------------------===//
+//
+// 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), os_id(0), user_id(0), status(ThreadStatusInvalid),
+      detached(false), reuse_count(0), 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;
+  reuse_count++;
+  SetName(0);
+  OnReset();
+}
+
+// ThreadRegistry implementation.
+
+const u32 ThreadRegistry::kUnknownTid = ~0U;
+
+ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
+                               u32 thread_quarantine_size)
+    : context_factory_(factory),
+      max_threads_(max_threads),
+      thread_quarantine_size_(thread_quarantine_size),
+      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 {
+    Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
+           SanitizerToolName, max_threads_);
+    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::DetachThread(u32 tid) {
+  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;
+  }
+  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();
+  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/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
new file mode 100644 (file)
index 0000000..1ae47b8
--- /dev/null
@@ -0,0 +1,142 @@
+//===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===//
+//
+// 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.
+  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;
+  int reuse_count;
+
+  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() {}
+};
+
+typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
+
+class ThreadRegistry {
+ public:
+  static const u32 kUnknownTid;
+
+  ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
+                 u32 thread_quarantine_size);
+  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 DetachThread(u32 tid);
+  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_;
+
+  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
index 695265594b3cd353ffdc38a53fccb7a90d3a99d0..0a5fe81ae454fa472700934bcfc174b8c83b4a09 100644 (file)
@@ -9,7 +9,10 @@
 // run-time libraries and implements windows-specific functions from
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
 #define WIN32_LEAN_AND_MEAN
 #define NOGDI
 #include <stdlib.h>
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
-#include "sanitizer_placement_new.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?
@@ -32,18 +38,30 @@ 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();
 }
 
-int GetPid() {
+uptr internal_getpid() {
   return GetProcessId(GetCurrentProcess());
 }
 
-uptr GetThreadSelf() {
+// In contrast to POSIX, on Windows GetCurrentThreadId()
+// returns a system-unique identifier.
+uptr GetTid() {
   return GetCurrentThreadId();
 }
 
+uptr GetThreadSelf() {
+  return GetTid();
+}
+
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                 uptr *stack_bottom) {
   CHECK(stack_top);
@@ -109,19 +127,38 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
   UNIMPLEMENTED();
 }
 
-const char *GetEnv(const char *name) {
-  static char env_buffer[32767] = {};
+static const int kMaxEnvNameLength = 128;
+static const DWORD kMaxEnvValueLength = 32767;
 
-  // Note: this implementation stores the result in a static buffer so we only
-  // allow it to be called just once.
-  static bool called_once = false;
-  if (called_once)
-    UNIMPLEMENTED();
-  called_once = true;
+namespace {
+
+struct EnvVariable {
+  char name[kMaxEnvNameLength];
+  char value[kMaxEnvValueLength];
+};
 
-  DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer));
-  if (rv > 0 && rv < sizeof(env_buffer))
-    return env_buffer;
+}  // 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;
 }
 
@@ -157,6 +194,11 @@ void SetStackSizeLimitInBytes(uptr limit) {
   UNIMPLEMENTED();
 }
 
+char *FindPathToBinary(const char *name) {
+  // Nothing here for now.
+  return 0;
+}
+
 void SleepForSeconds(int seconds) {
   Sleep(seconds * 1000);
 }
@@ -165,11 +207,20 @@ void SleepForMillis(int millis) {
   Sleep(millis);
 }
 
+u64 NanoTime() {
+  return 0;
+}
+
 void Abort() {
   abort();
   _exit(-1);  // abort is not NORETURN on Windows.
 }
 
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+                      string_predicate_t filter) {
+  UNIMPLEMENTED();
+};
+
 #ifndef SANITIZER_GO
 int Atexit(void (*function)(void)) {
   return atexit(function);
@@ -177,16 +228,16 @@ int Atexit(void (*function)(void)) {
 #endif
 
 // ------------------ sanitizer_libc.h
-void *internal_mmap(void *addr, uptr length, int prot, int flags,
-                    int fd, u64 offset) {
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+                   int fd, u64 offset) {
   UNIMPLEMENTED();
 }
 
-int internal_munmap(void *addr, uptr length) {
+uptr internal_munmap(void *addr, uptr length) {
   UNIMPLEMENTED();
 }
 
-int internal_close(fd_t fd) {
+uptr internal_close(fd_t fd) {
   UNIMPLEMENTED();
 }
 
@@ -194,15 +245,15 @@ int internal_isatty(fd_t fd) {
   return _isatty(fd);
 }
 
-fd_t internal_open(const char *filename, int flags) {
+uptr internal_open(const char *filename, int flags) {
   UNIMPLEMENTED();
 }
 
-fd_t internal_open(const char *filename, int flags, u32 mode) {
+uptr internal_open(const char *filename, int flags, u32 mode) {
   UNIMPLEMENTED();
 }
 
-fd_t OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, bool write) {
   UNIMPLEMENTED();
 }
 
@@ -222,15 +273,15 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
   return ret;
 }
 
-int internal_stat(const char *path, void *buf) {
+uptr internal_stat(const char *path, void *buf) {
   UNIMPLEMENTED();
 }
 
-int internal_lstat(const char *path, void *buf) {
+uptr internal_lstat(const char *path, void *buf) {
   UNIMPLEMENTED();
 }
 
-int internal_fstat(fd_t fd, void *buf) {
+uptr internal_fstat(fd_t fd, void *buf) {
   UNIMPLEMENTED();
 }
 
@@ -238,7 +289,7 @@ uptr internal_filesize(fd_t fd) {
   UNIMPLEMENTED();
 }
 
-int internal_dup2(int oldfd, int newfd) {
+uptr internal_dup2(int oldfd, int newfd) {
   UNIMPLEMENTED();
 }
 
@@ -246,7 +297,7 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
   UNIMPLEMENTED();
 }
 
-int internal_sched_yield() {
+uptr internal_sched_yield() {
   Sleep(0);
   return 0;
 }
@@ -268,6 +319,12 @@ BlockingMutex::BlockingMutex(LinkerInitialized li) {
   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?!?
@@ -289,6 +346,79 @@ void BlockingMutex::Unlock() {
   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
+}
+
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+                   uptr stack_top, uptr stack_bottom, bool fast) {
+  (void)fast;
+  (void)stack_top;
+  (void)stack_bottom;
+  stack->max_size = max_s;
+  void *tmp[kStackTraceMax];
+
+  // FIXME: CaptureStackBackTrace might be too slow for us.
+  // FIXME: Compare with StackWalk64.
+  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
+  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
+  uptr offset = 0;
+  // Skip the RTL frames by searching for the PC in the stacktrace.
+  // FIXME: this doesn't work well for the malloc/free stacks yet.
+  for (uptr i = 0; i < cs_ret; i++) {
+    if (pc != (uptr)tmp[i])
+      continue;
+    offset = i;
+    break;
+  }
+
+  stack->size = cs_ret - offset;
+  for (uptr i = 0; i < stack->size; i++)
+    stack->trace[i] = (uptr)tmp[i + offset];
+}
+
+void MaybeOpenReportFile() {
+  // Windows doesn't have native fork, and we don't support Cygwin or other
+  // environments that try to fake it, so the initial report_fd will always be
+  // correct.
+}
+
+void RawWrite(const char *buffer) {
+  static const char *kRawWriteError =
+      "RawWrite can't output requested buffer!\n";
+  uptr length = (uptr)internal_strlen(buffer);
+  if (length != internal_write(report_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);
+  }
+}
+
 }  // namespace __sanitizer
 
 #endif  // _WIN32
index b2937a428f3d27a24722fd746e8b553e2ec034c6..68936e02e4b174ef61c9c477c11e538e38ca6a19 100644 (file)
@@ -154,7 +154,6 @@ struct MD5Hash {
 MD5Hash md5_hash(const void *data, uptr size);
 
 struct ThreadState;
-struct ThreadContext;
 struct Context;
 struct ReportStack;
 class ReportDesc;
index a75d9bde08ade9801b12cf80426a02aebe23d8cc..de852b185a6d6d45163722f5fff0bae77b23edd8 100644 (file)
@@ -72,13 +72,14 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
   uptr l1 = atomic_load(pl1, memory_order_consume);
   if (l1 == 0) {
     uptr size = kTableSizeL2 * sizeof(FdDesc);
-    void *p = internal_alloc(MBlockFD, size);
+    // We need this to reside in user memory to properly catch races on it.
+    void *p = user_alloc(thr, pc, size);
     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
-      internal_free(p);
+      user_free(thr, pc, p);
   }
   return &((FdDesc*)l1)[fd % kTableSizeL2];  // NOLINT
 }
@@ -157,9 +158,9 @@ void FdRelease(ThreadState *thr, uptr pc, int fd) {
   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);
-  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
 }
 
 void FdAccess(ThreadState *thr, uptr pc, int fd) {
index ae748a13e150d5dd69a2eb73b6661142974331f5..dbde4212c59de212b75267c4e7c17cd26eb06a28 100644 (file)
@@ -47,17 +47,22 @@ void InitializeFlags(Flags *f, const char *env) {
   f->force_seq_cst_atomics = false;
   f->strip_path_prefix = "";
   f->suppressions = "";
+  f->print_suppressions = false;
+  f->print_benign = false;
   f->exitcode = 66;
+  f->halt_on_error = false;
   f->log_path = "stderr";
   f->atexit_sleep_ms = 1000;
   f->verbosity = 0;
   f->profile_memory = "";
   f->flush_memory_ms = 0;
+  f->flush_symbolizer_ms = 5000;
   f->stop_on_start = false;
   f->running_on_valgrind = false;
   f->external_symbolizer_path = "";
   f->history_size = kGoMode ? 1 : 2;  // There are a lot of goroutines in Go.
   f->io_sync = 1;
+  f->allocator_may_return_null = false;
 
   // Let a frontend override.
   OverrideFlags(f);
@@ -75,16 +80,21 @@ void InitializeFlags(Flags *f, const char *env) {
   ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics");
   ParseFlag(env, &f->strip_path_prefix, "strip_path_prefix");
   ParseFlag(env, &f->suppressions, "suppressions");
+  ParseFlag(env, &f->print_suppressions, "print_suppressions");
+  ParseFlag(env, &f->print_benign, "print_benign");
   ParseFlag(env, &f->exitcode, "exitcode");
+  ParseFlag(env, &f->halt_on_error, "halt_on_error");
   ParseFlag(env, &f->log_path, "log_path");
   ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
   ParseFlag(env, &f->verbosity, "verbosity");
   ParseFlag(env, &f->profile_memory, "profile_memory");
   ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms");
+  ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms");
   ParseFlag(env, &f->stop_on_start, "stop_on_start");
   ParseFlag(env, &f->external_symbolizer_path, "external_symbolizer_path");
   ParseFlag(env, &f->history_size, "history_size");
   ParseFlag(env, &f->io_sync, "io_sync");
+  ParseFlag(env, &f->allocator_may_return_null, "allocator_may_return_null");
 
   if (!f->report_bugs) {
     f->report_thread_leaks = false;
@@ -103,6 +113,8 @@ void InitializeFlags(Flags *f, const char *env) {
            " (must be [0..2])\n");
     Die();
   }
+
+  common_flags()->allocator_may_return_null = f->allocator_may_return_null;
 }
 
 }  // namespace __tsan
index 480b41538f941ef57bf706bcb6af4ff4dc610539..a7571c92b5e0e6b31df6a5e7f518ef9a2ae91dcb 100644 (file)
@@ -50,8 +50,14 @@ struct Flags {
   const char *strip_path_prefix;
   // Suppressions filename.
   const char *suppressions;
+  // Print matched suppressions at exit.
+  bool print_suppressions;
+  // Print matched "benign" races at exit.
+  bool print_benign;
   // Override exit status if something was reported.
   int exitcode;
+  // Exit after first reported error.
+  bool halt_on_error;
   // Write logs to "log_path.pid".
   // The special values are "stdout" and "stderr".
   // The default is "stderr".
@@ -65,6 +71,8 @@ struct Flags {
   const char *profile_memory;
   // Flush shadow memory every X ms.
   int flush_memory_ms;
+  // Flush symbolizer caches every X ms.
+  int flush_symbolizer_ms;
   // Stops on start until __tsan_resume() is called (for debugging).
   bool stop_on_start;
   // Controls whether RunningOnValgrind() returns true or false.
@@ -82,6 +90,8 @@ struct Flags {
   // 1 - reasonable level of synchronization (write->read)
   // 2 - global synchronization of all IO operations
   int io_sync;
+  // If false, the allocator will crash instead of returning 0 on out-of-memory.
+  bool allocator_may_return_null;
 };
 
 Flags *flags();
index 8a54511b6e076583a246ade590818210acec6720..eaaf9e3ebf600279334f7874b17cfed757bde73d 100644 (file)
@@ -8,11 +8,13 @@
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
 // FIXME: move as many interceptors as possible into
-// sanitizer_common/sanitizer_common_interceptors.h
+// 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"
 
 using namespace __tsan;  // NOLINT
 
-const int kSigCount = 128;
+const int kSigCount = 64;
 
 struct my_siginfo_t {
-  int opaque[128];
-};
-
-struct sigset_t {
-  u64 val[1024 / 8 / sizeof(u64)];
+  // The size is determined by looking at sizeof of real siginfo_t on linux.
+  u64 opaque[128 / sizeof(u64)];
 };
 
 struct ucontext_t {
-  uptr opaque[117];
+  // The size is determined by looking at sizeof of real ucontext_t on linux.
+  u64 opaque[936 / sizeof(u64) + 1];
 };
 
 extern "C" int pthread_attr_init(void *attr);
@@ -47,8 +47,10 @@ extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
 extern "C" int pthread_setspecific(unsigned key, const void *v);
 extern "C" int pthread_mutexattr_gettype(void *a, int *type);
 extern "C" int pthread_yield();
-extern "C" int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
-extern "C" int sigfillset(sigset_t *set);
+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)
 extern "C" void *pthread_self();
 extern "C" void _exit(int status);
 extern "C" int *__errno_location();
@@ -57,9 +59,9 @@ 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 mallopt(int param, int value);
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
-const int kPthreadAttrSize = 56;
 const int EINVAL = 22;
 const int EBUSY = 16;
 const int EPOLL_CTL_ADD = 1;
@@ -69,6 +71,7 @@ const int SIGFPE = 8;
 const int SIGSEGV = 11;
 const int SIGPIPE = 13;
 const int SIGBUS = 7;
+const int SIGSYS = 31;
 void *const MAP_FAILED = (void*)-1;
 const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
 const int MAP_FIXED = 0x10;
@@ -84,17 +87,12 @@ typedef void (*sighandler_t)(int sig);
 
 #define errno (*__errno_location())
 
-union pthread_attr_t {
-  char size[kPthreadAttrSize];
-  void *align;
-};
-
 struct sigaction_t {
   union {
     sighandler_t sa_handler;
     void (*sa_sigaction)(int sig, my_siginfo_t *siginfo, void *uctx);
   };
-  sigset_t sa_mask;
+  __sanitizer_sigset_t sa_mask;
   int sa_flags;
   void (*sa_restorer)();
 };
@@ -125,6 +123,21 @@ struct SignalContext {
   int pending_signal_count;
   SignalDesc pending_signals[kSigCount];
 };
+
+// Used to ignore interceptors coming directly from libjvm.so.
+atomic_uintptr_t libjvm_begin;
+atomic_uintptr_t libjvm_end;
+
+static bool libjvm_check(uptr pc) {
+  uptr begin = atomic_load(&libjvm_begin, memory_order_relaxed);
+  if (begin != 0 && pc >= begin) {
+    uptr end = atomic_load(&libjvm_end, memory_order_relaxed);
+    if (end != 0 && pc < end)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace __tsan
 
 static SignalContext *SigCtx(ThreadState *thr) {
@@ -178,8 +191,7 @@ ScopedInterceptor::~ScopedInterceptor() {
     StatInc(thr, StatInt_##func); \
     const uptr caller_pc = GET_CALLER_PC(); \
     ScopedInterceptor si(thr, #func, caller_pc); \
-    const uptr pc = __sanitizer::StackTrace::GetPreviousInstructionPc( \
-        __sanitizer::StackTrace::GetCurrentPc()); \
+    const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
     (void)pc; \
 /**/
 
@@ -189,7 +201,7 @@ ScopedInterceptor::~ScopedInterceptor() {
       Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
       Die(); \
     } \
-    if (thr->in_rtl > 1) \
+    if (thr->in_rtl > 1 || libjvm_check(pc)) \
       return REAL(func)(__VA_ARGS__); \
 /**/
 
@@ -293,15 +305,6 @@ class AtExitContext {
 
 static AtExitContext *atexit_ctx;
 
-static void finalize(void *arg) {
-  ThreadState * thr = cur_thread();
-  uptr pc = 0;
-  atexit_ctx->exit(thr, pc);
-  int status = Finalize(cur_thread());
-  if (status)
-    _exit(status);
-}
-
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
   if (cur_thread()->in_symbolizer)
     return 0;
@@ -320,25 +323,123 @@ 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);
-  if (dso)
-    return REAL(__cxa_atexit)(f, arg, dso);
+  if (dso) {
+    // Memory allocation in __cxa_atexit will race with free during exit,
+    // because we do not see synchronization around atexit callback list.
+    ThreadIgnoreBegin(thr);
+    int res = REAL(__cxa_atexit)(f, arg, dso);
+    ThreadIgnoreEnd(thr);
+    return res;
+  }
   return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
 }
 
-TSAN_INTERCEPTOR(void, longjmp, void *env, int val) {
-  SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
-  Printf("ThreadSanitizer: longjmp() is not supported\n");
-  Die();
+// 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--;
+    }
+  }
 }
 
-TSAN_INTERCEPTOR(void, siglongjmp, void *env, int val) {
-  SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
-  Printf("ThreadSanitizer: siglongjmp() is not supported\n");
-  Die();
+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;
+}
+
+static void LongJmp(ThreadState *thr, uptr *env) {
+  uptr mangled_sp = env[6];
+  // 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);
+      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) {
+  ScopedInRtl in_rtl;
+  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)
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
     return __libc_malloc(size);
   void *p = 0;
   {
@@ -355,21 +456,23 @@ TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
 }
 
 TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
-  if (cur_thread()->in_symbolizer)
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
     return __libc_calloc(size, n);
-  if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n)) return 0;
+  if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n))
+    return AllocatorReturnNull();
   void *p = 0;
   {
     SCOPED_INTERCEPTOR_RAW(calloc, size, n);
     p = user_alloc(thr, pc, n * size);
-    if (p) internal_memset(p, 0, n * size);
+    if (p)
+      internal_memset(p, 0, n * size);
   }
   invoke_malloc_hook(p, n * size);
   return p;
 }
 
 TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
-  if (cur_thread()->in_symbolizer)
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
     return __libc_realloc(p, size);
   if (p)
     invoke_free_hook(p);
@@ -384,7 +487,7 @@ TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
 TSAN_INTERCEPTOR(void, free, void *p) {
   if (p == 0)
     return;
-  if (cur_thread()->in_symbolizer)
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
     return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(free, p);
@@ -394,15 +497,22 @@ TSAN_INTERCEPTOR(void, free, void *p) {
 TSAN_INTERCEPTOR(void, cfree, void *p) {
   if (p == 0)
     return;
-  if (cur_thread()->in_symbolizer)
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
     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);
+  if (libjvm_check(pc))
+    return malloc_usable_size(p);
+  return user_alloc_usable_size(thr, pc, p);
+}
+
 #define OPERATOR_NEW_BODY(mangled_name) \
-  if (cur_thread()->in_symbolizer) \
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \
     return __libc_malloc(size); \
   void *p = 0; \
   {  \
@@ -412,36 +522,58 @@ TSAN_INTERCEPTOR(void, cfree, void *p) {
   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) \
+  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \
     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);
 void operator delete(void *ptr) {
   OPERATOR_DELETE_BODY(_ZdlPv);
 }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete[](void *ptr);
 void operator delete[](void *ptr) {
   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(_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(_ZdaPvRKSt9nothrow_t);
 }
@@ -479,30 +611,6 @@ TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) {
   return res;
 }
 
-TSAN_INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
-  SCOPED_TSAN_INTERCEPTOR(strcmp, s1, s2);
-  uptr len = 0;
-  for (; s1[len] && s2[len]; len++) {
-    if (s1[len] != s2[len])
-      break;
-  }
-  MemoryAccessRange(thr, pc, (uptr)s1, len + 1, false);
-  MemoryAccessRange(thr, pc, (uptr)s2, len + 1, false);
-  return s1[len] - s2[len];
-}
-
-TSAN_INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr n) {
-  SCOPED_TSAN_INTERCEPTOR(strncmp, s1, s2, n);
-  uptr len = 0;
-  for (; len < n && s1[len] && s2[len]; len++) {
-    if (s1[len] != 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 len == n ? 0 : s1[len] - s2[len];
-}
-
 TSAN_INTERCEPTOR(void*, memchr, void *s, int c, uptr n) {
   SCOPED_TSAN_INTERCEPTOR(memchr, s, c, n);
   void *res = REAL(memchr)(s, c, n);
@@ -572,6 +680,21 @@ TSAN_INTERCEPTOR(const char*, strstr, const char *s1, const char *s2) {
   return res;
 }
 
+TSAN_INTERCEPTOR(char*, strdup, const char *str) {
+  SCOPED_TSAN_INTERCEPTOR(strdup, str);
+  if (libjvm_check(pc)) {
+    // The memory must come from libc malloc,
+    // and we must not instrument accesses in this case.
+    uptr n = internal_strlen(str) + 1;
+    void *p = __libc_malloc(n);
+    if (p == 0)
+      return 0;
+    return (char*)internal_memcpy(p, str, n);
+  }
+  // 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)) {
@@ -595,7 +718,7 @@ TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
   if (res != MAP_FAILED) {
     if (fd > 0)
       FdAccess(thr, pc, fd);
-    MemoryResetRange(thr, pc, (uptr)res, sz);
+    MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
   }
   return res;
 }
@@ -609,13 +732,14 @@ TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
   if (res != MAP_FAILED) {
     if (fd > 0)
       FdAccess(thr, pc, fd);
-    MemoryResetRange(thr, pc, (uptr)res, sz);
+    MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
   }
   return res;
 }
 
 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;
 }
@@ -727,21 +851,21 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
 TSAN_INTERCEPTOR(int, pthread_create,
     void *th, void *attr, void *(*callback)(void*), void * param) {
   SCOPED_TSAN_INTERCEPTOR(pthread_create, th, attr, callback, param);
-  pthread_attr_t myattr;
+  __sanitizer_pthread_attr_t myattr;
   if (attr == 0) {
     pthread_attr_init(&myattr);
     attr = &myattr;
   }
   int detached = 0;
   pthread_attr_getdetachstate(attr, &detached);
-  uptr stacksize = 0;
-  pthread_attr_getstacksize(attr, &stacksize);
-  // We place the huge ThreadState object into TLS, account for that.
-  const uptr minstacksize = GetTlsSize() + 128*1024;
-  if (stacksize < minstacksize) {
-    DPrintf("ThreadSanitizer: stacksize %zu->%zu\n", stacksize, minstacksize);
-    pthread_attr_setstacksize(attr, minstacksize);
-  }
+
+#if defined(TSAN_DEBUG_OUTPUT)
+  int verbosity = (TSAN_DEBUG_OUTPUT);
+#else
+  int verbosity = 0;
+#endif
+  AdjustStackSizeLinux(attr, verbosity);
+
   ThreadParam p;
   p.callback = callback;
   p.param = param;
@@ -960,30 +1084,30 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
   return res;
 }
 
-// libpthread.so contains several versions of pthread_cond_init symbol.
-// When we just dlsym() it, we get the wrong (old) version.
-/*
 TSAN_INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, c, a);
+  MemoryWrite(thr, pc, (uptr)c, kSizeLog1);
   int res = REAL(pthread_cond_init)(c, a);
   return res;
 }
-*/
 
 TSAN_INTERCEPTOR(int, pthread_cond_destroy, void *c) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, c);
+  MemoryWrite(thr, pc, (uptr)c, kSizeLog1);
   int res = REAL(pthread_cond_destroy)(c);
   return res;
 }
 
 TSAN_INTERCEPTOR(int, pthread_cond_signal, void *c) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, c);
+  MemoryRead(thr, pc, (uptr)c, kSizeLog1);
   int res = REAL(pthread_cond_signal)(c);
   return res;
 }
 
 TSAN_INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, c);
+  MemoryRead(thr, pc, (uptr)c, kSizeLog1);
   int res = REAL(pthread_cond_broadcast)(c);
   return res;
 }
@@ -991,14 +1115,17 @@ TSAN_INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
 TSAN_INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, c, m);
   MutexUnlock(thr, pc, (uptr)m);
+  MemoryRead(thr, pc, (uptr)c, kSizeLog1);
   int res = REAL(pthread_cond_wait)(c, m);
   MutexLock(thr, pc, (uptr)m);
   return res;
 }
 
-TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
+TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m,
+    void *abstime) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, c, m, abstime);
   MutexUnlock(thr, pc, (uptr)m);
+  MemoryRead(thr, pc, (uptr)c, kSizeLog1);
   int res = REAL(pthread_cond_timedwait)(c, m, abstime);
   MutexLock(thr, pc, (uptr)m);
   return res;
@@ -1309,22 +1436,6 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
   return res;
 }
 
-TSAN_INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
-  SCOPED_TSAN_INTERCEPTOR(accept, fd, addr, addrlen);
-  int fd2 = REAL(accept)(fd, addr, addrlen);
-  if (fd >= 0 && fd2 >= 0)
-    FdSocketAccept(thr, pc, fd, fd2);
-  return fd2;
-}
-
-TSAN_INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
-  SCOPED_TSAN_INTERCEPTOR(accept4, fd, addr, addrlen, f);
-  int fd2 = REAL(accept4)(fd, addr, addrlen, f);
-  if (fd >= 0 && fd2 >= 0)
-    FdSocketAccept(thr, pc, fd, fd2);
-  return fd2;
-}
-
 TSAN_INTERCEPTOR(int, epoll_create, int size) {
   SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
   int fd = REAL(epoll_create)(size);
@@ -1383,40 +1494,6 @@ TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
   return res;
 }
 
-TSAN_INTERCEPTOR(long_t, readv, int fd, void *vec, int cnt) {
-  SCOPED_TSAN_INTERCEPTOR(readv, fd, vec, cnt);
-  int res = REAL(readv)(fd, vec, cnt);
-  if (res >= 0 && fd >= 0) {
-    FdAcquire(thr, pc, fd);
-  }
-  return res;
-}
-
-TSAN_INTERCEPTOR(long_t, preadv64, int fd, void *vec, int cnt, u64 off) {
-  SCOPED_TSAN_INTERCEPTOR(preadv64, fd, vec, cnt, off);
-  int res = REAL(preadv64)(fd, vec, cnt, off);
-  if (res >= 0 && fd >= 0) {
-    FdAcquire(thr, pc, fd);
-  }
-  return res;
-}
-
-TSAN_INTERCEPTOR(long_t, writev, int fd, void *vec, int cnt) {
-  SCOPED_TSAN_INTERCEPTOR(writev, fd, vec, cnt);
-  if (fd >= 0)
-    FdRelease(thr, pc, fd);
-  int res = REAL(writev)(fd, vec, cnt);
-  return res;
-}
-
-TSAN_INTERCEPTOR(long_t, pwritev64, int fd, void *vec, int cnt, u64 off) {
-  SCOPED_TSAN_INTERCEPTOR(pwritev64, fd, vec, cnt, off);
-  if (fd >= 0)
-    FdRelease(thr, pc, fd);
-  int res = REAL(pwritev64)(fd, vec, cnt, off);
-  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)
@@ -1442,15 +1519,6 @@ TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
   return res;
 }
 
-TSAN_INTERCEPTOR(long_t, recvmsg, int fd, void *msg, int flags) {
-  SCOPED_TSAN_INTERCEPTOR(recvmsg, fd, msg, flags);
-  int res = REAL(recvmsg)(fd, msg, 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));
@@ -1515,6 +1583,17 @@ TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
   return REAL(fwrite)(p, size, nmemb, f);
 }
 
+TSAN_INTERCEPTOR(int, fflush, void *stream) {
+  SCOPED_TSAN_INTERCEPTOR(fflush, stream);
+  return REAL(fflush)(stream);
+}
+
+TSAN_INTERCEPTOR(void, abort, int fake) {
+  SCOPED_TSAN_INTERCEPTOR(abort, fake);
+  REAL(fflush)(0);
+  REAL(abort)(fake);
+}
+
 TSAN_INTERCEPTOR(int, puts, const char *s) {
   SCOPED_TSAN_INTERCEPTOR(puts, s);
   MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s), false);
@@ -1556,26 +1635,19 @@ TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
   return res;
 }
 
-TSAN_INTERCEPTOR(int, poll, void *fds, long_t nfds, int timeout) {
-  SCOPED_TSAN_INTERCEPTOR(poll, fds, nfds, timeout);
-  int res = BLOCK_REAL(poll)(fds, nfds, timeout);
-  return res;
-}
-
-static void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
+void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
     my_siginfo_t *info, void *ctx) {
   ThreadState *thr = cur_thread();
   SignalContext *sctx = SigCtx(thr);
   // Don't mess with synchronous signals.
   if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
-      sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE ||
+      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) ||
       // 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 && sctx->in_blocking_func == 1 && thr->in_rtl == 1)) {
-    CHECK(thr->in_rtl == 0 || thr->in_rtl == 1);
     int in_rtl = thr->in_rtl;
     thr->in_rtl = 0;
     CHECK_EQ(thr->in_signal_handler, false);
@@ -1621,7 +1693,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
   internal_memcpy(&sigactions[sig], act, sizeof(*act));
   sigaction_t newact;
   internal_memcpy(&newact, act, sizeof(newact));
-  sigfillset(&newact.sa_mask);
+  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;
@@ -1644,6 +1716,11 @@ TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) {
   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);
@@ -1661,11 +1738,11 @@ TSAN_INTERCEPTOR(int, kill, int pid, int sig) {
   SignalContext *sctx = SigCtx(thr);
   CHECK_NE(sctx, 0);
   int prev = sctx->int_signal_send;
-  if (pid == GetPid()) {
+  if (pid == (int)internal_getpid()) {
     sctx->int_signal_send = sig;
   }
   int res = REAL(kill)(pid, sig);
-  if (pid == GetPid()) {
+  if (pid == (int)internal_getpid()) {
     CHECK_EQ(sctx->int_signal_send, sig);
     sctx->int_signal_send = prev;
   }
@@ -1694,13 +1771,30 @@ TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
   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);
+  // getaddrinfo calls fopen, which can be intercepted by user.
+  thr->in_rtl--;
+  CHECK_EQ(thr->in_rtl, 0);
+  int res = REAL(getaddrinfo)(node, service, hints, rv);
+  thr->in_rtl++;
+  ThreadIgnoreEnd(thr);
+  return res;
+}
+
 // 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;
-  Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+  if (flags()->verbosity > 0)
+    Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
 }
 
 TSAN_INTERCEPTOR(int, mlock, const void *addr, uptr len) {
@@ -1725,7 +1819,6 @@ TSAN_INTERCEPTOR(int, munlockall, void) {
 
 TSAN_INTERCEPTOR(int, fork, int fake) {
   SCOPED_TSAN_INTERCEPTOR(fork, fake);
-  // It's intercepted merely to process pending signals.
   int pid = REAL(fork)(fake);
   if (pid == 0) {
     // child
@@ -1742,27 +1835,106 @@ struct TsanInterceptorContext {
   const uptr pc;
 };
 
-#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;
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+// Causes interceptor recursion (getpwuid_r() calls fopen())
+#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+// Causes interceptor recursion (getaddrinfo() and fopen())
+#undef SANITIZER_INTERCEPT_GETADDRINFO
+#undef SANITIZER_INTERCEPT_GETNAMEINFO
+// Causes interceptor recursion (glob64() calls lstat64())
+#undef SANITIZER_INTERCEPT_GLOB
+
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+  do {                                                \
+  } while (false)
+#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_FD_ACQUIRE(ctx, fd) \
-    FdAcquire(((TsanInterceptorContext*)ctx)->thr, pc, fd)
+  FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
 #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
-    FdRelease(((TsanInterceptorContext*)ctx)->thr, pc, fd)
+  FdRelease(((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)
+  ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name)
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
+#define TSAN_SYSCALL() \
+  ThreadState *thr = cur_thread(); \
+  ScopedSyscall scoped_syscall(thr) \
+/**/
+
+struct ScopedSyscall {
+  ThreadState *thr;
+
+  explicit ScopedSyscall(ThreadState *thr)
+      : thr(thr) {
+    if (thr->in_rtl == 0)
+      Initialize(thr);
+    thr->in_rtl++;
+  }
+
+  ~ScopedSyscall() {
+    thr->in_rtl--;
+    if (thr->in_rtl == 0)
+      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_fd_close(uptr pc, int fd) {
+  TSAN_SYSCALL();
+  if (fd >= 0)
+    FdClose(thr, pc, fd);
+}
+
+static void syscall_pre_fork(uptr pc) {
+  TSAN_SYSCALL();
+}
+
+static void syscall_post_fork(uptr pc, int res) {
+  TSAN_SYSCALL();
+  if (res == 0) {
+    // child
+    FdOnFork(thr, pc);
+  } else if (res > 0) {
+    // parent
+  }
+}
+
+#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 { } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+  do { } while (false)
+#define COMMON_SYSCALL_FD_CLOSE(fd) \
+  syscall_fd_close(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 {
 
 void ProcessPendingSignals(ThreadState *thr) {
@@ -1774,8 +1946,8 @@ void ProcessPendingSignals(ThreadState *thr) {
   thr->in_signal_handler = true;
   sctx->pending_signal_count = 0;
   // These are too big for stack.
-  static THREADLOCAL sigset_t emptyset, oldset;
-  sigfillset(&emptyset);
+  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];
@@ -1796,8 +1968,9 @@ void ProcessPendingSignals(ThreadState *thr) {
           uptr pc = signal->sigaction ?
               (uptr)sigactions[sig].sa_sigaction :
               (uptr)sigactions[sig].sa_handler;
+          pc += 1;  // return address is expected, OutputReport() will undo this
           stack.Init(&pc, 1);
-          Lock l(&ctx->thread_mtx);
+          ThreadRegistryLock l(ctx->thread_registry);
           ScopedReport rep(ReportTypeErrnoInSignal);
           if (!IsFiredSuppression(ctx, rep, stack)) {
             rep.AddStack(&stack);
@@ -1813,6 +1986,16 @@ void ProcessPendingSignals(ThreadState *thr) {
   thr->in_signal_handler = false;
 }
 
+static void finalize(void *arg) {
+  ThreadState * thr = cur_thread();
+  uptr pc = 0;
+  atexit_ctx->exit(thr, pc);
+  int status = Finalize(cur_thread());
+  REAL(fflush)(0);
+  if (status)
+    _exit(status);
+}
+
 static void unreachable() {
   Printf("FATAL: ThreadSanitizer: unreachable called\n");
   Die();
@@ -1826,8 +2009,16 @@ void InitializeInterceptors() {
   REAL(memcpy) = internal_memcpy;
   REAL(memcmp) = internal_memcmp;
 
+  // Instruct libc malloc to consume less memory.
+  mallopt(1, 0);  // M_MXFAST
+  mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
+
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
+  TSAN_INTERCEPT(setjmp);
+  TSAN_INTERCEPT(_setjmp);
+  TSAN_INTERCEPT(sigsetjmp);
+  TSAN_INTERCEPT(__sigsetjmp);
   TSAN_INTERCEPT(longjmp);
   TSAN_INTERCEPT(siglongjmp);
 
@@ -1848,7 +2039,6 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(strlen);
   TSAN_INTERCEPT(memset);
   TSAN_INTERCEPT(memcpy);
-  TSAN_INTERCEPT(strcmp);
   TSAN_INTERCEPT(memchr);
   TSAN_INTERCEPT(memrchr);
   TSAN_INTERCEPT(memmove);
@@ -1856,10 +2046,10 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(strchr);
   TSAN_INTERCEPT(strchrnul);
   TSAN_INTERCEPT(strrchr);
-  TSAN_INTERCEPT(strncmp);
   TSAN_INTERCEPT(strcpy);  // NOLINT
   TSAN_INTERCEPT(strncpy);
   TSAN_INTERCEPT(strstr);
+  TSAN_INTERCEPT(strdup);
 
   TSAN_INTERCEPT(pthread_create);
   TSAN_INTERCEPT(pthread_join);
@@ -1888,12 +2078,12 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
   TSAN_INTERCEPT(pthread_rwlock_unlock);
 
-  // TSAN_INTERCEPT(pthread_cond_init);
-  TSAN_INTERCEPT(pthread_cond_destroy);
-  TSAN_INTERCEPT(pthread_cond_signal);
-  TSAN_INTERCEPT(pthread_cond_broadcast);
-  TSAN_INTERCEPT(pthread_cond_wait);
-  TSAN_INTERCEPT(pthread_cond_timedwait);
+  INTERCEPT_FUNCTION_VER(pthread_cond_init, GLIBC_2.3.2);
+  INTERCEPT_FUNCTION_VER(pthread_cond_destroy, 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);
 
   TSAN_INTERCEPT(pthread_barrier_init);
   TSAN_INTERCEPT(pthread_barrier_destroy);
@@ -1937,8 +2127,6 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(connect);
   TSAN_INTERCEPT(bind);
   TSAN_INTERCEPT(listen);
-  TSAN_INTERCEPT(accept);
-  TSAN_INTERCEPT(accept4);
   TSAN_INTERCEPT(epoll_create);
   TSAN_INTERCEPT(epoll_create1);
   TSAN_INTERCEPT(close);
@@ -1947,14 +2135,9 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(pipe);
   TSAN_INTERCEPT(pipe2);
 
-  TSAN_INTERCEPT(readv);
-  TSAN_INTERCEPT(preadv64);
-  TSAN_INTERCEPT(writev);
-  TSAN_INTERCEPT(pwritev64);
   TSAN_INTERCEPT(send);
   TSAN_INTERCEPT(sendmsg);
   TSAN_INTERCEPT(recv);
-  TSAN_INTERCEPT(recvmsg);
 
   TSAN_INTERCEPT(unlink);
   TSAN_INTERCEPT(fopen);
@@ -1962,16 +2145,18 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(fclose);
   TSAN_INTERCEPT(fread);
   TSAN_INTERCEPT(fwrite);
+  TSAN_INTERCEPT(fflush);
+  TSAN_INTERCEPT(abort);
   TSAN_INTERCEPT(puts);
   TSAN_INTERCEPT(rmdir);
   TSAN_INTERCEPT(opendir);
 
   TSAN_INTERCEPT(epoll_ctl);
   TSAN_INTERCEPT(epoll_wait);
-  TSAN_INTERCEPT(poll);
 
   TSAN_INTERCEPT(sigaction);
   TSAN_INTERCEPT(signal);
+  TSAN_INTERCEPT(sigsuspend);
   TSAN_INTERCEPT(raise);
   TSAN_INTERCEPT(kill);
   TSAN_INTERCEPT(pthread_kill);
@@ -1979,6 +2164,7 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(usleep);
   TSAN_INTERCEPT(nanosleep);
   TSAN_INTERCEPT(gettimeofday);
+  TSAN_INTERCEPT(getaddrinfo);
 
   TSAN_INTERCEPT(mlock);
   TSAN_INTERCEPT(munlock);
index 992e3834aae56c4338a74c01e0882b8acdea251e..e056bd465bf0c21f3514b09c54e013f121fe0a80 100644 (file)
 #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());
 }
@@ -31,6 +36,57 @@ void __tsan_write16(void *addr) {
   MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
+u16 __tsan_unaligned_read2(const uu16 *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, false, false);
+  return *addr;
+}
+
+u32 __tsan_unaligned_read4(const uu32 *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, false, false);
+  return *addr;
+}
+
+u64 __tsan_unaligned_read8(const uu64 *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, false, false);
+  return *addr;
+}
+
+void __tsan_unaligned_write2(uu16 *addr, u16 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, true, false);
+  *addr = v;
+}
+
+void __tsan_unaligned_write4(uu32 *addr, u32 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, true, false);
+  *addr = v;
+}
+
+void __tsan_unaligned_write8(uu64 *addr, u64 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, true, false);
+  *addr = v;
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uint16_t __sanitizer_unaligned_load16(void *addr)
+    ALIAS("__tsan_unaligned_read2");
+SANITIZER_INTERFACE_ATTRIBUTE
+uint32_t __sanitizer_unaligned_load32(void *addr)
+    ALIAS("__tsan_unaligned_read4");
+SANITIZER_INTERFACE_ATTRIBUTE
+uint64_t __sanitizer_unaligned_load64(void *addr)
+    ALIAS("__tsan_unaligned_read8");
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(void *addr, uint16_t v)
+    ALIAS("__tsan_unaligned_write2");
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(void *addr, uint32_t v)
+    ALIAS("__tsan_unaligned_write4");
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(void *addr, uint64_t v)
+    ALIAS("__tsan_unaligned_write8");
+}
+
 void __tsan_acquire(void *addr) {
   Acquire(cur_thread(), CALLERPC, (uptr)addr);
 }
index 2cfd7684183286f57a81d2a09c5140638121377c..63de7b2ab5c4eaca778523f6ed696964760bfe33 100644 (file)
@@ -25,30 +25,38 @@ 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.
-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_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
-    SANITIZER_INTERFACE_ATTRIBUTE;
+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 u16 __tsan_unaligned_read2(const uu16 *addr);
+SANITIZER_INTERFACE_ATTRIBUTE u32 __tsan_unaligned_read4(const uu32 *addr);
+SANITIZER_INTERFACE_ATTRIBUTE u64 __tsan_unaligned_read8(const uu64 *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write2(uu16 *addr, u16 v);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write4(uu32 *addr, u32 v);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write8(uu64 *addr, u64 v);
+
+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"
index 7e49fb8b059cc6f80735d678564c20354bcf0948..46d9e3ec1afa5b6ba146536d5603c4dcad757411 100644 (file)
@@ -11,6 +11,7 @@
 #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"
@@ -18,6 +19,7 @@
 #include "tsan_mman.h"
 #include "tsan_flags.h"
 #include "tsan_platform.h"
+#include "tsan_vector.h"
 
 #define CALLERPC ((uptr)__builtin_return_address(0))
 
@@ -65,6 +67,7 @@ struct ExpectRace {
   ExpectRace *next;
   ExpectRace *prev;
   int hitcount;
+  int addcount;
   uptr addr;
   uptr size;
   char *file;
@@ -89,16 +92,19 @@ 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)
+    if (race->addr == addr && race->size == size) {
+      race->addcount++;
       return;
+    }
   }
   race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace));
-  race->hitcount = 0;
   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++)
@@ -153,6 +159,68 @@ bool IsExpectedReport(uptr addr, uptr size) {
   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
@@ -160,12 +228,12 @@ using namespace __tsan;  // NOLINT
 extern "C" {
 void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {
   SCOPED_ANNOTATION(AnnotateHappensBefore);
-  Release(cur_thread(), CALLERPC, addr);
+  Release(thr, pc, addr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {
   SCOPED_ANNOTATION(AnnotateHappensAfter);
-  Acquire(cur_thread(), CALLERPC, addr);
+  Acquire(thr, pc, addr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {
@@ -235,14 +303,6 @@ void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) {
   SCOPED_ANNOTATION(AnnotateNoOp);
 }
 
-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");
-}
-
 void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
   SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
   Lock lock(&dyn_ann_ctx->mtx);
@@ -321,22 +381,22 @@ void INTERFACE_ATTRIBUTE AnnotateBenignRace(
 
 void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
   SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
-  IgnoreCtl(cur_thread(), false, true);
+  ThreadIgnoreBegin(thr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
   SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
-  IgnoreCtl(cur_thread(), false, false);
+  ThreadIgnoreEnd(thr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
   SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
-  IgnoreCtl(cur_thread(), true, true);
+  ThreadIgnoreBegin(thr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
   SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
-  IgnoreCtl(thr, true, false);
+  ThreadIgnoreEnd(thr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
@@ -355,6 +415,9 @@ void INTERFACE_ATTRIBUTE 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);
 }
@@ -366,6 +429,7 @@ void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
 void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
     char *f, int l, uptr mem, uptr sz, char *desc) {
   SCOPED_ANNOTATION(AnnotateBenignRaceSized);
+  BenignRaceImpl(f, l, mem, 1, desc);
 }
 
 int INTERFACE_ATTRIBUTE RunningOnValgrind() {
@@ -382,4 +446,7 @@ const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
   else
     return "0";
 }
+
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
 }  // extern "C"
index b65003294285d1c4a992602acd07f8948c1c4f8e..45c18352e698a5d0f013e0fe16fa5d5aba64d441 100644 (file)
@@ -21,8 +21,8 @@
 extern "C" {
 #endif
 
-void __tsan_acquire(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_release(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_acquire(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_release(void *addr);
 
 #ifdef __cplusplus
 }  // extern "C"
index 2c8b2ab049c0f50cca37205fbedaf418ba621723..02ebb47e6af19456bf35f5b96027093f1602efa8 100644 (file)
@@ -28,23 +28,37 @@ using namespace __tsan;  // NOLINT
 #define SCOPED_ATOMIC(func, ...) \
     const uptr callpc = (uptr)__builtin_return_address(0); \
     uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
-    pc = __sanitizer::StackTrace::GetPreviousInstructionPc(pc); \
     mo = ConvertOrder(mo); \
     mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
     ThreadState *const thr = cur_thread(); \
     AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
-    ScopedAtomic sa(thr, callpc, __FUNCTION__); \
+    ScopedAtomic sa(thr, callpc, a, mo, __FUNCTION__); \
     return Atomic##func(thr, pc, __VA_ARGS__); \
 /**/
 
+// Some shortcuts.
+typedef __tsan_memory_order morder;
+typedef __tsan_atomic8 a8;
+typedef __tsan_atomic16 a16;
+typedef __tsan_atomic32 a32;
+typedef __tsan_atomic64 a64;
+typedef __tsan_atomic128 a128;
+const morder mo_relaxed = __tsan_memory_order_relaxed;
+const morder mo_consume = __tsan_memory_order_consume;
+const morder mo_acquire = __tsan_memory_order_acquire;
+const morder mo_release = __tsan_memory_order_release;
+const morder mo_acq_rel = __tsan_memory_order_acq_rel;
+const morder mo_seq_cst = __tsan_memory_order_seq_cst;
+
 class ScopedAtomic {
  public:
-  ScopedAtomic(ThreadState *thr, uptr pc, const char *func)
+  ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
+               morder mo, const char *func)
       : thr_(thr) {
     CHECK_EQ(thr_->in_rtl, 0);
     ProcessPendingSignals(thr);
     FuncEntry(thr_, pc);
-    DPrintf("#%d: %s\n", thr_->tid, func);
+    DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
     thr_->in_rtl++;
   }
   ~ScopedAtomic() {
@@ -56,20 +70,6 @@ class ScopedAtomic {
   ThreadState *thr_;
 };
 
-// Some shortcuts.
-typedef __tsan_memory_order morder;
-typedef __tsan_atomic8 a8;
-typedef __tsan_atomic16 a16;
-typedef __tsan_atomic32 a32;
-typedef __tsan_atomic64 a64;
-typedef __tsan_atomic128 a128;
-const morder mo_relaxed = __tsan_memory_order_relaxed;
-const morder mo_consume = __tsan_memory_order_consume;
-const morder mo_acquire = __tsan_memory_order_acquire;
-const morder mo_release = __tsan_memory_order_release;
-const morder mo_acq_rel = __tsan_memory_order_acq_rel;
-const morder mo_seq_cst = __tsan_memory_order_seq_cst;
-
 static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
   StatInc(thr, StatAtomic);
   StatInc(thr, t);
@@ -288,16 +288,20 @@ static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
 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 = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
-  thr->clock.set(thr->tid, thr->fast_state.epoch());
-  if (IsAcqRelOrder(mo))
-    thr->clock.acq_rel(&s->clock);
-  else if (IsReleaseOrder(mo))
-    thr->clock.release(&s->clock);
-  else if (IsAcquireOrder(mo))
-    thr->clock.acquire(&s->clock);
+  SyncVar *s = 0;
+  if (mo != mo_relaxed) {
+    s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+    thr->clock.set(thr->tid, thr->fast_state.epoch());
+    if (IsAcqRelOrder(mo))
+      thr->clock.acq_rel(&s->clock);
+    else if (IsReleaseOrder(mo))
+      thr->clock.release(&s->clock);
+    else if (IsAcquireOrder(mo))
+      thr->clock.acquire(&s->clock);
+  }
   v = F(a, v);
-  s->mtx.Unlock();
+  if (s)
+    s->mtx.Unlock();
   return v;
 }
 
@@ -348,17 +352,21 @@ 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 = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
-  thr->clock.set(thr->tid, thr->fast_state.epoch());
-  if (IsAcqRelOrder(mo))
-    thr->clock.acq_rel(&s->clock);
-  else if (IsReleaseOrder(mo))
-    thr->clock.release(&s->clock);
-  else if (IsAcquireOrder(mo))
-    thr->clock.acquire(&s->clock);
+  SyncVar *s = 0;
+  if (mo != mo_relaxed) {
+    s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+    thr->clock.set(thr->tid, thr->fast_state.epoch());
+    if (IsAcqRelOrder(mo))
+      thr->clock.acq_rel(&s->clock);
+    else if (IsReleaseOrder(mo))
+      thr->clock.release(&s->clock);
+    else if (IsAcquireOrder(mo))
+      thr->clock.acquire(&s->clock);
+  }
   T cc = *c;
   T pr = func_cas(a, cc, v);
-  s->mtx.Unlock();
+  if (s)
+    s->mtx.Unlock();
   if (pr == cc)
     return true;
   *c = pr;
@@ -649,14 +657,14 @@ a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
 }
 
 #if __TSAN_HAS_INT128
-a128 __tsan_atomic64_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
+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
 
 void __tsan_atomic_thread_fence(morder mo) {
-  char* a;
+  char* a = 0;
   SCOPED_ATOMIC(Fence, mo);
 }
 
index 92796d1178fe8102cf583f248df7406f33600423..4d6e10bcf7b99f4cdac5355d426c08b6852fa59a 100644 (file)
@@ -50,8 +50,20 @@ void __tsan_write8(void *addr) {
 
 void __tsan_vptr_update(void **vptr_p, void *new_val) {
   CHECK_EQ(sizeof(vptr_p), 8);
-  if (*vptr_p != new_val)
-    MemoryWrite(cur_thread(), CALLERPC, (uptr)vptr_p, kSizeLog8);
+  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) {
index f8c0b4eb635cd3722730f1771218e1ea2f181883..7cc725779773f8c4ffc2b0997f816ba1a31b6a6d 100644 (file)
@@ -15,6 +15,8 @@
 #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
 
@@ -92,6 +94,8 @@ class ScopedJavaFunc {
 
 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
 static JavaContext *jctx;
+extern atomic_uintptr_t libjvm_begin;
+extern atomic_uintptr_t libjvm_end;
 
 static BlockDesc *getblock(uptr addr) {
   uptr i = (addr - jctx->heap_begin) / kHeapAlignment;
@@ -155,11 +159,22 @@ SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
 #define SCOPED_JAVA_FUNC(func) \
   ThreadState *thr = cur_thread(); \
   const uptr caller_pc = GET_CALLER_PC(); \
-  const uptr pc = (uptr)&func; \
+  const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
   (void)pc; \
   ScopedJavaFunc scoped(thr, caller_pc); \
 /**/
 
+void __tsan_java_preinit(const char *libjvm_path) {
+  SCOPED_JAVA_FUNC(__tsan_java_preinit);
+  if (libjvm_path) {
+    uptr begin, end;
+    if (GetCodeRangeForFile(libjvm_path, &begin, &end)) {
+      atomic_store(&libjvm_begin, begin, memory_order_relaxed);
+      atomic_store(&libjvm_end, end, memory_order_relaxed);
+    }
+  }
+}
+
 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);
@@ -269,6 +284,7 @@ void __tsan_java_mutex_lock(jptr addr) {
   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);
 }
 
@@ -289,6 +305,7 @@ void __tsan_java_mutex_read_lock(jptr addr) {
   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);
 }
 
@@ -301,3 +318,25 @@ void __tsan_java_mutex_read_unlock(jptr addr) {
 
   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);
+}
index 01922bc923193d375686e3f4d9fe865b6856eab9..818c07b97d447bfe49700d2651a130359836a998 100644 (file)
@@ -32,7 +32,11 @@ extern "C" {
 
 typedef unsigned long jptr;  // NOLINT
 
-// Must be called before any other callback from Java.
+// Must be called before any other callback from Java, right after dlopen
+// of JVM shared lib. If libjvm_path is specified, then all interceptors
+// coming directly from JVM will be ignored.
+void __tsan_java_preinit(const char *libjvm_path) INTERFACE_ATTRIBUTE;
+// Must be called after __tsan_java_preinit but before any other callback.
 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).
@@ -53,8 +57,7 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) INTERFACE_ATTRIBUTE;
 
 // Mutex lock.
 // Addr is any unique address associated with the mutex.
-// Must not be called on recursive reentry.
-// Object.wait() is handled as a pair of unlock/lock.
+// 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;
@@ -62,6 +65,16 @@ void __tsan_java_mutex_unlock(jptr addr) INTERFACE_ATTRIBUTE;
 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;
 
 #ifdef __cplusplus
 }  // extern "C"
index 23c73c50cc10b07034cf192e5161173f9fb429b5..832374becf5845b3504c03658674d61d148771f6 100644 (file)
@@ -27,6 +27,41 @@ extern "C" void WEAK __tsan_free_hook(void *ptr) {
 
 namespace __tsan {
 
+COMPILER_CHECK(sizeof(MBlock) == 16);
+
+void MBlock::Lock() {
+  atomic_uintptr_t *a = reinterpret_cast<atomic_uintptr_t*>(this);
+  uptr v = atomic_load(a, memory_order_relaxed);
+  for (int iter = 0;; iter++) {
+    if (v & 1) {
+      if (iter < 10)
+        proc_yield(20);
+      else
+        internal_sched_yield();
+      v = atomic_load(a, memory_order_relaxed);
+      continue;
+    }
+    if (atomic_compare_exchange_weak(a, &v, v | 1, memory_order_acquire))
+      break;
+  }
+}
+
+void MBlock::Unlock() {
+  atomic_uintptr_t *a = reinterpret_cast<atomic_uintptr_t*>(this);
+  uptr v = atomic_load(a, memory_order_relaxed);
+  DCHECK(v & 1);
+  atomic_store(a, v & ~1, memory_order_relaxed);
+}
+
+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);
@@ -38,10 +73,12 @@ void InitializeAllocator() {
 
 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() {
@@ -54,7 +91,7 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
   Context *ctx = CTX();
   StackTrace stack;
   stack.ObtainCurrent(thr, pc);
-  Lock l(&ctx->thread_mtx);
+  ThreadRegistryLock l(ctx->thread_registry);
   ScopedReport rep(ReportTypeSignalUnsafe);
   if (!IsFiredSuppression(ctx, rep, stack)) {
     rep.AddStack(&stack);
@@ -64,16 +101,18 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
 
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
   CHECK_GT(thr->in_rtl, 0);
+  if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
+    return AllocatorReturnNull();
   void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
   if (p == 0)
     return 0;
   MBlock *b = new(allocator()->GetMetaData(p)) MBlock;
-  b->size = sz;
-  b->head = 0;
-  b->alloc_tid = thr->unique_id;
-  b->alloc_stack_id = CurrentStackId(thr, pc);
+  b->Init(sz, thr->tid, CurrentStackId(thr, pc));
   if (CTX() && CTX()->initialized) {
-    MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
+    if (thr->ignore_reads_and_writes == 0)
+      MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
+    else
+      MemoryResetRange(thr, pc, (uptr)p, sz);
   }
   DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
   SignalUnsafeCall(thr, pc);
@@ -85,9 +124,9 @@ void user_free(ThreadState *thr, uptr pc, void *p) {
   CHECK_NE(p, (void*)0);
   DPrintf("#%d: free(%p)\n", thr->tid, p);
   MBlock *b = (MBlock*)allocator()->GetMetaData(p);
-  if (b->head)   {
-    Lock l(&b->mtx);
-    for (SyncVar *s = b->head; s;) {
+  if (b->ListHead()) {
+    MBlock::ScopedLock l(b);
+    for (SyncVar *s = b->ListHead(); s;) {
       SyncVar *res = s;
       s = s->next;
       StatInc(thr, StatSyncDestroyed);
@@ -95,12 +134,12 @@ void user_free(ThreadState *thr, uptr pc, void *p) {
       res->mtx.Unlock();
       DestroyAndFree(res);
     }
-    b->head = 0;
+    b->ListReset();
   }
   if (CTX() && CTX()->initialized && thr->in_rtl == 1) {
-    MemoryRangeFreed(thr, pc, (uptr)p, b->size);
+    if (thr->ignore_reads_and_writes == 0)
+      MemoryRangeFreed(thr, pc, (uptr)p, b->Size());
   }
-  b->~MBlock();
   allocator()->Deallocate(&thr->alloc_cache, p);
   SignalUnsafeCall(thr, pc);
 }
@@ -116,20 +155,29 @@ void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
       return 0;
     if (p) {
       MBlock *b = user_mblock(thr, p);
-      internal_memcpy(p2, p, min(b->size, sz));
+      CHECK_NE(b, 0);
+      internal_memcpy(p2, p, min(b->Size(), sz));
     }
   }
-  if (p) {
+  if (p)
     user_free(thr, pc, p);
-  }
   return p2;
 }
 
+uptr user_alloc_usable_size(ThreadState *thr, uptr pc, void *p) {
+  CHECK_GT(thr->in_rtl, 0);
+  if (p == 0)
+    return 0;
+  MBlock *b = (MBlock*)allocator()->GetMetaData(p);
+  return b ? b->Size() : 0;
+}
+
 MBlock *user_mblock(ThreadState *thr, void *p) {
-  CHECK_NE(p, (void*)0);
+  CHECK_NE(p, 0);
   Allocator *a = allocator();
   void *b = a->GetBlockBegin(p);
-  CHECK_NE(b, 0);
+  if (b == 0)
+    return 0;
   return (MBlock*)a->GetMetaData(b);
 }
 
@@ -152,11 +200,12 @@ void invoke_free_hook(void *ptr) {
 void *internal_alloc(MBlockType typ, uptr sz) {
   ThreadState *thr = cur_thread();
   CHECK_GT(thr->in_rtl, 0);
+  CHECK_LE(sz, InternalSizeClassMap::kMaxSize);
   if (thr->nomalloc) {
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
   }
-  return InternalAlloc(sz);
+  return InternalAlloc(sz, &thr->internal_alloc_cache);
 }
 
 void internal_free(void *p) {
@@ -166,7 +215,7 @@ void internal_free(void *p) {
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
   }
-  InternalFree(p);
+  InternalFree(p, &thr->internal_alloc_cache);
 }
 
 }  // namespace __tsan
@@ -213,6 +262,12 @@ uptr __tsan_get_allocated_size(void *p) {
   if (p == 0)
     return 0;
   MBlock *b = (MBlock*)allocator()->GetMetaData(p);
-  return b->size;
+  return b->Size();
+}
+
+void __tsan_on_thread_idle() {
+  ThreadState *thr = cur_thread();
+  allocator()->SwallowCache(&thr->alloc_cache);
+  internal_allocator()->SwallowCache(&thr->internal_alloc_cache);
 }
 }  // extern "C"
index 7a657e124bf8e3355540752f96ea9d8cb416d7a6..90faaffa1fca75f62e8813c48957b9c036af68f2 100644 (file)
@@ -29,6 +29,7 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
 void user_free(ThreadState *thr, uptr pc, void *p);
 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(ThreadState *thr, uptr pc, void *p);
 // Given the pointer p into a valid allocated block,
 // returns the descriptor of the block.
 MBlock *user_mblock(ThreadState *thr, void *p);
@@ -60,6 +61,7 @@ enum MBlockType {
   MBlockExpectRace,
   MBlockSignal,
   MBlockFD,
+  MBlockJmpBuf,
 
   // This must be the last.
   MBlockTypeCount
index 716722b0897b62e51ab6869936b6ae575a6c17ee..e7846c53e4af02b82d0f7f89b0cb8131fc19ffe4 100644 (file)
@@ -29,8 +29,8 @@ static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
   /*0  MutexTypeInvalid*/     {},
   /*1  MutexTypeTrace*/       {MutexTypeLeaf},
   /*2  MutexTypeThreads*/     {MutexTypeReport},
-  /*3  MutexTypeReport*/      {MutexTypeSyncTab, MutexTypeMBlock,
-                               MutexTypeJavaMBlock},
+  /*3  MutexTypeReport*/      {MutexTypeSyncTab, MutexTypeSyncVar,
+                               MutexTypeMBlock, MutexTypeJavaMBlock},
   /*4  MutexTypeSyncVar*/     {},
   /*5  MutexTypeSyncTab*/     {MutexTypeSyncVar},
   /*6  MutexTypeSlab*/        {MutexTypeLeaf},
index 6924eade4c647ca840d9dc6a3462df868d23470d..ef60bd47db29f4d7f60292dae76b42297e08f567 100644 (file)
@@ -20,7 +20,7 @@ class MutexSet {
  public:
   // Holds limited number of mutexes.
   // The oldest mutexes are discarded on overflow.
-  static const uptr kMaxSize = 64;
+  static const uptr kMaxSize = 16;
   struct Desc {
     u64 id;
     u64 epoch;
index 78c1a7d8195832a6a22b7c8d75ff88cff280ae01..ac36c5ab67a702a993ce134aa927bd271d130cc1 100644 (file)
@@ -35,9 +35,9 @@ C++ COMPAT linux memory layout:
 Go linux and darwin memory layout:
 0000 0000 0000 - 0000 1000 0000: executable
 0000 1000 0000 - 00f8 0000 0000: -
-00f8 0000 0000 - 0118 0000 0000: heap
-0118 0000 0000 - 1000 0000 0000: -
-1000 0000 0000 - 1460 0000 0000: shadow
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 1000 0000 0000: -
+1000 0000 0000 - 1380 0000 0000: shadow
 1460 0000 0000 - 6000 0000 0000: -
 6000 0000 0000 - 6200 0000 0000: traces
 6200 0000 0000 - 7fff ffff ffff: -
@@ -45,8 +45,8 @@ Go linux and darwin memory layout:
 Go windows memory layout:
 0000 0000 0000 - 0000 1000 0000: executable
 0000 1000 0000 - 00f8 0000 0000: -
-00f8 0000 0000 - 0118 0000 0000: heap
-0118 0000 0000 - 0100 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
 0100 0000 0000 - 0560 0000 0000: shadow
 0560 0000 0000 - 0760 0000 0000: traces
 0760 0000 0000 - 07ff ffff ffff: -
@@ -63,11 +63,11 @@ namespace __tsan {
 
 #if defined(TSAN_GO)
 static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x00fcffffffffULL;
-# if defined(_WIN32)
+static const uptr kLinuxAppMemEnd = 0x04dfffffffffULL;
+# if SANITIZER_WINDOWS
 static const uptr kLinuxShadowMsk = 0x010000000000ULL;
 # else
-static const uptr kLinuxShadowMsk = 0x100000000000ULL;
+static const uptr kLinuxShadowMsk = 0x200000000000ULL;
 # endif
 // TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout,
 // when memory addresses are of the 0x2axxxxxxxxxx form.
@@ -82,7 +82,7 @@ static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
 
 static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL;
 
-#if defined(_WIN32)
+#if SANITIZER_WINDOWS
 const uptr kTraceMemBegin = 0x056000000000ULL;
 #else
 const uptr kTraceMemBegin = 0x600000000000ULL;
@@ -130,13 +130,19 @@ static inline uptr AlternativeAddress(uptr addr) {
 #endif
 }
 
-uptr GetShadowMemoryConsumption();
 void FlushShadowMemory();
+void WriteMemoryProfile(char *buf, uptr buf_size);
 
 const char *InitializePlatform();
 void FinalizePlatform();
-uptr ALWAYS_INLINE INLINE GetThreadTrace(int tid) {
-  uptr p = kTraceMemBegin + (uptr)tid * kTraceSize * sizeof(Event);
+uptr ALWAYS_INLINE GetThreadTrace(int tid) {
+  uptr p = kTraceMemBegin + (uptr)(tid * 2) * kTraceSize * sizeof(Event);
+  DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+  return p;
+}
+
+uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
+  uptr p = kTraceMemBegin + (uptr)(tid * 2 + 1) * kTraceSize * sizeof(Event);
   DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
   return p;
 }
@@ -146,9 +152,6 @@ void internal_start_thread(void(*func)(void*), void *arg);
 // Says whether the addr relates to a global var.
 // Guesses with high probability, may yield both false positives and negatives.
 bool IsGlobalVar(uptr addr);
-uptr GetTlsSize();
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size);
 int ExtractResolvFDs(void *state, int *fds, int nfd);
 
 }  // namespace __tsan
index f7b05f2bf8ffb88e9b369281aff0f7eeef812b65..f13e3c893b39d826176d1a106604b21a97a5e5c7 100644 (file)
@@ -10,7 +10,9 @@
 // Linux-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef __linux__
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -19,7 +21,6 @@
 #include "tsan_rtl.h"
 #include "tsan_flags.h"
 
-#include <asm/prctl.h>
 #include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
 #include <dlfcn.h>
 #define __need_res_state
 #include <resolv.h>
+#include <malloc.h>
 
-extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
+extern "C" struct mallinfo __libc_mallinfo();
 
 namespace __tsan {
 
+const uptr kPageSize = 4096;
+
 #ifndef TSAN_GO
 ScopedInRtl::ScopedInRtl()
     : thr_(cur_thread()) {
@@ -66,8 +70,38 @@ ScopedInRtl::~ScopedInRtl() {
 }
 #endif
 
-uptr GetShadowMemoryConsumption() {
-  return 0;
+void FillProfileCallback(uptr start, uptr rss, bool file,
+                         uptr *mem, uptr stats_size) {
+  CHECK_EQ(7, stats_size);
+  mem[6] += rss;  // total
+  start >>= 40;
+  if (start < 0x10)  // shadow
+    mem[0] += rss;
+  else if (start >= 0x20 && start < 0x30)  // compat modules
+    mem[file ? 1 : 2] += rss;
+  else if (start >= 0x7e)  // modules
+    mem[file ? 1 : 2] += rss;
+  else if (start >= 0x60 && start < 0x62)  // traces
+    mem[3] += rss;
+  else if (start >= 0x7d && start < 0x7e)  // heap
+    mem[4] += rss;
+  else  // other
+    mem[5] += rss;
+}
+
+void WriteMemoryProfile(char *buf, uptr buf_size) {
+  uptr mem[7] = {};
+  __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
+  char *buf_pos = buf;
+  char *buf_end = buf + buf_size;
+  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
+      "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
+      mem[6] >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
+      mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
+  struct mallinfo mi = __libc_mallinfo();
+  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
+      "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
+      mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
 }
 
 void FlushShadowMemory() {
@@ -89,6 +123,63 @@ static void ProtectRange(uptr beg, uptr end) {
 #endif
 
 #ifndef TSAN_GO
+// 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 filename[256];
+  internal_snprintf(filename, sizeof(filename), "%s/tsan.rodata.%d",
+                    tmpdir, (int)internal_getpid());
+  uptr openrv = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+  if (internal_iserror(openrv))
+    return;
+  fd_t fd = openrv;
+  // Fill the file with kShadowRodata.
+  const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
+  InternalScopedBuffer<u64> marker(kMarkerSize);
+  for (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, kPageSize, PROT_READ | PROT_WRITE,
+                            MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
+  if (internal_iserror(page)) {
+    internal_close(fd);
+    internal_unlink(filename);
+    return;
+  }
+  // Map the file into shadow of .rodata sections.
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+  uptr start, end, offset, prot;
+  char name[128];
+  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);
+  internal_unlink(filename);
+}
+
 void InitializeShadowMemory() {
   uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
     kLinuxShadowEnd - kLinuxShadowBeg);
@@ -115,6 +206,8 @@ void InitializeShadowMemory() {
       kLinuxAppMemBeg, kLinuxAppMemEnd,
       (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
   DPrintf("stack        %zx\n", (uptr)&shadow);
+
+  MapRodata();
 }
 #endif
 
@@ -124,10 +217,11 @@ static uptr g_data_end;
 #ifndef TSAN_GO
 static void CheckPIE() {
   // Ensure that the binary is indeed compiled with -pie.
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(true);
   uptr start, end;
   if (proc_maps.Next(&start, &end,
-                     /*offset*/0, /*filename*/0, /*filename_size*/0)) {
+                     /*offset*/0, /*filename*/0, /*filename_size*/0,
+                     /*protection*/0)) {
     if ((u64)start < kLinuxAppMemBeg) {
       Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
              "something is mapped at 0x%zx < 0x%zx)\n",
@@ -140,11 +234,12 @@ static void CheckPIE() {
 }
 
 static void InitDataSeg() {
-  MemoryMappingLayout proc_maps;
+  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))) {
+  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
@@ -163,27 +258,6 @@ static void InitDataSeg() {
   CHECK_LT((uptr)&g_data_start, g_data_end);
 }
 
-static uptr g_tls_size;
-
-#ifdef __i386__
-# define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
-#else
-# define INTERNAL_FUNCTION
-#endif
-
-static int InitTlsSize() {
-  typedef void (*get_tls_func)(size_t*, size_t*) 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);
-  return tls_size;
-}
 #endif  // #ifndef TSAN_GO
 
 static rlim_t getlim(int res) {
@@ -238,53 +312,12 @@ const char *InitializePlatform() {
 
 #ifndef TSAN_GO
   CheckPIE();
-  g_tls_size = (uptr)InitTlsSize();
+  InitTlsSize();
   InitDataSeg();
 #endif
   return GetEnv(kTsanOptionsEnv);
 }
 
-void FinalizePlatform() {
-  fflush(0);
-}
-
-uptr GetTlsSize() {
-#ifndef TSAN_GO
-  return g_tls_size;
-#else
-  return 0;
-#endif
-}
-
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-#ifndef TSAN_GO
-  arch_prctl(ARCH_GET_FS, tls_addr);
-  *tls_addr -= g_tls_size;
-  *tls_size = g_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;
-    }
-  }
-#else
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-#endif
-}
-
 bool IsGlobalVar(uptr addr) {
   return g_data_start && addr >= g_data_start && addr < g_data_end;
 }
@@ -304,4 +337,4 @@ int ExtractResolvFDs(void *state, int *fds, int nfd) {
 
 }  // namespace __tsan
 
-#endif  // #ifdef __linux__
+#endif  // SANITIZER_LINUX
index b247468c8294bf4e96fd8f9221876dffd82e5d91..3dca611dc928884e4b24e1be834ac1f149755954 100644 (file)
@@ -10,7 +10,8 @@
 // Mac-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -87,18 +88,6 @@ void FinalizePlatform() {
   fflush(0);
 }
 
-uptr GetTlsSize() {
-  return 0;
-}
-
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-}
-
 }  // namespace __tsan
 
-#endif  // #ifdef __APPLE__
+#endif  // SANITIZER_MAC
index 376dc08688be04be24dd21d001803ff313712c9c..6e49ef42f0c015b1220c660130023bed30e482f2 100644 (file)
@@ -10,7 +10,8 @@
 // Windows-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef _WIN32
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 
 #include "tsan_platform.h"
 
@@ -39,18 +40,6 @@ void FinalizePlatform() {
   fflush(0);
 }
 
-uptr GetTlsSize() {
-  return 0;
-}
-
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-}
-
 }  // namespace __tsan
 
-#endif  // #ifdef _WIN32
+#endif  // SANITIZER_WINDOWS
index 098d8262ba13725bc29c468d136ba88c99e3e79c..15ab22b4ba76b8067d0394ee102385ae36fcd7fd 100644 (file)
 #include "tsan_report.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
 
 namespace __tsan {
 
+class Decorator: private __sanitizer::AnsiColorDecorator {
+ public:
+  Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+  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)
-    , sleep() {
+    , sleep()
+    , count() {
 }
 
 ReportMop::ReportMop()
@@ -44,6 +63,8 @@ const char *thread_name(char *buf, int tid) {
 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 == ReportTypeThreadLeak)
@@ -92,18 +113,24 @@ static const char *MopDesc(bool first, bool write, bool atomic) {
 }
 
 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) {
     Printf("  Location is global '%s' of size %zu at %zx (%s+%p)\n\n",
                loc->name, loc->size, loc->addr, loc->module, loc->offset);
@@ -111,7 +138,7 @@ static void PrintLocation(const ReportLocation *loc) {
     char thrbuf[kThreadBufSize];
     Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
         loc->size, loc->addr, thread_name(thrbuf, loc->tid));
-    PrintStack(loc->stack);
+    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) {
@@ -119,24 +146,34 @@ static void PrintLocation(const ReportLocation *loc) {
   } else if (loc->type == ReportLocationFD) {
     Printf("  Location is file descriptor %d created by %s at:\n",
         loc->fd, thread_name(thrbuf, loc->tid));
-    PrintStack(loc->stack);
+    print_stack = true;
   }
+  Printf("%s", d.EndLocation());
+  if (print_stack)
+    PrintStack(loc->stack);
 }
 
 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 created at:\n", rm->id);
+    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)
+  if (rt->name && rt->name[0] != '\0')
     Printf(" '%s'", rt->name);
   char thrbuf[kThreadBufSize];
   Printf(" (tid=%zu, %s) created by %s",
@@ -145,11 +182,15 @@ static void PrintThread(const ReportThread *rt) {
   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);
 }
 
@@ -172,9 +213,13 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
 }
 
 void PrintReport(const ReportDesc *rep) {
+  Decorator d;
   Printf("==================\n");
   const char *rep_typ_str = ReportTypeString(rep->typ);
-  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
+  Printf("%s", d.Warning());
+  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
+         (int)internal_getpid());
+  Printf("%s", d.EndWarning());
 
   for (uptr i = 0; i < rep->stacks.Size(); i++) {
     if (i)
@@ -197,37 +242,46 @@ void PrintReport(const ReportDesc *rep) {
   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 *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
     ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
 
   Printf("==================\n");
 }
 
-#else
+#else  // #ifndef TSAN_GO
+
+const int kMainThreadId = 1;
 
 void PrintStack(const ReportStack *ent) {
   if (ent == 0) {
-    Printf("  [failed to restore the stack]\n\n");
+    Printf("  [failed to restore the stack]\n");
     return;
   }
   for (int i = 0; ent; ent = ent->next, i++) {
     Printf("  %s()\n      %s:%d +0x%zx\n",
         ent->func, ent->file, ent->line, (void*)ent->offset);
   }
-  Printf("\n");
 }
 
 static void PrintMop(const ReportMop *mop, bool first) {
-  Printf("%s by goroutine %d:\n",
+  Printf("\n");
+  Printf("%s by ",
       (first ? (mop->write ? "Write" : "Read")
-             : (mop->write ? "Previous write" : "Previous read")),
-      mop->tid);
+             : (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 == 0)  // Little sense in describing the main thread.
+  if (rt->id == kMainThreadId)
     return;
+  Printf("\n");
   Printf("Goroutine %d (%s) created at:\n",
     rt->id, rt->running ? "running" : "finished");
   PrintStack(rt->stack);
@@ -235,7 +289,7 @@ static void PrintThread(const ReportThread *rt) {
 
 void PrintReport(const ReportDesc *rep) {
   Printf("==================\n");
-  Printf("WARNING: DATA RACE\n");
+  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++)
index eae2b3c721f677b4ab879a4caeef406af709cd73..c0eef9eb023b5fe3b880b82c80345e9761d594ce 100644 (file)
@@ -18,6 +18,7 @@ namespace __tsan {
 
 enum ReportType {
   ReportTypeRace,
+  ReportTypeVptrRace,
   ReportTypeUseAfterFree,
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
@@ -99,6 +100,7 @@ class ReportDesc {
   Vector<ReportMutex*> mutexes;
   Vector<ReportThread*> threads;
   ReportStack *sleep;
+  int count;
 
   ReportDesc();
   ~ReportDesc();
index 673a355f1dc3f6e5d41fb237537e1f6d229d0593..7f18064e957d16a29f032c07cd16b260dff4bd74 100644 (file)
@@ -21,6 +21,7 @@
 #include "tsan_rtl.h"
 #include "tsan_mman.h"
 #include "tsan_suppressions.h"
+#include "tsan_symbolize.h"
 
 volatile int __tsan_resumed = 0;
 
@@ -45,15 +46,33 @@ Context *CTX() {
   return ctx;
 }
 
+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));
+  MapThreadTrace(GetThreadTraceHeader(tid), sizeof(Trace));
+  new(ThreadTrace(tid)) Trace();
+  void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
+  return new(mem) ThreadContext(tid);
+}
+
+#ifndef TSAN_GO
+static const u32 kThreadQuarantineSize = 16;
+#else
+static const u32 kThreadQuarantineSize = 64;
+#endif
+
 Context::Context()
   : initialized()
   , report_mtx(MutexTypeReport, StatMtxReport)
   , nreported()
   , nmissed_expected()
-  , thread_mtx(MutexTypeThreads, StatMtxThreads)
+  , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
+      CreateThreadContext, kMaxTid, kThreadQuarantineSize))
   , racy_stacks(MBlockRacyStacks)
   , racy_addresses(MBlockRacyAddresses)
-  , fired_suppressions(MBlockRacyAddresses) {
+  , fired_suppressions(8) {
 }
 
 // The objects are allocated in TLS, so one may rely on zero-initialization.
@@ -63,10 +82,12 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
   : fast_state(tid, epoch)
   // Do not touch these, rely on zero initialization,
   // they may be accessed before the ctor.
-  // , fast_ignore_reads()
-  // , fast_ignore_writes()
+  // , ignore_reads_and_writes()
   // , in_rtl()
   , shadow_stack_pos(&shadow_stack[0])
+#ifndef TSAN_GO
+  , jmp_bufs(MBlockJmpBuf)
+#endif
   , tid(tid)
   , unique_id(unique_id)
   , stk_addr(stk_addr)
@@ -75,94 +96,74 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
   , tls_size(tls_size) {
 }
 
-ThreadContext::ThreadContext(int tid)
-  : tid(tid)
-  , unique_id()
-  , os_id()
-  , user_id()
-  , thr()
-  , status(ThreadStatusInvalid)
-  , detached()
-  , reuse_count()
-  , epoch0()
-  , epoch1()
-  , dead_info()
-  , dead_next()
-  , name() {
-}
-
-static void WriteMemoryProfile(char *buf, uptr buf_size, int num) {
-  uptr shadow = GetShadowMemoryConsumption();
-
-  int nthread = 0;
-  int nlivethread = 0;
-  uptr threadmem = 0;
-  {
-    Lock l(&ctx->thread_mtx);
-    for (unsigned i = 0; i < kMaxTid; i++) {
-      ThreadContext *tctx = ctx->threads[i];
-      if (tctx == 0)
-        continue;
-      nthread += 1;
-      threadmem += sizeof(ThreadContext);
-      if (tctx->status != ThreadStatusRunning)
-        continue;
-      nlivethread += 1;
-      threadmem += sizeof(ThreadState);
-    }
-  }
-
-  uptr nsync = 0;
-  uptr syncmem = CTX()->synctab.GetMemoryConsumption(&nsync);
-
-  internal_snprintf(buf, buf_size, "%d: shadow=%zuMB"
-                                   " thread=%zuMB(total=%d/live=%d)"
-                                   " sync=%zuMB(cnt=%zu)\n",
-    num,
-    shadow >> 20,
-    threadmem >> 20, nthread, nlivethread,
-    syncmem >> 20, nsync);
+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);
+  internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
+      i, n_threads, n_running_threads);
+  internal_write(fd, buf.data(), internal_strlen(buf.data()));
+  WriteMemoryProfile(buf.data(), buf.size());
+  internal_write(fd, buf.data(), internal_strlen(buf.data()));
 }
 
-static void MemoryProfileThread(void *arg) {
+static void BackgroundThread(void *arg) {
   ScopedInRtl in_rtl;
-  fd_t fd = (fd_t)(uptr)arg;
+  Context *ctx = CTX();
+  const u64 kMs2Ns = 1000 * 1000;
+
+  fd_t mprof_fd = kInvalidFd;
+  if (flags()->profile_memory && flags()->profile_memory[0]) {
+    InternalScopedBuffer<char> filename(4096);
+    internal_snprintf(filename.data(), filename.size(), "%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();
   for (int i = 0; ; i++) {
-    InternalScopedBuffer<char> buf(4096);
-    WriteMemoryProfile(buf.data(), buf.size(), i);
-    internal_write(fd, buf.data(), internal_strlen(buf.data()));
     SleepForSeconds(1);
-  }
-}
+    u64 now = NanoTime();
+
+    // Flush memory if requested.
+    if (flags()->flush_memory_ms) {
+      if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
+        FlushShadowMemory();
+        last_flush = NanoTime();
+      }
+    }
 
-static void InitializeMemoryProfile() {
-  if (flags()->profile_memory == 0 || flags()->profile_memory[0] == 0)
-    return;
-  InternalScopedBuffer<char> filename(4096);
-  internal_snprintf(filename.data(), filename.size(), "%s.%d",
-      flags()->profile_memory, GetPid());
-  fd_t fd = OpenFile(filename.data(), true);
-  if (fd == kInvalidFd) {
-    Printf("Failed to open memory profile file '%s'\n", &filename[0]);
-    Die();
-  }
-  internal_start_thread(&MemoryProfileThread, (void*)(uptr)fd);
-}
+    // Write memory profile if requested.
+    if (mprof_fd != kInvalidFd)
+      MemoryProfiler(ctx, mprof_fd, i);
 
-static void MemoryFlushThread(void *arg) {
-  ScopedInRtl in_rtl;
-  for (int i = 0; ; i++) {
-    SleepForMillis(flags()->flush_memory_ms);
-    FlushShadowMemory();
+#ifndef TSAN_GO
+    // 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);
+      }
+    }
+#endif
   }
 }
 
-static void InitializeMemoryFlush() {
-  if (flags()->flush_memory_ms == 0)
-    return;
-  if (flags()->flush_memory_ms < 100)
-    flags()->flush_memory_ms = 100;
-  internal_start_thread(&MemoryFlushThread, 0);
+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) {
@@ -201,9 +202,6 @@ void Initialize(ThreadState *thr) {
 #ifndef TSAN_GO
   InitializeShadowMemory();
 #endif
-  ctx->dead_list_size = 0;
-  ctx->dead_list_head = 0;
-  ctx->dead_list_tail = 0;
   InitializeFlags(&ctx->flags, env);
   // Setup correct file descriptor for error reports.
   if (internal_strcmp(flags()->log_path, "stdout") == 0)
@@ -217,32 +215,30 @@ void Initialize(ThreadState *thr) {
   // Initialize external symbolizer before internal threads are started.
   const char *external_symbolizer = flags()->external_symbolizer_path;
   if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
-    if (!InitializeExternalSymbolizer(external_symbolizer)) {
+    if (!getSymbolizer()->InitializeExternal(external_symbolizer)) {
       Printf("Failed to start external symbolizer: '%s'\n",
              external_symbolizer);
       Die();
     }
   }
 #endif
-  InitializeMemoryProfile();
-  InitializeMemoryFlush();
+  internal_start_thread(&BackgroundThread, 0);
 
   if (ctx->flags.verbosity)
     Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
-               GetPid());
+           (int)internal_getpid());
 
   // Initialize thread 0.
-  ctx->thread_seq = 0;
   int tid = ThreadCreate(thr, 0, 0, true);
   CHECK_EQ(tid, 0);
-  ThreadStart(thr, tid, GetPid());
+  ThreadStart(thr, tid, internal_getpid());
   CHECK_EQ(thr->in_rtl, 1);
   ctx->initialized = true;
 
   if (flags()->stop_on_start) {
     Printf("ThreadSanitizer is suspended at startup (pid %d)."
            " Call __tsan_resume().\n",
-           GetPid());
+           (int)internal_getpid());
     while (__tsan_resumed == 0) {}
   }
 }
@@ -257,6 +253,8 @@ int Finalize(ThreadState *thr) {
 
   // Wait for pending reports.
   ctx->report_mtx.Lock();
+  CommonSanitizerReportMutex.Lock();
+  CommonSanitizerReportMutex.Unlock();
   ctx->report_mtx.Unlock();
 
 #ifndef TSAN_GO
@@ -281,6 +279,13 @@ int Finalize(ThreadState *thr) {
         ctx->nmissed_expected);
   }
 
+  if (flags()->print_suppressions)
+    PrintMatchedSuppressions();
+#ifndef TSAN_GO
+  if (flags()->print_benign)
+    PrintMatchedBenignRaces();
+#endif
+
   failed = OnFinalize(failed);
 
   StatAggregate(ctx->stat, thr->stat);
@@ -307,15 +312,20 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) {
 void TraceSwitch(ThreadState *thr) {
   thr->nomalloc++;
   ScopedInRtl in_rtl;
-  Lock l(&thr->trace.mtx);
+  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];
+  TraceHeader *hdr = &thr_trace->headers[trace];
   hdr->epoch0 = thr->fast_state.epoch();
   hdr->stack0.ObtainCurrent(thr, 0);
   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()];
@@ -341,18 +351,18 @@ extern "C" void __tsan_report_race() {
 #endif
 
 ALWAYS_INLINE
-static Shadow LoadShadow(u64 *p) {
+Shadow LoadShadow(u64 *p) {
   u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed);
   return Shadow(raw);
 }
 
 ALWAYS_INLINE
-static void StoreShadow(u64 *sp, u64 s) {
+void StoreShadow(u64 *sp, u64 s) {
   atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed);
 }
 
 ALWAYS_INLINE
-static void StoreIfNotYetStored(u64 *sp, u64 *s) {
+void StoreIfNotYetStored(u64 *sp, u64 *s) {
   StoreShadow(sp, *s);
   *s = 0;
 }
@@ -377,7 +387,7 @@ static inline bool HappensBefore(Shadow old, ThreadState *thr) {
   return thr->clock.get(old.TidWithIgnore()) >= old.epoch();
 }
 
-ALWAYS_INLINE
+ALWAYS_INLINE USED
 void MemoryAccessImpl(ThreadState *thr, uptr addr,
     int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
     u64 *shadow_mem, Shadow cur) {
@@ -451,7 +461,28 @@ void MemoryAccessImpl(ThreadState *thr, uptr addr,
   return;
 }
 
-ALWAYS_INLINE
+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 + 8) & ~7)) {
+      size1 = 8;
+      kAccessSizeLog = kSizeLog8;
+    } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
+      size1 = 4;
+      kAccessSizeLog = kSizeLog4;
+    } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
+      size1 = 2;
+      kAccessSizeLog = kSizeLog2;
+    }
+    MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic);
+    addr += size1;
+    size -= size1;
+  }
+}
+
+ALWAYS_INLINE USED
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
     int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
   u64 *shadow_mem = (u64*)MemToShadow(addr);
@@ -472,6 +503,16 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
   }
 #endif
 
+  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, 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())
     return;
@@ -492,6 +533,8 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
 
 static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
                            u64 val) {
+  (void)thr;
+  (void)pc;
   if (size == 0)
     return;
   // FIXME: fix me.
@@ -508,23 +551,44 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
   // let it just crash as usual.
   if (!IsAppMem(addr) || !IsAppMem(addr + size - 1))
     return;
-  (void)thr;
-  (void)pc;
-  // Some programs mmap like hundreds of GBs but actually used a small part.
-  // So, it's better to report a false positive on the memory
-  // then to hang here senselessly.
-  const uptr kMaxResetSize = 4ull*1024*1024*1024;
-  if (size > kMaxResetSize)
-    size = kMaxResetSize;
+  // 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);
-  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 * kShadowCnt / kShadowCell;) {
-    p[i++] = val;
-    for (uptr j = 1; j < kShadowCnt; j++)
-      p[i++] = 0;
+  // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
+  // so we do it only for C/C++.
+  if (kGoMode || size < 64*1024) {
+    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 = 4096;
+    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;
+    }
   }
 }
 
@@ -533,10 +597,17 @@ void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) {
 }
 
 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;
+  thr->fast_state.IncrementEpoch();
+  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
   Shadow s(thr->fast_state);
   s.ClearIgnoreBit();
   s.MarkAsFreed();
@@ -546,6 +617,8 @@ void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
 }
 
 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+  thr->fast_state.IncrementEpoch();
+  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
   Shadow s(thr->fast_state);
   s.ClearIgnoreBit();
   s.SetWrite(true);
@@ -553,7 +626,7 @@ void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
   MemoryRangeSet(thr, pc, addr, size, s.raw());
 }
 
-ALWAYS_INLINE
+ALWAYS_INLINE USED
 void FuncEntry(ThreadState *thr, uptr pc) {
   DCHECK_EQ(thr->in_rtl, 0);
   StatInc(thr, StatFuncEnter);
@@ -583,7 +656,7 @@ void FuncEntry(ThreadState *thr, uptr pc) {
   thr->shadow_stack_pos++;
 }
 
-ALWAYS_INLINE
+ALWAYS_INLINE USED
 void FuncExit(ThreadState *thr) {
   DCHECK_EQ(thr->in_rtl, 0);
   StatInc(thr, StatFuncExit);
@@ -598,13 +671,18 @@ void FuncExit(ThreadState *thr) {
   thr->shadow_stack_pos--;
 }
 
-void IgnoreCtl(ThreadState *thr, bool write, bool begin) {
-  DPrintf("#%d: IgnoreCtl(%d, %d)\n", thr->tid, write, begin);
-  thr->ignore_reads_and_writes += begin ? 1 : -1;
+void ThreadIgnoreBegin(ThreadState *thr) {
+  DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid);
+  thr->ignore_reads_and_writes++;
   CHECK_GE(thr->ignore_reads_and_writes, 0);
-  if (thr->ignore_reads_and_writes)
-    thr->fast_state.SetIgnoreBit();
-  else
+  thr->fast_state.SetIgnoreBit();
+}
+
+void ThreadIgnoreEnd(ThreadState *thr) {
+  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();
 }
 
index e939921049a7c253c1085fdd268789627fbfca82..2548f67b25c9555e2b831a6cba9d7d1ffac8eba1 100644 (file)
 #ifndef TSAN_RTL_H
 #define TSAN_RTL_H
 
-#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.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"
@@ -44,15 +47,73 @@ namespace __tsan {
 
 // Descriptor of user's memory block.
 struct MBlock {
-  Mutex mtx;
-  uptr size;
-  u32 alloc_tid;
-  u32 alloc_stack_id;
-  SyncVar *head;
+  /*
+  u64 mtx : 1;  // must be first
+  u64 lst : 44;
+  u64 stk : 31;  // on word boundary
+  u64 tid : kTidBits;
+  u64 siz : 128 - 1 - 31 - 44 - kTidBits;  // 39
+  */
+  u64 raw[2];
+
+  void Init(uptr siz, u32 tid, u32 stk) {
+    raw[0] = raw[1] = 0;
+    raw[1] |= (u64)siz << ((1 + 44 + 31 + kTidBits) % 64);
+    raw[1] |= (u64)tid << ((1 + 44 + 31) % 64);
+    raw[0] |= (u64)stk << (1 + 44);
+    raw[1] |= (u64)stk >> (64 - 44 - 1);
+    DCHECK_EQ(Size(), siz);
+    DCHECK_EQ(Tid(), tid);
+    DCHECK_EQ(StackId(), stk);
+  }
+
+  u32 Tid() const {
+    return GetLsb(raw[1] >> ((1 + 44 + 31) % 64), kTidBits);
+  }
+
+  uptr Size() const {
+    return raw[1] >> ((1 + 31 + 44 + kTidBits) % 64);
+  }
+
+  u32 StackId() const {
+    return (raw[0] >> (1 + 44)) | GetLsb(raw[1] << (64 - 44 - 1), 31);
+  }
 
-  MBlock()
-    : mtx(MutexTypeMBlock, StatMtxMBlock) {
+  SyncVar *ListHead() const {
+    return (SyncVar*)(GetLsb(raw[0] >> 1, 44) << 3);
   }
+
+  void ListPush(SyncVar *v) {
+    SyncVar *lst = ListHead();
+    v->next = lst;
+    u64 x = (u64)v ^ (u64)lst;
+    x = (x >> 3) << 1;
+    raw[0] ^= x;
+    DCHECK_EQ(ListHead(), v);
+  }
+
+  SyncVar *ListPop() {
+    SyncVar *lst = ListHead();
+    SyncVar *nxt = lst->next;
+    lst->next = 0;
+    u64 x = (u64)lst ^ (u64)nxt;
+    x = (x >> 3) << 1;
+    raw[0] ^= x;
+    DCHECK_EQ(ListHead(), nxt);
+    return lst;
+  }
+
+  void ListReset() {
+    SyncVar *lst = ListHead();
+    u64 x = (u64)lst;
+    x = (x >> 3) << 1;
+    raw[0] ^= x;
+    DCHECK_EQ(ListHead(), 0);
+  }
+
+  void Lock();
+  void Unlock();
+  typedef GenericScopedLock<MBlock> ScopedLock;
 };
 
 #ifndef TSAN_GO
@@ -63,22 +124,11 @@ const uptr kAllocatorSpace = 0x7d0000000000ULL;
 #endif
 const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
 
-struct TsanMapUnmapCallback {
-  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.
-    uptr shadow_beg = MemToShadow(p);
-    uptr shadow_end = MemToShadow(p + size);
-    CHECK(IsAligned(shadow_end|shadow_beg, GetPageSizeCached()));
-    FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
-  }
-};
-
+struct MapUnmapCallback;
 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, sizeof(MBlock),
-    DefaultSizeClassMap> PrimaryAllocator;
+    DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<TsanMapUnmapCallback> SecondaryAllocator;
+typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
 typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
     SecondaryAllocator> Allocator;
 Allocator *allocator();
@@ -87,6 +137,8 @@ Allocator *allocator();
 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
@@ -332,6 +384,12 @@ class Shadow : public FastState {
 
 struct SignalContext;
 
+struct JmpBuf {
+  uptr sp;
+  uptr mangled_sp;
+  uptr *shadow_stack_pos;
+};
+
 // This struct is stored in TLS.
 struct ThreadState {
   FastState fast_state;
@@ -354,7 +412,6 @@ struct ThreadState {
   uptr *shadow_stack_pos;
   u64 *racy_shadow_addr;
   u64 racy_state[2];
-  Trace trace;
 #ifndef TSAN_GO
   // C/C++ uses embed shadow stack of fixed size.
   uptr shadow_stack[kShadowStackSize];
@@ -367,6 +424,8 @@ struct ThreadState {
   ThreadClock clock;
 #ifndef TSAN_GO
   AllocatorCache alloc_cache;
+  InternalAllocatorCache internal_alloc_cache;
+  Vector<JmpBuf> jmp_bufs;
 #endif
   u64 stat[StatCnt];
   const int tid;
@@ -375,6 +434,7 @@ struct ThreadState {
   bool in_symbolizer;
   bool is_alive;
   bool is_freeing;
+  bool is_vptr_access;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
@@ -408,41 +468,30 @@ INLINE ThreadState *cur_thread() {
 }
 #endif
 
-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 (trace) is still alive.
-};
-
-// An info about a thread that is hold for some time after its termination.
-struct ThreadDeadInfo {
-  Trace trace;
-};
-
-struct ThreadContext {
-  const int tid;
-  int unique_id;  // Non-rolling thread id.
-  uptr os_id;  // pid
-  uptr user_id;  // Some opaque user thread id (e.g. pthread_t).
+class ThreadContext : public ThreadContextBase {
+ public:
+  explicit ThreadContext(int tid);
+  ~ThreadContext();
   ThreadState *thr;
-  ThreadStatus status;
-  bool detached;
-  int reuse_count;
+#ifdef TSAN_GO
+  StackTrace creation_stack;
+#else
+  u32 creation_stack_id;
+#endif
   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;
-  StackTrace creation_stack;
-  int creation_tid;
-  ThreadDeadInfo *dead_info;
-  ThreadContext *dead_next;  // In dead thread list.
-  char *name;  // As annotated by user.
 
-  explicit ThreadContext(int tid);
+  // Override superclass callbacks.
+  void OnDead();
+  void OnJoined(void *arg);
+  void OnFinished();
+  void OnStarted(void *arg);
+  void OnCreated(void *arg);
+  void OnReset();
 };
 
 struct RacyStacks {
@@ -464,6 +513,7 @@ struct RacyAddress {
 struct FiredSuppression {
   ReportType type;
   uptr pc;
+  Suppression *supp;
 };
 
 struct Context {
@@ -476,20 +526,14 @@ struct Context {
   Mutex report_mtx;
   int nreported;
   int nmissed_expected;
+  atomic_uint64_t last_symbolize_time_ns;
 
-  Mutex thread_mtx;
-  unsigned thread_seq;
-  unsigned unique_thread_seq;
-  int alive_threads;
-  int max_alive_threads;
-  ThreadContext *threads[kMaxTid];
-  int dead_list_size;
-  ThreadContext* dead_list_head;
-  ThreadContext* dead_list_tail;
+  ThreadRegistry *thread_registry;
 
   Vector<RacyStacks> racy_stacks;
   Vector<RacyAddress> racy_addresses;
-  Vector<FiredSuppression> fired_suppressions;
+  // Number of fired suppressions may be large enough.
+  InternalMmapVector<FiredSuppression> fired_suppressions;
 
   Flags flags;
 
@@ -520,6 +564,7 @@ class ScopedReport {
   void AddMutex(const SyncVar *s);
   void AddLocation(uptr addr, uptr size);
   void AddSleep(u32 stack_id);
+  void SetCount(int count);
 
   const ReportDesc *GetReport() const;
 
@@ -537,13 +582,18 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset);
 
 void StatAggregate(u64 *dst, u64 *src);
 void StatOutput(u64 *stat);
-void ALWAYS_INLINE INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
+void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
   if (kCollectStats)
     thr->stat[typ] += n;
 }
+void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) {
+  if (kCollectStats)
+    thr->stat[typ] = n;
+}
 
 void MapShadow(uptr addr, uptr size);
 void MapThreadTrace(uptr addr, uptr size);
+void DontNeedShadowFor(uptr addr, uptr size);
 void InitializeShadowMemory();
 void InitializeInterceptors();
 void InitializeDynamicAnnotations();
@@ -552,11 +602,13 @@ void ReportRace(ThreadState *thr);
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
                   const ReportStack *suppress_stack1 = 0,
-                  const ReportStack *suppress_stack2 = 0);
+                  const ReportStack *suppress_stack2 = 0,
+                  const ReportLocation *suppress_loc = 0);
 bool IsFiredSuppression(Context *ctx,
                         const ScopedReport &srep,
                         const StackTrace &trace);
 bool IsExpectedReport(uptr addr, uptr size);
+void PrintMatchedBenignRaces();
 bool FrameIsInternal(const ReportStack *frame);
 ReportStack *SkipTsanInternalFrames(ReportStack *ent);
 
@@ -592,28 +644,30 @@ 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 INLINE MemoryRead(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryRead(ThreadState *thr, uptr pc,
                                      uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
 }
 
-void ALWAYS_INLINE INLINE MemoryWrite(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryWrite(ThreadState *thr, uptr pc,
                                       uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false);
 }
 
-void ALWAYS_INLINE INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
                                            uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
 }
 
-void ALWAYS_INLINE INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
                                             uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
 }
@@ -621,7 +675,8 @@ void ALWAYS_INLINE INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
 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 IgnoreCtl(ThreadState *thr, bool write, bool begin);
+void ThreadIgnoreBegin(ThreadState *thr);
+void ThreadIgnoreEnd(ThreadState *thr);
 
 void FuncEntry(ThreadState *thr, uptr pc);
 void FuncExit(ThreadState *thr);
@@ -640,8 +695,8 @@ 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);
-void MutexUnlock(ThreadState *thr, uptr pc, uptr addr);
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1);
+int  MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
@@ -677,9 +732,10 @@ 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 INLINE TraceAddEvent(ThreadState *thr, FastState fs,
+void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
                                         EventType typ, u64 addr) {
   DCHECK_GE((int)typ, 0);
   DCHECK_LE((int)typ, 7);
index 22a71503c5c484bfeb1d5a8642fd729675a80e9f..d274a7a8cc504dcf9db0ea98d61639a71d6d370a 100644 (file)
@@ -61,7 +61,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
       && s->owner_tid != SyncVar::kInvalidTid
       && !s->is_broken) {
     s->is_broken = true;
-    Lock l(&ctx->thread_mtx);
+    ThreadRegistryLock l(ctx->thread_registry);
     ScopedReport rep(ReportTypeMutexDestroyLocked);
     rep.AddMutex(s);
     StackTrace trace;
@@ -77,9 +77,10 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
   DestroyAndFree(s);
 }
 
-void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
   CHECK_GT(thr->in_rtl, 0);
-  DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
+  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()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
@@ -92,7 +93,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
   } else if (s->owner_tid == thr->tid) {
     CHECK_GT(s->recursion, 0);
   } else {
-    Printf("ThreadSanitizer WARNING: double lock\n");
+    Printf("ThreadSanitizer WARNING: double lock of mutex %p\n", addr);
     PrintCurrentStack(thr, pc);
   }
   if (s->recursion == 0) {
@@ -105,33 +106,36 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
   } else if (!s->is_recursive) {
     StatInc(thr, StatMutexRecLock);
   }
-  s->recursion++;
+  s->recursion += rec;
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
   s->mtx.Unlock();
 }
 
-void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
+int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
   CHECK_GT(thr->in_rtl, 0);
-  DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
+  DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
   if (IsAppMem(addr))
     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
+  int rec = 0;
   if (s->recursion == 0) {
     if (!s->is_broken) {
       s->is_broken = true;
-      Printf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
+      Printf("ThreadSanitizer WARNING: unlock of unlocked mutex %p\n", addr);
       PrintCurrentStack(thr, pc);
     }
   } else if (s->owner_tid != thr->tid) {
     if (!s->is_broken) {
       s->is_broken = true;
-      Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
+      Printf("ThreadSanitizer WARNING: mutex %p is unlocked by wrong thread\n",
+             addr);
       PrintCurrentStack(thr, pc);
     }
   } else {
-    s->recursion--;
+    rec = all ? s->recursion : 1;
+    s->recursion -= rec;
     if (s->recursion == 0) {
       StatInc(thr, StatMutexUnlock);
       s->owner_tid = SyncVar::kInvalidTid;
@@ -145,6 +149,7 @@ void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
   }
   thr->mset.Del(s->GetId(), true);
   s->mtx.Unlock();
+  return rec;
 }
 
 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
@@ -157,7 +162,8 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
   if (s->owner_tid != SyncVar::kInvalidTid) {
-    Printf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
+    Printf("ThreadSanitizer WARNING: read lock of a write locked mutex %p\n",
+           addr);
     PrintCurrentStack(thr, pc);
   }
   thr->clock.set(thr->tid, thr->fast_state.epoch());
@@ -178,8 +184,8 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
   if (s->owner_tid != SyncVar::kInvalidTid) {
-    Printf("ThreadSanitizer WARNING: read unlock of a write "
-               "locked mutex\n");
+    Printf("ThreadSanitizer WARNING: read unlock of a write locked mutex %p\n",
+           addr);
     PrintCurrentStack(thr, pc);
   }
   thr->clock.set(thr->tid, thr->fast_state.epoch());
@@ -229,7 +235,8 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
     }
   } else if (!s->is_broken) {
     s->is_broken = true;
-    Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
+    Printf("ThreadSanitizer WARNING: mutex %p is unlock by wrong thread\n",
+           addr);
     PrintCurrentStack(thr, pc);
   }
   thr->mset.Del(s->GetId(), write);
@@ -246,18 +253,19 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr) {
   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) {
-  Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  for (unsigned i = 0; i < kMaxTid; i++) {
-    ThreadContext *tctx = ctx->threads[i];
-    if (tctx == 0)
-      continue;
-    if (tctx->status == ThreadStatusRunning)
-      thr->clock.set(i, tctx->thr->fast_state.epoch());
-    else
-      thr->clock.set(i, tctx->epoch1);
-  }
+  ThreadRegistryLock l(CTX()->thread_registry);
+  CTX()->thread_registry->RunCallbackForEachThreadLocked(
+      UpdateClockCallback, thr);
 }
 
 void Release(ThreadState *thr, uptr pc, uptr addr) {
@@ -281,19 +289,20 @@ void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
 }
 
 #ifndef TSAN_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) {
-  Context *ctx = CTX();
   thr->last_sleep_stack_id = CurrentStackId(thr, pc);
-  Lock l(&ctx->thread_mtx);
-  for (unsigned i = 0; i < kMaxTid; i++) {
-    ThreadContext *tctx = ctx->threads[i];
-    if (tctx == 0)
-      continue;
-    if (tctx->status == ThreadStatusRunning)
-      thr->last_sleep_clock.set(i, tctx->thr->fast_state.epoch());
-    else
-      thr->last_sleep_clock.set(i, tctx->epoch1);
-  }
+  ThreadRegistryLock l(CTX()->thread_registry);
+  CTX()->thread_registry->RunCallbackForEachThreadLocked(
+      UpdateSleepClockCallback, thr);
 }
 #endif
 
index ff1d43bc9e8afdf6cf7cf42fa14c3f34864869f8..7c0a0280071e6ff5fb5128ae6d7dfea7857d3fbd 100644 (file)
@@ -93,8 +93,9 @@ static void StackStripMain(ReportStack *stack) {
     DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
   }
 #else
-  if (last && 0 == internal_strcmp(last, "schedunlock"))
-    last_frame2->next = 0;
+  // The last frame always point into runtime (gosched0, goexit0, runtime.main).
+  last_frame2->next = 0;
+  (void)last;
 #endif
 }
 
@@ -103,17 +104,25 @@ static ReportStack *SymbolizeStack(const StackTrace& trace) {
     return 0;
   ReportStack *stack = 0;
   for (uptr si = 0; si < trace.Size(); si++) {
+    const uptr pc = trace.Get(si);
+#ifndef TSAN_GO
     // We obtain the return address, that is, address of the next instruction,
     // so offset it by 1 byte.
-    bool is_last = (si == trace.Size() - 1);
-    ReportStack *ent = SymbolizeCode(trace.Get(si) - !is_last);
+    const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
+#else
+    // FIXME(dvyukov): Go sometimes uses address of a function as top pc.
+    uptr pc1 = pc;
+    if (si != trace.Size() - 1)
+      pc1 -= 1;
+#endif
+    ReportStack *ent = SymbolizeCode(pc1);
     CHECK_NE(ent, 0);
     ReportStack *last = ent;
     while (last->next) {
-      last->pc += !is_last;
+      last->pc = pc;  // restore original pc for report
       last = last->next;
     }
-    last->pc += !is_last;
+    last->pc = pc;  // restore original pc for report
     last->next = stack;
     stack = ent;
   }
@@ -123,14 +132,16 @@ static ReportStack *SymbolizeStack(const StackTrace& trace) {
 
 ScopedReport::ScopedReport(ReportType typ) {
   ctx_ = CTX();
-  ctx_->thread_mtx.CheckLocked();
+  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_);
 }
@@ -175,7 +186,7 @@ void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
 
 void ScopedReport::AddThread(const ThreadContext *tctx) {
   for (uptr i = 0; i < rep_->threads.Size(); i++) {
-    if (rep_->threads[i]->id == tctx->tid)
+    if ((u32)rep_->threads[i]->id == tctx->tid)
       return;
   }
   void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
@@ -185,42 +196,65 @@ void ScopedReport::AddThread(const ThreadContext *tctx) {
   rt->pid = tctx->os_id;
   rt->running = (tctx->status == ThreadStatusRunning);
   rt->name = tctx->name ? internal_strdup(tctx->name) : 0;
-  rt->parent_tid = tctx->creation_tid;
+  rt->parent_tid = tctx->parent_tid;
+  rt->stack = 0;
+#ifdef TSAN_GO
   rt->stack = SymbolizeStack(tctx->creation_stack);
+#else
+  uptr ssz = 0;
+  const uptr *stack = StackDepotGet(tctx->creation_stack_id, &ssz);
+  if (stack) {
+    StackTrace trace;
+    trace.Init(stack, ssz);
+    rt->stack = SymbolizeStack(trace);
+  }
+#endif
 }
 
 #ifndef TSAN_GO
-static ThreadContext *FindThread(int unique_id) {
+static ThreadContext *FindThreadByUidLocked(int unique_id) {
   Context *ctx = CTX();
-  ctx->thread_mtx.CheckLocked();
+  ctx->thread_registry->CheckLocked();
   for (unsigned i = 0; i < kMaxTid; i++) {
-    ThreadContext *tctx = ctx->threads[i];
-    if (tctx && tctx->unique_id == unique_id) {
+    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) {
+  Context *ctx = CTX();
+  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) {
   Context *ctx = CTX();
-  ctx->thread_mtx.CheckLocked();
-  for (unsigned i = 0; i < kMaxTid; i++) {
-    ThreadContext *tctx = ctx->threads[i];
-    if (tctx == 0 || tctx->status != ThreadStatusRunning)
-      continue;
-    ThreadState *thr = tctx->thr;
-    CHECK(thr);
-    if (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) {
-      *is_stack = true;
-      return tctx;
-    }
-    if (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size) {
-      *is_stack = false;
-      return tctx;
-    }
-  }
-  return 0;
+  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
 
@@ -234,7 +268,16 @@ void ScopedReport::AddMutex(const SyncVar *s) {
   rep_->mutexes.PushBack(rm);
   rm->id = s->uid;
   rm->destroyed = false;
-  rm->stack = SymbolizeStack(s->creation_stack);
+  rm->stack = 0;
+#ifndef TSAN_GO
+  uptr ssz = 0;
+  const uptr *stack = StackDepotGet(s->creation_stack_id, &ssz);
+  if (stack) {
+    StackTrace trace;
+    trace.Init(stack, ssz);
+    rm->stack = SymbolizeStack(trace);
+  }
+#endif
 }
 
 void ScopedReport::AddMutex(u64 id) {
@@ -272,27 +315,28 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
       trace.Init(stack, ssz);
       loc->stack = SymbolizeStack(trace);
     }
-    ThreadContext *tctx = FindThread(creat_tid);
+    ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
     if (tctx)
       AddThread(tctx);
     return;
   }
-  if (allocator()->PointerIsMine((void*)addr)) {
-    MBlock *b = user_mblock(0, (void*)addr);
-    ThreadContext *tctx = FindThread(b->alloc_tid);
+  MBlock *b = 0;
+  if (allocator()->PointerIsMine((void*)addr)
+      && (b = user_mblock(0, (void*)addr))) {
+    ThreadContext *tctx = FindThreadByTidLocked(b->Tid());
     void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
     ReportLocation *loc = new(mem) ReportLocation();
     rep_->locs.PushBack(loc);
     loc->type = ReportLocationHeap;
     loc->addr = (uptr)allocator()->GetBlockBegin((void*)addr);
-    loc->size = b->size;
-    loc->tid = tctx ? tctx->tid : b->alloc_tid;
+    loc->size = b->Size();
+    loc->tid = tctx ? tctx->tid : b->Tid();
     loc->name = 0;
     loc->file = 0;
     loc->line = 0;
     loc->stack = 0;
     uptr ssz = 0;
-    const uptr *stack = StackDepotGet(b->alloc_stack_id, &ssz);
+    const uptr *stack = StackDepotGet(b->StackId(), &ssz);
     if (stack) {
       StackTrace trace;
       trace.Init(stack, ssz);
@@ -331,6 +375,10 @@ void ScopedReport::AddSleep(u32 stack_id) {
 }
 #endif
 
+void ScopedReport::SetCount(int count) {
+  rep_->count = count;
+}
+
 const ReportDesc *ScopedReport::GetReport() const {
   return rep_;
 }
@@ -339,21 +387,17 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *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.
-  ThreadContext *tctx = CTX()->threads[tid];
+  Context *ctx = CTX();
+  ctx->thread_registry->CheckLocked();
+  ThreadContext *tctx = static_cast<ThreadContext*>(
+      ctx->thread_registry->GetThreadLocked(tid));
   if (tctx == 0)
     return;
-  Trace* trace = 0;
-  if (tctx->status == ThreadStatusRunning) {
-    CHECK(tctx->thr);
-    trace = &tctx->thr->trace;
-  } else if (tctx->status == ThreadStatusFinished
-      || tctx->status == ThreadStatusDead) {
-    if (tctx->dead_info == 0)
-      return;
-    trace = &tctx->dead_info->trace;
-  } else {
+  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];
@@ -464,31 +508,58 @@ static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
                   const ReportStack *suppress_stack1,
-                  const ReportStack *suppress_stack2) {
+                  const ReportStack *suppress_stack2,
+                  const ReportLocation *suppress_loc) {
+  atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
   const ReportDesc *rep = srep.GetReport();
-  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
+  Suppression *supp = 0;
+  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1, &supp);
+  if (suppress_pc == 0)
+    suppress_pc = IsSuppressed(rep->typ, suppress_stack2, &supp);
   if (suppress_pc == 0)
-    suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
+    suppress_pc = IsSuppressed(rep->typ, suppress_loc, &supp);
   if (suppress_pc != 0) {
-    FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
-    ctx->fired_suppressions.PushBack(supp);
+    FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
+    ctx->fired_suppressions.push_back(s);
   }
   if (OnReport(rep, suppress_pc != 0))
     return false;
   PrintReport(rep);
-  CTX()->nreported++;
+  ctx->nreported++;
+  if (flags()->halt_on_error)
+    internal__exit(flags()->exitcode);
   return true;
 }
 
 bool IsFiredSuppression(Context *ctx,
                         const ScopedReport &srep,
                         const StackTrace &trace) {
-  for (uptr k = 0; k < ctx->fired_suppressions.Size(); k++) {
+  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++) {
-      if (trace.Get(j) == ctx->fired_suppressions[k].pc)
+      FiredSuppression *s = &ctx->fired_suppressions[k];
+      if (trace.Get(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;
@@ -525,8 +596,8 @@ static bool IsJavaNonsense(const ReportDesc *rep) {
           || (frame->func == 0 && frame->file == 0 && frame->line == 0
           && frame->module == 0)) {
         if (frame) {
-          FiredSuppression supp = {rep->typ, frame->pc};
-          CTX()->fired_suppressions.PushBack(supp);
+          FiredSuppression supp = {rep->typ, frame->pc, 0};
+          CTX()->fired_suppressions.push_back(supp);
         }
         return true;
       }
@@ -557,10 +628,6 @@ void ReportRace(ThreadState *thr) {
   if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
     return;
 
-  if (thr->in_signal_handler)
-    Printf("ThreadSanitizer: printing report from signal handler."
-           " Can crash or hang.\n");
-
   bool freed = false;
   {
     Shadow s(thr->racy_state[1]);
@@ -583,9 +650,16 @@ void ReportRace(ThreadState *thr) {
   }
 
   Context *ctx = CTX();
-  Lock l0(&ctx->thread_mtx);
-
-  ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace);
+  ThreadRegistryLock l0(ctx->thread_registry);
+
+  ReportType typ = ReportTypeRace;
+  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;
   StackTrace traces[kMop];
   const uptr toppc = TraceTopPC(thr);
@@ -596,6 +670,8 @@ void ReportRace(ThreadState *thr) {
   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;
@@ -611,7 +687,8 @@ void ReportRace(ThreadState *thr) {
 
   for (uptr i = 0; i < kMop; i++) {
     FastState s(thr->racy_state[i]);
-    ThreadContext *tctx = ctx->threads[s.tid()];
+    ThreadContext *tctx = static_cast<ThreadContext*>(
+        ctx->thread_registry->GetThreadLocked(s.tid()));
     if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1)
       continue;
     rep.AddThread(tctx);
@@ -627,8 +704,11 @@ void ReportRace(ThreadState *thr) {
   }
 #endif
 
+  ReportLocation *suppress_loc = rep.GetReport()->locs.Size() ?
+                                 rep.GetReport()->locs[0] : 0;
   if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
-                              rep.GetReport()->mops[1]->stack))
+                              rep.GetReport()->mops[1]->stack,
+                              suppress_loc))
     return;
 
   AddRacyStacks(thr, traces, addr_min, addr_max);
@@ -646,6 +726,11 @@ void PrintCurrentStackSlow() {
       sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
   ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
       kStackTraceMax);
+  for (uptr i = 0; i < ptrace->size / 2; i++) {
+    uptr tmp = ptrace->trace[i];
+    ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
+    ptrace->trace[ptrace->size - i - 1] = tmp;
+  }
   StackTrace trace;
   trace.Init(ptrace->trace, ptrace->size);
   PrintStack(SymbolizeStack(trace));
index e30916dc6272a45128d98de102f560922e96dc4b..9811e1c015fc4408cd1eba4e7717136e8f62fe38 100644 (file)
 
 namespace __tsan {
 
+// ThreadContext implementation.
+
+ThreadContext::ThreadContext(int tid)
+  : ThreadContextBase(tid)
+  , thr()
+  , sync()
+  , epoch0()
+  , epoch1() {
+}
+
 #ifndef TSAN_GO
-const int kThreadQuarantineSize = 16;
-#else
-const int kThreadQuarantineSize = 64;
+ThreadContext::~ThreadContext() {
+}
 #endif
 
-static void MaybeReportThreadLeak(ThreadContext *tctx) {
-  if (tctx->detached)
+void ThreadContext::OnDead() {
+  sync.Reset();
+}
+
+void ThreadContext::OnJoined(void *arg) {
+  ThreadState *caller_thr = static_cast<ThreadState *>(arg);
+  caller_thr->clock.acquire(&sync);
+  StatInc(caller_thr, StatSyncAcquire);
+  sync.Reset();
+}
+
+struct OnCreatedArgs {
+  ThreadState *thr;
+  uptr pc;
+};
+
+void ThreadContext::OnCreated(void *arg) {
+  thr = 0;
+  if (tid == 0)
     return;
-  if (tctx->status != ThreadStatusCreated
-      && tctx->status != ThreadStatusRunning
-      && tctx->status != ThreadStatusFinished)
+  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);
+  args->thr->clock.set(args->thr->tid, args->thr->fast_state.epoch());
+  args->thr->fast_synch_epoch = args->thr->fast_state.epoch();
+  args->thr->clock.release(&sync);
+  StatInc(args->thr, StatSyncRelease);
+#ifdef TSAN_GO
+  creation_stack.ObtainCurrent(args->thr, args->pc);
+#else
+  creation_stack_id = CurrentStackId(args->thr, args->pc);
+#endif
+  if (reuse_count == 0)
+    StatInc(args->thr, StatThreadMaxTid);
+}
+
+void ThreadContext::OnReset() {
+  sync.Reset();
+  FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
+  //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
+}
+
+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, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
+#ifdef TSAN_GO
+  // Setup dynamic shadow stack.
+  const int kInitStackSize = 8;
+  args->thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+      kInitStackSize * sizeof(uptr));
+  args->thr->shadow_stack_pos = thr->shadow_stack;
+  args->thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+#endif
+#ifndef TSAN_GO
+  AllocatorThreadStart(args->thr);
+#endif
+  thr = args->thr;
+  thr->fast_synch_epoch = epoch0;
+  thr->clock.set(tid, epoch0);
+  thr->clock.acquire(&sync);
+  thr->fast_state.SetHistorySize(flags()->history_size);
+  const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
+  Trace *thr_trace = ThreadTrace(thr->tid);
+  thr_trace->headers[trace].epoch0 = epoch0;
+  StatInc(thr, StatSyncAcquire);
+  sync.Reset();
+  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);
+  thr->is_alive = true;
+}
+
+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);
+    thr->clock.set(thr->tid, thr->fast_state.epoch());
+    thr->fast_synch_epoch = thr->fast_state.epoch();
+    thr->clock.release(&sync);
+    StatInc(thr, StatSyncRelease);
+  }
+  epoch1 = thr->fast_state.epoch();
+
+#ifndef TSAN_GO
+  AllocatorThreadFinish(thr);
+#endif
+  thr->~ThreadState();
+  StatAggregate(CTX()->stat, thr->stat);
+  thr = 0;
+}
+
+#ifndef TSAN_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;
-  ScopedReport rep(ReportTypeThreadLeak);
-  rep.AddThread(tctx);
-  OutputReport(CTX(), rep);
+  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
+
+static void ThreadCheckIgnore(ThreadState *thr) {
+  if (thr->ignore_reads_and_writes) {
+    Printf("ThreadSanitizer: thread T%d finished with ignores enabled.\n",
+           thr->tid);
+  }
 }
 
 void ThreadFinalize(ThreadState *thr) {
   CHECK_GT(thr->in_rtl, 0);
+  ThreadCheckIgnore(thr);
+#ifndef TSAN_GO
   if (!flags()->report_thread_leaks)
     return;
-  Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  for (unsigned i = 0; i < kMaxTid; i++) {
-    ThreadContext *tctx = ctx->threads[i];
-    if (tctx == 0)
-      continue;
-    MaybeReportThreadLeak(tctx);
+  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);
+    rep.SetCount(leaks[i].count);
+    OutputReport(CTX(), rep);
   }
+#endif
 }
 
 int ThreadCount(ThreadState *thr) {
   CHECK_GT(thr->in_rtl, 0);
   Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  int cnt = 0;
-  for (unsigned i = 0; i < kMaxTid; i++) {
-    ThreadContext *tctx = ctx->threads[i];
-    if (tctx == 0)
-      continue;
-    if (tctx->status != ThreadStatusCreated
-        && tctx->status != ThreadStatusRunning)
-      continue;
-    cnt++;
-  }
-  return cnt;
-}
-
-static void ThreadDead(ThreadState *thr, ThreadContext *tctx) {
-  Context *ctx = CTX();
-  CHECK_GT(thr->in_rtl, 0);
-  CHECK(tctx->status == ThreadStatusRunning
-      || tctx->status == ThreadStatusFinished);
-  DPrintf("#%d: ThreadDead uid=%zu\n", thr->tid, tctx->user_id);
-  tctx->status = ThreadStatusDead;
-  tctx->user_id = 0;
-  tctx->sync.Reset();
-
-  // Put to dead list.
-  tctx->dead_next = 0;
-  if (ctx->dead_list_size == 0)
-    ctx->dead_list_head = tctx;
-  else
-    ctx->dead_list_tail->dead_next = tctx;
-  ctx->dead_list_tail = tctx;
-  ctx->dead_list_size++;
+  uptr result;
+  ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
+  return (int)result;
 }
 
 int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
   CHECK_GT(thr->in_rtl, 0);
-  Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
   StatInc(thr, StatThreadCreate);
-  int tid = -1;
-  ThreadContext *tctx = 0;
-  if (ctx->dead_list_size > kThreadQuarantineSize
-      || ctx->thread_seq >= kMaxTid) {
-    // Reusing old thread descriptor and tid.
-    if (ctx->dead_list_size == 0) {
-      Printf("ThreadSanitizer: %d thread limit exceeded. Dying.\n",
-                 kMaxTid);
-      Die();
-    }
-    StatInc(thr, StatThreadReuse);
-    tctx = ctx->dead_list_head;
-    ctx->dead_list_head = tctx->dead_next;
-    ctx->dead_list_size--;
-    if (ctx->dead_list_size == 0) {
-      CHECK_EQ(tctx->dead_next, 0);
-      ctx->dead_list_head = 0;
-    }
-    CHECK_EQ(tctx->status, ThreadStatusDead);
-    tctx->status = ThreadStatusInvalid;
-    tctx->reuse_count++;
-    tctx->sync.Reset();
-    tid = tctx->tid;
-    DestroyAndFree(tctx->dead_info);
-    if (tctx->name) {
-      internal_free(tctx->name);
-      tctx->name = 0;
-    }
-  } else {
-    // Allocating new thread descriptor and tid.
-    StatInc(thr, StatThreadMaxTid);
-    tid = ctx->thread_seq++;
-    void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
-    tctx = new(mem) ThreadContext(tid);
-    ctx->threads[tid] = tctx;
-    MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event));
-  }
-  CHECK_NE(tctx, 0);
-  CHECK_GE(tid, 0);
-  CHECK_LT(tid, kMaxTid);
+  Context *ctx = CTX();
+  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);
-  CHECK_EQ(tctx->status, ThreadStatusInvalid);
-  ctx->alive_threads++;
-  if (ctx->max_alive_threads < ctx->alive_threads) {
-    ctx->max_alive_threads++;
-    CHECK_EQ(ctx->max_alive_threads, ctx->alive_threads);
-    StatInc(thr, StatThreadMaxAlive);
-  }
-  tctx->status = ThreadStatusCreated;
-  tctx->thr = 0;
-  tctx->user_id = uid;
-  tctx->unique_id = ctx->unique_thread_seq++;
-  tctx->detached = detached;
-  if (tid) {
-    thr->fast_state.IncrementEpoch();
-    // Can't increment epoch w/o writing to the trace as well.
-    TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
-    thr->clock.set(thr->tid, thr->fast_state.epoch());
-    thr->fast_synch_epoch = thr->fast_state.epoch();
-    thr->clock.release(&tctx->sync);
-    StatInc(thr, StatSyncRelease);
-    tctx->creation_stack.ObtainCurrent(thr, pc);
-    tctx->creation_tid = thr->tid;
-  }
+  StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
   return tid;
 }
 
@@ -168,9 +217,8 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
   GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
 
   if (tid) {
-    if (stk_addr && stk_size) {
-      MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size);
-    }
+    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;
@@ -181,116 +229,42 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
       CHECK_GE(thr_end, tls_addr);
       CHECK_LE(thr_end, tls_addr + tls_size);
       // Since the thr object is huge, skip it.
-      MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
-      MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end);
+      MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
+      MemoryRangeImitateWrite(thr, /*pc=*/ 2,
+          thr_end, tls_addr + tls_size - thr_end);
     }
   }
 
-  Lock l(&CTX()->thread_mtx);
-  ThreadContext *tctx = CTX()->threads[tid];
-  CHECK_NE(tctx, 0);
-  CHECK_EQ(tctx->status, ThreadStatusCreated);
-  tctx->status = ThreadStatusRunning;
-  tctx->os_id = os_id;
-  // RoundUp so that one trace part does not contain events
-  // from different threads.
-  tctx->epoch0 = RoundUp(tctx->epoch1 + 1, kTracePartSize);
-  tctx->epoch1 = (u64)-1;
-  new(thr) ThreadState(CTX(), tid, tctx->unique_id,
-      tctx->epoch0, stk_addr, stk_size,
-      tls_addr, tls_size);
-#ifdef TSAN_GO
-  // 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 TSAN_GO
-  AllocatorThreadStart(thr);
-#endif
-  tctx->thr = thr;
-  thr->fast_synch_epoch = tctx->epoch0;
-  thr->clock.set(tid, tctx->epoch0);
-  thr->clock.acquire(&tctx->sync);
-  thr->fast_state.SetHistorySize(flags()->history_size);
-  const uptr trace = (tctx->epoch0 / kTracePartSize) % TraceParts();
-  thr->trace.headers[trace].epoch0 = tctx->epoch0;
-  StatInc(thr, StatSyncAcquire);
-  DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
-          "tls_addr=%zx tls_size=%zx\n",
-          tid, (uptr)tctx->epoch0, stk_addr, stk_size, tls_addr, tls_size);
-  thr->is_alive = true;
+  OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
+  CTX()->thread_registry->StartThread(tid, os_id, &args);
 }
 
 void ThreadFinish(ThreadState *thr) {
   CHECK_GT(thr->in_rtl, 0);
+  ThreadCheckIgnore(thr);
   StatInc(thr, StatThreadFinish);
-  // FIXME: Treat it as write.
   if (thr->stk_addr && thr->stk_size)
-    MemoryResetRange(thr, /*pc=*/ 3, thr->stk_addr, thr->stk_size);
-  if (thr->tls_addr && thr->tls_size) {
-    const uptr thr_beg = (uptr)thr;
-    const uptr thr_end = (uptr)thr + sizeof(*thr);
-    // Since the thr object is huge, skip it.
-    MemoryResetRange(thr, /*pc=*/ 4, thr->tls_addr, thr_beg - thr->tls_addr);
-    MemoryResetRange(thr, /*pc=*/ 5,
-        thr_end, thr->tls_addr + thr->tls_size - thr_end);
-  }
+    DontNeedShadowFor(thr->stk_addr, thr->stk_size);
+  if (thr->tls_addr && thr->tls_size)
+    DontNeedShadowFor(thr->tls_addr, thr->tls_size);
   thr->is_alive = false;
   Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  ThreadContext *tctx = ctx->threads[thr->tid];
-  CHECK_NE(tctx, 0);
-  CHECK_EQ(tctx->status, ThreadStatusRunning);
-  CHECK_GT(ctx->alive_threads, 0);
-  ctx->alive_threads--;
-  if (tctx->detached) {
-    ThreadDead(thr, tctx);
-  } else {
-    thr->fast_state.IncrementEpoch();
-    // Can't increment epoch w/o writing to the trace as well.
-    TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
-    thr->clock.set(thr->tid, thr->fast_state.epoch());
-    thr->fast_synch_epoch = thr->fast_state.epoch();
-    thr->clock.release(&tctx->sync);
-    StatInc(thr, StatSyncRelease);
-    tctx->status = ThreadStatusFinished;
-  }
+  ctx->thread_registry->FinishThread(thr->tid);
+}
 
-  // Save from info about the thread.
-  tctx->dead_info = new(internal_alloc(MBlockDeadInfo, sizeof(ThreadDeadInfo)))
-      ThreadDeadInfo();
-  for (uptr i = 0; i < TraceParts(); i++) {
-    tctx->dead_info->trace.headers[i].epoch0 = thr->trace.headers[i].epoch0;
-    tctx->dead_info->trace.headers[i].stack0.CopyFrom(
-        thr->trace.headers[i].stack0);
+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;
   }
-  tctx->epoch1 = thr->fast_state.epoch();
-
-#ifndef TSAN_GO
-  AllocatorThreadFinish(thr);
-#endif
-  thr->~ThreadState();
-  StatAggregate(ctx->stat, thr->stat);
-  tctx->thr = 0;
+  return false;
 }
 
 int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
   CHECK_GT(thr->in_rtl, 0);
   Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  int res = -1;
-  for (unsigned tid = 0; tid < kMaxTid; tid++) {
-    ThreadContext *tctx = ctx->threads[tid];
-    if (tctx != 0 && tctx->user_id == uid
-        && tctx->status != ThreadStatusInvalid) {
-      tctx->user_id = 0;
-      res = tid;
-      break;
-    }
-  }
+  int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
   DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
   return res;
 }
@@ -301,18 +275,7 @@ void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
   CHECK_LT(tid, kMaxTid);
   DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
   Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  ThreadContext *tctx = ctx->threads[tid];
-  if (tctx->status == ThreadStatusInvalid) {
-    Printf("ThreadSanitizer: join of non-existent thread\n");
-    return;
-  }
-  // FIXME(dvyukov): print message and continue (it's user error).
-  CHECK_EQ(tctx->detached, false);
-  CHECK_EQ(tctx->status, ThreadStatusFinished);
-  thr->clock.acquire(&tctx->sync);
-  StatInc(thr, StatSyncAcquire);
-  ThreadDead(thr, tctx);
+  ctx->thread_registry->JoinThread(tid, thr);
 }
 
 void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
@@ -320,31 +283,12 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
   CHECK_GT(tid, 0);
   CHECK_LT(tid, kMaxTid);
   Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  ThreadContext *tctx = ctx->threads[tid];
-  if (tctx->status == ThreadStatusInvalid) {
-    Printf("ThreadSanitizer: detach of non-existent thread\n");
-    return;
-  }
-  if (tctx->status == ThreadStatusFinished) {
-    ThreadDead(thr, tctx);
-  } else {
-    tctx->detached = true;
-  }
+  ctx->thread_registry->DetachThread(tid);
 }
 
 void ThreadSetName(ThreadState *thr, const char *name) {
-  Context *ctx = CTX();
-  Lock l(&ctx->thread_mtx);
-  ThreadContext *tctx = ctx->threads[thr->tid];
-  CHECK_NE(tctx, 0);
-  CHECK_EQ(tctx->status, ThreadStatusRunning);
-  if (tctx->name) {
-    internal_free(tctx->name);
-    tctx->name = 0;
-  }
-  if (name)
-    tctx->name = internal_strdup(name);
+  CHECK_GT(thr->in_rtl, 0);
+  CTX()->thread_registry->SetThreadName(thr->tid, name);
 }
 
 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
@@ -379,6 +323,13 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
 
   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;
@@ -421,25 +372,4 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
   }
 }
 
-void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
-    uptr size, uptr step, bool is_write) {
-  if (size == 0)
-    return;
-  FastState fast_state = thr->fast_state;
-  if (fast_state.GetIgnoreBit())
-    return;
-  StatInc(thr, StatMopRange);
-  fast_state.IncrementEpoch();
-  thr->fast_state = fast_state;
-  TraceAddEvent(thr, fast_state, EventTypeMop, pc);
-
-  for (uptr addr_end = addr + size; addr < addr_end; addr += step) {
-    u64 *shadow_mem = (u64*)MemToShadow(addr);
-    Shadow cur(fast_state);
-    cur.SetWrite(is_write);
-    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kSizeLog1);
-    MemoryAccessImpl(thr, addr, kSizeLog1, is_write, false,
-        shadow_mem, cur);
-  }
-}
 }  // namespace __tsan
index fbec4225d9cb79e39fc1a642ed5e56668aa6b3a2..3a3ac1172d89cc8732379c72bf4386c797b455fd 100644 (file)
@@ -36,6 +36,8 @@ void StatOutput(u64 *stat) {
   name[StatMop8]                         = "            size 8                ";
   name[StatMopSame]                      = "  Including same                  ";
   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             ";
@@ -103,6 +105,7 @@ void StatOutput(u64 *stat) {
   name[StatInt_realloc]                  = "  realloc                         ";
   name[StatInt_free]                     = "  free                            ";
   name[StatInt_cfree]                    = "  cfree                           ";
+  name[StatInt_malloc_usable_size]       = "  malloc_usable_size              ";
   name[StatInt_mmap]                     = "  mmap                            ";
   name[StatInt_mmap64]                   = "  mmap64                          ";
   name[StatInt_munmap]                   = "  munmap                          ";
@@ -133,6 +136,9 @@ void StatOutput(u64 *stat) {
   name[StatInt_strcpy]                   = "  strcpy                          ";
   name[StatInt_strncpy]                  = "  strncpy                         ";
   name[StatInt_strstr]                   = "  strstr                          ";
+  name[StatInt_strdup]                   = "  strdup                          ";
+  name[StatInt_strcasecmp]               = "  strcasecmp                      ";
+  name[StatInt_strncasecmp]              = "  strncasecmp                     ";
   name[StatInt_atexit]                   = "  atexit                          ";
   name[StatInt___cxa_guard_acquire]      = "  __cxa_guard_acquire             ";
   name[StatInt___cxa_guard_release]      = "  __cxa_guard_release             ";
@@ -172,6 +178,7 @@ void StatOutput(u64 *stat) {
   name[StatInt_pthread_barrier_destroy]  = "  pthread_barrier_destroy         ";
   name[StatInt_pthread_barrier_wait]     = "  pthread_barrier_wait            ";
   name[StatInt_pthread_once]             = "  pthread_once                    ";
+  name[StatInt_pthread_getschedparam]    = "  pthread_getschedparam           ";
   name[StatInt_sem_init]                 = "  sem_init                        ";
   name[StatInt_sem_destroy]              = "  sem_destroy                     ";
   name[StatInt_sem_wait]                 = "  sem_wait                        ";
@@ -221,11 +228,13 @@ void StatOutput(u64 *stat) {
   name[StatInt_pread]                    = "  pread                           ";
   name[StatInt_pread64]                  = "  pread64                         ";
   name[StatInt_readv]                    = "  readv                           ";
+  name[StatInt_preadv]                   = "  preadv                          ";
   name[StatInt_preadv64]                 = "  preadv64                        ";
   name[StatInt_write]                    = "  write                           ";
   name[StatInt_pwrite]                   = "  pwrite                          ";
   name[StatInt_pwrite64]                 = "  pwrite64                        ";
   name[StatInt_writev]                   = "  writev                          ";
+  name[StatInt_pwritev]                  = "  pwritev                         ";
   name[StatInt_pwritev64]                = "  pwritev64                       ";
   name[StatInt_send]                     = "  send                            ";
   name[StatInt_sendmsg]                  = "  sendmsg                         ";
@@ -237,13 +246,21 @@ void StatOutput(u64 *stat) {
   name[StatInt_fclose]                   = "  fclose                          ";
   name[StatInt_fread]                    = "  fread                           ";
   name[StatInt_fwrite]                   = "  fwrite                          ";
+  name[StatInt_fflush]                   = "  fflush                          ";
+  name[StatInt_abort]                    = "  abort                           ";
   name[StatInt_puts]                     = "  puts                            ";
   name[StatInt_rmdir]                    = "  rmdir                           ";
   name[StatInt_opendir]                  = "  opendir                         ";
   name[StatInt_epoll_ctl]                = "  epoll_ctl                       ";
   name[StatInt_epoll_wait]               = "  epoll_wait                      ";
   name[StatInt_poll]                     = "  poll                            ";
+  name[StatInt_ppoll]                    = "  ppoll                           ";
   name[StatInt_sigaction]                = "  sigaction                       ";
+  name[StatInt_signal]                   = "  signal                          ";
+  name[StatInt_sigsuspend]               = "  sigsuspend                      ";
+  name[StatInt_raise]                    = "  raise                           ";
+  name[StatInt_kill]                     = "  kill                            ";
+  name[StatInt_pthread_kill]             = "  pthread_kill                    ";
   name[StatInt_sleep]                    = "  sleep                           ";
   name[StatInt_usleep]                   = "  usleep                          ";
   name[StatInt_nanosleep]                = "  nanosleep                       ";
@@ -271,6 +288,87 @@ void StatOutput(u64 *stat) {
   name[StatInt_ctime_r]                  = "  ctime_r                         ";
   name[StatInt_asctime]                  = "  asctime                         ";
   name[StatInt_asctime_r]                = "  asctime_r                       ";
+  name[StatInt_frexp]                    = "  frexp                           ";
+  name[StatInt_frexpf]                   = "  frexpf                          ";
+  name[StatInt_frexpl]                   = "  frexpl                          ";
+  name[StatInt_getpwnam]                 = "  getpwnam                        ";
+  name[StatInt_getpwuid]                 = "  getpwuid                        ";
+  name[StatInt_getgrnam]                 = "  getgrnam                        ";
+  name[StatInt_getgrgid]                 = "  getgrgid                        ";
+  name[StatInt_getpwnam_r]               = "  getpwnam_r                      ";
+  name[StatInt_getpwuid_r]               = "  getpwuid_r                      ";
+  name[StatInt_getgrnam_r]               = "  getgrnam_r                      ";
+  name[StatInt_getgrgid_r]               = "  getgrgid_r                      ";
+  name[StatInt_clock_getres]             = "  clock_getres                    ";
+  name[StatInt_clock_gettime]            = "  clock_gettime                   ";
+  name[StatInt_clock_settime]            = "  clock_settime                   ";
+  name[StatInt_getitimer]                = "  getitimer                       ";
+  name[StatInt_setitimer]                = "  setitimer                       ";
+  name[StatInt_time]                     = "  time                            ";
+  name[StatInt_glob]                     = "  glob                            ";
+  name[StatInt_glob64]                   = "  glob64                          ";
+  name[StatInt_wait]                     = "  wait                            ";
+  name[StatInt_waitid]                   = "  waitid                          ";
+  name[StatInt_waitpid]                  = "  waitpid                         ";
+  name[StatInt_wait3]                    = "  wait3                           ";
+  name[StatInt_wait4]                    = "  wait4                           ";
+  name[StatInt_inet_ntop]                = "  inet_ntop                       ";
+  name[StatInt_inet_pton]                = "  inet_pton                       ";
+  name[StatInt_inet_aton]                = "  inet_aton                       ";
+  name[StatInt_getaddrinfo]              = "  getaddrinfo                     ";
+  name[StatInt_getnameinfo]              = "  getnameinfo                     ";
+  name[StatInt_getsockname]              = "  getsockname                     ";
+  name[StatInt_gethostent]               = "  gethostent                      ";
+  name[StatInt_gethostbyname]            = "  gethostbyname                   ";
+  name[StatInt_gethostbyname2]           = "  gethostbyname2                  ";
+  name[StatInt_gethostbyaddr]            = "  gethostbyaddr                   ";
+  name[StatInt_gethostent_r]             = "  gethostent_r                    ";
+  name[StatInt_gethostbyname_r]          = "  gethostbyname_r                 ";
+  name[StatInt_gethostbyname2_r]         = "  gethostbyname2_r                ";
+  name[StatInt_gethostbyaddr_r]          = "  gethostbyaddr_r                 ";
+  name[StatInt_getsockopt]               = "  getsockopt                      ";
+  name[StatInt_modf]                     = "  modf                            ";
+  name[StatInt_modff]                    = "  modff                           ";
+  name[StatInt_modfl]                    = "  modfl                           ";
+  name[StatInt_getpeername]              = "  getpeername                     ";
+  name[StatInt_ioctl]                    = "  ioctl                           ";
+  name[StatInt_sysinfo]                  = "  sysinfo                         ";
+  name[StatInt_readdir]                  = "  readdir                         ";
+  name[StatInt_readdir64]                = "  readdir64                       ";
+  name[StatInt_readdir_r]                = "  readdir_r                       ";
+  name[StatInt_readdir64_r]              = "  readdir64_r                     ";
+  name[StatInt_ptrace]                   = "  ptrace                          ";
+  name[StatInt_setlocale]                = "  setlocale                       ";
+  name[StatInt_getcwd]                   = "  getcwd                          ";
+  name[StatInt_get_current_dir_name]     = "  get_current_dir_name            ";
+  name[StatInt_strtoimax]                = "  strtoimax                       ";
+  name[StatInt_strtoumax]                = "  strtoumax                       ";
+  name[StatInt_mbstowcs]                 = "  mbstowcs                        ";
+  name[StatInt_mbsrtowcs]                = "  mbsrtowcs                       ";
+  name[StatInt_mbsnrtowcs]               = "  mbsnrtowcs                      ";
+  name[StatInt_wcstombs]                 = "  wcstombs                        ";
+  name[StatInt_wcsrtombs]                = "  wcsrtombs                       ";
+  name[StatInt_wcsnrtombs]               = "  wcsnrtombs                      ";
+  name[StatInt_tcgetattr]                = "  tcgetattr                       ";
+  name[StatInt_realpath]                 = "  realpath                        ";
+  name[StatInt_canonicalize_file_name]   = "  canonicalize_file_name          ";
+  name[StatInt_confstr]                  = "  confstr                         ";
+  name[StatInt_sched_getaffinity]        = "  sched_getaffinity               ";
+  name[StatInt_strerror]                 = "  strerror                        ";
+  name[StatInt_strerror_r]               = "  strerror_r                      ";
+  name[StatInt_scandir]                  = "  scandir                         ";
+  name[StatInt_scandir64]                = "  scandir64                       ";
+  name[StatInt_getgroups]                = "  getgroups                       ";
+  name[StatInt_wordexp]                  = "  wordexp                         ";
+  name[StatInt_sigwait]                  = "  sigwait                         ";
+  name[StatInt_sigwaitinfo]              = "  sigwaitinfo                     ";
+  name[StatInt_sigtimedwait]             = "  sigtimedwait                    ";
+  name[StatInt_sigemptyset]              = "  sigemptyset                     ";
+  name[StatInt_sigfillset]               = "  sigfillset                      ";
+  name[StatInt_sigpending]               = "  sigpending                      ";
+  name[StatInt_sigprocmask]              = "  sigprocmask                     ";
+  name[StatInt_backtrace]                = "  backtrace                       ";
+  name[StatInt_backtrace_symbols]        = "  backtrace_symbols               ";
 
   name[StatAnnotation]                   = "Dynamic annotations               ";
   name[StatAnnotateHappensBefore]        = "  HappensBefore                   ";
@@ -280,6 +378,7 @@ void StatOutput(u64 *stat) {
   name[StatAnnotateMutexIsNotPHB]        = "  MutexIsNotPHB                   ";
   name[StatAnnotateCondVarWait]          = "  CondVarWait                     ";
   name[StatAnnotateRWLockCreate]         = "  RWLockCreate                    ";
+  name[StatAnnotateRWLockCreateStatic]   = "  StatAnnotateRWLockCreateStatic  ";
   name[StatAnnotateRWLockDestroy]        = "  RWLockDestroy                   ";
   name[StatAnnotateRWLockAcquired]       = "  RWLockAcquired                  ";
   name[StatAnnotateRWLockReleased]       = "  RWLockReleased                  ";
index 8b08a024be2671ddc24255bd386a48626168c1f7..e392ff62c63df3526a7bde03c62a88991d0a26bd 100644 (file)
@@ -25,6 +25,8 @@ enum StatType {
   StatMop8,
   StatMopSame,
   StatMopRange,
+  StatMopRodata,
+  StatMopRangeRodata,
   StatShadowProcessed,
   StatShadowZero,
   StatShadowNonZero,  // Derived.
@@ -100,6 +102,7 @@ enum StatType {
   StatInt_realloc,
   StatInt_free,
   StatInt_cfree,
+  StatInt_malloc_usable_size,
   StatInt_mmap,
   StatInt_mmap64,
   StatInt_munmap,
@@ -129,7 +132,10 @@ enum StatType {
   StatInt_strncmp,
   StatInt_strcpy,
   StatInt_strncpy,
+  StatInt_strcasecmp,
+  StatInt_strncasecmp,
   StatInt_strstr,
+  StatInt_strdup,
   StatInt_atexit,
   StatInt___cxa_guard_acquire,
   StatInt___cxa_guard_release,
@@ -167,6 +173,7 @@ enum StatType {
   StatInt_pthread_barrier_destroy,
   StatInt_pthread_barrier_wait,
   StatInt_pthread_once,
+  StatInt_pthread_getschedparam,
   StatInt_sem_init,
   StatInt_sem_destroy,
   StatInt_sem_wait,
@@ -216,11 +223,13 @@ enum StatType {
   StatInt_pread,
   StatInt_pread64,
   StatInt_readv,
+  StatInt_preadv,
   StatInt_preadv64,
   StatInt_write,
   StatInt_pwrite,
   StatInt_pwrite64,
   StatInt_writev,
+  StatInt_pwritev,
   StatInt_pwritev64,
   StatInt_send,
   StatInt_sendmsg,
@@ -232,14 +241,18 @@ enum StatType {
   StatInt_fclose,
   StatInt_fread,
   StatInt_fwrite,
+  StatInt_fflush,
+  StatInt_abort,
   StatInt_puts,
   StatInt_rmdir,
   StatInt_opendir,
   StatInt_epoll_ctl,
   StatInt_epoll_wait,
   StatInt_poll,
+  StatInt_ppoll,
   StatInt_sigaction,
   StatInt_signal,
+  StatInt_sigsuspend,
   StatInt_raise,
   StatInt_kill,
   StatInt_pthread_kill,
@@ -270,6 +283,87 @@ enum StatType {
   StatInt_ctime_r,
   StatInt_asctime,
   StatInt_asctime_r,
+  StatInt_frexp,
+  StatInt_frexpf,
+  StatInt_frexpl,
+  StatInt_getpwnam,
+  StatInt_getpwuid,
+  StatInt_getgrnam,
+  StatInt_getgrgid,
+  StatInt_getpwnam_r,
+  StatInt_getpwuid_r,
+  StatInt_getgrnam_r,
+  StatInt_getgrgid_r,
+  StatInt_clock_getres,
+  StatInt_clock_gettime,
+  StatInt_clock_settime,
+  StatInt_getitimer,
+  StatInt_setitimer,
+  StatInt_time,
+  StatInt_glob,
+  StatInt_glob64,
+  StatInt_wait,
+  StatInt_waitid,
+  StatInt_waitpid,
+  StatInt_wait3,
+  StatInt_wait4,
+  StatInt_inet_ntop,
+  StatInt_inet_pton,
+  StatInt_inet_aton,
+  StatInt_getaddrinfo,
+  StatInt_getnameinfo,
+  StatInt_getsockname,
+  StatInt_gethostent,
+  StatInt_gethostbyname,
+  StatInt_gethostbyname2,
+  StatInt_gethostbyaddr,
+  StatInt_gethostent_r,
+  StatInt_gethostbyname_r,
+  StatInt_gethostbyname2_r,
+  StatInt_gethostbyaddr_r,
+  StatInt_getsockopt,
+  StatInt_modf,
+  StatInt_modff,
+  StatInt_modfl,
+  StatInt_getpeername,
+  StatInt_ioctl,
+  StatInt_sysinfo,
+  StatInt_readdir,
+  StatInt_readdir64,
+  StatInt_readdir_r,
+  StatInt_readdir64_r,
+  StatInt_ptrace,
+  StatInt_setlocale,
+  StatInt_getcwd,
+  StatInt_get_current_dir_name,
+  StatInt_strtoimax,
+  StatInt_strtoumax,
+  StatInt_mbstowcs,
+  StatInt_mbsrtowcs,
+  StatInt_mbsnrtowcs,
+  StatInt_wcstombs,
+  StatInt_wcsrtombs,
+  StatInt_wcsnrtombs,
+  StatInt_tcgetattr,
+  StatInt_realpath,
+  StatInt_canonicalize_file_name,
+  StatInt_confstr,
+  StatInt_sched_getaffinity,
+  StatInt_strerror,
+  StatInt_strerror_r,
+  StatInt_scandir,
+  StatInt_scandir64,
+  StatInt_getgroups,
+  StatInt_wordexp,
+  StatInt_sigwait,
+  StatInt_sigwaitinfo,
+  StatInt_sigtimedwait,
+  StatInt_sigemptyset,
+  StatInt_sigfillset,
+  StatInt_sigpending,
+  StatInt_sigprocmask,
+  StatInt_backtrace,
+  StatInt_backtrace_symbols,
 
   // Dynamic annotations.
   StatAnnotation,
index 8ee8de7c27887d09c8d4a4090a784eb4e247c0dd..912b3834e87288e032207db5411f61c45103c4dc 100644 (file)
 
 #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 TSAN_GO
 extern "C" const char *WEAK __tsan_default_suppressions() {
@@ -26,7 +39,7 @@ extern "C" const char *WEAK __tsan_default_suppressions() {
 
 namespace __tsan {
 
-static Suppression *g_suppressions;
+static SuppressionContext* g_ctx;
 
 static char *ReadFile(const char *filename) {
   if (filename == 0 || filename[0] == 0)
@@ -36,12 +49,13 @@ static char *ReadFile(const char *filename) {
     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
   else
     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
-  fd_t fd = OpenFile(tmp.data(), false);
-  if (fd == kInvalidFd) {
+  uptr openrv = OpenFile(tmp.data(), false);
+  if (internal_iserror(openrv)) {
     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
                tmp.data());
     Die();
   }
+  fd_t fd = openrv;
   const uptr fsize = internal_filesize(fd);
   if (fsize == (uptr)-1) {
     Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
@@ -59,114 +73,91 @@ static char *ReadFile(const char *filename) {
   return buf;
 }
 
-bool SuppressionMatch(char *templ, const char *str) {
-  if (str == 0 || str[0] == 0)
-    return false;
-  char *tpos;
-  const char *spos;
-  while (templ && templ[0]) {
-    if (templ[0] == '*') {
-      templ++;
-      continue;
-    }
-    if (str[0] == 0)
-      return false;
-    tpos = (char*)internal_strchr(templ, '*');
-    if (tpos != 0)
-      tpos[0] = 0;
-    spos = internal_strstr(str, templ);
-    str = spos + internal_strlen(templ);
-    templ = tpos;
-    if (tpos)
-      tpos[0] = '*';
-    if (spos == 0)
-      return false;
-  }
-  return true;
-}
-
-Suppression *SuppressionParse(Suppression *head, const char* supp) {
-  const char *line = supp;
-  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--;
-      SuppressionType stype;
-      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
-        stype = SuppressionRace;
-        line += sizeof("race:") - 1;
-      } else if (0 == internal_strncmp(line, "thread:",
-          sizeof("thread:") - 1)) {
-        stype = SuppressionThread;
-        line += sizeof("thread:") - 1;
-      } else if (0 == internal_strncmp(line, "mutex:",
-          sizeof("mutex:") - 1)) {
-        stype = SuppressionMutex;
-        line += sizeof("mutex:") - 1;
-      } else if (0 == internal_strncmp(line, "signal:",
-          sizeof("signal:") - 1)) {
-        stype = SuppressionSignal;
-        line += sizeof("signal:") - 1;
-      } else {
-        Printf("ThreadSanitizer: failed to parse suppressions file\n");
-        Die();
-      }
-      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
-          sizeof(Suppression));
-      s->next = head;
-      head = s;
-      s->type = stype;
-      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
-      internal_memcpy(s->templ, line, end2 - line);
-      s->templ[end2 - line] = 0;
-    }
-    if (end[0] == 0)
-      break;
-    line = end + 1;
-  }
-  return head;
-}
-
 void InitializeSuppressions() {
+  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
+  g_ctx = new(placeholder_) SuppressionContext;
   const char *supp = ReadFile(flags()->suppressions);
-  g_suppressions = SuppressionParse(0, supp);
+  g_ctx->Parse(supp);
 #ifndef TSAN_GO
   supp = __tsan_default_suppressions();
-  g_suppressions = SuppressionParse(g_suppressions, supp);
+  g_ctx->Parse(supp);
+  g_ctx->Parse(std_suppressions);
 #endif
 }
 
-uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
-  if (g_suppressions == 0 || stack == 0)
-    return 0;
-  SuppressionType stype;
+SuppressionType conv(ReportType typ) {
   if (typ == ReportTypeRace)
-    stype = SuppressionRace;
+    return SuppressionRace;
+  else if (typ == ReportTypeVptrRace)
+    return SuppressionRace;
+  else if (typ == ReportTypeUseAfterFree)
+    return SuppressionRace;
   else if (typ == ReportTypeThreadLeak)
-    stype = SuppressionThread;
+    return SuppressionThread;
   else if (typ == ReportTypeMutexDestroyLocked)
-    stype = SuppressionMutex;
+    return SuppressionMutex;
   else if (typ == ReportTypeSignalUnsafe)
-    stype = SuppressionSignal;
-  else
+    return SuppressionSignal;
+  else if (typ == ReportTypeErrnoInSignal)
+    return SuppressionNone;
+  Printf("ThreadSanitizer: unknown report type %d\n", typ),
+  Die();
+}
+
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
+  CHECK(g_ctx);
+  if (!g_ctx->SuppressionCount() || stack == 0) return 0;
+  SuppressionType stype = conv(typ);
+  if (stype == SuppressionNone)
     return 0;
+  Suppression *s;
   for (const ReportStack *frame = stack; frame; frame = frame->next) {
-    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
-      if (stype == supp->type &&
-          (SuppressionMatch(supp->templ, frame->func) ||
-           SuppressionMatch(supp->templ, frame->file) ||
-           SuppressionMatch(supp->templ, frame->module))) {
-        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
-        return frame->pc;
-      }
+    if (g_ctx->Match(frame->func, stype, &s) ||
+        g_ctx->Match(frame->file, stype, &s) ||
+        g_ctx->Match(frame->module, stype, &s)) {
+      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+      s->hit_count++;
+      *sp = s;
+      return frame->pc;
     }
   }
   return 0;
 }
+
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
+  CHECK(g_ctx);
+  if (!g_ctx->SuppressionCount() || loc == 0 ||
+      loc->type != ReportLocationGlobal)
+    return 0;
+  SuppressionType stype = conv(typ);
+  if (stype == SuppressionNone)
+    return 0;
+  Suppression *s;
+  if (g_ctx->Match(loc->name, stype, &s) ||
+      g_ctx->Match(loc->file, stype, &s) ||
+      g_ctx->Match(loc->module, stype, &s)) {
+      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+      s->hit_count++;
+      *sp = s;
+      return loc->addr;
+  }
+  return 0;
+}
+
+void PrintMatchedSuppressions() {
+  CHECK(g_ctx);
+  InternalMmapVector<Suppression *> matched(1);
+  g_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,
+           SuppressionTypeString(matched[i]->type), matched[i]->templ);
+  }
+}
 }  // namespace __tsan
index d44d8dd35297c89dfd9332da6036e1e75cb032e6..e38d81ece85c7f19587ec24db9253a31b74f5926 100644 (file)
 #ifndef TSAN_SUPPRESSIONS_H
 #define TSAN_SUPPRESSIONS_H
 
+#include "sanitizer_common/sanitizer_suppressions.h"
 #include "tsan_report.h"
 
 namespace __tsan {
 
 void InitializeSuppressions();
-void FinalizeSuppressions();
-uptr IsSuppressed(ReportType typ, const ReportStack *stack);
-
-// Exposed for testing.
-enum SuppressionType {
-  SuppressionRace,
-  SuppressionMutex,
-  SuppressionThread,
-  SuppressionSignal
-};
-
-struct Suppression {
-  Suppression *next;
-  SuppressionType type;
-  char *templ;
-};
-
-Suppression *SuppressionParse(Suppression *head, const char* supp);
-bool SuppressionMatch(char *templ, const char *str);
+void PrintMatchedSuppressions();
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
 
 }  // namespace __tsan
 
index 65a994670b5c5298cf90e2fd84c51a355a959aa2..0c7efac7a268994c453bbfdda16ce94edb8fd82c 100644 (file)
@@ -67,16 +67,65 @@ static ReportStack *NewReportStackEntry(const AddressInfo &info) {
   return ent;
 }
 
+
+  ReportStack *next;
+  char *module;
+  uptr offset;
+  uptr pc;
+  char *func;
+  char *file;
+  int line;
+  int col;
+
+
+// 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;
+
+// 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;
+}
+
 ReportStack *SymbolizeCode(uptr addr) {
-  if (!IsSymbolizerAvailable())
+  // 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;
+    if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf),
+                                  file_buf, sizeof(file_buf), &line, &col))
+      return NewReportStackEntry(addr);
+    ReportStack *ent = NewReportStackEntry(addr);
+    ent->module = 0;
+    ent->offset = 0;
+    ent->func = internal_strdup(func_buf);
+    ent->file = internal_strdup(file_buf);
+    ent->line = line;
+    ent->col = col;
+    return ent;
+  }
+  if (!getSymbolizer()->IsAvailable())
     return SymbolizeCodeAddr2Line(addr);
   ScopedInSymbolizer in_symbolizer;
   static const uptr kMaxAddrFrames = 16;
   InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
   for (uptr i = 0; i < kMaxAddrFrames; i++)
     new(&addr_frames[i]) AddressInfo();
-  uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
-                                                    kMaxAddrFrames);
+  uptr addr_frames_num =
+      getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames);
   if (addr_frames_num == 0)
     return NewReportStackEntry(addr);
   ReportStack *top = 0;
@@ -95,11 +144,11 @@ ReportStack *SymbolizeCode(uptr addr) {
 }
 
 ReportLocation *SymbolizeData(uptr addr) {
-  if (!IsSymbolizerAvailable())
+  if (!getSymbolizer()->IsAvailable())
     return 0;
   ScopedInSymbolizer in_symbolizer;
   DataInfo info;
-  if (!__sanitizer::SymbolizeData(addr, &info))
+  if (!getSymbolizer()->SymbolizeData(addr, &info))
     return 0;
   ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
                                                         sizeof(ReportLocation));
@@ -114,4 +163,11 @@ ReportLocation *SymbolizeData(uptr addr) {
   return ent;
 }
 
+void SymbolizeFlush() {
+  if (!getSymbolizer()->IsAvailable())
+    return;
+  ScopedInSymbolizer in_symbolizer;
+  getSymbolizer()->Flush();
+}
+
 }  // namespace __tsan
index 5275936a29377dac059292e48549657e196ad919..c610d1f54926e56805f66f99ae33945e012badda 100644 (file)
@@ -18,6 +18,7 @@ namespace __tsan {
 
 ReportStack *SymbolizeCode(uptr addr);
 ReportLocation *SymbolizeData(uptr addr);
+void SymbolizeFlush();
 
 ReportStack *SymbolizeCodeAddr2Line(uptr addr);
 
index 9bdd1ffdc5e603c6a83f359edef3a317bb2ce385..da0c87d297ed3d9872b0c9d3fcd565cfb867a984 100644 (file)
@@ -85,7 +85,8 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
   DlIteratePhdrCtx *ctx = (DlIteratePhdrCtx*)arg;
   InternalScopedBuffer<char> tmp(128);
   if (ctx->is_first) {
-    internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe", GetPid());
+    internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe",
+                      (int)internal_getpid());
     info->dlpi_name = tmp.data();
   }
   ctx->is_first = false;
index d392408fd888f23aa0279d99a60e707e7480c80c..04fef615531742507e6ff2b8ca57b67c68afa4de 100644 (file)
@@ -61,7 +61,7 @@ SyncVar* SyncTab::Create(ThreadState *thr, uptr pc, uptr addr) {
   const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
   SyncVar *res = new(mem) SyncVar(addr, uid);
 #ifndef TSAN_GO
-  res->creation_stack.ObtainCurrent(thr, pc);
+  res->creation_stack_id = CurrentStackId(thr, pc);
 #endif
   return res;
 }
@@ -80,9 +80,10 @@ SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
   // the hashmap anyway.
   if (PrimaryAllocator::PointerIsMine((void*)addr)) {
     MBlock *b = user_mblock(thr, (void*)addr);
-    Lock l(&b->mtx);
+    CHECK_NE(b, 0);
+    MBlock::ScopedLock l(b);
     SyncVar *res = 0;
-    for (res = b->head; res; res = res->next) {
+    for (res = b->ListHead(); res; res = res->next) {
       if (res->addr == addr)
         break;
     }
@@ -90,8 +91,7 @@ SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
       if (!create)
         return 0;
       res = Create(thr, pc, addr);
-      res->next = b->head;
-      b->head = res;
+      b->ListPush(res);
     }
     if (write_lock)
       res->mtx.Lock();
@@ -145,27 +145,37 @@ SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
   }
   if (PrimaryAllocator::PointerIsMine((void*)addr)) {
     MBlock *b = user_mblock(thr, (void*)addr);
+    CHECK_NE(b, 0);
     SyncVar *res = 0;
     {
-      Lock l(&b->mtx);
-      SyncVar **prev = &b->head;
-      res = *prev;
-      while (res) {
+      MBlock::ScopedLock l(b);
+      res = b->ListHead();
+      if (res) {
         if (res->addr == addr) {
           if (res->is_linker_init)
             return 0;
-          *prev = res->next;
-          break;
+          b->ListPop();
+        } else {
+          SyncVar **prev = &res->next;
+          res = *prev;
+          while (res) {
+            if (res->addr == addr) {
+              if (res->is_linker_init)
+                return 0;
+              *prev = res->next;
+              break;
+            }
+            prev = &res->next;
+            res = *prev;
+          }
+        }
+        if (res) {
+          StatInc(thr, StatSyncDestroyed);
+          res->mtx.Lock();
+          res->mtx.Unlock();
         }
-        prev = &res->next;
-        res = *prev;
       }
     }
-    if (res) {
-      StatInc(thr, StatSyncDestroyed);
-      res->mtx.Lock();
-      res->mtx.Unlock();
-    }
     return res;
   }
 #endif
@@ -195,26 +205,6 @@ SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
   return res;
 }
 
-uptr SyncVar::GetMemoryConsumption() {
-  return sizeof(*this)
-      + clock.size() * sizeof(u64)
-      + read_clock.size() * sizeof(u64)
-      + creation_stack.Size() * sizeof(uptr);
-}
-
-uptr SyncTab::GetMemoryConsumption(uptr *nsync) {
-  uptr mem = 0;
-  for (int i = 0; i < kPartCount; i++) {
-    Part *p = &tab_[i];
-    Lock l(&p->mtx);
-    for (SyncVar *s = p->val; s; s = s->next) {
-      *nsync += 1;
-      mem += s->GetMemoryConsumption();
-    }
-  }
-  return mem;
-}
-
 int SyncTab::PartIdx(uptr addr) {
   return (addr >> 3) % kPartCount;
 }
index 4dbb055a17e1de215df92f4512fcadb4faea8af5..2867a8ac79ef568efec2d90eecb4fda36ba68338 100644 (file)
@@ -57,7 +57,7 @@ struct SyncVar {
   const u64 uid;  // Globally unique id.
   SyncClock clock;
   SyncClock read_clock;  // Used for rw mutexes only.
-  StackTrace creation_stack;
+  u32 creation_stack_id;
   int owner_tid;  // Set only by exclusive owners.
   u64 last_lock;
   int recursion;
index b9aa51c7957542e64390a2062bc601759bf237b0..42caf80d349edb30b261e6eee6e1d39114c26fce 100644 (file)
@@ -55,8 +55,7 @@ do {
     goto RACE;
   }
   // Do the memory access intersect?
-  // In Go all memory accesses are 1 byte, so there can be no intersections.
-  if (kCppMode && Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+  if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
     StatInc(thr, StatShadowIntersect);
     if (Shadow::TidsAreEqual(old, cur)) {
       StatInc(thr, StatShadowSameThread);
index 99e9f792c20cb1c8248e84e6dd70753b8c1b2023..4da8b83d5c3ff191d114a8e7ad751aab336af1b0 100644 (file)
@@ -62,6 +62,11 @@ class Vector {
     return &end_[-1];
   }
 
+  void PopBack() {
+    DCHECK_GT(end_, begin_);
+    end_--;
+  }
+
   void Resize(uptr size) {
     uptr old_size = Size();
     EnsureSize(size);
index d56ef849b6fcf72bec2680129dda32547aa22eb5..c7378fdbda2ab3227fbc4e56b6e2d7b000950122 100644 (file)
@@ -26,7 +26,8 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) {
   uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
 
   AddressInfo Info;
-  if (!SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module)
+  if (!getSymbolizer()->SymbolizeCode(Loc, &Info, 1) ||
+      !Info.module || !*Info.module)
     return Location(Loc);
 
   if (!Info.file)
@@ -107,7 +108,7 @@ static void renderText(const char *Message, const Diag::Arg *Args) {
         Printf("%s", A.String);
         break;
       case Diag::AK_Mangled: {
-        Printf("'%s'", Demangle(A.String));
+        Printf("'%s'", getSymbolizer()->Demangle(A.String));
         break;
       }
       case Diag::AK_SInt:
index 6ca0f56c99d01d95a9e6d67e38321d0cb4c59ee8..9b31eb7defb59a5f6739916d72f35e32568d0ea3 100644 (file)
@@ -23,8 +23,8 @@
 
 // FIXME: Move this out to a config header.
 #if __SIZEOF_INT128__
-__extension__ typedef __int128 s128;
-__extension__ typedef unsigned __int128 u128;
+typedef __int128 s128;
+typedef unsigned __int128 u128;
 #define HAVE_INT128_T 1
 #else
 #define HAVE_INT128_T 0
index 3ff5a27dea60ee8bbd1f4c80144341a8c0504b68..4253a8025333e7710744141ad890f26f2a0a711e 100644 (file)
@@ -1,3 +1,55 @@
+2013-11-05  Jonathan Wakely  <jwakely.gcc@gmail.com>
+
+       N3655 C++1y TransformationTraits Redux
+       * include/std/type_traits (remove_const_t, remove_volatile_t,
+       remove_cv_t, add_const_t, add_volatile_t, add_cv_t, remove_reference_t,
+       add_lvalue_reference_t, add_rvalue_reference_t, make_signed_t,
+       make_unsigned_t, remove_extent_t, remove_all_extents_t,
+       remove_pointer_t, add_pointer_t, aligned_storage_t, decay_t,
+       enable_if_t, conditional_t, common_type_t, underlying_type_t,
+       result_of_t): Define.
+       * doc/xml/manual/status_cxx2014.xml: Update.
+       * testsuite/20_util/add_lvalue_reference/requirements/typedefs-3.cc:
+       New.
+       * testsuite/20_util/add_rvalue_reference/requirements/typedefs-3.cc:
+       New.
+       * testsuite/20_util/common_type/requirements/typedefs-3.cc: New.
+       * testsuite/20_util/conditional/requirements/typedefs-2.cc: New.
+       * testsuite/20_util/decay/requirements/typedefs-2.cc: New.
+       * testsuite/20_util/enable_if/requirements/typedefs-2.cc: New.
+       * testsuite/20_util/make_signed/requirements/typedefs-3.cc: New.
+       * testsuite/20_util/make_unsigned/requirements/typedefs-3.cc: New.
+       * testsuite/20_util/remove_reference/requirements/typedefs.cc: New.
+       * testsuite/20_util/result_of/requirements/typedefs.cc: New.
+       * testsuite/20_util/underlying_type/requirements/typedefs-3.cc: New.
+       * testsuite/20_util/common_type/requirements/typedefs-2.cc: Change to
+       compile-only test.
+       * testsuite/20_util/decay/requirements/typedefs.cc: Likewise.
+       * testsuite/20_util/make_signed/requirements/typedefs-1.cc: Likewise.
+       * testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error
+       line number.
+       * testsuite/20_util/make_signed/requirements/typedefs_neg.cc:
+       Likewise.
+       * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc:
+       Likewise.
+
+2013-11-05  Jonathan Wakely  <jwakely.gcc@gmail.com>
+
+       * doc/xml/manual/status_cxx2011.xml: Document aligned_union as
+       missing.
+
+2013-11-05  Jonathan Wakely  <jwakely.gcc@gmail.com>
+           Paolo Carlini  <paolo.carlini@oracle.com>
+
+       * include/experimental/optional: Use __and_<> and __not_<> in
+       conditions. Style fixes.
+       (__constexpr_addressof, swap): Make inline.
+       * testsuite/experimental/optional/cons/copy.cc: Adjust constants for
+       32-bit targets.
+       * testsuite/experimental/optional/cons/move.cc: Likewise.
+       * testsuite/experimental/optional/cons/value.cc: Likewise.
+       * testsuite/experimental/optional/constexpr/cons/value.cc: Likewise.
+
 2013-11-01  Michael Brune  <lucdanton@free.fr>
 
        * include/bits/enable_special_members.h: New.
index 5743c83f5a6578f2a9e864de901496117a900479..e013c1f9eeeeb475356e2be82b4eb755be54644f 100644 (file)
@@ -871,10 +871,11 @@ particular release.
       <entry/>
     </row>
     <row>
+      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>20.9.7.6</entry>
       <entry>Other transformations</entry>
-      <entry>Y</entry>
-      <entry/>
+      <entry>Partial</entry>
+      <entry>Missing <code>aligned_union</code>.</entry>
     </row>
     <row>
       <entry>20.10</entry>
index b368a810e6a7242a2e6e1fcfb4ca89a20fe7bb76..0e0ac37a9e857d363fa2ab7e577565a0f3ede4cf 100644 (file)
@@ -178,7 +178,6 @@ particular release.
 
 
     <row>
-      <?dbhtml bgcolor="#C8C8B0" ?>
       <entry>
        <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3658.html">
          N3658
@@ -202,7 +201,6 @@ particular release.
 
 
     <row>
-      <?dbhtml bgcolor="#C8C8B0" ?>
       <entry>
        <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2012/n3421.htm">
          N3421
@@ -227,26 +225,24 @@ particular release.
 
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>
-       <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3672.html">
+       <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3793.html">
          N3672
        </link>
       </entry>
       <entry>A proposal to add a utility class to represent optional objects</entry>
-      <entry>N</entry>
-      <entry/>
+      <entry>Y</entry>
+      <entry>Moved from C++14 to Library Fundamentals TS</entry>
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>
        <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3655.pdf">
          N3655
        </link>
       </entry>
       <entry>TransformationTraits Redux</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
 
@@ -259,7 +255,7 @@ particular release.
       </entry>
       <entry>C++ Dynamic Arrays</entry>
       <entry>N</entry>
-      <entry/>
+      <entry>Moved from C++14 to Library Fundamentals TS</entry>
     </row>
 
     <row>
index 5915892aec256c32c5181fa75c70ad8799ef83a8..5882ff59296c3f47589fddd471a247642179218f 100644 (file)
@@ -129,7 +129,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct _Has_addressof_impl<_Tp,
       decltype( std::declval<const _Tp&>().operator&(), void() )>
-    : std::true_type { };
+      : std::true_type { };
 
   /**
     * @brief Trait that detects the presence of an overloaded unary operator&.
@@ -157,7 +157,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     */
   template<typename _Tp, typename enable_if<_Has_addressof<_Tp>::value,
                                             int>::type...>
-    _Tp* __constexpr_addressof(_Tp& __t)
+    inline _Tp* __constexpr_addressof(_Tp& __t)
     { return std::__addressof(__t); }
 
   /**
@@ -235,32 +235,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         if (this->_M_engaged && __other._M_engaged)
           this->_M_get() = __other._M_get();
         else
-        {
-          if (__other._M_engaged)
-            this->_M_construct(__other._M_get());
-          else
-            this->_M_reset();
-        }
+         {
+           if (__other._M_engaged)
+             this->_M_construct(__other._M_get());
+           else
+             this->_M_reset();
+         }
 
         return *this;
       }
 
       _Optional_base&
       operator=(_Optional_base&& __other)
-      noexcept(is_nothrow_move_constructible<_Tp>()
-               && is_nothrow_move_assignable<_Tp>())
+      noexcept(__and_<is_nothrow_move_constructible<_Tp>,
+                     is_nothrow_move_assignable<_Tp>>())
       {
-        if (this->_M_engaged && __other._M_engaged)
-          this->_M_get() = std::move(__other._M_get());
-        else
-        {
-          if (__other._M_engaged)
-            this->_M_construct(std::move(__other._M_get()));
-          else
-            this->_M_reset();
-        }
-
-        return *this;
+       if (this->_M_engaged && __other._M_engaged)
+         this->_M_get() = std::move(__other._M_get());
+       else
+         {
+           if (__other._M_engaged)
+             this->_M_construct(std::move(__other._M_get()));
+           else
+             this->_M_reset();
+         }
+       return *this;
       }
 
       // [X.Y.4.2] Destructor.
@@ -373,35 +372,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Optional_base&
       operator=(const _Optional_base& __other)
       {
-        if (this->_M_engaged && __other._M_engaged)
-          this->_M_get() = __other._M_get();
-        else
-        {
-          if (__other._M_engaged)
-            this->_M_construct(__other._M_get());
-          else
-            this->_M_reset();
-        }
-
-        return *this;
+       if (this->_M_engaged && __other._M_engaged)
+         this->_M_get() = __other._M_get();
+       else
+         {
+           if (__other._M_engaged)
+             this->_M_construct(__other._M_get());
+           else
+             this->_M_reset();
+         }
+       return *this;
       }
 
       _Optional_base&
       operator=(_Optional_base&& __other)
-      noexcept(is_nothrow_move_constructible<_Tp>()
-               && is_nothrow_move_assignable<_Tp>())
+      noexcept(__and_<is_nothrow_move_constructible<_Tp>,
+                     is_nothrow_move_assignable<_Tp>>())
       {
-        if (this->_M_engaged && __other._M_engaged)
-          this->_M_get() = std::move(__other._M_get());
-        else
-        {
-          if (__other._M_engaged)
-            this->_M_construct(std::move(__other._M_get()));
-          else
-            this->_M_reset();
-        }
-
-        return *this;
+       if (this->_M_engaged && __other._M_engaged)
+         this->_M_get() = std::move(__other._M_get());
+       else
+         {
+           if (__other._M_engaged)
+             this->_M_construct(std::move(__other._M_get()));
+           else
+             this->_M_reset();
+         }
+       return *this;
       }
 
       // Sole difference
@@ -445,9 +442,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     private:
       struct _Empty_byte { };
-      union {
-          _Empty_byte _M_empty;
-          _Stored_type _M_payload;
+      union
+      {
+       _Empty_byte _M_empty;
+       _Stored_type _M_payload;
       };
       bool _M_engaged = false;
     };
@@ -462,22 +460,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         // Copy constructor.
         is_copy_constructible<_Tp>::value,
         // Copy assignment.
-        is_copy_constructible<_Tp>::value
-        && is_copy_assignable<_Tp>::value,
+        __and_<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>::value,
         // Move constructor.
         is_move_constructible<_Tp>::value,
         // Move assignment.
-        is_move_constructible<_Tp>::value
-        && is_move_assignable<_Tp>::value,
+        __and_<is_move_constructible<_Tp>, is_move_assignable<_Tp>>::value,
         // Unique tag type.
         optional<_Tp>>
     {
-      static_assert(!is_same<typename remove_cv<_Tp>::type,
-                             nullopt_t>()
-                    && !is_same<typename remove_cv<_Tp>::type,
-                             in_place_t>()
-                    && !is_reference<_Tp>(),
-                    "Invalid instantiation of optional<T>.");
+      static_assert(__and_<__not_<is_same<typename remove_cv<_Tp>::type,
+                                         nullopt_t>>,
+                          __not_<is_same<typename remove_cv<_Tp>::type,
+                                         in_place_t>>,
+                          __not_<is_reference<_Tp>>>(),
+                    "Invalid instantiation of optional<T>");
 
     private:
       using _Base = _Optional_base<_Tp>;
@@ -503,9 +499,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                >::type
         operator=(_Up&& __u)
         {
-          static_assert(is_constructible<_Tp, _Up>()
-                        && is_assignable<_Tp&, _Up>(),
-                        "Cannot assign to value type from argument.");
+          static_assert(__and_<is_constructible<_Tp, _Up>,
+                              is_assignable<_Tp&, _Up>>(),
+                        "Cannot assign to value type from argument");
 
           if (this->_M_is_engaged())
             this->_M_get() = std::forward<_Up>(__u);
@@ -520,7 +516,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        emplace(_Args&&... __args)
        {
          static_assert(is_constructible<_Tp, _Args&&...>(),
-                       "Cannot emplace value type from arguments.");
+                       "Cannot emplace value type from arguments");
 
          this->_M_reset();
          this->_M_construct(std::forward<_Args>(__args)...);
@@ -551,15 +547,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         if (this->_M_is_engaged() && __other._M_is_engaged())
           swap(this->_M_get(), __other._M_get());
         else if (this->_M_is_engaged())
-        {
-          __other._M_construct(std::move(this->_M_get()));
-          this->_M_destruct();
-        }
+         {
+           __other._M_construct(std::move(this->_M_get()));
+           this->_M_destruct();
+         }
         else if (__other._M_is_engaged())
-        {
-          this->_M_construct(std::move(__other._M_get()));
-          __other._M_destruct();
-        }
+         {
+           this->_M_construct(std::move(__other._M_get()));
+           __other._M_destruct();
+         }
       }
 
       // [X.Y.4.5] Observers.
@@ -585,11 +581,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr const _Tp&
       value() const
       {
-        return this->_M_is_engaged() ?
-          this->_M_get() :
-          (__throw_bad_optional_access("Attempt to access value of a disengaged"
-                                       " optional object."),
-           this->_M_get());
+       return this->_M_is_engaged()
+         ?  this->_M_get()
+         : (__throw_bad_optional_access("Attempt to access value of a "
+                                        "disengaged optional object"),
+            this->_M_get());
       }
 
       _Tp&
@@ -598,34 +594,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         if (this->_M_is_engaged())
           return this->_M_get();
 
-        __throw_bad_optional_access("Attempt to access value of a disengaged"
-                                    " optional object.");
+        __throw_bad_optional_access("Attempt to access value of a "
+                                   "disengaged optional object");
       }
 
       template<typename _Up>
        constexpr _Tp
        value_or(_Up&& __u) const&
        {
-         static_assert(is_copy_constructible<_Tp>()
-                       && is_convertible<_Up&&, _Tp>(),
-                       "Cannot return value.");
+         static_assert(__and_<is_copy_constructible<_Tp>,
+                              is_convertible<_Up&&, _Tp>>(),
+                       "Cannot return value");
 
-         return this->_M_is_engaged() ?
-           this->_M_get() :
-           static_cast<_Tp>(std::forward<_Up>(__u));
+         return this->_M_is_engaged()
+           ? this->_M_get()
+           static_cast<_Tp>(std::forward<_Up>(__u));
        }
 
       template<typename _Up>
        _Tp
        value_or(_Up&& __u) &&
        {
-         static_assert( is_move_constructible<_Tp>()
-                       && is_convertible<_Up&&, _Tp>(),
-                       "Cannot return value." );
+         static_assert(__and_<is_move_constructible<_Tp>,
+                              is_convertible<_Up&&, _Tp>>(),
+                       "Cannot return value" );
 
-         return this->_M_is_engaged() ?
-           std::move(this->_M_get()) :
-           static_cast<_Tp>(std::forward<_Up>(__u));
+         return this->_M_is_engaged()
+           ? std::move(this->_M_get())
+           static_cast<_Tp>(std::forward<_Up>(__u));
        }
     };
 
@@ -635,7 +631,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
     {
       return static_cast<bool>(__lhs) == static_cast<bool>(__rhs)
-        && (!__lhs || *__lhs == *__rhs);
+            && (!__lhs || *__lhs == *__rhs);
     }
 
   template<typename _Tp>
@@ -647,8 +643,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr bool
     operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
     {
-      return static_cast<bool>(__rhs)
-        && (!__lhs || *__lhs < *__rhs);
+      return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs);
     }
 
   template<typename _Tp>
@@ -790,7 +785,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // [X.Y.11]
   template<typename _Tp>
-    void
+    inline void
     swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs)
     noexcept(noexcept(__lhs.swap(__rhs)))
     { __lhs.swap(__rhs); }
index eef9df6998c1487736808deb62509905cc198d1b..3239564c64ed2643a4b2364f6ff891c35a915032 100644 (file)
@@ -1438,6 +1438,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       add_const<typename add_volatile<_Tp>::type>::type     type;
     };
 
+#if __cplusplus > 201103L
+  /// Alias template for remove_const
+  template<typename _Tp>
+    using remove_const_t = typename remove_const<_Tp>::type;
+
+  /// Alias template for remove_volatile
+  template<typename _Tp>
+    using remove_volatile_t = typename remove_volatile<_Tp>::type;
+
+  /// Alias template for remove_cv
+  template<typename _Tp>
+    using remove_cv_t = typename remove_cv<_Tp>::type;
+
+  /// Alias template for add_const
+  template<typename _Tp>
+    using add_const_t = typename add_const<_Tp>::type;
+
+  /// Alias template for add_volatile
+  template<typename _Tp>
+    using add_volatile_t = typename add_volatile<_Tp>::type;
+
+  /// Alias template for add_cv
+  template<typename _Tp>
+    using add_cv_t = typename add_cv<_Tp>::type;
+#endif
 
   // Reference transformations.
 
@@ -1482,6 +1507,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __add_rvalue_reference_helper<_Tp>
     { };
 
+#if __cplusplus > 201103L
+  /// Alias template for remove_reference
+  template<typename _Tp>
+    using remove_reference_t = typename remove_reference<_Tp>::type;
+
+  /// Alias template for add_lvalue_reference
+  template<typename _Tp>
+    using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type;
+
+  /// Alias template for add_rvalue_reference
+  template<typename _Tp>
+    using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type;
+#endif
 
   // Sign modifications.
 
@@ -1679,6 +1717,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<>
     struct make_signed<bool>;
 
+#if __cplusplus > 201103L
+  /// Alias template for make_signed
+  template<typename _Tp>
+    using make_signed_t = typename make_signed<_Tp>::type;
+
+  /// Alias template for make_unsigned
+  template<typename _Tp>
+    using make_unsigned_t = typename make_unsigned<_Tp>::type;
+#endif
 
   // Array modifications.
 
@@ -1708,6 +1755,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct remove_all_extents<_Tp[]>
     { typedef typename remove_all_extents<_Tp>::type     type; };
 
+#if __cplusplus > 201103L
+  /// Alias template for remove_extent
+  template<typename _Tp>
+    using remove_extent_t = typename remove_extent<_Tp>::type;
+
+  /// Alias template for remove_all_extents
+  template<typename _Tp>
+    using remove_all_extents_t = typename remove_all_extents<_Tp>::type;
+#endif
 
   // Pointer modifications.
 
@@ -1740,6 +1796,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __add_pointer_helper<_Tp>
     { };
 
+#if __cplusplus > 201103L
+  /// Alias template for remove_pointer
+  template<typename _Tp>
+    using remove_pointer_t = typename remove_pointer<_Tp>::type;
+
+  /// Alias template for add_pointer
+  template<typename _Tp>
+    using add_pointer_t = typename add_pointer<_Tp>::type;
+#endif
 
   template<std::size_t _Len>
     struct __aligned_storage_msa
@@ -2102,6 +2167,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       >::type
     { };
 
+#if __cplusplus > 201103L
+  /// Alias template for aligned_storage
+  template<size_t _Len, size_t _Align =
+           __alignof__(typename __aligned_storage_msa<_Len>::__type)>
+    using aligned_storage_t = typename aligned_storage<_Len, _Align>::type;
+
+  /// Alias template for decay
+  template<typename _Tp>
+    using decay_t = typename decay<_Tp>::type;
+
+  /// Alias template for enable_if
+  template<bool _Cond, typename _Tp = void>
+    using enable_if_t = typename enable_if<_Cond, _Tp>::type;
+
+  /// Alias template for conditional
+  template<bool _Cond, typename _Iftrue, typename _Iffalse>
+    using conditional_t = typename conditional<_Cond, _Iftrue, _Iffalse>::type;
+
+  /// Alias template for common_type
+  template<typename... _Tp>
+    using common_type_t = typename common_type<_Tp...>::type;
+
+  /// Alias template for underlying_type
+  template<typename _Tp>
+    using underlying_type_t = typename underlying_type<_Tp>::type;
+
+  /// Alias template for result_of
+  template<typename _Tp>
+    using result_of_t = typename result_of<_Tp>::type;
+#endif
+
   /// @} group metaprogramming
        
   /**
diff --git a/libstdc++-v3/testsuite/20_util/add_lvalue_reference/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/add_lvalue_reference/requirements/typedefs.cc
new file mode 100644 (file)
index 0000000..24e73cc
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+using namespace std;
+
+static_assert( is_same<typename add_lvalue_reference<long>::type,
+                       add_lvalue_reference_t<long>>(),
+               "add_lvalue_reference_t" );
diff --git a/libstdc++-v3/testsuite/20_util/add_rvalue_reference/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/add_rvalue_reference/requirements/typedefs.cc
new file mode 100644 (file)
index 0000000..18a6964
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+using namespace std;
+
+static_assert( is_same<typename add_rvalue_reference<long>::type,
+                       add_rvalue_reference_t<long>>(),
+               "add_rvalue_reference_t" );
index 07a694ba4de7358a9e211c65a68d186ba8a9d667..f662d32d5db505f00b02a06fef9bb41581c0dafd 100644 (file)
@@ -1,4 +1,5 @@
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
 // 2009-11-12  Paolo Carlini  <paolo.carlini@oracle.com>
 //
 // Copyright (C) 2009-2013 Free Software Foundation, Inc.
 // <http://www.gnu.org/licenses/>.
 
 #include <type_traits>
-#include <testsuite_hooks.h>
 
 // DR 1255.
 void test01()
 {
-  bool test __attribute__((unused)) = true;
   using std::common_type;
   using std::is_same;
 
-  VERIFY( (is_same<common_type<void>::type, void>::value) );
-  VERIFY( (is_same<common_type<const void>::type, void>::value) );
-  VERIFY( (is_same<common_type<volatile void>::type, void>::value) );
-  VERIFY( (is_same<common_type<const volatile void>::type, void>::value) );
+  static_assert( is_same<common_type<void>::type, void>(),
+                 "common_type<void>" );
+  static_assert( is_same<common_type<const void>::type, void>(),
+                 "common_type<const void>" );
+  static_assert( is_same<common_type<volatile void>::type, void>(),
+                 "common_type<volatile void>" );
+  static_assert( is_same<common_type<const volatile void>::type, void>(),
+                 "common_type<const volatile void>" );
 
-  VERIFY( (is_same<common_type<void, void>::type, void>::value) );
-  VERIFY( (is_same<common_type<void, const void>::type, void>::value) );
-  VERIFY( (is_same<common_type<void, volatile void>::type, void>::value) );
-  VERIFY( (is_same<common_type<void, const volatile void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const void, void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const void, const void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const void, volatile void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const void, const volatile void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<volatile void, void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<volatile void, volatile void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<volatile void, const void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<volatile void, const volatile void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const volatile void, void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const volatile void, const void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const volatile void, volatile void>::type,
-                  void>::value) );
-  VERIFY( (is_same<common_type<const volatile void, const volatile void>::type,
-                  void>::value) );
- }
-
-int main()
-{
-  test01();
-  return 0;
+  static_assert( is_same<common_type<void, void>::type, void>(),
+                 "common_type<void, void>" );
+  static_assert( is_same<common_type<void, const void>::type, void>(),
+                 "common_type<void, const void>" );
+  static_assert( is_same<common_type<void, volatile void>::type, void>(),
+                 "common_type<void, volatile void>" );
+  static_assert( is_same<common_type<void, const volatile void>::type, void>(),
+                 "common_type<void, const volatile void>" );
+  static_assert( is_same<common_type<const void, void>::type, void>(),
+                 "common_type<const void, void>" );
+  static_assert( is_same<common_type<const void, const void>::type, void>(),
+                 "common_type<const void, const void>" );
+  static_assert( is_same<common_type<const void, volatile void>::type, void>(),
+                 "common_type<const void, volatile void>" );
+  static_assert( is_same<common_type<const void, const volatile void>::type,
+                  void>(), "common_type<const void, const volatile void>" );
+  static_assert( is_same<common_type<volatile void, void>::type, void>(),
+                 "common_type<volatile void, void>" );
+  static_assert( is_same<common_type<volatile void, volatile void>::type,
+                  void>(), "common_type<volatile void, volatile void>" );
+  static_assert( is_same<common_type<volatile void, const void>::type,
+                  void>(), "common_type<volatile void, const void>" );
+  static_assert( is_same<common_type<volatile void, const volatile void>::type,
+                  void>(), "common_type<volatile void, const volatile void>" );
+  static_assert( is_same<common_type<const volatile void, void>::type, void>(),
+                "common_type<const volatile void, const volatile void>" );
+  static_assert( is_same<common_type<const volatile void, const void>::type,
+                  void>(), "common_type<const volatile void, const void>" );
+  static_assert( is_same<common_type<const volatile void, volatile void>::type,
+                  void>(), "common_type<const volatile void, volatile void>" );
+  static_assert( is_same<common_type<const volatile void, const volatile void>::type,
+                  void>(),
+                "common_type<const volatile void, const volatile void>" );
 }
diff --git a/libstdc++-v3/testsuite/20_util/common_type/requirements/typedefs-3.cc b/libstdc++-v3/testsuite/20_util/common_type/requirements/typedefs-3.cc
new file mode 100644 (file)
index 0000000..52852fc
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+//
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+static_assert( is_same<common_type<int, long, char, unsigned>::type,
+                       common_type_t<int, long, char, unsigned>>(),
+               "common_type_t" );
diff --git a/libstdc++-v3/testsuite/20_util/conditional/requirements/typedefs-2.cc b/libstdc++-v3/testsuite/20_util/conditional/requirements/typedefs-2.cc
new file mode 100644 (file)
index 0000000..94edeea
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+using namespace std;
+
+static_assert( is_same<typename conditional<true, long, void>::type,
+                       conditional_t<true, long, void>>(),
+               "conditional_t<true, ...>" );
+static_assert( is_same<typename conditional<false, long, void>::type,
+                       conditional_t<false, long, void>>(),
+               "conditional_t<false, ...>" );
diff --git a/libstdc++-v3/testsuite/20_util/decay/requirements/typedefs-2.cc b/libstdc++-v3/testsuite/20_util/decay/requirements/typedefs-2.cc
new file mode 100644 (file)
index 0000000..774e22e
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+template<typename Trait, typename Result>
+  using test = is_same<typename Trait::type, Result>;
+
+static_assert( test<decay<bool>, decay_t<bool>>(), "decay<bool>" );
+static_assert( test<decay<const int>, decay_t<const int>>(),
+               "decay<const int>" );
+static_assert( test<decay<int[4]>, decay_t<int[4]>>(), "decay<int[4]>" );
+typedef void (fn_type) ();
+static_assert( test<decay<fn_type>, decay_t<fn_type>>(), "decay<fn_type>" );
+typedef void (cfn_type) () const;
+static_assert( test<decay<cfn_type>, decay_t<cfn_type>>(), "decay<cfn_type>" );
index 51b2c5fa0c4efc5a79e11f9c7125911e70f6f7dd..11589e473f0145a59057c5681134fdedda753c98 100644 (file)
@@ -1,4 +1,5 @@
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
 
 // 2007-05-03  Benjamin Kosnik  <bkoz@redhat.com>
 //
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-#include <cstdlib>
 #include <type_traits>
-#include <testsuite_hooks.h>
 
 void test01()
 {
-  bool test __attribute__((unused)) = true;
   using std::decay;
   using std::is_same;
 
   // Positive tests.
   typedef decay<bool>::type            test1_type;
-  VERIFY( (is_same<test1_type, bool>::value) );
+  static_assert( is_same<test1_type, bool>(), "decay<bool>" );
 
   // NB: DR 705.
   typedef decay<const int>::type       test2_type;
-  VERIFY( (is_same<test2_type, int>::value) );
+  static_assert( is_same<test2_type, int>(), "decay<const int>" );
 
   typedef decay<int[4]>::type          test3_type;
-  VERIFY( (is_same<test3_type, std::remove_extent<int[4]>::type*>::value) );
+  static_assert( is_same<test3_type, std::remove_extent<int[4]>::type*>(),
+                 "decay<int[4]>" );
 
   typedef void (fn_type) ();
   typedef decay<fn_type>::type         test4_type;
-  VERIFY( (is_same<test4_type, std::add_pointer<fn_type>::type>::value) );
+  static_assert( is_same<test4_type, std::add_pointer<fn_type>::type>(),
+                 "decay<fn_type>" );
 
   typedef void (cfn_type) () const;
   typedef decay<cfn_type>::type        test5_type;
-  VERIFY( (is_same<test5_type, cfn_type>::value) );
-}
-
-int main()
-{
-  test01();
-  return 0;
+  static_assert( is_same<test5_type, cfn_type>(), "decay<cfn_type>" );
 }
index 1aeba824ec5ee96769d9580cd136266eb031039e..d01bdf31fa25bdd2ea2bc0070f737587e64edf81 100644 (file)
@@ -19,7 +19,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 1938 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2003 }
 
 #include <utility>
 
diff --git a/libstdc++-v3/testsuite/20_util/enable_if/requirements/typedefs-2.cc b/libstdc++-v3/testsuite/20_util/enable_if/requirements/typedefs-2.cc
new file mode 100644 (file)
index 0000000..42b7f4f
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+static_assert( is_same<enable_if<true>::type, enable_if_t<true>>(),
+               "enable_if_t<true>" );
+struct X;
+static_assert( is_same<enable_if<true, X>::type, enable_if_t<true, X>>(),
+               "enable_if_t<true, X>" );
index a0e70e6db6312615d48c68a1c1e27b5a2d5437c2..18791c6a9c9df8b13c2b04cac0e9b6f75a47a0d7 100644 (file)
@@ -1,4 +1,5 @@
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
 
 // 2007-05-03  Benjamin Kosnik  <bkoz@redhat.com>
 //
 // <http://www.gnu.org/licenses/>.
 
 #include <type_traits>
-#include <testsuite_hooks.h>
 
 enum test_enum { first_selection };
 
 void test01()
 {
-  bool test __attribute__((unused)) = true;
   using std::make_signed;
   using std::is_same;
   using std::is_signed;
 
   // Positive tests.
   typedef make_signed<const int>::type         test2_type;
-  VERIFY( (is_same<test2_type, const int>::value) );
+  static_assert( is_same<test2_type, const int>::value,
+                 "make_signed<const int>" );
 
   typedef make_signed<const unsigned int>::type        test21c_type;
-  VERIFY( (is_same<test21c_type, const signed int>::value) );
+  static_assert( is_same<test21c_type, const signed int>::value,
+                 "make_signed<const unsigned int>" );
 
   typedef make_signed<volatile unsigned int>::type     test21v_type;
-  VERIFY( (is_same<test21v_type, volatile signed int>::value) );
+  static_assert( is_same<test21v_type, volatile signed int>::value,
+                 "make_signed<volatile unsigned int>" );
 
   typedef make_signed<const volatile unsigned int>::type       test21cv_type;
-  VERIFY( (is_same<test21cv_type, const volatile signed int>::value) );
+  static_assert( is_same<test21cv_type, const volatile signed int>::value,
+                 "make_signed<const volatile unsigned int>" );
 
   typedef make_signed<const char>::type        test22_type;
-  VERIFY( (is_same<test22_type, const signed char>::value) );
+  static_assert( is_same<test22_type, const signed char>::value,
+                 "make_signed<const char>" );
 
 #ifdef _GLIBCXX_USE_WCHAR_T
   typedef make_signed<volatile wchar_t>::type          test23_type;
-  VERIFY( (is_same<test23_type, volatile signed wchar_t>::value) );
+  static_assert( is_same<test23_type, volatile signed wchar_t>::value,
+                 "make_signed<volatile wchar_t>" );
 #endif
 
   // Chapter 48, chapter 20. Smallest rank such that new signed type same size.
   typedef make_signed<test_enum>::type         test24_type;
-  VERIFY( is_signed<test24_type>::value );
-  VERIFY( sizeof(test24_type) == sizeof(test_enum) );
+  static_assert( is_signed<test24_type>::value,
+                 "make_signed<test_enum> makes signed type" );
+  static_assert( sizeof(test24_type) == sizeof(test_enum),
+                 "make_signed<test_enum> makes type of same size" );
 
   // GNU Extensions.
 #ifdef _GLIBCXX_USE_INT128
   typedef make_signed<unsigned __int128>::type  test25_type;
-  VERIFY( (is_same<test25_type, __int128>::value) );
+  static_assert( is_same<test25_type, __int128>::value,
+                 "make_signed<unsigned __int128>" );
 
   typedef make_signed<__int128>::type                  test26_type;
-  VERIFY( (is_same<test26_type, __int128>::value) );
+  static_assert( is_same<test26_type, __int128>::value,
+                 "make_signed<__int128>" );
 #endif
 }
-
-int main()
-{
-  test01();
-  return 0;
-}
diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs-3.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs-3.cc
new file mode 100644 (file)
index 0000000..f769004
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+template<typename Trait, typename Result>
+  using test = is_same<typename Trait::type, Result>;
+
+static_assert( test<make_signed<const int>, make_signed_t<const int>>(),
+               "make_signed_t<const int>" );
+
+static_assert( test<make_signed<unsigned>, make_signed_t<unsigned>>(),
+               "make_signed_t<unsigned>" );
+
+static_assert( test<make_signed<char>, make_signed_t<char>>(),
+               "make_signed_t<char>" );
index 53090b345642b25a330cc1ac2e9af341370721ff..30a19cf0c862b51c071c27b312dcdaf823ae80c4 100644 (file)
@@ -48,5 +48,5 @@ void test01()
 // { dg-error "required from here" "" { target *-*-* } 40 }
 // { dg-error "required from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1676 }
-// { dg-error "declaration of" "" { target *-*-* } 1640 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1714 }
+// { dg-error "declaration of" "" { target *-*-* } 1678 }
diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs-3.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs-3.cc
new file mode 100644 (file)
index 0000000..4bcabe5
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+template<typename Trait, typename Result>
+  using test = is_same<typename Trait::type, Result>;
+
+static_assert( test<make_unsigned<const int>, make_unsigned_t<const int>>(),
+               "make_unsigned_t<const int>" );
+
+static_assert( test<make_unsigned<unsigned>, make_unsigned_t<unsigned>>(),
+               "make_unsigned_t<unsigned>" );
+
+static_assert( test<make_unsigned<char>, make_unsigned_t<char>>(),
+               "make_unsigned_t<char>" );
index 7b7e59911f45f72b4ffb1d75bcc59b2fba6e7ca3..567908e43d65e193068356aef41dcfc609377bb1 100644 (file)
@@ -48,5 +48,5 @@ void test01()
 // { dg-error "required from here" "" { target *-*-* } 40 }
 // { dg-error "required from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1594 }
-// { dg-error "declaration of" "" { target *-*-* } 1558 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1632 }
+// { dg-error "declaration of" "" { target *-*-* } 1596 }
diff --git a/libstdc++-v3/testsuite/20_util/remove_reference/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/remove_reference/requirements/typedefs.cc
new file mode 100644 (file)
index 0000000..209cca4
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+static_assert( is_same<remove_reference<int>::type, remove_reference_t<int>>(),
+               "remove_reference_t<int>" );
+static_assert( is_same<remove_reference<int&>::type, remove_reference_t<int&>>(),
+               "remove_reference_t<int&>" );
+static_assert( is_same<remove_reference<int&&>::type, remove_reference_t<int&&>>(),
+               "remove_reference_t<int&&>" );
diff --git a/libstdc++-v3/testsuite/20_util/result_of/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/result_of/requirements/typedefs.cc
new file mode 100644 (file)
index 0000000..7c00704
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+using namespace std;
+
+using F1 = char(*)(char);
+static_assert( is_same<result_of<F1(int)>::type, result_of_t<F1(int)>>(),
+               "result_of_t<F1(int)>" );
+
+struct X { };
+using F2 = int X::*;
+static_assert( is_same<result_of<F2(X)>::type, result_of_t<F2(X)>>(),
+               "result_of_t<F2(X)>" );
diff --git a/libstdc++-v3/testsuite/20_util/underlying_type/requirements/typedefs-3.cc b/libstdc++-v3/testsuite/20_util/underlying_type/requirements/typedefs-3.cc
new file mode 100644 (file)
index 0000000..a4c5257
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++1y" }
+// { dg-do compile }
+//
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+//
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+using namespace std;
+
+enum E : long { };
+
+static_assert( is_same<typename underlying_type<E>::type,
+                       underlying_type_t<E>>(),
+               "underlying_type_t" );
index bbd932818c676a9ec558d8983967fe4057a36171..53c23a197ca2071c2ecf31bf035b07b0ba8e58ad 100644 (file)
@@ -63,11 +63,12 @@ int main()
   }
 
   {
-    std::experimental::optional<long> o { std::experimental::in_place, 0x1234ABCDF1E2D3C4 };
+    const long val = 0x1234ABCD;
+    std::experimental::optional<long> o { std::experimental::in_place, val};
     auto copy = o;
     VERIFY( copy );
-    VERIFY( *copy == 0x1234ABCDF1E2D3C4 );
-    VERIFY( o && o == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *copy == val );
+    VERIFY( o && o == val );
   }
 
   {
index 75d7677b7aa99c6a9e32f5adcff0b963cb0c63cd..ba31699091098bb199ea952c2a542902a39e0369 100644 (file)
@@ -63,11 +63,12 @@ int main()
   }
 
   {
-    std::experimental::optional<long> o { std::experimental::in_place, 0x1234ABCDF1E2D3C4 };
+    const long val = 0x1234ABCD;
+    std::experimental::optional<long> o { std::experimental::in_place, val};
     auto moved_to = std::move(o);
     VERIFY( moved_to );
-    VERIFY( *moved_to == 0x1234ABCDF1E2D3C4 );
-    VERIFY( o && *o == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *moved_to == val );
+    VERIFY( o && *o == val );
   }
 
   {
index 339c120707c2a7842d9be0f82821fea91a4d4739..1eba62d6d50ca5abdba35b3d35cf911fad927a86 100644 (file)
@@ -66,51 +66,51 @@ int main()
   // [20.5.4.1] Constructors
 
   {
-    auto i = 0x1234ABCDF1E2D3C4;
+    auto i = 0x1234ABCD;
     std::experimental::optional<long> o { i };
     VERIFY( o );
-    VERIFY( *o == 0x1234ABCDF1E2D3C4 );
-    VERIFY( i == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *o == 0x1234ABCD );
+    VERIFY( i == 0x1234ABCD );
   }
 
   {
-    auto i = 0x1234ABCDF1E2D3C4;
+    auto i = 0x1234ABCD;
     std::experimental::optional<long> o = i;
     VERIFY( o );
-    VERIFY( *o == 0x1234ABCDF1E2D3C4 );
-    VERIFY( i == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *o == 0x1234ABCD );
+    VERIFY( i == 0x1234ABCD );
   }
 
   {
-    auto i = 0x1234ABCDF1E2D3C4;
+    auto i = 0x1234ABCD;
     std::experimental::optional<long> o = { i };
     VERIFY( o );
-    VERIFY( *o == 0x1234ABCDF1E2D3C4 );
-    VERIFY( i == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *o == 0x1234ABCD );
+    VERIFY( i == 0x1234ABCD );
   }
 
   {
-    auto i = 0x1234ABCDF1E2D3C4;
+    auto i = 0x1234ABCD;
     std::experimental::optional<long> o { std::move(i) };
     VERIFY( o );
-    VERIFY( *o == 0x1234ABCDF1E2D3C4 );
-    VERIFY( i == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *o == 0x1234ABCD );
+    VERIFY( i == 0x1234ABCD );
   }
 
   {
-    auto i = 0x1234ABCDF1E2D3C4;
+    auto i = 0x1234ABCD;
     std::experimental::optional<long> o = std::move(i);
     VERIFY( o );
-    VERIFY( *o == 0x1234ABCDF1E2D3C4 );
-    VERIFY( i == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *o == 0x1234ABCD );
+    VERIFY( i == 0x1234ABCD );
   }
 
   {
-    auto i = 0x1234ABCDF1E2D3C4;
+    auto i = 0x1234ABCD;
     std::experimental::optional<long> o = { std::move(i) };
     VERIFY( o );
-    VERIFY( *o == 0x1234ABCDF1E2D3C4 );
-    VERIFY( i == 0x1234ABCDF1E2D3C4 );
+    VERIFY( *o == 0x1234ABCD );
+    VERIFY( i == 0x1234ABCD );
   }
 
   {
index 98e0a224a3766fab6d36f075c4f2caa6905a9e30..eb7233b261794a226d28f06f28a03079be11e3f5 100644 (file)
@@ -26,44 +26,44 @@ int main()
   // [20.5.4.1] Constructors
 
   {
-    constexpr auto i = 0x1234ABCDF1E2D3C4;
+    constexpr long i = 0x1234ABCD;
     constexpr std::experimental::optional<long> o { i };
     static_assert( o, "" );
-    static_assert( *o == 0x1234ABCDF1E2D3C4, "" );
+    static_assert( *o == 0x1234ABCD, "" );
   }
 
   {
-    constexpr auto i = 0x1234ABCDF1E2D3C4;
+    constexpr long i = 0x1234ABCD;
     constexpr std::experimental::optional<long> o = i;
     static_assert( o, "" );
-    static_assert( *o == 0x1234ABCDF1E2D3C4, "" );
+    static_assert( *o == 0x1234ABCD, "" );
   }
 
   {
-    constexpr auto i = 0x1234ABCDF1E2D3C4;
+    constexpr long i = 0x1234ABCD;
     constexpr std::experimental::optional<long> o = { i };
     static_assert( o, "" );
-    static_assert( *o == 0x1234ABCDF1E2D3C4, "" );
+    static_assert( *o == 0x1234ABCD, "" );
   }
 
   {
-    constexpr auto i = 0x1234ABCDF1E2D3C4;
+    constexpr long i = 0x1234ABCD;
     constexpr std::experimental::optional<long> o { std::move(i) };
     static_assert( o, "" );
-    static_assert( *o == 0x1234ABCDF1E2D3C4, "" );
+    static_assert( *o == 0x1234ABCD, "" );
   }
 
   {
-    constexpr auto i = 0x1234ABCDF1E2D3C4;
+    constexpr long i = 0x1234ABCD;
     constexpr std::experimental::optional<long> o = std::move(i);
     static_assert( o, "" );
-    static_assert( *o == 0x1234ABCDF1E2D3C4, "" );
+    static_assert( *o == 0x1234ABCD, "" );
   }
 
   {
-    constexpr auto i = 0x1234ABCDF1E2D3C4;
+    constexpr long i = 0x1234ABCD;
     constexpr std::experimental::optional<long> o = { std::move(i) };
     static_assert( o, "" );
-    static_assert( *o == 0x1234ABCDF1E2D3C4, "" );
+    static_assert( *o == 0x1234ABCD, "" );
   }
 }