Commit 5d3805fc by Jakub Jelinek Committed by Jakub Jelinek

ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch builtins...

	* ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch
	builtins, store max (log2 (align), 0) into uchar field instead of
	align into uptr field.
	(ubsan_expand_objsize_ifn): Use _v1 suffixed type mismatch builtins,
	store uchar 0 field instead of uptr 0 field.
	(instrument_nonnull_return): Use _v1 suffixed nonnull return builtin,
	instead of passing one address of struct with 2 locations pass
	two addresses of structs with 1 location each.
	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH,
	BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT,
	BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN,
	BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT): Removed.
	(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1,
	BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT,
	BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1,
	BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT): New builtins.

	* c-c++-common/ubsan/float-cast-overflow-1.c: Drop value keyword
	from expected output regexps.
	* c-c++-common/ubsan/float-cast-overflow-2.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-3.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-4.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-5.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-6.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-8.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-9.c: Likewise.
	* c-c++-common/ubsan/float-cast-overflow-10.c: Likewise.
	* g++.dg/ubsan/float-cast-overflow-bf.C: Likewise.
	* gcc.dg/ubsan/float-cast-overflow-bf.c: Likewise.
	* g++.dg/asan/default-options-1.C (__asan_default_options): Add
	used attribute.
	* g++.dg/asan/asan_test.C: Run with ASAN_OPTIONS=handle_segv=2
	in the environment.

	* All source files: Merge from upstream 315899.
        * asan/Makefile.am (nodist_saninclude_HEADERS): Add
	include/sanitizer/tsan_interface.h.
        * asan/libtool-version: Bump the libasan SONAME.
	* lsan/Makefile.am (sanitizer_lsan_files): Add lsan_common_mac.cc.
	(lsan_files): Add lsan_linux.cc, lsan_mac.cc and lsan_malloc_mac.cc.
        * sanitizer_common/Makefile.am (sanitizer_common_files): Add
	sancov_flags.cc, sanitizer_allocator_checks.cc,
	sanitizer_coverage_libcdep_new.cc, sanitizer_errno.cc,
	sanitizer_file.cc, sanitizer_mac_libcdep.cc and
	sanitizer_stoptheworld_mac.cc.  Remove sanitizer_coverage_libcdep.cc
	and sanitizer_coverage_mapping_libcdep.cc.
        * tsan/Makefile.am (tsan_files): Add tsan_external.cc.
	* ubsan/Makefile.am (DEFS): Add -DUBSAN_CAN_USE_CXXABI=1.
	(ubsan_files): Add ubsan_init_standalone.cc and
	ubsan_signals_standalone.cc.
	* ubsan/libtool-version: Bump the libubsan SONAME.
        * asan/Makefile.in: Regenerate.
        * lsan/Makefile.in: Regenerate.
        * sanitizer_common/Makefile.in: Regenerate.
        * tsan/Makefile.in: Regenerate.
	* ubsan/Makefile.in: Regenerate.

From-SVN: r253887
parent 93659712
2017-10-19 Jakub Jelinek <jakub@redhat.com>
* ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch
builtins, store max (log2 (align), 0) into uchar field instead of
align into uptr field.
(ubsan_expand_objsize_ifn): Use _v1 suffixed type mismatch builtins,
store uchar 0 field instead of uptr 0 field.
(instrument_nonnull_return): Use _v1 suffixed nonnull return builtin,
instead of passing one address of struct with 2 locations pass
two addresses of structs with 1 location each.
* sanitizer.def (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH,
BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT,
BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN,
BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT): Removed.
(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1,
BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT,
BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1,
BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT): New builtins.
2017-10-19 Martin Liska <mliska@suse.cz> 2017-10-19 Martin Liska <mliska@suse.cz>
PR driver/81829 PR driver/81829
...@@ -424,8 +424,8 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE, ...@@ -424,8 +424,8 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE,
"__ubsan_handle_vla_bound_not_positive", "__ubsan_handle_vla_bound_not_positive",
BT_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST) ATTR_COLD_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1,
"__ubsan_handle_type_mismatch", "__ubsan_handle_type_mismatch_v1",
BT_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST) ATTR_COLD_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW,
...@@ -464,8 +464,8 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT, ...@@ -464,8 +464,8 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT,
"__ubsan_handle_vla_bound_not_positive_abort", "__ubsan_handle_vla_bound_not_positive_abort",
BT_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST) ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT,
"__ubsan_handle_type_mismatch_abort", "__ubsan_handle_type_mismatch_v1_abort",
BT_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST) ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT,
...@@ -516,13 +516,13 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT, ...@@ -516,13 +516,13 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT,
"__ubsan_handle_nonnull_arg_abort", "__ubsan_handle_nonnull_arg_abort",
BT_FN_VOID_PTR, BT_FN_VOID_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST) ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1,
"__ubsan_handle_nonnull_return", "__ubsan_handle_nonnull_return_v1",
BT_FN_VOID_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST) ATTR_COLD_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT,
"__ubsan_handle_nonnull_return_abort", "__ubsan_handle_nonnull_return_v1_abort",
BT_FN_VOID_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST) ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS,
"__ubsan_handle_dynamic_type_cache_miss", "__ubsan_handle_dynamic_type_cache_miss",
......
2017-10-19 Jakub Jelinek <jakub@redhat.com> 2017-10-19 Jakub Jelinek <jakub@redhat.com>
* c-c++-common/ubsan/float-cast-overflow-1.c: Drop value keyword
from expected output regexps.
* c-c++-common/ubsan/float-cast-overflow-2.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-3.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-4.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-5.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-6.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-8.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-9.c: Likewise.
* c-c++-common/ubsan/float-cast-overflow-10.c: Likewise.
* g++.dg/ubsan/float-cast-overflow-bf.C: Likewise.
* gcc.dg/ubsan/float-cast-overflow-bf.c: Likewise.
* g++.dg/asan/default-options-1.C (__asan_default_options): Add
used attribute.
* g++.dg/asan/asan_test.C: Run with ASAN_OPTIONS=handle_segv=2
in the environment.
PR target/82580 PR target/82580
* gcc.target/i386/pr82580.c: Use {\msbb} instead of "sbb" in * gcc.target/i386/pr82580.c: Use {\msbb} instead of "sbb" in
scan-assembler-times. Check that there are no movzb* instructions scan-assembler-times. Check that there are no movzb* instructions
......
...@@ -9,38 +9,38 @@ ...@@ -9,38 +9,38 @@
#include "float-cast-overflow-8.c" #include "float-cast-overflow-8.c"
/* _Decimal32 */ /* _Decimal32 */
/* { dg-output "value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* _Decimal64 */ /* _Decimal64 */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* _Decimal128 */ /* _Decimal128 */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
...@@ -26,15 +26,15 @@ main (void) ...@@ -26,15 +26,15 @@ main (void)
return 0; return 0;
} }
/* { dg-output "value -133* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " -133* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type" } */
...@@ -30,23 +30,23 @@ main (void) ...@@ -30,23 +30,23 @@ main (void)
return 0; return 0;
} }
/* { dg-output "value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type" } */ /* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type" } */
...@@ -26,15 +26,15 @@ main (void) ...@@ -26,15 +26,15 @@ main (void)
return 0; return 0;
} }
/* { dg-output "value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type" } */ /* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type" } */
...@@ -26,15 +26,15 @@ main (void) ...@@ -26,15 +26,15 @@ main (void)
return 0; return 0;
} }
/* { dg-output "value -133 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " -133 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type" } */
...@@ -6,30 +6,30 @@ ...@@ -6,30 +6,30 @@
#include "float-cast-overflow-8.c" #include "float-cast-overflow-8.c"
/* __float80 */ /* __float80 */
/* { dg-output "value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */ /* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
/* __float128 */ /* __float128 */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */ /* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
// { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS=1" { target { ! run_expensive_tests } } } // { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS=1" { target { ! run_expensive_tests } } }
// { dg-additional-options "-msse2" { target { i?86-*-linux* x86_64-*-linux* } } } // { dg-additional-options "-msse2" { target { i?86-*-linux* x86_64-*-linux* } } }
// { dg-additional-options "-D__NO_INLINE__" { target { *-*-linux-gnu } } } // { dg-additional-options "-D__NO_INLINE__" { target { *-*-linux-gnu } } }
// { dg-set-target-env-var ASAN_OPTIONS "handle_segv=2" }
// { dg-final { asan-gtest } } // { dg-final { asan-gtest } }
#include "asan_test.cc" #include "asan_test.cc"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
const char *kAsanDefaultOptions="verbosity=1 foo=bar"; const char *kAsanDefaultOptions="verbosity=1 foo=bar";
extern "C" extern "C"
__attribute__((no_sanitize_address)) __attribute__((no_sanitize_address, used))
const char *__asan_default_options() { const char *__asan_default_options() {
return kAsanDefaultOptions; return kAsanDefaultOptions;
} }
......
...@@ -52,11 +52,11 @@ main (void) ...@@ -52,11 +52,11 @@ main (void)
return 0; return 0;
} }
/* { dg-output "value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type" } */
...@@ -48,25 +48,25 @@ main (void) ...@@ -48,25 +48,25 @@ main (void)
return 0; return 0;
} }
/* { dg-output "value -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output " -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */ /* { dg-output "\[^\n\r]* 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*value 2.5 is outside the range of representable values of type" } */ /* { dg-output "\[^\n\r]* 2.5 is outside the range of representable values of type" } */
...@@ -830,15 +830,17 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip) ...@@ -830,15 +830,17 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
enum built_in_function bcode enum built_in_function bcode
= (flag_sanitize_recover & ((check_align ? SANITIZE_ALIGNMENT : 0) = (flag_sanitize_recover & ((check_align ? SANITIZE_ALIGNMENT : 0)
| (check_null ? SANITIZE_NULL : 0))) | (check_null ? SANITIZE_NULL : 0)))
? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
: BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT; : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
tree fn = builtin_decl_implicit (bcode); tree fn = builtin_decl_implicit (bcode);
int align_log = tree_log2 (align);
tree data tree data
= ubsan_create_data ("__ubsan_null_data", 1, &loc, = ubsan_create_data ("__ubsan_null_data", 1, &loc,
ubsan_type_descriptor (TREE_TYPE (ckind), ubsan_type_descriptor (TREE_TYPE (ckind),
UBSAN_PRINT_POINTER), UBSAN_PRINT_POINTER),
NULL_TREE, NULL_TREE,
align, build_int_cst (unsigned_char_type_node,
MAX (align_log, 0)),
fold_convert (unsigned_char_type_node, ckind), fold_convert (unsigned_char_type_node, ckind),
NULL_TREE); NULL_TREE);
data = build_fold_addr_expr_loc (loc, data); data = build_fold_addr_expr_loc (loc, data);
...@@ -1001,14 +1003,14 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi) ...@@ -1001,14 +1003,14 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
ubsan_type_descriptor (TREE_TYPE (ptr), ubsan_type_descriptor (TREE_TYPE (ptr),
UBSAN_PRINT_POINTER), UBSAN_PRINT_POINTER),
NULL_TREE, NULL_TREE,
build_zero_cst (pointer_sized_int_node), build_zero_cst (unsigned_char_type_node),
ckind, ckind,
NULL_TREE); NULL_TREE);
data = build_fold_addr_expr_loc (loc, data); data = build_fold_addr_expr_loc (loc, data);
enum built_in_function bcode enum built_in_function bcode
= (flag_sanitize_recover & SANITIZE_OBJECT_SIZE) = (flag_sanitize_recover & SANITIZE_OBJECT_SIZE)
? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
: BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT; : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
tree p = make_ssa_name (pointer_sized_int_node); tree p = make_ssa_name (pointer_sized_int_node);
g = gimple_build_assign (p, NOP_EXPR, ptr); g = gimple_build_assign (p, NOP_EXPR, ptr);
gimple_set_location (g, loc); gimple_set_location (g, loc);
...@@ -2024,15 +2026,18 @@ instrument_nonnull_return (gimple_stmt_iterator *gsi) ...@@ -2024,15 +2026,18 @@ instrument_nonnull_return (gimple_stmt_iterator *gsi)
else else
{ {
tree data = ubsan_create_data ("__ubsan_nonnull_return_data", tree data = ubsan_create_data ("__ubsan_nonnull_return_data",
2, loc, NULL_TREE, NULL_TREE); 1, &loc[1], NULL_TREE, NULL_TREE);
data = build_fold_addr_expr_loc (loc[0], data); data = build_fold_addr_expr_loc (loc[0], data);
tree data2 = ubsan_create_data ("__ubsan_nonnull_return_data",
1, &loc[0], NULL_TREE, NULL_TREE);
data2 = build_fold_addr_expr_loc (loc[0], data2);
enum built_in_function bcode enum built_in_function bcode
= (flag_sanitize_recover & SANITIZE_RETURNS_NONNULL_ATTRIBUTE) = (flag_sanitize_recover & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1
: BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT; : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT;
tree fn = builtin_decl_explicit (bcode); tree fn = builtin_decl_explicit (bcode);
g = gimple_build_call (fn, 1, data); g = gimple_build_call (fn, 2, data, data2);
} }
gimple_set_location (g, loc[0]); gimple_set_location (g, loc[0]);
gsi_insert_before (gsi, g, GSI_SAME_STMT); gsi_insert_before (gsi, g, GSI_SAME_STMT);
......
2017-10-19 Jakub Jelinek <jakub@redhat.com>
* All source files: Merge from upstream 315899.
* asan/Makefile.am (nodist_saninclude_HEADERS): Add
include/sanitizer/tsan_interface.h.
* asan/libtool-version: Bump the libasan SONAME.
* lsan/Makefile.am (sanitizer_lsan_files): Add lsan_common_mac.cc.
(lsan_files): Add lsan_linux.cc, lsan_mac.cc and lsan_malloc_mac.cc.
* sanitizer_common/Makefile.am (sanitizer_common_files): Add
sancov_flags.cc, sanitizer_allocator_checks.cc,
sanitizer_coverage_libcdep_new.cc, sanitizer_errno.cc,
sanitizer_file.cc, sanitizer_mac_libcdep.cc and
sanitizer_stoptheworld_mac.cc. Remove sanitizer_coverage_libcdep.cc
and sanitizer_coverage_mapping_libcdep.cc.
* tsan/Makefile.am (tsan_files): Add tsan_external.cc.
* ubsan/Makefile.am (DEFS): Add -DUBSAN_CAN_USE_CXXABI=1.
(ubsan_files): Add ubsan_init_standalone.cc and
ubsan_signals_standalone.cc.
* ubsan/libtool-version: Bump the libubsan SONAME.
* asan/Makefile.in: Regenerate.
* lsan/Makefile.in: Regenerate.
* sanitizer_common/Makefile.in: Regenerate.
* tsan/Makefile.in: Regenerate.
* ubsan/Makefile.in: Regenerate.
2017-10-05 H.J. Lu <hongjiu.lu@intel.com> 2017-10-05 H.J. Lu <hongjiu.lu@intel.com>
PR sanitizer/82379 PR sanitizer/82379
......
285547 315899
The first line of this file holds the svn revision number of the The first line of this file holds the svn revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -17,7 +17,8 @@ endif ...@@ -17,7 +17,8 @@ endif
SUBDIRS += lsan asan ubsan SUBDIRS += lsan asan ubsan
nodist_saninclude_HEADERS += \ nodist_saninclude_HEADERS += \
include/sanitizer/lsan_interface.h \ include/sanitizer/lsan_interface.h \
include/sanitizer/asan_interface.h include/sanitizer/asan_interface.h \
include/sanitizer/tsan_interface.h
if TSAN_SUPPORTED if TSAN_SUPPORTED
SUBDIRS += tsan SUBDIRS += tsan
endif endif
......
...@@ -54,7 +54,8 @@ host_triplet = @host@ ...@@ -54,7 +54,8 @@ host_triplet = @host@
target_triplet = @target@ target_triplet = @target@
@SANITIZER_SUPPORTED_TRUE@am__append_1 = include/sanitizer/common_interface_defs.h \ @SANITIZER_SUPPORTED_TRUE@am__append_1 = include/sanitizer/common_interface_defs.h \
@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/lsan_interface.h \ @SANITIZER_SUPPORTED_TRUE@ include/sanitizer/lsan_interface.h \
@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/asan_interface.h @SANITIZER_SUPPORTED_TRUE@ include/sanitizer/asan_interface.h \
@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/tsan_interface.h
@SANITIZER_SUPPORTED_TRUE@@USING_MAC_INTERPOSE_FALSE@am__append_2 = interception @SANITIZER_SUPPORTED_TRUE@@USING_MAC_INTERPOSE_FALSE@am__append_2 = interception
@LIBBACKTRACE_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_3 = libbacktrace @LIBBACKTRACE_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_3 = libbacktrace
@SANITIZER_SUPPORTED_TRUE@@TSAN_SUPPORTED_TRUE@am__append_4 = tsan @SANITIZER_SUPPORTED_TRUE@@TSAN_SUPPORTED_TRUE@am__append_4 = tsan
......
...@@ -25,6 +25,7 @@ asan_files = \ ...@@ -25,6 +25,7 @@ asan_files = \
asan_flags.cc \ asan_flags.cc \
asan_globals.cc \ asan_globals.cc \
asan_interceptors.cc \ asan_interceptors.cc \
asan_interceptors_memintrinsics.cc \
asan_linux.cc \ asan_linux.cc \
asan_mac.cc \ asan_mac.cc \
asan_malloc_linux.cc \ asan_malloc_linux.cc \
...@@ -36,6 +37,7 @@ asan_files = \ ...@@ -36,6 +37,7 @@ asan_files = \
asan_posix.cc \ asan_posix.cc \
asan_report.cc \ asan_report.cc \
asan_rtl.cc \ asan_rtl.cc \
asan_shadow_setup.cc \
asan_stack.cc \ asan_stack.cc \
asan_stats.cc \ asan_stats.cc \
asan_suppressions.cc \ asan_suppressions.cc \
......
...@@ -114,12 +114,13 @@ libasan_la_DEPENDENCIES = \ ...@@ -114,12 +114,13 @@ libasan_la_DEPENDENCIES = \
am__objects_1 = asan_activation.lo asan_allocator.lo asan_debugging.lo \ am__objects_1 = asan_activation.lo asan_allocator.lo asan_debugging.lo \
asan_descriptions.lo asan_errors.lo asan_fake_stack.lo \ asan_descriptions.lo asan_errors.lo asan_fake_stack.lo \
asan_flags.lo asan_globals.lo asan_interceptors.lo \ asan_flags.lo asan_globals.lo asan_interceptors.lo \
asan_linux.lo asan_mac.lo asan_malloc_linux.lo \ asan_interceptors_memintrinsics.lo asan_linux.lo asan_mac.lo \
asan_malloc_mac.lo asan_malloc_win.lo asan_memory_profile.lo \ asan_malloc_linux.lo asan_malloc_mac.lo asan_malloc_win.lo \
asan_new_delete.lo asan_poisoning.lo asan_posix.lo \ asan_memory_profile.lo asan_new_delete.lo asan_poisoning.lo \
asan_report.lo asan_rtl.lo asan_stack.lo asan_stats.lo \ asan_posix.lo asan_report.lo asan_rtl.lo asan_shadow_setup.lo \
asan_suppressions.lo asan_thread.lo asan_win.lo \ asan_stack.lo asan_stats.lo asan_suppressions.lo \
asan_win_dll_thunk.lo asan_win_dynamic_runtime_thunk.lo asan_thread.lo asan_win.lo asan_win_dll_thunk.lo \
asan_win_dynamic_runtime_thunk.lo
am_libasan_la_OBJECTS = $(am__objects_1) am_libasan_la_OBJECTS = $(am__objects_1)
libasan_la_OBJECTS = $(am_libasan_la_OBJECTS) libasan_la_OBJECTS = $(am_libasan_la_OBJECTS)
libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
...@@ -317,6 +318,7 @@ asan_files = \ ...@@ -317,6 +318,7 @@ asan_files = \
asan_flags.cc \ asan_flags.cc \
asan_globals.cc \ asan_globals.cc \
asan_interceptors.cc \ asan_interceptors.cc \
asan_interceptors_memintrinsics.cc \
asan_linux.cc \ asan_linux.cc \
asan_mac.cc \ asan_mac.cc \
asan_malloc_linux.cc \ asan_malloc_linux.cc \
...@@ -328,6 +330,7 @@ asan_files = \ ...@@ -328,6 +330,7 @@ asan_files = \
asan_posix.cc \ asan_posix.cc \
asan_report.cc \ asan_report.cc \
asan_rtl.cc \ asan_rtl.cc \
asan_shadow_setup.cc \
asan_stack.cc \ asan_stack.cc \
asan_stats.cc \ asan_stats.cc \
asan_suppressions.cc \ asan_suppressions.cc \
...@@ -466,6 +469,7 @@ distclean-compile: ...@@ -466,6 +469,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_flags.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors_memintrinsics.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_mac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_malloc_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_malloc_linux.Plo@am__quote@
...@@ -477,6 +481,7 @@ distclean-compile: ...@@ -477,6 +481,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_report.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_report.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_rtl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_rtl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_shadow_setup.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stack.Plo@am__quote@ @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_stats.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_suppressions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_suppressions.Plo@am__quote@
......
...@@ -75,13 +75,16 @@ static struct AsanDeactivatedFlags { ...@@ -75,13 +75,16 @@ static struct AsanDeactivatedFlags {
void Print() { void Print() {
Report( Report(
"quarantine_size_mb %d, max_redzone %d, poison_heap %d, " "quarantine_size_mb %d, thread_local_quarantine_size_kb %d, "
"malloc_context_size %d, alloc_dealloc_mismatch %d, " "max_redzone %d, poison_heap %d, malloc_context_size %d, "
"allocator_may_return_null %d, coverage %d, coverage_dir %s\n", "alloc_dealloc_mismatch %d, allocator_may_return_null %d, coverage %d, "
allocator_options.quarantine_size_mb, allocator_options.max_redzone, "coverage_dir %s, allocator_release_to_os_interval_ms %d\n",
poison_heap, malloc_context_size, allocator_options.quarantine_size_mb,
allocator_options.thread_local_quarantine_size_kb,
allocator_options.max_redzone, poison_heap, malloc_context_size,
allocator_options.alloc_dealloc_mismatch, allocator_options.alloc_dealloc_mismatch,
allocator_options.may_return_null, coverage, coverage_dir); allocator_options.may_return_null, coverage, coverage_dir,
allocator_options.release_to_os_interval_ms);
} }
} asan_deactivated_flags; } asan_deactivated_flags;
...@@ -101,10 +104,10 @@ void AsanDeactivate() { ...@@ -101,10 +104,10 @@ void AsanDeactivate() {
// Deactivate the runtime. // Deactivate the runtime.
SetCanPoisonMemory(false); SetCanPoisonMemory(false);
SetMallocContextSize(1); SetMallocContextSize(1);
ReInitializeCoverage(false, nullptr);
AllocatorOptions disabled = asan_deactivated_flags.allocator_options; AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
disabled.quarantine_size_mb = 0; disabled.quarantine_size_mb = 0;
disabled.thread_local_quarantine_size_kb = 0;
disabled.min_redzone = 16; // Redzone must be at least 16 bytes long. disabled.min_redzone = 16; // Redzone must be at least 16 bytes long.
disabled.max_redzone = 16; disabled.max_redzone = 16;
disabled.alloc_dealloc_mismatch = false; disabled.alloc_dealloc_mismatch = false;
...@@ -124,8 +127,6 @@ void AsanActivate() { ...@@ -124,8 +127,6 @@ void AsanActivate() {
SetCanPoisonMemory(asan_deactivated_flags.poison_heap); SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
SetMallocContextSize(asan_deactivated_flags.malloc_context_size); SetMallocContextSize(asan_deactivated_flags.malloc_context_size);
ReInitializeCoverage(asan_deactivated_flags.coverage,
asan_deactivated_flags.coverage_dir);
ReInitializeAllocator(asan_deactivated_flags.allocator_options); ReInitializeAllocator(asan_deactivated_flags.allocator_options);
asan_is_deactivated = false; asan_is_deactivated = false;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
ASAN_ACTIVATION_FLAG(int, redzone) ASAN_ACTIVATION_FLAG(int, redzone)
ASAN_ACTIVATION_FLAG(int, max_redzone) ASAN_ACTIVATION_FLAG(int, max_redzone)
ASAN_ACTIVATION_FLAG(int, quarantine_size_mb) ASAN_ACTIVATION_FLAG(int, quarantine_size_mb)
ASAN_ACTIVATION_FLAG(int, thread_local_quarantine_size_kb)
ASAN_ACTIVATION_FLAG(bool, alloc_dealloc_mismatch) ASAN_ACTIVATION_FLAG(bool, alloc_dealloc_mismatch)
ASAN_ACTIVATION_FLAG(bool, poison_heap) ASAN_ACTIVATION_FLAG(bool, poison_heap)
...@@ -31,3 +32,4 @@ COMMON_ACTIVATION_FLAG(bool, coverage) ...@@ -31,3 +32,4 @@ COMMON_ACTIVATION_FLAG(bool, coverage)
COMMON_ACTIVATION_FLAG(const char *, coverage_dir) COMMON_ACTIVATION_FLAG(const char *, coverage_dir)
COMMON_ACTIVATION_FLAG(int, verbosity) COMMON_ACTIVATION_FLAG(int, verbosity)
COMMON_ACTIVATION_FLAG(bool, help) COMMON_ACTIVATION_FLAG(bool, help)
COMMON_ACTIVATION_FLAG(s32, allocator_release_to_os_interval_ms)
...@@ -31,10 +31,12 @@ struct AsanChunk; ...@@ -31,10 +31,12 @@ struct AsanChunk;
struct AllocatorOptions { struct AllocatorOptions {
u32 quarantine_size_mb; u32 quarantine_size_mb;
u32 thread_local_quarantine_size_kb;
u16 min_redzone; u16 min_redzone;
u16 max_redzone; u16 max_redzone;
u8 may_return_null; u8 may_return_null;
u8 alloc_dealloc_mismatch; u8 alloc_dealloc_mismatch;
s32 release_to_os_interval_ms;
void SetFrom(const Flags *f, const CommonFlags *cf); void SetFrom(const Flags *f, const CommonFlags *cf);
void CopyTo(Flags *f, CommonFlags *cf); void CopyTo(Flags *f, CommonFlags *cf);
...@@ -47,28 +49,29 @@ void GetAllocatorOptions(AllocatorOptions *options); ...@@ -47,28 +49,29 @@ void GetAllocatorOptions(AllocatorOptions *options);
class AsanChunkView { class AsanChunkView {
public: public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
bool IsValid(); // Checks if AsanChunkView points to a valid allocated bool IsValid() const; // Checks if AsanChunkView points to a valid
// or quarantined chunk. // allocated or quarantined chunk.
bool IsAllocated(); // Checks if the memory is currently allocated. bool IsAllocated() const; // Checks if the memory is currently allocated.
uptr Beg(); // First byte of user memory. bool IsQuarantined() const; // Checks if the memory is currently quarantined.
uptr End(); // Last byte of user memory. uptr Beg() const; // First byte of user memory.
uptr UsedSize(); // Size requested by the user. uptr End() const; // Last byte of user memory.
uptr AllocTid(); uptr UsedSize() const; // Size requested by the user.
uptr FreeTid(); uptr AllocTid() const;
uptr FreeTid() const;
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
u32 GetAllocStackId(); u32 GetAllocStackId() const;
u32 GetFreeStackId(); u32 GetFreeStackId() const;
StackTrace GetAllocStack(); StackTrace GetAllocStack() const;
StackTrace GetFreeStack(); StackTrace GetFreeStack() const;
AllocType GetAllocType(); AllocType GetAllocType() const;
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) { bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const {
if (addr >= Beg() && (addr + access_size) <= End()) { if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg(); *offset = addr - Beg();
return true; return true;
} }
return false; return false;
} }
bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) { bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) const {
(void)access_size; (void)access_size;
if (addr < Beg()) { if (addr < Beg()) {
*offset = Beg() - addr; *offset = Beg() - addr;
...@@ -76,7 +79,7 @@ class AsanChunkView { ...@@ -76,7 +79,7 @@ class AsanChunkView {
} }
return false; return false;
} }
bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) { bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) const {
if (addr + access_size > End()) { if (addr + access_size > End()) {
*offset = addr - End(); *offset = addr - End();
return true; return true;
...@@ -114,7 +117,11 @@ struct AsanMapUnmapCallback { ...@@ -114,7 +117,11 @@ struct AsanMapUnmapCallback {
}; };
#if SANITIZER_CAN_USE_ALLOCATOR64 #if SANITIZER_CAN_USE_ALLOCATOR64
# if defined(__powerpc64__) # if SANITIZER_FUCHSIA
const uptr kAllocatorSpace = ~(uptr)0;
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
typedef DefaultSizeClassMap SizeClassMap;
# elif defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T. const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
typedef DefaultSizeClassMap SizeClassMap; typedef DefaultSizeClassMap SizeClassMap;
...@@ -156,10 +163,17 @@ typedef FlatByteMap<kNumRegions> ByteMap; ...@@ -156,10 +163,17 @@ typedef FlatByteMap<kNumRegions> ByteMap;
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
# endif # endif
typedef CompactSizeClassMap SizeClassMap; typedef CompactSizeClassMap SizeClassMap;
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16, struct AP32 {
SizeClassMap, kRegionSizeLog, static const uptr kSpaceBeg = 0;
ByteMap, static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
AsanMapUnmapCallback> PrimaryAllocator; static const uptr kMetadataSize = 16;
typedef __asan::SizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = __asan::kRegionSizeLog;
typedef __asan::ByteMap ByteMap;
typedef AsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
#endif // SANITIZER_CAN_USE_ALLOCATOR64 #endif // SANITIZER_CAN_USE_ALLOCATOR64
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses; static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
......
...@@ -148,7 +148,7 @@ static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { ...@@ -148,7 +148,7 @@ static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size,
(void *)descr.chunk_begin, (void *)descr.chunk_begin,
(void *)(descr.chunk_begin + descr.chunk_size)); (void *)(descr.chunk_begin + descr.chunk_size));
str.append("%s", d.EndLocation()); str.append("%s", d.Default());
Printf("%s", str.data()); Printf("%s", str.data());
} }
...@@ -250,12 +250,15 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, ...@@ -250,12 +250,15 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
str.append("%c", var.name_pos[i]); str.append("%c", var.name_pos[i]);
} }
str.append("'"); str.append("'");
if (var.line > 0) {
str.append(" (line %d)", var.line);
}
if (pos_descr) { if (pos_descr) {
Decorator d; Decorator d;
// FIXME: we may want to also print the size of the access here, // 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. // but in case of accesses generated by memset it may be confusing.
str.append("%s <== Memory access at offset %zd %s this variable%s\n", str.append("%s <== Memory access at offset %zd %s this variable%s\n",
d.Location(), addr, pos_descr, d.EndLocation()); d.Location(), addr, pos_descr, d.Default());
} else { } else {
str.append("\n"); str.append("\n");
} }
...@@ -290,7 +293,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, ...@@ -290,7 +293,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
MaybeDemangleGlobalName(g.name)); MaybeDemangleGlobalName(g.name));
PrintGlobalLocation(&str, g); PrintGlobalLocation(&str, g);
str.append("' (0x%zx) of size %zu\n", g.beg, g.size); str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
str.append("%s", d.EndLocation()); str.append("%s", d.Default());
PrintGlobalNameIfASCII(&str, g); PrintGlobalNameIfASCII(&str, g);
Printf("%s", str.data()); Printf("%s", str.data());
} }
...@@ -338,10 +341,10 @@ void StackAddressDescription::Print() const { ...@@ -338,10 +341,10 @@ void StackAddressDescription::Print() const {
ThreadNameWithParenthesis(tid, tname, sizeof(tname))); ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
if (!frame_descr) { if (!frame_descr) {
Printf("%s\n", d.EndLocation()); Printf("%s\n", d.Default());
return; return;
} }
Printf(" at offset %zu in frame%s\n", offset, d.EndLocation()); Printf(" at offset %zu in frame%s\n", offset, d.Default());
// Now we print the frame where the alloca has happened. // Now we print the frame where the alloca has happened.
// We print this frame as a stack trace with one element. // We print this frame as a stack trace with one element.
...@@ -350,7 +353,7 @@ void StackAddressDescription::Print() const { ...@@ -350,7 +353,7 @@ void StackAddressDescription::Print() const {
// previously. That's unfortunate, but I have no better solution, // previously. That's unfortunate, but I have no better solution,
// especially given that the alloca may be from entirely different place // especially given that the alloca may be from entirely different place
// (e.g. use-after-scope, or different thread's stack). // (e.g. use-after-scope, or different thread's stack).
Printf("%s", d.EndLocation()); Printf("%s", d.Default());
StackTrace alloca_stack(&frame_pc, 1); StackTrace alloca_stack(&frame_pc, 1);
alloca_stack.Print(); alloca_stack.Print();
...@@ -400,18 +403,18 @@ void HeapAddressDescription::Print() const { ...@@ -400,18 +403,18 @@ void HeapAddressDescription::Print() const {
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
free_thread->tid, free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
d.EndAllocation()); d.Default());
StackTrace free_stack = GetStackTraceFromId(free_stack_id); StackTrace free_stack = GetStackTraceFromId(free_stack_id);
free_stack.Print(); free_stack.Print();
Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid, alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation()); d.Default());
} else { } else {
Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid, alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation()); d.Default());
} }
alloc_stack.Print(); alloc_stack.Print();
DescribeThread(GetCurrentThread()); DescribeThread(GetCurrentThread());
......
...@@ -32,11 +32,8 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { ...@@ -32,11 +32,8 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
public: public:
Decorator() : SanitizerCommonDecorator() {} Decorator() : SanitizerCommonDecorator() {}
const char *Access() { return Blue(); } const char *Access() { return Blue(); }
const char *EndAccess() { return Default(); }
const char *Location() { return Green(); } const char *Location() { return Green(); }
const char *EndLocation() { return Default(); }
const char *Allocation() { return Magenta(); } const char *Allocation() { return Magenta(); }
const char *EndAllocation() { return Default(); }
const char *ShadowByte(u8 byte) { const char *ShadowByte(u8 byte) {
switch (byte) { switch (byte) {
...@@ -70,9 +67,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { ...@@ -70,9 +67,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
return Default(); return Default();
} }
} }
const char *EndShadowByte() { return Default(); }
const char *MemoryByte() { return Magenta(); }
const char *EndMemoryByte() { return Default(); }
}; };
enum ShadowKind : u8 { enum ShadowKind : u8 {
......
...@@ -25,61 +25,28 @@ struct ErrorBase { ...@@ -25,61 +25,28 @@ struct ErrorBase {
u32 tid; u32 tid;
}; };
struct ErrorStackOverflow : ErrorBase {
uptr addr, pc, bp, sp;
// ErrorStackOverflow never owns the context.
void *context;
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
// constructor
ErrorStackOverflow() = default;
ErrorStackOverflow(u32 tid, const SignalContext &sig)
: ErrorBase(tid),
addr(sig.addr),
pc(sig.pc),
bp(sig.bp),
sp(sig.sp),
context(sig.context) {
scariness.Clear();
scariness.Scare(10, "stack-overflow");
}
void Print();
};
struct ErrorDeadlySignal : ErrorBase { struct ErrorDeadlySignal : ErrorBase {
uptr addr, pc, bp, sp; SignalContext signal;
// ErrorDeadlySignal never owns the context.
void *context;
int signo;
SignalContext::WriteFlag write_flag;
bool is_memory_access;
// VS2013 doesn't implement unrestricted unions, so we need a trivial default // VS2013 doesn't implement unrestricted unions, so we need a trivial default
// constructor // constructor
ErrorDeadlySignal() = default; ErrorDeadlySignal() = default;
ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_) ErrorDeadlySignal(u32 tid, const SignalContext &sig)
: ErrorBase(tid), : ErrorBase(tid), signal(sig) {
addr(sig.addr),
pc(sig.pc),
bp(sig.bp),
sp(sig.sp),
context(sig.context),
signo(signo_),
write_flag(sig.write_flag),
is_memory_access(sig.is_memory_access) {
scariness.Clear(); scariness.Clear();
if (is_memory_access) { if (signal.IsStackOverflow()) {
if (addr < GetPageSizeCached()) { scariness.Scare(10, "stack-overflow");
scariness.Scare(10, "null-deref"); } else if (!signal.is_memory_access) {
} else if (addr == pc) {
scariness.Scare(60, "wild-jump");
} else if (write_flag == SignalContext::WRITE) {
scariness.Scare(30, "wild-addr-write");
} else if (write_flag == SignalContext::READ) {
scariness.Scare(20, "wild-addr-read");
} else {
scariness.Scare(25, "wild-addr");
}
} else {
scariness.Scare(10, "signal"); scariness.Scare(10, "signal");
} else if (signal.addr < GetPageSizeCached()) {
scariness.Scare(10, "null-deref");
} else if (signal.addr == signal.pc) {
scariness.Scare(60, "wild-jump");
} else if (signal.write_flag == SignalContext::WRITE) {
scariness.Scare(30, "wild-addr-write");
} else if (signal.write_flag == SignalContext::READ) {
scariness.Scare(20, "wild-addr-read");
} else {
scariness.Scare(25, "wild-addr");
} }
} }
void Print(); void Print();
...@@ -170,6 +137,7 @@ struct ErrorMallocUsableSizeNotOwned : ErrorBase { ...@@ -170,6 +137,7 @@ struct ErrorMallocUsableSizeNotOwned : ErrorBase {
stack(stack_), stack(stack_),
addr_description(addr, /*shouldLockThreadRegistry=*/false) { addr_description(addr, /*shouldLockThreadRegistry=*/false) {
scariness.Clear(); scariness.Clear();
scariness.Scare(10, "bad-malloc_usable_size");
} }
void Print(); void Print();
}; };
...@@ -187,6 +155,7 @@ struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase { ...@@ -187,6 +155,7 @@ struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
stack(stack_), stack(stack_),
addr_description(addr, /*shouldLockThreadRegistry=*/false) { addr_description(addr, /*shouldLockThreadRegistry=*/false) {
scariness.Clear(); scariness.Clear();
scariness.Scare(10, "bad-__sanitizer_get_allocated_size");
} }
void Print(); void Print();
}; };
...@@ -256,7 +225,10 @@ struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase { ...@@ -256,7 +225,10 @@ struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
beg(beg_), beg(beg_),
end(end_), end(end_),
old_mid(old_mid_), old_mid(old_mid_),
new_mid(new_mid_) {} new_mid(new_mid_) {
scariness.Clear();
scariness.Scare(10, "bad-__sanitizer_annotate_contiguous_container");
}
void Print(); void Print();
}; };
...@@ -272,7 +244,10 @@ struct ErrorODRViolation : ErrorBase { ...@@ -272,7 +244,10 @@ struct ErrorODRViolation : ErrorBase {
global1(*g1), global1(*g1),
global2(*g2), global2(*g2),
stack_id1(stack_id1_), stack_id1(stack_id1_),
stack_id2(stack_id2_) {} stack_id2(stack_id2_) {
scariness.Clear();
scariness.Scare(10, "odr-violation");
}
void Print(); void Print();
}; };
...@@ -290,7 +265,10 @@ struct ErrorInvalidPointerPair : ErrorBase { ...@@ -290,7 +265,10 @@ struct ErrorInvalidPointerPair : ErrorBase {
bp(bp_), bp(bp_),
sp(sp_), sp(sp_),
addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false), addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false),
addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {} addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {
scariness.Clear();
scariness.Scare(10, "invalid-pointer-pair");
}
void Print(); void Print();
}; };
...@@ -311,7 +289,6 @@ struct ErrorGeneric : ErrorBase { ...@@ -311,7 +289,6 @@ struct ErrorGeneric : ErrorBase {
// clang-format off // clang-format off
#define ASAN_FOR_EACH_ERROR_KIND(macro) \ #define ASAN_FOR_EACH_ERROR_KIND(macro) \
macro(StackOverflow) \
macro(DeadlySignal) \ macro(DeadlySignal) \
macro(DoubleFree) \ macro(DoubleFree) \
macro(NewDeleteSizeMismatch) \ macro(NewDeleteSizeMismatch) \
...@@ -348,6 +325,7 @@ struct ErrorDescription { ...@@ -348,6 +325,7 @@ struct ErrorDescription {
// We can add a wrapper around it to make it "more c++-like", but that would // We can add a wrapper around it to make it "more c++-like", but that would
// add a lot of code and the benefit wouldn't be that big. // add a lot of code and the benefit wouldn't be that big.
union { union {
ErrorBase Base;
ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER) ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER)
}; };
......
...@@ -169,7 +169,7 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { ...@@ -169,7 +169,7 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
} }
} }
#if SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
static THREADLOCAL FakeStack *fake_stack_tls; static THREADLOCAL FakeStack *fake_stack_tls;
FakeStack *GetTLSFakeStack() { FakeStack *GetTLSFakeStack() {
...@@ -181,7 +181,7 @@ void SetTLSFakeStack(FakeStack *fs) { ...@@ -181,7 +181,7 @@ void SetTLSFakeStack(FakeStack *fs) {
#else #else
FakeStack *GetTLSFakeStack() { return 0; } FakeStack *GetTLSFakeStack() { return 0; }
void SetTLSFakeStack(FakeStack *fs) { } void SetTLSFakeStack(FakeStack *fs) { }
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID #endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
static FakeStack *GetFakeStack() { static FakeStack *GetFakeStack() {
AsanThread *t = GetCurrentThread(); AsanThread *t = GetCurrentThread();
......
...@@ -59,7 +59,7 @@ void InitializeFlags() { ...@@ -59,7 +59,7 @@ void InitializeFlags() {
{ {
CommonFlags cf; CommonFlags cf;
cf.CopyFrom(*common_flags()); cf.CopyFrom(*common_flags());
cf.detect_leaks = CAN_SANITIZE_LEAKS; cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS;
cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf.malloc_context_size = kDefaultMallocContextSize; cf.malloc_context_size = kDefaultMallocContextSize;
cf.intercept_tls_get_addr = true; cf.intercept_tls_get_addr = true;
...@@ -93,6 +93,18 @@ void InitializeFlags() { ...@@ -93,6 +93,18 @@ void InitializeFlags() {
RegisterCommonFlags(&ubsan_parser); RegisterCommonFlags(&ubsan_parser);
#endif #endif
if (SANITIZER_MAC) {
// Support macOS MallocScribble and MallocPreScribble:
// <https://developer.apple.com/library/content/documentation/Performance/
// Conceptual/ManagingMemory/Articles/MallocDebug.html>
if (GetEnv("MallocScribble")) {
f->max_free_fill_size = 0x1000;
}
if (GetEnv("MallocPreScribble")) {
f->malloc_fill_byte = 0xaa;
}
}
// Override from ASan compile definition. // Override from ASan compile definition.
const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
asan_parser.ParseString(asan_compile_def); asan_parser.ParseString(asan_compile_def);
...@@ -104,6 +116,10 @@ void InitializeFlags() { ...@@ -104,6 +116,10 @@ void InitializeFlags() {
const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
ubsan_parser.ParseString(ubsan_default_options); ubsan_parser.ParseString(ubsan_default_options);
#endif #endif
#if CAN_SANITIZE_LEAKS
const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions();
lsan_parser.ParseString(lsan_default_options);
#endif
// Override from command line. // Override from command line.
asan_parser.ParseString(GetEnv("ASAN_OPTIONS")); asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
...@@ -154,9 +170,24 @@ void InitializeFlags() { ...@@ -154,9 +170,24 @@ void InitializeFlags() {
f->quarantine_size_mb = f->quarantine_size >> 20; f->quarantine_size_mb = f->quarantine_size >> 20;
if (f->quarantine_size_mb < 0) { if (f->quarantine_size_mb < 0) {
const int kDefaultQuarantineSizeMb = const int kDefaultQuarantineSizeMb =
(ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; (ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8;
f->quarantine_size_mb = kDefaultQuarantineSizeMb; f->quarantine_size_mb = kDefaultQuarantineSizeMb;
} }
if (f->thread_local_quarantine_size_kb < 0) {
const u32 kDefaultThreadLocalQuarantineSizeKb =
// It is not advised to go lower than 64Kb, otherwise quarantine batches
// pushed from thread local quarantine to global one will create too
// much overhead. One quarantine batch size is 8Kb and it holds up to
// 1021 chunk, which amounts to 1/8 memory overhead per batch when
// thread local quarantine is set to 64Kb.
(ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10);
f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb;
}
if (f->thread_local_quarantine_size_kb == 0 && f->quarantine_size_mb > 0) {
Report("%s: thread_local_quarantine_size_kb can be set to 0 only when "
"quarantine_size_mb is set to 0\n", SanitizerToolName);
Die();
}
if (!f->replace_str && common_flags()->intercept_strlen) { if (!f->replace_str && common_flags()->intercept_strlen) {
Report("WARNING: strlen interceptor is enabled even though replace_str=0. " Report("WARNING: strlen interceptor is enabled even though replace_str=0. "
"Use intercept_strlen=0 to disable it."); "Use intercept_strlen=0 to disable it.");
...@@ -165,13 +196,14 @@ void InitializeFlags() { ...@@ -165,13 +196,14 @@ void InitializeFlags() {
Report("WARNING: strchr* interceptors are enabled even though " Report("WARNING: strchr* interceptors are enabled even though "
"replace_str=0. Use intercept_strchr=0 to disable them."); "replace_str=0. Use intercept_strchr=0 to disable them.");
} }
if (!f->replace_str && common_flags()->intercept_strndup) {
Report("WARNING: strndup* interceptors are enabled even though "
"replace_str=0. Use intercept_strndup=0 to disable them.");
}
} }
} // namespace __asan } // namespace __asan
#if !SANITIZER_SUPPORTS_WEAK_HOOKS SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) {
extern "C" { return "";
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE }
const char* __asan_default_options() { return ""; }
} // extern "C"
#endif
...@@ -21,6 +21,12 @@ ASAN_FLAG(int, quarantine_size_mb, -1, ...@@ -21,6 +21,12 @@ ASAN_FLAG(int, quarantine_size_mb, -1,
"Size (in Mb) of quarantine used to detect use-after-free " "Size (in Mb) of quarantine used to detect use-after-free "
"errors. Lower value may reduce memory usage but increase the " "errors. Lower value may reduce memory usage but increase the "
"chance of false negatives.") "chance of false negatives.")
ASAN_FLAG(int, thread_local_quarantine_size_kb, -1,
"Size (in Kb) of thread local quarantine used to detect "
"use-after-free errors. Lower value may reduce memory usage but "
"increase the chance of false negatives. It is not advised to go "
"lower than 64Kb, otherwise frequent transfers to global quarantine "
"might affect performance.")
ASAN_FLAG(int, redzone, 16, ASAN_FLAG(int, redzone, 16,
"Minimal size (in bytes) of redzones around heap objects. " "Minimal size (in bytes) of redzones around heap objects. "
"Requirement: redzone >= 16, is a power of two.") "Requirement: redzone >= 16, is a power of two.")
...@@ -55,8 +61,14 @@ ASAN_FLAG( ...@@ -55,8 +61,14 @@ ASAN_FLAG(
int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K. int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
"ASan allocator flag. max_malloc_fill_size is the maximal amount of " "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
"bytes that will be filled with malloc_fill_byte on malloc.") "bytes that will be filled with malloc_fill_byte on malloc.")
ASAN_FLAG(
int, max_free_fill_size, 0,
"ASan allocator flag. max_free_fill_size is the maximal amount of "
"bytes that will be filled with free_fill_byte during free.")
ASAN_FLAG(int, malloc_fill_byte, 0xbe, ASAN_FLAG(int, malloc_fill_byte, 0xbe,
"Value used to fill the newly allocated memory.") "Value used to fill the newly allocated memory.")
ASAN_FLAG(int, free_fill_byte, 0x55,
"Value used to fill deallocated memory.")
ASAN_FLAG(bool, allow_user_poisoning, true, ASAN_FLAG(bool, allow_user_poisoning, true,
"If set, user may manually mark memory regions as poisoned or " "If set, user may manually mark memory regions as poisoned or "
"unpoisoned.") "unpoisoned.")
...@@ -65,6 +77,10 @@ ASAN_FLAG( ...@@ -65,6 +77,10 @@ ASAN_FLAG(
"Number of seconds to sleep between printing an error report and " "Number of seconds to sleep between printing an error report and "
"terminating the program. Useful for debugging purposes (e.g. when one " "terminating the program. Useful for debugging purposes (e.g. when one "
"needs to attach gdb).") "needs to attach gdb).")
ASAN_FLAG(
int, sleep_after_init, 0,
"Number of seconds to sleep after AddressSanitizer is initialized. "
"Useful for debugging purposes (e.g. when one needs to attach gdb).")
ASAN_FLAG(bool, check_malloc_usable_size, true, ASAN_FLAG(bool, check_malloc_usable_size, true,
"Allows the users to work around the bug in Nvidia drivers prior to " "Allows the users to work around the bug in Nvidia drivers prior to "
"295.*.") "295.*.")
...@@ -129,11 +145,16 @@ ASAN_FLAG(int, detect_odr_violation, 2, ...@@ -129,11 +145,16 @@ ASAN_FLAG(int, detect_odr_violation, 2,
"If >=2, detect violation of One-Definition-Rule (ODR); " "If >=2, detect violation of One-Definition-Rule (ODR); "
"If ==1, detect ODR-violation only if the two variables " "If ==1, detect ODR-violation only if the two variables "
"have different sizes") "have different sizes")
ASAN_FLAG(bool, dump_instruction_bytes, false,
"If true, dump 16 bytes starting at the instruction that caused SEGV")
ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
ASAN_FLAG(bool, halt_on_error, true, ASAN_FLAG(bool, halt_on_error, true,
"Crash the program after printing the first error report " "Crash the program after printing the first error report "
"(WARNING: USE AT YOUR OWN RISK!)") "(WARNING: USE AT YOUR OWN RISK!)")
ASAN_FLAG(bool, use_odr_indicator, false, ASAN_FLAG(bool, use_odr_indicator, false,
"Use special ODR indicator symbol for ODR violation detection") "Use special ODR indicator symbol for ODR violation detection")
ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
"realloc(p, 0) is equivalent to free(p) by default (Same as the "
"POSIX standard). If set to false, realloc(p, 0) will return a "
"pointer to an allocated space which can not be used.")
ASAN_FLAG(bool, verify_asan_link_order, true,
"Check position of ASan runtime in library list (needs to be disabled"
" when other library has to be preloaded system-wide)")
//===-- asan_fuchsia.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.
//
// Fuchsia-specific details.
//===---------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_fuchsia.h"
#if SANITIZER_FUCHSIA
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include <limits.h>
#include <zircon/sanitizer.h>
#include <zircon/syscalls.h>
#include <zircon/threads.h>
namespace __asan {
// The system already set up the shadow memory for us.
// __sanitizer::GetMaxVirtualAddress has already been called by
// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc).
// Just do some additional sanity checks here.
void InitializeShadowMemory() {
if (Verbosity()) PrintAddressSpaceLayout();
// Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address.
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
DCHECK(kLowShadowBeg != kDefaultShadowSentinel);
__asan_shadow_memory_dynamic_address = kLowShadowBeg;
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1);
CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit);
CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base);
CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1);
CHECK_EQ(kLowShadowEnd, 0);
CHECK_EQ(kLowShadowBeg, 0);
}
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
UNIMPLEMENTED();
}
void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
void InitializeAsanInterceptors() {}
void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
void InitializePlatformExceptionHandlers() {}
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
UNIMPLEMENTED();
}
// We can use a plain thread_local variable for TSD.
static thread_local void *per_thread;
void *AsanTSDGet() { return per_thread; }
void AsanTSDSet(void *tsd) { per_thread = tsd; }
// There's no initialization needed, and the passed-in destructor
// will never be called. Instead, our own thread destruction hook
// (below) will call AsanThread::TSDDtor directly.
void AsanTSDInit(void (*destructor)(void *tsd)) {
DCHECK(destructor == &PlatformTSDDtor);
}
void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
static inline size_t AsanThreadMmapSize() {
return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
}
struct AsanThread::InitOptions {
uptr stack_bottom, stack_size;
};
// Shared setup between thread creation and startup for the initial thread.
static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
uptr user_id, bool detached,
const char *name, uptr stack_bottom,
uptr stack_size) {
// In lieu of AsanThread::Create.
AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
u32 tid =
asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args);
asanThreadRegistry().SetThreadName(tid, name);
// On other systems, AsanThread::Init() is called from the new
// thread itself. But on Fuchsia we already know the stack address
// range beforehand, so we can do most of the setup right now.
const AsanThread::InitOptions options = {stack_bottom, stack_size};
thread->Init(&options);
return thread;
}
// This gets the same arguments passed to Init by CreateAsanThread, above.
// We're in the creator thread before the new thread is actually started,
// but its stack address range is already known. We don't bother tracking
// the static TLS address range because the system itself already uses an
// ASan-aware allocator for that.
void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
DCHECK_NE(GetCurrentThread(), this);
DCHECK_NE(GetCurrentThread(), nullptr);
CHECK_NE(options->stack_bottom, 0);
CHECK_NE(options->stack_size, 0);
stack_bottom_ = options->stack_bottom;
stack_top_ = options->stack_bottom + options->stack_size;
}
// Called by __asan::AsanInitInternal (asan_rtl.c).
AsanThread *CreateMainThread() {
thrd_t self = thrd_current();
char name[ZX_MAX_NAME_LEN];
CHECK_NE(__sanitizer::MainThreadStackBase, 0);
CHECK_GT(__sanitizer::MainThreadStackSize, 0);
AsanThread *t = CreateAsanThread(
nullptr, 0, reinterpret_cast<uptr>(self), true,
_zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
sizeof(name)) == ZX_OK
? name
: nullptr,
__sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize);
SetCurrentThread(t);
return t;
}
// This is called before each thread creation is attempted. So, in
// its first call, the calling thread is the initial and sole thread.
static void *BeforeThreadCreateHook(uptr user_id, bool detached,
const char *name, uptr stack_bottom,
uptr stack_size) {
EnsureMainThreadIDIsCorrect();
// Strict init-order checking is thread-hostile.
if (flags()->strict_init_order) StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
u32 parent_tid = GetCurrentTidOrInvalid();
return CreateAsanThread(&stack, parent_tid, user_id, detached, name,
stack_bottom, stack_size);
}
// This is called after creating a new thread (in the creating thread),
// with the pointer returned by BeforeThreadCreateHook (above).
static void ThreadCreateHook(void *hook, bool aborted) {
AsanThread *thread = static_cast<AsanThread *>(hook);
if (!aborted) {
// The thread was created successfully.
// ThreadStartHook is already running in the new thread.
} else {
// The thread wasn't created after all.
// Clean up everything we set up in BeforeThreadCreateHook.
asanThreadRegistry().FinishThread(thread->tid());
UnmapOrDie(thread, AsanThreadMmapSize());
}
}
// This is called in the newly-created thread before it runs anything else,
// with the pointer returned by BeforeThreadCreateHook (above).
// cf. asan_interceptors.cc:asan_thread_start
static void ThreadStartHook(void *hook, uptr os_id) {
AsanThread *thread = static_cast<AsanThread *>(hook);
SetCurrentThread(thread);
// In lieu of AsanThread::ThreadStart.
asanThreadRegistry().StartThread(thread->tid(), os_id, /*workerthread*/ false,
nullptr);
}
// Each thread runs this just before it exits,
// with the pointer returned by BeforeThreadCreateHook (above).
// All per-thread destructors have already been called.
static void ThreadExitHook(void *hook, uptr os_id) {
AsanThread::TSDDtor(per_thread);
}
} // namespace __asan
// These are declared (in extern "C") by <zircon/sanitizer.h>.
// The system runtime will call our definitions directly.
void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
const char *name, void *stack_base,
size_t stack_size) {
return __asan::BeforeThreadCreateHook(
reinterpret_cast<uptr>(thread), detached, name,
reinterpret_cast<uptr>(stack_base), stack_size);
}
void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
__asan::ThreadCreateHook(hook, error != thrd_success);
}
void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
__asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
}
void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
__asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self));
}
#endif // SANITIZER_FUCHSIA
...@@ -311,6 +311,26 @@ void __asan_unregister_image_globals(uptr *flag) { ...@@ -311,6 +311,26 @@ void __asan_unregister_image_globals(uptr *flag) {
*flag = 0; *flag = 0;
} }
void __asan_register_elf_globals(uptr *flag, void *start, void *stop) {
if (*flag) return;
if (!start) return;
CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
__asan_global *globals_start = (__asan_global*)start;
__asan_global *globals_stop = (__asan_global*)stop;
__asan_register_globals(globals_start, globals_stop - globals_start);
*flag = 1;
}
void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) {
if (!*flag) return;
if (!start) return;
CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
__asan_global *globals_start = (__asan_global*)start;
__asan_global *globals_stop = (__asan_global*)stop;
__asan_unregister_globals(globals_start, globals_stop - globals_start);
*flag = 0;
}
// Register an array of globals. // Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) { void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return; if (!flags()->report_globals) return;
...@@ -327,8 +347,26 @@ void __asan_register_globals(__asan_global *globals, uptr n) { ...@@ -327,8 +347,26 @@ void __asan_register_globals(__asan_global *globals, uptr n) {
Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]); Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
} }
for (uptr i = 0; i < n; i++) { for (uptr i = 0; i < n; i++) {
if (SANITIZER_WINDOWS && globals[i].beg == 0) {
// The MSVC incremental linker may pad globals out to 256 bytes. As long
// as __asan_global is less than 256 bytes large and its size is a power
// of two, we can skip over the padding.
static_assert(
sizeof(__asan_global) < 256 &&
(sizeof(__asan_global) & (sizeof(__asan_global) - 1)) == 0,
"sizeof(__asan_global) incompatible with incremental linker padding");
// If these are padding bytes, the rest of the global should be zero.
CHECK(globals[i].size == 0 && globals[i].size_with_redzone == 0 &&
globals[i].name == nullptr && globals[i].module_name == nullptr &&
globals[i].odr_indicator == 0);
continue;
}
RegisterGlobal(&globals[i]); RegisterGlobal(&globals[i]);
} }
// Poison the metadata. It should not be accessible to user code.
PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global),
kAsanGlobalRedzoneMagic);
} }
// Unregister an array of globals. // Unregister an array of globals.
...@@ -337,8 +375,16 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) { ...@@ -337,8 +375,16 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return; if (!flags()->report_globals) return;
BlockingMutexLock lock(&mu_for_globals); BlockingMutexLock lock(&mu_for_globals);
for (uptr i = 0; i < n; i++) { for (uptr i = 0; i < n; i++) {
if (SANITIZER_WINDOWS && globals[i].beg == 0) {
// Skip globals that look like padding from the MSVC incremental linker.
// See comment in __asan_register_globals.
continue;
}
UnregisterGlobal(&globals[i]); UnregisterGlobal(&globals[i]);
} }
// Unpoison the metadata.
PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 0);
} }
// This method runs immediately prior to dynamic initialization in each TU, // This method runs immediately prior to dynamic initialization in each TU,
......
//===-- asan_globals_win.cc -----------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Global registration code that is linked into every Windows DLL and EXE.
//
//===----------------------------------------------------------------------===//
#include "asan_interface_internal.h"
#if SANITIZER_WINDOWS
namespace __asan {
#pragma section(".ASAN$GA", read, write) // NOLINT
#pragma section(".ASAN$GZ", read, write) // NOLINT
extern "C" __declspec(allocate(".ASAN$GA"))
__asan_global __asan_globals_start = {};
extern "C" __declspec(allocate(".ASAN$GZ"))
__asan_global __asan_globals_end = {};
#pragma comment(linker, "/merge:.ASAN=.data")
static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
__asan_global *start = &__asan_globals_start + 1;
__asan_global *end = &__asan_globals_end;
uptr bytediff = (uptr)end - (uptr)start;
if (bytediff % sizeof(__asan_global) != 0) {
#ifdef SANITIZER_DLL_THUNK
__debugbreak();
#else
CHECK("corrupt asan global array");
#endif
}
// We know end >= start because the linker sorts the portion after the dollar
// sign alphabetically.
uptr n = end - start;
hook(start, n);
}
static void register_dso_globals() {
call_on_globals(&__asan_register_globals);
}
static void unregister_dso_globals() {
call_on_globals(&__asan_unregister_globals);
}
// Register globals
#pragma section(".CRT$XCU", long, read) // NOLINT
#pragma section(".CRT$XTX", long, read) // NOLINT
extern "C" __declspec(allocate(".CRT$XCU"))
void (*const __asan_dso_reg_hook)() = &register_dso_globals;
extern "C" __declspec(allocate(".CRT$XTX"))
void (*const __asan_dso_unreg_hook)() = &unregister_dso_globals;
} // namespace __asan
#endif // SANITIZER_WINDOWS
...@@ -13,9 +13,30 @@ ...@@ -13,9 +13,30 @@
#define ASAN_INTERCEPTORS_H #define ASAN_INTERCEPTORS_H
#include "asan_internal.h" #include "asan_internal.h"
#include "asan_interceptors_memintrinsics.h"
#include "interception/interception.h" #include "interception/interception.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_interceptors.h"
namespace __asan {
void InitializeAsanInterceptors();
void InitializePlatformInterceptors();
#define ENSURE_ASAN_INITED() \
do { \
CHECK(!asan_init_is_running); \
if (UNLIKELY(!asan_inited)) { \
AsanInitFromRtl(); \
} \
} while (0)
} // namespace __asan
// There is no general interception at all on Fuchsia.
// Only the functions in asan_interceptors_memintrinsics.h are
// really defined to replace libc functions.
#if !SANITIZER_FUCHSIA
// Use macro to describe if specific function should be // Use macro to describe if specific function should be
// intercepted on a given platform. // intercepted on a given platform.
#if !SANITIZER_WINDOWS #if !SANITIZER_WINDOWS
...@@ -32,7 +53,7 @@ ...@@ -32,7 +53,7 @@
# define ASAN_INTERCEPT_FORK 0 # define ASAN_INTERCEPT_FORK 0
#endif #endif
#if SANITIZER_FREEBSD || SANITIZER_LINUX #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
#else #else
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
...@@ -45,15 +66,15 @@ ...@@ -45,15 +66,15 @@
#endif #endif
#if !SANITIZER_WINDOWS #if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1 # define ASAN_INTERCEPT_SIGLONGJMP 1
#else #else
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0 # define ASAN_INTERCEPT_SIGLONGJMP 0
#endif #endif
#if !SANITIZER_WINDOWS #if SANITIZER_LINUX && !SANITIZER_ANDROID
# define ASAN_INTERCEPT_SIGLONGJMP 1 # define ASAN_INTERCEPT___LONGJMP_CHK 1
#else #else
# define ASAN_INTERCEPT_SIGLONGJMP 0 # define ASAN_INTERCEPT___LONGJMP_CHK 0
#endif #endif
// Android bug: https://code.google.com/p/android/issues/detail?id=61799 // Android bug: https://code.google.com/p/android/issues/detail?id=61799
...@@ -77,8 +98,6 @@ ...@@ -77,8 +98,6 @@
#endif #endif
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c) DECLARE_REAL(char*, strchr, const char *str, int c)
DECLARE_REAL(SIZE_T, strlen, const char *s) DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size) DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
...@@ -105,18 +124,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, ...@@ -105,18 +124,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
#define ASAN_INTERCEPT_FUNC(name) #define ASAN_INTERCEPT_FUNC(name)
#endif // SANITIZER_MAC #endif // SANITIZER_MAC
namespace __asan { #endif // !SANITIZER_FUCHSIA
void InitializeAsanInterceptors();
void InitializePlatformInterceptors();
#define ENSURE_ASAN_INITED() do { \
CHECK(!asan_init_is_running); \
if (UNLIKELY(!asan_inited)) { \
AsanInitFromRtl(); \
} \
} while (0)
} // namespace __asan
#endif // ASAN_INTERCEPTORS_H #endif // ASAN_INTERCEPTORS_H
//===-- asan_interceptors_memintrinsics.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.
//
// ASan versions of memcpy, memmove, and memset.
//===---------------------------------------------------------------------===//
#include "asan_interceptors_memintrinsics.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_suppressions.h"
using namespace __asan; // NOLINT
void *__asan_memcpy(void *to, const void *from, uptr size) {
ASAN_MEMCPY_IMPL(nullptr, to, from, size);
}
void *__asan_memset(void *block, int c, uptr size) {
ASAN_MEMSET_IMPL(nullptr, block, c, size);
}
void *__asan_memmove(void *to, const void *from, uptr size) {
ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
}
#if SANITIZER_FUCHSIA
// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only
// things there it wants are these three. Just define them as aliases
// here rather than repeating the contents.
decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]];
decltype(memmove) memmove[[gnu::alias("__asan_memmove")]];
decltype(memset) memset[[gnu::alias("__asan_memset")]];
#endif // SANITIZER_FUCHSIA
//===-- asan_interceptors_memintrinsics.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_memintrin.cc
//===---------------------------------------------------------------------===//
#ifndef ASAN_MEMINTRIN_H
#define ASAN_MEMINTRIN_H
#include "asan_interface_internal.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "interception/interception.h"
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
namespace __asan {
// Return true if we can quickly decide that the region is unpoisoned.
// We assume that a redzone is at least 16 bytes.
static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
if (size == 0) return true;
if (size <= 32)
return !AddressIsPoisoned(beg) &&
!AddressIsPoisoned(beg + size - 1) &&
!AddressIsPoisoned(beg + size / 2);
if (size <= 64)
return !AddressIsPoisoned(beg) &&
!AddressIsPoisoned(beg + size / 4) &&
!AddressIsPoisoned(beg + size - 1) &&
!AddressIsPoisoned(beg + 3 * size / 4) &&
!AddressIsPoisoned(beg + size / 2);
return false;
}
struct AsanInterceptorContext {
const char *interceptor_name;
};
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
// and ASAN_WRITE_RANGE as macro instead of function so
// that no extra frames are created, and stack trace contains
// relevant information only.
// We check all shadow bytes.
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
uptr __offset = (uptr)(offset); \
uptr __size = (uptr)(size); \
uptr __bad = 0; \
if (__offset > __offset + __size) { \
GET_STACK_TRACE_FATAL_HERE; \
ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
} \
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
bool suppressed = false; \
if (_ctx) { \
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
GET_STACK_TRACE_FATAL_HERE; \
suppressed = IsStackTraceSuppressed(&stack); \
} \
} \
if (!suppressed) { \
GET_CURRENT_PC_BP_SP; \
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
} \
} \
} while (0)
// memcpy is called during __asan_init() from the internals of printf(...).
// We do not treat memcpy with to==from as a bug.
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \
do { \
if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
if (asan_init_is_running) { \
return REAL(memcpy)(to, from, size); \
} \
ENSURE_ASAN_INITED(); \
if (flags()->replace_intrin) { \
if (to != from) { \
CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
} \
ASAN_READ_RANGE(ctx, from, size); \
ASAN_WRITE_RANGE(ctx, to, size); \
} \
return REAL(memcpy)(to, from, size); \
} while (0)
// memset is called inside Printf.
#define ASAN_MEMSET_IMPL(ctx, block, c, size) \
do { \
if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
if (asan_init_is_running) { \
return REAL(memset)(block, c, size); \
} \
ENSURE_ASAN_INITED(); \
if (flags()->replace_intrin) { \
ASAN_WRITE_RANGE(ctx, block, size); \
} \
return REAL(memset)(block, c, size); \
} while (0)
#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
do { \
if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
ENSURE_ASAN_INITED(); \
if (flags()->replace_intrin) { \
ASAN_READ_RANGE(ctx, from, size); \
ASAN_WRITE_RANGE(ctx, to, size); \
} \
return internal_memmove(to, from, size); \
} while (0)
#define ASAN_READ_RANGE(ctx, offset, size) \
ACCESS_MEMORY_RANGE(ctx, offset, size, false)
#define ASAN_WRITE_RANGE(ctx, offset, size) \
ACCESS_MEMORY_RANGE(ctx, offset, size, true)
// Behavior of functions like "memcpy" or "strcpy" is undefined
// if memory intervals overlap. We report error in this case.
// Macro is used to avoid creation of new frames.
static inline bool RangesOverlap(const char *offset1, uptr length1,
const char *offset2, uptr length2) {
return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
}
#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
const char *offset1 = (const char*)_offset1; \
const char *offset2 = (const char*)_offset2; \
if (RangesOverlap(offset1, length1, offset2, length2)) { \
GET_STACK_TRACE_FATAL_HERE; \
ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
offset2, length2, &stack); \
} \
} while (0)
} // namespace __asan
#endif // ASAN_MEMINTRIN_H
//===-- asan_interface.inc ------------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Asan interface list.
//===----------------------------------------------------------------------===//
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
INTERFACE_FUNCTION(__asan_address_is_poisoned)
INTERFACE_FUNCTION(__asan_after_dynamic_init)
INTERFACE_FUNCTION(__asan_alloca_poison)
INTERFACE_FUNCTION(__asan_allocas_unpoison)
INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_describe_address)
INTERFACE_FUNCTION(__asan_exp_load1)
INTERFACE_FUNCTION(__asan_exp_load2)
INTERFACE_FUNCTION(__asan_exp_load4)
INTERFACE_FUNCTION(__asan_exp_load8)
INTERFACE_FUNCTION(__asan_exp_load16)
INTERFACE_FUNCTION(__asan_exp_loadN)
INTERFACE_FUNCTION(__asan_exp_store1)
INTERFACE_FUNCTION(__asan_exp_store2)
INTERFACE_FUNCTION(__asan_exp_store4)
INTERFACE_FUNCTION(__asan_exp_store8)
INTERFACE_FUNCTION(__asan_exp_store16)
INTERFACE_FUNCTION(__asan_exp_storeN)
INTERFACE_FUNCTION(__asan_get_alloc_stack)
INTERFACE_FUNCTION(__asan_get_current_fake_stack)
INTERFACE_FUNCTION(__asan_get_free_stack)
INTERFACE_FUNCTION(__asan_get_report_access_size)
INTERFACE_FUNCTION(__asan_get_report_access_type)
INTERFACE_FUNCTION(__asan_get_report_address)
INTERFACE_FUNCTION(__asan_get_report_bp)
INTERFACE_FUNCTION(__asan_get_report_description)
INTERFACE_FUNCTION(__asan_get_report_pc)
INTERFACE_FUNCTION(__asan_get_report_sp)
INTERFACE_FUNCTION(__asan_get_shadow_mapping)
INTERFACE_FUNCTION(__asan_handle_no_return)
INTERFACE_FUNCTION(__asan_init)
INTERFACE_FUNCTION(__asan_load_cxx_array_cookie)
INTERFACE_FUNCTION(__asan_load1)
INTERFACE_FUNCTION(__asan_load2)
INTERFACE_FUNCTION(__asan_load4)
INTERFACE_FUNCTION(__asan_load8)
INTERFACE_FUNCTION(__asan_load16)
INTERFACE_FUNCTION(__asan_loadN)
INTERFACE_FUNCTION(__asan_load1_noabort)
INTERFACE_FUNCTION(__asan_load2_noabort)
INTERFACE_FUNCTION(__asan_load4_noabort)
INTERFACE_FUNCTION(__asan_load8_noabort)
INTERFACE_FUNCTION(__asan_load16_noabort)
INTERFACE_FUNCTION(__asan_loadN_noabort)
INTERFACE_FUNCTION(__asan_locate_address)
INTERFACE_FUNCTION(__asan_memcpy)
INTERFACE_FUNCTION(__asan_memmove)
INTERFACE_FUNCTION(__asan_memset)
INTERFACE_FUNCTION(__asan_poison_cxx_array_cookie)
INTERFACE_FUNCTION(__asan_poison_intra_object_redzone)
INTERFACE_FUNCTION(__asan_poison_memory_region)
INTERFACE_FUNCTION(__asan_poison_stack_memory)
INTERFACE_FUNCTION(__asan_print_accumulated_stats)
INTERFACE_FUNCTION(__asan_region_is_poisoned)
INTERFACE_FUNCTION(__asan_register_globals)
INTERFACE_FUNCTION(__asan_register_elf_globals)
INTERFACE_FUNCTION(__asan_register_image_globals)
INTERFACE_FUNCTION(__asan_report_error)
INTERFACE_FUNCTION(__asan_report_exp_load1)
INTERFACE_FUNCTION(__asan_report_exp_load2)
INTERFACE_FUNCTION(__asan_report_exp_load4)
INTERFACE_FUNCTION(__asan_report_exp_load8)
INTERFACE_FUNCTION(__asan_report_exp_load16)
INTERFACE_FUNCTION(__asan_report_exp_load_n)
INTERFACE_FUNCTION(__asan_report_exp_store1)
INTERFACE_FUNCTION(__asan_report_exp_store2)
INTERFACE_FUNCTION(__asan_report_exp_store4)
INTERFACE_FUNCTION(__asan_report_exp_store8)
INTERFACE_FUNCTION(__asan_report_exp_store16)
INTERFACE_FUNCTION(__asan_report_exp_store_n)
INTERFACE_FUNCTION(__asan_report_load1)
INTERFACE_FUNCTION(__asan_report_load2)
INTERFACE_FUNCTION(__asan_report_load4)
INTERFACE_FUNCTION(__asan_report_load8)
INTERFACE_FUNCTION(__asan_report_load16)
INTERFACE_FUNCTION(__asan_report_load_n)
INTERFACE_FUNCTION(__asan_report_load1_noabort)
INTERFACE_FUNCTION(__asan_report_load2_noabort)
INTERFACE_FUNCTION(__asan_report_load4_noabort)
INTERFACE_FUNCTION(__asan_report_load8_noabort)
INTERFACE_FUNCTION(__asan_report_load16_noabort)
INTERFACE_FUNCTION(__asan_report_load_n_noabort)
INTERFACE_FUNCTION(__asan_report_present)
INTERFACE_FUNCTION(__asan_report_store1)
INTERFACE_FUNCTION(__asan_report_store2)
INTERFACE_FUNCTION(__asan_report_store4)
INTERFACE_FUNCTION(__asan_report_store8)
INTERFACE_FUNCTION(__asan_report_store16)
INTERFACE_FUNCTION(__asan_report_store_n)
INTERFACE_FUNCTION(__asan_report_store1_noabort)
INTERFACE_FUNCTION(__asan_report_store2_noabort)
INTERFACE_FUNCTION(__asan_report_store4_noabort)
INTERFACE_FUNCTION(__asan_report_store8_noabort)
INTERFACE_FUNCTION(__asan_report_store16_noabort)
INTERFACE_FUNCTION(__asan_report_store_n_noabort)
INTERFACE_FUNCTION(__asan_set_death_callback)
INTERFACE_FUNCTION(__asan_set_error_report_callback)
INTERFACE_FUNCTION(__asan_set_shadow_00)
INTERFACE_FUNCTION(__asan_set_shadow_f1)
INTERFACE_FUNCTION(__asan_set_shadow_f2)
INTERFACE_FUNCTION(__asan_set_shadow_f3)
INTERFACE_FUNCTION(__asan_set_shadow_f5)
INTERFACE_FUNCTION(__asan_set_shadow_f8)
INTERFACE_FUNCTION(__asan_stack_free_0)
INTERFACE_FUNCTION(__asan_stack_free_1)
INTERFACE_FUNCTION(__asan_stack_free_2)
INTERFACE_FUNCTION(__asan_stack_free_3)
INTERFACE_FUNCTION(__asan_stack_free_4)
INTERFACE_FUNCTION(__asan_stack_free_5)
INTERFACE_FUNCTION(__asan_stack_free_6)
INTERFACE_FUNCTION(__asan_stack_free_7)
INTERFACE_FUNCTION(__asan_stack_free_8)
INTERFACE_FUNCTION(__asan_stack_free_9)
INTERFACE_FUNCTION(__asan_stack_free_10)
INTERFACE_FUNCTION(__asan_stack_malloc_0)
INTERFACE_FUNCTION(__asan_stack_malloc_1)
INTERFACE_FUNCTION(__asan_stack_malloc_2)
INTERFACE_FUNCTION(__asan_stack_malloc_3)
INTERFACE_FUNCTION(__asan_stack_malloc_4)
INTERFACE_FUNCTION(__asan_stack_malloc_5)
INTERFACE_FUNCTION(__asan_stack_malloc_6)
INTERFACE_FUNCTION(__asan_stack_malloc_7)
INTERFACE_FUNCTION(__asan_stack_malloc_8)
INTERFACE_FUNCTION(__asan_stack_malloc_9)
INTERFACE_FUNCTION(__asan_stack_malloc_10)
INTERFACE_FUNCTION(__asan_store1)
INTERFACE_FUNCTION(__asan_store2)
INTERFACE_FUNCTION(__asan_store4)
INTERFACE_FUNCTION(__asan_store8)
INTERFACE_FUNCTION(__asan_store16)
INTERFACE_FUNCTION(__asan_storeN)
INTERFACE_FUNCTION(__asan_store1_noabort)
INTERFACE_FUNCTION(__asan_store2_noabort)
INTERFACE_FUNCTION(__asan_store4_noabort)
INTERFACE_FUNCTION(__asan_store8_noabort)
INTERFACE_FUNCTION(__asan_store16_noabort)
INTERFACE_FUNCTION(__asan_storeN_noabort)
INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone)
INTERFACE_FUNCTION(__asan_unpoison_memory_region)
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
INTERFACE_FUNCTION(__asan_unregister_globals)
INTERFACE_FUNCTION(__asan_unregister_elf_globals)
INTERFACE_FUNCTION(__asan_unregister_image_globals)
INTERFACE_FUNCTION(__asan_version_mismatch_check_v8)
INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
INTERFACE_FUNCTION(__sanitizer_ptr_sub)
INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
INTERFACE_WEAK_FUNCTION(__asan_default_options)
INTERFACE_WEAK_FUNCTION(__asan_default_suppressions)
INTERFACE_WEAK_FUNCTION(__asan_on_error)
...@@ -65,6 +65,11 @@ extern "C" { ...@@ -65,6 +65,11 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
void __asan_unregister_image_globals(uptr *flag); void __asan_unregister_image_globals(uptr *flag);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_register_elf_globals(uptr *flag, void *start, void *stop);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop);
// These two functions should be called by the instrumented code. // These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals. // 'globals' is an array of structures describing 'n' globals.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
...@@ -163,12 +168,12 @@ extern "C" { ...@@ -163,12 +168,12 @@ extern "C" {
void __asan_set_error_report_callback(void (*callback)(const char*)); void __asan_set_error_report_callback(void (*callback)(const char*));
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __asan_on_error(); void __asan_on_error();
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ const char* __asan_default_options(); const char* __asan_default_options();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
extern uptr __asan_shadow_memory_dynamic_address; extern uptr __asan_shadow_memory_dynamic_address;
...@@ -240,6 +245,9 @@ extern "C" { ...@@ -240,6 +245,9 @@ extern "C" {
void __asan_alloca_poison(uptr addr, uptr size); void __asan_alloca_poison(uptr addr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
void __asan_allocas_unpoison(uptr top, uptr bottom); void __asan_allocas_unpoison(uptr top, uptr bottom);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char* __asan_default_suppressions();
} // extern "C" } // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H #endif // ASAN_INTERFACE_INTERNAL_H
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
// If set, values like allocator chunk size, as well as defaults for some flags // If set, values like allocator chunk size, as well as defaults for some flags
// will be changed towards less memory overhead. // will be changed towards less memory overhead.
#ifndef ASAN_LOW_MEMORY #ifndef ASAN_LOW_MEMORY
# if SANITIZER_IOS || (SANITIZER_WORDSIZE == 32) # if SANITIZER_IOS || SANITIZER_ANDROID
# define ASAN_LOW_MEMORY 1 # define ASAN_LOW_MEMORY 1
# else # else
# define ASAN_LOW_MEMORY 0 # define ASAN_LOW_MEMORY 0
...@@ -62,21 +62,29 @@ void AsanInitFromRtl(); ...@@ -62,21 +62,29 @@ void AsanInitFromRtl();
// asan_win.cc // asan_win.cc
void InitializePlatformExceptionHandlers(); void InitializePlatformExceptionHandlers();
// Returns whether an address is a valid allocated system heap block.
// asan_win.cc / asan_posix.cc // 'addr' must point to the beginning of the block.
const char *DescribeSignalOrException(int signo); bool IsSystemHeapAddress(uptr addr);
// asan_rtl.cc // asan_rtl.cc
void PrintAddressSpaceLayout();
void NORETURN ShowStatsAndAbort(); void NORETURN ShowStatsAndAbort();
// asan_shadow_setup.cc
void InitializeShadowMemory();
// asan_malloc_linux.cc / asan_malloc_mac.cc // asan_malloc_linux.cc / asan_malloc_mac.cc
void ReplaceSystemMalloc(); void ReplaceSystemMalloc();
// asan_linux.cc / asan_mac.cc / asan_win.cc // asan_linux.cc / asan_mac.cc / asan_win.cc
uptr FindDynamicShadowStart();
void *AsanDoesNotSupportStaticLinkage(); void *AsanDoesNotSupportStaticLinkage();
void AsanCheckDynamicRTPrereqs(); void AsanCheckDynamicRTPrereqs();
void AsanCheckIncompatibleRT(); void AsanCheckIncompatibleRT();
// asan_thread.cc
AsanThread *CreateMainThread();
// Support function for __asan_(un)register_image_globals. Searches for the // Support function for __asan_(un)register_image_globals. Searches for the
// loaded image containing `needle' and then enumerates all global metadata // loaded image containing `needle' and then enumerates all global metadata
// structures declared in that image, applying `op' (e.g., // structures declared in that image, applying `op' (e.g.,
...@@ -101,17 +109,6 @@ void *AsanDlSymNext(const char *sym); ...@@ -101,17 +109,6 @@ void *AsanDlSymNext(const char *sym);
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
// Platform-specific options.
#if SANITIZER_MAC
bool PlatformHasDifferentMemcpyAndMemmove();
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
(PlatformHasDifferentMemcpyAndMemmove())
#elif SANITIZER_WINDOWS64
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
#else
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
#endif // SANITIZER_MAC
// Add convenient macro for interface functions that may be represented as // Add convenient macro for interface functions that may be represented as
// weak hooks. // weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \ #define ASAN_MALLOC_HOOK(ptr, size) \
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h" #include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "asan_interceptors.h" #include "asan_interceptors.h"
#include "asan_internal.h" #include "asan_internal.h"
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#if SANITIZER_ANDROID || SANITIZER_FREEBSD #if SANITIZER_ANDROID || SANITIZER_FREEBSD
#include <ucontext.h> #include <ucontext.h>
extern "C" void* _DYNAMIC; extern "C" void* _DYNAMIC;
#elif SANITIZER_NETBSD
#include <link_elf.h>
#include <ucontext.h>
extern Elf_Dyn _DYNAMIC;
#else #else
#include <sys/ucontext.h> #include <sys/ucontext.h>
#include <link.h> #include <link.h>
...@@ -68,12 +72,18 @@ namespace __asan { ...@@ -68,12 +72,18 @@ namespace __asan {
void InitializePlatformInterceptors() {} void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {} void InitializePlatformExceptionHandlers() {}
bool IsSystemHeapAddress (uptr addr) { return false; }
void *AsanDoesNotSupportStaticLinkage() { void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static. // This will fail to link with -static.
return &_DYNAMIC; // defined in link.h return &_DYNAMIC; // defined in link.h
} }
uptr FindDynamicShadowStart() {
UNREACHABLE("FindDynamicShadowStart is not available");
return 0;
}
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -93,6 +103,15 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, ...@@ -93,6 +103,15 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
return 0; return 0;
#if SANITIZER_NETBSD
// Ignore first entry (the main program)
char **p = (char **)data;
if (!(*p)) {
*p = (char *)-1;
return 0;
}
#endif
*(const char **)data = info->dlpi_name; *(const char **)data = info->dlpi_name;
return 1; return 1;
} }
...@@ -108,7 +127,7 @@ static void ReportIncompatibleRT() { ...@@ -108,7 +127,7 @@ static void ReportIncompatibleRT() {
} }
void AsanCheckDynamicRTPrereqs() { void AsanCheckDynamicRTPrereqs() {
if (!ASAN_DYNAMIC) if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
return; return;
// Ensure that dynamic RT is the first DSO in the list // Ensure that dynamic RT is the first DSO in the list
...@@ -137,9 +156,9 @@ void AsanCheckIncompatibleRT() { ...@@ -137,9 +156,9 @@ void AsanCheckIncompatibleRT() {
// system libraries, causing crashes later in ASan initialization. // system libraries, causing crashes later in ASan initialization.
MemoryMappingLayout proc_maps(/*cache_enabled*/true); MemoryMappingLayout proc_maps(/*cache_enabled*/true);
char filename[128]; char filename[128];
while (proc_maps.Next(nullptr, nullptr, nullptr, filename, MemoryMappedSegment segment(filename, sizeof(filename));
sizeof(filename), nullptr)) { while (proc_maps.Next(&segment)) {
if (IsDynamicRTName(filename)) { if (IsDynamicRTName(segment.filename)) {
Report("Your application is linked against " Report("Your application is linked against "
"incompatible ASan runtimes.\n"); "incompatible ASan runtimes.\n");
Die(); Die();
...@@ -171,4 +190,4 @@ void *AsanDlSymNext(const char *sym) { ...@@ -171,4 +190,4 @@ void *AsanDlSymNext(const char *sym) {
} // namespace __asan } // namespace __asan
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
...@@ -46,21 +46,36 @@ namespace __asan { ...@@ -46,21 +46,36 @@ namespace __asan {
void InitializePlatformInterceptors() {} void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {} void InitializePlatformExceptionHandlers() {}
bool IsSystemHeapAddress (uptr addr) { return false; }
bool PlatformHasDifferentMemcpyAndMemmove() {
// On OS X 10.7 memcpy() and memmove() are both resolved
// into memmove$VARIANT$sse42.
// See also https://github.com/google/sanitizers/issues/34.
// TODO(glider): need to check dynamically that memcpy() and memmove() are
// actually the same function.
return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
}
// No-op. Mac does not support static linkage anyway. // No-op. Mac does not support static linkage anyway.
void *AsanDoesNotSupportStaticLinkage() { void *AsanDoesNotSupportStaticLinkage() {
return 0; return 0;
} }
uptr FindDynamicShadowStart() {
uptr granularity = GetMmapGranularity();
uptr alignment = 8 * granularity;
uptr left_padding = granularity;
uptr space_size = kHighShadowEnd + left_padding;
uptr largest_gap_found = 0;
uptr shadow_start = FindAvailableMemoryRange(space_size, alignment,
granularity, &largest_gap_found);
// If the shadow doesn't fit, restrict the address space to make it fit.
if (shadow_start == 0) {
uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment);
RestrictMemoryToMaxAddress(new_max_vm);
kHighMemEnd = new_max_vm - 1;
space_size = kHighShadowEnd + left_padding;
shadow_start =
FindAvailableMemoryRange(space_size, alignment, granularity, nullptr);
}
CHECK_NE((uptr)0, shadow_start);
CHECK(IsAligned(shadow_start, alignment));
return shadow_start;
}
// No-op. Mac does not support static linkage anyway. // No-op. Mac does not support static linkage anyway.
void AsanCheckDynamicRTPrereqs() {} void AsanCheckDynamicRTPrereqs() {}
...@@ -145,7 +160,8 @@ void asan_register_worker_thread(int parent_tid, StackTrace *stack) { ...@@ -145,7 +160,8 @@ void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
parent_tid, stack, /* detached */ true); parent_tid, stack, /* detached */ true);
t->Init(); t->Init();
asanThreadRegistry().StartThread(t->tid(), 0, 0); asanThreadRegistry().StartThread(t->tid(), GetTid(),
/* workerthread */ true, 0);
SetCurrentThread(t); SetCurrentThread(t);
} }
} }
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h" #include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
SANITIZER_NETBSD
#include "sanitizer_common/sanitizer_tls_get_addr.h" #include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "asan_allocator.h" #include "asan_allocator.h"
...@@ -28,9 +29,9 @@ static uptr allocated_for_dlsym; ...@@ -28,9 +29,9 @@ static uptr allocated_for_dlsym;
static const uptr kDlsymAllocPoolSize = 1024; static const uptr kDlsymAllocPoolSize = 1024;
static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
static bool IsInDlsymAllocPool(const void *ptr) { static INLINE bool IsInDlsymAllocPool(const void *ptr) {
uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
return off < sizeof(alloc_memory_for_dlsym); return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]);
} }
static void *AllocateFromLocalPool(uptr size_in_bytes) { static void *AllocateFromLocalPool(uptr size_in_bytes) {
...@@ -41,6 +42,26 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { ...@@ -41,6 +42,26 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
return mem; return mem;
} }
static INLINE bool MaybeInDlsym() {
// Fuchsia doesn't use dlsym-based interceptors.
return !SANITIZER_FUCHSIA && asan_init_is_running;
}
static void *ReallocFromLocalPool(void *ptr, uptr size) {
const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
void *new_ptr;
if (UNLIKELY(MaybeInDlsym())) {
new_ptr = AllocateFromLocalPool(size);
} else {
ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
new_ptr = asan_malloc(size, &stack);
}
internal_memcpy(new_ptr, ptr, copy_size);
return new_ptr;
}
INTERCEPTOR(void, free, void *ptr) { INTERCEPTOR(void, free, void *ptr) {
GET_STACK_TRACE_FREE; GET_STACK_TRACE_FREE;
if (UNLIKELY(IsInDlsymAllocPool(ptr))) if (UNLIKELY(IsInDlsymAllocPool(ptr)))
...@@ -48,63 +69,61 @@ INTERCEPTOR(void, free, void *ptr) { ...@@ -48,63 +69,61 @@ INTERCEPTOR(void, free, void *ptr) {
asan_free(ptr, &stack, FROM_MALLOC); asan_free(ptr, &stack, FROM_MALLOC);
} }
#if SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void, cfree, void *ptr) { INTERCEPTOR(void, cfree, void *ptr) {
GET_STACK_TRACE_FREE; GET_STACK_TRACE_FREE;
if (UNLIKELY(IsInDlsymAllocPool(ptr))) if (UNLIKELY(IsInDlsymAllocPool(ptr)))
return; return;
asan_free(ptr, &stack, FROM_MALLOC); asan_free(ptr, &stack, FROM_MALLOC);
} }
#endif // SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void*, malloc, uptr size) { INTERCEPTOR(void*, malloc, uptr size) {
if (UNLIKELY(!asan_inited)) if (UNLIKELY(MaybeInDlsym()))
// Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
return AllocateFromLocalPool(size); return AllocateFromLocalPool(size);
ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack); return asan_malloc(size, &stack);
} }
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
if (UNLIKELY(!asan_inited)) if (UNLIKELY(MaybeInDlsym()))
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
return AllocateFromLocalPool(nmemb * size); return AllocateFromLocalPool(nmemb * size);
ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack); return asan_calloc(nmemb, size, &stack);
} }
INTERCEPTOR(void*, realloc, void *ptr, uptr size) { INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
return ReallocFromLocalPool(ptr, size);
if (UNLIKELY(MaybeInDlsym()))
return AllocateFromLocalPool(size);
ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
void *new_ptr;
if (UNLIKELY(!asan_inited)) {
new_ptr = AllocateFromLocalPool(size);
} else {
copy_size = size;
new_ptr = asan_malloc(copy_size, &stack);
}
internal_memcpy(new_ptr, ptr, copy_size);
return new_ptr;
}
return asan_realloc(ptr, size, &stack); return asan_realloc(ptr, size, &stack);
} }
#if SANITIZER_INTERCEPT_MEMALIGN
INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
return asan_memalign(boundary, size, &stack, FROM_MALLOC); return asan_memalign(boundary, size, &stack, FROM_MALLOC);
} }
INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
DTLS_on_libc_memalign(res, size); DTLS_on_libc_memalign(res, size);
return res; return res;
} }
#endif // SANITIZER_INTERCEPT_MEMALIGN
INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
GET_CURRENT_PC_BP_SP; GET_CURRENT_PC_BP_SP;
...@@ -112,6 +131,7 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { ...@@ -112,6 +131,7 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
return asan_malloc_usable_size(ptr, pc, bp); return asan_malloc_usable_size(ptr, pc, bp);
} }
#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
// We avoid including malloc.h for portability reasons. // We avoid including malloc.h for portability reasons.
// man mallinfo says the fields are "long", but the implementation uses int. // man mallinfo says the fields are "long", but the implementation uses int.
// It doesn't matter much -- we just need to make sure that the libc's mallinfo // It doesn't matter much -- we just need to make sure that the libc's mallinfo
...@@ -129,6 +149,7 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { ...@@ -129,6 +149,7 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
INTERCEPTOR(int, mallopt, int cmd, int value) { INTERCEPTOR(int, mallopt, int cmd, int value) {
return -1; return -1;
} }
#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
...@@ -141,10 +162,12 @@ INTERCEPTOR(void*, valloc, uptr size) { ...@@ -141,10 +162,12 @@ INTERCEPTOR(void*, valloc, uptr size) {
return asan_valloc(size, &stack); return asan_valloc(size, &stack);
} }
#if SANITIZER_INTERCEPT_PVALLOC
INTERCEPTOR(void*, pvalloc, uptr size) { INTERCEPTOR(void*, pvalloc, uptr size) {
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
return asan_pvalloc(size, &stack); return asan_pvalloc(size, &stack);
} }
#endif // SANITIZER_INTERCEPT_PVALLOC
INTERCEPTOR(void, malloc_stats, void) { INTERCEPTOR(void, malloc_stats, void) {
__asan_print_accumulated_stats(); __asan_print_accumulated_stats();
...@@ -210,4 +233,5 @@ void ReplaceSystemMalloc() { ...@@ -210,4 +233,5 @@ void ReplaceSystemMalloc() {
} // namespace __asan } // namespace __asan
#endif // SANITIZER_ANDROID #endif // SANITIZER_ANDROID
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX #endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
// SANITIZER_NETBSD
...@@ -54,11 +54,6 @@ void _free_base(void *ptr) { ...@@ -54,11 +54,6 @@ void _free_base(void *ptr) {
} }
ALLOCATION_FUNCTION_ATTRIBUTE ALLOCATION_FUNCTION_ATTRIBUTE
void cfree(void *ptr) {
CHECK(!"cfree() should not be used on Windows");
}
ALLOCATION_FUNCTION_ATTRIBUTE
void *malloc(size_t size) { void *malloc(size_t size) {
GET_STACK_TRACE_MALLOC; GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack); return asan_malloc(size, &stack);
...@@ -103,7 +98,7 @@ void *realloc(void *ptr, size_t size) { ...@@ -103,7 +98,7 @@ void *realloc(void *ptr, size_t size) {
ALLOCATION_FUNCTION_ATTRIBUTE ALLOCATION_FUNCTION_ATTRIBUTE
void *_realloc_dbg(void *ptr, size_t size, int) { void *_realloc_dbg(void *ptr, size_t size, int) {
CHECK(!"_realloc_dbg should not exist!"); UNREACHABLE("_realloc_dbg should not exist!");
return 0; return 0;
} }
......
...@@ -113,6 +113,13 @@ ...@@ -113,6 +113,13 @@
// || `[0x40000000, 0x47ffffff]` || LowShadow || // || `[0x40000000, 0x47ffffff]` || LowShadow ||
// || `[0x00000000, 0x3fffffff]` || LowMem || // || `[0x00000000, 0x3fffffff]` || LowMem ||
// //
// Shadow mapping on NetBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
// || `[0x4feffffffe01, 0x7f7ffffff000]` || HighMem ||
// || `[0x49fdffffffc0, 0x4feffffffe00]` || HighShadow ||
// || `[0x480000000000, 0x49fdffffffbf]` || ShadowGap ||
// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
//
// Default Windows/i386 mapping: // Default Windows/i386 mapping:
// (the exact location of HighShadow/HighMem may vary depending // (the exact location of HighShadow/HighMem may vary depending
// on WoW64, /LARGEADDRESSAWARE, etc). // on WoW64, /LARGEADDRESSAWARE, etc).
...@@ -138,12 +145,14 @@ static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; ...@@ -138,12 +145,14 @@ static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
#define SHADOW_SCALE kDefaultShadowScale #define SHADOW_SCALE kDefaultShadowScale
#if SANITIZER_FUCHSIA
#if SANITIZER_WORDSIZE == 32 # define SHADOW_OFFSET (0)
#elif SANITIZER_WORDSIZE == 32
# if SANITIZER_ANDROID # if SANITIZER_ANDROID
# define SHADOW_OFFSET (0) # define SHADOW_OFFSET (0)
# elif defined(__mips__) # elif defined(__mips__)
...@@ -176,6 +185,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 ...@@ -176,6 +185,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# define SHADOW_OFFSET kSystemZ_ShadowOffset64 # define SHADOW_OFFSET kSystemZ_ShadowOffset64
# elif SANITIZER_FREEBSD # elif SANITIZER_FREEBSD
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64 # define SHADOW_OFFSET kFreeBSD_ShadowOffset64
# elif SANITIZER_NETBSD
# define SHADOW_OFFSET kNetBSD_ShadowOffset64
# elif SANITIZER_MAC # elif SANITIZER_MAC
# define SHADOW_OFFSET kDefaultShadowOffset64 # define SHADOW_OFFSET kDefaultShadowOffset64
# elif defined(__mips64) # elif defined(__mips64)
...@@ -189,7 +200,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 ...@@ -189,7 +200,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
#define kLowMemBeg 0 #define kLowMemBeg 0
#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0) #define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
......
...@@ -30,69 +30,99 @@ struct AllocationSite { ...@@ -30,69 +30,99 @@ struct AllocationSite {
class HeapProfile { class HeapProfile {
public: public:
HeapProfile() : allocations_(1024) {} HeapProfile() : allocations_(1024) {}
void Insert(u32 id, uptr size) {
total_allocated_ += size; void ProcessChunk(const AsanChunkView& cv) {
total_count_++; if (cv.IsAllocated()) {
// Linear lookup will be good enough for most cases (although not all). total_allocated_user_size_ += cv.UsedSize();
for (uptr i = 0; i < allocations_.size(); i++) { total_allocated_count_++;
if (allocations_[i].id == id) { u32 id = cv.GetAllocStackId();
allocations_[i].total_size += size; if (id)
allocations_[i].count++; Insert(id, cv.UsedSize());
return; } else if (cv.IsQuarantined()) {
} total_quarantined_user_size_ += cv.UsedSize();
total_quarantined_count_++;
} else {
total_other_count_++;
} }
allocations_.push_back({id, size, 1});
} }
void Print(uptr top_percent) { void Print(uptr top_percent, uptr max_number_of_contexts) {
InternalSort(&allocations_, allocations_.size(), InternalSort(&allocations_, allocations_.size(),
[](const AllocationSite &a, const AllocationSite &b) { [](const AllocationSite &a, const AllocationSite &b) {
return a.total_size > b.total_size; return a.total_size > b.total_size;
}); });
CHECK(total_allocated_); CHECK(total_allocated_user_size_);
uptr total_shown = 0; uptr total_shown = 0;
Printf("Live Heap Allocations: %zd bytes from %zd allocations; " Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: "
"showing top %zd%%\n", total_allocated_, total_count_, top_percent); "%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; "
for (uptr i = 0; i < allocations_.size(); i++) { "showing top %zd%% (at most %zd unique contexts)\n",
total_allocated_user_size_, total_allocated_count_,
total_quarantined_user_size_, total_quarantined_count_,
total_other_count_, total_allocated_count_ +
total_quarantined_count_ + total_other_count_, top_percent,
max_number_of_contexts);
for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts);
i++) {
auto &a = allocations_[i]; auto &a = allocations_[i];
Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size, Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size,
a.total_size * 100 / total_allocated_, a.count); a.total_size * 100 / total_allocated_user_size_, a.count);
StackDepotGet(a.id).Print(); StackDepotGet(a.id).Print();
total_shown += a.total_size; total_shown += a.total_size;
if (total_shown * 100 / total_allocated_ > top_percent) if (total_shown * 100 / total_allocated_user_size_ > top_percent)
break; break;
} }
} }
private: private:
uptr total_allocated_ = 0; uptr total_allocated_user_size_ = 0;
uptr total_count_ = 0; uptr total_allocated_count_ = 0;
uptr total_quarantined_user_size_ = 0;
uptr total_quarantined_count_ = 0;
uptr total_other_count_ = 0;
InternalMmapVector<AllocationSite> allocations_; InternalMmapVector<AllocationSite> allocations_;
void Insert(u32 id, uptr size) {
// Linear lookup will be good enough for most cases (although not all).
for (uptr i = 0; i < allocations_.size(); i++) {
if (allocations_[i].id == id) {
allocations_[i].total_size += size;
allocations_[i].count++;
return;
}
}
allocations_.push_back({id, size, 1});
}
}; };
static void ChunkCallback(uptr chunk, void *arg) { static void ChunkCallback(uptr chunk, void *arg) {
HeapProfile *hp = reinterpret_cast<HeapProfile*>(arg); reinterpret_cast<HeapProfile*>(arg)->ProcessChunk(
AsanChunkView cv = FindHeapChunkByAllocBeg(chunk); FindHeapChunkByAllocBeg(chunk));
if (!cv.IsAllocated()) return;
u32 id = cv.GetAllocStackId();
if (!id) return;
hp->Insert(id, cv.UsedSize());
} }
static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
void *argument) { void *argument) {
HeapProfile hp; HeapProfile hp;
__lsan::ForEachChunk(ChunkCallback, &hp); __lsan::ForEachChunk(ChunkCallback, &hp);
hp.Print(reinterpret_cast<uptr>(argument)); uptr *Arg = reinterpret_cast<uptr*>(argument);
hp.Print(Arg[0], Arg[1]);
if (Verbosity())
__asan_print_accumulated_stats();
} }
} // namespace __asan } // namespace __asan
#endif // CAN_SANITIZE_LEAKS
extern "C" { extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_print_memory_profile(uptr top_percent) { void __sanitizer_print_memory_profile(uptr top_percent,
__sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent); uptr max_number_of_contexts) {
#if CAN_SANITIZE_LEAKS
uptr Arg[2];
Arg[0] = top_percent;
Arg[1] = max_number_of_contexts;
__sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg);
#endif // CAN_SANITIZE_LEAKS
} }
} // extern "C" } // extern "C"
#endif // CAN_SANITIZE_LEAKS
...@@ -23,22 +23,26 @@ ...@@ -23,22 +23,26 @@
// dllexport would normally do. We need to export them in order to make the // dllexport would normally do. We need to export them in order to make the
// VS2015 dynamic CRT (MD) work. // VS2015 dynamic CRT (MD) work.
#if SANITIZER_WINDOWS #if SANITIZER_WINDOWS
# define CXX_OPERATOR_ATTRIBUTE #define CXX_OPERATOR_ATTRIBUTE
# ifdef _WIN64 #define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new #ifdef _WIN64
# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new
# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow
# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[] COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete
# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[] COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete
# else COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[]
# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[]
# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete
# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete
# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[]
# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[]
# endif
#else #else
# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE COMMENT_EXPORT("??2@YAPAXI@Z") // operator new
COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow
COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete
COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete
COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[]
COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
#endif
#undef COMMENT_EXPORT
#else
#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
#endif #endif
using namespace __asan; // NOLINT using namespace __asan; // NOLINT
...@@ -61,12 +65,17 @@ struct nothrow_t {}; ...@@ -61,12 +65,17 @@ struct nothrow_t {};
enum class align_val_t: size_t {}; enum class align_val_t: size_t {};
} // namespace std } // namespace std
#define OPERATOR_NEW_BODY(type) \ // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
#define OPERATOR_NEW_BODY(type, nothrow) \
GET_STACK_TRACE_MALLOC;\ GET_STACK_TRACE_MALLOC;\
return asan_memalign(0, size, &stack, type); void *res = asan_memalign(0, size, &stack, type);\
#define OPERATOR_NEW_BODY_ALIGN(type) \ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
return res;
#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
GET_STACK_TRACE_MALLOC;\ GET_STACK_TRACE_MALLOC;\
return asan_memalign((uptr)align, size, &stack, type); void *res = asan_memalign((uptr)align, size, &stack, type);\
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
return res;
// On OS X it's not enough to just provide our own 'operator new' and // 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 // 'operator delete' implementations, because they're going to be in the
...@@ -77,40 +86,42 @@ enum class align_val_t: size_t {}; ...@@ -77,40 +86,42 @@ enum class align_val_t: size_t {};
// OS X we need to intercept them using their mangled names. // OS X we need to intercept them using their mangled names.
#if !SANITIZER_MAC #if !SANITIZER_MAC
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); } void *operator new(size_t size)
{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); } void *operator new[](size_t size)
{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&) void *operator new(size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW); } { OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&) void *operator new[](size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW_BR); } { OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::align_val_t align) void *operator new(size_t size, std::align_val_t align)
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); } { OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::align_val_t align) void *operator new[](size_t size, std::align_val_t align)
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); } { OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); } { OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); } { OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
#else // SANITIZER_MAC #else // SANITIZER_MAC
INTERCEPTOR(void *, _Znwm, size_t size) { INTERCEPTOR(void *, _Znwm, size_t size) {
OPERATOR_NEW_BODY(FROM_NEW); OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
} }
INTERCEPTOR(void *, _Znam, size_t size) { INTERCEPTOR(void *, _Znam, size_t size) {
OPERATOR_NEW_BODY(FROM_NEW_BR); OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
} }
INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) { INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(FROM_NEW); OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
} }
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(FROM_NEW_BR); OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
} }
#endif #endif
......
...@@ -62,12 +62,9 @@ struct ShadowSegmentEndpoint { ...@@ -62,12 +62,9 @@ struct ShadowSegmentEndpoint {
}; };
void FlushUnneededASanShadowMemory(uptr p, uptr size) { void FlushUnneededASanShadowMemory(uptr p, uptr size) {
// Since asan's mapping is compacting, the shadow chunk may be // Since asan's mapping is compacting, the shadow chunk may be
// not page-aligned, so we only flush the page-aligned portion. // not page-aligned, so we only flush the page-aligned portion.
uptr page_size = GetPageSizeCached(); ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
ReleaseMemoryToOS(shadow_beg, shadow_end - shadow_beg);
} }
void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
...@@ -410,7 +407,7 @@ const void *__sanitizer_contiguous_container_find_bad_address( ...@@ -410,7 +407,7 @@ const void *__sanitizer_contiguous_container_find_bad_address(
// ending with end. // ending with end.
uptr kMaxRangeToCheck = 32; uptr kMaxRangeToCheck = 32;
uptr r1_beg = beg; uptr r1_beg = beg;
uptr r1_end = Min(end + kMaxRangeToCheck, mid); uptr r1_end = Min(beg + kMaxRangeToCheck, mid);
uptr r2_beg = Max(beg, mid - kMaxRangeToCheck); uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
uptr r2_end = Min(end, mid + kMaxRangeToCheck); uptr r2_end = Min(end, mid + kMaxRangeToCheck);
uptr r3_beg = Max(end - kMaxRangeToCheck, mid); uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
......
...@@ -44,8 +44,11 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, ...@@ -44,8 +44,11 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
// for mapping shadow and zeroing out pages doesn't "just work", so we should // for mapping shadow and zeroing out pages doesn't "just work", so we should
// probably provide higher-level interface for these operations. // probably provide higher-level interface for these operations.
// For now, just memset on Windows. // For now, just memset on Windows.
if (value || if (value || SANITIZER_WINDOWS == 1 ||
SANITIZER_WINDOWS == 1 || // TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be
// changed at all. It doesn't currently have an efficient means
// to zero a bunch of pages, but maybe we should add one.
SANITIZER_FUCHSIA == 1 ||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
} else { } else {
...@@ -84,8 +87,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( ...@@ -84,8 +87,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
} }
} }
// Calls __sanitizer::ReleaseMemoryToOS() on // Calls __sanitizer::ReleaseMemoryPagesToOS() on
// [MemToShadow(p), MemToShadow(p+size)] with proper rounding. // [MemToShadow(p), MemToShadow(p+size)].
void FlushUnneededASanShadowMemory(uptr p, uptr size); void FlushUnneededASanShadowMemory(uptr p, uptr size);
} // namespace __asan } // namespace __asan
...@@ -31,72 +31,10 @@ ...@@ -31,72 +31,10 @@
namespace __asan { namespace __asan {
const char *DescribeSignalOrException(int signo) {
switch (signo) {
case SIGFPE:
return "FPE";
case SIGILL:
return "ILL";
case SIGABRT:
return "ABRT";
default:
return "SEGV";
}
}
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
ScopedDeadlySignal signal_scope(GetCurrentThread()); StartReportDeadlySignal();
int code = (int)((siginfo_t*)siginfo)->si_code; SignalContext sig(siginfo, context);
// Write the first message using fd=2, just in case. ReportDeadlySignal(sig);
// It may actually fail to write in case stderr is closed.
internal_write(2, "ASAN:DEADLYSIGNAL\n", 18);
SignalContext sig = SignalContext::Create(siginfo, context);
// Access at a reasonable offset above SP, or slightly below it (to account
// for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
// probably a stack overflow.
#ifdef __s390__
// On s390, the fault address in siginfo points to start of the page, not
// to the precise word that was accessed. Mask off the low bits of sp to
// take it into account.
bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) &&
sig.addr < sig.sp + 0xFFFF;
#else
bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
#endif
#if __powerpc__
// Large stack frames can be allocated with e.g.
// lis r0,-10000
// stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
// If the store faults then sp will not have been updated, so test above
// will not work, becase the fault address will be more than just "slightly"
// below sp.
if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
u32 inst = *(unsigned *)sig.pc;
u32 ra = (inst >> 16) & 0x1F;
u32 opcd = inst >> 26;
u32 xo = (inst >> 1) & 0x3FF;
// Check for store-with-update to sp. The instructions we accept are:
// stbu rs,d(ra) stbux rs,ra,rb
// sthu rs,d(ra) sthux rs,ra,rb
// stwu rs,d(ra) stwux rs,ra,rb
// stdu rs,ds(ra) stdux rs,ra,rb
// where ra is r1 (the stack pointer).
if (ra == 1 &&
(opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
(opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
IsStackAccess = true;
}
#endif // __powerpc__
// We also check si_code to filter out SEGV caused by something else other
// then hitting the guard page or unmapped memory, like, for example,
// unaligned memory access.
if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(sig);
else
ReportDeadlySignal(signo, sig);
} }
// ---------------------- TSD ---------------- {{{1 // ---------------------- TSD ---------------- {{{1
......
...@@ -58,9 +58,8 @@ void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, ...@@ -58,9 +58,8 @@ void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
bool in_shadow, const char *after) { bool in_shadow, const char *after) {
Decorator d; Decorator d;
str->append("%s%s%x%x%s%s", before, str->append("%s%s%x%x%s%s", before,
in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4,
byte >> 4, byte & 15, byte & 15, d.Default(), after);
in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
} }
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
...@@ -86,7 +85,8 @@ bool ParseFrameDescription(const char *frame_descr, ...@@ -86,7 +85,8 @@ bool ParseFrameDescription(const char *frame_descr,
char *p; char *p;
// This string is created by the compiler and has the following form: // This string is created by the compiler and has the following form:
// "n alloc_1 alloc_2 ... alloc_n" // "n alloc_1 alloc_2 ... alloc_n"
// where alloc_i looks like "offset size len ObjectName". // where alloc_i looks like "offset size len ObjectName"
// or "offset size len ObjectName:line".
uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
if (n_objects == 0) if (n_objects == 0)
return false; return false;
...@@ -99,7 +99,14 @@ bool ParseFrameDescription(const char *frame_descr, ...@@ -99,7 +99,14 @@ bool ParseFrameDescription(const char *frame_descr,
return false; return false;
} }
p++; p++;
StackVarDescr var = {beg, size, p, len}; char *colon_pos = internal_strchr(p, ':');
uptr line = 0;
uptr name_len = len;
if (colon_pos != nullptr && colon_pos < p + len) {
name_len = colon_pos - p;
line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10);
}
StackVarDescr var = {beg, size, p, name_len, line};
vars->push_back(var); vars->push_back(var);
p += len; p += len;
} }
...@@ -113,53 +120,15 @@ bool ParseFrameDescription(const char *frame_descr, ...@@ -113,53 +120,15 @@ bool ParseFrameDescription(const char *frame_descr,
// immediately after printing error report. // immediately after printing error report.
class ScopedInErrorReport { class ScopedInErrorReport {
public: public:
explicit ScopedInErrorReport(bool fatal = false) { explicit ScopedInErrorReport(bool fatal = false)
halt_on_error_ = fatal || flags()->halt_on_error; : halt_on_error_(fatal || flags()->halt_on_error) {
// Make sure the registry and sanitizer report mutexes are locked while
if (lock_.TryLock()) { // we're printing an error report.
StartReporting(); // We can lock them only here to avoid self-deadlock in case of
return; // recursive reports.
} asanThreadRegistry().Lock();
Printf(
// ASan found two bugs in different threads simultaneously. "=================================================================\n");
u32 current_tid = GetCurrentTidOrInvalid();
if (reporting_thread_tid_ == current_tid ||
reporting_thread_tid_ == kInvalidTid) {
// This is either asynch signal or nested error during error reporting.
// Fail simple to avoid deadlocks in Report().
// Can't use Report() here because of potential deadlocks
// in nested signal handlers.
const char msg[] = "AddressSanitizer: nested bug in the same thread, "
"aborting.\n";
WriteToFile(kStderrFd, msg, sizeof(msg));
internal__exit(common_flags()->exitcode);
}
if (halt_on_error_) {
// Do not print more than one report, otherwise they will mix up.
// Error reporting functions shouldn't return at this situation, as
// they are effectively no-returns.
Report("AddressSanitizer: while reporting a bug found another one. "
"Ignoring.\n");
// Sleep long enough to make sure that the thread which started
// to print an error report will finish doing it.
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
// If we're still not dead for some reason, use raw _exit() instead of
// Die() to bypass any additional checks.
internal__exit(common_flags()->exitcode);
} else {
// The other thread will eventually finish reporting
// so it's safe to wait
lock_.Lock();
}
StartReporting();
} }
~ScopedInErrorReport() { ~ScopedInErrorReport() {
...@@ -177,6 +146,8 @@ class ScopedInErrorReport { ...@@ -177,6 +146,8 @@ class ScopedInErrorReport {
if (common_flags()->print_cmdline) if (common_flags()->print_cmdline)
PrintCmdline(); PrintCmdline();
if (common_flags()->print_module_map == 2) PrintModuleMap();
// Copy the message buffer so that we could start logging without holding a // Copy the message buffer so that we could start logging without holding a
// lock that gets aquired during printing. // lock that gets aquired during printing.
InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize); InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
...@@ -192,14 +163,19 @@ class ScopedInErrorReport { ...@@ -192,14 +163,19 @@ class ScopedInErrorReport {
error_report_callback(buffer_copy.data()); error_report_callback(buffer_copy.data());
} }
if (halt_on_error_ && common_flags()->abort_on_error) {
// On Android the message is truncated to 512 characters.
// FIXME: implement "compact" error format, possibly without, or with
// highly compressed stack traces?
// FIXME: or just use the summary line as abort message?
SetAbortMessage(buffer_copy.data());
}
// In halt_on_error = false mode, reset the current error object (before // In halt_on_error = false mode, reset the current error object (before
// unlocking). // unlocking).
if (!halt_on_error_) if (!halt_on_error_)
internal_memset(&current_error_, 0, sizeof(current_error_)); internal_memset(&current_error_, 0, sizeof(current_error_));
CommonSanitizerReportMutex.Unlock();
reporting_thread_tid_ = kInvalidTid;
lock_.Unlock();
if (halt_on_error_) { if (halt_on_error_) {
Report("ABORTING\n"); Report("ABORTING\n");
Die(); Die();
...@@ -217,39 +193,18 @@ class ScopedInErrorReport { ...@@ -217,39 +193,18 @@ class ScopedInErrorReport {
} }
private: private:
void StartReporting() { ScopedErrorReportLock error_report_lock_;
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
// We can lock them only here to avoid self-deadlock in case of
// recursive reports.
asanThreadRegistry().Lock();
CommonSanitizerReportMutex.Lock();
reporting_thread_tid_ = GetCurrentTidOrInvalid();
Printf("===================================================="
"=============\n");
}
static StaticSpinMutex lock_;
static u32 reporting_thread_tid_;
// Error currently being reported. This enables the destructor to interact // Error currently being reported. This enables the destructor to interact
// with the debugger and point it to an error description. // with the debugger and point it to an error description.
static ErrorDescription current_error_; static ErrorDescription current_error_;
bool halt_on_error_; bool halt_on_error_;
}; };
StaticSpinMutex ScopedInErrorReport::lock_;
u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
ErrorDescription ScopedInErrorReport::current_error_; ErrorDescription ScopedInErrorReport::current_error_;
void ReportStackOverflow(const SignalContext &sig) { void ReportDeadlySignal(const SignalContext &sig) {
ScopedInErrorReport in_report(/*fatal*/ true); ScopedInErrorReport in_report(/*fatal*/ true);
ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig); ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
in_report.ReportError(error);
}
void ReportDeadlySignal(int signo, const SignalContext &sig) {
ScopedInErrorReport in_report(/*fatal*/ true);
ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo);
in_report.ReportError(error); in_report.ReportError(error);
} }
...@@ -425,7 +380,7 @@ void __asan_describe_address(uptr addr) { ...@@ -425,7 +380,7 @@ void __asan_describe_address(uptr addr) {
} }
int __asan_report_present() { int __asan_report_present() {
return ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric; return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid;
} }
uptr __asan_get_report_pc() { uptr __asan_get_report_pc() {
...@@ -447,9 +402,11 @@ uptr __asan_get_report_sp() { ...@@ -447,9 +402,11 @@ uptr __asan_get_report_sp() {
} }
uptr __asan_get_report_address() { uptr __asan_get_report_address() {
if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) ErrorDescription &err = ScopedInErrorReport::CurrentError();
return ScopedInErrorReport::CurrentError() if (err.kind == kErrorKindGeneric)
.Generic.addr_description.Address(); return err.Generic.addr_description.Address();
else if (err.kind == kErrorKindDoubleFree)
return err.DoubleFree.addr_description.addr;
return 0; return 0;
} }
...@@ -468,7 +425,7 @@ uptr __asan_get_report_access_size() { ...@@ -468,7 +425,7 @@ uptr __asan_get_report_access_size() {
const char *__asan_get_report_description() { const char *__asan_get_report_description() {
if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
return ScopedInErrorReport::CurrentError().Generic.bug_descr; return ScopedInErrorReport::CurrentError().Generic.bug_descr;
return nullptr; return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription();
} }
extern "C" { extern "C" {
...@@ -482,9 +439,6 @@ void __sanitizer_ptr_cmp(void *a, void *b) { ...@@ -482,9 +439,6 @@ void __sanitizer_ptr_cmp(void *a, void *b) {
} }
} // extern "C" } // extern "C"
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default implementation of __asan_on_error that does nothing // Provide default implementation of __asan_on_error that does nothing
// and may be overriden by user. // and may be overriden by user.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
void __asan_on_error() {}
#endif
...@@ -21,6 +21,7 @@ struct StackVarDescr { ...@@ -21,6 +21,7 @@ struct StackVarDescr {
uptr size; uptr size;
const char *name_pos; const char *name_pos;
uptr name_len; uptr name_len;
uptr line;
}; };
// Returns the number of globals close to the provided address and copies // Returns the number of globals close to the provided address and copies
...@@ -43,8 +44,7 @@ bool ParseFrameDescription(const char *frame_descr, ...@@ -43,8 +44,7 @@ bool ParseFrameDescription(const char *frame_descr,
// Different kinds of error reports. // Different kinds of error reports.
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal); uptr access_size, u32 exp, bool fatal);
void ReportStackOverflow(const SignalContext &sig); void ReportDeadlySignal(const SignalContext &sig);
void ReportDeadlySignal(int signo, const SignalContext &sig);
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
BufferedStackTrace *free_stack); BufferedStackTrace *free_stack);
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
......
...@@ -44,6 +44,7 @@ static void AsanDie() { ...@@ -44,6 +44,7 @@ static void AsanDie() {
// Don't die twice - run a busy loop. // Don't die twice - run a busy loop.
while (1) { } while (1) { }
} }
if (common_flags()->print_module_map >= 1) PrintModuleMap();
if (flags()->sleep_before_dying) { if (flags()->sleep_before_dying) {
Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
SleepForSeconds(flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying);
...@@ -81,26 +82,6 @@ void ShowStatsAndAbort() { ...@@ -81,26 +82,6 @@ void ShowStatsAndAbort() {
Die(); Die();
} }
// ---------------------- mmap -------------------- {{{1
// Reserve memory range [beg, end].
// We need to use inclusive range because end+1 may not be representable.
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
CHECK_EQ((beg % GetMmapGranularity()), 0);
CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
uptr size = end - beg + 1;
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
void *res = MmapFixedNoReserve(beg, size, name);
if (res != (void*)beg) {
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
"Perhaps you're using ulimit -v\n", size);
Abort();
}
if (common_flags()->no_huge_pages_for_shadow)
NoHugePagesInRegion(beg, size);
if (common_flags()->use_madv_dontdump)
DontDumpShadowMemory(beg, size);
}
// --------------- LowLevelAllocateCallbac ---------- {{{1 // --------------- LowLevelAllocateCallbac ---------- {{{1
static void OnLowLevelAllocate(uptr ptr, uptr size) { static void OnLowLevelAllocate(uptr ptr, uptr size) {
PoisonShadow(ptr, size, kAsanInternalHeapMagic); PoisonShadow(ptr, size, kAsanInternalHeapMagic);
...@@ -332,46 +313,7 @@ static void InitializeHighMemEnd() { ...@@ -332,46 +313,7 @@ static void InitializeHighMemEnd() {
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
} }
static void ProtectGap(uptr addr, uptr size) { void PrintAddressSpaceLayout() {
if (!flags()->protect_shadow_gap) {
// The shadow gap is unprotected, so there is a chance that someone
// is actually using this memory. Which means it needs a shadow...
uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
uptr GapShadowEnd =
RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
if (Verbosity())
Printf("protect_shadow_gap=0:"
" not protecting shadow gap, allocating gap's shadow\n"
"|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg,
GapShadowEnd);
ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
"unprotected gap shadow");
return;
}
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res)
return;
// A few pages at the start of the address space can not be protected.
// But we really want to protect as much as possible, to prevent this memory
// being returned as a result of a non-FIXED mmap().
if (addr == kZeroBaseShadowStart) {
uptr step = GetMmapGranularity();
while (size > step && addr < kZeroBaseMaxShadowStart) {
addr += step;
size -= step;
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res)
return;
}
}
Report("ERROR: Failed to protect the shadow gap. "
"ASan cannot proceed correctly. ABORTING.\n");
DumpProcessMap();
Die();
}
static void PrintAddressSpaceLayout() {
Printf("|| `[%p, %p]` || HighMem ||\n", Printf("|| `[%p, %p]` || HighMem ||\n",
(void*)kHighMemBeg, (void*)kHighMemEnd); (void*)kHighMemBeg, (void*)kHighMemEnd);
Printf("|| `[%p, %p]` || HighShadow ||\n", Printf("|| `[%p, %p]` || HighShadow ||\n",
...@@ -408,6 +350,8 @@ static void PrintAddressSpaceLayout() { ...@@ -408,6 +350,8 @@ static void PrintAddressSpaceLayout() {
Printf("redzone=%zu\n", (uptr)flags()->redzone); Printf("redzone=%zu\n", (uptr)flags()->redzone);
Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone); Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb); Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb);
Printf("thread_local_quarantine_size_kb=%zuK\n",
(uptr)flags()->thread_local_quarantine_size_kb);
Printf("malloc_context_size=%zu\n", Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size); (uptr)common_flags()->malloc_context_size);
...@@ -472,78 +416,9 @@ static void AsanInitInternal() { ...@@ -472,78 +416,9 @@ static void AsanInitInternal() {
ReplaceSystemMalloc(); ReplaceSystemMalloc();
// Set the shadow memory address to uninitialized.
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
uptr shadow_start = kLowShadowBeg;
// Detect if a dynamic shadow address must used and find a available location
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
// expands to |__asan_shadow_memory_dynamic_address| which is
// |kDefaultShadowSentinel|.
if (shadow_start == kDefaultShadowSentinel) {
__asan_shadow_memory_dynamic_address = 0;
CHECK_EQ(0, kLowShadowBeg);
uptr granularity = GetMmapGranularity();
uptr alignment = 8 * granularity;
uptr left_padding = granularity;
uptr space_size = kHighShadowEnd + left_padding;
shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity);
CHECK_NE((uptr)0, shadow_start);
CHECK(IsAligned(shadow_start, alignment));
}
// Update the shadow memory address (potentially) used by instrumentation.
__asan_shadow_memory_dynamic_address = shadow_start;
if (kLowShadowBeg)
shadow_start -= GetMmapGranularity();
bool full_shadow_is_available =
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
!ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
}
#endif
if (Verbosity()) PrintAddressSpaceLayout();
DisableCoreDumperIfNecessary(); DisableCoreDumperIfNecessary();
if (full_shadow_is_available) { InitializeShadowMemory();
// mmap the low shadow plus at least one page at the left.
if (kLowShadowBeg)
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
CHECK(kLowShadowBeg != kLowShadowEnd);
// mmap the low shadow plus at least one page at the left.
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
// mmap the mid shadow.
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
// protect the gaps.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
} else {
Report("Shadow memory range interleaves with an existing memory mapping. "
"ASan cannot proceed correctly. ABORTING.\n");
Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
shadow_start, kHighShadowEnd);
DumpProcessMap();
Die();
}
AsanTSDInit(PlatformTSDDtor); AsanTSDInit(PlatformTSDDtor);
InstallDeadlySignalHandlers(AsanOnDeadlySignal); InstallDeadlySignalHandlers(AsanOnDeadlySignal);
...@@ -574,20 +449,18 @@ static void AsanInitInternal() { ...@@ -574,20 +449,18 @@ static void AsanInitInternal() {
InitTlsSize(); InitTlsSize();
// Create main thread. // Create main thread.
AsanThread *main_thread = AsanThread::Create( AsanThread *main_thread = CreateMainThread();
/* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
/* stack */ nullptr, /* detached */ true);
CHECK_EQ(0, main_thread->tid()); CHECK_EQ(0, main_thread->tid());
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid(),
/* signal_thread_is_registered */ nullptr);
force_interface_symbols(); // no-op. force_interface_symbols(); // no-op.
SanitizerInitializeUnwinder(); SanitizerInitializeUnwinder();
if (CAN_SANITIZE_LEAKS) { if (CAN_SANITIZE_LEAKS) {
__lsan::InitCommonLsan(); __lsan::InitCommonLsan();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
Atexit(__lsan::DoLeakCheck); if (flags()->halt_on_error)
Atexit(__lsan::DoLeakCheck);
else
Atexit(__lsan::DoRecoverableLeakCheckVoid);
} }
} }
...@@ -607,6 +480,11 @@ static void AsanInitInternal() { ...@@ -607,6 +480,11 @@ static void AsanInitInternal() {
} }
VReport(1, "AddressSanitizer Init done\n"); VReport(1, "AddressSanitizer Init done\n");
if (flags()->sleep_after_init) {
Report("Sleeping for %d second(s)\n", flags()->sleep_after_init);
SleepForSeconds(flags()->sleep_after_init);
}
} }
// Initialize as requested from some part of ASan runtime library (interceptors, // Initialize as requested from some part of ASan runtime library (interceptors,
...@@ -646,6 +524,7 @@ void NOINLINE __asan_handle_no_return() { ...@@ -646,6 +524,7 @@ void NOINLINE __asan_handle_no_return() {
top = curr_thread->stack_top(); top = curr_thread->stack_top();
bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
} else { } else {
CHECK(!SANITIZER_FUCHSIA);
// If we haven't seen this thread, try asking the OS for stack bounds. // If we haven't seen this thread, try asking the OS for stack bounds.
uptr tls_addr, tls_size, stack_size; uptr tls_addr, tls_size, stack_size;
GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr, GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
......
...@@ -45,7 +45,7 @@ struct ScarinessScoreBase { ...@@ -45,7 +45,7 @@ struct ScarinessScoreBase {
}; };
int GetScore() const { return score; } int GetScore() const { return score; }
const char *GetDescription() const { return descr; } const char *GetDescription() const { return descr; }
void Print() { void Print() const {
if (score && flags()->print_scariness) if (score && flags()->print_scariness)
Printf("SCARINESS: %d (%s)\n", score, descr); Printf("SCARINESS: %d (%s)\n", score, descr);
} }
......
//===-- asan_shadow_setup.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.
//
// Set up the shadow memory.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
// asan_fuchsia.cc has its own InitializeShadowMemory implementation.
#if !SANITIZER_FUCHSIA
#include "asan_internal.h"
#include "asan_mapping.h"
namespace __asan {
// ---------------------- mmap -------------------- {{{1
// Reserve memory range [beg, end].
// We need to use inclusive range because end+1 may not be representable.
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
CHECK_EQ((beg % GetMmapGranularity()), 0);
CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
uptr size = end - beg + 1;
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
void *res = MmapFixedNoReserve(beg, size, name);
if (res != (void *)beg) {
Report(
"ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
"Perhaps you're using ulimit -v\n",
size);
Abort();
}
if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
}
static void ProtectGap(uptr addr, uptr size) {
if (!flags()->protect_shadow_gap) {
// The shadow gap is unprotected, so there is a chance that someone
// is actually using this memory. Which means it needs a shadow...
uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
uptr GapShadowEnd =
RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
if (Verbosity())
Printf(
"protect_shadow_gap=0:"
" not protecting shadow gap, allocating gap's shadow\n"
"|| `[%p, %p]` || ShadowGap's shadow ||\n",
GapShadowBeg, GapShadowEnd);
ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
"unprotected gap shadow");
return;
}
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res) return;
// A few pages at the start of the address space can not be protected.
// But we really want to protect as much as possible, to prevent this memory
// being returned as a result of a non-FIXED mmap().
if (addr == kZeroBaseShadowStart) {
uptr step = GetMmapGranularity();
while (size > step && addr < kZeroBaseMaxShadowStart) {
addr += step;
size -= step;
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res) return;
}
}
Report(
"ERROR: Failed to protect the shadow gap. "
"ASan cannot proceed correctly. ABORTING.\n");
DumpProcessMap();
Die();
}
static void MaybeReportLinuxPIEBug() {
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
Report(
"See https://github.com/google/sanitizers/issues/856 for possible "
"workarounds.\n");
#endif
}
void InitializeShadowMemory() {
// Set the shadow memory address to uninitialized.
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
uptr shadow_start = kLowShadowBeg;
// Detect if a dynamic shadow address must used and find a available location
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
// expands to |__asan_shadow_memory_dynamic_address| which is
// |kDefaultShadowSentinel|.
if (shadow_start == kDefaultShadowSentinel) {
__asan_shadow_memory_dynamic_address = 0;
CHECK_EQ(0, kLowShadowBeg);
shadow_start = FindDynamicShadowStart();
}
// Update the shadow memory address (potentially) used by instrumentation.
__asan_shadow_memory_dynamic_address = shadow_start;
if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
bool full_shadow_is_available =
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
!ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
}
#endif
if (Verbosity()) PrintAddressSpaceLayout();
if (full_shadow_is_available) {
// mmap the low shadow plus at least one page at the left.
if (kLowShadowBeg)
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
CHECK(kLowShadowBeg != kLowShadowEnd);
// mmap the low shadow plus at least one page at the left.
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
// mmap the mid shadow.
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
// protect the gaps.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
} else {
Report(
"Shadow memory range interleaves with an existing memory mapping. "
"ASan cannot proceed correctly. ABORTING.\n");
Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
shadow_start, kHighShadowEnd);
MaybeReportLinuxPIEBug();
DumpProcessMap();
Die();
}
}
} // namespace __asan
#endif // !SANITIZER_FUCHSIA
...@@ -39,10 +39,6 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, ...@@ -39,10 +39,6 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
stack->size = 0; stack->size = 0;
if (LIKELY(asan_inited)) { if (LIKELY(asan_inited)) {
if ((t = GetCurrentThread()) && !t->isUnwinding()) { if ((t = GetCurrentThread()) && !t->isUnwinding()) {
// On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
// yields the call stack of the signal's handler and not of the code
// that raised the signal (as it does on Linux).
if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
uptr stack_top = t->stack_top(); uptr stack_top = t->stack_top();
uptr stack_bottom = t->stack_bottom(); uptr stack_bottom = t->stack_bottom();
ScopedUnwinding unwind_scope(t); ScopedUnwinding unwind_scope(t);
......
...@@ -29,15 +29,9 @@ static const char *kSuppressionTypes[] = { ...@@ -29,15 +29,9 @@ static const char *kSuppressionTypes[] = {
kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary, kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
kODRViolation}; kODRViolation};
extern "C" { SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) {
#if SANITIZER_SUPPORTS_WEAK_HOOKS return "";
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE }
const char *__asan_default_suppressions();
#else
// No week hooks, provide empty implementation.
const char *__asan_default_suppressions() { return ""; }
#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
} // extern "C"
void InitializeSuppressions() { void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx); CHECK_EQ(nullptr, suppression_ctx);
......
...@@ -25,11 +25,6 @@ namespace __asan { ...@@ -25,11 +25,6 @@ namespace __asan {
// AsanThreadContext implementation. // AsanThreadContext implementation.
struct CreateThreadContextArgs {
AsanThread *thread;
StackTrace *stack;
};
void AsanThreadContext::OnCreated(void *arg) { void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg); CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
if (args->stack) if (args->stack)
...@@ -86,7 +81,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg, ...@@ -86,7 +81,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__); AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
thread->start_routine_ = start_routine; thread->start_routine_ = start_routine;
thread->arg_ = arg; thread->arg_ = arg;
CreateThreadContextArgs args = { thread, stack }; AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached, asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
parent_tid, &args); parent_tid, &args);
...@@ -164,16 +159,19 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, ...@@ -164,16 +159,19 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
} }
inline AsanThread::StackBounds AsanThread::GetStackBounds() const { inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
if (!atomic_load(&stack_switching_, memory_order_acquire)) if (!atomic_load(&stack_switching_, memory_order_acquire)) {
return StackBounds{stack_bottom_, stack_top_}; // NOLINT // Make sure the stack bounds are fully initialized.
if (stack_bottom_ >= stack_top_) return {0, 0};
return {stack_bottom_, stack_top_};
}
char local; char local;
const uptr cur_stack = (uptr)&local; const uptr cur_stack = (uptr)&local;
// Note: need to check next stack first, because FinishSwitchFiber // Note: need to check next stack first, because FinishSwitchFiber
// may be in process of overwriting stack_top_/bottom_. But in such case // may be in process of overwriting stack_top_/bottom_. But in such case
// we are already on the next stack. // we are already on the next stack.
if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT return {next_stack_bottom_, next_stack_top_};
return StackBounds{stack_bottom_, stack_top_}; // NOLINT return {stack_bottom_, stack_top_};
} }
uptr AsanThread::stack_top() { uptr AsanThread::stack_top() {
...@@ -218,12 +216,12 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { ...@@ -218,12 +216,12 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
return nullptr; return nullptr;
} }
void AsanThread::Init() { void AsanThread::Init(const InitOptions *options) {
next_stack_top_ = next_stack_bottom_ = 0; next_stack_top_ = next_stack_bottom_ = 0;
atomic_store(&stack_switching_, false, memory_order_release); atomic_store(&stack_switching_, false, memory_order_release);
fake_stack_ = nullptr; // Will be initialized lazily if needed. fake_stack_ = nullptr; // Will be initialized lazily if needed.
CHECK_EQ(this->stack_size(), 0U); CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(); SetThreadStackAndTls(options);
CHECK_GT(this->stack_size(), 0U); CHECK_GT(this->stack_size(), 0U);
CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1)); CHECK(AddrIsInMem(stack_top_ - 1));
...@@ -234,10 +232,15 @@ void AsanThread::Init() { ...@@ -234,10 +232,15 @@ void AsanThread::Init() {
&local); &local);
} }
// Fuchsia doesn't use ThreadStart.
// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls.
#if !SANITIZER_FUCHSIA
thread_return_t AsanThread::ThreadStart( thread_return_t AsanThread::ThreadStart(
uptr os_id, atomic_uintptr_t *signal_thread_is_registered) { tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
Init(); Init();
asanThreadRegistry().StartThread(tid(), os_id, nullptr); asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false,
nullptr);
if (signal_thread_is_registered) if (signal_thread_is_registered)
atomic_store(signal_thread_is_registered, 1, memory_order_release); atomic_store(signal_thread_is_registered, 1, memory_order_release);
...@@ -264,7 +267,21 @@ thread_return_t AsanThread::ThreadStart( ...@@ -264,7 +267,21 @@ thread_return_t AsanThread::ThreadStart(
return res; return res;
} }
void AsanThread::SetThreadStackAndTls() { AsanThread *CreateMainThread() {
AsanThread *main_thread = AsanThread::Create(
/* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
/* stack */ nullptr, /* detached */ true);
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid(),
/* signal_thread_is_registered */ nullptr);
return main_thread;
}
// This implementation doesn't use the argument, which is just passed down
// from the caller of Init (which see, above). It's only there to support
// OS-specific implementations that need more information passed through.
void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
DCHECK_EQ(options, nullptr);
uptr tls_size = 0; uptr tls_size = 0;
uptr stack_size = 0; uptr stack_size = 0;
GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_), GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
...@@ -277,6 +294,8 @@ void AsanThread::SetThreadStackAndTls() { ...@@ -277,6 +294,8 @@ void AsanThread::SetThreadStackAndTls() {
CHECK(AddrIsInStack((uptr)&local)); CHECK(AddrIsInStack((uptr)&local));
} }
#endif // !SANITIZER_FUCHSIA
void AsanThread::ClearShadowForThreadStackAndTLS() { void AsanThread::ClearShadowForThreadStackAndTLS() {
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
if (tls_begin_ != tls_end_) if (tls_begin_ != tls_end_)
...@@ -297,24 +316,27 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr, ...@@ -297,24 +316,27 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
return true; return true;
} }
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
u8 *shadow_bottom = (u8*)MemToShadow(bottom); u8 *shadow_bottom = (u8*)MemToShadow(bottom);
while (shadow_ptr >= shadow_bottom && while (shadow_ptr >= shadow_bottom &&
*shadow_ptr != kAsanStackLeftRedzoneMagic) { *shadow_ptr != kAsanStackLeftRedzoneMagic) {
shadow_ptr--; shadow_ptr--;
mem_ptr -= SHADOW_GRANULARITY;
} }
while (shadow_ptr >= shadow_bottom && while (shadow_ptr >= shadow_bottom &&
*shadow_ptr == kAsanStackLeftRedzoneMagic) { *shadow_ptr == kAsanStackLeftRedzoneMagic) {
shadow_ptr--; shadow_ptr--;
mem_ptr -= SHADOW_GRANULARITY;
} }
if (shadow_ptr < shadow_bottom) { if (shadow_ptr < shadow_bottom) {
return false; return false;
} }
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY);
CHECK(ptr[0] == kCurrentStackFrameMagic); CHECK(ptr[0] == kCurrentStackFrameMagic);
access->offset = addr - (uptr)ptr; access->offset = addr - (uptr)ptr;
access->frame_pc = ptr[2]; access->frame_pc = ptr[2];
...@@ -389,7 +411,7 @@ void EnsureMainThreadIDIsCorrect() { ...@@ -389,7 +411,7 @@ void EnsureMainThreadIDIsCorrect() {
context->os_id = GetTid(); context->os_id = GetTid();
} }
__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
__asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
__asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
if (!context) return nullptr; if (!context) return nullptr;
...@@ -399,7 +421,7 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { ...@@ -399,7 +421,7 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
// --- Implementation of LSan-specific functions --- {{{1 // --- Implementation of LSan-specific functions --- {{{1
namespace __lsan { namespace __lsan {
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
uptr *cache_end, DTLS **dtls) { uptr *cache_end, DTLS **dtls) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
...@@ -415,7 +437,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, ...@@ -415,7 +437,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true; return true;
} }
void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
void *arg) { void *arg) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
if (t && t->has_fake_stack()) if (t && t->has_fake_stack())
......
...@@ -47,6 +47,11 @@ class AsanThreadContext : public ThreadContextBase { ...@@ -47,6 +47,11 @@ class AsanThreadContext : public ThreadContextBase {
void OnCreated(void *arg) override; void OnCreated(void *arg) override;
void OnFinished() override; void OnFinished() override;
struct CreateThreadContextArgs {
AsanThread *thread;
StackTrace *stack;
};
}; };
// AsanThreadContext objects are never freed, so we need many of them. // AsanThreadContext objects are never freed, so we need many of them.
...@@ -60,8 +65,10 @@ class AsanThread { ...@@ -60,8 +65,10 @@ class AsanThread {
static void TSDDtor(void *tsd); static void TSDDtor(void *tsd);
void Destroy(); void Destroy();
void Init(); // Should be called from the thread itself. struct InitOptions;
thread_return_t ThreadStart(uptr os_id, void Init(const InitOptions *options = nullptr);
thread_return_t ThreadStart(tid_t os_id,
atomic_uintptr_t *signal_thread_is_registered); atomic_uintptr_t *signal_thread_is_registered);
uptr stack_top(); uptr stack_top();
...@@ -116,17 +123,15 @@ class AsanThread { ...@@ -116,17 +123,15 @@ class AsanThread {
bool isUnwinding() const { return unwinding_; } bool isUnwinding() const { return unwinding_; }
void setUnwinding(bool b) { unwinding_ = b; } void setUnwinding(bool b) { unwinding_ = b; }
// True if we are in a deadly signal handler.
bool isInDeadlySignal() const { return in_deadly_signal_; }
void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; } AsanStats &stats() { return stats_; }
private: private:
// NOTE: There is no AsanThread constructor. It is allocated // NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state. // via mmap() and *must* be valid in zero-initialized state.
void SetThreadStackAndTls();
void SetThreadStackAndTls(const InitOptions *options);
void ClearShadowForThreadStackAndTLS(); void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack(); FakeStack *AsyncSignalSafeLazyInitFakeStack();
...@@ -156,7 +161,6 @@ class AsanThread { ...@@ -156,7 +161,6 @@ class AsanThread {
AsanThreadLocalMallocStorage malloc_storage_; AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_; AsanStats stats_;
bool unwinding_; bool unwinding_;
bool in_deadly_signal_;
}; };
// ScopedUnwinding is a scope for stacktracing member of a context // ScopedUnwinding is a scope for stacktracing member of a context
...@@ -171,20 +175,6 @@ class ScopedUnwinding { ...@@ -171,20 +175,6 @@ class ScopedUnwinding {
AsanThread *thread; AsanThread *thread;
}; };
// ScopedDeadlySignal is a scope for handling deadly signals.
class ScopedDeadlySignal {
public:
explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
if (thread) thread->setInDeadlySignal(true);
}
~ScopedDeadlySignal() {
if (thread) thread->setInDeadlySignal(false);
}
private:
AsanThread *thread;
};
// Returns a single instance of registry. // Returns a single instance of registry.
ThreadRegistry &asanThreadRegistry(); ThreadRegistry &asanThreadRegistry();
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include "asan_mapping.h" #include "asan_mapping.h"
#include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_win.h"
#include "sanitizer_common/sanitizer_win_defs.h"
using namespace __asan; // NOLINT using namespace __asan; // NOLINT
...@@ -40,35 +42,50 @@ uptr __asan_get_shadow_memory_dynamic_address() { ...@@ -40,35 +42,50 @@ uptr __asan_get_shadow_memory_dynamic_address() {
__asan_init(); __asan_init();
return __asan_shadow_memory_dynamic_address; return __asan_shadow_memory_dynamic_address;
} }
// -------------------- A workaround for the absence of weak symbols ----- {{{
// We don't have a direct equivalent of weak symbols when using MSVC, but we can
// use the /alternatename directive to tell the linker to default a specific
// symbol to a specific value, which works nicely for allocator hooks and
// __asan_default_options().
void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
void __sanitizer_default_free_hook(void *ptr) { }
const char* __asan_default_default_options() { return ""; }
const char* __asan_default_default_suppressions() { return ""; }
void __asan_default_on_error() {}
// 64-bit msvc will not prepend an underscore for symbols.
#ifdef _WIN64
#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT
#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT
#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT
#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT
#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT
#else
#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT
#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT
#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT
#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT
#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT
#endif
// }}}
} // extern "C" } // extern "C"
// ---------------------- Windows-specific interceptors ---------------- {{{ // ---------------------- Windows-specific interceptors ---------------- {{{
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
static LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler;
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
CONTEXT *context = info->ContextRecord;
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
SignalContext sig(exception_record, context);
ReportDeadlySignal(sig);
UNREACHABLE("returned from reporting deadly signal");
}
// Wrapper SEH Handler. If the exception should be handled by asan, we call
// __asan_unhandled_exception_filter, otherwise, we execute the user provided
// exception handler or the default.
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
DWORD exception_code = info->ExceptionRecord->ExceptionCode;
if (__sanitizer::IsHandledDeadlyException(exception_code))
return __asan_unhandled_exception_filter(info);
if (user_seh_handler)
return user_seh_handler(info);
// Bubble out to the default exception filter.
if (default_seh_handler)
return default_seh_handler(info);
return EXCEPTION_CONTINUE_SEARCH;
}
INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter,
LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
CHECK(REAL(SetUnhandledExceptionFilter));
if (ExceptionFilter == &SEHHandler)
return REAL(SetUnhandledExceptionFilter)(ExceptionFilter);
// We record the user provided exception handler to be called for all the
// exceptions unhandled by asan.
Swap(ExceptionFilter, user_seh_handler);
return ExceptionFilter;
}
INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) { INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) {
CHECK(REAL(RtlRaiseException)); CHECK(REAL(RtlRaiseException));
// This is a noreturn function, unless it's one of the exceptions raised to // This is a noreturn function, unless it's one of the exceptions raised to
...@@ -141,6 +158,7 @@ namespace __asan { ...@@ -141,6 +158,7 @@ namespace __asan {
void InitializePlatformInterceptors() { void InitializePlatformInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread); ASAN_INTERCEPT_FUNC(CreateThread);
ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
#ifdef _WIN64 #ifdef _WIN64
ASAN_INTERCEPT_FUNC(__C_specific_handler); ASAN_INTERCEPT_FUNC(__C_specific_handler);
...@@ -197,6 +215,18 @@ void *AsanDoesNotSupportStaticLinkage() { ...@@ -197,6 +215,18 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0; return 0;
} }
uptr FindDynamicShadowStart() {
uptr granularity = GetMmapGranularity();
uptr alignment = 8 * granularity;
uptr left_padding = granularity;
uptr space_size = kHighShadowEnd + left_padding;
uptr shadow_start =
FindAvailableMemoryRange(space_size, alignment, granularity, nullptr);
CHECK_NE((uptr)0, shadow_start);
CHECK(IsAligned(shadow_start, alignment));
return shadow_start;
}
void AsanCheckDynamicRTPrereqs() {} void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {} void AsanCheckIncompatibleRT() {}
...@@ -257,52 +287,8 @@ void InitializePlatformExceptionHandlers() { ...@@ -257,52 +287,8 @@ void InitializePlatformExceptionHandlers() {
#endif #endif
} }
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; bool IsSystemHeapAddress(uptr addr) {
return ::HeapValidate(GetProcessHeap(), 0, (void*)addr) != FALSE;
// Check based on flags if we should report this exception.
static bool ShouldReportDeadlyException(unsigned code) {
switch (code) {
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_IN_PAGE_ERROR:
return common_flags()->handle_segv;
case EXCEPTION_BREAKPOINT:
case EXCEPTION_ILLEGAL_INSTRUCTION: {
return common_flags()->handle_sigill;
}
}
return false;
}
// Return the textual name for this exception.
const char *DescribeSignalOrException(int signo) {
unsigned code = signo;
// Get the string description of the exception if this is a known deadly
// exception.
switch (code) {
case EXCEPTION_ACCESS_VIOLATION:
return "access-violation";
case EXCEPTION_IN_PAGE_ERROR:
return "in-page-error";
case EXCEPTION_BREAKPOINT:
return "breakpoint";
case EXCEPTION_ILLEGAL_INSTRUCTION:
return "illegal-instruction";
}
return nullptr;
}
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
CONTEXT *context = info->ContextRecord;
if (ShouldReportDeadlyException(exception_record->ExceptionCode)) {
SignalContext sig = SignalContext::Create(exception_record, context);
ReportDeadlySignal(exception_record->ExceptionCode, sig);
}
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
return default_seh_handler(info);
} }
// We want to install our own exception handler (EH) to print helpful reports // We want to install our own exception handler (EH) to print helpful reports
...@@ -341,10 +327,25 @@ int __asan_set_seh_filter() { ...@@ -341,10 +327,25 @@ int __asan_set_seh_filter() {
// immediately after the CRT runs. This way, our exception filter is called // immediately after the CRT runs. This way, our exception filter is called
// first and we can delegate to their filter if appropriate. // first and we can delegate to their filter if appropriate.
#pragma section(".CRT$XCAB", long, read) // NOLINT #pragma section(".CRT$XCAB", long, read) // NOLINT
__declspec(allocate(".CRT$XCAB")) __declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() =
int (*__intercept_seh)() = __asan_set_seh_filter; __asan_set_seh_filter;
// Piggyback on the TLS initialization callback directory to initialize asan as
// early as possible. Initializers in .CRT$XL* are called directly by ntdll,
// which run before the CRT. Users also add code to .CRT$XLC, so it's important
// to run our initializers first.
static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) {
if (reason == DLL_PROCESS_ATTACH) __asan_init();
}
#pragma section(".CRT$XLAB", long, read) // NOLINT
__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
unsigned long, void *) = asan_thread_init;
#endif #endif
WIN_FORCE_LINK(__asan_dso_reg_hook)
// }}} // }}}
} // namespace __asan } // namespace __asan
#endif // _WIN32 #endif // SANITIZER_WINDOWS
...@@ -12,24 +12,31 @@ ...@@ -12,24 +12,31 @@
// using the default "import library" generated when linking the DLL RTL. // using the default "import library" generated when linking the DLL RTL.
// //
// This includes: // This includes:
// - creating weak aliases to default implementation imported from asan dll.
// - forwarding the detect_stack_use_after_return runtime option // - forwarding the detect_stack_use_after_return runtime option
// - working around deficiencies of the MD runtime // - working around deficiencies of the MD runtime
// - installing a custom SEH handler // - installing a custom SEH handler
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Only compile this code when building asan_dynamic_runtime_thunk.lib #ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
// Using #ifdef rather than relying on Makefiles etc. #define SANITIZER_IMPORT_INTERFACE 1
// simplifies the build procedure. #include "sanitizer_common/sanitizer_win_defs.h"
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
// Define weak alias for all weak functions imported from asan dll.
#define INTERFACE_FUNCTION(Name)
#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
#include "asan_interface.inc"
// First, declare CRT sections we'll be using in this file // First, declare CRT sections we'll be using in this file
#pragma section(".CRT$XIB", long, read) // NOLINT
#pragma section(".CRT$XID", long, read) // NOLINT #pragma section(".CRT$XID", long, read) // NOLINT
#pragma section(".CRT$XCAB", long, read) // NOLINT #pragma section(".CRT$XCAB", long, read) // NOLINT
#pragma section(".CRT$XTW", long, read) // NOLINT #pragma section(".CRT$XTW", long, read) // NOLINT
#pragma section(".CRT$XTY", long, read) // NOLINT #pragma section(".CRT$XTY", long, read) // NOLINT
#pragma section(".CRT$XLAB", long, read) // NOLINT
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Define a copy of __asan_option_detect_stack_use_after_return that should be // Define a copy of __asan_option_detect_stack_use_after_return that should be
...@@ -44,14 +51,33 @@ ...@@ -44,14 +51,33 @@
// after initialization anyways. // after initialization anyways.
extern "C" { extern "C" {
__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); __declspec(dllimport) int __asan_should_detect_stack_use_after_return();
int __asan_option_detect_stack_use_after_return = int __asan_option_detect_stack_use_after_return;
__asan_should_detect_stack_use_after_return();
__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address(); __declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address();
void* __asan_shadow_memory_dynamic_address = void* __asan_shadow_memory_dynamic_address;
}
static int InitializeClonedVariables() {
__asan_option_detect_stack_use_after_return =
__asan_should_detect_stack_use_after_return();
__asan_shadow_memory_dynamic_address =
__asan_get_shadow_memory_dynamic_address(); __asan_get_shadow_memory_dynamic_address();
return 0;
} }
static void NTAPI asan_thread_init(void *mod, unsigned long reason,
void *reserved) {
if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables();
}
// Our cloned variables must be initialized before C/C++ constructors. If TLS
// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB
// initializer is needed as a backup.
__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() =
InitializeClonedVariables;
__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
unsigned long, void *) = asan_thread_init;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
// unload or on exit. ASan relies on LLVM global_dtors to call // unload or on exit. ASan relies on LLVM global_dtors to call
...@@ -98,4 +124,6 @@ __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = ...@@ -98,4 +124,6 @@ __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
SetSEHFilter; SetSEHFilter;
} }
#endif // ASAN_DYNAMIC_RUNTIME_THUNK WIN_FORCE_LINK(__asan_dso_reg_hook)
#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
//===-- asan_win_weak_interception.cc -------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This module should be included in Address Sanitizer when it is implemented as
// a shared library on Windows (dll), in order to delegate the calls of weak
// functions to the implementation in the main executable when a strong
// definition is provided.
//===----------------------------------------------------------------------===//
#ifdef SANITIZER_DYNAMIC
#include "sanitizer_common/sanitizer_win_weak_interception.h"
#include "asan_interface_internal.h"
// Check if strong definitions for weak functions are present in the main
// executable. If that is the case, override dll functions to point to strong
// implementations.
#define INTERFACE_FUNCTION(Name)
#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
#include "asan_interface.inc"
#endif // SANITIZER_DYNAMIC
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
# a separate file so that version updates don't involve re-running # a separate file so that version updates don't involve re-running
# automake. # automake.
# CURRENT:REVISION:AGE # CURRENT:REVISION:AGE
4:0:0 5:0:0
...@@ -44,7 +44,8 @@ ...@@ -44,7 +44,8 @@
#endif #endif
#define CONST_SECTION .section .rodata #define CONST_SECTION .section .rodata
#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) #if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
defined(__linux__)
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
#else #else
#define NO_EXEC_STACK_DIRECTIVE #define NO_EXEC_STACK_DIRECTIVE
...@@ -67,10 +68,42 @@ ...@@ -67,10 +68,42 @@
#endif #endif
#if defined(__arm__) #if defined(__arm__)
/*
* Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
* - for '-mthumb -march=armv6' compiler defines '__thumb__'
* - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
*/
#if defined(__thumb2__) || defined(__thumb__)
#define DEFINE_CODE_STATE .thumb SEPARATOR
#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
#if defined(__thumb2__)
#define USE_THUMB_2
#define IT(cond) it cond
#define ITT(cond) itt cond
#define ITE(cond) ite cond
#else
#define USE_THUMB_1
#define IT(cond)
#define ITT(cond)
#define ITE(cond)
#endif // defined(__thumb__2)
#else // !defined(__thumb2__) && !defined(__thumb__)
#define DEFINE_CODE_STATE .arm SEPARATOR
#define DECLARE_FUNC_ENCODING
#define IT(cond)
#define ITT(cond)
#define ITE(cond)
#endif
#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
#endif
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 #if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
#define ARM_HAS_BX #define ARM_HAS_BX
#endif #endif
#if !defined(__ARM_FEATURE_CLZ) && \ #if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
(__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__))) (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
#define __ARM_FEATURE_CLZ #define __ARM_FEATURE_CLZ
#endif #endif
...@@ -92,19 +125,14 @@ ...@@ -92,19 +125,14 @@
JMP(ip) JMP(ip)
#endif #endif
#if __ARM_ARCH_ISA_THUMB == 2 #if defined(USE_THUMB_2)
#define IT(cond) it cond
#define ITT(cond) itt cond
#else
#define IT(cond)
#define ITT(cond)
#endif
#if __ARM_ARCH_ISA_THUMB == 2
#define WIDE(op) op.w #define WIDE(op) op.w
#else #else
#define WIDE(op) op #define WIDE(op) op
#endif #endif
#else // !defined(__arm)
#define DECLARE_FUNC_ENCODING
#define DEFINE_CODE_STATE
#endif #endif
#define GLUE2(a, b) a##b #define GLUE2(a, b) a##b
...@@ -119,13 +147,16 @@ ...@@ -119,13 +147,16 @@
#endif #endif
#define DEFINE_COMPILERRT_FUNCTION(name) \ #define DEFINE_COMPILERRT_FUNCTION(name) \
DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \ FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) \ DECLARE_SYMBOL_VISIBILITY(name) \
DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name): SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \ FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
...@@ -134,16 +165,20 @@ ...@@ -134,16 +165,20 @@
SYMBOL_NAME(name): SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \ FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR \ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name): SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
DEFINE_CODE_STATE \
.globl name SEPARATOR \ .globl name SEPARATOR \
SYMBOL_IS_FUNC(name) SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \
HIDDEN(name) SEPARATOR \ HIDDEN(name) SEPARATOR \
DECLARE_FUNC_ENCODING \
name: name:
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
......
...@@ -142,6 +142,10 @@ extern "C" { ...@@ -142,6 +142,10 @@ extern "C" {
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end); void **end);
// 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(void);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
......
...@@ -156,8 +156,10 @@ extern "C" { ...@@ -156,8 +156,10 @@ extern "C" {
// Prints stack traces for all live heap allocations ordered by total // Prints stack traces for all live heap allocations ordered by total
// allocation size until `top_percent` of total live heap is shown. // allocation size until `top_percent` of total live heap is shown.
// `top_percent` should be between 1 and 100. // `top_percent` should be between 1 and 100.
// At most `max_number_of_contexts` contexts (stack traces) is printed.
// Experimental feature currently available only with asan on Linux/x86_64. // Experimental feature currently available only with asan on Linux/x86_64.
void __sanitizer_print_memory_profile(size_t top_percent); void __sanitizer_print_memory_profile(size_t top_percent,
size_t max_number_of_contexts);
// Fiber annotation interface. // Fiber annotation interface.
// Before switching to a different stack, one must call // Before switching to a different stack, one must call
...@@ -180,6 +182,13 @@ extern "C" { ...@@ -180,6 +182,13 @@ extern "C" {
void __sanitizer_finish_switch_fiber(void *fake_stack_save, void __sanitizer_finish_switch_fiber(void *fake_stack_save,
const void **bottom_old, const void **bottom_old,
size_t *size_old); size_t *size_old);
// Get full module name and calculate pc offset within it.
// Returns 1 if pc belongs to some module, 0 if module was not found.
int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path,
size_t module_path_len,
void **pc_offset);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
......
...@@ -17,45 +17,15 @@ ...@@ -17,45 +17,15 @@
extern "C" { extern "C" {
#endif #endif
// Initialize coverage.
void __sanitizer_cov_init();
// Record and dump coverage info. // Record and dump coverage info.
void __sanitizer_cov_dump(); void __sanitizer_cov_dump();
// Open <name>.sancov.packed in the coverage directory and return the file
// descriptor. Returns -1 on failure, or if coverage dumping is disabled.
// This is intended for use by sandboxing code.
intptr_t __sanitizer_maybe_open_cov_file(const char *name);
// Get the number of unique covered blocks (or edges).
// This can be useful for coverage-directed in-process fuzzers.
uintptr_t __sanitizer_get_total_unique_coverage();
// Get the number of unique indirect caller-callee pairs.
uintptr_t __sanitizer_get_total_unique_caller_callee_pairs();
// Reset the basic-block (edge) coverage to the initial state. // Clear collected coverage info.
// Useful for in-process fuzzing to start collecting coverage from scratch. void __sanitizer_cov_reset();
// Experimental, will likely not work for multi-threaded process.
void __sanitizer_reset_coverage();
// Set *data to the array of covered PCs and return the size of that array.
// Some of the entries in *data will be zero.
uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data);
// The coverage instrumentation may optionally provide imprecise counters. // Dump collected coverage info. Sorts pcs by module into individual .sancov
// Rather than exposing the counter values to the user we instead map // files.
// the counters to a bitset. void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len);
// Every counter is associated with 8 bits in the bitset.
// We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
// The i-th bit is set to 1 if the counter value is in the i-th range.
// This counter-based coverage implementation is *not* thread-safe.
// Returns the number of registered coverage counters.
uintptr_t __sanitizer_get_number_of_counters();
// Updates the counter 'bitset', clears the counters and returns the number of
// new bits in 'bitset'.
// If 'bitset' is nullptr, only clears the counters.
// Otherwise 'bitset' should be at least
// __sanitizer_get_number_of_counters bytes long and 8-aligned.
uintptr_t
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
......
...@@ -62,8 +62,14 @@ extern "C" { ...@@ -62,8 +62,14 @@ extern "C" {
// for the program it is linked into (if the return value is non-zero). This // 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 // function must be defined as returning a constant value; any behavior beyond
// that is unsupported. // that is unsupported.
// To avoid dead stripping, you may need to define this function with
// __attribute__((used))
int __lsan_is_turned_off(); int __lsan_is_turned_off();
// This function may be optionally provided by user and should return
// a string containing LSan runtime options. See lsan_flags.inc for details.
const char *__lsan_default_options();
// This function may be optionally provided by the user and should return // This function may be optionally provided by the user and should return
// a string containing LSan suppressions. // a string containing LSan suppressions.
const char *__lsan_default_suppressions(); const char *__lsan_default_suppressions();
......
//===-- tsan_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 ThreadSanitizer (TSan), a race detector.
//
// Public interface header for TSan.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_TSAN_INTERFACE_H
#define SANITIZER_TSAN_INTERFACE_H
#include <sanitizer/common_interface_defs.h>
#ifdef __cplusplus
extern "C" {
#endif
// __tsan_release establishes a happens-before relation with a preceding
// __tsan_acquire on the same address.
void __tsan_acquire(void *addr);
void __tsan_release(void *addr);
// Annotations for custom mutexes.
// The annotations allow to get better reports (with sets of locked mutexes),
// detect more types of bugs (e.g. mutex misuses, races between lock/unlock and
// destruction and potential deadlocks) and improve precision and performance
// (by ignoring individual atomic operations in mutex code). However, the
// downside is that annotated mutex code itself is not checked for correctness.
// Mutex creation flags are passed to __tsan_mutex_create annotation.
// If mutex has no constructor and __tsan_mutex_create is not called,
// the flags may be passed to __tsan_mutex_pre_lock/__tsan_mutex_post_lock
// annotations.
// Mutex has static storage duration and no-op constructor and destructor.
// This effectively makes tsan ignore destroy annotation.
const unsigned __tsan_mutex_linker_init = 1 << 0;
// Mutex is write reentrant.
const unsigned __tsan_mutex_write_reentrant = 1 << 1;
// Mutex is read reentrant.
const unsigned __tsan_mutex_read_reentrant = 1 << 2;
// Mutex operation flags:
// Denotes read lock operation.
const unsigned __tsan_mutex_read_lock = 1 << 3;
// Denotes try lock operation.
const unsigned __tsan_mutex_try_lock = 1 << 4;
// Denotes that a try lock operation has failed to acquire the mutex.
const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
// Denotes that the lock operation acquires multiple recursion levels.
// Number of levels is passed in recursion parameter.
// This is useful for annotation of e.g. Java builtin monitors,
// for which wait operation releases all recursive acquisitions of the mutex.
const unsigned __tsan_mutex_recursive_lock = 1 << 6;
// Denotes that the unlock operation releases all recursion levels.
// Number of released levels is returned and later must be passed to
// the corresponding __tsan_mutex_post_lock annotation.
const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
// Annotate creation of a mutex.
// Supported flags: mutex creation flags.
void __tsan_mutex_create(void *addr, unsigned flags);
// Annotate destruction of a mutex.
// Supported flags:
// - __tsan_mutex_linker_init
void __tsan_mutex_destroy(void *addr, unsigned flags);
// Annotate start of lock operation.
// Supported flags:
// - __tsan_mutex_read_lock
// - __tsan_mutex_try_lock
// - all mutex creation flags
void __tsan_mutex_pre_lock(void *addr, unsigned flags);
// Annotate end of lock operation.
// Supported flags:
// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_lock)
// - __tsan_mutex_try_lock (must match __tsan_mutex_pre_lock)
// - __tsan_mutex_try_lock_failed
// - __tsan_mutex_recursive_lock
// - all mutex creation flags
void __tsan_mutex_post_lock(void *addr, unsigned flags, int recursion);
// Annotate start of unlock operation.
// Supported flags:
// - __tsan_mutex_read_lock
// - __tsan_mutex_recursive_unlock
int __tsan_mutex_pre_unlock(void *addr, unsigned flags);
// Annotate end of unlock operation.
// Supported flags:
// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_unlock)
void __tsan_mutex_post_unlock(void *addr, unsigned flags);
// Annotate start/end of notify/signal/broadcast operation.
// Supported flags: none.
void __tsan_mutex_pre_signal(void *addr, unsigned flags);
void __tsan_mutex_post_signal(void *addr, unsigned flags);
// Annotate start/end of a region of code where lock/unlock/signal operation
// diverts to do something else unrelated to the mutex. This can be used to
// annotate, for example, calls into cooperative scheduler or contention
// profiling code.
// These annotations must be called only from within
// __tsan_mutex_pre/post_lock, __tsan_mutex_pre/post_unlock,
// __tsan_mutex_pre/post_signal regions.
// Supported flags: none.
void __tsan_mutex_pre_divert(void *addr, unsigned flags);
void __tsan_mutex_post_divert(void *addr, unsigned flags);
// External race detection API.
// Can be used by non-instrumented libraries to detect when their objects are
// being used in an unsafe manner.
// - __tsan_external_read/__tsan_external_write annotates the logical reads
// and writes of the object at the specified address. 'caller_pc' should
// be the PC of the library user, which the library can obtain with e.g.
// `__builtin_return_address(0)`.
// - __tsan_external_register_tag registers a 'tag' with the specified name,
// which is later used in read/write annotations to denote the object type
// - __tsan_external_assign_tag can optionally mark a heap object with a tag
void *__tsan_external_register_tag(const char *object_type);
void __tsan_external_register_header(void *tag, const char *header);
void __tsan_external_assign_tag(void *addr, void *tag);
void __tsan_external_read(void *addr, void *caller_pc, void *tag);
void __tsan_external_write(void *addr, void *caller_pc, void *tag);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SANITIZER_TSAN_INTERFACE_H
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
#ifndef INTERCEPTION_H #ifndef INTERCEPTION_H
#define INTERCEPTION_H #define INTERCEPTION_H
#if !defined(__linux__) && !defined(__FreeBSD__) && \ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__) && \
!defined(__APPLE__) && !defined(_WIN32) !defined(__NetBSD__) && !defined(_WIN32) && !defined(__Fuchsia__)
# error "Interception doesn't work on this operating system." # error "Interception doesn't work on this operating system."
#endif #endif
...@@ -127,7 +127,7 @@ const interpose_substitution substitution_##func_name[] \ ...@@ -127,7 +127,7 @@ const interpose_substitution substitution_##func_name[] \
extern "C" ret_type func(__VA_ARGS__); extern "C" ret_type func(__VA_ARGS__);
# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__) || defined(__NetBSD__)
# define WRAP(x) __interceptor_ ## x # define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x # define WRAPPER_NAME(x) "__interceptor_" #x
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
...@@ -137,7 +137,7 @@ const interpose_substitution substitution_##func_name[] \ ...@@ -137,7 +137,7 @@ const interpose_substitution substitution_##func_name[] \
# define DECLARE_WRAPPER(ret_type, func, ...) \ # define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__) \ extern "C" ret_type func(__VA_ARGS__) \
__attribute__((alias("__interceptor_" #func), visibility("default"))); __attribute__((alias("__interceptor_" #func), visibility("default")));
#else #elif !defined(__Fuchsia__)
# define WRAP(x) __interceptor_ ## x # define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x # define WRAPPER_NAME(x) "__interceptor_" #x
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
...@@ -146,7 +146,15 @@ const interpose_substitution substitution_##func_name[] \ ...@@ -146,7 +146,15 @@ const interpose_substitution substitution_##func_name[] \
__attribute__((weak, alias("__interceptor_" #func), visibility("default"))); __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
#endif #endif
#if !defined(__APPLE__) #if defined(__Fuchsia__)
// There is no general interception at all on Fuchsia.
// Sanitizer runtimes just define functions directly to preempt them,
// and have bespoke ways to access the underlying libc functions.
# include <zircon/sanitizer.h>
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
# define REAL(x) __unsanitized_##x
# define DECLARE_REAL(ret_type, func, ...)
#elif !defined(__APPLE__)
# define PTR_TO_REAL(x) real_##x # define PTR_TO_REAL(x) real_##x
# define REAL(x) __interception::PTR_TO_REAL(x) # define REAL(x) __interception::PTR_TO_REAL(x)
# define FUNC_TYPE(x) x##_f # define FUNC_TYPE(x) x##_f
...@@ -164,15 +172,19 @@ const interpose_substitution substitution_##func_name[] \ ...@@ -164,15 +172,19 @@ const interpose_substitution substitution_##func_name[] \
# define ASSIGN_REAL(x, y) # define ASSIGN_REAL(x, y)
#endif // __APPLE__ #endif // __APPLE__
#if !defined(__Fuchsia__)
#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
DECLARE_REAL(ret_type, func, __VA_ARGS__) \ DECLARE_REAL(ret_type, func, __VA_ARGS__) \
extern "C" ret_type WRAP(func)(__VA_ARGS__); extern "C" ret_type WRAP(func)(__VA_ARGS__);
#else
#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...)
#endif
// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR // Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
// macros does its job. In exceptional cases you may need to call REAL(foo) // macros does its job. In exceptional cases you may need to call REAL(foo)
// without defining INTERCEPTOR(..., foo, ...). For example, if you override // without defining INTERCEPTOR(..., foo, ...). For example, if you override
// foo with an interceptor for other function. // foo with an interceptor for other function.
#if !defined(__APPLE__) #if !defined(__APPLE__) && !defined(__Fuchsia__)
# define DEFINE_REAL(ret_type, func, ...) \ # define DEFINE_REAL(ret_type, func, ...) \
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
namespace __interception { \ namespace __interception { \
...@@ -182,7 +194,18 @@ const interpose_substitution substitution_##func_name[] \ ...@@ -182,7 +194,18 @@ const interpose_substitution substitution_##func_name[] \
# define DEFINE_REAL(ret_type, func, ...) # define DEFINE_REAL(ret_type, func, ...)
#endif #endif
#if !defined(__APPLE__) #if defined(__Fuchsia__)
// We need to define the __interceptor_func name just to get
// sanitizer_common/scripts/gen_dynamic_list.py to export func.
// But we don't need to export __interceptor_func to get that.
#define INTERCEPTOR(ret_type, func, ...) \
extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \
__interceptor_##func(__VA_ARGS__); \
extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__)
#elif !defined(__APPLE__)
#define INTERCEPTOR(ret_type, func, ...) \ #define INTERCEPTOR(ret_type, func, ...) \
DEFINE_REAL(ret_type, func, __VA_ARGS__) \ DEFINE_REAL(ret_type, func, __VA_ARGS__) \
DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
...@@ -239,7 +262,7 @@ typedef unsigned long uptr; // NOLINT ...@@ -239,7 +262,7 @@ typedef unsigned long uptr; // NOLINT
#define INCLUDED_FROM_INTERCEPTION_LIB #define INCLUDED_FROM_INTERCEPTION_LIB
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
# include "interception_linux.h" # include "interception_linux.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \ # define INTERCEPT_FUNCTION_VER(func, symver) \
...@@ -249,7 +272,7 @@ typedef unsigned long uptr; // NOLINT ...@@ -249,7 +272,7 @@ typedef unsigned long uptr; // NOLINT
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \ # define INTERCEPT_FUNCTION_VER(func, symver) \
INTERCEPT_FUNCTION_VER_MAC(func, symver) INTERCEPT_FUNCTION_VER_MAC(func, symver)
#else // defined(_WIN32) #elif defined(_WIN32)
# include "interception_win.h" # include "interception_win.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func) # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \ # define INTERCEPT_FUNCTION_VER(func, symver) \
......
...@@ -10,14 +10,22 @@ ...@@ -10,14 +10,22 @@
// Linux-specific interception methods. // Linux-specific interception methods.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#include "interception.h" #include "interception.h"
#include <dlfcn.h> // for dlsym() and dlvsym() #include <dlfcn.h> // for dlsym() and dlvsym()
#ifdef __NetBSD__
#include "sanitizer_common/sanitizer_libc.h"
#endif
namespace __interception { namespace __interception {
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
uptr real, uptr wrapper) { uptr real, uptr wrapper) {
#ifdef __NetBSD__
// XXX: Find a better way to handle renames
if (internal_strcmp(func_name, "sigaction") == 0) func_name = "__sigaction14";
#endif
*func_addr = (uptr)dlsym(RTLD_NEXT, func_name); *func_addr = (uptr)dlsym(RTLD_NEXT, func_name);
return real == wrapper; return real == wrapper;
} }
...@@ -30,5 +38,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver) { ...@@ -30,5 +38,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver) {
} // namespace __interception } // namespace __interception
#endif // __linux__ || __FreeBSD__ || __NetBSD__
#endif // __linux__ || __FreeBSD__
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
// Linux-specific interception methods. // Linux-specific interception methods.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB) #if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error "interception_linux.h should be included from interception library only" # error "interception_linux.h should be included from interception library only"
...@@ -42,4 +42,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver); ...@@ -42,4 +42,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
#endif // !defined(__ANDROID__) #endif // !defined(__ANDROID__)
#endif // INTERCEPTION_LINUX_H #endif // INTERCEPTION_LINUX_H
#endif // __linux__ || __FreeBSD__ #endif // __linux__ || __FreeBSD__ || __NetBSD__
...@@ -146,10 +146,16 @@ static void InterceptionFailed() { ...@@ -146,10 +146,16 @@ static void InterceptionFailed() {
} }
static bool DistanceIsWithin2Gig(uptr from, uptr target) { static bool DistanceIsWithin2Gig(uptr from, uptr target) {
#if SANITIZER_WINDOWS64
if (from < target) if (from < target)
return target - from <= (uptr)0x7FFFFFFFU; return target - from <= (uptr)0x7FFFFFFFU;
else else
return from - target <= (uptr)0x80000000U; return from - target <= (uptr)0x80000000U;
#else
// In a 32-bit address space, the address calculation will wrap, so this check
// is unnecessary.
return true;
#endif
} }
static uptr GetMmapGranularity() { static uptr GetMmapGranularity() {
...@@ -215,9 +221,8 @@ static bool IsMemoryPadding(uptr address, uptr size) { ...@@ -215,9 +221,8 @@ static bool IsMemoryPadding(uptr address, uptr size) {
return true; return true;
} }
static const u8 kHintNop10Bytes[] = { static const u8 kHintNop9Bytes[] = {
0x66, 0x66, 0x0F, 0x1F, 0x84, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00
}; };
template<class T> template<class T>
...@@ -232,8 +237,8 @@ static bool FunctionHasPrefix(uptr address, const T &pattern) { ...@@ -232,8 +237,8 @@ static bool FunctionHasPrefix(uptr address, const T &pattern) {
static bool FunctionHasPadding(uptr address, uptr size) { static bool FunctionHasPadding(uptr address, uptr size) {
if (IsMemoryPadding(address - size, size)) if (IsMemoryPadding(address - size, size))
return true; return true;
if (size <= sizeof(kHintNop10Bytes) && if (size <= sizeof(kHintNop9Bytes) &&
FunctionHasPrefix(address, kHintNop10Bytes)) FunctionHasPrefix(address, kHintNop9Bytes))
return true; return true;
return false; return false;
} }
...@@ -469,7 +474,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { ...@@ -469,7 +474,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
switch (*(u8*)address) { switch (*(u8*)address) {
case 0xA1: // A1 XX XX XX XX XX XX XX XX : case 0xA1: // A1 XX XX XX XX XX XX XX XX :
// movabs eax, dword ptr ds:[XXXXXXXX] // movabs eax, dword ptr ds:[XXXXXXXX]
return 8; return 9;
} }
switch (*(u16*)address) { switch (*(u16*)address) {
...@@ -487,6 +492,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { ...@@ -487,6 +492,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x5741: // push r15 case 0x5741: // push r15
case 0x9066: // Two-byte NOP case 0x9066: // Two-byte NOP
return 2; return 2;
case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]
if (rel_offset)
*rel_offset = 2;
return 6;
} }
switch (0x00FFFFFF & *(u32*)address) { switch (0x00FFFFFF & *(u32*)address) {
...@@ -870,6 +880,8 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { ...@@ -870,6 +880,8 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
IMAGE_DATA_DIRECTORY *export_directory = IMAGE_DATA_DIRECTORY *export_directory =
&headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (export_directory->Size == 0)
return 0;
RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module, RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
export_directory->VirtualAddress); export_directory->VirtualAddress);
RVAPtr<DWORD> functions(module, exports->AddressOfFunctions); RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
......
...@@ -16,11 +16,15 @@ endif ...@@ -16,11 +16,15 @@ endif
sanitizer_lsan_files = \ sanitizer_lsan_files = \
lsan_common.cc \ lsan_common.cc \
lsan_common_linux.cc lsan_common_linux.cc \
lsan_common_mac.cc
lsan_files = \ lsan_files = \
$(sanitizer_lsan_files) \ $(sanitizer_lsan_files) \
lsan.cc \ lsan.cc \
lsan_linux.cc \
lsan_mac.cc \
lsan_malloc_mac.cc \
lsan_allocator.cc \ lsan_allocator.cc \
lsan_interceptors.cc \ lsan_interceptors.cc \
lsan_preinit.cc \ lsan_preinit.cc \
......
...@@ -107,9 +107,10 @@ liblsan_la_DEPENDENCIES = \ ...@@ -107,9 +107,10 @@ liblsan_la_DEPENDENCIES = \
$(top_builddir)/sanitizer_common/libsanitizer_common.la \ $(top_builddir)/sanitizer_common/libsanitizer_common.la \
$(top_builddir)/interception/libinterception.la \ $(top_builddir)/interception/libinterception.la \
$(am__append_1) $(am__DEPENDENCIES_1) $(am__append_1) $(am__DEPENDENCIES_1)
am__objects_1 = lsan_common.lo lsan_common_linux.lo am__objects_1 = lsan_common.lo lsan_common_linux.lo lsan_common_mac.lo
am__objects_2 = $(am__objects_1) lsan.lo lsan_allocator.lo \ am__objects_2 = $(am__objects_1) lsan.lo lsan_linux.lo lsan_mac.lo \
lsan_interceptors.lo lsan_preinit.lo lsan_thread.lo lsan_malloc_mac.lo lsan_allocator.lo lsan_interceptors.lo \
lsan_preinit.lo lsan_thread.lo
am_liblsan_la_OBJECTS = $(am__objects_2) am_liblsan_la_OBJECTS = $(am__objects_2)
liblsan_la_OBJECTS = $(am_liblsan_la_OBJECTS) liblsan_la_OBJECTS = $(am_liblsan_la_OBJECTS)
liblsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ liblsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
...@@ -299,11 +300,15 @@ noinst_LTLIBRARIES = libsanitizer_lsan.la ...@@ -299,11 +300,15 @@ noinst_LTLIBRARIES = libsanitizer_lsan.la
@LSAN_SUPPORTED_TRUE@toolexeclib_LTLIBRARIES = liblsan.la @LSAN_SUPPORTED_TRUE@toolexeclib_LTLIBRARIES = liblsan.la
sanitizer_lsan_files = \ sanitizer_lsan_files = \
lsan_common.cc \ lsan_common.cc \
lsan_common_linux.cc lsan_common_linux.cc \
lsan_common_mac.cc
lsan_files = \ lsan_files = \
$(sanitizer_lsan_files) \ $(sanitizer_lsan_files) \
lsan.cc \ lsan.cc \
lsan_linux.cc \
lsan_mac.cc \
lsan_malloc_mac.cc \
lsan_allocator.cc \ lsan_allocator.cc \
lsan_interceptors.cc \ lsan_interceptors.cc \
lsan_preinit.cc \ lsan_preinit.cc \
...@@ -446,7 +451,11 @@ distclean-compile: ...@@ -446,7 +451,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_allocator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common.Plo@am__quote@ @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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_interceptors.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_interceptors.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_malloc_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_preinit.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_preinit.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_thread.Plo@am__quote@
......
...@@ -54,6 +54,9 @@ static void InitializeFlags() { ...@@ -54,6 +54,9 @@ static void InitializeFlags() {
RegisterLsanFlags(&parser, f); RegisterLsanFlags(&parser, f);
RegisterCommonFlags(&parser); RegisterCommonFlags(&parser);
// Override from user-specified string.
const char *lsan_default_options = MaybeCallLsanDefaultOptions();
parser.ParseString(lsan_default_options);
parser.ParseString(GetEnv("LSAN_OPTIONS")); parser.ParseString(GetEnv("LSAN_OPTIONS"));
SetVerbosity(common_flags()->verbosity); SetVerbosity(common_flags()->verbosity);
...@@ -63,6 +66,18 @@ static void InitializeFlags() { ...@@ -63,6 +66,18 @@ static void InitializeFlags() {
if (common_flags()->help) parser.PrintFlagDescriptions(); if (common_flags()->help) parser.PrintFlagDescriptions();
} }
static void OnStackUnwind(const SignalContext &sig, const void *,
BufferedStackTrace *stack) {
GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp,
sig.context,
common_flags()->fast_unwind_on_fatal);
}
void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
nullptr);
}
extern "C" void __lsan_init() { extern "C" void __lsan_init() {
CHECK(!lsan_init_is_running); CHECK(!lsan_init_is_running);
if (lsan_inited) if (lsan_inited)
...@@ -74,9 +89,11 @@ extern "C" void __lsan_init() { ...@@ -74,9 +89,11 @@ extern "C" void __lsan_init() {
InitializeFlags(); InitializeFlags();
InitCommonLsan(); InitCommonLsan();
InitializeAllocator(); InitializeAllocator();
ReplaceSystemMalloc();
InitTlsSize(); InitTlsSize();
InitializeInterceptors(); InitializeInterceptors();
InitializeThreadRegistry(); InitializeThreadRegistry();
InstallDeadlySignalHandlers(LsanOnDeadlySignal);
u32 tid = ThreadCreate(0, 0, true); u32 tid = ThreadCreate(0, 0, true);
CHECK_EQ(tid, 0); CHECK_EQ(tid, 0);
ThreadStart(tid, GetTid()); ThreadStart(tid, GetTid());
......
...@@ -10,24 +10,15 @@ ...@@ -10,24 +10,15 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "lsan_thread.h"
#include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_stacktrace.h"
#define GET_STACK_TRACE(max_size, fast) \ #define GET_STACK_TRACE(max_size, fast) \
BufferedStackTrace stack; \ __sanitizer::BufferedStackTrace stack; \
{ \ GetStackTraceWithPcBpAndContext(&stack, max_size, \
uptr stack_top = 0, stack_bottom = 0; \ StackTrace::GetCurrentPc(), \
ThreadContext *t; \ GET_CURRENT_FRAME(), nullptr, fast);
if (fast && (t = CurrentThreadContext())) { \
stack_top = t->stack_end(); \
stack_bottom = t->stack_begin(); \
} \
if (!SANITIZER_MIPS || \
IsValidFrame(GET_CURRENT_FRAME(), stack_top, stack_bottom)) { \
stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
/* context */ 0, stack_top, stack_bottom, fast); \
} \
}
#define GET_STACK_TRACE_FATAL \ #define GET_STACK_TRACE_FATAL \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
...@@ -36,9 +27,37 @@ ...@@ -36,9 +27,37 @@
GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
common_flags()->fast_unwind_on_malloc) common_flags()->fast_unwind_on_malloc)
#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true)
namespace __lsan { namespace __lsan {
void InitializeInterceptors(); void InitializeInterceptors();
void ReplaceSystemMalloc();
#define ENSURE_LSAN_INITED do { \
CHECK(!lsan_init_is_running); \
if (!lsan_inited) \
__lsan_init(); \
} while (0)
// Get the stack trace with the given pc and bp.
// The pc will be in the position 0 of the resulting stack trace.
// The bp may refer to the current frame or to the caller's frame.
ALWAYS_INLINE
void GetStackTraceWithPcBpAndContext(__sanitizer::BufferedStackTrace *stack,
__sanitizer::uptr max_depth,
__sanitizer::uptr pc, __sanitizer::uptr bp,
void *context, bool fast) {
uptr stack_top = 0, stack_bottom = 0;
ThreadContext *t;
if (fast && (t = CurrentThreadContext())) {
stack_top = t->stack_end();
stack_bottom = t->stack_begin();
}
if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) {
stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
}
}
} // namespace __lsan } // namespace __lsan
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
#include "lsan_allocator.h" #include "lsan_allocator.h"
#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_stacktrace.h"
...@@ -22,51 +24,27 @@ ...@@ -22,51 +24,27 @@
extern "C" void *memset(void *ptr, int value, uptr num); extern "C" void *memset(void *ptr, int value, uptr num);
namespace __lsan { namespace __lsan {
#if defined(__i386__) || defined(__arm__)
struct ChunkMetadata { static const uptr kMaxAllowedMallocSize = 1UL << 30;
u8 allocated : 8; // Must be first. #elif defined(__mips64) || defined(__aarch64__)
ChunkTag tag : 2;
uptr requested_size : 54;
u32 stack_trace_id;
};
#if defined(__mips64) || defined(__aarch64__)
static const uptr kMaxAllowedMallocSize = 4UL << 30; static const uptr kMaxAllowedMallocSize = 4UL << 30;
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
typedef CompactSizeClassMap SizeClassMap;
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
PrimaryAllocator;
#else #else
static const uptr kMaxAllowedMallocSize = 8UL << 30; static const uptr kMaxAllowedMallocSize = 8UL << 30;
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = 0x600000000000ULL;
static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
static const uptr kMetadataSize = sizeof(ChunkMetadata);
typedef DefaultSizeClassMap SizeClassMap;
typedef NoOpMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
#endif #endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<> SecondaryAllocator; typedef LargeMmapAllocator<> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
SecondaryAllocator> Allocator; SecondaryAllocator> Allocator;
static Allocator allocator; static Allocator allocator;
static THREADLOCAL AllocatorCache cache;
void InitializeAllocator() { void InitializeAllocator() {
allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null); SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
allocator.InitLinkerInitialized(
common_flags()->allocator_release_to_os_interval_ms);
} }
void AllocatorThreadFinish() { void AllocatorThreadFinish() {
allocator.SwallowCache(&cache); allocator.SwallowCache(GetAllocatorCache());
} }
static ChunkMetadata *Metadata(const void *p) { static ChunkMetadata *Metadata(const void *p) {
...@@ -96,9 +74,9 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, ...@@ -96,9 +74,9 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
size = 1; size = 1;
if (size > kMaxAllowedMallocSize) { if (size > kMaxAllowedMallocSize) {
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
return nullptr; return Allocator::FailureHandler::OnBadRequest();
} }
void *p = allocator.Allocate(&cache, size, alignment, false); void *p = allocator.Allocate(GetAllocatorCache(), size, alignment);
// Do not rely on the allocator to clear the memory (it's slow). // Do not rely on the allocator to clear the memory (it's slow).
if (cleared && allocator.FromPrimary(p)) if (cleared && allocator.FromPrimary(p))
memset(p, 0, size); memset(p, 0, size);
...@@ -108,11 +86,18 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, ...@@ -108,11 +86,18 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
return p; return p;
} }
static void *Calloc(uptr nmemb, uptr size, const StackTrace &stack) {
if (UNLIKELY(CheckForCallocOverflow(size, nmemb)))
return Allocator::FailureHandler::OnBadRequest();
size *= nmemb;
return Allocate(stack, size, 1, true);
}
void Deallocate(void *p) { void Deallocate(void *p) {
if (&__sanitizer_free_hook) __sanitizer_free_hook(p); if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
RunFreeHooks(p); RunFreeHooks(p);
RegisterDeallocation(p); RegisterDeallocation(p);
allocator.Deallocate(&cache, p); allocator.Deallocate(GetAllocatorCache(), p);
} }
void *Reallocate(const StackTrace &stack, void *p, uptr new_size, void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
...@@ -120,17 +105,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, ...@@ -120,17 +105,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
RegisterDeallocation(p); RegisterDeallocation(p);
if (new_size > kMaxAllowedMallocSize) { if (new_size > kMaxAllowedMallocSize) {
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
allocator.Deallocate(&cache, p); allocator.Deallocate(GetAllocatorCache(), p);
return nullptr; return Allocator::FailureHandler::OnBadRequest();
} }
p = allocator.Reallocate(&cache, p, new_size, alignment); p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
RegisterAllocation(stack, p, new_size); RegisterAllocation(stack, p, new_size);
return p; return p;
} }
void GetAllocatorCacheRange(uptr *begin, uptr *end) { void GetAllocatorCacheRange(uptr *begin, uptr *end) {
*begin = (uptr)&cache; *begin = (uptr)GetAllocatorCache();
*end = *begin + sizeof(cache); *end = *begin + sizeof(AllocatorCache);
} }
uptr GetMallocUsableSize(const void *p) { uptr GetMallocUsableSize(const void *p) {
...@@ -139,6 +124,39 @@ uptr GetMallocUsableSize(const void *p) { ...@@ -139,6 +124,39 @@ uptr GetMallocUsableSize(const void *p) {
return m->requested_size; return m->requested_size;
} }
void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) {
if (UNLIKELY(!IsPowerOfTwo(alignment))) {
errno = errno_EINVAL;
return Allocator::FailureHandler::OnBadRequest();
}
return SetErrnoOnNull(Allocate(stack, size, alignment, kAlwaysClearMemory));
}
void *lsan_malloc(uptr size, const StackTrace &stack) {
return SetErrnoOnNull(Allocate(stack, size, 1, kAlwaysClearMemory));
}
void lsan_free(void *p) {
Deallocate(p);
}
void *lsan_realloc(void *p, uptr size, const StackTrace &stack) {
return SetErrnoOnNull(Reallocate(stack, p, size, 1));
}
void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) {
return SetErrnoOnNull(Calloc(nmemb, size, stack));
}
void *lsan_valloc(uptr size, const StackTrace &stack) {
return SetErrnoOnNull(
Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory));
}
uptr lsan_mz_size(const void *p) {
return GetMallocUsableSize(p);
}
///// Interface to the common LSan module. ///// ///// Interface to the common LSan module. /////
void LockAllocator() { void LockAllocator() {
...@@ -254,4 +272,17 @@ SANITIZER_INTERFACE_ATTRIBUTE ...@@ -254,4 +272,17 @@ SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_allocated_size(const void *p) { uptr __sanitizer_get_allocated_size(const void *p) {
return GetMallocUsableSize(p); return GetMallocUsableSize(p);
} }
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default (no-op) implementation of malloc hooks.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
#endif
} // extern "C" } // extern "C"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment