2013-08-30 18:12:58 +02:00
|
|
|
/* UndefinedBehaviorSanitizer, undefined behavior detector.
|
2014-01-02 23:23:26 +01:00
|
|
|
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
2013-08-30 18:12:58 +02:00
|
|
|
Contributed by Marek Polacek <polacek@redhat.com>
|
|
|
|
|
|
|
|
This file is part of GCC.
|
|
|
|
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free
|
|
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
|
|
version.
|
|
|
|
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with GCC; see the file COPYING3. If not see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "coretypes.h"
|
|
|
|
#include "tree.h"
|
2013-11-19 13:31:09 +01:00
|
|
|
#include "stor-layout.h"
|
|
|
|
#include "stringpool.h"
|
2013-08-30 18:12:58 +02:00
|
|
|
#include "cgraph.h"
|
2013-11-19 12:45:15 +01:00
|
|
|
#include "tree-pass.h"
|
2013-11-22 16:58:51 +01:00
|
|
|
#include "tree-ssa-alias.h"
|
2013-12-05 19:03:44 +01:00
|
|
|
#include "tree-pretty-print.h"
|
2013-11-22 16:58:51 +01:00
|
|
|
#include "internal-fn.h"
|
|
|
|
#include "gimple-expr.h"
|
2013-08-30 18:12:58 +02:00
|
|
|
#include "gimple.h"
|
2013-11-19 12:45:15 +01:00
|
|
|
#include "gimple-iterator.h"
|
|
|
|
#include "gimple-ssa.h"
|
|
|
|
#include "gimple-walk.h"
|
2013-08-30 18:12:58 +02:00
|
|
|
#include "hashtab.h"
|
|
|
|
#include "output.h"
|
2013-08-31 17:31:34 +02:00
|
|
|
#include "tm_p.h"
|
2013-08-30 18:12:58 +02:00
|
|
|
#include "toplev.h"
|
2013-11-19 12:45:15 +01:00
|
|
|
#include "cfgloop.h"
|
2013-08-30 18:12:58 +02:00
|
|
|
#include "ubsan.h"
|
|
|
|
#include "c-family/c-common.h"
|
2013-12-05 19:03:44 +01:00
|
|
|
#include "rtl.h"
|
|
|
|
#include "expr.h"
|
2013-12-20 10:05:04 +01:00
|
|
|
#include "tree-ssanames.h"
|
|
|
|
#include "asan.h"
|
|
|
|
#include "gimplify-me.h"
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
/* 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_marked_p tree_map_base_marked_p
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
/* Hash from a tree in a tree_type_map. */
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
tree_type_map_hash (const void *item)
|
|
|
|
{
|
|
|
|
return TYPE_UID (((const struct tree_type_map *)item)->type.from);
|
|
|
|
}
|
|
|
|
|
2013-08-30 18:12:58 +02:00
|
|
|
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,
|
2013-12-05 19:03:44 +01:00
|
|
|
the rest is passed by reference. T is a value we are to encode.
|
|
|
|
IN_EXPAND_P is true if this function is called during expansion. */
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
tree
|
2013-12-05 19:03:44 +01:00
|
|
|
ubsan_encode_value (tree t, bool in_expand_p)
|
2013-08-30 18:12:58 +02:00
|
|
|
{
|
|
|
|
tree type = TREE_TYPE (t);
|
2013-12-05 19:03:44 +01:00
|
|
|
const unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
|
|
|
|
if (bitsize <= POINTER_SIZE)
|
|
|
|
switch (TREE_CODE (type))
|
|
|
|
{
|
|
|
|
case BOOLEAN_TYPE:
|
|
|
|
case ENUMERAL_TYPE:
|
|
|
|
case INTEGER_TYPE:
|
2013-08-30 18:12:58 +02:00
|
|
|
return fold_build1 (NOP_EXPR, pointer_sized_int_node, t);
|
2013-12-05 19:03:44 +01:00
|
|
|
case REAL_TYPE:
|
|
|
|
{
|
|
|
|
tree itype = build_nonstandard_integer_type (bitsize, true);
|
|
|
|
t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
|
|
|
|
return fold_convert (pointer_sized_int_node, t);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
gcc_unreachable ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!DECL_P (t) || !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 (type, NULL);
|
|
|
|
tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
|
|
|
|
if (in_expand_p)
|
|
|
|
{
|
|
|
|
rtx mem
|
|
|
|
= assign_stack_temp_for_type (TYPE_MODE (type),
|
|
|
|
GET_MODE_SIZE (TYPE_MODE (type)),
|
|
|
|
type);
|
|
|
|
SET_DECL_RTL (var, mem);
|
|
|
|
expand_assignment (var, t, false);
|
|
|
|
return build_fold_addr_expr (var);
|
|
|
|
}
|
|
|
|
t = build_fold_addr_expr (var);
|
|
|
|
return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
|
|
|
|
}
|
2013-08-30 18:12:58 +02:00
|
|
|
else
|
|
|
|
return build_fold_addr_expr (t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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. */
|
2013-11-26 22:27:19 +01:00
|
|
|
size_t len = strlen (xloc.file);
|
|
|
|
tree str = build_string (len + 1, xloc.file);
|
2013-08-30 18:12:58 +02:00
|
|
|
TREE_TYPE (str) = build_array_type (char_type_node,
|
|
|
|
build_index_type (size_int (len)));
|
|
|
|
TREE_READONLY (str) = 1;
|
|
|
|
TREE_STATIC (str) = 1;
|
2013-11-26 22:27:19 +01:00
|
|
|
str = build_fold_addr_expr (str);
|
2013-08-30 18:12:58 +02:00
|
|
|
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)
|
|
|
|
{
|
decl.c, [...]: Replace host_integerp (..., 1) with tree_fits_uhwi_p throughout.
gcc/ada/
* gcc-interface/decl.c, gcc-interface/misc.c, gcc-interface/utils.c:
Replace host_integerp (..., 1) with tree_fits_uhwi_p throughout.
gcc/c-family/
* c-ada-spec.c, c-common.c, c-pretty-print.c: Replace
host_integerp (..., 1) with tree_fits_uhwi_p throughout.
gcc/cp/
* decl.c: Replace host_integerp (..., 1) with tree_fits_uhwi_p
throughout.
gcc/
* builtins.c, config/alpha/alpha.c, config/iq2000/iq2000.c,
config/mips/mips.c, dbxout.c, dwarf2out.c, expr.c, fold-const.c,
gimple-fold.c, godump.c, omp-low.c, predict.c, sdbout.c, stor-layout.c,
tree-dfa.c, tree-sra.c, tree-ssa-forwprop.c, tree-ssa-loop-prefetch.c,
tree-ssa-phiopt.c, tree-ssa-sccvn.c, tree-ssa-strlen.c,
tree-ssa-structalias.c, tree-vect-data-refs.c, tree-vect-patterns.c,
tree.c, varasm.c, alias.c, cfgexpand.c, config/aarch64/aarch64.c,
config/arm/arm.c, config/epiphany/epiphany.c, config/i386/i386.c,
config/m32c/m32c-pragma.c, config/mep/mep-pragma.c,
config/rs6000/rs6000.c, config/sparc/sparc.c, emit-rtl.c, function.c,
gimplify.c, ipa-prop.c, stmt.c, trans-mem.c, tree-cfg.c,
tree-object-size.c, tree-ssa-ccp.c, tree-ssa-loop-ivcanon.c,
tree-stdarg.c, tree-switch-conversion.c, tree-vect-generic.c,
tree-vrp.c, tsan.c, ubsan.c: Replace host_integerp (..., 1) with
tree_fits_uhwi_p throughout.
From-SVN: r204956
2013-11-18 15:51:26 +01:00
|
|
|
gcc_assert (TYPE_SIZE (type) && tree_fits_uhwi_p (TYPE_SIZE (type)));
|
decl.c, [...]: Replace tree_low_cst (..., 1) with tree_to_uhwi throughout.
gcc/ada/
* gcc-interface/decl.c, gcc-interface/utils.c, gcc-interface/utils2.c:
Replace tree_low_cst (..., 1) with tree_to_uhwi throughout.
gcc/c-family/
* c-common.c, c-cppbuiltin.c: Replace tree_low_cst (..., 1) with
tree_to_uhwi throughout.
gcc/c/
* c-decl.c, c-typeck.c: Replace tree_low_cst (..., 1) with
tree_to_uhwi throughout.
gcc/cp/
* call.c, class.c, decl.c, error.c: Replace tree_low_cst (..., 1) with
tree_to_uhwi throughout.
gcc/objc/
* objc-encoding.c: Replace tree_low_cst (..., 1) with tree_to_uhwi
throughout.
gcc/
* alias.c, asan.c, builtins.c, cfgexpand.c, cgraph.c,
config/aarch64/aarch64.c, config/alpha/predicates.md,
config/arm/arm.c, config/darwin.c, config/epiphany/epiphany.c,
config/i386/i386.c, config/iq2000/iq2000.c, config/m32c/m32c-pragma.c,
config/mep/mep-pragma.c, config/mips/mips.c,
config/picochip/picochip.c, config/rs6000/rs6000.c, cppbuiltin.c,
dbxout.c, dwarf2out.c, emit-rtl.c, except.c, expr.c, fold-const.c,
function.c, gimple-fold.c, godump.c, ipa-cp.c, ipa-prop.c, omp-low.c,
predict.c, sdbout.c, stor-layout.c, trans-mem.c, tree-object-size.c,
tree-sra.c, tree-ssa-ccp.c, tree-ssa-forwprop.c,
tree-ssa-loop-ivcanon.c, tree-ssa-loop-ivopts.c, tree-ssa-loop-niter.c,
tree-ssa-loop-prefetch.c, tree-ssa-strlen.c, tree-stdarg.c,
tree-switch-conversion.c, tree-vect-generic.c, tree-vect-loop.c,
tree-vect-patterns.c, tree-vrp.c, tree.c, tsan.c, ubsan.c, varasm.c:
Replace tree_low_cst (..., 1) with tree_to_uhwi throughout.
From-SVN: r204961
2013-11-18 15:52:19 +01:00
|
|
|
int prec = exact_log2 (tree_to_uhwi (TYPE_SIZE (type)));
|
2013-09-20 15:26:07 +02:00
|
|
|
gcc_assert (prec != -1);
|
2013-08-30 18:12:58 +02:00
|
|
|
return (prec << 1) | !TYPE_UNSIGNED (type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
|
2013-11-19 12:45:15 +01:00
|
|
|
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. WANT_POINTER_TYPE_P
|
|
|
|
means whether we are interested in the pointer type and not the pointer
|
|
|
|
itself. */
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
tree
|
2013-11-19 12:45:15 +01:00
|
|
|
ubsan_type_descriptor (tree type, bool want_pointer_type_p)
|
2013-08-30 18:12:58 +02:00
|
|
|
{
|
|
|
|
/* See through any typedefs. */
|
|
|
|
type = TYPE_MAIN_VARIANT (type);
|
|
|
|
|
|
|
|
tree decl = decl_for_type_lookup (type);
|
2013-11-27 09:02:48 +01:00
|
|
|
/* It is possible that some of the earlier created DECLs were found
|
|
|
|
unused, in that case they weren't emitted and varpool_get_node
|
|
|
|
returns NULL node on them. But now we really need them. Thus,
|
|
|
|
renew them here. */
|
|
|
|
if (decl != NULL_TREE && varpool_get_node (decl))
|
|
|
|
return build_fold_addr_expr (decl);
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
tree dtype = ubsan_type_descriptor_type ();
|
2013-11-19 12:45:15 +01:00
|
|
|
tree type2 = type;
|
|
|
|
const char *tname = NULL;
|
|
|
|
char *pretty_name;
|
|
|
|
unsigned char deref_depth = 0;
|
2013-08-30 18:12:58 +02:00
|
|
|
unsigned short tkind, tinfo;
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
/* Get the name of the type, or the name of the pointer type. */
|
|
|
|
if (want_pointer_type_p)
|
|
|
|
{
|
|
|
|
gcc_assert (POINTER_TYPE_P (type));
|
|
|
|
type2 = TREE_TYPE (type);
|
|
|
|
|
|
|
|
/* Remove any '*' operators from TYPE. */
|
|
|
|
while (POINTER_TYPE_P (type2))
|
|
|
|
deref_depth++, type2 = TREE_TYPE (type2);
|
|
|
|
|
|
|
|
if (TREE_CODE (type2) == METHOD_TYPE)
|
|
|
|
type2 = TYPE_METHOD_BASETYPE (type2);
|
|
|
|
}
|
|
|
|
|
2014-01-08 11:06:09 +01:00
|
|
|
/* If an array, get its type. */
|
|
|
|
type2 = strip_array_types (type2);
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
if (TYPE_NAME (type2) != NULL)
|
2013-09-25 11:04:20 +02:00
|
|
|
{
|
2013-11-19 12:45:15 +01:00
|
|
|
if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE)
|
|
|
|
tname = IDENTIFIER_POINTER (TYPE_NAME (type2));
|
2013-09-25 11:04:20 +02:00
|
|
|
else
|
2013-11-19 12:45:15 +01:00
|
|
|
tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2)));
|
2013-09-25 11:04:20 +02:00
|
|
|
}
|
2013-11-19 12:45:15 +01:00
|
|
|
|
|
|
|
if (tname == NULL)
|
|
|
|
/* We weren't able to determine the type name. */
|
2013-08-30 18:12:58 +02:00
|
|
|
tname = "<unknown>";
|
2013-09-25 11:04:20 +02:00
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
/* Decorate the type name with '', '*', "struct", or "union". */
|
|
|
|
pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth);
|
|
|
|
if (want_pointer_type_p)
|
2013-08-30 18:12:58 +02:00
|
|
|
{
|
2013-11-19 12:45:15 +01:00
|
|
|
int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s",
|
|
|
|
TYPE_VOLATILE (type2) ? "volatile " : "",
|
|
|
|
TYPE_READONLY (type2) ? "const " : "",
|
|
|
|
TYPE_RESTRICT (type2) ? "restrict " : "",
|
|
|
|
TYPE_ATOMIC (type2) ? "_Atomic " : "",
|
|
|
|
TREE_CODE (type2) == RECORD_TYPE
|
|
|
|
? "struct "
|
|
|
|
: TREE_CODE (type2) == UNION_TYPE
|
|
|
|
? "union " : "", tname,
|
|
|
|
deref_depth == 0 ? "" : " ");
|
|
|
|
while (deref_depth-- > 0)
|
|
|
|
pretty_name[pos++] = '*';
|
|
|
|
pretty_name[pos++] = '\'';
|
|
|
|
pretty_name[pos] = '\0';
|
2013-08-30 18:12:58 +02:00
|
|
|
}
|
|
|
|
else
|
2013-11-19 12:45:15 +01:00
|
|
|
sprintf (pretty_name, "'%s'", tname);
|
|
|
|
|
|
|
|
switch (TREE_CODE (type))
|
|
|
|
{
|
2013-12-20 10:05:04 +01:00
|
|
|
case BOOLEAN_TYPE:
|
|
|
|
case ENUMERAL_TYPE:
|
2013-11-19 12:45:15 +01:00
|
|
|
case INTEGER_TYPE:
|
|
|
|
tkind = 0x0000;
|
|
|
|
break;
|
|
|
|
case REAL_TYPE:
|
|
|
|
tkind = 0x0001;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tkind = 0xffff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
tinfo = get_ubsan_type_info_for_type (type);
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
size_t len = strlen (pretty_name);
|
|
|
|
tree str = build_string (len + 1, pretty_name);
|
2013-08-30 18:12:58 +02:00
|
|
|
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;
|
2014-03-18 15:56:23 +01:00
|
|
|
varpool_finalize_decl (decl);
|
2013-08-30 18:12:58 +02:00
|
|
|
|
2013-11-27 09:02:48 +01:00
|
|
|
/* Save the VAR_DECL into the hash table. */
|
2013-08-30 18:12:58 +02:00
|
|
|
decl_for_type_insert (type, decl);
|
|
|
|
|
2013-11-27 09:02:48 +01:00
|
|
|
return build_fold_addr_expr (decl);
|
2013-08-30 18:12:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a structure for the ubsan library. NAME is a name of the new
|
|
|
|
structure. The arguments in ... are of __ubsan_type_descriptor type
|
2013-11-19 12:45:15 +01:00
|
|
|
and there are at most two of them. MISMATCH are data used by ubsan
|
|
|
|
pointer checking. */
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
tree
|
2013-11-19 12:45:15 +01:00
|
|
|
ubsan_create_data (const char *name, location_t loc,
|
|
|
|
const struct ubsan_mismatch_data *mismatch, ...)
|
2013-08-30 18:12:58 +02:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
tree ret, t;
|
2013-11-25 11:46:20 +01:00
|
|
|
tree fields[5];
|
2013-08-30 18:12:58 +02:00
|
|
|
vec<tree, va_gc> *saved_args = NULL;
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
/* Firstly, create a pointer to type descriptor type. */
|
|
|
|
tree td_type = ubsan_type_descriptor_type ();
|
|
|
|
TYPE_READONLY (td_type) = 1;
|
|
|
|
td_type = build_pointer_type (td_type);
|
2013-11-26 22:27:19 +01:00
|
|
|
loc = LOCATION_LOCUS (loc);
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
/* 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++;
|
|
|
|
}
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
va_start (args, mismatch);
|
2013-08-30 18:12:58 +02:00
|
|
|
for (t = va_arg (args, tree); t != NULL_TREE;
|
|
|
|
i++, t = va_arg (args, tree))
|
|
|
|
{
|
|
|
|
gcc_checking_assert (i < 3);
|
2013-11-19 12:45:15 +01:00
|
|
|
/* Save the tree arguments for later use. */
|
2013-08-30 18:12:58 +02:00
|
|
|
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];
|
|
|
|
}
|
2013-11-19 12:45:15 +01:00
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
if (mismatch != NULL)
|
|
|
|
{
|
|
|
|
/* We have to add two more decls. */
|
|
|
|
fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
|
2013-11-25 11:46:20 +01:00
|
|
|
pointer_sized_int_node);
|
2013-11-19 12:45:15 +01:00
|
|
|
DECL_CONTEXT (fields[i]) = ret;
|
|
|
|
DECL_CHAIN (fields[i - 1]) = fields[i];
|
|
|
|
i++;
|
|
|
|
|
|
|
|
fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
|
|
|
|
unsigned_char_type_node);
|
|
|
|
DECL_CONTEXT (fields[i]) = ret;
|
|
|
|
DECL_CHAIN (fields[i - 1]) = fields[i];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2013-08-30 18:12:58 +02:00
|
|
|
TYPE_FIELDS (ret) = fields[0];
|
|
|
|
TYPE_NAME (ret) = get_identifier (name);
|
|
|
|
layout_type (ret);
|
|
|
|
|
|
|
|
/* Now, fill in the type. */
|
|
|
|
char tmp_name[32];
|
|
|
|
static unsigned int ubsan_var_id_num;
|
|
|
|
ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++);
|
|
|
|
tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
|
|
|
|
ret);
|
|
|
|
TREE_STATIC (var) = 1;
|
|
|
|
TREE_PUBLIC (var) = 0;
|
|
|
|
DECL_ARTIFICIAL (var) = 1;
|
|
|
|
DECL_IGNORED_P (var) = 1;
|
|
|
|
DECL_EXTERNAL (var) = 0;
|
|
|
|
|
|
|
|
vec<constructor_elt, va_gc> *v;
|
|
|
|
vec_alloc (v, i);
|
|
|
|
tree ctor = build_constructor (ret, v);
|
|
|
|
|
|
|
|
/* If desirable, set the __ubsan_source_location element. */
|
|
|
|
if (loc != UNKNOWN_LOCATION)
|
|
|
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc));
|
|
|
|
|
|
|
|
size_t nelts = vec_safe_length (saved_args);
|
|
|
|
for (i = 0; i < nelts; i++)
|
|
|
|
{
|
|
|
|
t = (*saved_args)[i];
|
|
|
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t);
|
|
|
|
}
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
if (mismatch != NULL)
|
|
|
|
{
|
|
|
|
/* Append the pointer data. */
|
|
|
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, mismatch->align);
|
|
|
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, mismatch->ckind);
|
|
|
|
}
|
|
|
|
|
2013-08-30 18:12:58 +02:00
|
|
|
TREE_CONSTANT (ctor) = 1;
|
|
|
|
TREE_STATIC (ctor) = 1;
|
|
|
|
DECL_INITIAL (var) = ctor;
|
2014-03-18 15:56:23 +01:00
|
|
|
varpool_finalize_decl (var);
|
2013-08-30 18:12:58 +02:00
|
|
|
|
|
|
|
return var;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Instrument the __builtin_unreachable call. We just call the libubsan
|
|
|
|
routine instead. */
|
|
|
|
|
|
|
|
tree
|
|
|
|
ubsan_instrument_unreachable (location_t loc)
|
|
|
|
{
|
2014-03-18 16:05:30 +01:00
|
|
|
initialize_sanitizer_builtins ();
|
2013-11-19 12:45:15 +01:00
|
|
|
tree data = ubsan_create_data ("__ubsan_unreachable_data", loc, NULL,
|
|
|
|
NULL_TREE);
|
2013-08-30 18:12:58 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
/* Expand UBSAN_NULL internal call. */
|
|
|
|
|
|
|
|
void
|
|
|
|
ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
|
|
|
|
{
|
|
|
|
gimple stmt = gsi_stmt (gsi);
|
|
|
|
location_t loc = gimple_location (stmt);
|
|
|
|
gcc_assert (gimple_call_num_args (stmt) == 2);
|
|
|
|
tree ptr = gimple_call_arg (stmt, 0);
|
|
|
|
tree ckind = gimple_call_arg (stmt, 1);
|
|
|
|
|
|
|
|
basic_block cur_bb = gsi_bb (gsi);
|
|
|
|
|
|
|
|
/* Split the original block holding the pointer dereference. */
|
|
|
|
edge e = split_block (cur_bb, stmt);
|
|
|
|
|
|
|
|
/* Get a hold on the 'condition block', the 'then block' and the
|
|
|
|
'else block'. */
|
|
|
|
basic_block cond_bb = e->src;
|
|
|
|
basic_block fallthru_bb = e->dest;
|
|
|
|
basic_block then_bb = create_empty_bb (cond_bb);
|
|
|
|
if (current_loops)
|
|
|
|
{
|
|
|
|
add_bb_to_loop (then_bb, cond_bb->loop_father);
|
|
|
|
loops_state_set (LOOPS_NEED_FIXUP);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make an edge coming from the 'cond block' into the 'then block';
|
|
|
|
this edge is unlikely taken, so set up the probability accordingly. */
|
|
|
|
e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
|
|
|
|
e->probability = PROB_VERY_UNLIKELY;
|
|
|
|
|
|
|
|
/* Connect 'then block' with the 'else block'. This is needed
|
|
|
|
as the ubsan routines we call in the 'then block' are not noreturn.
|
|
|
|
The 'then block' only has one outcoming edge. */
|
|
|
|
make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
|
|
|
|
|
|
|
|
/* Set up the fallthrough basic block. */
|
|
|
|
e = find_edge (cond_bb, fallthru_bb);
|
|
|
|
e->flags = EDGE_FALSE_VALUE;
|
|
|
|
e->count = cond_bb->count;
|
|
|
|
e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY;
|
|
|
|
|
|
|
|
/* Update dominance info for the newly created then_bb; note that
|
|
|
|
fallthru_bb's dominance info has already been updated by
|
|
|
|
split_bock. */
|
|
|
|
if (dom_info_available_p (CDI_DOMINATORS))
|
|
|
|
set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
|
|
|
|
|
|
|
|
/* Put the ubsan builtin call into the newly created BB. */
|
|
|
|
tree fn = builtin_decl_implicit (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH);
|
|
|
|
const struct ubsan_mismatch_data m
|
|
|
|
= { build_zero_cst (pointer_sized_int_node), ckind };
|
|
|
|
tree data = ubsan_create_data ("__ubsan_null_data",
|
|
|
|
loc, &m,
|
|
|
|
ubsan_type_descriptor (TREE_TYPE (ptr), true),
|
|
|
|
NULL_TREE);
|
|
|
|
data = build_fold_addr_expr_loc (loc, data);
|
|
|
|
gimple g = gimple_build_call (fn, 2, data,
|
|
|
|
build_zero_cst (pointer_sized_int_node));
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
|
|
|
|
gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
|
|
|
|
|
|
|
|
/* Unlink the UBSAN_NULLs vops before replacing it. */
|
|
|
|
unlink_stmt_vdef (stmt);
|
|
|
|
|
|
|
|
g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
|
|
|
|
NULL_TREE, NULL_TREE);
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
|
|
|
|
/* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
|
|
|
|
gsi_replace (&gsi, g, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Instrument a member call. We check whether 'this' is NULL. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
instrument_member_call (gimple_stmt_iterator *iter)
|
|
|
|
{
|
|
|
|
tree this_parm = gimple_call_arg (gsi_stmt (*iter), 0);
|
|
|
|
tree kind = build_int_cst (unsigned_char_type_node, UBSAN_MEMBER_CALL);
|
|
|
|
gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 2, this_parm, kind);
|
|
|
|
gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
|
|
|
|
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Instrument a memory reference. T is the pointer, IS_LHS says
|
|
|
|
whether the pointer is on the left hand side of the assignment. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
instrument_mem_ref (tree t, gimple_stmt_iterator *iter, bool is_lhs)
|
|
|
|
{
|
|
|
|
enum ubsan_null_ckind ikind = is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF;
|
|
|
|
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (t))))
|
|
|
|
ikind = UBSAN_MEMBER_ACCESS;
|
|
|
|
tree kind = build_int_cst (unsigned_char_type_node, ikind);
|
|
|
|
gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 2, t, kind);
|
|
|
|
gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
|
|
|
|
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
|
|
|
}
|
|
|
|
|
2013-11-27 12:40:22 +01:00
|
|
|
/* Perform the pointer instrumentation. */
|
2013-11-19 12:45:15 +01:00
|
|
|
|
2013-11-27 12:40:22 +01:00
|
|
|
static void
|
|
|
|
instrument_null (gimple_stmt_iterator gsi, bool is_lhs)
|
2013-11-19 12:45:15 +01:00
|
|
|
{
|
2013-11-27 12:40:22 +01:00
|
|
|
gimple stmt = gsi_stmt (gsi);
|
|
|
|
tree t = is_lhs ? gimple_get_lhs (stmt) : gimple_assign_rhs1 (stmt);
|
|
|
|
t = get_base_address (t);
|
2013-11-19 12:45:15 +01:00
|
|
|
const enum tree_code code = TREE_CODE (t);
|
|
|
|
if (code == MEM_REF
|
|
|
|
&& TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
|
2013-11-27 12:40:22 +01:00
|
|
|
instrument_mem_ref (TREE_OPERAND (t, 0), &gsi, is_lhs);
|
2013-11-19 12:45:15 +01:00
|
|
|
else if (code == ADDR_EXPR
|
|
|
|
&& POINTER_TYPE_P (TREE_TYPE (t))
|
|
|
|
&& TREE_CODE (TREE_TYPE (TREE_TYPE (t))) == METHOD_TYPE)
|
2013-11-27 12:40:22 +01:00
|
|
|
instrument_member_call (&gsi);
|
2013-11-19 12:45:15 +01:00
|
|
|
}
|
|
|
|
|
2013-12-04 23:47:11 +01:00
|
|
|
/* Build an ubsan builtin call for the signed-integer-overflow
|
|
|
|
sanitization. CODE says what kind of builtin are we building,
|
|
|
|
LOC is a location, LHSTYPE is the type of LHS, OP0 and OP1
|
|
|
|
are operands of the binary operation. */
|
|
|
|
|
|
|
|
tree
|
|
|
|
ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype,
|
|
|
|
tree op0, tree op1)
|
|
|
|
{
|
|
|
|
tree data = ubsan_create_data ("__ubsan_overflow_data", loc, NULL,
|
|
|
|
ubsan_type_descriptor (lhstype, false),
|
|
|
|
NULL_TREE);
|
|
|
|
enum built_in_function fn_code;
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
{
|
|
|
|
case PLUS_EXPR:
|
|
|
|
fn_code = BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW;
|
|
|
|
break;
|
|
|
|
case MINUS_EXPR:
|
|
|
|
fn_code = BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW;
|
|
|
|
break;
|
|
|
|
case MULT_EXPR:
|
|
|
|
fn_code = BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW;
|
|
|
|
break;
|
|
|
|
case NEGATE_EXPR:
|
|
|
|
fn_code = BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gcc_unreachable ();
|
|
|
|
}
|
|
|
|
tree fn = builtin_decl_explicit (fn_code);
|
|
|
|
return build_call_expr_loc (loc, fn, 2 + (code != NEGATE_EXPR),
|
|
|
|
build_fold_addr_expr_loc (loc, data),
|
2013-12-05 19:03:44 +01:00
|
|
|
ubsan_encode_value (op0, true),
|
|
|
|
op1 ? ubsan_encode_value (op1, true)
|
|
|
|
: NULL_TREE);
|
2013-12-04 23:47:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Perform the signed integer instrumentation. GSI is the iterator
|
|
|
|
pointing at statement we are trying to instrument. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
instrument_si_overflow (gimple_stmt_iterator gsi)
|
|
|
|
{
|
|
|
|
gimple stmt = gsi_stmt (gsi);
|
|
|
|
tree_code code = gimple_assign_rhs_code (stmt);
|
|
|
|
tree lhs = gimple_assign_lhs (stmt);
|
|
|
|
tree lhstype = TREE_TYPE (lhs);
|
|
|
|
tree a, b;
|
|
|
|
gimple g;
|
|
|
|
|
|
|
|
/* If this is not a signed operation, don't instrument anything here.
|
|
|
|
Also punt on bit-fields. */
|
|
|
|
if (!INTEGRAL_TYPE_P (lhstype)
|
|
|
|
|| TYPE_OVERFLOW_WRAPS (lhstype)
|
|
|
|
|| GET_MODE_BITSIZE (TYPE_MODE (lhstype)) != TYPE_PRECISION (lhstype))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
{
|
|
|
|
case MINUS_EXPR:
|
|
|
|
case PLUS_EXPR:
|
|
|
|
case MULT_EXPR:
|
|
|
|
/* Transform
|
|
|
|
i = u {+,-,*} 5;
|
|
|
|
into
|
|
|
|
i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5); */
|
|
|
|
a = gimple_assign_rhs1 (stmt);
|
|
|
|
b = gimple_assign_rhs2 (stmt);
|
|
|
|
g = gimple_build_call_internal (code == PLUS_EXPR
|
|
|
|
? IFN_UBSAN_CHECK_ADD
|
|
|
|
: code == MINUS_EXPR
|
|
|
|
? IFN_UBSAN_CHECK_SUB
|
|
|
|
: IFN_UBSAN_CHECK_MUL, 2, a, b);
|
|
|
|
gimple_call_set_lhs (g, lhs);
|
|
|
|
gsi_replace (&gsi, g, false);
|
|
|
|
break;
|
|
|
|
case NEGATE_EXPR:
|
|
|
|
/* Represent i = -u;
|
|
|
|
as
|
|
|
|
i = UBSAN_CHECK_SUB (0, u); */
|
|
|
|
a = build_int_cst (lhstype, 0);
|
|
|
|
b = gimple_assign_rhs1 (stmt);
|
|
|
|
g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
|
|
|
|
gimple_call_set_lhs (g, lhs);
|
|
|
|
gsi_replace (&gsi, g, false);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-20 10:05:04 +01:00
|
|
|
/* Instrument loads from (non-bitfield) bool and C++ enum values
|
|
|
|
to check if the memory value is outside of the range of the valid
|
|
|
|
type values. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
instrument_bool_enum_load (gimple_stmt_iterator *gsi)
|
|
|
|
{
|
|
|
|
gimple stmt = gsi_stmt (*gsi);
|
|
|
|
tree rhs = gimple_assign_rhs1 (stmt);
|
|
|
|
tree type = TREE_TYPE (rhs);
|
|
|
|
tree minv = NULL_TREE, maxv = NULL_TREE;
|
|
|
|
|
|
|
|
if (TREE_CODE (type) == BOOLEAN_TYPE && (flag_sanitize & SANITIZE_BOOL))
|
|
|
|
{
|
|
|
|
minv = boolean_false_node;
|
|
|
|
maxv = boolean_true_node;
|
|
|
|
}
|
|
|
|
else if (TREE_CODE (type) == ENUMERAL_TYPE
|
|
|
|
&& (flag_sanitize & SANITIZE_ENUM)
|
|
|
|
&& TREE_TYPE (type) != NULL_TREE
|
|
|
|
&& TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
|
|
|
|
&& (TYPE_PRECISION (TREE_TYPE (type))
|
|
|
|
< GET_MODE_PRECISION (TYPE_MODE (type))))
|
|
|
|
{
|
|
|
|
minv = TYPE_MIN_VALUE (TREE_TYPE (type));
|
|
|
|
maxv = TYPE_MAX_VALUE (TREE_TYPE (type));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
int modebitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
|
|
|
|
HOST_WIDE_INT bitsize, bitpos;
|
|
|
|
tree offset;
|
|
|
|
enum machine_mode mode;
|
|
|
|
int volatilep = 0, unsignedp = 0;
|
|
|
|
tree base = get_inner_reference (rhs, &bitsize, &bitpos, &offset, &mode,
|
|
|
|
&unsignedp, &volatilep, false);
|
|
|
|
tree utype = build_nonstandard_integer_type (modebitsize, 1);
|
|
|
|
|
|
|
|
if ((TREE_CODE (base) == VAR_DECL && DECL_HARD_REGISTER (base))
|
|
|
|
|| (bitpos % modebitsize) != 0
|
|
|
|
|| bitsize != modebitsize
|
|
|
|
|| GET_MODE_BITSIZE (TYPE_MODE (utype)) != modebitsize
|
|
|
|
|| TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
|
|
|
|
return;
|
|
|
|
|
|
|
|
location_t loc = gimple_location (stmt);
|
|
|
|
tree ptype = build_pointer_type (TREE_TYPE (rhs));
|
|
|
|
tree atype = reference_alias_ptr_type (rhs);
|
|
|
|
gimple g = gimple_build_assign (make_ssa_name (ptype, NULL),
|
|
|
|
build_fold_addr_expr (rhs));
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
gsi_insert_before (gsi, g, GSI_SAME_STMT);
|
|
|
|
tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g),
|
|
|
|
build_int_cst (atype, 0));
|
|
|
|
tree urhs = make_ssa_name (utype, NULL);
|
|
|
|
g = gimple_build_assign (urhs, mem);
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
gsi_insert_before (gsi, g, GSI_SAME_STMT);
|
|
|
|
minv = fold_convert (utype, minv);
|
|
|
|
maxv = fold_convert (utype, maxv);
|
|
|
|
if (!integer_zerop (minv))
|
|
|
|
{
|
|
|
|
g = gimple_build_assign_with_ops (MINUS_EXPR,
|
|
|
|
make_ssa_name (utype, NULL),
|
|
|
|
urhs, minv);
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
gsi_insert_before (gsi, g, GSI_SAME_STMT);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimple_stmt_iterator gsi2 = *gsi;
|
|
|
|
basic_block then_bb, fallthru_bb;
|
|
|
|
*gsi = create_cond_insert_point (gsi, true, false, true,
|
|
|
|
&then_bb, &fallthru_bb);
|
|
|
|
g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g),
|
|
|
|
int_const_binop (MINUS_EXPR, maxv, minv),
|
|
|
|
NULL_TREE, NULL_TREE);
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
gsi_insert_after (gsi, g, GSI_NEW_STMT);
|
|
|
|
|
|
|
|
gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs, NULL_TREE);
|
|
|
|
update_stmt (stmt);
|
|
|
|
|
|
|
|
tree data = ubsan_create_data ("__ubsan_invalid_value_data",
|
|
|
|
loc, NULL,
|
|
|
|
ubsan_type_descriptor (type, false),
|
|
|
|
NULL_TREE);
|
|
|
|
data = build_fold_addr_expr_loc (loc, data);
|
|
|
|
tree fn = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE);
|
|
|
|
|
|
|
|
gsi2 = gsi_after_labels (then_bb);
|
|
|
|
tree val = force_gimple_operand_gsi (&gsi2, ubsan_encode_value (urhs),
|
|
|
|
true, NULL_TREE, true, GSI_SAME_STMT);
|
|
|
|
g = gimple_build_call (fn, 2, data, val);
|
|
|
|
gimple_set_location (g, loc);
|
|
|
|
gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
|
|
|
|
}
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
/* Gate and execute functions for ubsan pass. */
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
ubsan_pass (void)
|
|
|
|
{
|
|
|
|
basic_block bb;
|
|
|
|
gimple_stmt_iterator gsi;
|
|
|
|
|
2014-03-18 16:05:30 +01:00
|
|
|
initialize_sanitizer_builtins ();
|
|
|
|
|
Eliminate FOR_EACH_BB macro.
gcc/
* basic-block.h (FOR_EACH_BB): Eliminate macro.
* asan.c (transform_statements, execute_sanopt): Eliminate
use of FOR_EACH_BB in favor of FOR_EACH_BB_FN, to make use of cfun
explicit.
* auto-inc-dec.c (rest_of_handle_auto_inc_dec): Likewise.
* bb-reorder.c (find_rarely_executed_basic_blocks_and_crossing_edges,
set_edge_can_fallthru_flag, fix_up_fall_thru_edges,
fix_crossing_unconditional_branches, add_reg_crossing_jump_notes,
insert_section_boundary_note, rest_of_handle_reorder_blocks,
duplicate_computed_gotos): Likewise.
* cfg.c (clear_edges, compact_blocks, brief_dump_cfg): Likewise.
* cfganal.c (find_unreachable_blocks, add_noreturn_fake_exit_edges,
compute_dominance_frontiers_1, single_pred_before_succ_order): Likewise.
* cfgbuild.c (find_many_sub_basic_blocks): Likewise.
* cfgcleanup.c (try_optimize_cfg, delete_dead_jumptables): Likewise.
* cfgexpand.c (add_scope_conflicts, discover_nonconstant_array_refs):
Likewise.
* cfgloop.c (flow_loops_cfg_dump, get_loop_body, record_loop_exits,
verify_loop_structure): Likewise.
* cfgloopanal.c (mark_loop_exit_edges): Likewise.
* cfgrtl.c (compute_bb_for_insn, find_partition_fixes,
verify_hot_cold_block_grouping, purge_all_dead_edges,
fixup_abnormal_edges, record_effective_endpoints,
outof_cfg_layout_mode, fixup_reorder_chain, force_one_exit_fallthru,
break_superblocks): Likewise.
* cgraphbuild.c (build_cgraph_edges, rebuild_cgraph_edges,
cgraph_rebuild_references): Likewise.
* combine-stack-adj.c (combine_stack_adjustments): Likewise.
* combine.c (delete_noop_moves, create_log_links,
combine_instructions): Likewise.
* config/arm/arm.c (thumb1_reorg, thumb2_reorg): Likewise.
* config/bfin/bfin.c (bfin_gen_bundles, reorder_var_tracking_notes):
Likewise.
* config/c6x/c6x.c (c6x_gen_bundles, conditionalize_after_sched,
c6x_reorg): Likewise.
* config/epiphany/resolve-sw-modes.c (resolve_sw_modes): Likewise.
* config/frv/frv.c (frv_optimize_membar): Likewise.
* config/i386/i386.c (ix86_finalize_stack_realign_flags): Likewise.
* config/ia64/ia64.c (ia64_reorg): Likewise.
* config/mips/mips.c (mips_annotate_pic_calls): Likewise.
* config/picochip/picochip.c (reorder_var_tracking_notes): Likewise.
* config/rs6000/rs6000.c (rs6000_alloc_sdmode_stack_slot): Likewise.
* config/s390/s390.c (s390_regs_ever_clobbered): Likewise.
* config/sh/sh_treg_combine.cc (sh_treg_combine::execute): Likewise.
* config/spu/spu.c (spu_machine_dependent_reorg): Likewise.
* config/tilegx/tilegx.c (tilegx_gen_bundles,
reorder_var_tracking_notes): Likewise.
* config/tilepro/tilepro.c (tilepro_gen_bundles,
reorder_var_tracking_notes): Likewise.
* coverage.c (coverage_compute_cfg_checksum): Likewise.
* cprop.c (compute_hash_table_work, compute_cprop_data,
local_cprop_pass, find_implicit_sets): Likewise.
* cse.c (cse_condition_code_reg): Likewise.
* dce.c (prescan_insns_for_dce): Likewise.
* df-core.c (df_compact_blocks): Likewise.
* df-problems.c (df_word_lr_alloc): Likewise.
* df-scan.c (df_scan_start_dump, df_scan_blocks, df_insn_rescan_all,
df_update_entry_exit_and_calls): Likewise.
* dominance.c (calculate_dominance_info, verify_dominators,
debug_dominance_info): Likewise.
* dse.c (dse_step5_nospill): Likewise.
* except.c (finish_eh_generation): Likewise.
* final.c (compute_alignments): Likewise.
* function.c (thread_prologue_and_epilogue_insns,
rest_of_match_asm_constraints): Likewise.
* gcse.c (compute_hash_table_work, prune_expressions,
compute_pre_data, compute_code_hoist_vbeinout, hoist_code,
calculate_bb_reg_pressure, compute_ld_motion_mems): Likewise.
* gimple-iterator.c (gsi_commit_edge_inserts): Likewise.
* gimple-ssa-isolate-paths.c (find_implicit_erroneous_behaviour,
find_explicit_erroneous_behaviour): Likewise.
* graphite-sese-to-poly.c (rewrite_reductions_out_of_ssa,
rewrite_cross_bb_scalar_deps_out_of_ssa): Likewise.
* haifa-sched.c (haifa_sched_init): Likewise.
* hw-doloop.c (discover_loops, set_bb_indices, reorder_loops):
Likewise.
* ifcvt.c (if_convert): Likewise.
* init-regs.c (initialize_uninitialized_regs): Likewise.
* ipa-prop.c (ipcp_transform_function): Likewise.
* ipa-pure-const.c (analyze_function): Likewise.
* ipa-split.c (find_split_points, execute_split_functions): Likewise.
* ira-build.c (form_loop_tree): Likewise.
* ira-costs.c (find_costs_and_classes): Likewise.
* ira-emit.c (emit_moves, add_ranges_and_copies, ira_emit): Likewise.
* ira.c (decrease_live_ranges_number, compute_regs_asm_clobbered,
mark_elimination, update_equiv_regs, find_moveable_pseudos,
split_live_ranges_for_shrink_wrap, allocate_initial_values): Likewise.
* jump.c (mark_all_labels): Likewise.
* lcm.c (compute_laterin, compute_insert_delete, compute_available,
compute_nearerout, compute_rev_insert_delete): Likewise.
* loop-init.c (fix_loop_structure): Likewise.
* loop-invariant.c (calculate_loop_reg_pressure): Likewise.
* lower-subreg.c (decompose_multiword_subregs,
decompose_multiword_subregs): Likewise.
* lra-assigns.c (assign_by_spills): Likewise.
* lra-coalesce.c (lra_coalesce): Likewise.
* lra-constraints.c (lra_inheritance, remove_inheritance_pseudos):
Likewise.
* lra-eliminations.c (lra_init_elimination): Likewise.
* lra-spills.c (assign_spill_hard_regs, spill_pseudos,
lra_final_code_change): Likewise.
* lra.c (remove_scratches, check_rtl, has_nonexceptional_receiver,
update_inc_notes): Likewise.
* mcf.c (adjust_cfg_counts): Likewise.
* mode-switching.c (optimize_mode_switching): Likewise.
* modulo-sched.c (rest_of_handle_sms): Likewise.
* omp-low.c (optimize_omp_library_calls, expand_omp_taskreg,
expand_omp_target): Likewise.
* postreload-gcse.c (alloc_mem, compute_hash_table): Likewise.
* postreload.c (reload_cse_regs_1): Likewise.
* predict.c (strip_predict_hints, tree_bb_level_predictions,
tree_estimate_probability, expensive_function_p,
estimate_bb_frequencies, compute_function_frequency): Likewise.
* profile.c (is_inconsistent, compute_branch_probabilities,
branch_prob): Likewise.
* ree.c (find_removable_extensions): Likewise.
* reg-stack.c (compensate_edges, convert_regs, reg_to_stack): Likewise.
* regcprop.c (copyprop_hardreg_forward): Likewise.
* reginfo.c (init_subregs_of_mode): Likewise.
* regrename.c (regrename_analyze): Likewise.
* regstat.c (regstat_compute_ri, regstat_compute_calls_crossed):
Likewise.
* reload1.c (has_nonexceptional_receiver, reload,
calculate_elim_costs_all_insns): Likewise.
* resource.c (init_resource_info, free_resource_info): Likewise.
* sched-ebb.c (schedule_ebbs): Likewise.
* sched-rgn.c (is_cfg_nonregular, find_single_block_region,
haifa_find_rgns, sched_rgn_local_init): Likewise.
* sel-sched-dump.c (sel_dump_cfg_2): Likewise.
* sel-sched-ir.c (init_lv_sets, free_lv_sets,
make_regions_from_the_rest): Likewise.
* sese.c (build_sese_loop_nests, sese_build_liveouts): Likewise.
* stack-ptr-mod.c (notice_stack_pointer_modification): Likewise.
* store-motion.c (compute_store_table, build_store_vectors,
one_store_motion_pass): Likewise.
* tracer.c (tail_duplicate): Likewise.
* trans-mem.c (compute_transaction_bits): Likewise.
* tree-call-cdce.c (tree_call_cdce): Likewise.
* tree-cfg.c (replace_loop_annotate, factor_computed_gotos,
fold_cond_expr_cond, make_edges, assign_discriminators,
make_abnormal_goto_edges, cleanup_dead_labels, group_case_labels,
dump_cfg_stats, gimple_verify_flow_info, print_loop,
execute_fixup_cfg): Likewise.
* tree-cfgcleanup.c (cleanup_tree_cfg_1, merge_phi_nodes): Likewise.
* tree-complex.c (init_dont_simulate_again, tree_lower_complex):
Likewise.
* tree-dfa.c (collect_dfa_stats, dump_enumerated_decls): Likewise.
* tree-eh.c (execute_lower_resx, execute_lower_eh_dispatch,
mark_reachable_handlers): Likewise.
* tree-emutls.c (lower_emutls_function_body): Likewise.
* tree-if-conv.c (main_tree_if_conversion): Likewise.
* tree-inline.c (optimize_inline_calls): Likewise.
* tree-into-ssa.c (rewrite_into_ssa, update_ssa): Likewise.
* tree-nrv.c (tree_nrv, execute_return_slot_opt): Likewise.
* tree-object-size.c (compute_object_sizes): Likewise.
* tree-outof-ssa.c (eliminate_useless_phis, rewrite_trees,
insert_backedge_copies, tree_profiling): Likewise.
* tree-scalar-evolution.c (scev_const_prop): Likewise.
* tree-sra.c (scan_function, sra_modify_function_body,
propagate_dereference_distances, ipa_sra_modify_function_body,
convert_callers): Likewise.
* tree-ssa-ccp.c (ccp_initialize, execute_fold_all_builtins): Likewise.
* tree-ssa-coalesce.c (build_ssa_conflict_graph): Likewise.
create_outofssa_var_map, coalesce_partitions): Likewise.
* tree-ssa-copy.c (init_copy_prop): Likewise.
* tree-ssa-copyrename.c (rename_ssa_copies): Likewise.
* tree-ssa-dce.c (find_obviously_necessary_stmts,
eliminate_unnecessary_stmts): Likewise.
* tree-ssa-dom.c (free_all_edge_infos, tree_ssa_dominator_optimize):
Likewise.
* tree-ssa-forwprop.c (ssa_forward_propagate_and_combine): Likewise.
* tree-ssa-live.c (clear_unused_block_pointer, remove_unused_locals,
new_tree_live_info, calculate_live_on_exit, dump_live_info,
analyze_memory_references, fill_always_executed_in,
tree_ssa_lim_finalize): Likewise.
* tree-ssa-loop-manip.c (find_uses_to_rename, verify_loop_closed_ssa):
Likewise.
* tree-ssa-math-opts.c (execute_cse_reciprocals, execute_cse_sincos,
execute_optimize_bswap, execute_optimize_widening_mul): Likewise.
* tree-ssa-propagate.c (substitute_and_fold): Likewise.
* tree-ssa-structalias.c (compute_points_to_sets): Likewise.
* tree-ssa-tail-merge.c (find_same_succ, reset_cluster_vectors):
Likewise.
* tree-ssa-ter.c (find_replaceable_exprs): Likewise.
* tree-ssa-threadupdate.c (thread_through_all_blocks): Likewise.
* tree-ssa-uncprop.c (associate_equivalences_with_edges,
tree_ssa_uncprop): Likewise.
* tree-ssa-uninit.c (warn_uninitialized_vars,
execute_late_warn_uninitialized): Likewise.
* tree-ssa.c (verify_ssa, execute_update_addresses_taken): Likewise.
* tree-stdarg.c (check_all_va_list_escapes, execute_optimize_stdarg):
Likewise.
* tree-switch-conversion.c (do_switchconv): Likewise.
* tree-vect-generic.c (expand_vector_operations): Likewise.
* tree-vectorizer.c (adjust_simduid_builtins, note_simd_array_uses,
execute_vect_slp): Likewise.
* tree-vrp.c (check_all_array_refs, remove_range_assertions,
vrp_initialize, identify_jump_threads, instrument_memory_accesses):
Likewise.
* ubsan.c (ubsan_pass): Likewise.
* value-prof.c (verify_histograms, gimple_value_profile_transformations,
gimple_find_values_to_profile): Likewise.
* var-tracking.c (vt_find_locations, dump_dataflow_sets, vt_emit_notes,
vt_initialize, delete_debug_insns, vt_finalize): Likewise.
gcc/testsuite/
* g++.dg/plugin/selfassign.c (execute_warn_self_assign): Eliminate
use of FOR_EACH_BB in favor of FOR_EACH_BB_FN, to make use of cfun
explicit.
* gcc.dg/plugin/selfassign.c (execute_warn_self_assign): Likewise.
From-SVN: r205828
2013-12-09 22:06:06 +01:00
|
|
|
FOR_EACH_BB_FN (bb, cfun)
|
2013-11-19 12:45:15 +01:00
|
|
|
{
|
|
|
|
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
|
|
|
|
{
|
|
|
|
gimple stmt = gsi_stmt (gsi);
|
2013-11-22 21:07:31 +01:00
|
|
|
if (is_gimple_debug (stmt) || gimple_clobber_p (stmt))
|
2013-11-19 12:45:15 +01:00
|
|
|
{
|
|
|
|
gsi_next (&gsi);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-12-04 23:47:11 +01:00
|
|
|
if ((flag_sanitize & SANITIZE_SI_OVERFLOW)
|
|
|
|
&& is_gimple_assign (stmt))
|
|
|
|
instrument_si_overflow (gsi);
|
|
|
|
|
2013-11-27 12:40:22 +01:00
|
|
|
if (flag_sanitize & SANITIZE_NULL)
|
|
|
|
{
|
|
|
|
if (gimple_store_p (stmt))
|
|
|
|
instrument_null (gsi, true);
|
|
|
|
if (gimple_assign_load_p (stmt))
|
|
|
|
instrument_null (gsi, false);
|
|
|
|
}
|
|
|
|
|
2013-12-20 10:05:04 +01:00
|
|
|
if (flag_sanitize & (SANITIZE_BOOL | SANITIZE_ENUM)
|
|
|
|
&& gimple_assign_load_p (stmt))
|
|
|
|
instrument_bool_enum_load (&gsi);
|
|
|
|
|
2013-11-19 12:45:15 +01:00
|
|
|
gsi_next (&gsi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
gate_ubsan (void)
|
|
|
|
{
|
2013-12-20 10:05:04 +01:00
|
|
|
return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW
|
|
|
|
| SANITIZE_BOOL | SANITIZE_ENUM);
|
2013-11-19 12:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const pass_data pass_data_ubsan =
|
|
|
|
{
|
|
|
|
GIMPLE_PASS, /* type */
|
|
|
|
"ubsan", /* name */
|
|
|
|
OPTGROUP_NONE, /* optinfo_flags */
|
|
|
|
true, /* has_gate */
|
|
|
|
true, /* has_execute */
|
|
|
|
TV_TREE_UBSAN, /* tv_id */
|
|
|
|
( PROP_cfg | PROP_ssa ), /* properties_required */
|
|
|
|
0, /* properties_provided */
|
|
|
|
0, /* properties_destroyed */
|
|
|
|
0, /* todo_flags_start */
|
|
|
|
TODO_update_ssa, /* todo_flags_finish */
|
|
|
|
};
|
|
|
|
|
|
|
|
class pass_ubsan : public gimple_opt_pass
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
pass_ubsan (gcc::context *ctxt)
|
|
|
|
: gimple_opt_pass (pass_data_ubsan, ctxt)
|
|
|
|
{}
|
|
|
|
|
|
|
|
/* opt_pass methods: */
|
|
|
|
bool gate () { return gate_ubsan (); }
|
|
|
|
unsigned int execute () { return ubsan_pass (); }
|
|
|
|
|
|
|
|
}; // class pass_ubsan
|
|
|
|
|
|
|
|
} // anon namespace
|
|
|
|
|
|
|
|
gimple_opt_pass *
|
|
|
|
make_pass_ubsan (gcc::context *ctxt)
|
|
|
|
{
|
|
|
|
return new pass_ubsan (ctxt);
|
|
|
|
}
|
|
|
|
|
2013-08-30 18:12:58 +02:00
|
|
|
#include "gt-ubsan.h"
|