mirror of git://gcc.gnu.org/git/gcc.git
parent
f07f30cfb5
commit
de5a5fa139
|
|
@ -1,3 +1,7 @@
|
||||||
|
2013-08-30 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
* bootstrap-ubsan.mk: New.
|
||||||
|
|
||||||
2013-03-27 Kai Tietz <ktietz@redhat.com>
|
2013-03-27 Kai Tietz <ktietz@redhat.com>
|
||||||
|
|
||||||
* dfp.m4: Add support for cygwin x64 target.
|
* dfp.m4: Add support for cygwin x64 target.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This option enables -fsanitize=undefined for stage2 and stage3.
|
||||||
|
|
||||||
|
STAGE2_CFLAGS += -fsanitize=undefined
|
||||||
|
STAGE3_CFLAGS += -fsanitize=undefined
|
||||||
|
POSTSTAGE1_LDFLAGS += -fsanitize=undefined -static-libubsan -lpthread \
|
||||||
|
-B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/ubsan/ \
|
||||||
|
-B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/ubsan/.libs
|
||||||
|
|
@ -1,3 +1,79 @@
|
||||||
|
2013-08-30 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
* Makefile.in (ubsan.o): Add.
|
||||||
|
(c-family/c-ubsan.o): Add.
|
||||||
|
(builtins.o): Add ubsan.h dependency.
|
||||||
|
* ubsan.h: New file.
|
||||||
|
* ubsan.c: New file.
|
||||||
|
* common.opt: Add -fsanitize=undefined option.
|
||||||
|
(flag_sanitize): Add variable.
|
||||||
|
(fsanitize=): Add option. Add Driver.
|
||||||
|
(fsanitize=thread): Remove option.
|
||||||
|
(fsanitize=address): Likewise.
|
||||||
|
(static-libubsan): New option.
|
||||||
|
* doc/invoke.texi: Document the new flag and -static-libubsan.
|
||||||
|
* sanitizer.def (DEF_SANITIZER_BUILTIN): Define.
|
||||||
|
(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE): Define.
|
||||||
|
* builtin-attrs.def (ATTR_COLD): Define.
|
||||||
|
(ATTR_COLD_NOTHROW_LEAF_LIST): Define.
|
||||||
|
* builtins.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW,
|
||||||
|
BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Define.
|
||||||
|
* flag-types.h (sanitize_code): New enum.
|
||||||
|
* opts.c (common_handle_option): Parse command line arguments
|
||||||
|
of -fsanitize=. Add -fsanitize=unreachable option.
|
||||||
|
* varasm.c (get_variable_section): Adjust.
|
||||||
|
(assemble_noswitch_variable): Likewise.
|
||||||
|
(assemble_variable): Likewise.
|
||||||
|
(output_constant_def_contents): Likewise.
|
||||||
|
(categorize_decl_for_section): Likewise.
|
||||||
|
(place_block_symbol): Likewise.
|
||||||
|
(output_object_block): Likewise.
|
||||||
|
* builtins.def: Likewise.
|
||||||
|
* toplev.c (compile_file): Likewise.
|
||||||
|
(process_options): Likewise.
|
||||||
|
* cppbuiltin.c: Likewise.
|
||||||
|
* tsan.c (tsan_pass): Likewise.
|
||||||
|
(tsan_gate): Likewise.
|
||||||
|
(tsan_gate_O0): Likewise.
|
||||||
|
* cfgexpand.c (partition_stack_vars): Likewise.
|
||||||
|
(expand_stack_vars): Likewise.
|
||||||
|
(defer_stack_allocation): Likewise.
|
||||||
|
(expand_used_vars): Likewise.
|
||||||
|
* cfgcleanup.c (old_insns_match_p): Likewise.
|
||||||
|
* asan.c (asan_finish_file): Likewise.
|
||||||
|
(asan_instrument): Likewise.
|
||||||
|
(gate_asan): Likewise.
|
||||||
|
(initialize_sanitizer_builtins): Build BT_FN_VOID_PTR_PTR_PTR.
|
||||||
|
(ATTR_COLD_NOTHROW_LEAF_LIST): Define.
|
||||||
|
(asan_global_struct): Use pointer_sized_int_node instead
|
||||||
|
calling build_nonstandard_integer_type.
|
||||||
|
(initialize_sanitizer_builtins): Likewise.
|
||||||
|
(asan_finish_file): Likewise.
|
||||||
|
* gcc.c: Document %{%:function(args):X}.
|
||||||
|
(static_spec_functions): Add sanitize.
|
||||||
|
(handle_spec_function): Add retval_nonnull argument and if non-NULL,
|
||||||
|
store funcval != NULL there.
|
||||||
|
(do_spec_1): Adjust handle_spec_function caller.
|
||||||
|
(handle_braces): Allow %:function(args) as condition.
|
||||||
|
(sanitize_spec_function): New function.
|
||||||
|
(ADD_STATIC_LIBUBSAN_LIBS): Define.
|
||||||
|
(LIBUBSAN_SPEC): Likewise.
|
||||||
|
(LIBUBSAN_EARLY_SPEC): Likewise.
|
||||||
|
(SANITIZER_SPEC): Handle libubsan.
|
||||||
|
(SANITIZER_EARLY_SPEC): Likewise.
|
||||||
|
* config/darwin.h (LINK_COMMAND_SPEC_A): Use %:sanitize(address)
|
||||||
|
instead of fsanitize=address.
|
||||||
|
* config/arm/linux-eabi.h (ASAN_CC1_SPEC): Use %:sanitize(address)
|
||||||
|
instead of fsanitize=address*.
|
||||||
|
* builtins.c: Include ubsan.h.
|
||||||
|
(fold_builtin_0): Instrument __builtin_unreachable.
|
||||||
|
* config/rs6000/rs6000.h (FRAME_GROWS_DOWNWARD): Use flag_sanitize
|
||||||
|
instead of flag_asan.
|
||||||
|
* tree.h (enum tree_index): Add TI_POINTER_SIZED_TYPE.
|
||||||
|
(pointer_sized_int_node): Define.
|
||||||
|
* tree.c (build_common_tree_nodes): Initialize
|
||||||
|
pointer_sized_int_node.
|
||||||
|
|
||||||
2013-08-30 Mike Stump <mikestump@comcast.net>
|
2013-08-30 Mike Stump <mikestump@comcast.net>
|
||||||
|
|
||||||
* doc/install.texi (Prerequisites): Note regression in Tcl 8.6
|
* doc/install.texi (Prerequisites): Note regression in Tcl 8.6
|
||||||
|
|
|
||||||
|
|
@ -1154,7 +1154,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
|
||||||
c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
|
c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
|
||||||
c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \
|
c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \
|
||||||
c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o \
|
c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o \
|
||||||
c-family/array-notation-common.o
|
c-family/array-notation-common.o c-family/c-ubsan.o
|
||||||
|
|
||||||
# Language-independent object files.
|
# Language-independent object files.
|
||||||
# We put the insn-*.o files first so that a parallel make will build
|
# We put the insn-*.o files first so that a parallel make will build
|
||||||
|
|
@ -1383,6 +1383,7 @@ OBJS = \
|
||||||
tree-affine.o \
|
tree-affine.o \
|
||||||
asan.o \
|
asan.o \
|
||||||
tsan.o \
|
tsan.o \
|
||||||
|
ubsan.o \
|
||||||
tree-call-cdce.o \
|
tree-call-cdce.o \
|
||||||
tree-cfg.o \
|
tree-cfg.o \
|
||||||
tree-cfgcleanup.o \
|
tree-cfgcleanup.o \
|
||||||
|
|
@ -2028,6 +2029,10 @@ c-family/array-notation-common.o : c-family/array-notation-common.c $(TREE_H) \
|
||||||
c-family/stub-objc.o : c-family/stub-objc.c $(CONFIG_H) $(SYSTEM_H) \
|
c-family/stub-objc.o : c-family/stub-objc.c $(CONFIG_H) $(SYSTEM_H) \
|
||||||
coretypes.h $(TREE_H) $(C_COMMON_H) c-family/c-objc.h
|
coretypes.h $(TREE_H) $(C_COMMON_H) c-family/c-objc.h
|
||||||
|
|
||||||
|
c-family/c-ubsan.o : c-family/c-ubsan.c $(CONFIG_H) $(SYSTEM_H) \
|
||||||
|
coretypes.h $(TREE_H) $(C_COMMON_H) c-family/c-ubsan.h \
|
||||||
|
alloc-pool.h $(CGRAPH_H) $(GIMPLE_H) $(HASH_TABLE_H) output.h \
|
||||||
|
toplev.h ubsan.h
|
||||||
default-c.o: config/default-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
default-c.o: config/default-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||||
$(C_TARGET_H) $(C_TARGET_DEF_H)
|
$(C_TARGET_H) $(C_TARGET_DEF_H)
|
||||||
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \
|
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \
|
||||||
|
|
@ -2265,8 +2270,11 @@ tsan.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
|
||||||
$(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(CGRAPH_H) $(GGC_H) \
|
$(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(CGRAPH_H) $(GGC_H) \
|
||||||
$(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) \
|
$(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) \
|
||||||
$(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) tree-iterator.h \
|
$(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) tree-iterator.h \
|
||||||
intl.h cfghooks.h output.h options.h c-family/c-common.h tsan.h asan.h \
|
intl.h cfghooks.h output.h options.h $(C_COMMON_H) tsan.h asan.h \
|
||||||
tree-ssa-propagate.h
|
tree-ssa-propagate.h
|
||||||
|
ubsan.o : ubsan.c ubsan.h $(CONFIG_H) $(SYSTEM_H) $(GIMPLE_H) \
|
||||||
|
output.h coretypes.h $(TREE_H) $(CGRAPH_H) $(HASHTAB_H) gt-ubsan.h \
|
||||||
|
toplev.h $(C_COMMON_H)
|
||||||
tree-ssa-tail-merge.o: tree-ssa-tail-merge.c \
|
tree-ssa-tail-merge.o: tree-ssa-tail-merge.c \
|
||||||
$(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_H) \
|
$(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_H) \
|
||||||
$(FLAGS_H) $(TM_P_H) $(BASIC_BLOCK_H) $(CFGLOOP_H) \
|
$(FLAGS_H) $(TM_P_H) $(BASIC_BLOCK_H) $(CFGLOOP_H) \
|
||||||
|
|
@ -2836,7 +2844,7 @@ builtins.o : builtins.c builtins.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||||
hard-reg-set.h $(DIAGNOSTIC_CORE_H) hard-reg-set.h $(EXCEPT_H) \
|
hard-reg-set.h $(DIAGNOSTIC_CORE_H) hard-reg-set.h $(EXCEPT_H) \
|
||||||
$(TM_P_H) $(PREDICT_H) $(LIBFUNCS_H) langhooks.h $(BASIC_BLOCK_H) \
|
$(TM_P_H) $(PREDICT_H) $(LIBFUNCS_H) langhooks.h $(BASIC_BLOCK_H) \
|
||||||
tree-mudflap.h realmpfr.h $(BUILTINS_DEF) $(MACHMODE_H) \
|
tree-mudflap.h realmpfr.h $(BUILTINS_DEF) $(MACHMODE_H) \
|
||||||
$(DIAGNOSTIC_CORE_H) $(TREE_FLOW_H) value-prof.h
|
$(DIAGNOSTIC_CORE_H) $(TREE_FLOW_H) value-prof.h ubsan.h
|
||||||
calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||||
$(TREE_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \
|
$(TREE_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \
|
||||||
$(LIBFUNCS_H) $(REGS_H) $(DIAGNOSTIC_CORE_H) output.h \
|
$(LIBFUNCS_H) $(REGS_H) $(DIAGNOSTIC_CORE_H) output.h \
|
||||||
|
|
@ -3830,6 +3838,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
|
||||||
$(srcdir)/ipa-inline.h \
|
$(srcdir)/ipa-inline.h \
|
||||||
$(srcdir)/vtable-verify.c \
|
$(srcdir)/vtable-verify.c \
|
||||||
$(srcdir)/asan.c \
|
$(srcdir)/asan.c \
|
||||||
|
$(srcdir)/ubsan.c \
|
||||||
$(srcdir)/tsan.c $(srcdir)/ipa-devirt.c \
|
$(srcdir)/tsan.c $(srcdir)/ipa-devirt.c \
|
||||||
@all_gtfiles@
|
@all_gtfiles@
|
||||||
|
|
||||||
|
|
|
||||||
26
gcc/asan.c
26
gcc/asan.c
|
|
@ -1938,7 +1938,7 @@ asan_global_struct (void)
|
||||||
= build_decl (UNKNOWN_LOCATION, FIELD_DECL,
|
= build_decl (UNKNOWN_LOCATION, FIELD_DECL,
|
||||||
get_identifier (field_names[i]),
|
get_identifier (field_names[i]),
|
||||||
(i == 0 || i == 3) ? const_ptr_type_node
|
(i == 0 || i == 3) ? const_ptr_type_node
|
||||||
: build_nonstandard_integer_type (POINTER_SIZE, 1));
|
: pointer_sized_int_node);
|
||||||
DECL_CONTEXT (fields[i]) = ret;
|
DECL_CONTEXT (fields[i]) = ret;
|
||||||
if (i)
|
if (i)
|
||||||
DECL_CHAIN (fields[i - 1]) = fields[i];
|
DECL_CHAIN (fields[i - 1]) = fields[i];
|
||||||
|
|
@ -2016,10 +2016,12 @@ initialize_sanitizer_builtins (void)
|
||||||
tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
|
tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
|
||||||
tree BT_FN_VOID_PTR
|
tree BT_FN_VOID_PTR
|
||||||
= build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
|
= build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
|
||||||
|
tree BT_FN_VOID_PTR_PTR_PTR
|
||||||
|
= build_function_type_list (void_type_node, ptr_type_node,
|
||||||
|
ptr_type_node, ptr_type_node, NULL_TREE);
|
||||||
tree BT_FN_VOID_PTR_PTRMODE
|
tree BT_FN_VOID_PTR_PTRMODE
|
||||||
= build_function_type_list (void_type_node, ptr_type_node,
|
= build_function_type_list (void_type_node, ptr_type_node,
|
||||||
build_nonstandard_integer_type (POINTER_SIZE,
|
pointer_sized_int_node, NULL_TREE);
|
||||||
1), NULL_TREE);
|
|
||||||
tree BT_FN_VOID_INT
|
tree BT_FN_VOID_INT
|
||||||
= build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
|
= build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
|
||||||
tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
|
tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
|
||||||
|
|
@ -2081,6 +2083,12 @@ initialize_sanitizer_builtins (void)
|
||||||
#undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
|
#undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
|
||||||
#define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
|
#define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
|
||||||
ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
|
ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
|
||||||
|
#undef ATTR_COLD_NOTHROW_LEAF_LIST
|
||||||
|
#define ATTR_COLD_NOTHROW_LEAF_LIST \
|
||||||
|
/* ECF_COLD missing */ ATTR_NOTHROW_LEAF_LIST
|
||||||
|
#undef ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST
|
||||||
|
#define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
|
||||||
|
/* ECF_COLD missing */ ATTR_NORETURN_NOTHROW_LEAF_LIST
|
||||||
#undef DEF_SANITIZER_BUILTIN
|
#undef DEF_SANITIZER_BUILTIN
|
||||||
#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
|
#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
|
||||||
decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \
|
decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \
|
||||||
|
|
@ -2157,7 +2165,7 @@ asan_finish_file (void)
|
||||||
/* Avoid instrumenting code in the asan ctors/dtors.
|
/* Avoid instrumenting code in the asan ctors/dtors.
|
||||||
We don't need to insert padding after the description strings,
|
We don't need to insert padding after the description strings,
|
||||||
nor after .LASAN* array. */
|
nor after .LASAN* array. */
|
||||||
flag_asan = 0;
|
flag_sanitize &= ~SANITIZE_ADDRESS;
|
||||||
|
|
||||||
tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
|
tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
|
||||||
append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
|
append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
|
||||||
|
|
@ -2170,7 +2178,6 @@ asan_finish_file (void)
|
||||||
if (gcount)
|
if (gcount)
|
||||||
{
|
{
|
||||||
tree type = asan_global_struct (), var, ctor;
|
tree type = asan_global_struct (), var, ctor;
|
||||||
tree uptr = build_nonstandard_integer_type (POINTER_SIZE, 1);
|
|
||||||
tree dtor_statements = NULL_TREE;
|
tree dtor_statements = NULL_TREE;
|
||||||
vec<constructor_elt, va_gc> *v;
|
vec<constructor_elt, va_gc> *v;
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
|
@ -2199,22 +2206,23 @@ asan_finish_file (void)
|
||||||
varpool_assemble_decl (varpool_node_for_decl (var));
|
varpool_assemble_decl (varpool_node_for_decl (var));
|
||||||
|
|
||||||
fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
|
fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
|
||||||
|
tree gcount_tree = build_int_cst (pointer_sized_int_node, gcount);
|
||||||
append_to_statement_list (build_call_expr (fn, 2,
|
append_to_statement_list (build_call_expr (fn, 2,
|
||||||
build_fold_addr_expr (var),
|
build_fold_addr_expr (var),
|
||||||
build_int_cst (uptr, gcount)),
|
gcount_tree),
|
||||||
&asan_ctor_statements);
|
&asan_ctor_statements);
|
||||||
|
|
||||||
fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS);
|
fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS);
|
||||||
append_to_statement_list (build_call_expr (fn, 2,
|
append_to_statement_list (build_call_expr (fn, 2,
|
||||||
build_fold_addr_expr (var),
|
build_fold_addr_expr (var),
|
||||||
build_int_cst (uptr, gcount)),
|
gcount_tree),
|
||||||
&dtor_statements);
|
&dtor_statements);
|
||||||
cgraph_build_static_cdtor ('D', dtor_statements,
|
cgraph_build_static_cdtor ('D', dtor_statements,
|
||||||
MAX_RESERVED_INIT_PRIORITY - 1);
|
MAX_RESERVED_INIT_PRIORITY - 1);
|
||||||
}
|
}
|
||||||
cgraph_build_static_cdtor ('I', asan_ctor_statements,
|
cgraph_build_static_cdtor ('I', asan_ctor_statements,
|
||||||
MAX_RESERVED_INIT_PRIORITY - 1);
|
MAX_RESERVED_INIT_PRIORITY - 1);
|
||||||
flag_asan = 1;
|
flag_sanitize |= SANITIZE_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Instrument the current function. */
|
/* Instrument the current function. */
|
||||||
|
|
@ -2231,7 +2239,7 @@ asan_instrument (void)
|
||||||
static bool
|
static bool
|
||||||
gate_asan (void)
|
gate_asan (void)
|
||||||
{
|
{
|
||||||
return flag_asan != 0
|
return (flag_sanitize & SANITIZE_ADDRESS) != 0
|
||||||
&& !lookup_attribute ("no_sanitize_address",
|
&& !lookup_attribute ("no_sanitize_address",
|
||||||
DECL_ATTRIBUTES (current_function_decl));
|
DECL_ATTRIBUTES (current_function_decl));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ DEF_LIST_INT_INT (5,6)
|
||||||
#undef DEF_LIST_INT_INT
|
#undef DEF_LIST_INT_INT
|
||||||
|
|
||||||
/* Construct trees for identifiers. */
|
/* Construct trees for identifiers. */
|
||||||
|
DEF_ATTR_IDENT (ATTR_COLD, "cold")
|
||||||
DEF_ATTR_IDENT (ATTR_CONST, "const")
|
DEF_ATTR_IDENT (ATTR_CONST, "const")
|
||||||
DEF_ATTR_IDENT (ATTR_FORMAT, "format")
|
DEF_ATTR_IDENT (ATTR_FORMAT, "format")
|
||||||
DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
|
DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
|
||||||
|
|
@ -130,6 +131,10 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LIST, ATTR_NORETURN, \
|
||||||
ATTR_NULL, ATTR_NOTHROW_LIST)
|
ATTR_NULL, ATTR_NOTHROW_LIST)
|
||||||
DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LEAF_LIST, ATTR_NORETURN,\
|
DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LEAF_LIST, ATTR_NORETURN,\
|
||||||
ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
|
ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
|
||||||
|
DEF_ATTR_TREE_LIST (ATTR_COLD_NOTHROW_LEAF_LIST, ATTR_COLD,\
|
||||||
|
ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
|
||||||
|
DEF_ATTR_TREE_LIST (ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST, ATTR_COLD,\
|
||||||
|
ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
|
||||||
DEF_ATTR_TREE_LIST (ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST, ATTR_CONST,\
|
DEF_ATTR_TREE_LIST (ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST, ATTR_CONST,\
|
||||||
ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
|
ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
|
||||||
DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \
|
DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "value-prof.h"
|
#include "value-prof.h"
|
||||||
#include "diagnostic-core.h"
|
#include "diagnostic-core.h"
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
|
#include "ubsan.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef PAD_VARARGS_DOWN
|
#ifndef PAD_VARARGS_DOWN
|
||||||
|
|
@ -10303,6 +10304,11 @@ fold_builtin_0 (location_t loc, tree fndecl, bool ignore ATTRIBUTE_UNUSED)
|
||||||
case BUILT_IN_CLASSIFY_TYPE:
|
case BUILT_IN_CLASSIFY_TYPE:
|
||||||
return fold_builtin_classify_type (NULL_TREE);
|
return fold_builtin_classify_type (NULL_TREE);
|
||||||
|
|
||||||
|
case BUILT_IN_UNREACHABLE:
|
||||||
|
if (flag_sanitize & SANITIZE_UNREACHABLE)
|
||||||
|
return ubsan_instrument_unreachable (loc);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
|
#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
|
||||||
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
|
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
|
||||||
true, true, true, ATTRS, true, \
|
true, true, true, ATTRS, true, \
|
||||||
(flag_asan || flag_tsan))
|
(flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
|
||||||
|
| SANITIZE_UNDEFINED)))
|
||||||
|
|
||||||
#undef DEF_CILKPLUS_BUILTIN
|
#undef DEF_CILKPLUS_BUILTIN
|
||||||
#define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
|
#define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
2013-08-30 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
* c-ubsan.c: New file.
|
||||||
|
* c-ubsan.h: New file.
|
||||||
|
|
||||||
2013-08-30 Gabriel Dos Reis <gdr@integrable-solutions.net>
|
2013-08-30 Gabriel Dos Reis <gdr@integrable-solutions.net>
|
||||||
|
|
||||||
* c-pretty-print.h (c_pretty_printer::declaration): Now a virtual
|
* c-pretty-print.h (c_pretty_printer::declaration): Now a virtual
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
/* UndefinedBehaviorSanitizer, undefined behavior detector.
|
||||||
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
Contributed by Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GCC; see the file COPYING3. If not see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "coretypes.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "alloc-pool.h"
|
||||||
|
#include "cgraph.h"
|
||||||
|
#include "gimple.h"
|
||||||
|
#include "hash-table.h"
|
||||||
|
#include "output.h"
|
||||||
|
#include "toplev.h"
|
||||||
|
#include "ubsan.h"
|
||||||
|
#include "c-family/c-common.h"
|
||||||
|
#include "c-family/c-ubsan.h"
|
||||||
|
|
||||||
|
/* Instrument division by zero and INT_MIN / -1. If not instrumenting,
|
||||||
|
return NULL_TREE. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
ubsan_instrument_division (location_t loc, tree op0, tree op1)
|
||||||
|
{
|
||||||
|
tree t, tt;
|
||||||
|
tree type = TREE_TYPE (op0);
|
||||||
|
|
||||||
|
/* At this point both operands should have the same type,
|
||||||
|
because they are already converted to RESULT_TYPE.
|
||||||
|
Use TYPE_MAIN_VARIANT since typedefs can confuse us. */
|
||||||
|
gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
|
||||||
|
== TYPE_MAIN_VARIANT (TREE_TYPE (op1)));
|
||||||
|
|
||||||
|
/* TODO: REAL_TYPE is not supported yet. */
|
||||||
|
if (TREE_CODE (type) != INTEGER_TYPE)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
/* If we *know* that the divisor is not -1 or 0, we don't have to
|
||||||
|
instrument this expression.
|
||||||
|
??? We could use decl_constant_value to cover up more cases. */
|
||||||
|
if (TREE_CODE (op1) == INTEGER_CST
|
||||||
|
&& integer_nonzerop (op1)
|
||||||
|
&& !integer_minus_onep (op1))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
t = fold_build2 (EQ_EXPR, boolean_type_node,
|
||||||
|
op1, build_int_cst (type, 0));
|
||||||
|
|
||||||
|
/* We check INT_MIN / -1 only for signed types. */
|
||||||
|
if (!TYPE_UNSIGNED (type))
|
||||||
|
{
|
||||||
|
tree x;
|
||||||
|
tt = fold_build2 (EQ_EXPR, boolean_type_node, op1,
|
||||||
|
build_int_cst (type, -1));
|
||||||
|
x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
|
||||||
|
TYPE_MIN_VALUE (type));
|
||||||
|
x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
|
||||||
|
t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case we have a SAVE_EXPR in a conditional context, we need to
|
||||||
|
make sure it gets evaluated before the condition. */
|
||||||
|
t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t);
|
||||||
|
tree data = ubsan_create_data ("__ubsan_overflow_data",
|
||||||
|
loc, ubsan_type_descriptor (type),
|
||||||
|
NULL_TREE);
|
||||||
|
data = build_fold_addr_expr_loc (loc, data);
|
||||||
|
tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW);
|
||||||
|
tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
|
||||||
|
ubsan_encode_value (op1));
|
||||||
|
t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Instrument left and right shifts. If not instrumenting, return
|
||||||
|
NULL_TREE. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
ubsan_instrument_shift (location_t loc, enum tree_code code,
|
||||||
|
tree op0, tree op1)
|
||||||
|
{
|
||||||
|
tree t, tt = NULL_TREE;
|
||||||
|
tree type0 = TREE_TYPE (op0);
|
||||||
|
tree type1 = TREE_TYPE (op1);
|
||||||
|
tree op1_utype = unsigned_type_for (type1);
|
||||||
|
HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
|
||||||
|
tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
|
||||||
|
tree precm1 = build_int_cst (type1, op0_prec - 1);
|
||||||
|
|
||||||
|
t = fold_convert_loc (loc, op1_utype, op1);
|
||||||
|
t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);
|
||||||
|
|
||||||
|
/* For signed x << y, in C99/C11, the following:
|
||||||
|
(unsigned) x >> (precm1 - y)
|
||||||
|
if non-zero, is undefined. */
|
||||||
|
if (code == LSHIFT_EXPR
|
||||||
|
&& !TYPE_UNSIGNED (type0)
|
||||||
|
&& flag_isoc99)
|
||||||
|
{
|
||||||
|
tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1);
|
||||||
|
tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
|
||||||
|
tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
|
||||||
|
tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
|
||||||
|
build_int_cst (TREE_TYPE (tt), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For signed x << y, in C++11/C++14, the following:
|
||||||
|
x < 0 || ((unsigned) x >> (precm1 - y))
|
||||||
|
if > 1, is undefined. */
|
||||||
|
if (code == LSHIFT_EXPR
|
||||||
|
&& !TYPE_UNSIGNED (TREE_TYPE (op0))
|
||||||
|
&& (cxx_dialect == cxx11 || cxx_dialect == cxx1y))
|
||||||
|
{
|
||||||
|
tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1);
|
||||||
|
tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
|
||||||
|
tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
|
||||||
|
tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
|
||||||
|
build_int_cst (TREE_TYPE (tt), 1));
|
||||||
|
x = fold_build2 (LT_EXPR, boolean_type_node, op0,
|
||||||
|
build_int_cst (type0, 0));
|
||||||
|
tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case we have a SAVE_EXPR in a conditional context, we need to
|
||||||
|
make sure it gets evaluated before the condition. */
|
||||||
|
t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t);
|
||||||
|
tree data = ubsan_create_data ("__ubsan_shift_data",
|
||||||
|
loc, ubsan_type_descriptor (type0),
|
||||||
|
ubsan_type_descriptor (type1), NULL_TREE);
|
||||||
|
|
||||||
|
data = build_fold_addr_expr_loc (loc, data);
|
||||||
|
|
||||||
|
t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t,
|
||||||
|
tt ? tt : integer_zero_node);
|
||||||
|
tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS);
|
||||||
|
tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
|
||||||
|
ubsan_encode_value (op1));
|
||||||
|
t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* UndefinedBehaviorSanitizer, undefined behavior detector.
|
||||||
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
Contributed by Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GCC; see the file COPYING3. If not see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef GCC_C_UBSAN_H
|
||||||
|
#define GCC_C_UBSAN_H
|
||||||
|
|
||||||
|
extern tree ubsan_instrument_division (location_t, tree, tree);
|
||||||
|
extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree);
|
||||||
|
|
||||||
|
#endif /* GCC_C_UBSAN_H */
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
2013-08-30 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
* c-typeck.c (build_binary_op): Add division by zero and shift
|
||||||
|
instrumentation.
|
||||||
|
|
||||||
2013-08-26 Joern Rennecke <joern.rennecke@embecosm.com>
|
2013-08-26 Joern Rennecke <joern.rennecke@embecosm.com>
|
||||||
Joseph Myers <joseph@codesourcery.com>
|
Joseph Myers <joseph@codesourcery.com>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "gimple.h"
|
#include "gimple.h"
|
||||||
#include "c-family/c-objc.h"
|
#include "c-family/c-objc.h"
|
||||||
#include "c-family/c-common.h"
|
#include "c-family/c-common.h"
|
||||||
|
#include "c-family/c-ubsan.h"
|
||||||
|
|
||||||
/* Possible cases of implicit bad conversions. Used to select
|
/* Possible cases of implicit bad conversions. Used to select
|
||||||
diagnostic messages in convert_for_assignment. */
|
diagnostic messages in convert_for_assignment. */
|
||||||
|
|
@ -9541,6 +9542,15 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
operands to truth-values. */
|
operands to truth-values. */
|
||||||
bool boolean_op = false;
|
bool boolean_op = false;
|
||||||
|
|
||||||
|
/* Remember whether we're doing / or %. */
|
||||||
|
bool doing_div_or_mod = false;
|
||||||
|
|
||||||
|
/* Remember whether we're doing << or >>. */
|
||||||
|
bool doing_shift = false;
|
||||||
|
|
||||||
|
/* Tree holding instrumentation expression. */
|
||||||
|
tree instrument_expr = NULL;
|
||||||
|
|
||||||
if (location == UNKNOWN_LOCATION)
|
if (location == UNKNOWN_LOCATION)
|
||||||
location = input_location;
|
location = input_location;
|
||||||
|
|
||||||
|
|
@ -9742,6 +9752,7 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
case FLOOR_DIV_EXPR:
|
case FLOOR_DIV_EXPR:
|
||||||
case ROUND_DIV_EXPR:
|
case ROUND_DIV_EXPR:
|
||||||
case EXACT_DIV_EXPR:
|
case EXACT_DIV_EXPR:
|
||||||
|
doing_div_or_mod = true;
|
||||||
warn_for_div_by_zero (location, op1);
|
warn_for_div_by_zero (location, op1);
|
||||||
|
|
||||||
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|
||||||
|
|
@ -9789,6 +9800,7 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
|
|
||||||
case TRUNC_MOD_EXPR:
|
case TRUNC_MOD_EXPR:
|
||||||
case FLOOR_MOD_EXPR:
|
case FLOOR_MOD_EXPR:
|
||||||
|
doing_div_or_mod = true;
|
||||||
warn_for_div_by_zero (location, op1);
|
warn_for_div_by_zero (location, op1);
|
||||||
|
|
||||||
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
|
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
|
||||||
|
|
@ -9887,6 +9899,7 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
|
else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
|
||||||
&& code1 == INTEGER_TYPE)
|
&& code1 == INTEGER_TYPE)
|
||||||
{
|
{
|
||||||
|
doing_shift = true;
|
||||||
if (TREE_CODE (op1) == INTEGER_CST)
|
if (TREE_CODE (op1) == INTEGER_CST)
|
||||||
{
|
{
|
||||||
if (tree_int_cst_sgn (op1) < 0)
|
if (tree_int_cst_sgn (op1) < 0)
|
||||||
|
|
@ -9939,6 +9952,7 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
|
else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
|
||||||
&& code1 == INTEGER_TYPE)
|
&& code1 == INTEGER_TYPE)
|
||||||
{
|
{
|
||||||
|
doing_shift = true;
|
||||||
if (TREE_CODE (op1) == INTEGER_CST)
|
if (TREE_CODE (op1) == INTEGER_CST)
|
||||||
{
|
{
|
||||||
if (tree_int_cst_sgn (op1) < 0)
|
if (tree_int_cst_sgn (op1) < 0)
|
||||||
|
|
@ -10483,6 +10497,21 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flag_sanitize & SANITIZE_UNDEFINED
|
||||||
|
&& current_function_decl != 0
|
||||||
|
&& (doing_div_or_mod || doing_shift))
|
||||||
|
{
|
||||||
|
/* OP0 and/or OP1 might have side-effects. */
|
||||||
|
op0 = c_save_expr (op0);
|
||||||
|
op1 = c_save_expr (op1);
|
||||||
|
op0 = c_fully_fold (op0, false, NULL);
|
||||||
|
op1 = c_fully_fold (op1, false, NULL);
|
||||||
|
if (doing_div_or_mod)
|
||||||
|
instrument_expr = ubsan_instrument_division (location, op0, op1);
|
||||||
|
else if (doing_shift)
|
||||||
|
instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Treat expressions in initializers specially as they can't trap. */
|
/* Treat expressions in initializers specially as they can't trap. */
|
||||||
if (int_const_or_overflow)
|
if (int_const_or_overflow)
|
||||||
ret = (require_constant_value
|
ret = (require_constant_value
|
||||||
|
|
@ -10506,6 +10535,11 @@ build_binary_op (location_t location, enum tree_code code,
|
||||||
if (semantic_result_type)
|
if (semantic_result_type)
|
||||||
ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
|
ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
|
||||||
protected_set_expr_location (ret, location);
|
protected_set_expr_location (ret, location);
|
||||||
|
|
||||||
|
if ((flag_sanitize & SANITIZE_UNDEFINED) && instrument_expr != NULL)
|
||||||
|
ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret),
|
||||||
|
instrument_expr, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1137,7 +1137,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
|
||||||
|
|
||||||
/* For address sanitizer, never crossjump __asan_report_* builtins,
|
/* For address sanitizer, never crossjump __asan_report_* builtins,
|
||||||
otherwise errors might be reported on incorrect lines. */
|
otherwise errors might be reported on incorrect lines. */
|
||||||
if (flag_asan)
|
if (flag_sanitize & SANITIZE_ADDRESS)
|
||||||
{
|
{
|
||||||
rtx call = get_call_rtx_from (i1);
|
rtx call = get_call_rtx_from (i1);
|
||||||
if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
|
if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
|
||||||
|
|
|
||||||
|
|
@ -764,7 +764,7 @@ partition_stack_vars (void)
|
||||||
sizes, as the shorter vars wouldn't be adequately protected.
|
sizes, as the shorter vars wouldn't be adequately protected.
|
||||||
Don't do that for "large" (unsupported) alignment objects,
|
Don't do that for "large" (unsupported) alignment objects,
|
||||||
those aren't protected anyway. */
|
those aren't protected anyway. */
|
||||||
if (flag_asan && isize != jsize
|
if ((flag_sanitize & SANITIZE_ADDRESS) && isize != jsize
|
||||||
&& ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
|
&& ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -940,7 +940,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
|
||||||
alignb = stack_vars[i].alignb;
|
alignb = stack_vars[i].alignb;
|
||||||
if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
|
if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
|
||||||
{
|
{
|
||||||
if (flag_asan && pred)
|
if ((flag_sanitize & SANITIZE_ADDRESS) && pred)
|
||||||
{
|
{
|
||||||
HOST_WIDE_INT prev_offset = frame_offset;
|
HOST_WIDE_INT prev_offset = frame_offset;
|
||||||
tree repr_decl = NULL_TREE;
|
tree repr_decl = NULL_TREE;
|
||||||
|
|
@ -1110,7 +1110,7 @@ defer_stack_allocation (tree var, bool toplevel)
|
||||||
/* If stack protection is enabled, *all* stack variables must be deferred,
|
/* If stack protection is enabled, *all* stack variables must be deferred,
|
||||||
so that we can re-order the strings to the top of the frame.
|
so that we can re-order the strings to the top of the frame.
|
||||||
Similarly for Address Sanitizer. */
|
Similarly for Address Sanitizer. */
|
||||||
if (flag_stack_protect || flag_asan)
|
if (flag_stack_protect || (flag_sanitize & SANITIZE_ADDRESS))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* We handle "large" alignment via dynamic allocation. We want to handle
|
/* We handle "large" alignment via dynamic allocation. We want to handle
|
||||||
|
|
@ -1753,7 +1753,7 @@ expand_used_vars (void)
|
||||||
expand_stack_vars (stack_protect_decl_phase_2, &data);
|
expand_stack_vars (stack_protect_decl_phase_2, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_asan)
|
if (flag_sanitize & SANITIZE_ADDRESS)
|
||||||
/* Phase 3, any partitions that need asan protection
|
/* Phase 3, any partitions that need asan protection
|
||||||
in addition to phase 1 and 2. */
|
in addition to phase 1 and 2. */
|
||||||
expand_stack_vars (asan_decl_phase_3, &data);
|
expand_stack_vars (asan_decl_phase_3, &data);
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,10 @@ unsigned int help_columns
|
||||||
Variable
|
Variable
|
||||||
bool flag_opts_finished
|
bool flag_opts_finished
|
||||||
|
|
||||||
|
; What the sanitizer should instrument
|
||||||
|
Variable
|
||||||
|
unsigned int flag_sanitize
|
||||||
|
|
||||||
###
|
###
|
||||||
Driver
|
Driver
|
||||||
|
|
||||||
|
|
@ -850,13 +854,9 @@ fargument-noalias-anything
|
||||||
Common Ignore
|
Common Ignore
|
||||||
Does nothing. Preserved for backward compatibility.
|
Does nothing. Preserved for backward compatibility.
|
||||||
|
|
||||||
fsanitize=address
|
fsanitize=
|
||||||
Common Report Var(flag_asan)
|
Common Driver Report Joined
|
||||||
Enable AddressSanitizer, a memory error detector
|
Select what to sanitize
|
||||||
|
|
||||||
fsanitize=thread
|
|
||||||
Common Report Var(flag_tsan)
|
|
||||||
Enable ThreadSanitizer, a data race detector
|
|
||||||
|
|
||||||
fasynchronous-unwind-tables
|
fasynchronous-unwind-tables
|
||||||
Common Report Var(flag_asynchronous_unwind_tables) Optimization
|
Common Report Var(flag_asynchronous_unwind_tables) Optimization
|
||||||
|
|
@ -2604,6 +2604,9 @@ Driver
|
||||||
static-libtsan
|
static-libtsan
|
||||||
Driver
|
Driver
|
||||||
|
|
||||||
|
static-libubsan
|
||||||
|
Driver
|
||||||
|
|
||||||
symbolic
|
symbolic
|
||||||
Driver
|
Driver
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC)
|
LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC)
|
||||||
|
|
||||||
#undef ASAN_CC1_SPEC
|
#undef ASAN_CC1_SPEC
|
||||||
#define ASAN_CC1_SPEC "%{fsanitize=*:-funwind-tables}"
|
#define ASAN_CC1_SPEC "%{%:sanitize(address):-funwind-tables}"
|
||||||
|
|
||||||
#undef CC1_SPEC
|
#undef CC1_SPEC
|
||||||
#define CC1_SPEC \
|
#define CC1_SPEC \
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ extern GTY(()) int darwin_ms_struct;
|
||||||
%{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
|
%{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
|
||||||
%{fopenmp|ftree-parallelize-loops=*: \
|
%{fopenmp|ftree-parallelize-loops=*: \
|
||||||
%{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
|
%{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
|
||||||
%{fsanitize=address: -lasan } \
|
%{%:sanitize(address): -lasan } \
|
||||||
%{fgnu-tm: \
|
%{fgnu-tm: \
|
||||||
%{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \
|
%{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \
|
||||||
%{!nostdlib:%{!nodefaultlibs:\
|
%{!nostdlib:%{!nodefaultlibs:\
|
||||||
|
|
|
||||||
|
|
@ -1498,7 +1498,8 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
|
||||||
|
|
||||||
On the RS/6000, we grow upwards, from the area after the outgoing
|
On the RS/6000, we grow upwards, from the area after the outgoing
|
||||||
arguments. */
|
arguments. */
|
||||||
#define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0 || flag_asan != 0)
|
#define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0 \
|
||||||
|
|| (flag_sanitize & SANITIZE_ADDRESS) != 0)
|
||||||
|
|
||||||
/* Size of the outgoing register save area */
|
/* Size of the outgoing register save area */
|
||||||
#define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX \
|
#define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX \
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
2013-08-30 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
* typeck.c (cp_build_binary_op): Add division by zero and shift
|
||||||
|
instrumentation.
|
||||||
|
* error.c (dump_expr): Special-case ubsan builtins.
|
||||||
|
|
||||||
2013-08-30 Paolo Carlini <paolo.carlini@oracle.com>
|
2013-08-30 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/51424
|
PR c++/51424
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "tree-pretty-print.h"
|
#include "tree-pretty-print.h"
|
||||||
#include "pointer-set.h"
|
#include "pointer-set.h"
|
||||||
#include "c-family/c-objc.h"
|
#include "c-family/c-objc.h"
|
||||||
|
#include "ubsan.h"
|
||||||
|
|
||||||
#include <new> // For placement-new.
|
#include <new> // For placement-new.
|
||||||
|
|
||||||
|
|
@ -2007,6 +2008,12 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
|
||||||
}
|
}
|
||||||
skipfirst = true;
|
skipfirst = true;
|
||||||
}
|
}
|
||||||
|
if (flag_sanitize & SANITIZE_UNDEFINED
|
||||||
|
&& is_ubsan_builtin_p (fn))
|
||||||
|
{
|
||||||
|
pp_string (cxx_pp, M_("<ubsan routine call>"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
dump_expr (pp, fn, flags | TFF_EXPR_IN_PARENS);
|
dump_expr (pp, fn, flags | TFF_EXPR_IN_PARENS);
|
||||||
dump_call_expr_args (pp, t, flags, skipfirst);
|
dump_call_expr_args (pp, t, flags, skipfirst);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "convert.h"
|
#include "convert.h"
|
||||||
#include "c-family/c-common.h"
|
#include "c-family/c-common.h"
|
||||||
#include "c-family/c-objc.h"
|
#include "c-family/c-objc.h"
|
||||||
|
#include "c-family/c-ubsan.h"
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
|
||||||
static tree pfn_from_ptrmemfunc (tree);
|
static tree pfn_from_ptrmemfunc (tree);
|
||||||
|
|
@ -3882,6 +3883,7 @@ cp_build_binary_op (location_t location,
|
||||||
tree final_type = 0;
|
tree final_type = 0;
|
||||||
|
|
||||||
tree result;
|
tree result;
|
||||||
|
tree orig_type = NULL;
|
||||||
|
|
||||||
/* Nonzero if this is an operation like MIN or MAX which can
|
/* Nonzero if this is an operation like MIN or MAX which can
|
||||||
safely be computed in short if both args are promoted shorts.
|
safely be computed in short if both args are promoted shorts.
|
||||||
|
|
@ -3906,6 +3908,15 @@ cp_build_binary_op (location_t location,
|
||||||
op0 = orig_op0;
|
op0 = orig_op0;
|
||||||
op1 = orig_op1;
|
op1 = orig_op1;
|
||||||
|
|
||||||
|
/* Remember whether we're doing / or %. */
|
||||||
|
bool doing_div_or_mod = false;
|
||||||
|
|
||||||
|
/* Remember whether we're doing << or >>. */
|
||||||
|
bool doing_shift = false;
|
||||||
|
|
||||||
|
/* Tree holding instrumentation expression. */
|
||||||
|
tree instrument_expr = NULL;
|
||||||
|
|
||||||
if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
|
if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
|
||||||
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|
||||||
|| code == TRUTH_XOR_EXPR)
|
|| code == TRUTH_XOR_EXPR)
|
||||||
|
|
@ -4086,8 +4097,12 @@ cp_build_binary_op (location_t location,
|
||||||
{
|
{
|
||||||
enum tree_code tcode0 = code0, tcode1 = code1;
|
enum tree_code tcode0 = code0, tcode1 = code1;
|
||||||
tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none);
|
tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none);
|
||||||
|
cop1 = maybe_constant_value (cop1);
|
||||||
|
|
||||||
warn_for_div_by_zero (location, maybe_constant_value (cop1));
|
if (tcode0 == INTEGER_TYPE)
|
||||||
|
doing_div_or_mod = true;
|
||||||
|
|
||||||
|
warn_for_div_by_zero (location, cop1);
|
||||||
|
|
||||||
if (tcode0 == COMPLEX_TYPE || tcode0 == VECTOR_TYPE)
|
if (tcode0 == COMPLEX_TYPE || tcode0 == VECTOR_TYPE)
|
||||||
tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
|
tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
|
||||||
|
|
@ -4125,8 +4140,11 @@ cp_build_binary_op (location_t location,
|
||||||
case FLOOR_MOD_EXPR:
|
case FLOOR_MOD_EXPR:
|
||||||
{
|
{
|
||||||
tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none);
|
tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none);
|
||||||
|
cop1 = maybe_constant_value (cop1);
|
||||||
|
|
||||||
warn_for_div_by_zero (location, maybe_constant_value (cop1));
|
if (code0 == INTEGER_TYPE)
|
||||||
|
doing_div_or_mod = true;
|
||||||
|
warn_for_div_by_zero (location, cop1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
|
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
|
||||||
|
|
@ -4180,6 +4198,7 @@ cp_build_binary_op (location_t location,
|
||||||
if (TREE_CODE (const_op1) != INTEGER_CST)
|
if (TREE_CODE (const_op1) != INTEGER_CST)
|
||||||
const_op1 = op1;
|
const_op1 = op1;
|
||||||
result_type = type0;
|
result_type = type0;
|
||||||
|
doing_shift = true;
|
||||||
if (TREE_CODE (const_op1) == INTEGER_CST)
|
if (TREE_CODE (const_op1) == INTEGER_CST)
|
||||||
{
|
{
|
||||||
if (tree_int_cst_lt (const_op1, integer_zero_node))
|
if (tree_int_cst_lt (const_op1, integer_zero_node))
|
||||||
|
|
@ -4227,6 +4246,7 @@ cp_build_binary_op (location_t location,
|
||||||
if (TREE_CODE (const_op1) != INTEGER_CST)
|
if (TREE_CODE (const_op1) != INTEGER_CST)
|
||||||
const_op1 = op1;
|
const_op1 = op1;
|
||||||
result_type = type0;
|
result_type = type0;
|
||||||
|
doing_shift = true;
|
||||||
if (TREE_CODE (const_op1) == INTEGER_CST)
|
if (TREE_CODE (const_op1) == INTEGER_CST)
|
||||||
{
|
{
|
||||||
if (tree_int_cst_lt (const_op1, integer_zero_node))
|
if (tree_int_cst_lt (const_op1, integer_zero_node))
|
||||||
|
|
@ -4796,8 +4816,9 @@ cp_build_binary_op (location_t location,
|
||||||
|
|
||||||
if (shorten && none_complex)
|
if (shorten && none_complex)
|
||||||
{
|
{
|
||||||
|
orig_type = result_type;
|
||||||
final_type = result_type;
|
final_type = result_type;
|
||||||
result_type = shorten_binary_op (result_type, op0, op1,
|
result_type = shorten_binary_op (result_type, op0, op1,
|
||||||
shorten == -1);
|
shorten == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4863,6 +4884,36 @@ cp_build_binary_op (location_t location,
|
||||||
if (build_type == NULL_TREE)
|
if (build_type == NULL_TREE)
|
||||||
build_type = result_type;
|
build_type = result_type;
|
||||||
|
|
||||||
|
if ((flag_sanitize & SANITIZE_UNDEFINED)
|
||||||
|
&& !processing_template_decl
|
||||||
|
&& current_function_decl != 0
|
||||||
|
&& (doing_div_or_mod || doing_shift))
|
||||||
|
{
|
||||||
|
/* OP0 and/or OP1 might have side-effects. */
|
||||||
|
op0 = cp_save_expr (op0);
|
||||||
|
op1 = cp_save_expr (op1);
|
||||||
|
op0 = maybe_constant_value (fold_non_dependent_expr_sfinae (op0,
|
||||||
|
tf_none));
|
||||||
|
op1 = maybe_constant_value (fold_non_dependent_expr_sfinae (op1,
|
||||||
|
tf_none));
|
||||||
|
if (doing_div_or_mod)
|
||||||
|
{
|
||||||
|
/* For diagnostics we want to use the promoted types without
|
||||||
|
shorten_binary_op. So convert the arguments to the
|
||||||
|
original result_type. */
|
||||||
|
tree cop0 = op0;
|
||||||
|
tree cop1 = op1;
|
||||||
|
if (orig_type != NULL && result_type != orig_type)
|
||||||
|
{
|
||||||
|
cop0 = cp_convert (orig_type, op0, complain);
|
||||||
|
cop1 = cp_convert (orig_type, op1, complain);
|
||||||
|
}
|
||||||
|
instrument_expr = ubsan_instrument_division (location, cop0, cop1);
|
||||||
|
}
|
||||||
|
else if (doing_shift)
|
||||||
|
instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
|
||||||
|
}
|
||||||
|
|
||||||
result = build2 (resultcode, build_type, op0, op1);
|
result = build2 (resultcode, build_type, op0, op1);
|
||||||
result = fold_if_not_in_template (result);
|
result = fold_if_not_in_template (result);
|
||||||
if (final_type != 0)
|
if (final_type != 0)
|
||||||
|
|
@ -4873,6 +4924,10 @@ cp_build_binary_op (location_t location,
|
||||||
&& !TREE_OVERFLOW_P (op1))
|
&& !TREE_OVERFLOW_P (op1))
|
||||||
overflow_warning (location, result);
|
overflow_warning (location, result);
|
||||||
|
|
||||||
|
if ((flag_sanitize & SANITIZE_UNDEFINED) && instrument_expr != NULL)
|
||||||
|
result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result),
|
||||||
|
instrument_expr, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile)
|
||||||
cpp_define_formatted (pfile, "__PIE__=%d", flag_pie);
|
cpp_define_formatted (pfile, "__PIE__=%d", flag_pie);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_asan)
|
if (flag_sanitize & SANITIZE_ADDRESS)
|
||||||
cpp_define (pfile, "__SANITIZE_ADDRESS__");
|
cpp_define (pfile, "__SANITIZE_ADDRESS__");
|
||||||
|
|
||||||
if (optimize_size)
|
if (optimize_size)
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||||
@gccoptlist{@var{object-file-name} -l@var{library} @gol
|
@gccoptlist{@var{object-file-name} -l@var{library} @gol
|
||||||
-nostartfiles -nodefaultlibs -nostdlib -pie -rdynamic @gol
|
-nostartfiles -nodefaultlibs -nostdlib -pie -rdynamic @gol
|
||||||
-s -static -static-libgcc -static-libstdc++ @gol
|
-s -static -static-libgcc -static-libstdc++ @gol
|
||||||
-static-libasan -static-libtsan @gol
|
-static-libasan -static-libtsan -static-libubsan @gol
|
||||||
-shared -shared-libgcc -symbolic @gol
|
-shared -shared-libgcc -symbolic @gol
|
||||||
-T @var{script} -Wl,@var{option} -Xlinker @var{option} @gol
|
-T @var{script} -Wl,@var{option} -Xlinker @var{option} @gol
|
||||||
-u @var{symbol}}
|
-u @var{symbol}}
|
||||||
|
|
@ -5208,6 +5208,14 @@ Memory access instructions will be instrumented to detect
|
||||||
data race bugs.
|
data race bugs.
|
||||||
See @uref{http://code.google.com/p/data-race-test/wiki/ThreadSanitizer} for more details.
|
See @uref{http://code.google.com/p/data-race-test/wiki/ThreadSanitizer} for more details.
|
||||||
|
|
||||||
|
@item -fsanitize=undefined
|
||||||
|
Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector
|
||||||
|
Various computations will be instrumented to detect undefined behavior
|
||||||
|
at runtime, e.g.@: division by zero or various overflows.
|
||||||
|
While @option{-ftrapv} causes traps for signed overflows to be emitted,
|
||||||
|
@option{-fsanitize=undefined} gives a diagnostic message.
|
||||||
|
This currently works only for the C family of languages.
|
||||||
|
|
||||||
@item -fdump-final-insns@r{[}=@var{file}@r{]}
|
@item -fdump-final-insns@r{[}=@var{file}@r{]}
|
||||||
@opindex fdump-final-insns
|
@opindex fdump-final-insns
|
||||||
Dump the final internal representation (RTL) to @var{file}. If the
|
Dump the final internal representation (RTL) to @var{file}. If the
|
||||||
|
|
@ -10160,6 +10168,15 @@ option is not used, then this links against the shared version of
|
||||||
driver to link @file{libtsan} statically, without necessarily linking
|
driver to link @file{libtsan} statically, without necessarily linking
|
||||||
other libraries statically.
|
other libraries statically.
|
||||||
|
|
||||||
|
@item -static-libubsan
|
||||||
|
When the @option{-fsanitize=undefined} option is used to link a program,
|
||||||
|
the GCC driver automatically links against @option{libubsan}. If
|
||||||
|
@file{libubsan} is available as a shared library, and the @option{-static}
|
||||||
|
option is not used, then this links against the shared version of
|
||||||
|
@file{libubsan}. The @option{-static-libubsan} option directs the GCC
|
||||||
|
driver to link @file{libubsan} statically, without necessarily linking
|
||||||
|
other libraries statically.
|
||||||
|
|
||||||
@item -static-libstdc++
|
@item -static-libstdc++
|
||||||
When the @command{g++} program is used to link a C++ program, it
|
When the @command{g++} program is used to link a C++ program, it
|
||||||
normally automatically links against @option{libstdc++}. If
|
normally automatically links against @option{libstdc++}. If
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,19 @@ enum fp_contract_mode {
|
||||||
FP_CONTRACT_FAST = 2
|
FP_CONTRACT_FAST = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Different instrumentation modes. */
|
||||||
|
enum sanitize_code {
|
||||||
|
/* AddressSanitizer. */
|
||||||
|
SANITIZE_ADDRESS = 1 << 0,
|
||||||
|
/* ThreadSanitizer. */
|
||||||
|
SANITIZE_THREAD = 1 << 1,
|
||||||
|
/* UndefinedBehaviorSanitizer. */
|
||||||
|
SANITIZE_SHIFT = 1 << 2,
|
||||||
|
SANITIZE_DIVIDE = 1 << 3,
|
||||||
|
SANITIZE_UNREACHABLE = 1 << 4,
|
||||||
|
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
|
||||||
|
};
|
||||||
|
|
||||||
/* flag_vtable_verify initialization levels. */
|
/* flag_vtable_verify initialization levels. */
|
||||||
enum vtv_priority {
|
enum vtv_priority {
|
||||||
VTV_NO_PRIORITY = 0, /* i.E. Do NOT do vtable verification. */
|
VTV_NO_PRIORITY = 0, /* i.E. Do NOT do vtable verification. */
|
||||||
|
|
|
||||||
113
gcc/gcc.c
113
gcc/gcc.c
|
|
@ -215,7 +215,7 @@ static inline void process_marked_switches (void);
|
||||||
static const char *process_brace_body (const char *, const char *, const char *, int, int);
|
static const char *process_brace_body (const char *, const char *, const char *, int, int);
|
||||||
static const struct spec_function *lookup_spec_function (const char *);
|
static const struct spec_function *lookup_spec_function (const char *);
|
||||||
static const char *eval_spec_function (const char *, const char *);
|
static const char *eval_spec_function (const char *, const char *);
|
||||||
static const char *handle_spec_function (const char *);
|
static const char *handle_spec_function (const char *, bool *);
|
||||||
static char *save_string (const char *, int);
|
static char *save_string (const char *, int);
|
||||||
static void set_collect_gcc_options (void);
|
static void set_collect_gcc_options (void);
|
||||||
static int do_spec_1 (const char *, int, const char *);
|
static int do_spec_1 (const char *, int, const char *);
|
||||||
|
|
@ -253,6 +253,7 @@ static const char *convert_filename (const char *, int, int);
|
||||||
static const char *getenv_spec_function (int, const char **);
|
static const char *getenv_spec_function (int, const char **);
|
||||||
static const char *if_exists_spec_function (int, const char **);
|
static const char *if_exists_spec_function (int, const char **);
|
||||||
static const char *if_exists_else_spec_function (int, const char **);
|
static const char *if_exists_else_spec_function (int, const char **);
|
||||||
|
static const char *sanitize_spec_function (int, const char **);
|
||||||
static const char *replace_outfile_spec_function (int, const char **);
|
static const char *replace_outfile_spec_function (int, const char **);
|
||||||
static const char *remove_outfile_spec_function (int, const char **);
|
static const char *remove_outfile_spec_function (int, const char **);
|
||||||
static const char *version_compare_spec_function (int, const char **);
|
static const char *version_compare_spec_function (int, const char **);
|
||||||
|
|
@ -432,6 +433,10 @@ or with constant text in a single argument.
|
||||||
than the OR.
|
than the OR.
|
||||||
If %* appears in X, all of the alternatives must be starred, and
|
If %* appears in X, all of the alternatives must be starred, and
|
||||||
only the first matching alternative is substituted.
|
only the first matching alternative is substituted.
|
||||||
|
%{%:function(args):X}
|
||||||
|
Call function named FUNCTION with args ARGS. If the function
|
||||||
|
returns non-NULL, then X is substituted, if it returns
|
||||||
|
NULL, it isn't substituted.
|
||||||
%{S:X; if S was given to GCC, substitutes X;
|
%{S:X; if S was given to GCC, substitutes X;
|
||||||
T:Y; else if T was given to GCC, substitutes Y;
|
T:Y; else if T was given to GCC, substitutes Y;
|
||||||
:D} else substitutes D. There can be as many clauses as you need.
|
:D} else substitutes D. There can be as many clauses as you need.
|
||||||
|
|
@ -586,6 +591,28 @@ proper position among the other output files. */
|
||||||
#define LIBTSAN_EARLY_SPEC ""
|
#define LIBTSAN_EARLY_SPEC ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIBUBSAN_SPEC
|
||||||
|
#ifdef STATIC_LIBUBSAN_LIBS
|
||||||
|
#define ADD_STATIC_LIBUBSAN_LIBS \
|
||||||
|
" %{static-libubsan:" STATIC_LIBUBSAN_LIBS "}"
|
||||||
|
#else
|
||||||
|
#define ADD_STATIC_LIBUBSAN_LIBS
|
||||||
|
#endif
|
||||||
|
#ifdef LIBUBSAN_EARLY_SPEC
|
||||||
|
#define LIBUBSAN_SPEC ADD_STATIC_LIBUBSAN_LIBS
|
||||||
|
#elif defined(HAVE_LD_STATIC_DYNAMIC)
|
||||||
|
#define LIBUBSAN_SPEC "%{static-libubsan:" LD_STATIC_OPTION \
|
||||||
|
"} -lubsan %{static-libubsan:" LD_DYNAMIC_OPTION "}" \
|
||||||
|
ADD_STATIC_LIBUBSAN_LIBS
|
||||||
|
#else
|
||||||
|
#define LIBUBSAN_SPEC "-lubsan" ADD_STATIC_LIBUBSAN_LIBS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIBUBSAN_EARLY_SPEC
|
||||||
|
#define LIBUBSAN_EARLY_SPEC ""
|
||||||
|
#endif
|
||||||
|
|
||||||
/* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
|
/* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
|
||||||
included. */
|
included. */
|
||||||
#ifndef LIBGCC_SPEC
|
#ifndef LIBGCC_SPEC
|
||||||
|
|
@ -708,18 +735,20 @@ proper position among the other output files. */
|
||||||
/* Linker command line options for -fsanitize= early on the command line. */
|
/* Linker command line options for -fsanitize= early on the command line. */
|
||||||
#ifndef SANITIZER_EARLY_SPEC
|
#ifndef SANITIZER_EARLY_SPEC
|
||||||
#define SANITIZER_EARLY_SPEC "\
|
#define SANITIZER_EARLY_SPEC "\
|
||||||
%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_EARLY_SPEC "} \
|
%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
|
||||||
%{fsanitize=thread:" LIBTSAN_EARLY_SPEC "}}}"
|
%{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
|
||||||
|
%{%:sanitize(undefined):" LIBUBSAN_EARLY_SPEC "}}}"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Linker command line options for -fsanitize= late on the command line. */
|
/* Linker command line options for -fsanitize= late on the command line. */
|
||||||
#ifndef SANITIZER_SPEC
|
#ifndef SANITIZER_SPEC
|
||||||
#define SANITIZER_SPEC "\
|
#define SANITIZER_SPEC "\
|
||||||
%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_SPEC "\
|
%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
|
||||||
%{static:%ecannot specify -static with -fsanitize=address}\
|
%{static:%ecannot specify -static with -fsanitize=address}\
|
||||||
%{fsanitize=thread:%e-fsanitize=address is incompatible with -fsanitize=thread}}\
|
%{%:sanitize(thread):%e-fsanitize=address is incompatible with -fsanitize=thread}}\
|
||||||
%{fsanitize=thread:" LIBTSAN_SPEC "\
|
%{%:sanitize(thread):" LIBTSAN_SPEC "\
|
||||||
%{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}"
|
%{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}\
|
||||||
|
%{%:sanitize(undefined):" LIBUBSAN_SPEC "}}}"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This is the spec to use, once the code for creating the vtable
|
/* This is the spec to use, once the code for creating the vtable
|
||||||
|
|
@ -1333,6 +1362,7 @@ static const struct spec_function static_spec_functions[] =
|
||||||
{ "getenv", getenv_spec_function },
|
{ "getenv", getenv_spec_function },
|
||||||
{ "if-exists", if_exists_spec_function },
|
{ "if-exists", if_exists_spec_function },
|
||||||
{ "if-exists-else", if_exists_else_spec_function },
|
{ "if-exists-else", if_exists_else_spec_function },
|
||||||
|
{ "sanitize", sanitize_spec_function },
|
||||||
{ "replace-outfile", replace_outfile_spec_function },
|
{ "replace-outfile", replace_outfile_spec_function },
|
||||||
{ "remove-outfile", remove_outfile_spec_function },
|
{ "remove-outfile", remove_outfile_spec_function },
|
||||||
{ "version-compare", version_compare_spec_function },
|
{ "version-compare", version_compare_spec_function },
|
||||||
|
|
@ -5283,7 +5313,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
p = handle_spec_function (p);
|
p = handle_spec_function (p, NULL);
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -5519,10 +5549,13 @@ eval_spec_function (const char *func, const char *args)
|
||||||
ARGS is processed as a spec in a separate context and split into an
|
ARGS is processed as a spec in a separate context and split into an
|
||||||
argument vector in the normal fashion. The function returns a string
|
argument vector in the normal fashion. The function returns a string
|
||||||
containing a spec which we then process in the caller's context, or
|
containing a spec which we then process in the caller's context, or
|
||||||
NULL if no processing is required. */
|
NULL if no processing is required.
|
||||||
|
|
||||||
|
If RETVAL_NONNULL is not NULL, then store a bool whether function
|
||||||
|
returned non-NULL. */
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
handle_spec_function (const char *p)
|
handle_spec_function (const char *p, bool *retval_nonnull)
|
||||||
{
|
{
|
||||||
char *func, *args;
|
char *func, *args;
|
||||||
const char *endp, *funcval;
|
const char *endp, *funcval;
|
||||||
|
|
@ -5568,6 +5601,8 @@ handle_spec_function (const char *p)
|
||||||
funcval = eval_spec_function (func, args);
|
funcval = eval_spec_function (func, args);
|
||||||
if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
|
if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
|
||||||
p = NULL;
|
p = NULL;
|
||||||
|
if (retval_nonnull)
|
||||||
|
*retval_nonnull = funcval != NULL;
|
||||||
|
|
||||||
free (func);
|
free (func);
|
||||||
free (args);
|
free (args);
|
||||||
|
|
@ -5711,19 +5746,28 @@ handle_braces (const char *p)
|
||||||
p++, a_is_negated = true;
|
p++, a_is_negated = true;
|
||||||
|
|
||||||
SKIP_WHITE();
|
SKIP_WHITE();
|
||||||
if (*p == '.')
|
if (*p == '%' && p[1] == ':')
|
||||||
p++, a_is_suffix = true;
|
{
|
||||||
else if (*p == ',')
|
atom = NULL;
|
||||||
p++, a_is_spectype = true;
|
end_atom = NULL;
|
||||||
|
p = handle_spec_function (p + 2, &a_matched);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*p == '.')
|
||||||
|
p++, a_is_suffix = true;
|
||||||
|
else if (*p == ',')
|
||||||
|
p++, a_is_spectype = true;
|
||||||
|
|
||||||
atom = p;
|
atom = p;
|
||||||
while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
|
while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
|
||||||
|| *p == ',' || *p == '.' || *p == '@')
|
|| *p == ',' || *p == '.' || *p == '@')
|
||||||
p++;
|
p++;
|
||||||
end_atom = p;
|
end_atom = p;
|
||||||
|
|
||||||
if (*p == '*')
|
if (*p == '*')
|
||||||
p++, a_is_starred = 1;
|
p++, a_is_starred = 1;
|
||||||
|
}
|
||||||
|
|
||||||
SKIP_WHITE();
|
SKIP_WHITE();
|
||||||
switch (*p)
|
switch (*p)
|
||||||
|
|
@ -5748,7 +5792,7 @@ handle_braces (const char *p)
|
||||||
if (ordered_set)
|
if (ordered_set)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
|
||||||
if (atom == end_atom)
|
if (atom && atom == end_atom)
|
||||||
{
|
{
|
||||||
if (!n_way_choice || disj_matched || *p == '|'
|
if (!n_way_choice || disj_matched || *p == '|'
|
||||||
|| a_is_negated || a_is_suffix || a_is_spectype
|
|| a_is_negated || a_is_suffix || a_is_spectype
|
||||||
|
|
@ -5773,7 +5817,9 @@ handle_braces (const char *p)
|
||||||
match. */
|
match. */
|
||||||
if (!disj_matched && !n_way_matched)
|
if (!disj_matched && !n_way_matched)
|
||||||
{
|
{
|
||||||
if (a_is_suffix)
|
if (atom == NULL)
|
||||||
|
/* a_matched is already set by handle_spec_function. */;
|
||||||
|
else if (a_is_suffix)
|
||||||
a_matched = input_suffix_matches (atom, end_atom);
|
a_matched = input_suffix_matches (atom, end_atom);
|
||||||
else if (a_is_spectype)
|
else if (a_is_spectype)
|
||||||
a_matched = input_spec_matches (atom, end_atom);
|
a_matched = input_spec_matches (atom, end_atom);
|
||||||
|
|
@ -8070,6 +8116,27 @@ if_exists_else_spec_function (int argc, const char **argv)
|
||||||
return argv[1];
|
return argv[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sanitize built-in spec function.
|
||||||
|
|
||||||
|
This returns non-NULL, if sanitizing address, thread or
|
||||||
|
any of the undefined behavior sanitizers. */
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
sanitize_spec_function (int argc, const char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (strcmp (argv[0], "address") == 0)
|
||||||
|
return (flag_sanitize & SANITIZE_ADDRESS) ? "" : NULL;
|
||||||
|
if (strcmp (argv[0], "thread") == 0)
|
||||||
|
return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
|
||||||
|
if (strcmp (argv[0], "undefined") == 0)
|
||||||
|
return (flag_sanitize & SANITIZE_UNDEFINED) ? "" : NULL;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* replace-outfile built-in spec function.
|
/* replace-outfile built-in spec function.
|
||||||
|
|
||||||
This looks for the first argument in the outfiles array's name and
|
This looks for the first argument in the outfiles array's name and
|
||||||
|
|
|
||||||
64
gcc/opts.c
64
gcc/opts.c
|
|
@ -1405,6 +1405,70 @@ common_handle_option (struct gcc_options *opts,
|
||||||
opts->x_exit_after_options = true;
|
opts->x_exit_after_options = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_fsanitize_:
|
||||||
|
{
|
||||||
|
const char *p = arg;
|
||||||
|
while (*p != 0)
|
||||||
|
{
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const char *const name;
|
||||||
|
unsigned int flag;
|
||||||
|
size_t len;
|
||||||
|
} spec[] =
|
||||||
|
{
|
||||||
|
{ "address", SANITIZE_ADDRESS, sizeof "address" - 1 },
|
||||||
|
{ "thread", SANITIZE_THREAD, sizeof "thread" - 1 },
|
||||||
|
{ "shift", SANITIZE_SHIFT, sizeof "shift" - 1 },
|
||||||
|
{ "integer-divide-by-zero", SANITIZE_DIVIDE,
|
||||||
|
sizeof "integer-divide-by-zero" - 1 },
|
||||||
|
{ "undefined", SANITIZE_UNDEFINED, sizeof "undefined" - 1 },
|
||||||
|
{ "unreachable", SANITIZE_UNREACHABLE,
|
||||||
|
sizeof "unreachable" - 1 },
|
||||||
|
{ NULL, 0, 0 }
|
||||||
|
};
|
||||||
|
const char *comma;
|
||||||
|
size_t len, i;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
comma = strchr (p, ',');
|
||||||
|
if (comma == NULL)
|
||||||
|
len = strlen (p);
|
||||||
|
else
|
||||||
|
len = comma - p;
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
p = comma + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to see if the string matches an option class name. */
|
||||||
|
for (i = 0; spec[i].name != NULL; ++i)
|
||||||
|
if (len == spec[i].len
|
||||||
|
&& memcmp (p, spec[i].name, len) == 0)
|
||||||
|
{
|
||||||
|
/* Handle both -fsanitize and -fno-sanitize cases. */
|
||||||
|
if (value)
|
||||||
|
flag_sanitize |= spec[i].flag;
|
||||||
|
else
|
||||||
|
flag_sanitize &= ~spec[i].flag;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! found)
|
||||||
|
warning_at (loc, 0,
|
||||||
|
"unrecognized argument to -fsanitize= option: %q.*s",
|
||||||
|
(int) len, p);
|
||||||
|
|
||||||
|
if (comma == NULL)
|
||||||
|
break;
|
||||||
|
p = comma + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OPT_O:
|
case OPT_O:
|
||||||
case OPT_Os:
|
case OPT_Os:
|
||||||
case OPT_Ofast:
|
case OPT_Ofast:
|
||||||
|
|
|
||||||
|
|
@ -283,3 +283,17 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_THREAD_FENCE,
|
||||||
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_SIGNAL_FENCE,
|
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_SIGNAL_FENCE,
|
||||||
"__tsan_atomic_signal_fence",
|
"__tsan_atomic_signal_fence",
|
||||||
BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST)
|
BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST)
|
||||||
|
|
||||||
|
/* Undefined Behavior Sanitizer */
|
||||||
|
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW,
|
||||||
|
"__ubsan_handle_divrem_overflow",
|
||||||
|
BT_FN_VOID_PTR_PTR_PTR,
|
||||||
|
ATTR_COLD_NOTHROW_LEAF_LIST)
|
||||||
|
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS,
|
||||||
|
"__ubsan_handle_shift_out_of_bounds",
|
||||||
|
BT_FN_VOID_PTR_PTR_PTR,
|
||||||
|
ATTR_COLD_NOTHROW_LEAF_LIST)
|
||||||
|
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE,
|
||||||
|
"__ubsan_handle_builtin_unreachable",
|
||||||
|
BT_FN_VOID_PTR,
|
||||||
|
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,34 @@
|
||||||
|
2013-08-30 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
* g++.dg/ubsan/div-by-zero-1.C: New test.
|
||||||
|
* c-c++-common/ubsan/save-expr-1.c: New test.
|
||||||
|
* c-c++-common/ubsan/save-expr-2.c: New test.
|
||||||
|
* c-c++-common/ubsan/save-expr-3.c: New test.
|
||||||
|
* c-c++-common/ubsan/save-expr-4.c: New test.
|
||||||
|
* c-c++-common/ubsan/typedef-1.c: New test.
|
||||||
|
* c-c++-common/ubsan/const-char-1.c: New test.
|
||||||
|
* c-c++-common/ubsan/const-expr.c: New test.
|
||||||
|
* c-c++-common/ubsan/div-by-zero-1.c: Likewise.
|
||||||
|
* c-c++-common/ubsan/shift-1.c: Likewise.
|
||||||
|
* c-c++-common/ubsan/shift-2.c: Likewise.
|
||||||
|
* c-c++-common/ubsan/div-by-zero-2.c: Likewise.
|
||||||
|
* lib/ubsan-dg.exp: New file.
|
||||||
|
* g++.dg/dg.exp: Add ubsan tests.
|
||||||
|
* g++.dg/ubsan/ubsan.exp: New file.
|
||||||
|
* gcc.dg/ubsan/ubsan.exp: New file.
|
||||||
|
* g++.dg/ubsan/cxx11-shift-1.C: New test.
|
||||||
|
* g++.dg/ubsan/cxx11-shift-2.C: New test.
|
||||||
|
* c-c++-common/ubsan/div-by-zero-3.c: New test.
|
||||||
|
* c-c++-common/ubsan/div-by-zero-1.c: New test.
|
||||||
|
* c-c++-common/ubsan/div-by-zero-4.c: New test.
|
||||||
|
* c-c++-common/ubsan/shift-3.c: New test.
|
||||||
|
* c-c++-common/ubsan/unreachable-1.c: New test.
|
||||||
|
* c-c++-common/ubsan/shift-1.c: New test.
|
||||||
|
* c-c++-common/ubsan/shift-2.c: New test.
|
||||||
|
* c-c++-common/ubsan/div-by-zero-2.c: New test.
|
||||||
|
* gcc.dg/ubsan/c99-shift-2.c: New test.
|
||||||
|
* gcc.dg/ubsan/c99-shift-1.c: New test.
|
||||||
|
|
||||||
2013-08-29 Jan Hubicka <jh@suse.cz>
|
2013-08-29 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
* gcc.dg/tree-ssa/attr-alias.c: Rename test3 to test1 to match template
|
* gcc.dg/tree-ssa/attr-alias.c: Rename test3 to test1 to match template
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift" } */
|
||||||
|
|
||||||
|
void
|
||||||
|
foo (void)
|
||||||
|
{
|
||||||
|
int y = 1 << 2;
|
||||||
|
__builtin_printf ("%d\n", y);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w" } */
|
||||||
|
|
||||||
|
enum e { A = 1 << 1, B, };
|
||||||
|
const int arr[] = {
|
||||||
|
1 << 2,
|
||||||
|
1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
bar (int a, int b)
|
||||||
|
{
|
||||||
|
return a >> b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
foo (void)
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
int vla[B << 3];
|
||||||
|
return bar (A, (i <<= 6, i + 2));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
volatile int a = 0;
|
||||||
|
volatile long long int b = 0;
|
||||||
|
volatile unsigned int c = 1;
|
||||||
|
|
||||||
|
a / b;
|
||||||
|
0 / 0;
|
||||||
|
a / 0;
|
||||||
|
0 / b;
|
||||||
|
2 / --c;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-output "division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
volatile const unsigned long int o = 1UL;
|
||||||
|
int zero = 0;
|
||||||
|
|
||||||
|
o / 0;
|
||||||
|
1UL / 0;
|
||||||
|
1UL / zero;
|
||||||
|
o / zero;
|
||||||
|
o / (++zero - 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-output "division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-overflow" } */
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
volatile int min = INT_MIN;
|
||||||
|
volatile int zero = 0;
|
||||||
|
|
||||||
|
INT_MIN / -1;
|
||||||
|
min / -1;
|
||||||
|
min / (10 * zero - (2 - 1));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-output "division of -2147483648 by -1 cannot be represented in type int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division of -2147483648 by -1 cannot be represented in type int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*division of -2147483648 by -1 cannot be represented in type int(\n|\r\n|\r)" } */
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-overflow" } */
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
/* This should not fail. */
|
||||||
|
return (unsigned int) INT_MIN / -1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
|
||||||
|
|
||||||
|
static int x;
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int o = 1;
|
||||||
|
int y = x << o;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
foo (int i, unsigned int u)
|
||||||
|
{
|
||||||
|
return u / i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bar (int i, unsigned int u)
|
||||||
|
{
|
||||||
|
return u % i;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
|
||||||
|
|
||||||
|
int x;
|
||||||
|
|
||||||
|
int
|
||||||
|
foo (int i, int u)
|
||||||
|
{
|
||||||
|
return (i << u) << x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bar (int i, int u)
|
||||||
|
{
|
||||||
|
return (i >> u) >> x;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
|
||||||
|
|
||||||
|
int x;
|
||||||
|
|
||||||
|
int
|
||||||
|
foo (int i, unsigned int u)
|
||||||
|
{
|
||||||
|
return (i % u) << (x / u);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bar (int i, unsigned int u)
|
||||||
|
{
|
||||||
|
return (((x % u) << (u / i)) >> x);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w" } */
|
||||||
|
|
||||||
|
typedef const unsigned long long int CULLI;
|
||||||
|
typedef volatile int VI;
|
||||||
|
struct s { signed long int a; };
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
struct s s = { .a = 400 };
|
||||||
|
CULLI culli = 42;
|
||||||
|
VI vi = 370;
|
||||||
|
volatile int shiftcount = 153;
|
||||||
|
|
||||||
|
a <<= 152;
|
||||||
|
1 << shiftcount;
|
||||||
|
1 << 154;
|
||||||
|
culli << 524;
|
||||||
|
1 << vi++;
|
||||||
|
(long) 1 << (s.a + 2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* { dg-output "shift exponent 152 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent 153 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent 154 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent 524 is too large for \[^\n\r]*-bit type long long unsigned int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent 370 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent 402 is too large for \[^\n\r]*-bit type long int(\n|\r\n|\r)" } */
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
volatile int b = -5;
|
||||||
|
long long int c = -6;
|
||||||
|
|
||||||
|
a << -3;
|
||||||
|
1 << -4;
|
||||||
|
1 << b;
|
||||||
|
a << c;
|
||||||
|
a << (b + c);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* { dg-output "shift exponent -3 is negative(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent -4 is negative(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent -5 is negative(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent -6 is negative(\n|\r\n|\r)" } */
|
||||||
|
/* { dg-output "\[^\n\r]*shift exponent -11 is negative(\n|\r\n|\r)" } */
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
unsigned int a = 1;
|
||||||
|
a <<= 31;
|
||||||
|
a <<= 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=undefined" } */
|
||||||
|
|
||||||
|
typedef int V;
|
||||||
|
int
|
||||||
|
foo (void)
|
||||||
|
{
|
||||||
|
V v = 9;
|
||||||
|
int a = 3;
|
||||||
|
v += v % a;
|
||||||
|
return v / 3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=unreachable" } */
|
||||||
|
/* { dg-shouldfail "ubsan" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
__builtin_unreachable ();
|
||||||
|
}
|
||||||
|
/* { dg-output "execution reached a __builtin_unreachable\\(\\) call" } */
|
||||||
|
|
@ -52,6 +52,7 @@ set tests [prune $tests $srcdir/$subdir/tm/*]
|
||||||
set tests [prune $tests $srcdir/$subdir/guality/*]
|
set tests [prune $tests $srcdir/$subdir/guality/*]
|
||||||
set tests [prune $tests $srcdir/$subdir/simulate-thread/*]
|
set tests [prune $tests $srcdir/$subdir/simulate-thread/*]
|
||||||
set tests [prune $tests $srcdir/$subdir/asan/*]
|
set tests [prune $tests $srcdir/$subdir/asan/*]
|
||||||
|
set tests [prune $tests $srcdir/$subdir/ubsan/*]
|
||||||
|
|
||||||
# Main loop.
|
# Main loop.
|
||||||
g++-dg-runtest $tests $DEFAULT_CXXFLAGS
|
g++-dg-runtest $tests $DEFAULT_CXXFLAGS
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w -std=c++11" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
a <<= 31;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w -std=c++11" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int a = -42;
|
||||||
|
a <<= 1;
|
||||||
|
}
|
||||||
|
/* { dg-output "left shift of negative value -42" } */
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w" } */
|
||||||
|
|
||||||
|
void
|
||||||
|
foo (int i)
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
case 0 * (1 / 0): /* { dg-error "is not a constant expression" } */
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GCC.
|
||||||
|
#
|
||||||
|
# GCC is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# GCC is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with GCC; see the file COPYING3. If not see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Load support procs.
|
||||||
|
load_lib g++-dg.exp
|
||||||
|
load_lib ubsan-dg.exp
|
||||||
|
|
||||||
|
# Initialize `dg'.
|
||||||
|
dg-init
|
||||||
|
if [ubsan_init] {
|
||||||
|
|
||||||
|
# Main loop.
|
||||||
|
gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/ubsan/*.c]] ""
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# All done.
|
||||||
|
ubsan_finish
|
||||||
|
dg-finish
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w -std=c99" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int a = -42;
|
||||||
|
a << 1;
|
||||||
|
}
|
||||||
|
/* { dg-output "left shift of negative value -42" } */
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-fsanitize=shift -w -std=c99" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
a <<= 31;
|
||||||
|
}
|
||||||
|
/* { dg-output "left shift of 1 by 31 places cannot be represented in type int" } */
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GCC.
|
||||||
|
#
|
||||||
|
# GCC is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# GCC is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with GCC; see the file COPYING3. If not see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# GCC testsuite that uses the `dg.exp' driver.
|
||||||
|
|
||||||
|
# Load support procs.
|
||||||
|
load_lib gcc-dg.exp
|
||||||
|
load_lib ubsan-dg.exp
|
||||||
|
|
||||||
|
# Initialize `dg'.
|
||||||
|
dg-init
|
||||||
|
if [ubsan_init] {
|
||||||
|
|
||||||
|
# Main loop.
|
||||||
|
gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/ubsan/*.c]] ""
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# All done.
|
||||||
|
ubsan_finish
|
||||||
|
dg-finish
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with GCC; see the file COPYING3. If not see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#
|
||||||
|
# ubsan_link_flags -- compute library path and flags to find libubsan.
|
||||||
|
# (originally from g++.exp)
|
||||||
|
#
|
||||||
|
|
||||||
|
proc ubsan_link_flags { paths } {
|
||||||
|
global srcdir
|
||||||
|
global ld_library_path
|
||||||
|
global shlib_ext
|
||||||
|
|
||||||
|
set gccpath ${paths}
|
||||||
|
set flags ""
|
||||||
|
|
||||||
|
set shlib_ext [get_shlib_extension]
|
||||||
|
|
||||||
|
if { $gccpath != "" } {
|
||||||
|
if { [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.a"]
|
||||||
|
|| [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.${shlib_ext}"] } {
|
||||||
|
append flags " -B${gccpath}/libsanitizer/ubsan/ "
|
||||||
|
append flags " -L${gccpath}/libsanitizer/ubsan/.libs"
|
||||||
|
append ld_library_path ":${gccpath}/libsanitizer/ubsan/.libs"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
global tool_root_dir
|
||||||
|
|
||||||
|
set libubsan [lookfor_file ${tool_root_dir} libubsan]
|
||||||
|
if { $libubsan != "" } {
|
||||||
|
append flags "-L${libubsan} "
|
||||||
|
append ld_library_path ":${libubsan}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_ld_library_path_env_vars
|
||||||
|
|
||||||
|
return "$flags"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# ubsan_init -- called at the start of each subdir of tests
|
||||||
|
#
|
||||||
|
|
||||||
|
proc ubsan_init { args } {
|
||||||
|
global TEST_ALWAYS_FLAGS
|
||||||
|
global ALWAYS_CXXFLAGS
|
||||||
|
global TOOL_OPTIONS
|
||||||
|
global ubsan_saved_TEST_ALWAYS_FLAGS
|
||||||
|
|
||||||
|
set link_flags ""
|
||||||
|
if ![is_remote host] {
|
||||||
|
if [info exists TOOL_OPTIONS] {
|
||||||
|
set link_flags "[ubsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
|
||||||
|
} else {
|
||||||
|
set link_flags "[ubsan_link_flags [get_multilibs]]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if [info exists TEST_ALWAYS_FLAGS] {
|
||||||
|
set ubsan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
|
||||||
|
}
|
||||||
|
if [info exists ALWAYS_CXXFLAGS] {
|
||||||
|
set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
|
||||||
|
} else {
|
||||||
|
if [info exists TEST_ALWAYS_FLAGS] {
|
||||||
|
set TEST_ALWAYS_FLAGS "$link_flags $TEST_ALWAYS_FLAGS"
|
||||||
|
} else {
|
||||||
|
set TEST_ALWAYS_FLAGS "$link_flags"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if { $link_flags != "" } {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# ubsan_finish -- called at the end of each subdir of tests
|
||||||
|
#
|
||||||
|
|
||||||
|
proc ubsan_finish { args } {
|
||||||
|
global TEST_ALWAYS_FLAGS
|
||||||
|
global ubsan_saved_TEST_ALWAYS_FLAGS
|
||||||
|
|
||||||
|
if [info exists ubsan_saved_TEST_ALWAYS_FLAGS] {
|
||||||
|
set TEST_ALWAYS_FLAGS $ubsan_saved_TEST_ALWAYS_FLAGS
|
||||||
|
} else {
|
||||||
|
unset TEST_ALWAYS_FLAGS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -573,10 +573,10 @@ compile_file (void)
|
||||||
mudflap_finish_file ();
|
mudflap_finish_file ();
|
||||||
|
|
||||||
/* File-scope initialization for AddressSanitizer. */
|
/* File-scope initialization for AddressSanitizer. */
|
||||||
if (flag_asan)
|
if (flag_sanitize & SANITIZE_ADDRESS)
|
||||||
asan_finish_file ();
|
asan_finish_file ();
|
||||||
|
|
||||||
if (flag_tsan)
|
if (flag_sanitize & SANITIZE_THREAD)
|
||||||
tsan_finish_file ();
|
tsan_finish_file ();
|
||||||
|
|
||||||
output_shared_constant_pool ();
|
output_shared_constant_pool ();
|
||||||
|
|
@ -1542,12 +1542,12 @@ process_options (void)
|
||||||
warn_stack_protect = 0;
|
warn_stack_protect = 0;
|
||||||
|
|
||||||
/* Address Sanitizer needs porting to each target architecture. */
|
/* Address Sanitizer needs porting to each target architecture. */
|
||||||
if (flag_asan
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
&& (targetm.asan_shadow_offset == NULL
|
&& (targetm.asan_shadow_offset == NULL
|
||||||
|| !FRAME_GROWS_DOWNWARD))
|
|| !FRAME_GROWS_DOWNWARD))
|
||||||
{
|
{
|
||||||
warning (0, "-fsanitize=address not supported for this target");
|
warning (0, "-fsanitize=address not supported for this target");
|
||||||
flag_asan = 0;
|
flag_sanitize &= ~SANITIZE_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable -Werror=coverage-mismatch when -Werror and -Wno-error
|
/* Enable -Werror=coverage-mismatch when -Werror and -Wno-error
|
||||||
|
|
|
||||||
|
|
@ -9677,6 +9677,8 @@ build_common_tree_nodes (bool signed_char, bool short_double)
|
||||||
= build_pointer_type (build_type_variant (void_type_node, 1, 0));
|
= build_pointer_type (build_type_variant (void_type_node, 1, 0));
|
||||||
fileptr_type_node = ptr_type_node;
|
fileptr_type_node = ptr_type_node;
|
||||||
|
|
||||||
|
pointer_sized_int_node = build_nonstandard_integer_type (POINTER_SIZE, 1);
|
||||||
|
|
||||||
float_type_node = make_node (REAL_TYPE);
|
float_type_node = make_node (REAL_TYPE);
|
||||||
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
|
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
|
||||||
layout_type (float_type_node);
|
layout_type (float_type_node);
|
||||||
|
|
|
||||||
|
|
@ -4288,6 +4288,7 @@ enum tree_index
|
||||||
TI_VA_LIST_FPR_COUNTER_FIELD,
|
TI_VA_LIST_FPR_COUNTER_FIELD,
|
||||||
TI_BOOLEAN_TYPE,
|
TI_BOOLEAN_TYPE,
|
||||||
TI_FILEPTR_TYPE,
|
TI_FILEPTR_TYPE,
|
||||||
|
TI_POINTER_SIZED_TYPE,
|
||||||
|
|
||||||
TI_DFLOAT32_TYPE,
|
TI_DFLOAT32_TYPE,
|
||||||
TI_DFLOAT64_TYPE,
|
TI_DFLOAT64_TYPE,
|
||||||
|
|
@ -4444,6 +4445,7 @@ extern GTY(()) tree global_trees[TI_MAX];
|
||||||
#define va_list_fpr_counter_field global_trees[TI_VA_LIST_FPR_COUNTER_FIELD]
|
#define va_list_fpr_counter_field global_trees[TI_VA_LIST_FPR_COUNTER_FIELD]
|
||||||
/* The C type `FILE *'. */
|
/* The C type `FILE *'. */
|
||||||
#define fileptr_type_node global_trees[TI_FILEPTR_TYPE]
|
#define fileptr_type_node global_trees[TI_FILEPTR_TYPE]
|
||||||
|
#define pointer_sized_int_node global_trees[TI_POINTER_SIZED_TYPE]
|
||||||
|
|
||||||
#define boolean_type_node global_trees[TI_BOOLEAN_TYPE]
|
#define boolean_type_node global_trees[TI_BOOLEAN_TYPE]
|
||||||
#define boolean_false_node global_trees[TI_BOOLEAN_FALSE]
|
#define boolean_false_node global_trees[TI_BOOLEAN_FALSE]
|
||||||
|
|
|
||||||
|
|
@ -713,7 +713,7 @@ tsan_pass (void)
|
||||||
static bool
|
static bool
|
||||||
tsan_gate (void)
|
tsan_gate (void)
|
||||||
{
|
{
|
||||||
return flag_tsan != 0;
|
return (flag_sanitize & SANITIZE_THREAD) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inserts __tsan_init () into the list of CTORs. */
|
/* Inserts __tsan_init () into the list of CTORs. */
|
||||||
|
|
@ -775,7 +775,7 @@ make_pass_tsan (gcc::context *ctxt)
|
||||||
static bool
|
static bool
|
||||||
tsan_gate_O0 (void)
|
tsan_gate_O0 (void)
|
||||||
{
|
{
|
||||||
return flag_tsan != 0 && !optimize;
|
return (flag_sanitize & SANITIZE_THREAD) != 0 && !optimize;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,416 @@
|
||||||
|
/* UndefinedBehaviorSanitizer, undefined behavior detector.
|
||||||
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
Contributed by Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GCC; see the file COPYING3. If not see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "coretypes.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "cgraph.h"
|
||||||
|
#include "gimple.h"
|
||||||
|
#include "hashtab.h"
|
||||||
|
#include "pointer-set.h"
|
||||||
|
#include "output.h"
|
||||||
|
#include "toplev.h"
|
||||||
|
#include "ubsan.h"
|
||||||
|
#include "c-family/c-common.h"
|
||||||
|
|
||||||
|
/* Map from a tree to a VAR_DECL tree. */
|
||||||
|
|
||||||
|
struct GTY(()) tree_type_map {
|
||||||
|
struct tree_map_base type;
|
||||||
|
tree decl;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define tree_type_map_eq tree_map_base_eq
|
||||||
|
#define tree_type_map_hash tree_map_base_hash
|
||||||
|
#define tree_type_map_marked_p tree_map_base_marked_p
|
||||||
|
|
||||||
|
static GTY ((if_marked ("tree_type_map_marked_p"), param_is (struct tree_type_map)))
|
||||||
|
htab_t decl_tree_for_type;
|
||||||
|
|
||||||
|
/* Lookup a VAR_DECL for TYPE, and return it if we find one. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
decl_for_type_lookup (tree type)
|
||||||
|
{
|
||||||
|
/* If the hash table is not initialized yet, create it now. */
|
||||||
|
if (decl_tree_for_type == NULL)
|
||||||
|
{
|
||||||
|
decl_tree_for_type = htab_create_ggc (10, tree_type_map_hash,
|
||||||
|
tree_type_map_eq, 0);
|
||||||
|
/* That also means we don't have to bother with the lookup. */
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tree_type_map *h, in;
|
||||||
|
in.type.from = type;
|
||||||
|
|
||||||
|
h = (struct tree_type_map *)
|
||||||
|
htab_find_with_hash (decl_tree_for_type, &in, TYPE_UID (type));
|
||||||
|
return h ? h->decl : NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert a mapping TYPE->DECL in the VAR_DECL for type hashtable. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
decl_for_type_insert (tree type, tree decl)
|
||||||
|
{
|
||||||
|
struct tree_type_map *h;
|
||||||
|
void **slot;
|
||||||
|
|
||||||
|
h = ggc_alloc_tree_type_map ();
|
||||||
|
h->type.from = type;
|
||||||
|
h->decl = decl;
|
||||||
|
slot = htab_find_slot_with_hash (decl_tree_for_type, h, TYPE_UID (type),
|
||||||
|
INSERT);
|
||||||
|
*(struct tree_type_map **) slot = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper routine, which encodes a value in the pointer_sized_int_node.
|
||||||
|
Arguments with precision <= POINTER_SIZE are passed directly,
|
||||||
|
the rest is passed by reference. T is a value we are to encode. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
ubsan_encode_value (tree t)
|
||||||
|
{
|
||||||
|
tree type = TREE_TYPE (t);
|
||||||
|
switch (TREE_CODE (type))
|
||||||
|
{
|
||||||
|
case INTEGER_TYPE:
|
||||||
|
if (TYPE_PRECISION (type) <= POINTER_SIZE)
|
||||||
|
return fold_build1 (NOP_EXPR, pointer_sized_int_node, t);
|
||||||
|
else
|
||||||
|
return build_fold_addr_expr (t);
|
||||||
|
case REAL_TYPE:
|
||||||
|
{
|
||||||
|
unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
|
||||||
|
if (bitsize <= POINTER_SIZE)
|
||||||
|
{
|
||||||
|
tree itype = build_nonstandard_integer_type (bitsize, true);
|
||||||
|
t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
|
||||||
|
return fold_convert (pointer_sized_int_node, t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!TREE_ADDRESSABLE (t))
|
||||||
|
{
|
||||||
|
/* The reason for this is that we don't want to pessimize
|
||||||
|
code by making vars unnecessarily addressable. */
|
||||||
|
tree var = create_tmp_var (TREE_TYPE (t), NULL);
|
||||||
|
tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
|
||||||
|
t = build_fold_addr_expr (var);
|
||||||
|
return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return build_fold_addr_expr (t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
gcc_unreachable ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build
|
||||||
|
struct __ubsan_type_descriptor
|
||||||
|
{
|
||||||
|
unsigned short __typekind;
|
||||||
|
unsigned short __typeinfo;
|
||||||
|
char __typename[];
|
||||||
|
}
|
||||||
|
type. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
ubsan_type_descriptor_type (void)
|
||||||
|
{
|
||||||
|
static const char *field_names[3]
|
||||||
|
= { "__typekind", "__typeinfo", "__typename" };
|
||||||
|
tree fields[3], ret;
|
||||||
|
tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
|
||||||
|
tree flex_arr_type = build_array_type (char_type_node, itype);
|
||||||
|
|
||||||
|
ret = make_node (RECORD_TYPE);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
|
||||||
|
get_identifier (field_names[i]),
|
||||||
|
(i == 2) ? flex_arr_type
|
||||||
|
: short_unsigned_type_node);
|
||||||
|
DECL_CONTEXT (fields[i]) = ret;
|
||||||
|
if (i)
|
||||||
|
DECL_CHAIN (fields[i - 1]) = fields[i];
|
||||||
|
}
|
||||||
|
TYPE_FIELDS (ret) = fields[0];
|
||||||
|
TYPE_NAME (ret) = get_identifier ("__ubsan_type_descriptor");
|
||||||
|
layout_type (ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build
|
||||||
|
struct __ubsan_source_location
|
||||||
|
{
|
||||||
|
const char *__filename;
|
||||||
|
unsigned int __line;
|
||||||
|
unsigned int __column;
|
||||||
|
}
|
||||||
|
type. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
ubsan_source_location_type (void)
|
||||||
|
{
|
||||||
|
static const char *field_names[3]
|
||||||
|
= { "__filename", "__line", "__column" };
|
||||||
|
tree fields[3], ret;
|
||||||
|
tree const_char_type = build_qualified_type (char_type_node,
|
||||||
|
TYPE_QUAL_CONST);
|
||||||
|
|
||||||
|
ret = make_node (RECORD_TYPE);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
|
||||||
|
get_identifier (field_names[i]),
|
||||||
|
(i == 0) ? build_pointer_type (const_char_type)
|
||||||
|
: unsigned_type_node);
|
||||||
|
DECL_CONTEXT (fields[i]) = ret;
|
||||||
|
if (i)
|
||||||
|
DECL_CHAIN (fields[i - 1]) = fields[i];
|
||||||
|
}
|
||||||
|
TYPE_FIELDS (ret) = fields[0];
|
||||||
|
TYPE_NAME (ret) = get_identifier ("__ubsan_source_location");
|
||||||
|
layout_type (ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper routine that returns a CONSTRUCTOR of __ubsan_source_location
|
||||||
|
type with its fields filled from a location_t LOC. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
ubsan_source_location (location_t loc)
|
||||||
|
{
|
||||||
|
expanded_location xloc;
|
||||||
|
tree type = ubsan_source_location_type ();
|
||||||
|
|
||||||
|
xloc = expand_location (loc);
|
||||||
|
|
||||||
|
/* Fill in the values from LOC. */
|
||||||
|
size_t len = strlen (xloc.file);
|
||||||
|
tree str = build_string (len + 1, xloc.file);
|
||||||
|
TREE_TYPE (str) = build_array_type (char_type_node,
|
||||||
|
build_index_type (size_int (len)));
|
||||||
|
TREE_READONLY (str) = 1;
|
||||||
|
TREE_STATIC (str) = 1;
|
||||||
|
str = build_fold_addr_expr_loc (loc, str);
|
||||||
|
tree ctor = build_constructor_va (type, 3, NULL_TREE, str, NULL_TREE,
|
||||||
|
build_int_cst (unsigned_type_node,
|
||||||
|
xloc.line), NULL_TREE,
|
||||||
|
build_int_cst (unsigned_type_node,
|
||||||
|
xloc.column));
|
||||||
|
TREE_CONSTANT (ctor) = 1;
|
||||||
|
TREE_STATIC (ctor) = 1;
|
||||||
|
|
||||||
|
return ctor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This routine returns a magic number for TYPE. */
|
||||||
|
|
||||||
|
static unsigned short
|
||||||
|
get_ubsan_type_info_for_type (tree type)
|
||||||
|
{
|
||||||
|
int prec = exact_log2 (TYPE_PRECISION (type));
|
||||||
|
if (prec == -1)
|
||||||
|
error ("unexpected size of type %qT", type);
|
||||||
|
|
||||||
|
return (prec << 1) | !TYPE_UNSIGNED (type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
|
||||||
|
descriptor. It first looks into the pointer map; if not found,
|
||||||
|
create the VAR_DECL, put it into the pointer map and return the
|
||||||
|
ADDR_EXPR of it. TYPE describes a particular type. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
ubsan_type_descriptor (tree type)
|
||||||
|
{
|
||||||
|
/* See through any typedefs. */
|
||||||
|
type = TYPE_MAIN_VARIANT (type);
|
||||||
|
|
||||||
|
tree decl = decl_for_type_lookup (type);
|
||||||
|
if (decl != NULL_TREE)
|
||||||
|
return decl;
|
||||||
|
|
||||||
|
tree dtype = ubsan_type_descriptor_type ();
|
||||||
|
const char *tname;
|
||||||
|
unsigned short tkind, tinfo;
|
||||||
|
|
||||||
|
/* At least for INTEGER_TYPE/REAL_TYPE/COMPLEX_TYPE, this should work.
|
||||||
|
??? For e.g. type_unsigned_for (type), the TYPE_NAME would be NULL. */
|
||||||
|
if (TYPE_NAME (type) != NULL)
|
||||||
|
tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
|
||||||
|
else
|
||||||
|
tname = "<unknown>";
|
||||||
|
if (TREE_CODE (type) == INTEGER_TYPE)
|
||||||
|
{
|
||||||
|
/* For INTEGER_TYPE, this is 0x0000. */
|
||||||
|
tkind = 0x000;
|
||||||
|
tinfo = get_ubsan_type_info_for_type (type);
|
||||||
|
}
|
||||||
|
else if (TREE_CODE (type) == REAL_TYPE)
|
||||||
|
/* We don't have float support yet. */
|
||||||
|
gcc_unreachable ();
|
||||||
|
else
|
||||||
|
gcc_unreachable ();
|
||||||
|
|
||||||
|
/* Create a new VAR_DECL of type descriptor. */
|
||||||
|
char tmp_name[32];
|
||||||
|
static unsigned int type_var_id_num;
|
||||||
|
ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++);
|
||||||
|
decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
|
||||||
|
dtype);
|
||||||
|
TREE_STATIC (decl) = 1;
|
||||||
|
TREE_PUBLIC (decl) = 0;
|
||||||
|
DECL_ARTIFICIAL (decl) = 1;
|
||||||
|
DECL_IGNORED_P (decl) = 1;
|
||||||
|
DECL_EXTERNAL (decl) = 0;
|
||||||
|
|
||||||
|
size_t len = strlen (tname);
|
||||||
|
tree str = build_string (len + 1, tname);
|
||||||
|
TREE_TYPE (str) = build_array_type (char_type_node,
|
||||||
|
build_index_type (size_int (len)));
|
||||||
|
TREE_READONLY (str) = 1;
|
||||||
|
TREE_STATIC (str) = 1;
|
||||||
|
tree ctor = build_constructor_va (dtype, 3, NULL_TREE,
|
||||||
|
build_int_cst (short_unsigned_type_node,
|
||||||
|
tkind), NULL_TREE,
|
||||||
|
build_int_cst (short_unsigned_type_node,
|
||||||
|
tinfo), NULL_TREE, str);
|
||||||
|
TREE_CONSTANT (ctor) = 1;
|
||||||
|
TREE_STATIC (ctor) = 1;
|
||||||
|
DECL_INITIAL (decl) = ctor;
|
||||||
|
rest_of_decl_compilation (decl, 1, 0);
|
||||||
|
|
||||||
|
/* Save the address of the VAR_DECL into the pointer map. */
|
||||||
|
decl = build_fold_addr_expr (decl);
|
||||||
|
decl_for_type_insert (type, decl);
|
||||||
|
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a structure for the ubsan library. NAME is a name of the new
|
||||||
|
structure. The arguments in ... are of __ubsan_type_descriptor type
|
||||||
|
and there are at most two of them. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
ubsan_create_data (const char *name, location_t loc, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
tree ret, t;
|
||||||
|
tree fields[3];
|
||||||
|
vec<tree, va_gc> *saved_args = NULL;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
/* Firstly, create a pointer to type descriptor type. */
|
||||||
|
tree td_type = ubsan_type_descriptor_type ();
|
||||||
|
TYPE_READONLY (td_type) = 1;
|
||||||
|
td_type = build_pointer_type (td_type);
|
||||||
|
|
||||||
|
/* Create the structure type. */
|
||||||
|
ret = make_node (RECORD_TYPE);
|
||||||
|
if (loc != UNKNOWN_LOCATION)
|
||||||
|
{
|
||||||
|
fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
|
||||||
|
ubsan_source_location_type ());
|
||||||
|
DECL_CONTEXT (fields[i]) = ret;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start (args, loc);
|
||||||
|
for (t = va_arg (args, tree); t != NULL_TREE;
|
||||||
|
i++, t = va_arg (args, tree))
|
||||||
|
{
|
||||||
|
gcc_checking_assert (i < 3);
|
||||||
|
/* Save the tree argument for later use. */
|
||||||
|
vec_safe_push (saved_args, t);
|
||||||
|
fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
|
||||||
|
td_type);
|
||||||
|
DECL_CONTEXT (fields[i]) = ret;
|
||||||
|
if (i)
|
||||||
|
DECL_CHAIN (fields[i - 1]) = fields[i];
|
||||||
|
}
|
||||||
|
TYPE_FIELDS (ret) = fields[0];
|
||||||
|
TYPE_NAME (ret) = get_identifier (name);
|
||||||
|
layout_type (ret);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
/* Now, fill in the type. */
|
||||||
|
char tmp_name[32];
|
||||||
|
static unsigned int ubsan_var_id_num;
|
||||||
|
ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++);
|
||||||
|
tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
|
||||||
|
ret);
|
||||||
|
TREE_STATIC (var) = 1;
|
||||||
|
TREE_PUBLIC (var) = 0;
|
||||||
|
DECL_ARTIFICIAL (var) = 1;
|
||||||
|
DECL_IGNORED_P (var) = 1;
|
||||||
|
DECL_EXTERNAL (var) = 0;
|
||||||
|
|
||||||
|
vec<constructor_elt, va_gc> *v;
|
||||||
|
vec_alloc (v, i);
|
||||||
|
tree ctor = build_constructor (ret, v);
|
||||||
|
|
||||||
|
/* If desirable, set the __ubsan_source_location element. */
|
||||||
|
if (loc != UNKNOWN_LOCATION)
|
||||||
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc));
|
||||||
|
|
||||||
|
size_t nelts = vec_safe_length (saved_args);
|
||||||
|
for (i = 0; i < nelts; i++)
|
||||||
|
{
|
||||||
|
t = (*saved_args)[i];
|
||||||
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
TREE_CONSTANT (ctor) = 1;
|
||||||
|
TREE_STATIC (ctor) = 1;
|
||||||
|
DECL_INITIAL (var) = ctor;
|
||||||
|
rest_of_decl_compilation (var, 1, 0);
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Instrument the __builtin_unreachable call. We just call the libubsan
|
||||||
|
routine instead. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
ubsan_instrument_unreachable (location_t loc)
|
||||||
|
{
|
||||||
|
tree data = ubsan_create_data ("__ubsan_unreachable_data", loc, NULL_TREE);
|
||||||
|
tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
|
||||||
|
return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a call to a libubsan routine. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_ubsan_builtin_p (tree t)
|
||||||
|
{
|
||||||
|
gcc_checking_assert (TREE_CODE (t) == FUNCTION_DECL);
|
||||||
|
return strncmp (IDENTIFIER_POINTER (DECL_NAME (t)),
|
||||||
|
"__builtin___ubsan_", 18) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "gt-ubsan.h"
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* UndefinedBehaviorSanitizer, undefined behavior detector.
|
||||||
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
Contributed by Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GCC; see the file COPYING3. If not see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef GCC_UBSAN_H
|
||||||
|
#define GCC_UBSAN_H
|
||||||
|
|
||||||
|
extern tree ubsan_instrument_unreachable (location_t);
|
||||||
|
extern tree ubsan_create_data (const char *, location_t, ...);
|
||||||
|
extern tree ubsan_type_descriptor (tree);
|
||||||
|
extern tree ubsan_encode_value (tree);
|
||||||
|
extern bool is_ubsan_builtin_p (tree);
|
||||||
|
|
||||||
|
#endif /* GCC_UBSAN_H */
|
||||||
|
|
||||||
26
gcc/varasm.c
26
gcc/varasm.c
|
|
@ -1102,7 +1102,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
|
||||||
&& bss_initializer_p (decl))
|
&& bss_initializer_p (decl))
|
||||||
{
|
{
|
||||||
if (!TREE_PUBLIC (decl)
|
if (!TREE_PUBLIC (decl)
|
||||||
&& !(flag_asan && asan_protect_global (decl)))
|
&& !((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
|
&& asan_protect_global (decl)))
|
||||||
return lcomm_section;
|
return lcomm_section;
|
||||||
if (bss_noswitch_section)
|
if (bss_noswitch_section)
|
||||||
return bss_noswitch_section;
|
return bss_noswitch_section;
|
||||||
|
|
@ -1904,7 +1905,7 @@ assemble_noswitch_variable (tree decl, const char *name, section *sect,
|
||||||
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
|
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
|
||||||
rounded = size;
|
rounded = size;
|
||||||
|
|
||||||
if (flag_asan && asan_protect_global (decl))
|
if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl))
|
||||||
size += asan_red_zone_size (size);
|
size += asan_red_zone_size (size);
|
||||||
|
|
||||||
/* Don't allocate zero bytes of common,
|
/* Don't allocate zero bytes of common,
|
||||||
|
|
@ -2063,7 +2064,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
|
||||||
|
|
||||||
align_variable (decl, dont_output_data);
|
align_variable (decl, dont_output_data);
|
||||||
|
|
||||||
if (flag_asan
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
&& asan_protect_global (decl))
|
&& asan_protect_global (decl))
|
||||||
{
|
{
|
||||||
asan_protected = true;
|
asan_protected = true;
|
||||||
|
|
@ -3376,7 +3377,8 @@ output_constant_def_contents (rtx symbol)
|
||||||
/* We are no longer deferring this constant. */
|
/* We are no longer deferring this constant. */
|
||||||
TREE_ASM_WRITTEN (decl) = TREE_ASM_WRITTEN (exp) = 1;
|
TREE_ASM_WRITTEN (decl) = TREE_ASM_WRITTEN (exp) = 1;
|
||||||
|
|
||||||
if (flag_asan && TREE_CODE (exp) == STRING_CST
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
|
&& TREE_CODE (exp) == STRING_CST
|
||||||
&& asan_protect_global (exp))
|
&& asan_protect_global (exp))
|
||||||
{
|
{
|
||||||
asan_protected = true;
|
asan_protected = true;
|
||||||
|
|
@ -6291,7 +6293,8 @@ categorize_decl_for_section (const_tree decl, int reloc)
|
||||||
else if (TREE_CODE (decl) == STRING_CST)
|
else if (TREE_CODE (decl) == STRING_CST)
|
||||||
{
|
{
|
||||||
if (flag_mudflap
|
if (flag_mudflap
|
||||||
|| (flag_asan && asan_protect_global (CONST_CAST_TREE (decl))))
|
|| ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
|
&& asan_protect_global (CONST_CAST_TREE (decl))))
|
||||||
/* or !flag_merge_constants */
|
/* or !flag_merge_constants */
|
||||||
return SECCAT_RODATA;
|
return SECCAT_RODATA;
|
||||||
else
|
else
|
||||||
|
|
@ -6317,7 +6320,8 @@ categorize_decl_for_section (const_tree decl, int reloc)
|
||||||
else if (reloc & targetm.asm_out.reloc_rw_mask ())
|
else if (reloc & targetm.asm_out.reloc_rw_mask ())
|
||||||
ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
|
ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
|
||||||
else if (reloc || flag_merge_constants < 2 || flag_mudflap
|
else if (reloc || flag_merge_constants < 2 || flag_mudflap
|
||||||
|| (flag_asan && asan_protect_global (CONST_CAST_TREE (decl))))
|
|| ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
|
&& asan_protect_global (CONST_CAST_TREE (decl))))
|
||||||
/* C and C++ don't allow different variables to share the same
|
/* C and C++ don't allow different variables to share the same
|
||||||
location. -fmerge-all-constants allows even that (at the
|
location. -fmerge-all-constants allows even that (at the
|
||||||
expense of not conforming). */
|
expense of not conforming). */
|
||||||
|
|
@ -7075,7 +7079,7 @@ place_block_symbol (rtx symbol)
|
||||||
decl = SYMBOL_REF_DECL (symbol);
|
decl = SYMBOL_REF_DECL (symbol);
|
||||||
alignment = DECL_ALIGN (decl);
|
alignment = DECL_ALIGN (decl);
|
||||||
size = get_constant_size (DECL_INITIAL (decl));
|
size = get_constant_size (DECL_INITIAL (decl));
|
||||||
if (flag_asan
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
|
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
|
||||||
&& asan_protect_global (DECL_INITIAL (decl)))
|
&& asan_protect_global (DECL_INITIAL (decl)))
|
||||||
size += asan_red_zone_size (size);
|
size += asan_red_zone_size (size);
|
||||||
|
|
@ -7085,7 +7089,8 @@ place_block_symbol (rtx symbol)
|
||||||
decl = SYMBOL_REF_DECL (symbol);
|
decl = SYMBOL_REF_DECL (symbol);
|
||||||
alignment = get_variable_align (decl);
|
alignment = get_variable_align (decl);
|
||||||
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
|
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
|
||||||
if (flag_asan && asan_protect_global (decl))
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
|
&& asan_protect_global (decl))
|
||||||
{
|
{
|
||||||
size += asan_red_zone_size (size);
|
size += asan_red_zone_size (size);
|
||||||
alignment = MAX (alignment,
|
alignment = MAX (alignment,
|
||||||
|
|
@ -7235,7 +7240,7 @@ output_object_block (struct object_block *block)
|
||||||
DECL_ALIGN (decl));
|
DECL_ALIGN (decl));
|
||||||
size = get_constant_size (DECL_INITIAL (decl));
|
size = get_constant_size (DECL_INITIAL (decl));
|
||||||
offset += size;
|
offset += size;
|
||||||
if (flag_asan
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
|
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
|
||||||
&& asan_protect_global (DECL_INITIAL (decl)))
|
&& asan_protect_global (DECL_INITIAL (decl)))
|
||||||
{
|
{
|
||||||
|
|
@ -7251,7 +7256,8 @@ output_object_block (struct object_block *block)
|
||||||
assemble_variable_contents (decl, XSTR (symbol, 0), false);
|
assemble_variable_contents (decl, XSTR (symbol, 0), false);
|
||||||
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
|
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
|
||||||
offset += size;
|
offset += size;
|
||||||
if (flag_asan && asan_protect_global (decl))
|
if ((flag_sanitize & SANITIZE_ADDRESS)
|
||||||
|
&& asan_protect_global (decl))
|
||||||
{
|
{
|
||||||
size = asan_red_zone_size (size);
|
size = asan_red_zone_size (size);
|
||||||
assemble_zeros (size);
|
assemble_zeros (size);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
|
2013-08-30 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
|
* Makefile.am (SUBDIRS): Add ubsan.
|
||||||
|
* configure.ac (AC_CONFIG_FILES): Add ubsan/Makefile.
|
||||||
|
* merge.sh: Merge ubsan.
|
||||||
|
* sanitizer_common/sanitizer_report_decorator.h: Partial merge from trunk.
|
||||||
|
* sanitizer_common/sanitizer_printf.cc: Likewise.
|
||||||
|
* sanitizer_common/sanitizer_common.h: Likewise.
|
||||||
|
* ubsan: New directory. Import ubsan runtime from llvm.
|
||||||
|
|
||||||
2013-06-03 Christophe Lyon <christophe.lyon@linaro.org>
|
2013-06-03 Christophe Lyon <christophe.lyon@linaro.org>
|
||||||
|
|
||||||
* sanitizer_common/sanitizer_linux.cc (MemoryMappingLayout::Next):
|
* sanitizer_common/sanitizer_linux.cc (MemoryMappingLayout::Next):
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
ACLOCAL_AMFLAGS = -I .. -I ../config
|
ACLOCAL_AMFLAGS = -I .. -I ../config
|
||||||
|
|
||||||
if TSAN_SUPPORTED
|
if TSAN_SUPPORTED
|
||||||
SUBDIRS = interception sanitizer_common asan tsan
|
SUBDIRS = interception sanitizer_common asan tsan ubsan
|
||||||
else
|
else
|
||||||
SUBDIRS = interception sanitizer_common asan
|
SUBDIRS = interception sanitizer_common asan ubsan
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USING_MAC_INTERPOSE
|
if USING_MAC_INTERPOSE
|
||||||
SUBDIRS = sanitizer_common asan
|
SUBDIRS = sanitizer_common asan ubsan
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
|
||||||
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS
|
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS
|
||||||
ETAGS = etags
|
ETAGS = etags
|
||||||
CTAGS = ctags
|
CTAGS = ctags
|
||||||
DIST_SUBDIRS = interception sanitizer_common asan tsan
|
DIST_SUBDIRS = interception sanitizer_common asan ubsan tsan
|
||||||
ACLOCAL = @ACLOCAL@
|
ACLOCAL = @ACLOCAL@
|
||||||
AMTAR = @AMTAR@
|
AMTAR = @AMTAR@
|
||||||
AR = @AR@
|
AR = @AR@
|
||||||
|
|
@ -209,9 +209,9 @@ top_build_prefix = @top_build_prefix@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
ACLOCAL_AMFLAGS = -I .. -I ../config
|
ACLOCAL_AMFLAGS = -I .. -I ../config
|
||||||
@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan
|
@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan ubsan
|
||||||
@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan
|
@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan ubsan
|
||||||
@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan
|
@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan ubsan
|
||||||
|
|
||||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||||
# values defined in terms of make variables, as is the case for CC and
|
# values defined in terms of make variables, as is the case for CC and
|
||||||
|
|
|
||||||
|
|
@ -14543,7 +14543,7 @@ fi
|
||||||
ac_config_files="$ac_config_files Makefile"
|
ac_config_files="$ac_config_files Makefile"
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile asan/Makefile"
|
ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile asan/Makefile ubsan/Makefile"
|
||||||
|
|
||||||
|
|
||||||
if test "x$TSAN_SUPPORTED" = "xyes"; then
|
if test "x$TSAN_SUPPORTED" = "xyes"; then
|
||||||
|
|
@ -15674,6 +15674,7 @@ do
|
||||||
"interception/Makefile") CONFIG_FILES="$CONFIG_FILES interception/Makefile" ;;
|
"interception/Makefile") CONFIG_FILES="$CONFIG_FILES interception/Makefile" ;;
|
||||||
"sanitizer_common/Makefile") CONFIG_FILES="$CONFIG_FILES sanitizer_common/Makefile" ;;
|
"sanitizer_common/Makefile") CONFIG_FILES="$CONFIG_FILES sanitizer_common/Makefile" ;;
|
||||||
"asan/Makefile") CONFIG_FILES="$CONFIG_FILES asan/Makefile" ;;
|
"asan/Makefile") CONFIG_FILES="$CONFIG_FILES asan/Makefile" ;;
|
||||||
|
"ubsan/Makefile") CONFIG_FILES="$CONFIG_FILES ubsan/Makefile" ;;
|
||||||
"tsan/Makefile") CONFIG_FILES="$CONFIG_FILES tsan/Makefile" ;;
|
"tsan/Makefile") CONFIG_FILES="$CONFIG_FILES tsan/Makefile" ;;
|
||||||
|
|
||||||
*) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
*) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||||
|
|
@ -17030,6 +17031,17 @@ _EOF
|
||||||
;;
|
;;
|
||||||
"asan/Makefile":F) cat > vpsed$$ << \_EOF
|
"asan/Makefile":F) cat > vpsed$$ << \_EOF
|
||||||
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
||||||
|
_EOF
|
||||||
|
sed -f vpsed$$ $ac_file > tmp$$
|
||||||
|
mv tmp$$ $ac_file
|
||||||
|
rm vpsed$$
|
||||||
|
echo 'MULTISUBDIR =' >> $ac_file
|
||||||
|
ml_norecursion=yes
|
||||||
|
. ${multi_basedir}/config-ml.in
|
||||||
|
{ ml_norecursion=; unset ml_norecursion;}
|
||||||
|
;;
|
||||||
|
"ubsan/Makefile":F) cat > vpsed$$ << \_EOF
|
||||||
|
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
||||||
_EOF
|
_EOF
|
||||||
sed -f vpsed$$ $ac_file > tmp$$
|
sed -f vpsed$$ $ac_file > tmp$$
|
||||||
mv tmp$$ $ac_file
|
mv tmp$$ $ac_file
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ AM_CONDITIONAL(USING_MAC_INTERPOSE, $MAC_INTERPOSE)
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
|
|
||||||
AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan], [DIR/Makefile ]),
|
AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan ubsan], [DIR/Makefile ]),
|
||||||
[cat > vpsed$$ << \_EOF
|
[cat > vpsed$$ << \_EOF
|
||||||
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
||||||
_EOF
|
_EOF
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ merge lib/asan asan
|
||||||
merge lib/tsan/rtl tsan
|
merge lib/tsan/rtl tsan
|
||||||
merge lib/sanitizer_common sanitizer_common
|
merge lib/sanitizer_common sanitizer_common
|
||||||
merge lib/interception interception
|
merge lib/interception interception
|
||||||
|
merge lib/ubsan ubsan
|
||||||
|
|
||||||
rm -rf upstream
|
rm -rf upstream
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#define SANITIZER_COMMON_H
|
#define SANITIZER_COMMON_H
|
||||||
|
|
||||||
#include "sanitizer_internal_defs.h"
|
#include "sanitizer_internal_defs.h"
|
||||||
|
#include "sanitizer_mutex.h"
|
||||||
|
|
||||||
namespace __sanitizer {
|
namespace __sanitizer {
|
||||||
struct StackTrace;
|
struct StackTrace;
|
||||||
|
|
@ -105,6 +106,8 @@ bool PrintsToTty();
|
||||||
void Printf(const char *format, ...);
|
void Printf(const char *format, ...);
|
||||||
void Report(const char *format, ...);
|
void Report(const char *format, ...);
|
||||||
void SetPrintfAndReportCallback(void (*callback)(const char *));
|
void SetPrintfAndReportCallback(void (*callback)(const char *));
|
||||||
|
// Can be used to prevent mixing error reports from different sanitizers.
|
||||||
|
extern StaticSpinMutex CommonSanitizerReportMutex;
|
||||||
|
|
||||||
fd_t OpenFile(const char *filename, bool write);
|
fd_t OpenFile(const char *filename, bool write);
|
||||||
// Opens the file 'file_name" and reads up to 'max_len' bytes.
|
// Opens the file 'file_name" and reads up to 'max_len' bytes.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
namespace __sanitizer {
|
namespace __sanitizer {
|
||||||
|
|
||||||
|
StaticSpinMutex CommonSanitizerReportMutex;
|
||||||
|
|
||||||
static int AppendChar(char **buff, const char *buff_end, char c) {
|
static int AppendChar(char **buff, const char *buff_end, char c) {
|
||||||
if (*buff < buff_end) {
|
if (*buff < buff_end) {
|
||||||
**buff = c;
|
**buff = c;
|
||||||
|
|
|
||||||
|
|
@ -12,24 +12,26 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef SANITIZER_ALLOCATOR_H
|
#ifndef SANITIZER_REPORT_DECORATOR_H
|
||||||
#define SANITIZER_ALLOCATOR_H
|
#define SANITIZER_REPORT_DECORATOR_H
|
||||||
|
|
||||||
namespace __sanitizer {
|
namespace __sanitizer {
|
||||||
class AnsiColorDecorator {
|
class AnsiColorDecorator {
|
||||||
public:
|
public:
|
||||||
explicit AnsiColorDecorator(bool use_ansi_colors) : ansi_(use_ansi_colors) { }
|
explicit AnsiColorDecorator(bool use_ansi_colors) : ansi_(use_ansi_colors) { }
|
||||||
const char *Black() { return ansi_ ? "\033[1m\033[30m" : ""; }
|
const char *Bold() const { return ansi_ ? "\033[1m" : ""; }
|
||||||
const char *Red() { return ansi_ ? "\033[1m\033[31m" : ""; }
|
const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; }
|
||||||
const char *Green() { return ansi_ ? "\033[1m\033[32m" : ""; }
|
const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; }
|
||||||
const char *Yellow() { return ansi_ ? "\033[1m\033[33m" : ""; }
|
const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; }
|
||||||
const char *Blue() { return ansi_ ? "\033[1m\033[34m" : ""; }
|
const char *Yellow() const { return ansi_ ? "\033[1m\033[33m" : ""; }
|
||||||
const char *Magenta() { return ansi_ ? "\033[1m\033[35m" : ""; }
|
const char *Blue() const { return ansi_ ? "\033[1m\033[34m" : ""; }
|
||||||
const char *Cyan() { return ansi_ ? "\033[1m\033[36m" : ""; }
|
const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; }
|
||||||
const char *White() { return ansi_ ? "\033[1m\033[37m" : ""; }
|
const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; }
|
||||||
const char *Default() { return ansi_ ? "\033[1m\033[0m" : ""; }
|
const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; }
|
||||||
|
const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; }
|
||||||
private:
|
private:
|
||||||
bool ansi_;
|
bool ansi_;
|
||||||
};
|
};
|
||||||
} // namespace __sanitizer
|
} // namespace __sanitizer
|
||||||
#endif // SANITIZER_ALLOCATOR_H
|
|
||||||
|
#endif // SANITIZER_REPORT_DECORATOR_H
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
AM_CPPFLAGS = -I $(top_srcdir) -I $(top_srcdir)/include
|
||||||
|
|
||||||
|
# May be used by toolexeclibdir.
|
||||||
|
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
|
||||||
|
|
||||||
|
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||||
|
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
|
||||||
|
AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
toolexeclib_LTLIBRARIES = libubsan.la
|
||||||
|
|
||||||
|
ubsan_files = \
|
||||||
|
ubsan_diag.cc \
|
||||||
|
ubsan_handlers.cc \
|
||||||
|
ubsan_handlers_cxx.cc \
|
||||||
|
ubsan_type_hash.cc \
|
||||||
|
ubsan_value.cc
|
||||||
|
|
||||||
|
libubsan_la_SOURCES = $(ubsan_files)
|
||||||
|
libubsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(LIBSTDCXX_RAW_CXX_LDFLAGS)
|
||||||
|
libubsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` -lpthread -ldl
|
||||||
|
|
||||||
|
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||||
|
# values defined in terms of make variables, as is the case for CC and
|
||||||
|
# friends when we are called from the top level Makefile.
|
||||||
|
AM_MAKEFLAGS = \
|
||||||
|
"AR_FLAGS=$(AR_FLAGS)" \
|
||||||
|
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||||
|
"CFLAGS=$(CFLAGS)" \
|
||||||
|
"CXXFLAGS=$(CXXFLAGS)" \
|
||||||
|
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||||
|
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||||
|
"INSTALL=$(INSTALL)" \
|
||||||
|
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||||
|
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||||
|
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||||
|
"JC1FLAGS=$(JC1FLAGS)" \
|
||||||
|
"LDFLAGS=$(LDFLAGS)" \
|
||||||
|
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||||
|
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||||
|
"MAKE=$(MAKE)" \
|
||||||
|
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||||
|
"PICFLAG=$(PICFLAG)" \
|
||||||
|
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||||
|
"SHELL=$(SHELL)" \
|
||||||
|
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||||
|
"exec_prefix=$(exec_prefix)" \
|
||||||
|
"infodir=$(infodir)" \
|
||||||
|
"libdir=$(libdir)" \
|
||||||
|
"prefix=$(prefix)" \
|
||||||
|
"includedir=$(includedir)" \
|
||||||
|
"AR=$(AR)" \
|
||||||
|
"AS=$(AS)" \
|
||||||
|
"LD=$(LD)" \
|
||||||
|
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||||
|
"NM=$(NM)" \
|
||||||
|
"PICFLAG=$(PICFLAG)" \
|
||||||
|
"RANLIB=$(RANLIB)" \
|
||||||
|
"DESTDIR=$(DESTDIR)"
|
||||||
|
|
||||||
|
MAKEOVERRIDES=
|
||||||
|
|
||||||
|
## ################################################################
|
||||||
|
|
||||||
|
|
@ -0,0 +1,578 @@
|
||||||
|
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||||
|
# @configure_input@
|
||||||
|
|
||||||
|
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||||
|
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||||
|
# Inc.
|
||||||
|
# This Makefile.in is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||||
|
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
pkgdatadir = $(datadir)/@PACKAGE@
|
||||||
|
pkgincludedir = $(includedir)/@PACKAGE@
|
||||||
|
pkglibdir = $(libdir)/@PACKAGE@
|
||||||
|
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||||
|
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||||
|
install_sh_DATA = $(install_sh) -c -m 644
|
||||||
|
install_sh_PROGRAM = $(install_sh) -c
|
||||||
|
install_sh_SCRIPT = $(install_sh) -c
|
||||||
|
INSTALL_HEADER = $(INSTALL_DATA)
|
||||||
|
transform = $(program_transform_name)
|
||||||
|
NORMAL_INSTALL = :
|
||||||
|
PRE_INSTALL = :
|
||||||
|
POST_INSTALL = :
|
||||||
|
NORMAL_UNINSTALL = :
|
||||||
|
PRE_UNINSTALL = :
|
||||||
|
POST_UNINSTALL = :
|
||||||
|
build_triplet = @build@
|
||||||
|
host_triplet = @host@
|
||||||
|
target_triplet = @target@
|
||||||
|
subdir = ubsan
|
||||||
|
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
|
||||||
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||||
|
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
||||||
|
$(top_srcdir)/../config/depstand.m4 \
|
||||||
|
$(top_srcdir)/../config/lead-dot.m4 \
|
||||||
|
$(top_srcdir)/../config/libstdc++-raw-cxx.m4 \
|
||||||
|
$(top_srcdir)/../config/multi.m4 \
|
||||||
|
$(top_srcdir)/../config/override.m4 \
|
||||||
|
$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
|
||||||
|
$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
|
||||||
|
$(top_srcdir)/acinclude.m4 $(top_srcdir)/../libtool.m4 \
|
||||||
|
$(top_srcdir)/configure.ac
|
||||||
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
|
$(ACLOCAL_M4)
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||||
|
CONFIG_CLEAN_FILES =
|
||||||
|
CONFIG_CLEAN_VPATH_FILES =
|
||||||
|
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||||
|
am__vpath_adj = case $$p in \
|
||||||
|
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||||
|
*) f=$$p;; \
|
||||||
|
esac;
|
||||||
|
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||||
|
am__install_max = 40
|
||||||
|
am__nobase_strip_setup = \
|
||||||
|
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||||
|
am__nobase_strip = \
|
||||||
|
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||||
|
am__nobase_list = $(am__nobase_strip_setup); \
|
||||||
|
for p in $$list; do echo "$$p $$p"; done | \
|
||||||
|
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||||
|
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||||
|
if (++n[$$2] == $(am__install_max)) \
|
||||||
|
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||||
|
END { for (dir in files) print dir, files[dir] }'
|
||||||
|
am__base_list = \
|
||||||
|
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||||
|
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||||
|
am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
|
||||||
|
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
|
||||||
|
am__DEPENDENCIES_1 =
|
||||||
|
libubsan_la_DEPENDENCIES = \
|
||||||
|
$(top_builddir)/sanitizer_common/libsanitizer_common.la \
|
||||||
|
$(top_builddir)/interception/libinterception.la \
|
||||||
|
$(am__DEPENDENCIES_1)
|
||||||
|
am__objects_1 = ubsan_diag.lo ubsan_handlers.lo ubsan_handlers_cxx.lo \
|
||||||
|
ubsan_type_hash.lo ubsan_value.lo
|
||||||
|
am_libubsan_la_OBJECTS = $(am__objects_1)
|
||||||
|
libubsan_la_OBJECTS = $(am_libubsan_la_OBJECTS)
|
||||||
|
libubsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
|
||||||
|
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
|
||||||
|
$(CXXFLAGS) $(libubsan_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||||
|
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||||
|
depcomp = $(SHELL) $(top_srcdir)/../depcomp
|
||||||
|
am__depfiles_maybe = depfiles
|
||||||
|
am__mv = mv -f
|
||||||
|
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||||
|
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||||
|
LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
|
--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||||
|
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||||
|
CXXLD = $(CXX)
|
||||||
|
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
|
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
|
||||||
|
$(LDFLAGS) -o $@
|
||||||
|
SOURCES = $(libubsan_la_SOURCES)
|
||||||
|
ETAGS = etags
|
||||||
|
CTAGS = ctags
|
||||||
|
ACLOCAL = @ACLOCAL@
|
||||||
|
AMTAR = @AMTAR@
|
||||||
|
AR = @AR@
|
||||||
|
AUTOCONF = @AUTOCONF@
|
||||||
|
AUTOHEADER = @AUTOHEADER@
|
||||||
|
AUTOMAKE = @AUTOMAKE@
|
||||||
|
AWK = @AWK@
|
||||||
|
CC = @CC@
|
||||||
|
CCAS = @CCAS@
|
||||||
|
CCASDEPMODE = @CCASDEPMODE@
|
||||||
|
CCASFLAGS = @CCASFLAGS@
|
||||||
|
CCDEPMODE = @CCDEPMODE@
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
|
CPP = @CPP@
|
||||||
|
CPPFLAGS = @CPPFLAGS@
|
||||||
|
CXX = @CXX@
|
||||||
|
CXXCPP = @CXXCPP@
|
||||||
|
CXXDEPMODE = @CXXDEPMODE@
|
||||||
|
CXXFLAGS = @CXXFLAGS@
|
||||||
|
CYGPATH_W = @CYGPATH_W@
|
||||||
|
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||||
|
DEPDIR = @DEPDIR@
|
||||||
|
DSYMUTIL = @DSYMUTIL@
|
||||||
|
DUMPBIN = @DUMPBIN@
|
||||||
|
ECHO_C = @ECHO_C@
|
||||||
|
ECHO_N = @ECHO_N@
|
||||||
|
ECHO_T = @ECHO_T@
|
||||||
|
EGREP = @EGREP@
|
||||||
|
EXEEXT = @EXEEXT@
|
||||||
|
FGREP = @FGREP@
|
||||||
|
GREP = @GREP@
|
||||||
|
INSTALL = @INSTALL@
|
||||||
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
|
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||||
|
LD = @LD@
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
LIBOBJS = @LIBOBJS@
|
||||||
|
LIBS = @LIBS@
|
||||||
|
LIBSTDCXX_RAW_CXX_CXXFLAGS = @LIBSTDCXX_RAW_CXX_CXXFLAGS@
|
||||||
|
LIBSTDCXX_RAW_CXX_LDFLAGS = @LIBSTDCXX_RAW_CXX_LDFLAGS@
|
||||||
|
LIBTOOL = @LIBTOOL@
|
||||||
|
LIPO = @LIPO@
|
||||||
|
LN_S = @LN_S@
|
||||||
|
LTLIBOBJS = @LTLIBOBJS@
|
||||||
|
MAINT = @MAINT@
|
||||||
|
MAKEINFO = @MAKEINFO@
|
||||||
|
MKDIR_P = @MKDIR_P@
|
||||||
|
NM = @NM@
|
||||||
|
NMEDIT = @NMEDIT@
|
||||||
|
OBJDUMP = @OBJDUMP@
|
||||||
|
OBJEXT = @OBJEXT@
|
||||||
|
OTOOL = @OTOOL@
|
||||||
|
OTOOL64 = @OTOOL64@
|
||||||
|
PACKAGE = @PACKAGE@
|
||||||
|
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||||
|
PACKAGE_NAME = @PACKAGE_NAME@
|
||||||
|
PACKAGE_STRING = @PACKAGE_STRING@
|
||||||
|
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||||
|
PACKAGE_URL = @PACKAGE_URL@
|
||||||
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
|
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||||
|
RANLIB = @RANLIB@
|
||||||
|
SED = @SED@
|
||||||
|
SET_MAKE = @SET_MAKE@
|
||||||
|
SHELL = @SHELL@
|
||||||
|
STRIP = @STRIP@
|
||||||
|
VERSION = @VERSION@
|
||||||
|
abs_builddir = @abs_builddir@
|
||||||
|
abs_srcdir = @abs_srcdir@
|
||||||
|
abs_top_builddir = @abs_top_builddir@
|
||||||
|
abs_top_srcdir = @abs_top_srcdir@
|
||||||
|
ac_ct_CC = @ac_ct_CC@
|
||||||
|
ac_ct_CXX = @ac_ct_CXX@
|
||||||
|
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||||
|
am__include = @am__include@
|
||||||
|
am__leading_dot = @am__leading_dot@
|
||||||
|
am__quote = @am__quote@
|
||||||
|
am__tar = @am__tar@
|
||||||
|
am__untar = @am__untar@
|
||||||
|
bindir = @bindir@
|
||||||
|
build = @build@
|
||||||
|
build_alias = @build_alias@
|
||||||
|
build_cpu = @build_cpu@
|
||||||
|
build_os = @build_os@
|
||||||
|
build_vendor = @build_vendor@
|
||||||
|
builddir = @builddir@
|
||||||
|
datadir = @datadir@
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
docdir = @docdir@
|
||||||
|
dvidir = @dvidir@
|
||||||
|
enable_shared = @enable_shared@
|
||||||
|
enable_static = @enable_static@
|
||||||
|
exec_prefix = @exec_prefix@
|
||||||
|
host = @host@
|
||||||
|
host_alias = @host_alias@
|
||||||
|
host_cpu = @host_cpu@
|
||||||
|
host_os = @host_os@
|
||||||
|
host_vendor = @host_vendor@
|
||||||
|
htmldir = @htmldir@
|
||||||
|
includedir = @includedir@
|
||||||
|
infodir = @infodir@
|
||||||
|
install_sh = @install_sh@
|
||||||
|
libdir = @libdir@
|
||||||
|
libexecdir = @libexecdir@
|
||||||
|
localedir = @localedir@
|
||||||
|
localstatedir = @localstatedir@
|
||||||
|
mandir = @mandir@
|
||||||
|
mkdir_p = @mkdir_p@
|
||||||
|
multi_basedir = @multi_basedir@
|
||||||
|
oldincludedir = @oldincludedir@
|
||||||
|
pdfdir = @pdfdir@
|
||||||
|
prefix = @prefix@
|
||||||
|
program_transform_name = @program_transform_name@
|
||||||
|
psdir = @psdir@
|
||||||
|
sbindir = @sbindir@
|
||||||
|
sharedstatedir = @sharedstatedir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
sysconfdir = @sysconfdir@
|
||||||
|
target = @target@
|
||||||
|
target_alias = @target_alias@
|
||||||
|
target_cpu = @target_cpu@
|
||||||
|
target_noncanonical = @target_noncanonical@
|
||||||
|
target_os = @target_os@
|
||||||
|
target_vendor = @target_vendor@
|
||||||
|
toolexecdir = @toolexecdir@
|
||||||
|
toolexeclibdir = @toolexeclibdir@
|
||||||
|
top_build_prefix = @top_build_prefix@
|
||||||
|
top_builddir = @top_builddir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
AM_CPPFLAGS = -I $(top_srcdir) -I $(top_srcdir)/include
|
||||||
|
|
||||||
|
# May be used by toolexeclibdir.
|
||||||
|
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
|
||||||
|
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
|
||||||
|
-Wno-long-long -fPIC -fno-builtin -fno-exceptions \
|
||||||
|
-fomit-frame-pointer -funwind-tables -fvisibility=hidden \
|
||||||
|
-Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
toolexeclib_LTLIBRARIES = libubsan.la
|
||||||
|
ubsan_files = \
|
||||||
|
ubsan_diag.cc \
|
||||||
|
ubsan_handlers.cc \
|
||||||
|
ubsan_handlers_cxx.cc \
|
||||||
|
ubsan_type_hash.cc \
|
||||||
|
ubsan_value.cc
|
||||||
|
|
||||||
|
libubsan_la_SOURCES = $(ubsan_files)
|
||||||
|
libubsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(LIBSTDCXX_RAW_CXX_LDFLAGS)
|
||||||
|
libubsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` -lpthread -ldl
|
||||||
|
|
||||||
|
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||||
|
# values defined in terms of make variables, as is the case for CC and
|
||||||
|
# friends when we are called from the top level Makefile.
|
||||||
|
AM_MAKEFLAGS = \
|
||||||
|
"AR_FLAGS=$(AR_FLAGS)" \
|
||||||
|
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||||
|
"CFLAGS=$(CFLAGS)" \
|
||||||
|
"CXXFLAGS=$(CXXFLAGS)" \
|
||||||
|
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||||
|
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||||
|
"INSTALL=$(INSTALL)" \
|
||||||
|
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||||
|
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||||
|
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||||
|
"JC1FLAGS=$(JC1FLAGS)" \
|
||||||
|
"LDFLAGS=$(LDFLAGS)" \
|
||||||
|
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||||
|
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||||
|
"MAKE=$(MAKE)" \
|
||||||
|
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||||
|
"PICFLAG=$(PICFLAG)" \
|
||||||
|
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||||
|
"SHELL=$(SHELL)" \
|
||||||
|
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||||
|
"exec_prefix=$(exec_prefix)" \
|
||||||
|
"infodir=$(infodir)" \
|
||||||
|
"libdir=$(libdir)" \
|
||||||
|
"prefix=$(prefix)" \
|
||||||
|
"includedir=$(includedir)" \
|
||||||
|
"AR=$(AR)" \
|
||||||
|
"AS=$(AS)" \
|
||||||
|
"LD=$(LD)" \
|
||||||
|
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||||
|
"NM=$(NM)" \
|
||||||
|
"PICFLAG=$(PICFLAG)" \
|
||||||
|
"RANLIB=$(RANLIB)" \
|
||||||
|
"DESTDIR=$(DESTDIR)"
|
||||||
|
|
||||||
|
MAKEOVERRIDES =
|
||||||
|
all: all-am
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .cc .lo .o .obj
|
||||||
|
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||||
|
@for dep in $?; do \
|
||||||
|
case '$(am__configure_deps)' in \
|
||||||
|
*$$dep*) \
|
||||||
|
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||||
|
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||||
|
exit 1;; \
|
||||||
|
esac; \
|
||||||
|
done; \
|
||||||
|
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ubsan/Makefile'; \
|
||||||
|
$(am__cd) $(top_srcdir) && \
|
||||||
|
$(AUTOMAKE) --foreign ubsan/Makefile
|
||||||
|
.PRECIOUS: Makefile
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
@case '$?' in \
|
||||||
|
*config.status*) \
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||||
|
*) \
|
||||||
|
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||||
|
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||||
|
esac;
|
||||||
|
|
||||||
|
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||||
|
|
||||||
|
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||||
|
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||||
|
$(am__aclocal_m4_deps):
|
||||||
|
install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
|
||||||
|
@$(NORMAL_INSTALL)
|
||||||
|
test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
|
||||||
|
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
|
||||||
|
list2=; for p in $$list; do \
|
||||||
|
if test -f $$p; then \
|
||||||
|
list2="$$list2 $$p"; \
|
||||||
|
else :; fi; \
|
||||||
|
done; \
|
||||||
|
test -z "$$list2" || { \
|
||||||
|
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
|
||||||
|
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \
|
||||||
|
}
|
||||||
|
|
||||||
|
uninstall-toolexeclibLTLIBRARIES:
|
||||||
|
@$(NORMAL_UNINSTALL)
|
||||||
|
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
|
||||||
|
for p in $$list; do \
|
||||||
|
$(am__strip_dir) \
|
||||||
|
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \
|
||||||
|
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
clean-toolexeclibLTLIBRARIES:
|
||||||
|
-test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES)
|
||||||
|
@list='$(toolexeclib_LTLIBRARIES)'; for p in $$list; do \
|
||||||
|
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||||
|
test "$$dir" != "$$p" || dir=.; \
|
||||||
|
echo "rm -f \"$${dir}/so_locations\""; \
|
||||||
|
rm -f "$${dir}/so_locations"; \
|
||||||
|
done
|
||||||
|
libubsan.la: $(libubsan_la_OBJECTS) $(libubsan_la_DEPENDENCIES)
|
||||||
|
$(libubsan_la_LINK) -rpath $(toolexeclibdir) $(libubsan_la_OBJECTS) $(libubsan_la_LIBADD) $(LIBS)
|
||||||
|
|
||||||
|
mostlyclean-compile:
|
||||||
|
-rm -f *.$(OBJEXT)
|
||||||
|
|
||||||
|
distclean-compile:
|
||||||
|
-rm -f *.tab.c
|
||||||
|
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_diag.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_handlers.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_handlers_cxx.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_type_hash.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_value.Plo@am__quote@
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
|
||||||
|
|
||||||
|
.cc.obj:
|
||||||
|
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||||
|
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||||
|
|
||||||
|
.cc.lo:
|
||||||
|
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
|
||||||
|
|
||||||
|
mostlyclean-libtool:
|
||||||
|
-rm -f *.lo
|
||||||
|
|
||||||
|
clean-libtool:
|
||||||
|
-rm -rf .libs _libs
|
||||||
|
|
||||||
|
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||||
|
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||||
|
unique=`for i in $$list; do \
|
||||||
|
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||||
|
done | \
|
||||||
|
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||||
|
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||||
|
mkid -fID $$unique
|
||||||
|
tags: TAGS
|
||||||
|
|
||||||
|
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||||
|
$(TAGS_FILES) $(LISP)
|
||||||
|
set x; \
|
||||||
|
here=`pwd`; \
|
||||||
|
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||||
|
unique=`for i in $$list; do \
|
||||||
|
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||||
|
done | \
|
||||||
|
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||||
|
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||||
|
shift; \
|
||||||
|
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||||
|
test -n "$$unique" || unique=$$empty_fix; \
|
||||||
|
if test $$# -gt 0; then \
|
||||||
|
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||||
|
"$$@" $$unique; \
|
||||||
|
else \
|
||||||
|
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||||
|
$$unique; \
|
||||||
|
fi; \
|
||||||
|
fi
|
||||||
|
ctags: CTAGS
|
||||||
|
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||||
|
$(TAGS_FILES) $(LISP)
|
||||||
|
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||||
|
unique=`for i in $$list; do \
|
||||||
|
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||||
|
done | \
|
||||||
|
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||||
|
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||||
|
test -z "$(CTAGS_ARGS)$$unique" \
|
||||||
|
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||||
|
$$unique
|
||||||
|
|
||||||
|
GTAGS:
|
||||||
|
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||||
|
&& $(am__cd) $(top_srcdir) \
|
||||||
|
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||||
|
|
||||||
|
distclean-tags:
|
||||||
|
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||||
|
check-am: all-am
|
||||||
|
check: check-am
|
||||||
|
all-am: Makefile $(LTLIBRARIES)
|
||||||
|
installdirs:
|
||||||
|
for dir in "$(DESTDIR)$(toolexeclibdir)"; do \
|
||||||
|
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||||
|
done
|
||||||
|
install: install-am
|
||||||
|
install-exec: install-exec-am
|
||||||
|
install-data: install-data-am
|
||||||
|
uninstall: uninstall-am
|
||||||
|
|
||||||
|
install-am: all-am
|
||||||
|
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||||
|
|
||||||
|
installcheck: installcheck-am
|
||||||
|
install-strip:
|
||||||
|
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||||
|
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||||
|
`test -z '$(STRIP)' || \
|
||||||
|
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||||
|
mostlyclean-generic:
|
||||||
|
|
||||||
|
clean-generic:
|
||||||
|
|
||||||
|
distclean-generic:
|
||||||
|
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||||
|
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||||
|
|
||||||
|
maintainer-clean-generic:
|
||||||
|
@echo "This command is intended for maintainers to use"
|
||||||
|
@echo "it deletes files that may require special tools to rebuild."
|
||||||
|
clean: clean-am
|
||||||
|
|
||||||
|
clean-am: clean-generic clean-libtool clean-toolexeclibLTLIBRARIES \
|
||||||
|
mostlyclean-am
|
||||||
|
|
||||||
|
distclean: distclean-am
|
||||||
|
-rm -rf ./$(DEPDIR)
|
||||||
|
-rm -f Makefile
|
||||||
|
distclean-am: clean-am distclean-compile distclean-generic \
|
||||||
|
distclean-tags
|
||||||
|
|
||||||
|
dvi: dvi-am
|
||||||
|
|
||||||
|
dvi-am:
|
||||||
|
|
||||||
|
html: html-am
|
||||||
|
|
||||||
|
html-am:
|
||||||
|
|
||||||
|
info: info-am
|
||||||
|
|
||||||
|
info-am:
|
||||||
|
|
||||||
|
install-data-am:
|
||||||
|
|
||||||
|
install-dvi: install-dvi-am
|
||||||
|
|
||||||
|
install-dvi-am:
|
||||||
|
|
||||||
|
install-exec-am: install-toolexeclibLTLIBRARIES
|
||||||
|
|
||||||
|
install-html: install-html-am
|
||||||
|
|
||||||
|
install-html-am:
|
||||||
|
|
||||||
|
install-info: install-info-am
|
||||||
|
|
||||||
|
install-info-am:
|
||||||
|
|
||||||
|
install-man:
|
||||||
|
|
||||||
|
install-pdf: install-pdf-am
|
||||||
|
|
||||||
|
install-pdf-am:
|
||||||
|
|
||||||
|
install-ps: install-ps-am
|
||||||
|
|
||||||
|
install-ps-am:
|
||||||
|
|
||||||
|
installcheck-am:
|
||||||
|
|
||||||
|
maintainer-clean: maintainer-clean-am
|
||||||
|
-rm -rf ./$(DEPDIR)
|
||||||
|
-rm -f Makefile
|
||||||
|
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||||
|
|
||||||
|
mostlyclean: mostlyclean-am
|
||||||
|
|
||||||
|
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||||
|
mostlyclean-libtool
|
||||||
|
|
||||||
|
pdf: pdf-am
|
||||||
|
|
||||||
|
pdf-am:
|
||||||
|
|
||||||
|
ps: ps-am
|
||||||
|
|
||||||
|
ps-am:
|
||||||
|
|
||||||
|
uninstall-am: uninstall-toolexeclibLTLIBRARIES
|
||||||
|
|
||||||
|
.MAKE: install-am install-strip
|
||||||
|
|
||||||
|
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||||
|
clean-libtool clean-toolexeclibLTLIBRARIES ctags distclean \
|
||||||
|
distclean-compile distclean-generic distclean-libtool \
|
||||||
|
distclean-tags dvi dvi-am html html-am info info-am install \
|
||||||
|
install-am install-data install-data-am install-dvi \
|
||||||
|
install-dvi-am install-exec install-exec-am install-html \
|
||||||
|
install-html-am install-info install-info-am install-man \
|
||||||
|
install-pdf install-pdf-am install-ps install-ps-am \
|
||||||
|
install-strip install-toolexeclibLTLIBRARIES installcheck \
|
||||||
|
installcheck-am installdirs maintainer-clean \
|
||||||
|
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||||
|
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||||
|
tags uninstall uninstall-am uninstall-toolexeclibLTLIBRARIES
|
||||||
|
|
||||||
|
|
||||||
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||||
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||||
|
.NOEXPORT:
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# This file is used to maintain libtool version info for libmudflap. See
|
||||||
|
# the libtool manual to understand the meaning of the fields. This is
|
||||||
|
# a separate file so that version updates don't involve re-running
|
||||||
|
# automake.
|
||||||
|
# CURRENT:REVISION:AGE
|
||||||
|
0:0:0
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
//===-- ubsan_diag.cc -----------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Diagnostic reporting for the UBSan runtime.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ubsan_diag.h"
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
#include "sanitizer_common/sanitizer_libc.h"
|
||||||
|
#include "sanitizer_common/sanitizer_report_decorator.h"
|
||||||
|
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||||
|
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace __ubsan;
|
||||||
|
|
||||||
|
Location __ubsan::getCallerLocation(uptr CallerLoc) {
|
||||||
|
if (!CallerLoc)
|
||||||
|
return Location();
|
||||||
|
|
||||||
|
uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
|
||||||
|
|
||||||
|
AddressInfo Info;
|
||||||
|
if (!SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module)
|
||||||
|
return Location(Loc);
|
||||||
|
|
||||||
|
if (!Info.file)
|
||||||
|
return ModuleLocation(Info.module, Info.module_offset);
|
||||||
|
|
||||||
|
return SourceLocation(Info.file, Info.line, Info.column);
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag &Diag::operator<<(const TypeDescriptor &V) {
|
||||||
|
return AddArg(V.getTypeName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag &Diag::operator<<(const Value &V) {
|
||||||
|
if (V.getType().isSignedIntegerTy())
|
||||||
|
AddArg(V.getSIntValue());
|
||||||
|
else if (V.getType().isUnsignedIntegerTy())
|
||||||
|
AddArg(V.getUIntValue());
|
||||||
|
else if (V.getType().isFloatTy())
|
||||||
|
AddArg(V.getFloatValue());
|
||||||
|
else
|
||||||
|
AddArg("<unknown>");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hexadecimal printing for numbers too large for Printf to handle directly.
|
||||||
|
static void PrintHex(UIntMax Val) {
|
||||||
|
#if HAVE_INT128_T
|
||||||
|
Printf("0x%08x%08x%08x%08x",
|
||||||
|
(unsigned int)(Val >> 96),
|
||||||
|
(unsigned int)(Val >> 64),
|
||||||
|
(unsigned int)(Val >> 32),
|
||||||
|
(unsigned int)(Val));
|
||||||
|
#else
|
||||||
|
UNREACHABLE("long long smaller than 64 bits?");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderLocation(Location Loc) {
|
||||||
|
switch (Loc.getKind()) {
|
||||||
|
case Location::LK_Source: {
|
||||||
|
SourceLocation SLoc = Loc.getSourceLocation();
|
||||||
|
if (SLoc.isInvalid())
|
||||||
|
Printf("<unknown>:");
|
||||||
|
else {
|
||||||
|
Printf("%s:%d:", SLoc.getFilename(), SLoc.getLine());
|
||||||
|
if (SLoc.getColumn())
|
||||||
|
Printf("%d:", SLoc.getColumn());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Location::LK_Module:
|
||||||
|
Printf("%s:0x%zx:", Loc.getModuleLocation().getModuleName(),
|
||||||
|
Loc.getModuleLocation().getOffset());
|
||||||
|
break;
|
||||||
|
case Location::LK_Memory:
|
||||||
|
Printf("%p:", Loc.getMemoryLocation());
|
||||||
|
break;
|
||||||
|
case Location::LK_Null:
|
||||||
|
Printf("<unknown>:");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderText(const char *Message, const Diag::Arg *Args) {
|
||||||
|
for (const char *Msg = Message; *Msg; ++Msg) {
|
||||||
|
if (*Msg != '%') {
|
||||||
|
char Buffer[64];
|
||||||
|
unsigned I;
|
||||||
|
for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
|
||||||
|
Buffer[I] = Msg[I];
|
||||||
|
Buffer[I] = '\0';
|
||||||
|
Printf(Buffer);
|
||||||
|
Msg += I - 1;
|
||||||
|
} else {
|
||||||
|
const Diag::Arg &A = Args[*++Msg - '0'];
|
||||||
|
switch (A.Kind) {
|
||||||
|
case Diag::AK_String:
|
||||||
|
Printf("%s", A.String);
|
||||||
|
break;
|
||||||
|
case Diag::AK_Mangled: {
|
||||||
|
Printf("'%s'", Demangle(A.String));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Diag::AK_SInt:
|
||||||
|
// 'long long' is guaranteed to be at least 64 bits wide.
|
||||||
|
if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
|
||||||
|
Printf("%lld", (long long)A.SInt);
|
||||||
|
else
|
||||||
|
PrintHex(A.SInt);
|
||||||
|
break;
|
||||||
|
case Diag::AK_UInt:
|
||||||
|
if (A.UInt <= UINT64_MAX)
|
||||||
|
Printf("%llu", (unsigned long long)A.UInt);
|
||||||
|
else
|
||||||
|
PrintHex(A.UInt);
|
||||||
|
break;
|
||||||
|
case Diag::AK_Float: {
|
||||||
|
// FIXME: Support floating-point formatting in sanitizer_common's
|
||||||
|
// printf, and stop using snprintf here.
|
||||||
|
char Buffer[32];
|
||||||
|
snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
|
||||||
|
Printf("%s", Buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Diag::AK_Pointer:
|
||||||
|
Printf("%p", A.Pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the earliest-starting range in Ranges which ends after Loc.
|
||||||
|
static Range *upperBound(MemoryLocation Loc, Range *Ranges,
|
||||||
|
unsigned NumRanges) {
|
||||||
|
Range *Best = 0;
|
||||||
|
for (unsigned I = 0; I != NumRanges; ++I)
|
||||||
|
if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
|
||||||
|
(!Best ||
|
||||||
|
Best->getStart().getMemoryLocation() >
|
||||||
|
Ranges[I].getStart().getMemoryLocation()))
|
||||||
|
Best = &Ranges[I];
|
||||||
|
return Best;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a snippet of the address space near a location.
|
||||||
|
static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
|
||||||
|
MemoryLocation Loc,
|
||||||
|
Range *Ranges, unsigned NumRanges,
|
||||||
|
const Diag::Arg *Args) {
|
||||||
|
const unsigned BytesToShow = 32;
|
||||||
|
const unsigned MinBytesNearLoc = 4;
|
||||||
|
|
||||||
|
// Show at least the 8 bytes surrounding Loc.
|
||||||
|
MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
|
||||||
|
for (unsigned I = 0; I < NumRanges; ++I) {
|
||||||
|
Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
|
||||||
|
Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have too many interesting bytes, prefer to show bytes after Loc.
|
||||||
|
if (Max - Min > BytesToShow)
|
||||||
|
Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
|
||||||
|
Max = Min + BytesToShow;
|
||||||
|
|
||||||
|
// Emit data.
|
||||||
|
for (uptr P = Min; P != Max; ++P) {
|
||||||
|
// FIXME: Check that the address is readable before printing it.
|
||||||
|
unsigned char C = *reinterpret_cast<const unsigned char*>(P);
|
||||||
|
Printf("%s%02x", (P % 8 == 0) ? " " : " ", C);
|
||||||
|
}
|
||||||
|
Printf("\n");
|
||||||
|
|
||||||
|
// Emit highlights.
|
||||||
|
Printf(Decor.Green());
|
||||||
|
Range *InRange = upperBound(Min, Ranges, NumRanges);
|
||||||
|
for (uptr P = Min; P != Max; ++P) {
|
||||||
|
char Pad = ' ', Byte = ' ';
|
||||||
|
if (InRange && InRange->getEnd().getMemoryLocation() == P)
|
||||||
|
InRange = upperBound(P, Ranges, NumRanges);
|
||||||
|
if (!InRange && P > Loc)
|
||||||
|
break;
|
||||||
|
if (InRange && InRange->getStart().getMemoryLocation() < P)
|
||||||
|
Pad = '~';
|
||||||
|
if (InRange && InRange->getStart().getMemoryLocation() <= P)
|
||||||
|
Byte = '~';
|
||||||
|
char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
|
||||||
|
Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
|
||||||
|
}
|
||||||
|
Printf("%s\n", Decor.Default());
|
||||||
|
|
||||||
|
// Go over the line again, and print names for the ranges.
|
||||||
|
InRange = 0;
|
||||||
|
unsigned Spaces = 0;
|
||||||
|
for (uptr P = Min; P != Max; ++P) {
|
||||||
|
if (!InRange || InRange->getEnd().getMemoryLocation() == P)
|
||||||
|
InRange = upperBound(P, Ranges, NumRanges);
|
||||||
|
if (!InRange)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Spaces += (P % 8) == 0 ? 2 : 1;
|
||||||
|
|
||||||
|
if (InRange && InRange->getStart().getMemoryLocation() == P) {
|
||||||
|
while (Spaces--)
|
||||||
|
Printf(" ");
|
||||||
|
renderText(InRange->getText(), Args);
|
||||||
|
Printf("\n");
|
||||||
|
// FIXME: We only support naming one range for now!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spaces += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Print names for anything we can identify within the line:
|
||||||
|
//
|
||||||
|
// * If we can identify the memory itself as belonging to a particular
|
||||||
|
// global, stack variable, or dynamic allocation, then do so.
|
||||||
|
//
|
||||||
|
// * If we have a pointer-size, pointer-aligned range highlighted,
|
||||||
|
// determine whether the value of that range is a pointer to an
|
||||||
|
// entity which we can name, and if so, print that name.
|
||||||
|
//
|
||||||
|
// This needs an external symbolizer, or (preferably) ASan instrumentation.
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag::~Diag() {
|
||||||
|
__sanitizer::AnsiColorDecorator Decor(PrintsToTty());
|
||||||
|
SpinMutexLock l(&CommonSanitizerReportMutex);
|
||||||
|
Printf(Decor.Bold());
|
||||||
|
|
||||||
|
renderLocation(Loc);
|
||||||
|
|
||||||
|
switch (Level) {
|
||||||
|
case DL_Error:
|
||||||
|
Printf("%s runtime error: %s%s",
|
||||||
|
Decor.Red(), Decor.Default(), Decor.Bold());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DL_Note:
|
||||||
|
Printf("%s note: %s", Decor.Black(), Decor.Default());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderText(Message, Args);
|
||||||
|
|
||||||
|
Printf("%s\n", Decor.Default());
|
||||||
|
|
||||||
|
if (Loc.isMemoryLocation())
|
||||||
|
renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
|
||||||
|
NumRanges, Args);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
//===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Diagnostics emission for Clang's undefined behavior sanitizer.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#ifndef UBSAN_DIAG_H
|
||||||
|
#define UBSAN_DIAG_H
|
||||||
|
|
||||||
|
#include "ubsan_value.h"
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
|
||||||
|
/// \brief A location within a loaded module in the program. These are used when
|
||||||
|
/// the location can't be resolved to a SourceLocation.
|
||||||
|
class ModuleLocation {
|
||||||
|
const char *ModuleName;
|
||||||
|
uptr Offset;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModuleLocation() : ModuleName(0), Offset(0) {}
|
||||||
|
ModuleLocation(const char *ModuleName, uptr Offset)
|
||||||
|
: ModuleName(ModuleName), Offset(Offset) {}
|
||||||
|
const char *getModuleName() const { return ModuleName; }
|
||||||
|
uptr getOffset() const { return Offset; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A location of some data within the program's address space.
|
||||||
|
typedef uptr MemoryLocation;
|
||||||
|
|
||||||
|
/// \brief Location at which a diagnostic can be emitted. Either a
|
||||||
|
/// SourceLocation, a ModuleLocation, or a MemoryLocation.
|
||||||
|
class Location {
|
||||||
|
public:
|
||||||
|
enum LocationKind { LK_Null, LK_Source, LK_Module, LK_Memory };
|
||||||
|
|
||||||
|
private:
|
||||||
|
LocationKind Kind;
|
||||||
|
// FIXME: In C++11, wrap these in an anonymous union.
|
||||||
|
SourceLocation SourceLoc;
|
||||||
|
ModuleLocation ModuleLoc;
|
||||||
|
MemoryLocation MemoryLoc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Location() : Kind(LK_Null) {}
|
||||||
|
Location(SourceLocation Loc) :
|
||||||
|
Kind(LK_Source), SourceLoc(Loc) {}
|
||||||
|
Location(ModuleLocation Loc) :
|
||||||
|
Kind(LK_Module), ModuleLoc(Loc) {}
|
||||||
|
Location(MemoryLocation Loc) :
|
||||||
|
Kind(LK_Memory), MemoryLoc(Loc) {}
|
||||||
|
|
||||||
|
LocationKind getKind() const { return Kind; }
|
||||||
|
|
||||||
|
bool isSourceLocation() const { return Kind == LK_Source; }
|
||||||
|
bool isModuleLocation() const { return Kind == LK_Module; }
|
||||||
|
bool isMemoryLocation() const { return Kind == LK_Memory; }
|
||||||
|
|
||||||
|
SourceLocation getSourceLocation() const {
|
||||||
|
CHECK(isSourceLocation());
|
||||||
|
return SourceLoc;
|
||||||
|
}
|
||||||
|
ModuleLocation getModuleLocation() const {
|
||||||
|
CHECK(isModuleLocation());
|
||||||
|
return ModuleLoc;
|
||||||
|
}
|
||||||
|
MemoryLocation getMemoryLocation() const {
|
||||||
|
CHECK(isMemoryLocation());
|
||||||
|
return MemoryLoc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Try to obtain a location for the caller. This might fail, and produce either
|
||||||
|
/// an invalid location or a module location for the caller.
|
||||||
|
Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC());
|
||||||
|
|
||||||
|
/// A diagnostic severity level.
|
||||||
|
enum DiagLevel {
|
||||||
|
DL_Error, ///< An error.
|
||||||
|
DL_Note ///< A note, attached to a prior diagnostic.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Annotation for a range of locations in a diagnostic.
|
||||||
|
class Range {
|
||||||
|
Location Start, End;
|
||||||
|
const char *Text;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Range() : Start(), End(), Text() {}
|
||||||
|
Range(MemoryLocation Start, MemoryLocation End, const char *Text)
|
||||||
|
: Start(Start), End(End), Text(Text) {}
|
||||||
|
Location getStart() const { return Start; }
|
||||||
|
Location getEnd() const { return End; }
|
||||||
|
const char *getText() const { return Text; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A mangled C++ name. Really just a strong typedef for 'const char*'.
|
||||||
|
class MangledName {
|
||||||
|
const char *Name;
|
||||||
|
public:
|
||||||
|
MangledName(const char *Name) : Name(Name) {}
|
||||||
|
const char *getName() const { return Name; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Representation of an in-flight diagnostic.
|
||||||
|
///
|
||||||
|
/// Temporary \c Diag instances are created by the handler routines to
|
||||||
|
/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
|
||||||
|
/// message.
|
||||||
|
class Diag {
|
||||||
|
/// The location at which the problem occurred.
|
||||||
|
Location Loc;
|
||||||
|
|
||||||
|
/// The diagnostic level.
|
||||||
|
DiagLevel Level;
|
||||||
|
|
||||||
|
/// The message which will be emitted, with %0, %1, ... placeholders for
|
||||||
|
/// arguments.
|
||||||
|
const char *Message;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Kinds of arguments, corresponding to members of \c Arg's union.
|
||||||
|
enum ArgKind {
|
||||||
|
AK_String, ///< A string argument, displayed as-is.
|
||||||
|
AK_Mangled,///< A C++ mangled name, demangled before display.
|
||||||
|
AK_UInt, ///< An unsigned integer argument.
|
||||||
|
AK_SInt, ///< A signed integer argument.
|
||||||
|
AK_Float, ///< A floating-point argument.
|
||||||
|
AK_Pointer ///< A pointer argument, displayed in hexadecimal.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An individual diagnostic message argument.
|
||||||
|
struct Arg {
|
||||||
|
Arg() {}
|
||||||
|
Arg(const char *String) : Kind(AK_String), String(String) {}
|
||||||
|
Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {}
|
||||||
|
Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
|
||||||
|
Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
|
||||||
|
Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
|
||||||
|
Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
|
||||||
|
|
||||||
|
ArgKind Kind;
|
||||||
|
union {
|
||||||
|
const char *String;
|
||||||
|
UIntMax UInt;
|
||||||
|
SIntMax SInt;
|
||||||
|
FloatMax Float;
|
||||||
|
const void *Pointer;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const unsigned MaxArgs = 5;
|
||||||
|
static const unsigned MaxRanges = 1;
|
||||||
|
|
||||||
|
/// The arguments which have been added to this diagnostic so far.
|
||||||
|
Arg Args[MaxArgs];
|
||||||
|
unsigned NumArgs;
|
||||||
|
|
||||||
|
/// The ranges which have been added to this diagnostic so far.
|
||||||
|
Range Ranges[MaxRanges];
|
||||||
|
unsigned NumRanges;
|
||||||
|
|
||||||
|
Diag &AddArg(Arg A) {
|
||||||
|
CHECK(NumArgs != MaxArgs);
|
||||||
|
Args[NumArgs++] = A;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag &AddRange(Range A) {
|
||||||
|
CHECK(NumRanges != MaxRanges);
|
||||||
|
Ranges[NumRanges++] = A;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \c Diag objects are not copyable.
|
||||||
|
Diag(const Diag &); // NOT IMPLEMENTED
|
||||||
|
Diag &operator=(const Diag &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Diag(Location Loc, DiagLevel Level, const char *Message)
|
||||||
|
: Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
|
||||||
|
~Diag();
|
||||||
|
|
||||||
|
Diag &operator<<(const char *Str) { return AddArg(Str); }
|
||||||
|
Diag &operator<<(MangledName MN) { return AddArg(MN); }
|
||||||
|
Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
|
||||||
|
Diag &operator<<(const void *V) { return AddArg(V); }
|
||||||
|
Diag &operator<<(const TypeDescriptor &V);
|
||||||
|
Diag &operator<<(const Value &V);
|
||||||
|
Diag &operator<<(const Range &R) { return AddRange(R); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace __ubsan
|
||||||
|
|
||||||
|
#endif // UBSAN_DIAG_H
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
//===-- ubsan_handlers.cc -------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Error logging entry points for the UBSan runtime.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ubsan_handlers.h"
|
||||||
|
#include "ubsan_diag.h"
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
|
using namespace __sanitizer;
|
||||||
|
using namespace __ubsan;
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
const char *TypeCheckKinds[] = {
|
||||||
|
"load of", "store to", "reference binding to", "member access within",
|
||||||
|
"member call on", "constructor call on", "downcast of", "downcast of"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
|
||||||
|
Location FallbackLoc) {
|
||||||
|
Location Loc = Data->Loc.acquire();
|
||||||
|
|
||||||
|
// Use the SourceLocation from Data to track deduplication, even if 'invalid'
|
||||||
|
if (Loc.getSourceLocation().isDisabled())
|
||||||
|
return;
|
||||||
|
if (Data->Loc.isInvalid())
|
||||||
|
Loc = FallbackLoc;
|
||||||
|
|
||||||
|
if (!Pointer)
|
||||||
|
Diag(Loc, DL_Error, "%0 null pointer of type %1")
|
||||||
|
<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
|
||||||
|
else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
|
||||||
|
Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
|
||||||
|
"which requires %2 byte alignment")
|
||||||
|
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
|
||||||
|
<< Data->Alignment << Data->Type;
|
||||||
|
else
|
||||||
|
Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
|
||||||
|
"for an object of type %2")
|
||||||
|
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
|
||||||
|
if (Pointer)
|
||||||
|
Diag(Pointer, DL_Note, "pointer points here");
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
|
||||||
|
ValueHandle Pointer) {
|
||||||
|
handleTypeMismatchImpl(Data, Pointer, getCallerLocation());
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
|
||||||
|
ValueHandle Pointer) {
|
||||||
|
handleTypeMismatchImpl(Data, Pointer, getCallerLocation());
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Common diagnostic emission for various forms of integer overflow.
|
||||||
|
template<typename T> static void HandleIntegerOverflow(OverflowData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
const char *Operator,
|
||||||
|
T RHS) {
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Diag(Loc, DL_Error, "%0 integer overflow: "
|
||||||
|
"%1 %2 %3 cannot be represented in type %4")
|
||||||
|
<< (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
|
||||||
|
<< Value(Data->Type, LHS) << Operator << RHS << Data->Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_add_overflow(OverflowData *Data,
|
||||||
|
ValueHandle LHS, ValueHandle RHS) {
|
||||||
|
HandleIntegerOverflow(Data, LHS, "+", Value(Data->Type, RHS));
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_add_overflow_abort(OverflowData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
ValueHandle RHS) {
|
||||||
|
__ubsan_handle_add_overflow(Data, LHS, RHS);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_sub_overflow(OverflowData *Data,
|
||||||
|
ValueHandle LHS, ValueHandle RHS) {
|
||||||
|
HandleIntegerOverflow(Data, LHS, "-", Value(Data->Type, RHS));
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_sub_overflow_abort(OverflowData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
ValueHandle RHS) {
|
||||||
|
__ubsan_handle_sub_overflow(Data, LHS, RHS);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_mul_overflow(OverflowData *Data,
|
||||||
|
ValueHandle LHS, ValueHandle RHS) {
|
||||||
|
HandleIntegerOverflow(Data, LHS, "*", Value(Data->Type, RHS));
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_mul_overflow_abort(OverflowData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
ValueHandle RHS) {
|
||||||
|
__ubsan_handle_mul_overflow(Data, LHS, RHS);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
|
||||||
|
ValueHandle OldVal) {
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Data->Type.isSignedIntegerTy())
|
||||||
|
Diag(Loc, DL_Error,
|
||||||
|
"negation of %0 cannot be represented in type %1; "
|
||||||
|
"cast to an unsigned type to negate this value to itself")
|
||||||
|
<< Value(Data->Type, OldVal) << Data->Type;
|
||||||
|
else
|
||||||
|
Diag(Loc, DL_Error,
|
||||||
|
"negation of %0 cannot be represented in type %1")
|
||||||
|
<< Value(Data->Type, OldVal) << Data->Type;
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
|
||||||
|
ValueHandle OldVal) {
|
||||||
|
__ubsan_handle_negate_overflow(Data, OldVal);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
|
||||||
|
ValueHandle LHS, ValueHandle RHS) {
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Value LHSVal(Data->Type, LHS);
|
||||||
|
Value RHSVal(Data->Type, RHS);
|
||||||
|
if (RHSVal.isMinusOne())
|
||||||
|
Diag(Loc, DL_Error,
|
||||||
|
"division of %0 by -1 cannot be represented in type %1")
|
||||||
|
<< LHSVal << Data->Type;
|
||||||
|
else
|
||||||
|
Diag(Loc, DL_Error, "division by zero");
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
ValueHandle RHS) {
|
||||||
|
__ubsan_handle_divrem_overflow(Data, LHS, RHS);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
ValueHandle RHS) {
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Value LHSVal(Data->LHSType, LHS);
|
||||||
|
Value RHSVal(Data->RHSType, RHS);
|
||||||
|
if (RHSVal.isNegative())
|
||||||
|
Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
|
||||||
|
else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
|
||||||
|
Diag(Loc, DL_Error,
|
||||||
|
"shift exponent %0 is too large for %1-bit type %2")
|
||||||
|
<< RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
|
||||||
|
else if (LHSVal.isNegative())
|
||||||
|
Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
|
||||||
|
else
|
||||||
|
Diag(Loc, DL_Error,
|
||||||
|
"left shift of %0 by %1 places cannot be represented in type %2")
|
||||||
|
<< LHSVal << RHSVal << Data->LHSType;
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
|
||||||
|
ShiftOutOfBoundsData *Data,
|
||||||
|
ValueHandle LHS,
|
||||||
|
ValueHandle RHS) {
|
||||||
|
__ubsan_handle_shift_out_of_bounds(Data, LHS, RHS);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
|
||||||
|
ValueHandle Index) {
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Value IndexVal(Data->IndexType, Index);
|
||||||
|
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
|
||||||
|
<< IndexVal << Data->ArrayType;
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
|
||||||
|
ValueHandle Index) {
|
||||||
|
__ubsan_handle_out_of_bounds(Data, Index);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
|
||||||
|
Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
|
||||||
|
Diag(Data->Loc, DL_Error,
|
||||||
|
"execution reached the end of a value-returning function "
|
||||||
|
"without returning a value");
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
|
||||||
|
ValueHandle Bound) {
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Diag(Loc, DL_Error, "variable length array bound evaluates to "
|
||||||
|
"non-positive value %0")
|
||||||
|
<< Value(Data->Type, Bound);
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
|
||||||
|
ValueHandle Bound) {
|
||||||
|
__ubsan_handle_vla_bound_not_positive(Data, Bound);
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
|
||||||
|
ValueHandle From) {
|
||||||
|
// TODO: Add deduplication once a SourceLocation is generated for this check.
|
||||||
|
Diag(getCallerLocation(), DL_Error,
|
||||||
|
"value %0 is outside the range of representable values of type %2")
|
||||||
|
<< Value(Data->FromType, From) << Data->FromType << Data->ToType;
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_float_cast_overflow_abort(
|
||||||
|
FloatCastOverflowData *Data,
|
||||||
|
ValueHandle From) {
|
||||||
|
Diag(getCallerLocation(), DL_Error,
|
||||||
|
"value %0 is outside the range of representable values of type %2")
|
||||||
|
<< Value(Data->FromType, From) << Data->FromType << Data->ToType;
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
|
||||||
|
ValueHandle Val) {
|
||||||
|
// TODO: Add deduplication once a SourceLocation is generated for this check.
|
||||||
|
Diag(getCallerLocation(), DL_Error,
|
||||||
|
"load of value %0, which is not a valid value for type %1")
|
||||||
|
<< Value(Data->Type, Val) << Data->Type;
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
|
||||||
|
ValueHandle Val) {
|
||||||
|
Diag(getCallerLocation(), DL_Error,
|
||||||
|
"load of value %0, which is not a valid value for type %1")
|
||||||
|
<< Value(Data->Type, Val) << Data->Type;
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
//===-- ubsan_handlers.h ----------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Entry points to the runtime library for Clang's undefined behavior sanitizer.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#ifndef UBSAN_HANDLERS_H
|
||||||
|
#define UBSAN_HANDLERS_H
|
||||||
|
|
||||||
|
#include "ubsan_value.h"
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
|
||||||
|
struct TypeMismatchData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
const TypeDescriptor &Type;
|
||||||
|
uptr Alignment;
|
||||||
|
unsigned char TypeCheckKind;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RECOVERABLE(checkname, ...) \
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
|
||||||
|
void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
|
||||||
|
void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ );
|
||||||
|
|
||||||
|
/// \brief Handle a runtime type check failure, caused by either a misaligned
|
||||||
|
/// pointer, a null pointer, or a pointer to insufficient storage for the
|
||||||
|
/// type.
|
||||||
|
RECOVERABLE(type_mismatch, TypeMismatchData *Data, ValueHandle Pointer)
|
||||||
|
|
||||||
|
struct OverflowData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
const TypeDescriptor &Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle an integer addition overflow.
|
||||||
|
RECOVERABLE(add_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
|
||||||
|
|
||||||
|
/// \brief Handle an integer subtraction overflow.
|
||||||
|
RECOVERABLE(sub_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
|
||||||
|
|
||||||
|
/// \brief Handle an integer multiplication overflow.
|
||||||
|
RECOVERABLE(mul_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
|
||||||
|
|
||||||
|
/// \brief Handle a signed integer overflow for a unary negate operator.
|
||||||
|
RECOVERABLE(negate_overflow, OverflowData *Data, ValueHandle OldVal)
|
||||||
|
|
||||||
|
/// \brief Handle an INT_MIN/-1 overflow or division by zero.
|
||||||
|
RECOVERABLE(divrem_overflow, OverflowData *Data,
|
||||||
|
ValueHandle LHS, ValueHandle RHS)
|
||||||
|
|
||||||
|
struct ShiftOutOfBoundsData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
const TypeDescriptor &LHSType;
|
||||||
|
const TypeDescriptor &RHSType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle a shift where the RHS is out of bounds or a left shift where
|
||||||
|
/// the LHS is negative or overflows.
|
||||||
|
RECOVERABLE(shift_out_of_bounds, ShiftOutOfBoundsData *Data,
|
||||||
|
ValueHandle LHS, ValueHandle RHS)
|
||||||
|
|
||||||
|
struct OutOfBoundsData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
const TypeDescriptor &ArrayType;
|
||||||
|
const TypeDescriptor &IndexType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle an array index out of bounds error.
|
||||||
|
RECOVERABLE(out_of_bounds, OutOfBoundsData *Data, ValueHandle Index)
|
||||||
|
|
||||||
|
struct UnreachableData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle a __builtin_unreachable which is reached.
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
void __ubsan_handle_builtin_unreachable(UnreachableData *Data);
|
||||||
|
/// \brief Handle reaching the end of a value-returning function.
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
void __ubsan_handle_missing_return(UnreachableData *Data);
|
||||||
|
|
||||||
|
struct VLABoundData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
const TypeDescriptor &Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle a VLA with a non-positive bound.
|
||||||
|
RECOVERABLE(vla_bound_not_positive, VLABoundData *Data, ValueHandle Bound)
|
||||||
|
|
||||||
|
struct FloatCastOverflowData {
|
||||||
|
// FIXME: SourceLocation Loc;
|
||||||
|
const TypeDescriptor &FromType;
|
||||||
|
const TypeDescriptor &ToType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle overflow in a conversion to or from a floating-point type.
|
||||||
|
RECOVERABLE(float_cast_overflow, FloatCastOverflowData *Data, ValueHandle From)
|
||||||
|
|
||||||
|
struct InvalidValueData {
|
||||||
|
// FIXME: SourceLocation Loc;
|
||||||
|
const TypeDescriptor &Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle a load of an invalid value for the type.
|
||||||
|
RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UBSAN_HANDLERS_H
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
//===-- ubsan_handlers_cxx.cc ---------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Error logging entry points for the UBSan runtime, which are only used for C++
|
||||||
|
// compilations. This file is permitted to use language features which require
|
||||||
|
// linking against a C++ ABI library.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ubsan_handlers_cxx.h"
|
||||||
|
#include "ubsan_diag.h"
|
||||||
|
#include "ubsan_type_hash.h"
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
|
using namespace __sanitizer;
|
||||||
|
using namespace __ubsan;
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
extern const char *TypeCheckKinds[];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleDynamicTypeCacheMiss(
|
||||||
|
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
|
||||||
|
bool Abort) {
|
||||||
|
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
|
||||||
|
// Just a cache miss. The type matches after all.
|
||||||
|
return;
|
||||||
|
|
||||||
|
SourceLocation Loc = Data->Loc.acquire();
|
||||||
|
if (Loc.isDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Diag(Loc, DL_Error,
|
||||||
|
"%0 address %1 which does not point to an object of type %2")
|
||||||
|
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
|
||||||
|
|
||||||
|
// If possible, say what type it actually points to.
|
||||||
|
DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
|
||||||
|
if (!DTI.isValid())
|
||||||
|
Diag(Pointer, DL_Note, "object has invalid vptr")
|
||||||
|
<< MangledName(DTI.getMostDerivedTypeName())
|
||||||
|
<< Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
|
||||||
|
else if (!DTI.getOffset())
|
||||||
|
Diag(Pointer, DL_Note, "object is of type %0")
|
||||||
|
<< MangledName(DTI.getMostDerivedTypeName())
|
||||||
|
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
|
||||||
|
else
|
||||||
|
// FIXME: Find the type at the specified offset, and include that
|
||||||
|
// in the note.
|
||||||
|
Diag(Pointer - DTI.getOffset(), DL_Note,
|
||||||
|
"object is base class subobject at offset %0 within object of type %1")
|
||||||
|
<< DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
|
||||||
|
<< MangledName(DTI.getSubobjectTypeName())
|
||||||
|
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1");
|
||||||
|
|
||||||
|
if (Abort)
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
|
||||||
|
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
|
||||||
|
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false);
|
||||||
|
}
|
||||||
|
void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
|
||||||
|
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
|
||||||
|
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
//===-- ubsan_handlers_cxx.h ------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Entry points to the runtime library for Clang's undefined behavior sanitizer,
|
||||||
|
// for C++-specific checks. This code is not linked into C binaries.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#ifndef UBSAN_HANDLERS_CXX_H
|
||||||
|
#define UBSAN_HANDLERS_CXX_H
|
||||||
|
|
||||||
|
#include "ubsan_value.h"
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
|
||||||
|
struct DynamicTypeCacheMissData {
|
||||||
|
SourceLocation Loc;
|
||||||
|
const TypeDescriptor &Type;
|
||||||
|
void *TypeInfo;
|
||||||
|
unsigned char TypeCheckKind;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Handle a runtime type check failure, caused by an incorrect vptr.
|
||||||
|
/// When this handler is called, all we know is that the type was not in the
|
||||||
|
/// cache; this does not necessarily imply the existence of a bug.
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
void __ubsan_handle_dynamic_type_cache_miss(
|
||||||
|
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
void __ubsan_handle_dynamic_type_cache_miss_abort(
|
||||||
|
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UBSAN_HANDLERS_H
|
||||||
|
|
@ -0,0 +1,246 @@
|
||||||
|
//===-- ubsan_type_hash.cc ------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Implementation of a hash table for fast checking of inheritance
|
||||||
|
// relationships. This file is only linked into C++ compilations, and is
|
||||||
|
// permitted to use language features which require a C++ ABI library.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ubsan_type_hash.h"
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
|
// The following are intended to be binary compatible with the definitions
|
||||||
|
// given in the Itanium ABI. We make no attempt to be ODR-compatible with
|
||||||
|
// those definitions, since existing ABI implementations aren't.
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
class type_info {
|
||||||
|
public:
|
||||||
|
virtual ~type_info();
|
||||||
|
|
||||||
|
const char *__type_name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
/// Type info for classes with no bases, and base class for type info for
|
||||||
|
/// classes with bases.
|
||||||
|
class __class_type_info : public std::type_info {
|
||||||
|
virtual ~__class_type_info();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Type info for classes with simple single public inheritance.
|
||||||
|
class __si_class_type_info : public __class_type_info {
|
||||||
|
public:
|
||||||
|
virtual ~__si_class_type_info();
|
||||||
|
|
||||||
|
const __class_type_info *__base_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class __base_class_type_info {
|
||||||
|
public:
|
||||||
|
const __class_type_info *__base_type;
|
||||||
|
long __offset_flags;
|
||||||
|
|
||||||
|
enum __offset_flags_masks {
|
||||||
|
__virtual_mask = 0x1,
|
||||||
|
__public_mask = 0x2,
|
||||||
|
__offset_shift = 8
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Type info for classes with multiple, virtual, or non-public inheritance.
|
||||||
|
class __vmi_class_type_info : public __class_type_info {
|
||||||
|
public:
|
||||||
|
virtual ~__vmi_class_type_info();
|
||||||
|
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int base_count;
|
||||||
|
__base_class_type_info base_info[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace abi = __cxxabiv1;
|
||||||
|
|
||||||
|
// We implement a simple two-level cache for type-checking results. For each
|
||||||
|
// (vptr,type) pair, a hash is computed. This hash is assumed to be globally
|
||||||
|
// unique; if it collides, we will get false negatives, but:
|
||||||
|
// * such a collision would have to occur on the *first* bad access,
|
||||||
|
// * the probability of such a collision is low (and for a 64-bit target, is
|
||||||
|
// negligible), and
|
||||||
|
// * the vptr, and thus the hash, can be affected by ASLR, so multiple runs
|
||||||
|
// give better coverage.
|
||||||
|
//
|
||||||
|
// The first caching layer is a small hash table with no chaining; buckets are
|
||||||
|
// reused as needed. The second caching layer is a large hash table with open
|
||||||
|
// chaining. We can freely evict from either layer since this is just a cache.
|
||||||
|
//
|
||||||
|
// FIXME: Make these hash table accesses thread-safe. The races here are benign
|
||||||
|
// (worst-case, we could miss a bug or see a slowdown) but we should
|
||||||
|
// avoid upsetting race detectors.
|
||||||
|
|
||||||
|
/// Find a bucket to store the given hash value in.
|
||||||
|
static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
|
||||||
|
static const unsigned HashTableSize = 65537;
|
||||||
|
static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize] = { 1 };
|
||||||
|
|
||||||
|
unsigned Probe = V & 65535;
|
||||||
|
for (int Tries = 5; Tries; --Tries) {
|
||||||
|
if (!__ubsan_vptr_hash_set[Probe] || __ubsan_vptr_hash_set[Probe] == V)
|
||||||
|
return &__ubsan_vptr_hash_set[Probe];
|
||||||
|
Probe += ((V >> 16) & 65535) + 1;
|
||||||
|
if (Probe >= HashTableSize)
|
||||||
|
Probe -= HashTableSize;
|
||||||
|
}
|
||||||
|
// FIXME: Pick a random entry from the probe sequence to evict rather than
|
||||||
|
// just taking the first.
|
||||||
|
return &__ubsan_vptr_hash_set[V];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A cache of recently-checked hashes. Mini hash table with "random" evictions.
|
||||||
|
__ubsan::HashValue
|
||||||
|
__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize] = { 1 };
|
||||||
|
|
||||||
|
/// \brief Determine whether \p Derived has a \p Base base class subobject at
|
||||||
|
/// offset \p Offset.
|
||||||
|
static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
|
||||||
|
const abi::__class_type_info *Base,
|
||||||
|
sptr Offset) {
|
||||||
|
if (Derived->__type_name == Base->__type_name)
|
||||||
|
return Offset == 0;
|
||||||
|
|
||||||
|
if (const abi::__si_class_type_info *SI =
|
||||||
|
dynamic_cast<const abi::__si_class_type_info*>(Derived))
|
||||||
|
return isDerivedFromAtOffset(SI->__base_type, Base, Offset);
|
||||||
|
|
||||||
|
const abi::__vmi_class_type_info *VTI =
|
||||||
|
dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
|
||||||
|
if (!VTI)
|
||||||
|
// No base class subobjects.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Look for a base class which is derived from \p Base at the right offset.
|
||||||
|
for (unsigned int base = 0; base != VTI->base_count; ++base) {
|
||||||
|
// FIXME: Curtail the recursion if this base can't possibly contain the
|
||||||
|
// given offset.
|
||||||
|
sptr OffsetHere = VTI->base_info[base].__offset_flags >>
|
||||||
|
abi::__base_class_type_info::__offset_shift;
|
||||||
|
if (VTI->base_info[base].__offset_flags &
|
||||||
|
abi::__base_class_type_info::__virtual_mask)
|
||||||
|
// For now, just punt on virtual bases and say 'yes'.
|
||||||
|
// FIXME: OffsetHere is the offset in the vtable of the virtual base
|
||||||
|
// offset. Read the vbase offset out of the vtable and use it.
|
||||||
|
return true;
|
||||||
|
if (isDerivedFromAtOffset(VTI->base_info[base].__base_type,
|
||||||
|
Base, Offset - OffsetHere))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Find the derived-most dynamic base class of \p Derived at offset
|
||||||
|
/// \p Offset.
|
||||||
|
static const abi::__class_type_info *findBaseAtOffset(
|
||||||
|
const abi::__class_type_info *Derived, sptr Offset) {
|
||||||
|
if (!Offset)
|
||||||
|
return Derived;
|
||||||
|
|
||||||
|
if (const abi::__si_class_type_info *SI =
|
||||||
|
dynamic_cast<const abi::__si_class_type_info*>(Derived))
|
||||||
|
return findBaseAtOffset(SI->__base_type, Offset);
|
||||||
|
|
||||||
|
const abi::__vmi_class_type_info *VTI =
|
||||||
|
dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
|
||||||
|
if (!VTI)
|
||||||
|
// No base class subobjects.
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (unsigned int base = 0; base != VTI->base_count; ++base) {
|
||||||
|
sptr OffsetHere = VTI->base_info[base].__offset_flags >>
|
||||||
|
abi::__base_class_type_info::__offset_shift;
|
||||||
|
if (VTI->base_info[base].__offset_flags &
|
||||||
|
abi::__base_class_type_info::__virtual_mask)
|
||||||
|
// FIXME: Can't handle virtual bases yet.
|
||||||
|
continue;
|
||||||
|
if (const abi::__class_type_info *Base =
|
||||||
|
findBaseAtOffset(VTI->base_info[base].__base_type,
|
||||||
|
Offset - OffsetHere))
|
||||||
|
return Base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct VtablePrefix {
|
||||||
|
/// The offset from the vptr to the start of the most-derived object.
|
||||||
|
/// This should never be greater than zero, and will usually be exactly
|
||||||
|
/// zero.
|
||||||
|
sptr Offset;
|
||||||
|
/// The type_info object describing the most-derived class type.
|
||||||
|
std::type_info *TypeInfo;
|
||||||
|
};
|
||||||
|
VtablePrefix *getVtablePrefix(void *Object) {
|
||||||
|
VtablePrefix **VptrPtr = reinterpret_cast<VtablePrefix**>(Object);
|
||||||
|
if (!*VptrPtr)
|
||||||
|
return 0;
|
||||||
|
VtablePrefix *Prefix = *VptrPtr - 1;
|
||||||
|
if (Prefix->Offset > 0 || !Prefix->TypeInfo)
|
||||||
|
// This can't possibly be a valid vtable.
|
||||||
|
return 0;
|
||||||
|
return Prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) {
|
||||||
|
// A crash anywhere within this function probably means the vptr is corrupted.
|
||||||
|
// FIXME: Perform these checks more cautiously.
|
||||||
|
|
||||||
|
// Check whether this is something we've evicted from the cache.
|
||||||
|
HashValue *Bucket = getTypeCacheHashTableBucket(Hash);
|
||||||
|
if (*Bucket == Hash) {
|
||||||
|
__ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VtablePrefix *Vtable = getVtablePrefix(Object);
|
||||||
|
if (!Vtable)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check that this is actually a type_info object for a class type.
|
||||||
|
abi::__class_type_info *Derived =
|
||||||
|
dynamic_cast<abi::__class_type_info*>(Vtable->TypeInfo);
|
||||||
|
if (!Derived)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
abi::__class_type_info *Base = (abi::__class_type_info*)Type;
|
||||||
|
if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Success. Cache this result.
|
||||||
|
__ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash;
|
||||||
|
*Bucket = Hash;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) {
|
||||||
|
VtablePrefix *Vtable = getVtablePrefix(Object);
|
||||||
|
if (!Vtable)
|
||||||
|
return DynamicTypeInfo(0, 0, 0);
|
||||||
|
const abi::__class_type_info *ObjectType = findBaseAtOffset(
|
||||||
|
static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
|
||||||
|
-Vtable->Offset);
|
||||||
|
return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
|
||||||
|
ObjectType ? ObjectType->__type_name : "<unknown>");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
//===-- ubsan_type_hash.h ---------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Hashing of types for Clang's undefined behavior checker.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#ifndef UBSAN_TYPE_HASH_H
|
||||||
|
#define UBSAN_TYPE_HASH_H
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
|
||||||
|
typedef uptr HashValue;
|
||||||
|
|
||||||
|
/// \brief Information about the dynamic type of an object (extracted from its
|
||||||
|
/// vptr).
|
||||||
|
class DynamicTypeInfo {
|
||||||
|
const char *MostDerivedTypeName;
|
||||||
|
sptr Offset;
|
||||||
|
const char *SubobjectTypeName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DynamicTypeInfo(const char *MDTN, sptr Offset, const char *STN)
|
||||||
|
: MostDerivedTypeName(MDTN), Offset(Offset), SubobjectTypeName(STN) {}
|
||||||
|
|
||||||
|
/// Determine whether the object had a valid dynamic type.
|
||||||
|
bool isValid() const { return MostDerivedTypeName; }
|
||||||
|
/// Get the name of the most-derived type of the object.
|
||||||
|
const char *getMostDerivedTypeName() const { return MostDerivedTypeName; }
|
||||||
|
/// Get the offset from the most-derived type to this base class.
|
||||||
|
sptr getOffset() const { return Offset; }
|
||||||
|
/// Get the name of the most-derived type at the specified offset.
|
||||||
|
const char *getSubobjectTypeName() const { return SubobjectTypeName; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Get information about the dynamic type of an object.
|
||||||
|
DynamicTypeInfo getDynamicTypeInfo(void *Object);
|
||||||
|
|
||||||
|
/// \brief Check whether the dynamic type of \p Object has a \p Type subobject
|
||||||
|
/// at offset 0.
|
||||||
|
/// \return \c true if the type matches, \c false if not.
|
||||||
|
bool checkDynamicType(void *Object, void *Type, HashValue Hash);
|
||||||
|
|
||||||
|
const unsigned VptrTypeCacheSize = 128;
|
||||||
|
|
||||||
|
/// \brief A cache of the results of checkDynamicType. \c checkDynamicType would
|
||||||
|
/// return \c true (modulo hash collisions) if
|
||||||
|
/// \code
|
||||||
|
/// __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] == Hash
|
||||||
|
/// \endcode
|
||||||
|
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
HashValue __ubsan_vptr_type_cache[VptrTypeCacheSize];
|
||||||
|
|
||||||
|
} // namespace __ubsan
|
||||||
|
|
||||||
|
#endif // UBSAN_TYPE_HASH_H
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
//===-- ubsan_value.cc ----------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Representation of a runtime value, as marshaled from the generated code to
|
||||||
|
// the ubsan runtime.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ubsan_value.h"
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
#include "sanitizer_common/sanitizer_libc.h"
|
||||||
|
|
||||||
|
using namespace __ubsan;
|
||||||
|
|
||||||
|
SIntMax Value::getSIntValue() const {
|
||||||
|
CHECK(getType().isSignedIntegerTy());
|
||||||
|
if (isInlineInt()) {
|
||||||
|
// Val was zero-extended to ValueHandle. Sign-extend from original width
|
||||||
|
// to SIntMax.
|
||||||
|
const unsigned ExtraBits =
|
||||||
|
sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
|
||||||
|
return SIntMax(Val) << ExtraBits >> ExtraBits;
|
||||||
|
}
|
||||||
|
if (getType().getIntegerBitWidth() == 64)
|
||||||
|
return *reinterpret_cast<s64*>(Val);
|
||||||
|
#if HAVE_INT128_T
|
||||||
|
if (getType().getIntegerBitWidth() == 128)
|
||||||
|
return *reinterpret_cast<s128*>(Val);
|
||||||
|
#else
|
||||||
|
if (getType().getIntegerBitWidth() == 128)
|
||||||
|
UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
|
||||||
|
#endif
|
||||||
|
UNREACHABLE("unexpected bit width");
|
||||||
|
}
|
||||||
|
|
||||||
|
UIntMax Value::getUIntValue() const {
|
||||||
|
CHECK(getType().isUnsignedIntegerTy());
|
||||||
|
if (isInlineInt())
|
||||||
|
return Val;
|
||||||
|
if (getType().getIntegerBitWidth() == 64)
|
||||||
|
return *reinterpret_cast<u64*>(Val);
|
||||||
|
#if HAVE_INT128_T
|
||||||
|
if (getType().getIntegerBitWidth() == 128)
|
||||||
|
return *reinterpret_cast<u128*>(Val);
|
||||||
|
#else
|
||||||
|
if (getType().getIntegerBitWidth() == 128)
|
||||||
|
UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
|
||||||
|
#endif
|
||||||
|
UNREACHABLE("unexpected bit width");
|
||||||
|
}
|
||||||
|
|
||||||
|
UIntMax Value::getPositiveIntValue() const {
|
||||||
|
if (getType().isUnsignedIntegerTy())
|
||||||
|
return getUIntValue();
|
||||||
|
SIntMax Val = getSIntValue();
|
||||||
|
CHECK(Val >= 0);
|
||||||
|
return Val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the floating-point value of this object, extended to a long double.
|
||||||
|
/// These are always passed by address (our calling convention doesn't allow
|
||||||
|
/// them to be passed in floating-point registers, so this has little cost).
|
||||||
|
FloatMax Value::getFloatValue() const {
|
||||||
|
CHECK(getType().isFloatTy());
|
||||||
|
if (isInlineFloat()) {
|
||||||
|
switch (getType().getFloatBitWidth()) {
|
||||||
|
#if 0
|
||||||
|
// FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
|
||||||
|
// from '__fp16' to 'long double'.
|
||||||
|
case 16: {
|
||||||
|
__fp16 Value;
|
||||||
|
internal_memcpy(&Value, &Val, 4);
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
case 32: {
|
||||||
|
float Value;
|
||||||
|
internal_memcpy(&Value, &Val, 4);
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
case 64: {
|
||||||
|
double Value;
|
||||||
|
internal_memcpy(&Value, &Val, 8);
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (getType().getFloatBitWidth()) {
|
||||||
|
case 64: return *reinterpret_cast<double*>(Val);
|
||||||
|
case 80: return *reinterpret_cast<long double*>(Val);
|
||||||
|
case 128: return *reinterpret_cast<long double*>(Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNREACHABLE("unexpected floating point bit width");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
//===-- ubsan_value.h -------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Representation of data which is passed from the compiler-generated calls into
|
||||||
|
// the ubsan runtime.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#ifndef UBSAN_VALUE_H
|
||||||
|
#define UBSAN_VALUE_H
|
||||||
|
|
||||||
|
// For now, only support linux and darwin. Other platforms should be easy to
|
||||||
|
// add, and probably work as-is.
|
||||||
|
#if !defined(__linux__) && !defined(__APPLE__)
|
||||||
|
#error "UBSan not supported for this platform!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_atomic.h"
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
|
// FIXME: Move this out to a config header.
|
||||||
|
#if __SIZEOF_INT128__
|
||||||
|
__extension__ typedef __int128 s128;
|
||||||
|
__extension__ typedef unsigned __int128 u128;
|
||||||
|
#define HAVE_INT128_T 1
|
||||||
|
#else
|
||||||
|
#define HAVE_INT128_T 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace __ubsan {
|
||||||
|
|
||||||
|
/// \brief Largest integer types we support.
|
||||||
|
#if HAVE_INT128_T
|
||||||
|
typedef s128 SIntMax;
|
||||||
|
typedef u128 UIntMax;
|
||||||
|
#else
|
||||||
|
typedef s64 SIntMax;
|
||||||
|
typedef u64 UIntMax;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// \brief Largest floating-point type we support.
|
||||||
|
typedef long double FloatMax;
|
||||||
|
|
||||||
|
/// \brief A description of a source location. This corresponds to Clang's
|
||||||
|
/// \c PresumedLoc type.
|
||||||
|
class SourceLocation {
|
||||||
|
const char *Filename;
|
||||||
|
u32 Line;
|
||||||
|
u32 Column;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SourceLocation() : Filename(), Line(), Column() {}
|
||||||
|
SourceLocation(const char *Filename, unsigned Line, unsigned Column)
|
||||||
|
: Filename(Filename), Line(Line), Column(Column) {}
|
||||||
|
|
||||||
|
/// \brief Determine whether the source location is known.
|
||||||
|
bool isInvalid() const { return !Filename; }
|
||||||
|
|
||||||
|
/// \brief Atomically acquire a copy, disabling original in-place.
|
||||||
|
/// Exactly one call to acquire() returns a copy that isn't disabled.
|
||||||
|
SourceLocation acquire() {
|
||||||
|
u32 OldColumn = __sanitizer::atomic_exchange(
|
||||||
|
(__sanitizer::atomic_uint32_t *)&Column, ~u32(0),
|
||||||
|
__sanitizer::memory_order_relaxed);
|
||||||
|
return SourceLocation(Filename, Line, OldColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if this Location has been disabled.
|
||||||
|
/// Disabled SourceLocations are invalid to use.
|
||||||
|
bool isDisabled() {
|
||||||
|
return Column == ~u32(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get the presumed filename for the source location.
|
||||||
|
const char *getFilename() const { return Filename; }
|
||||||
|
/// \brief Get the presumed line number.
|
||||||
|
unsigned getLine() const { return Line; }
|
||||||
|
/// \brief Get the column within the presumed line.
|
||||||
|
unsigned getColumn() const { return Column; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// \brief A description of a type.
|
||||||
|
class TypeDescriptor {
|
||||||
|
/// A value from the \c Kind enumeration, specifying what flavor of type we
|
||||||
|
/// have.
|
||||||
|
u16 TypeKind;
|
||||||
|
|
||||||
|
/// A \c Type-specific value providing information which allows us to
|
||||||
|
/// interpret the meaning of a ValueHandle of this type.
|
||||||
|
u16 TypeInfo;
|
||||||
|
|
||||||
|
/// The name of the type follows, in a format suitable for including in
|
||||||
|
/// diagnostics.
|
||||||
|
char TypeName[1];
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Kind {
|
||||||
|
/// An integer type. Lowest bit is 1 for a signed value, 0 for an unsigned
|
||||||
|
/// value. Remaining bits are log_2(bit width). The value representation is
|
||||||
|
/// the integer itself if it fits into a ValueHandle, and a pointer to the
|
||||||
|
/// integer otherwise.
|
||||||
|
TK_Integer = 0x0000,
|
||||||
|
/// A floating-point type. Low 16 bits are bit width. The value
|
||||||
|
/// representation is that of bitcasting the floating-point value to an
|
||||||
|
/// integer type.
|
||||||
|
TK_Float = 0x0001,
|
||||||
|
/// Any other type. The value representation is unspecified.
|
||||||
|
TK_Unknown = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *getTypeName() const { return TypeName; }
|
||||||
|
|
||||||
|
Kind getKind() const {
|
||||||
|
return static_cast<Kind>(TypeKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIntegerTy() const { return getKind() == TK_Integer; }
|
||||||
|
bool isSignedIntegerTy() const {
|
||||||
|
return isIntegerTy() && (TypeInfo & 1);
|
||||||
|
}
|
||||||
|
bool isUnsignedIntegerTy() const {
|
||||||
|
return isIntegerTy() && !(TypeInfo & 1);
|
||||||
|
}
|
||||||
|
unsigned getIntegerBitWidth() const {
|
||||||
|
CHECK(isIntegerTy());
|
||||||
|
return 1 << (TypeInfo >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFloatTy() const { return getKind() == TK_Float; }
|
||||||
|
unsigned getFloatBitWidth() const {
|
||||||
|
CHECK(isFloatTy());
|
||||||
|
return TypeInfo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief An opaque handle to a value.
|
||||||
|
typedef uptr ValueHandle;
|
||||||
|
|
||||||
|
|
||||||
|
/// \brief Representation of an operand value provided by the instrumented code.
|
||||||
|
///
|
||||||
|
/// This is a combination of a TypeDescriptor (which is emitted as constant data
|
||||||
|
/// as an operand to a handler function) and a ValueHandle (which is passed at
|
||||||
|
/// runtime when a check failure occurs).
|
||||||
|
class Value {
|
||||||
|
/// The type of the value.
|
||||||
|
const TypeDescriptor &Type;
|
||||||
|
/// The encoded value itself.
|
||||||
|
ValueHandle Val;
|
||||||
|
|
||||||
|
/// Is \c Val a (zero-extended) integer?
|
||||||
|
bool isInlineInt() const {
|
||||||
|
CHECK(getType().isIntegerTy());
|
||||||
|
const unsigned InlineBits = sizeof(ValueHandle) * 8;
|
||||||
|
const unsigned Bits = getType().getIntegerBitWidth();
|
||||||
|
return Bits <= InlineBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is \c Val a (zero-extended) integer representation of a float?
|
||||||
|
bool isInlineFloat() const {
|
||||||
|
CHECK(getType().isFloatTy());
|
||||||
|
const unsigned InlineBits = sizeof(ValueHandle) * 8;
|
||||||
|
const unsigned Bits = getType().getFloatBitWidth();
|
||||||
|
return Bits <= InlineBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {}
|
||||||
|
|
||||||
|
const TypeDescriptor &getType() const { return Type; }
|
||||||
|
|
||||||
|
/// \brief Get this value as a signed integer.
|
||||||
|
SIntMax getSIntValue() const;
|
||||||
|
|
||||||
|
/// \brief Get this value as an unsigned integer.
|
||||||
|
UIntMax getUIntValue() const;
|
||||||
|
|
||||||
|
/// \brief Decode this value, which must be a positive or unsigned integer.
|
||||||
|
UIntMax getPositiveIntValue() const;
|
||||||
|
|
||||||
|
/// Is this an integer with value -1?
|
||||||
|
bool isMinusOne() const {
|
||||||
|
return getType().isSignedIntegerTy() && getSIntValue() == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this a negative integer?
|
||||||
|
bool isNegative() const {
|
||||||
|
return getType().isSignedIntegerTy() && getSIntValue() < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get this value as a floating-point quantity.
|
||||||
|
FloatMax getFloatValue() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace __ubsan
|
||||||
|
|
||||||
|
#endif // UBSAN_VALUE_H
|
||||||
Loading…
Reference in New Issue