From patchwork Fri Aug 30 08:38:51 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 271174 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "www.sourceware.org", Issuer "StartCom Class 1 Primary Intermediate Server CA" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 104CE2C0087 for ; Fri, 30 Aug 2013 18:39:22 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=iWgFzPJAzKFtZRzwi HjGBvpSykoaHBlEz2G9jczZxJtsFmV1rD0BxFg7PmZSXi3N+JWam3QtyslFQ640R s9uqq5AzkXVJKAZuRRd6gMU1EuBBrdrOvHADocZsOWSdeLqkmcxLJjReuEh8rzrM rKIWpBZ9giUsvIBV6OCax5M33g= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=default; bh=jSPWHy4bhv1+UCSzIYRUquB mFW8=; b=yVaAZQr2CHEPr1I+pXbT+MWwmcuPkyURVKV6YHBVgo6C9qeJnGdbKuX rV3zuEThjzcTdhXJ+q3BdUeyomMkMuVRkY37Qs0wJuqFi2OURVAVAB8CCGnSYEsk HcKAtk5B8B4syonY+xyksRkfsemkrxmCALpcP3vNCNnulgGXeTT0= Received: (qmail 23702 invoked by alias); 30 Aug 2013 08:39:12 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 23685 invoked by uid 89); 30 Aug 2013 08:39:11 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 30 Aug 2013 08:39:11 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.7 required=5.0 tests=AWL, BAYES_05, KAM_STOCKGEN, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r7U8cwHu026421 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 30 Aug 2013 04:38:58 -0400 Received: from redhat.com (ovpn-116-91.ams2.redhat.com [10.36.116.91]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r7U8cpP9017534 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Fri, 30 Aug 2013 04:38:53 -0400 Date: Fri, 30 Aug 2013 10:38:51 +0200 From: Marek Polacek To: Jakub Jelinek Cc: GCC Patches , Jason Merrill , "Joseph S. Myers" Subject: Re: Request to merge Undefined Behavior Sanitizer in (take 3) Message-ID: <20130830083850.GE23899@redhat.com> References: <20130815150848.GZ17022@redhat.com> <20130822175107.GC4968@redhat.com> <20130822190157.GD4968@redhat.com> <20130827143040.GC574@redhat.com> <20130830081306.GD23899@redhat.com> <20130830081544.GG21876@tucnak.zalov.cz> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20130830081544.GG21876@tucnak.zalov.cz> User-Agent: Mutt/1.5.20 (2009-06-14) On Fri, Aug 30, 2013 at 10:15:44AM +0200, Jakub Jelinek wrote: > So, can you please post a new final patch for the merge (with the new directories > or files in libsanitizer/ just listed in the ChangeLog entries, but not > actually included in the patch, that would make it too large and anyone can > look at libsanitizer/ubsan/ on the branch)? Yep. This is diff between trunk and the ubsan branch without new files. BTW, when merging the ChangeLog.ubsan into normal ChangeLog, should I change the CL entry dates to the day of the merge into the trunk, or can I keep them as they are? Marek diff --git a/config/ChangeLog.ubsan b/config/ChangeLog.ubsan new file mode 100644 index 0000000..2286374 --- /dev/null +++ b/config/ChangeLog.ubsan @@ -0,0 +1,7 @@ +2013-08-14 Marek Polacek + + * bootstrap-ubsan.mk (POSTSTAGE1_LDFLAGS): Add -lpthread. + +2013-07-30 Marek Polacek + + * bootstrap-ubsan.mk: New. diff --git a/config/bootstrap-ubsan.mk b/config/bootstrap-ubsan.mk new file mode 100644 index 0000000..2d21e83 --- /dev/null +++ b/config/bootstrap-ubsan.mk @@ -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 diff --git a/gcc/ChangeLog.ubsan b/gcc/ChangeLog.ubsan new file mode 100644 index 0000000..9ed8f96 --- /dev/null +++ b/gcc/ChangeLog.ubsan @@ -0,0 +1,189 @@ +2013-08-29 Marek Polacek + + * Makefile.in (ubsan.o): Add $(HASHTAB_H) and gt-ubsan.h + dependencies. Remove pointer-set.h dependency. + * ubsan.c: Convert to C style hash table. + +2013-08-28 Marek Polacek + + * ubsan.c: Use pointer_map instead of pointer_map_t. + (insert_decl_for_type): Adjust. + (lookup_decl_for_type): Likewise. + +2013-08-28 Marek Polacek + + * Makefile.in (ubsan.o): Add pointer-set.h dependency. Remove + alloc-pool.h and HASH_TABLE_H dependencies. + +2013-08-27 Marek Polacek + + * ubsan.c: Use pointer map instead of hash table. + +2013-08-26 Marek Polacek + + * 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. + * ubsan.c (ubsan_encode_value): Use pointer_sized_int_node instead + calling uptr_type. + (uptr_type): Remove function. + * asan.c (asan_global_struct): Use pointer_sized_int_node instead + calling build_nonstandard_integer_type. + (initialize_sanitizer_builtins): Likewise. + (asan_finish_file): Likewise. + +2013-08-23 Marek Polacek + + * ubsan.c (ubsan_typedesc_hasher::hash): Hash the TYPE_UID of the + type. + (ubsan_type_descriptor): Get TYPE_MAIN_VARIANT before initializing + the type descriptor. + +2013-08-20 Marek Polacek + + * ubsan.c (is_ubsan_builtin_p): New function. + * ubsan.h: Declare it. + +2013-08-05 Marek Polacek + + * ubsan.c (ubsan_source_location_type): Properly create + const char type using build_qualified_type. + +2013-07-31 Marek Polacek + + * doc/invoke.texi: Improve documentation of -fsanitize=undefined. + +2013-07-30 Marek Polacek + + * config/rs6000/rs6000.h (FRAME_GROWS_DOWNWARD): Use flag_sanitize + instead of flag_asan. + +2013-07-30 Marek Polacek + + * ubsan.c (ubsan_source_location): Use build_constructor_va + instead of build_constructor. + (ubsan_type_descriptor): Likewise. + +2013-07-29 Marek Polacek + + * common.opt (static-libubsan): New option. + * doc/invoke.texi: Document -static-libubsan. + +2013-07-24 Marek Polacek + + * ubsan.c (struct ubsan_typedesc): Improve comment. + +2013-07-21 Marek Polacek + + * ubsan.c (struct ubsan_typedesc): Add comments. + (ubsan_typedesc_hasher::hash): Don't hash the VAR_DECL element. + (ubsan_typedesc_hasher::equal): Adjust comment. + (ubsan_typedesc_get_alloc_pool): Remove comment. + (empty_ubsan_typedesc_hash_table): Remove function. + (ubsan_source_location_type): Remove bogus comment. + (get_tinfo_for_type): Remove function. + (get_ubsan_type_info_for_type): New function. + (ubsan_type_descriptor): Use ASM_GENERATE_INTERNAL_LABEL instead of + ASM_FORMAT_PRIVATE_NAME. Use TYPE_MAIN_VARIANT of the type. + (ubsan_create_data): Likewise. + +2013-07-15 Marek Polacek + + * gcc.c (ADD_STATIC_LIBUBSAN_LIBS): Define. + (LIBUBSAN_SPEC): Likewise. + (LIBUBSAN_EARLY_SPEC): Likewise. + (SANITIZER_SPEC): Handle libubsan. + (SANITIZER_EARLY_SPEC): Likewise. + +2013-07-15 Marek Polacek + + * builtin-attrs.def (ATTR_COLD_NOTHROW_LEAF_LIST): Define. + * sanitizer.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW): Don't mark + as NORETURN. + (BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Likewise. + * asan.c (ATTR_COLD_NOTHROW_LEAF_LIST): Define. + +2013-07-14 Marek Polacek + + * opts.c (common_handle_option): Add -fsanitize=unreachable option. + * builtins.c (fold_builtin_0): Use SANITIZE_UNREACHABLE instead of + SANITIZE_UNDEFINED. + * flag-types.h (enum sanitize_code): Add SANITIZE_UNREACHABLE. + +2013-07-14 Marek Polacek + + * Makefile.in (c-family/c-ubsan.o): Add alloc-pool.h, CGRAPH_H, + GIMPLE_H, HASH_TABLE_H, output.h, toplev.h and ubsan.h dependencies. + (builtins.o): Add ubsan.h dependency. + +2013-07-14 Marek Polacek + + * builtins.c: Include ubsan.h. + (fold_builtin_0): Instrument __builtin_unreachable. + * sanitizer.def (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE): Define. + * Makefile.in: Add ubsan.c. + * ubsan.h: New file. + * ubsan.c: New file. + +2013-07-14 Jakub Jelinek + + * gcc.c: Document %{%:function(args):X}. + (SANITIZER_EARLY_SPEC, SANITIZER_SPEC): Use %:sanitize(address) + instead of fsanitize=address and %:sanitize(thread) instead of + fsanitize=thread. + (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. + * common.opt (fsanitize=): Add Driver. + * 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*. + +2013-07-14 Marek Polacek + + * common.opt (flag_sanitize): Add variable. + (fsanitize=): Add option. + (fsanitize=thread): Remove option. + (fsanitize=address): Likewise. + * flag-types.h (sanitize_code): New enum. + * opts.c (common_handle_option): Parse command line arguments + of -fsanitize=. + * 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. + +2013-07-05 Marek Polacek + + * Makefile.in: Add ubsan.c. + * common.opt: Add -fsanitize=undefined option. + * doc/invoke.texi: Document the new flag. + * sanitizer.def (DEF_SANITIZER_BUILTIN): Define. + * builtin-attrs.def (ATTR_COLD): Define. + * asan.c (initialize_sanitizer_builtins): Build + BT_FN_VOID_PTR_PTR_PTR. + * builtins.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW, + BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Define. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 064e7c3..7396313 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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-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/array-notation-common.o + c-family/array-notation-common.o c-family/c-ubsan.o # Language-independent object files. # We put the insn-*.o files first so that a parallel make will build @@ -1383,6 +1383,7 @@ OBJS = \ tree-affine.o \ asan.o \ tsan.o \ + ubsan.o \ tree-call-cdce.o \ tree-cfg.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) \ 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 \ $(C_TARGET_H) $(C_TARGET_DEF_H) $(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) \ $(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_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 +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 \ $(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_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) \ $(TM_P_H) $(PREDICT_H) $(LIBFUNCS_H) langhooks.h $(BASIC_BLOCK_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) \ $(TREE_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_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)/vtable-verify.c \ $(srcdir)/asan.c \ + $(srcdir)/ubsan.c \ $(srcdir)/tsan.c $(srcdir)/ipa-devirt.c \ @all_gtfiles@ diff --git a/gcc/asan.c b/gcc/asan.c index 81118a7..e7b1f47 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -1938,7 +1938,7 @@ asan_global_struct (void) = build_decl (UNKNOWN_LOCATION, FIELD_DECL, get_identifier (field_names[i]), (i == 0 || i == 3) ? const_ptr_type_node - : build_nonstandard_integer_type (POINTER_SIZE, 1)); + : pointer_sized_int_node); DECL_CONTEXT (fields[i]) = ret; if (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_PTR = 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 = build_function_type_list (void_type_node, ptr_type_node, - build_nonstandard_integer_type (POINTER_SIZE, - 1), NULL_TREE); + pointer_sized_int_node, NULL_TREE); tree BT_FN_VOID_INT = build_function_type_list (void_type_node, integer_type_node, NULL_TREE); 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 #define ATTR_TMPURE_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 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \ @@ -2157,7 +2165,7 @@ asan_finish_file (void) /* Avoid instrumenting code in the asan ctors/dtors. We don't need to insert padding after the description strings, nor after .LASAN* array. */ - flag_asan = 0; + flag_sanitize &= ~SANITIZE_ADDRESS; tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT); append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements); @@ -2170,7 +2178,6 @@ asan_finish_file (void) if (gcount) { tree type = asan_global_struct (), var, ctor; - tree uptr = build_nonstandard_integer_type (POINTER_SIZE, 1); tree dtor_statements = NULL_TREE; vec *v; char buf[20]; @@ -2199,22 +2206,23 @@ asan_finish_file (void) varpool_assemble_decl (varpool_node_for_decl (var)); 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, build_fold_addr_expr (var), - build_int_cst (uptr, gcount)), + gcount_tree), &asan_ctor_statements); fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS); append_to_statement_list (build_call_expr (fn, 2, build_fold_addr_expr (var), - build_int_cst (uptr, gcount)), + gcount_tree), &dtor_statements); cgraph_build_static_cdtor ('D', dtor_statements, MAX_RESERVED_INIT_PRIORITY - 1); } cgraph_build_static_cdtor ('I', asan_ctor_statements, MAX_RESERVED_INIT_PRIORITY - 1); - flag_asan = 1; + flag_sanitize |= SANITIZE_ADDRESS; } /* Instrument the current function. */ @@ -2231,7 +2239,7 @@ asan_instrument (void) static bool gate_asan (void) { - return flag_asan != 0 + return (flag_sanitize & SANITIZE_ADDRESS) != 0 && !lookup_attribute ("no_sanitize_address", DECL_ATTRIBUTES (current_function_decl)); } diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def index dcaeee9..7939727 100644 --- a/gcc/builtin-attrs.def +++ b/gcc/builtin-attrs.def @@ -83,6 +83,7 @@ DEF_LIST_INT_INT (5,6) #undef DEF_LIST_INT_INT /* Construct trees for identifiers. */ +DEF_ATTR_IDENT (ATTR_COLD, "cold") DEF_ATTR_IDENT (ATTR_CONST, "const") DEF_ATTR_IDENT (ATTR_FORMAT, "format") 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) DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LEAF_LIST, ATTR_NORETURN,\ 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,\ ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST) DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \ diff --git a/gcc/builtins.c b/gcc/builtins.c index d8baad1..92aec31 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "value-prof.h" #include "diagnostic-core.h" #include "builtins.h" +#include "ubsan.h" #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: return fold_builtin_classify_type (NULL_TREE); + case BUILT_IN_UNREACHABLE: + if (flag_sanitize & SANITIZE_UNREACHABLE) + return ubsan_instrument_unreachable (loc); + break; + default: break; } diff --git a/gcc/builtins.def b/gcc/builtins.def index ce04049..8ccf3ae 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -161,7 +161,8 @@ along with GCC; see the file COPYING3. If not see #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ true, true, true, ATTRS, true, \ - (flag_asan || flag_tsan)) + (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \ + | SANITIZE_UNDEFINED))) #undef DEF_CILKPLUS_BUILTIN #define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ diff --git a/gcc/c-family/ChangeLog.ubsan b/gcc/c-family/ChangeLog.ubsan new file mode 100644 index 0000000..450c4eb --- /dev/null +++ b/gcc/c-family/ChangeLog.ubsan @@ -0,0 +1,63 @@ +2013-08-15 Marek Polacek + + * c-ubsan.c (ubsan_instrument_division): Evaluate SAVE_EXPRs + before the condition. + (ubsan_instrument_shift): Likewise. + +2013-08-14 Marek Polacek + + * c-ubsan.c (ubsan_instrument_division): Use TYPE_MAIN_VARIANT + in the assert. + +2013-07-14 Marek Polacek + + * c-ubsan.c (struct ubsan_typedesc): Move to ubsan.c. + (struct ubsan_typedesc_hasher): Likewise. + (ubsan_typedesc_hasher::hash): Likewise. + (ubsan_typedesc_hasher::equal): Likewise. + (ubsan_typedesc_init): Likewise. + (ubsan_typedesc_get_alloc_pool): Likewise. + (get_typedesc_hash_table): Likewise. + (ubsan_typedesc_new): Likewise. + (empty_ubsan_typedesc_hash_table): Likewise. + (uptr_type): Likewise. + (ubsan_encode_value): Likewise. + (ubsan_type_descriptor_type): Likewise. + (ubsan_source_location_type): Likewise. + (ubsan_source_location): Likewise. + (get_tinfo_for_type): Likewise. + (ubsan_type_descriptor): Likewise. + (ubsan_create_data): Likewise. + * c-ubsan.h: Rename GCC_UBSAN_H to GCC_C_UBSAN_H. + +2013-07-07 Marek Polacek + + * c-ubsan.c (empty_ubsan_typedesc_hash_table): Comment out function. + +2013-07-05 Marek Polacek + + * c-ubsan.c (struct ubsan_typedesc): Declare. + (ubsan_typedesc_ht): New hashtable. + (ubsan_typedesc_hasher::hash): New function. + (ubsan_typedesc_hasher::equal): Likewise. + (ubsan_typedesc_init): Likewise. + (ubsan_typedesc_get_alloc_pool): Likewise. + (get_typedesc_hash_table): Likewise. + (ubsan_typedesc_new): Likewise. + (empty_ubsan_typedesc_hash_table): Likewise. + (uptr_type): Likewise. + (ubsan_encode_value): Likewise. + (ubsan_type_descriptor_type): Likewise. + (ubsan_source_location_type): Likewise. + (ubsan_source_location): Likewise. + (get_tinfo_for_type): Likewise. + (ubsan_type_descriptor): Likewise. + (ubsan_create_data): Likewise. + (ubsan_instrument_division): Create and pass arguments for the ubsan + library. + (ubsan_instrument_shift): Likewise. + +2013-07-05 Marek Polacek + + * c-ubsan.c: New file. + * c-ubsan.h: New file. diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c new file mode 100644 index 0000000..9f43f6d --- /dev/null +++ b/gcc/c-family/c-ubsan.c @@ -0,0 +1,158 @@ +/* UndefinedBehaviorSanitizer, undefined behavior detector. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Marek Polacek + +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 +. */ + +#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; +} diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h new file mode 100644 index 0000000..b032b70 --- /dev/null +++ b/gcc/c-family/c-ubsan.h @@ -0,0 +1,27 @@ +/* UndefinedBehaviorSanitizer, undefined behavior detector. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Marek Polacek + +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 +. */ + +#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 */ diff --git a/gcc/c/ChangeLog.ubsan b/gcc/c/ChangeLog.ubsan new file mode 100644 index 0000000..f41ae90 --- /dev/null +++ b/gcc/c/ChangeLog.ubsan @@ -0,0 +1,19 @@ +2013-07-31 Marek Polacek + + * c-typeck.c (build_binary_op): Sanitize only when + doing shift or division. + +2013-07-30 Marek Polacek + + * c-typeck.c (build_binary_op): Sanitize only when + current_function_decl is not zero. + +2013-07-21 Marek Polacek + + * c-typeck.c (build_binary_op): Call c_fully_fold on both + SAVE_EXPRs. + +2013-07-05 Marek Polacek + + * c-typeck.c (build_binary_op): Add division by zero and shift + instrumentation. diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 8b3e3d9..f29ca04 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "c-family/c-objc.h" #include "c-family/c-common.h" +#include "c-family/c-ubsan.h" /* Possible cases of implicit bad conversions. Used to select diagnostic messages in convert_for_assignment. */ @@ -9541,6 +9542,15 @@ build_binary_op (location_t location, enum tree_code code, operands to truth-values. */ 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) location = input_location; @@ -9742,6 +9752,7 @@ build_binary_op (location_t location, enum tree_code code, case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case EXACT_DIV_EXPR: + doing_div_or_mod = true; warn_for_div_by_zero (location, op1); 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 FLOOR_MOD_EXPR: + doing_div_or_mod = true; warn_for_div_by_zero (location, op1); 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) && code1 == INTEGER_TYPE) { + doing_shift = true; if (TREE_CODE (op1) == INTEGER_CST) { 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) && code1 == INTEGER_TYPE) { + doing_shift = true; if (TREE_CODE (op1) == INTEGER_CST) { 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; } + 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. */ if (int_const_or_overflow) ret = (require_constant_value @@ -10506,6 +10535,11 @@ build_binary_op (location_t location, enum tree_code code, if (semantic_result_type) ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); 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; } diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index f4f58cb..d918b4a 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -1137,7 +1137,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) /* For address sanitizer, never crossjump __asan_report_* builtins, otherwise errors might be reported on incorrect lines. */ - if (flag_asan) + if (flag_sanitize & SANITIZE_ADDRESS) { rtx call = get_call_rtx_from (i1); if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index a7d9170..4da5e7e 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -764,7 +764,7 @@ partition_stack_vars (void) sizes, as the shorter vars wouldn't be adequately protected. Don't do that for "large" (unsupported) alignment objects, 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) break; @@ -940,7 +940,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data) alignb = stack_vars[i].alignb; 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; 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, so that we can re-order the strings to the top of the frame. Similarly for Address Sanitizer. */ - if (flag_stack_protect || flag_asan) + if (flag_stack_protect || (flag_sanitize & SANITIZE_ADDRESS)) return true; /* 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); } - if (flag_asan) + if (flag_sanitize & SANITIZE_ADDRESS) /* Phase 3, any partitions that need asan protection in addition to phase 1 and 2. */ expand_stack_vars (asan_decl_phase_3, &data); diff --git a/gcc/common.opt b/gcc/common.opt index 9082280..caf624f 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -207,6 +207,10 @@ unsigned int help_columns Variable bool flag_opts_finished +; What the sanitizer should instrument +Variable +unsigned int flag_sanitize + ### Driver @@ -850,13 +854,9 @@ fargument-noalias-anything Common Ignore Does nothing. Preserved for backward compatibility. -fsanitize=address -Common Report Var(flag_asan) -Enable AddressSanitizer, a memory error detector - -fsanitize=thread -Common Report Var(flag_tsan) -Enable ThreadSanitizer, a data race detector +fsanitize= +Common Driver Report Joined +Select what to sanitize fasynchronous-unwind-tables Common Report Var(flag_asynchronous_unwind_tables) Optimization @@ -2604,6 +2604,9 @@ Driver static-libtsan Driver +static-libubsan +Driver + symbolic Driver diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h index c6e686b..232c38d 100644 --- a/gcc/config/arm/linux-eabi.h +++ b/gcc/config/arm/linux-eabi.h @@ -85,7 +85,7 @@ LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) #undef ASAN_CC1_SPEC -#define ASAN_CC1_SPEC "%{fsanitize=*:-funwind-tables}" +#define ASAN_CC1_SPEC "%{%:sanitize(address):-funwind-tables}" #undef CC1_SPEC #define CC1_SPEC \ diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index d87cd8e..9d04472 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -178,7 +178,7 @@ extern GTY(()) int darwin_ms_struct; %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \ %{fopenmp|ftree-parallelize-loops=*: \ %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \ - %{fsanitize=address: -lasan } \ + %{%:sanitize(address): -lasan } \ %{fgnu-tm: \ %{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \ %{!nostdlib:%{!nodefaultlibs:\ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index e5a6abd..f89b20d 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -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 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 */ #define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX \ diff --git a/gcc/cp/ChangeLog.ubsan b/gcc/cp/ChangeLog.ubsan new file mode 100644 index 0000000..5674fc0 --- /dev/null +++ b/gcc/cp/ChangeLog.ubsan @@ -0,0 +1,13 @@ +2013-08-20 Marek Polacek + + * error.c (dump_expr): Special-case ubsan builtins. + +2013-07-30 Marek Polacek + + * typeck.c (cp_build_binary_op): Sanitize only when + current_function_decl is not zero. + +2013-07-05 Marek Polacek + + * typeck.c (cp_build_binary_op): Add division by zero and shift + instrumentation. diff --git a/gcc/cp/error.c b/gcc/cp/error.c index af71000..db481a1 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "pointer-set.h" #include "c-family/c-objc.h" +#include "ubsan.h" #include // For placement-new. @@ -2007,6 +2008,12 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) } skipfirst = true; } + if (flag_sanitize & SANITIZE_UNDEFINED + && is_ubsan_builtin_p (fn)) + { + pp_string (cxx_pp, M_("")); + break; + } dump_expr (pp, fn, flags | TFF_EXPR_IN_PARENS); dump_call_expr_args (pp, t, flags, skipfirst); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e09c325..b4abbc5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "convert.h" #include "c-family/c-common.h" #include "c-family/c-objc.h" +#include "c-family/c-ubsan.h" #include "params.h" static tree pfn_from_ptrmemfunc (tree); @@ -3882,6 +3883,7 @@ cp_build_binary_op (location_t location, tree final_type = 0; tree result; + tree orig_type = NULL; /* Nonzero if this is an operation like MIN or MAX which can 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; 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 || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR || code == TRUTH_XOR_EXPR) @@ -4086,8 +4097,12 @@ cp_build_binary_op (location_t location, { enum tree_code tcode0 = code0, tcode1 = code1; 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) tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0))); @@ -4125,8 +4140,11 @@ cp_build_binary_op (location_t location, case FLOOR_MOD_EXPR: { 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 @@ -4180,6 +4198,7 @@ cp_build_binary_op (location_t location, if (TREE_CODE (const_op1) != INTEGER_CST) const_op1 = op1; result_type = type0; + doing_shift = true; if (TREE_CODE (const_op1) == INTEGER_CST) { 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) const_op1 = op1; result_type = type0; + doing_shift = true; if (TREE_CODE (const_op1) == INTEGER_CST) { 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) { + orig_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); } @@ -4863,6 +4884,36 @@ cp_build_binary_op (location_t location, if (build_type == NULL_TREE) 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 = fold_if_not_in_template (result); if (final_type != 0) @@ -4873,6 +4924,10 @@ cp_build_binary_op (location_t location, && !TREE_OVERFLOW_P (op1)) 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; } diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c index 7ce01cb..2ceccdc 100644 --- a/gcc/cppbuiltin.c +++ b/gcc/cppbuiltin.c @@ -90,7 +90,7 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile) cpp_define_formatted (pfile, "__PIE__=%d", flag_pie); } - if (flag_asan) + if (flag_sanitize & SANITIZE_ADDRESS) cpp_define (pfile, "__SANITIZE_ADDRESS__"); if (optimize_size) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0858f2f..1365f65 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -455,7 +455,7 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{@var{object-file-name} -l@var{library} @gol -nostartfiles -nodefaultlibs -nostdlib -pie -rdynamic @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 -T @var{script} -Wl,@var{option} -Xlinker @var{option} @gol -u @var{symbol}} @@ -5208,6 +5208,14 @@ Memory access instructions will be instrumented to detect data race bugs. 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{]} @opindex fdump-final-insns 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 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++ When the @command{g++} program is used to link a C++ program, it normally automatically links against @option{libstdc++}. If diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 8eea9a6..45616bc 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -191,6 +191,19 @@ enum fp_contract_mode { 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. */ enum vtv_priority { VTV_NO_PRIORITY = 0, /* i.E. Do NOT do vtable verification. */ diff --git a/gcc/gcc.c b/gcc/gcc.c index 7c15cf3..d48c4db 100644 --- a/gcc/gcc.c +++ b/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 struct spec_function *lookup_spec_function (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 void set_collect_gcc_options (void); 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 *if_exists_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 *remove_outfile_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. If %* appears in X, all of the alternatives must be starred, and 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; T:Y; else if T was given to GCC, substitutes Y; :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 "" #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 included. */ #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. */ #ifndef SANITIZER_EARLY_SPEC #define SANITIZER_EARLY_SPEC "\ -%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_EARLY_SPEC "} \ - %{fsanitize=thread:" LIBTSAN_EARLY_SPEC "}}}" +%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \ + %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \ + %{%:sanitize(undefined):" LIBUBSAN_EARLY_SPEC "}}}" #endif /* Linker command line options for -fsanitize= late on the command line. */ #ifndef SANITIZER_SPEC #define SANITIZER_SPEC "\ -%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_SPEC "\ +%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\ %{static:%ecannot specify -static with -fsanitize=address}\ - %{fsanitize=thread:%e-fsanitize=address is incompatible with -fsanitize=thread}}\ - %{fsanitize=thread:" LIBTSAN_SPEC "\ - %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}" + %{%:sanitize(thread):%e-fsanitize=address is incompatible with -fsanitize=thread}}\ + %{%:sanitize(thread):" LIBTSAN_SPEC "\ + %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}\ + %{%:sanitize(undefined):" LIBUBSAN_SPEC "}}}" #endif /* 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 }, { "if-exists", if_exists_spec_function }, { "if-exists-else", if_exists_else_spec_function }, + { "sanitize", sanitize_spec_function }, { "replace-outfile", replace_outfile_spec_function }, { "remove-outfile", remove_outfile_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; case ':': - p = handle_spec_function (p); + p = handle_spec_function (p, NULL); if (p == 0) return -1; 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 argument vector in the normal fashion. The function returns a string 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 * -handle_spec_function (const char *p) +handle_spec_function (const char *p, bool *retval_nonnull) { char *func, *args; const char *endp, *funcval; @@ -5568,6 +5601,8 @@ handle_spec_function (const char *p) funcval = eval_spec_function (func, args); if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0) p = NULL; + if (retval_nonnull) + *retval_nonnull = funcval != NULL; free (func); free (args); @@ -5711,19 +5746,28 @@ handle_braces (const char *p) p++, a_is_negated = true; SKIP_WHITE(); - if (*p == '.') - p++, a_is_suffix = true; - else if (*p == ',') - p++, a_is_spectype = true; - - atom = p; - while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '=' - || *p == ',' || *p == '.' || *p == '@') - p++; - end_atom = p; + if (*p == '%' && p[1] == ':') + { + atom = NULL; + 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; + while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '=' + || *p == ',' || *p == '.' || *p == '@') + p++; + end_atom = p; - if (*p == '*') - p++, a_is_starred = 1; + if (*p == '*') + p++, a_is_starred = 1; + } SKIP_WHITE(); switch (*p) @@ -5748,7 +5792,7 @@ handle_braces (const char *p) if (ordered_set) goto invalid; - if (atom == end_atom) + if (atom && atom == end_atom) { if (!n_way_choice || disj_matched || *p == '|' || a_is_negated || a_is_suffix || a_is_spectype @@ -5773,7 +5817,9 @@ handle_braces (const char *p) match. */ 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); else if (a_is_spectype) 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]; } +/* 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. This looks for the first argument in the outfiles array's name and diff --git a/gcc/opts.c b/gcc/opts.c index 6856c3c..133fe0f 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1405,6 +1405,70 @@ common_handle_option (struct gcc_options *opts, opts->x_exit_after_options = true; 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_Os: case OPT_Ofast: diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 99f87e5..4c8a037 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -283,3 +283,17 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_THREAD_FENCE, DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_SIGNAL_FENCE, "__tsan_atomic_signal_fence", 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) diff --git a/gcc/testsuite/ChangeLog.ubsan b/gcc/testsuite/ChangeLog.ubsan new file mode 100644 index 0000000..9ba895e --- /dev/null +++ b/gcc/testsuite/ChangeLog.ubsan @@ -0,0 +1,56 @@ +2013-08-20 Marek Polacek + + * g++.dg/ubsan/div-by-zero-1.C: New test. + +2013-08-15 Marek Polacek + + * 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. + +2013-08-14 Marek Polacek + + * c-c++-common/ubsan/typedef-1.c: New test. + +2013-08-05 Marek Polacek + + * c-c++-common/ubsan/const-char-1.c: New test. + +2013-07-31 Marek Polacek + + * g++.dg/dg.exp: Add missing ubsan tests. + +2013-07-30 Marek Polacek + + * c-c++-common/ubsan/const-expr.c: New test. + +2013-07-22 Marek Polacek + + * c-c++-common/ubsan/div-by-zero-3.c: Add more testing. + * 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. + +2013-07-18 Marek Polacek + + * lib/ubsan-dg.exp: Fix a typo in comment. + +2013-07-15 Marek Polacek + + * lib/ubsan-dg.exp: New file. + * 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. diff --git a/gcc/testsuite/c-c++-common/ubsan/const-char-1.c b/gcc/testsuite/c-c++-common/ubsan/const-char-1.c new file mode 100644 index 0000000..6c2c3f8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/const-char-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=shift" } */ + +void +foo (void) +{ + int y = 1 << 2; + __builtin_printf ("%d\n", y); +} diff --git a/gcc/testsuite/c-c++-common/ubsan/const-expr-1.c b/gcc/testsuite/c-c++-common/ubsan/const-expr-1.c new file mode 100644 index 0000000..f474ec6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/const-expr-1.c @@ -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)); +} diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c new file mode 100644 index 0000000..4e2a2b9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c @@ -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)" } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-2.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-2.c new file mode 100644 index 0000000..ee96738 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-2.c @@ -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)" } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-3.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-3.c new file mode 100644 index 0000000..719e6c9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-3.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-overflow" } */ + +#include + +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)" } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-4.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-4.c new file mode 100644 index 0000000..295f624 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-4.c @@ -0,0 +1,11 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-overflow" } */ + +#include + +int +main (void) +{ + /* This should not fail. */ + return (unsigned int) INT_MIN / -1; +} diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-1.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-1.c new file mode 100644 index 0000000..24532e8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-1.c @@ -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; +} diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-2.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-2.c new file mode 100644 index 0000000..14ac17d --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-2.c @@ -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; +} diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-3.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-3.c new file mode 100644 index 0000000..dd2903b --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-3.c @@ -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; +} diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-4.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-4.c new file mode 100644 index 0000000..aa34a70 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-4.c @@ -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); +} diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-1.c b/gcc/testsuite/c-c++-common/ubsan/shift-1.c new file mode 100644 index 0000000..48cf3cd --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/shift-1.c @@ -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)" } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-2.c b/gcc/testsuite/c-c++-common/ubsan/shift-2.c new file mode 100644 index 0000000..68a7d13 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/shift-2.c @@ -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)" } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-3.c b/gcc/testsuite/c-c++-common/ubsan/shift-3.c new file mode 100644 index 0000000..c639d17 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/shift-3.c @@ -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; +} diff --git a/gcc/testsuite/c-c++-common/ubsan/typedef-1.c b/gcc/testsuite/c-c++-common/ubsan/typedef-1.c new file mode 100644 index 0000000..8dcf451 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/typedef-1.c @@ -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; +} diff --git a/gcc/testsuite/c-c++-common/ubsan/unreachable-1.c b/gcc/testsuite/c-c++-common/ubsan/unreachable-1.c new file mode 100644 index 0000000..336240c --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/unreachable-1.c @@ -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" } */ diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index 710218e..0528538 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -52,6 +52,7 @@ set tests [prune $tests $srcdir/$subdir/tm/*] set tests [prune $tests $srcdir/$subdir/guality/*] set tests [prune $tests $srcdir/$subdir/simulate-thread/*] set tests [prune $tests $srcdir/$subdir/asan/*] +set tests [prune $tests $srcdir/$subdir/ubsan/*] # Main loop. g++-dg-runtest $tests $DEFAULT_CXXFLAGS diff --git a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C new file mode 100644 index 0000000..a5c0e33 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C @@ -0,0 +1,9 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=shift -w -std=c++11" } */ + +int +main (void) +{ + int a = 1; + a <<= 31; +} diff --git a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C new file mode 100644 index 0000000..fbc16df --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C @@ -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" } */ diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C new file mode 100644 index 0000000..d7d2c8f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C @@ -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" } */ + ; +} diff --git a/gcc/testsuite/g++.dg/ubsan/ubsan.exp b/gcc/testsuite/g++.dg/ubsan/ubsan.exp new file mode 100644 index 0000000..b2651a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/ubsan.exp @@ -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 +# . + +# 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 diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-1.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-1.c new file mode 100644 index 0000000..ff6776b --- /dev/null +++ b/gcc/testsuite/gcc.dg/ubsan/c99-shift-1.c @@ -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" } */ diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-2.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-2.c new file mode 100644 index 0000000..7dceb58 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ubsan/c99-shift-2.c @@ -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" } */ diff --git a/gcc/testsuite/gcc.dg/ubsan/ubsan.exp b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp new file mode 100644 index 0000000..d077d1d --- /dev/null +++ b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp @@ -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 +# . + +# 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 diff --git a/gcc/testsuite/lib/ubsan-dg.exp b/gcc/testsuite/lib/ubsan-dg.exp new file mode 100644 index 0000000..4ec5fdf --- /dev/null +++ b/gcc/testsuite/lib/ubsan-dg.exp @@ -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 +# . + +# +# 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 + } +} diff --git a/gcc/toplev.c b/gcc/toplev.c index 53f53fd..4d12bc9 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -573,10 +573,10 @@ compile_file (void) mudflap_finish_file (); /* File-scope initialization for AddressSanitizer. */ - if (flag_asan) + if (flag_sanitize & SANITIZE_ADDRESS) asan_finish_file (); - if (flag_tsan) + if (flag_sanitize & SANITIZE_THREAD) tsan_finish_file (); output_shared_constant_pool (); @@ -1542,12 +1542,12 @@ process_options (void) warn_stack_protect = 0; /* Address Sanitizer needs porting to each target architecture. */ - if (flag_asan + if ((flag_sanitize & SANITIZE_ADDRESS) && (targetm.asan_shadow_offset == NULL || !FRAME_GROWS_DOWNWARD)) { 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 diff --git a/gcc/tree.c b/gcc/tree.c index 5ed0d1d..b469b97 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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)); fileptr_type_node = ptr_type_node; + pointer_sized_int_node = build_nonstandard_integer_type (POINTER_SIZE, 1); + float_type_node = make_node (REAL_TYPE); TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; layout_type (float_type_node); diff --git a/gcc/tree.h b/gcc/tree.h index 501448a..83edaba 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4288,6 +4288,7 @@ enum tree_index TI_VA_LIST_FPR_COUNTER_FIELD, TI_BOOLEAN_TYPE, TI_FILEPTR_TYPE, + TI_POINTER_SIZED_TYPE, TI_DFLOAT32_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] /* The C type `FILE *'. */ #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_false_node global_trees[TI_BOOLEAN_FALSE] diff --git a/gcc/tsan.c b/gcc/tsan.c index b9171c8..fb91129 100644 --- a/gcc/tsan.c +++ b/gcc/tsan.c @@ -713,7 +713,7 @@ tsan_pass (void) static bool tsan_gate (void) { - return flag_tsan != 0; + return (flag_sanitize & SANITIZE_THREAD) != 0; } /* Inserts __tsan_init () into the list of CTORs. */ @@ -775,7 +775,7 @@ make_pass_tsan (gcc::context *ctxt) static bool tsan_gate_O0 (void) { - return flag_tsan != 0 && !optimize; + return (flag_sanitize & SANITIZE_THREAD) != 0 && !optimize; } namespace { diff --git a/gcc/ubsan.c b/gcc/ubsan.c new file mode 100644 index 0000000..e4bdd2a --- /dev/null +++ b/gcc/ubsan.c @@ -0,0 +1,416 @@ +/* UndefinedBehaviorSanitizer, undefined behavior detector. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Marek Polacek + +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 +. */ + +#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 = ""; + 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 *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 *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" diff --git a/gcc/ubsan.h b/gcc/ubsan.h new file mode 100644 index 0000000..3553a6c --- /dev/null +++ b/gcc/ubsan.h @@ -0,0 +1,31 @@ +/* UndefinedBehaviorSanitizer, undefined behavior detector. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Marek Polacek + +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 +. */ + +#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 */ + diff --git a/gcc/varasm.c b/gcc/varasm.c index 69ec26a..0504eeb 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1102,7 +1102,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p) && bss_initializer_p (decl)) { if (!TREE_PUBLIC (decl) - && !(flag_asan && asan_protect_global (decl))) + && !((flag_sanitize & SANITIZE_ADDRESS) + && asan_protect_global (decl))) return lcomm_section; if (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); rounded = size; - if (flag_asan && asan_protect_global (decl)) + if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl)) size += asan_red_zone_size (size); /* 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); - if (flag_asan + if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl)) { asan_protected = true; @@ -3376,7 +3377,8 @@ output_constant_def_contents (rtx symbol) /* We are no longer deferring this constant. */ 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_protected = true; @@ -6291,7 +6293,8 @@ categorize_decl_for_section (const_tree decl, int reloc) else if (TREE_CODE (decl) == STRING_CST) { 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 */ return SECCAT_RODATA; else @@ -6317,7 +6320,8 @@ categorize_decl_for_section (const_tree decl, int reloc) else if (reloc & targetm.asm_out.reloc_rw_mask ()) ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO; 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 location. -fmerge-all-constants allows even that (at the expense of not conforming). */ @@ -7075,7 +7079,7 @@ place_block_symbol (rtx symbol) decl = SYMBOL_REF_DECL (symbol); alignment = DECL_ALIGN (decl); size = get_constant_size (DECL_INITIAL (decl)); - if (flag_asan + if ((flag_sanitize & SANITIZE_ADDRESS) && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST && asan_protect_global (DECL_INITIAL (decl))) size += asan_red_zone_size (size); @@ -7085,7 +7089,8 @@ place_block_symbol (rtx symbol) decl = SYMBOL_REF_DECL (symbol); alignment = get_variable_align (decl); 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); alignment = MAX (alignment, @@ -7235,7 +7240,7 @@ output_object_block (struct object_block *block) DECL_ALIGN (decl)); size = get_constant_size (DECL_INITIAL (decl)); offset += size; - if (flag_asan + if ((flag_sanitize & SANITIZE_ADDRESS) && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST && 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); size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); offset += size; - if (flag_asan && asan_protect_global (decl)) + if ((flag_sanitize & SANITIZE_ADDRESS) + && asan_protect_global (decl)) { size = asan_red_zone_size (size); assemble_zeros (size); diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog index d2c80b3..318a5c7 100644 --- a/libsanitizer/ChangeLog +++ b/libsanitizer/ChangeLog @@ -1,3 +1,13 @@ +2013-07-05 Jakub Jelinek + + * 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 * sanitizer_common/sanitizer_linux.cc (MemoryMappingLayout::Next): diff --git a/libsanitizer/Makefile.am b/libsanitizer/Makefile.am index 308d438..739c33b 100644 --- a/libsanitizer/Makefile.am +++ b/libsanitizer/Makefile.am @@ -1,13 +1,13 @@ ACLOCAL_AMFLAGS = -I .. -I ../config if TSAN_SUPPORTED -SUBDIRS = interception sanitizer_common asan tsan +SUBDIRS = interception sanitizer_common asan tsan ubsan else -SUBDIRS = interception sanitizer_common asan +SUBDIRS = interception sanitizer_common asan ubsan endif if USING_MAC_INTERPOSE -SUBDIRS = sanitizer_common asan +SUBDIRS = sanitizer_common asan ubsan endif # Work around what appears to be a GNU make bug handling MAKEFLAGS diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in index 125692e..286cea6 100644 --- a/libsanitizer/Makefile.in +++ b/libsanitizer/Makefile.in @@ -76,7 +76,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = interception sanitizer_common asan tsan +DIST_SUBDIRS = interception sanitizer_common asan ubsan tsan ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ @@ -209,9 +209,9 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I .. -I ../config -@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan -@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan -@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan +@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan ubsan +@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan ubsan +@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan ubsan # 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 diff --git a/libsanitizer/configure b/libsanitizer/configure index 19a1037..2cad869 100755 --- a/libsanitizer/configure +++ b/libsanitizer/configure @@ -14543,7 +14543,7 @@ fi 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 @@ -15674,6 +15674,7 @@ do "interception/Makefile") CONFIG_FILES="$CONFIG_FILES interception/Makefile" ;; "sanitizer_common/Makefile") CONFIG_FILES="$CONFIG_FILES sanitizer_common/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" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; @@ -17039,6 +17040,17 @@ _EOF . ${multi_basedir}/config-ml.in { ml_norecursion=; unset ml_norecursion;} ;; + "ubsan/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; "tsan/Makefile":F) cat > vpsed$$ << \_EOF s!`test -f '$<' || echo '$(srcdir)/'`!! _EOF diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac index 3cf161d..5919da6 100644 --- a/libsanitizer/configure.ac +++ b/libsanitizer/configure.ac @@ -89,7 +89,7 @@ AM_CONDITIONAL(USING_MAC_INTERPOSE, $MAC_INTERPOSE) AC_CONFIG_FILES([Makefile]) -AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan], [DIR/Makefile ]), +AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan ubsan], [DIR/Makefile ]), [cat > vpsed$$ << \_EOF s!`test -f '$<' || echo '$(srcdir)/'`!! _EOF diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh index 9c29b31..23748a7 100755 --- a/libsanitizer/merge.sh +++ b/libsanitizer/merge.sh @@ -69,6 +69,7 @@ merge lib/asan asan merge lib/tsan/rtl tsan merge lib/sanitizer_common sanitizer_common merge lib/interception interception +merge lib/ubsan ubsan rm -rf upstream