From patchwork Fri Jul 5 14:04:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 257178 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 008402C0090 for ; Sat, 6 Jul 2013 00:04:47 +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:subject:message-id:mime-version:content-type; q=dns; s= default; b=mwz+/nBJyqiE9z8oVlH8CpyQcsHYMFNjAhApsjzprDuDsEjJSn0bj T7zcaBtmLXvDn66sx7yx6aEuYGiUOujgK+uywSSwhKIK0bRpDAf4+FalvZK45Qtj B7y+6fjHtsCba/R2/u6uU6VEyX/nrbx7VJ4Hdxl1QTroJztBURO5R0= 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:subject:message-id:mime-version:content-type; s= default; bh=UQl6Aq7uRL342kpUgOvZAlYXkCA=; b=kmaLdXCmkOdeqz7mFLvh npW2AI7+iEIlijFn3WjqKboEPespi8ZgWO8PcsCsA7kfX2J+ZkCRQksQA8P+/VFT u+0LkAcevbatcJ6VkM2NDO2c2FR3LGFTJuSiv/TNYswcPf+oegW+HLP9OPUF3jrS 1hwDcCT5H+y19cVEb6sG9Uw= Received: (qmail 11905 invoked by alias); 5 Jul 2013 14:04:40 -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 11894 invoked by uid 89); 5 Jul 2013 14:04:39 -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; Fri, 05 Jul 2013 14:04:38 +0000 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 r65E4aMf025470 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 5 Jul 2013 10:04:36 -0400 Received: from redhat.com (ovpn-116-16.ams2.redhat.com [10.36.116.16]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r65E4W8M002762 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for ; Fri, 5 Jul 2013 10:04:34 -0400 Date: Fri, 5 Jul 2013 16:04:31 +0200 From: Marek Polacek To: GCC Patches Subject: [ubsan] Add libcall arguments Message-ID: <20130705140431.GB21800@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) This patch adds creating and passing the arguments for the ubsan library. So, we can finally make use of the ubsan library. We currently sanitize only divisions by zero and shifts. What it can do now is e.g. for: int main (void) { long int a = 4; int b = 113; return a << b; } it at runtime says: xx.c:1:57: runtime error: shift exponent 113 is too large for 64-bit type long int There are a few things I'm not entirely happy about; I have yet to handle freeing the hash table, but I think I'll need the GTY machinery for this (ubsan is not a pass, so I can't just call it at the end of the pas). Or maybe just create a destructor and use append_to_statement_list. The code is still somewhat in flux and may be quite messy, but I wanted to push this one before doing something else. Commited to ubsan branch. 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. Marek --- gcc/c-family/c-ubsan.c.mp 2013-07-05 14:41:56.823158917 +0200 +++ gcc/c-family/c-ubsan.c 2013-07-05 14:42:12.499214028 +0200 @@ -22,9 +22,459 @@ along with GCC; see the file COPYING3. #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 "c-family/c-common.h" #include "c-family/c-ubsan.h" +/* This type represents an entry in the hash table. */ +struct ubsan_typedesc +{ + tree type; + tree decl; +}; + +static alloc_pool ubsan_typedesc_alloc_pool; + +/* Hash table for type descriptors. */ +struct ubsan_typedesc_hasher + : typed_noop_remove +{ + typedef ubsan_typedesc value_type; + typedef ubsan_typedesc compare_type; + + static inline hashval_t hash (const value_type *); + static inline bool equal (const value_type *, const compare_type *); +}; + +/* Hash a memory reference. */ + +inline hashval_t +ubsan_typedesc_hasher::hash (const ubsan_typedesc *data) +{ + hashval_t h = iterative_hash_object (data->type, 0); + h = iterative_hash_object (data->decl, h); + return h; +} + +/* Compare two data types. */ + +inline bool +ubsan_typedesc_hasher::equal (const ubsan_typedesc *d1, + const ubsan_typedesc *d2) +{ + /* ??? Here, the types should have identical __typekind, + _typeinfo and __typename. Is this enough? */ + return d1->type == d2->type; +} + +static hash_table ubsan_typedesc_ht; + +/* Initializes an instance of ubsan_typedesc. */ + +static void +ubsan_typedesc_init (ubsan_typedesc *data, tree type, tree decl) +{ + data->type = type; + data->decl = decl; +} + +/* This creates the alloc pool used to store the instances of + ubsan_typedesc that are stored in the hash table ubsan_typedesc_ht. */ + +static alloc_pool +ubsan_typedesc_get_alloc_pool () +{ + if (ubsan_typedesc_alloc_pool == NULL) + ubsan_typedesc_alloc_pool = create_alloc_pool ("ubsan_typedesc", + sizeof (ubsan_typedesc), + 10); + // XXX But where do we free this? We'll need GTY machinery. + return ubsan_typedesc_alloc_pool; +} + +/* Returns a reference to the hash table containing data type. + This function ensures that the hash table is created. */ + +static hash_table & +get_typedesc_hash_table () +{ + if (!ubsan_typedesc_ht.is_created ()) + ubsan_typedesc_ht.create (10); + + return ubsan_typedesc_ht; +} + +/* Allocates memory for an instance of ubsan_typedesc into the memory + pool returned by ubsan_typedesc_get_alloc_pool and initialize it. + TYPE describes a particular type, DECL is its VAR_DECL. */ + +static ubsan_typedesc * +ubsan_typedesc_new (tree type, tree decl) +{ + ubsan_typedesc *desc = + (ubsan_typedesc *) pool_alloc (ubsan_typedesc_get_alloc_pool ()); + + ubsan_typedesc_init (desc, type, decl); + return desc; +} + +/* Clear all entries from the type descriptor hash table. */ + +static void +empty_ubsan_typedesc_hash_table () +{ + // XXX But when do we call this? + if (ubsan_typedesc_ht.is_created ()) + ubsan_typedesc_ht.empty (); +} + +/* Build the ubsan uptr type. */ + +static tree +uptr_type (void) +{ + return build_nonstandard_integer_type (POINTER_SIZE, 1); +} + +/* Helper routine, which encodes a value in the uptr type. + Arguments with precision <= POINTER_SIZE are passed directly, + the rest is passed by reference. T is a value we are to encode. */ + +static 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, uptr_type (), 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 (uptr_type (), 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; + + 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) ? const_string_type_node + : 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 (); + vec *v; + + xloc = expand_location (loc); + + /* Fill in the values from LOC. */ + vec_alloc (v, 3); + tree ctor = build_constructor (type, v); + 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); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, str); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (unsigned_type_node, + xloc.line)); + CONSTRUCTOR_APPEND_ELT (v, 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. + ??? This is probably too ugly. Tweak it. */ + +static unsigned short +get_tinfo_for_type (tree type) +{ + unsigned short tinfo; + + switch (GET_MODE_SIZE (TYPE_MODE (type))) + { + case 4: + tinfo = 5; + break; + case 8: + tinfo = 6; + break; + case 16: + tinfo = 7; + break; + default: + error ("unexpected size of type %qT", type); + } + + tinfo <<= 1; + + /* The MSB here says whether the value is signed or not. */ + tinfo |= !TYPE_UNSIGNED (type); + return tinfo; +} + +/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type + descriptor. It first looks into the hash table; if not found, + create the VAR_DECL, put it into the hash table and return the + ADDR_EXPR of it. TYPE describes a particular type. */ + +static tree +ubsan_type_descriptor (tree type) +{ + hash_table ht = get_typedesc_hash_table (); + ubsan_typedesc d; + ubsan_typedesc_init (&d, type, NULL); + + ubsan_typedesc **slot = ht.find_slot (&d, INSERT); + if (*slot != NULL) + /* We have the VAR_DECL in the table. Return it. */ + return (*slot)->decl; + + tree dtype = ubsan_type_descriptor_type (); + vec *v; + 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_tinfo_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; + static unsigned int type_var_id_num; + ASM_FORMAT_PRIVATE_NAME (tmp_name, ".Lubsan_type", type_var_id_num++); + tree 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; + + vec_alloc (v, 3); + tree ctor = build_constructor (dtype, v); + 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; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (short_unsigned_type_node, + tkind)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (short_unsigned_type_node, + tinfo)); + CONSTRUCTOR_APPEND_ELT (v, 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 hash table. */ + decl = build_fold_addr_expr (decl); + *slot = ubsan_typedesc_new (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. */ + +static 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; + static unsigned int ubsan_var_id_num; + ASM_FORMAT_PRIVATE_NAME (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 division by zero and INT_MIN / -1. If not instrumenting, return NULL_TREE. */ @@ -38,6 +488,7 @@ ubsan_instrument_division (location_t lo because they are already converted to RESULT_TYPE. */ gcc_assert (type == TREE_TYPE (op1)); + /* TODO: REAL_TYPE is not supported yet. */ if (TREE_CODE (type) != INTEGER_TYPE) return NULL_TREE; @@ -63,8 +514,13 @@ ubsan_instrument_division (location_t lo x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt); t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x); } + 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, 0); + 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; @@ -78,10 +534,12 @@ ubsan_instrument_shift (location_t loc, 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 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 (TREE_TYPE (op1), 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); @@ -90,11 +548,11 @@ ubsan_instrument_shift (location_t loc, (unsigned) x >> (precm1 - y) if non-zero, is undefined. */ if (code == LSHIFT_EXPR - && !TYPE_UNSIGNED (TREE_TYPE (op0)) + && !TYPE_UNSIGNED (type0) && 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_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)); @@ -108,19 +566,25 @@ ubsan_instrument_shift (location_t loc, && (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_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 (TREE_TYPE (op0), 0)); + build_int_cst (type0, 0)); tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt); } + 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, 0); + 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;