From patchwork Wed Jun 12 15:46:41 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 250811 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 "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 4B1F92C0079 for ; Thu, 13 Jun 2013 01:47:00 +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=MdRNhnA3dKVRdCoYE caqsiWa9unqZnoaxM2dLn7RwKATl0Aiz+/zBr1nbr9vvXjPFbGLvpV4AdCaGxcvj 9XZ5H7CGb1u/LO6GT03mU5K712MOYXdFOTB/3lc1DtVCVaItXmjtsznHrj+Rj7Kh D3KHxVM15qx6iDLclEccvy2qUE= 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=7uAs51YHvW7OsVCt4K3VbU2 u2Dk=; b=J1s44dgVV0sEjxatCtSXgG/1/qoPBil8BlxnIV/g6QZM8qkLEAhQFaK rVr73k8YpmPHPBxgimxXDnq/JAWj9gHVNyQM6FljRHHSq6A7aMNGlGcoZ4gqbql3 XL4HMJbqlACAM5tjwW7dc7U5cTUYnSjRFUPUH+kvxUIjmybe4SjY= Received: (qmail 1913 invoked by alias); 12 Jun 2013 15:46:50 -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 1850 invoked by uid 89); 12 Jun 2013 15:46:50 -0000 X-Spam-SWARE-Status: No, score=-6.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS, TW_CX autolearn=ham version=3.3.1 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 12 Jun 2013 15:46:47 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r5CFkkhi028751 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 12 Jun 2013 11:46:46 -0400 Received: from redhat.com (ovpn-116-31.ams2.redhat.com [10.36.116.31]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r5CFkf8e004375 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Wed, 12 Jun 2013 11:46:44 -0400 Date: Wed, 12 Jun 2013 17:46:41 +0200 From: Marek Polacek To: Jakub Jelinek Cc: GCC Patches , Marc Glisse , Jason Merrill Subject: Re: [RFC] Implement Undefined Behavior Sanitizer (take 2) Message-ID: <20130612154641.GB20883@redhat.com> References: <20130611194439.GP4160@redhat.com> <20130611200900.GK2336@tucnak.redhat.com> <20130611202024.GR4160@redhat.com> <20130611203325.GL2336@tucnak.redhat.com> <20130611204012.GS4160@redhat.com> <20130611204412.GM2336@tucnak.redhat.com> <20130612134824.GU4160@redhat.com> <20130612135208.GV2336@tucnak.redhat.com> <20130612151745.GA20883@redhat.com> <20130612152921.GX2336@tucnak.redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20130612152921.GX2336@tucnak.redhat.com> User-Agent: Mutt/1.5.20 (2009-06-14) On Wed, Jun 12, 2013 at 05:29:21PM +0200, Jakub Jelinek wrote: > > @@ -4070,8 +4081,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 (!processing_template_decl && tcode0 == INTEGER_TYPE) > > + doing_div_or_mod = true; > > Either the !processing_template_decl here is unneeded, or > if you'd check it (and perhaps flag_ubsan too) in this part of code, > then you wouldn't need to check it later. Fixed. > > @@ -4832,6 +4853,31 @@ cp_build_binary_op (location_t location, > > if (build_type == NULL_TREE) > > build_type = result_type; > > > > + if (flag_ubsan && !processing_template_decl) > > But, I'd certainly avoid doing the cp_save_expr/maybe_constant_value > etc. for all the binary operations you don't want to instrument > (thus check (doing_div_or_mod || doing_shift) also). Of course. Fixed. > > + { > > + /* 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. */ > > + if (orig_type != NULL && result_type != orig_type) > > + { > > + op0 = cp_convert (orig_type, op0, complain); > > + op1 = cp_convert (orig_type, op1, complain); > > And you don't want to change op0/op1, have your own tree vars, assign > op{0,1} to them and change here if result_type is not orig_type, > then pass those vars to ubsan_instrument_division. Like this? 2013-06-12 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. c-family/ * c-ubsan.c: New file. * c-ubsan.h: New file. cp/ * typeck.c (cp_build_binary_op): Add division by zero and shift instrumentation. c/ * c-typeck.c (build_binary_op): Add division by zero and shift instrumentation. Marek --- gcc/c-family/c-ubsan.c.mp 2013-06-11 19:51:55.555492466 +0200 +++ gcc/c-family/c-ubsan.c 2013-06-12 17:05:20.800370083 +0200 @@ -0,0 +1,127 @@ +/* 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 "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. */ + gcc_assert (type == TREE_TYPE (op1)); + + 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); + } + tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW); + tt = build_call_expr_loc (loc, tt, 0); + 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 op1_utype = unsigned_type_for (TREE_TYPE (op1)); + HOST_WIDE_INT op0_prec = TYPE_PRECISION (TREE_TYPE (op0)); + tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1); + tree precm1 = build_int_cst (TREE_TYPE (op1), 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 (TREE_TYPE (op0)) + && flag_isoc99) + { + tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1); + tt = fold_convert_loc (loc, unsigned_type_for (TREE_TYPE (op0)), 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 (TREE_TYPE (op0)), 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 (TREE_TYPE (op0), 0)); + tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt); + } + + 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, 0); + t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node); + + return t; +} --- gcc/c-family/c-ubsan.h.mp 2013-06-11 19:51:50.616457500 +0200 +++ gcc/c-family/c-ubsan.h 2013-06-11 16:51:38.297942275 +0200 @@ -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_UBSAN_H +#define GCC_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_UBSAN_H */ --- gcc/sanitizer.def.mp 2013-06-11 19:51:43.781408808 +0200 +++ gcc/sanitizer.def 2013-06-11 19:53:37.768224970 +0200 @@ -283,3 +283,13 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOM 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_NORETURN_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_NORETURN_NOTHROW_LEAF_LIST) --- gcc/builtins.def.mp 2013-06-11 19:51:43.790408877 +0200 +++ gcc/builtins.def 2013-06-11 19:53:37.721224606 +0200 @@ -155,7 +155,7 @@ along with GCC; see the file COPYING3. #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_asan || flag_tsan || flag_ubsan)) #undef DEF_CILKPLUS_BUILTIN #define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ --- gcc/Makefile.in.mp 2013-06-11 19:51:43.780408801 +0200 +++ gcc/Makefile.in 2013-06-11 19:53:37.710224521 +0200 @@ -1150,7 +1150,7 @@ C_COMMON_OBJS = c-family/c-common.o c-fa 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 @@ -2021,6 +2021,9 @@ c-family/array-notation-common.o : c-fam 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 + 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) \ --- gcc/doc/invoke.texi.mp 2013-06-11 19:51:43.784408831 +0200 +++ gcc/doc/invoke.texi 2013-06-11 19:53:37.761224914 +0200 @@ -5143,6 +5143,11 @@ Memory access instructions will be instr 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, e.g.@: division by zero or various overflows. + @item -fdump-final-insns@r{[}=@var{file}@r{]} @opindex fdump-final-insns Dump the final internal representation (RTL) to @var{file}. If the --- gcc/cp/typeck.c.mp 2013-06-11 19:51:43.785408839 +0200 +++ gcc/cp/typeck.c 2013-06-12 17:42:40.599293416 +0200 @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. #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); @@ -3867,6 +3868,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. @@ -3891,6 +3893,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) @@ -4070,8 +4081,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))); @@ -4109,8 +4124,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 @@ -4164,6 +4182,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)) @@ -4211,6 +4230,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)) @@ -4765,8 +4785,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); } @@ -4832,6 +4853,34 @@ cp_build_binary_op (location_t location, if (build_type == NULL_TREE) build_type = result_type; + if (flag_ubsan && !processing_template_decl + && (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) @@ -4842,6 +4891,10 @@ cp_build_binary_op (location_t location, && !TREE_OVERFLOW_P (op1)) overflow_warning (location, result); + if (flag_ubsan && instrument_expr != NULL) + result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result), + instrument_expr, result); + return result; } --- gcc/common.opt.mp 2013-06-11 19:51:43.787408855 +0200 +++ gcc/common.opt 2013-06-11 19:53:37.742224768 +0200 @@ -858,6 +858,10 @@ fsanitize=thread Common Report Var(flag_tsan) Enable ThreadSanitizer, a data race detector +fsanitize=undefined +Common Report Var(flag_ubsan) +Enable UndefinedBehaviorSanitizer, an undefined behavior detector + fasynchronous-unwind-tables Common Report Var(flag_asynchronous_unwind_tables) Optimization Generate unwind tables that are exact at each instruction boundary --- gcc/builtin-attrs.def.mp 2013-06-11 19:51:43.791408885 +0200 +++ gcc/builtin-attrs.def 2013-06-11 19:53:37.717224576 +0200 @@ -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,8 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHRO 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_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, \ --- gcc/c/c-typeck.c.mp 2013-06-11 19:51:43.789408869 +0200 +++ gcc/c/c-typeck.c 2013-06-12 17:03:32.582989258 +0200 @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. #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. */ @@ -9527,6 +9528,15 @@ build_binary_op (location_t location, en 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; @@ -9728,6 +9738,7 @@ build_binary_op (location_t location, en 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 @@ -9775,6 +9786,7 @@ build_binary_op (location_t location, en 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 @@ -9873,6 +9885,7 @@ build_binary_op (location_t location, en 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) @@ -9925,6 +9938,7 @@ build_binary_op (location_t location, en 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) @@ -10469,6 +10483,17 @@ build_binary_op (location_t location, en return error_mark_node; } + if (flag_ubsan) + { + /* OP0 and/or OP1 might have side-effects. */ + op0 = c_save_expr (op0); + op1 = c_save_expr (op1); + 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 @@ -10492,6 +10517,11 @@ build_binary_op (location_t location, en if (semantic_result_type) ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); protected_set_expr_location (ret, location); + + if (flag_ubsan && instrument_expr != NULL) + ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), + instrument_expr, ret); + return ret; } --- gcc/asan.c.mp 2013-06-11 19:51:43.793408901 +0200 +++ gcc/asan.c 2013-06-11 19:53:37.713224545 +0200 @@ -2034,6 +2034,9 @@ 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, @@ -2099,6 +2102,9 @@ 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_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, \