opts.c (common_handle_option): Handle -fsanitize=alignment.
* opts.c (common_handle_option): Handle -fsanitize=alignment. * ubsan.h (enum ubsan_null_ckind): Add UBSAN_CTOR_CALL. (ubsan_expand_bounds_ifn, ubsan_expand_null_ifn): Change return type to bool. * stor-layout.h (min_align_of_type): New prototype. * asan.c (pass_sanopt::execute): Don't perform gsi_next if ubsan_expand* told us not to do it. Remove the extra gsi_end_p check. * ubsan.c: Include builtins.h. (ubsan_expand_bounds_ifn): Change return type to bool, always return true. (ubsan_expand_null_ifn): Change return type to bool, change argument to gimple_stmt_iterator *. Handle both null and alignment sanitization, take type from ckind argument's type rather than first argument. (instrument_member_call): Removed. (instrument_mem_ref): Remove t argument, add mem and base arguments. Handle both null and alignment sanitization, don't say whole struct access is member access. Build 3 argument IFN_UBSAN_NULL call instead of 2 argument. (instrument_null): Adjust instrument_mem_ref caller. Don't instrument calls here. (pass_ubsan::gate, pass_ubsan::execute): Handle SANITIZE_ALIGNMENT like SANITIZE_NULL. * stor-layout.c (min_align_of_type): New function. * flag-types.h (enum sanitize_code): Add SANITIZE_ALIGNMENT. Or it into SANITIZE_UNDEFINED. * doc/invoke.texi (-fsanitize=alignment): Document. cp/ * cp-gimplify.c (cp_genericize_r): For -fsanitize=null and/or -fsanitize=alignment call ubsan_maybe_instrument_reference for casts to REFERENCE_TYPE and ubsan_maybe_instrument_member_call for calls to member functions. c-family/ * c-common.h (min_align_of_type): Removed prototype. * c-common.c (min_align_of_type): Removed. * c-ubsan.h (ubsan_maybe_instrument_reference, ubsan_maybe_instrument_member_call): New prototypes. * c-ubsan.c: Include stor-layout.h and builtins.h. (ubsan_maybe_instrument_reference_or_call, ubsan_maybe_instrument_reference, ubsan_maybe_instrument_call): New functions. testsuite/ * c-c++-common/ubsan/align-1.c: New test. * c-c++-common/ubsan/align-2.c: New test. * c-c++-common/ubsan/align-3.c: New test. * c-c++-common/ubsan/align-4.c: New test. * c-c++-common/ubsan/align-5.c: New test. * c-c++-common/ubsan/attrib-4.c: New test. * g++.dg/ubsan/align-1.C: New test. * g++.dg/ubsan/align-2.C: New test. * g++.dg/ubsan/align-3.C: New test. * g++.dg/ubsan/attrib-1.C: New test. * g++.dg/ubsan/null-1.C: New test. * g++.dg/ubsan/null-2.C: New test. From-SVN: r213406
This commit is contained in:
parent
bbe2542f72
commit
944fa280bc
|
@ -1,3 +1,34 @@
|
|||
2014-08-01 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* opts.c (common_handle_option): Handle -fsanitize=alignment.
|
||||
* ubsan.h (enum ubsan_null_ckind): Add UBSAN_CTOR_CALL.
|
||||
(ubsan_expand_bounds_ifn, ubsan_expand_null_ifn): Change return
|
||||
type to bool.
|
||||
* stor-layout.h (min_align_of_type): New prototype.
|
||||
* asan.c (pass_sanopt::execute): Don't perform gsi_next if
|
||||
ubsan_expand* told us not to do it. Remove the extra gsi_end_p
|
||||
check.
|
||||
* ubsan.c: Include builtins.h.
|
||||
(ubsan_expand_bounds_ifn): Change return type to bool,
|
||||
always return true.
|
||||
(ubsan_expand_null_ifn): Change return type to bool, change
|
||||
argument to gimple_stmt_iterator *. Handle both null and alignment
|
||||
sanitization, take type from ckind argument's type rather than
|
||||
first argument.
|
||||
(instrument_member_call): Removed.
|
||||
(instrument_mem_ref): Remove t argument, add mem and base arguments.
|
||||
Handle both null and alignment sanitization, don't say whole
|
||||
struct access is member access. Build 3 argument IFN_UBSAN_NULL
|
||||
call instead of 2 argument.
|
||||
(instrument_null): Adjust instrument_mem_ref caller. Don't
|
||||
instrument calls here.
|
||||
(pass_ubsan::gate, pass_ubsan::execute): Handle SANITIZE_ALIGNMENT
|
||||
like SANITIZE_NULL.
|
||||
* stor-layout.c (min_align_of_type): New function.
|
||||
* flag-types.h (enum sanitize_code): Add SANITIZE_ALIGNMENT.
|
||||
Or it into SANITIZE_UNDEFINED.
|
||||
* doc/invoke.texi (-fsanitize=alignment): Document.
|
||||
|
||||
2014-07-31 Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
* tree-ssa-tail-merge.c (same_succ_hash): Convert to inchash.
|
||||
|
|
17
gcc/asan.c
17
gcc/asan.c
|
@ -2750,21 +2750,25 @@ pass_sanopt::execute (function *fun)
|
|||
FOR_EACH_BB_FN (bb, fun)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
|
||||
{
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
bool no_next = false;
|
||||
|
||||
if (!is_gimple_call (stmt))
|
||||
continue;
|
||||
{
|
||||
gsi_next (&gsi);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gimple_call_internal_p (stmt))
|
||||
switch (gimple_call_internal_fn (stmt))
|
||||
{
|
||||
case IFN_UBSAN_NULL:
|
||||
ubsan_expand_null_ifn (gsi);
|
||||
no_next = ubsan_expand_null_ifn (&gsi);
|
||||
break;
|
||||
case IFN_UBSAN_BOUNDS:
|
||||
ubsan_expand_bounds_ifn (&gsi);
|
||||
no_next = ubsan_expand_bounds_ifn (&gsi);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -2777,9 +2781,8 @@ pass_sanopt::execute (function *fun)
|
|||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
/* ubsan_expand_bounds_ifn might move us to the end of the BB. */
|
||||
if (gsi_end_p (gsi))
|
||||
break;
|
||||
if (!no_next)
|
||||
gsi_next (&gsi);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
2014-08-01 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* c-common.h (min_align_of_type): Removed prototype.
|
||||
* c-common.c (min_align_of_type): Removed.
|
||||
* c-ubsan.h (ubsan_maybe_instrument_reference,
|
||||
ubsan_maybe_instrument_member_call): New prototypes.
|
||||
* c-ubsan.c: Include stor-layout.h and builtins.h.
|
||||
(ubsan_maybe_instrument_reference_or_call,
|
||||
ubsan_maybe_instrument_reference, ubsan_maybe_instrument_call): New
|
||||
functions.
|
||||
|
||||
2014-07-31 Marc Glisse <marc.glisse@inria.fr>
|
||||
|
||||
PR c++/60517
|
||||
|
|
|
@ -4965,26 +4965,6 @@ c_common_get_alias_set (tree t)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Return the least alignment required for type TYPE. */
|
||||
|
||||
unsigned int
|
||||
min_align_of_type (tree type)
|
||||
{
|
||||
unsigned int align = TYPE_ALIGN (type);
|
||||
align = MIN (align, BIGGEST_ALIGNMENT);
|
||||
#ifdef BIGGEST_FIELD_ALIGNMENT
|
||||
align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
|
||||
#endif
|
||||
unsigned int field_align = align;
|
||||
#ifdef ADJUST_FIELD_ALIGN
|
||||
tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
type);
|
||||
field_align = ADJUST_FIELD_ALIGN (field, field_align);
|
||||
#endif
|
||||
align = MIN (align, field_align);
|
||||
return align / BITS_PER_UNIT;
|
||||
}
|
||||
|
||||
/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
|
||||
the IS_SIZEOF parameter indicates which operator is being applied.
|
||||
The COMPLAIN flag controls whether we should diagnose possibly
|
||||
|
|
|
@ -762,7 +762,6 @@ extern tree c_wrap_maybe_const (tree, bool);
|
|||
extern tree c_save_expr (tree);
|
||||
extern tree c_common_truthvalue_conversion (location_t, tree);
|
||||
extern void c_apply_type_quals_to_decl (int, tree);
|
||||
extern unsigned int min_align_of_type (tree);
|
||||
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
|
||||
extern tree c_alignof_expr (location_t, tree);
|
||||
/* Print an error message for invalid operands to arith operation CODE.
|
||||
|
|
|
@ -31,6 +31,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "c-family/c-ubsan.h"
|
||||
#include "asan.h"
|
||||
#include "internal-fn.h"
|
||||
#include "stor-layout.h"
|
||||
#include "builtins.h"
|
||||
|
||||
/* Instrument division by zero and INT_MIN / -1. If not instrumenting,
|
||||
return NULL_TREE. */
|
||||
|
@ -350,3 +352,99 @@ ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static tree
|
||||
ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree type,
|
||||
enum ubsan_null_ckind ckind)
|
||||
{
|
||||
tree orig_op = op;
|
||||
bool instrument = false;
|
||||
unsigned int mina = 0;
|
||||
|
||||
if (current_function_decl == NULL_TREE
|
||||
|| lookup_attribute ("no_sanitize_undefined",
|
||||
DECL_ATTRIBUTES (current_function_decl)))
|
||||
return NULL_TREE;
|
||||
|
||||
if (flag_sanitize & SANITIZE_ALIGNMENT)
|
||||
{
|
||||
mina = min_align_of_type (type);
|
||||
if (mina <= 1)
|
||||
mina = 0;
|
||||
}
|
||||
while ((TREE_CODE (op) == NOP_EXPR
|
||||
|| TREE_CODE (op) == NON_LVALUE_EXPR)
|
||||
&& TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
|
||||
op = TREE_OPERAND (op, 0);
|
||||
if (TREE_CODE (op) == NOP_EXPR
|
||||
&& TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
|
||||
{
|
||||
if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op))))
|
||||
instrument = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flag_sanitize & SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
|
||||
{
|
||||
bool strict_overflow_p = false;
|
||||
/* tree_single_nonzero_warnv_p will not return true for non-weak
|
||||
non-automatic decls with -fno-delete-null-pointer-checks,
|
||||
which is disabled during -fsanitize=null. We don't want to
|
||||
instrument those, just weak vars though. */
|
||||
int save_flag_delete_null_pointer_checks
|
||||
= flag_delete_null_pointer_checks;
|
||||
flag_delete_null_pointer_checks = 1;
|
||||
if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p)
|
||||
|| strict_overflow_p)
|
||||
instrument = true;
|
||||
flag_delete_null_pointer_checks
|
||||
= save_flag_delete_null_pointer_checks;
|
||||
}
|
||||
else if (flag_sanitize & SANITIZE_NULL)
|
||||
instrument = true;
|
||||
if (mina && mina > get_pointer_alignment (op) / BITS_PER_UNIT)
|
||||
instrument = true;
|
||||
}
|
||||
if (!instrument)
|
||||
return NULL_TREE;
|
||||
op = save_expr (orig_op);
|
||||
tree kind = build_int_cst (TREE_TYPE (op), ckind);
|
||||
tree align = build_int_cst (pointer_sized_int_node, mina);
|
||||
tree call
|
||||
= build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
|
||||
3, op, kind, align);
|
||||
TREE_SIDE_EFFECTS (call) = 1;
|
||||
return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
|
||||
}
|
||||
|
||||
/* Instrument a NOP_EXPR to REFERENCE_TYPE if needed. */
|
||||
|
||||
void
|
||||
ubsan_maybe_instrument_reference (tree stmt)
|
||||
{
|
||||
tree op = TREE_OPERAND (stmt, 0);
|
||||
op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
|
||||
TREE_TYPE (TREE_TYPE (stmt)),
|
||||
UBSAN_REF_BINDING);
|
||||
if (op)
|
||||
TREE_OPERAND (stmt, 0) = op;
|
||||
}
|
||||
|
||||
/* Instrument a CALL_EXPR to a method if needed. */
|
||||
|
||||
void
|
||||
ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
|
||||
{
|
||||
if (call_expr_nargs (stmt) == 0)
|
||||
return;
|
||||
tree op = CALL_EXPR_ARG (stmt, 0);
|
||||
if (op == error_mark_node
|
||||
|| !POINTER_TYPE_P (TREE_TYPE (op)))
|
||||
return;
|
||||
op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
|
||||
TREE_TYPE (TREE_TYPE (op)),
|
||||
is_ctor ? UBSAN_CTOR_CALL
|
||||
: UBSAN_MEMBER_CALL);
|
||||
if (op)
|
||||
CALL_EXPR_ARG (stmt, 0) = op;
|
||||
}
|
||||
|
|
|
@ -28,5 +28,7 @@ extern tree ubsan_instrument_return (location_t);
|
|||
extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
|
||||
extern bool ubsan_array_ref_instrumented_p (const_tree);
|
||||
extern void ubsan_maybe_instrument_array_ref (tree *, bool);
|
||||
extern void ubsan_maybe_instrument_reference (tree);
|
||||
extern void ubsan_maybe_instrument_member_call (tree, bool);
|
||||
|
||||
#endif /* GCC_C_UBSAN_H */
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2014-08-01 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* cp-gimplify.c (cp_genericize_r): For -fsanitize=null and/or
|
||||
-fsanitize=alignment call ubsan_maybe_instrument_reference
|
||||
for casts to REFERENCE_TYPE and ubsan_maybe_instrument_member_call
|
||||
for calls to member functions.
|
||||
|
||||
2014-07-31 Marc Glisse <marc.glisse@inria.fr>
|
||||
|
||||
PR c++/60517
|
||||
|
|
|
@ -1198,6 +1198,27 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
|
|||
*stmt_p = size_one_node;
|
||||
return NULL;
|
||||
}
|
||||
else if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
|
||||
{
|
||||
if (TREE_CODE (stmt) == NOP_EXPR
|
||||
&& TREE_CODE (TREE_TYPE (stmt)) == REFERENCE_TYPE)
|
||||
ubsan_maybe_instrument_reference (stmt);
|
||||
else if (TREE_CODE (stmt) == CALL_EXPR)
|
||||
{
|
||||
tree fn = CALL_EXPR_FN (stmt);
|
||||
if (fn != NULL_TREE
|
||||
&& !error_operand_p (fn)
|
||||
&& POINTER_TYPE_P (TREE_TYPE (fn))
|
||||
&& TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) == METHOD_TYPE)
|
||||
{
|
||||
bool is_ctor
|
||||
= TREE_CODE (fn) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
|
||||
&& DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0));
|
||||
ubsan_maybe_instrument_member_call (stmt, is_ctor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pointer_set_insert (p_set, *stmt_p);
|
||||
|
||||
|
|
|
@ -5463,7 +5463,8 @@ instead.
|
|||
This option enables pointer checking. Particularly, the application
|
||||
built with this option turned on will issue an error message when it
|
||||
tries to dereference a NULL pointer, or if a reference (possibly an
|
||||
rvalue reference) is bound to a NULL pointer.
|
||||
rvalue reference) is bound to a NULL pointer, or if a method is invoked
|
||||
on an object pointed by a NULL pointer.
|
||||
|
||||
@item -fsanitize=return
|
||||
@opindex fsanitize=return
|
||||
|
@ -5490,6 +5491,13 @@ This option enables instrumentation of array bounds. Various out of bounds
|
|||
accesses are detected. Flexible array members and initializers of variables
|
||||
with static storage are not instrumented.
|
||||
|
||||
@item -fsanitize=alignment
|
||||
@opindex fsanitize=alignment
|
||||
|
||||
This option enables checking of alignment of pointers when they are
|
||||
dereferenced, or when a reference is bound to insufficiently aligned target,
|
||||
or when a method or constructor is invoked on insufficiently aligned object.
|
||||
|
||||
@item -fsanitize=float-divide-by-zero
|
||||
@opindex fsanitize=float-divide-by-zero
|
||||
Detect floating-point division by zero. Unlike other similar options,
|
||||
|
|
|
@ -233,10 +233,11 @@ enum sanitize_code {
|
|||
SANITIZE_FLOAT_DIVIDE = 1 << 14,
|
||||
SANITIZE_FLOAT_CAST = 1 << 15,
|
||||
SANITIZE_BOUNDS = 1 << 16,
|
||||
SANITIZE_ALIGNMENT = 1 << 17,
|
||||
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
|
||||
| SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
|
||||
| SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
|
||||
| SANITIZE_BOUNDS,
|
||||
| SANITIZE_BOUNDS | SANITIZE_ALIGNMENT,
|
||||
SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
|
||||
};
|
||||
|
||||
|
|
|
@ -1492,6 +1492,7 @@ common_handle_option (struct gcc_options *opts,
|
|||
{ "float-cast-overflow", SANITIZE_FLOAT_CAST,
|
||||
sizeof "float-cast-overflow" - 1 },
|
||||
{ "bounds", SANITIZE_BOUNDS, sizeof "bounds" - 1 },
|
||||
{ "alignment", SANITIZE_ALIGNMENT, sizeof "alignment" - 1 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
const char *comma;
|
||||
|
|
|
@ -2390,6 +2390,27 @@ layout_type (tree type)
|
|||
gcc_assert (!TYPE_ALIAS_SET_KNOWN_P (type));
|
||||
}
|
||||
|
||||
/* Return the least alignment required for type TYPE. */
|
||||
|
||||
unsigned int
|
||||
min_align_of_type (tree type)
|
||||
{
|
||||
unsigned int align = TYPE_ALIGN (type);
|
||||
align = MIN (align, BIGGEST_ALIGNMENT);
|
||||
#ifdef BIGGEST_FIELD_ALIGNMENT
|
||||
align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
|
||||
#endif
|
||||
unsigned int field_align = align;
|
||||
#ifdef ADJUST_FIELD_ALIGN
|
||||
tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
type);
|
||||
field_align = ADJUST_FIELD_ALIGN (field, field_align);
|
||||
ggc_free (field);
|
||||
#endif
|
||||
align = MIN (align, field_align);
|
||||
return align / BITS_PER_UNIT;
|
||||
}
|
||||
|
||||
/* Vector types need to re-check the target flags each time we report
|
||||
the machine mode. We need to do this because attribute target can
|
||||
change the result of vector_mode_supported_p and have_regs_of_mode
|
||||
|
|
|
@ -59,6 +59,9 @@ extern void layout_decl (tree, unsigned);
|
|||
node, does nothing except for the first time. */
|
||||
extern void layout_type (tree);
|
||||
|
||||
/* Return the least alignment in bytes required for type TYPE. */
|
||||
extern unsigned int min_align_of_type (tree);
|
||||
|
||||
/* Construct various nodes representing fract or accum data types. */
|
||||
extern tree make_fract_type (int, int, int);
|
||||
extern tree make_accum_type (int, int, int);
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
2014-08-01 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* c-c++-common/ubsan/align-1.c: New test.
|
||||
* c-c++-common/ubsan/align-2.c: New test.
|
||||
* c-c++-common/ubsan/align-3.c: New test.
|
||||
* c-c++-common/ubsan/align-4.c: New test.
|
||||
* c-c++-common/ubsan/align-5.c: New test.
|
||||
* c-c++-common/ubsan/attrib-4.c: New test.
|
||||
* g++.dg/ubsan/align-1.C: New test.
|
||||
* g++.dg/ubsan/align-2.C: New test.
|
||||
* g++.dg/ubsan/align-3.C: New test.
|
||||
* g++.dg/ubsan/attrib-1.C: New test.
|
||||
* g++.dg/ubsan/null-1.C: New test.
|
||||
* g++.dg/ubsan/null-2.C: New test.
|
||||
|
||||
2014-08-01 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
* lib/target-supports.exp (check_effective_target_glibc)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
|
||||
|
||||
struct S { int a; char b; long long c; short d[10]; };
|
||||
struct T { char a; long long b; };
|
||||
struct U { char a; int b; int c; long long d; struct S e; struct T f; };
|
||||
struct V { long long a; struct S b; struct T c; struct U u; } v;
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f1 (int *p, int *q, char *r, long long *s)
|
||||
{
|
||||
*p = *q + *r + *s;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
f2 (struct S *p)
|
||||
{
|
||||
return p->a;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) long long
|
||||
f3 (struct S *p, int i)
|
||||
{
|
||||
return p->c + p->d[1] + p->d[i];
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) long long
|
||||
f4 (long long *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
f1 (&v.u.b, &v.u.c, &v.u.a, &v.u.d);
|
||||
if (f2 (&v.u.e) + f3 (&v.u.e, 4) + f4 (&v.u.f.b) != 0)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/* Limit this to known non-strict alignment targets. */
|
||||
/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
|
||||
/* { dg-options "-fsanitize=alignment" } */
|
||||
|
||||
struct S { int a; char b; long long c; short d[10]; };
|
||||
struct T { char a; long long b; };
|
||||
struct U { char a; int b; int c; long long d; struct S e; struct T f; } __attribute__((packed));
|
||||
struct V { long long a; struct S b; struct T c; struct U u; } v;
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f1 (int *p, int *q, char *r, long long *s)
|
||||
{
|
||||
*p =
|
||||
*q
|
||||
+ *r
|
||||
+ *s;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
f2 (struct S *p)
|
||||
{
|
||||
return p->a;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) long long
|
||||
f3 (struct S *p, int i)
|
||||
{
|
||||
return p->c
|
||||
+ p->d[1]
|
||||
+ p->d[i];
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) long long
|
||||
f4 (long long *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
f1 (&v.u.b, &v.u.c, &v.u.a, &v.u.d);
|
||||
if (f2 (&v.u.e) + f3 (&v.u.e, 4) + f4 (&v.u.f.b) != 0)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "\.c:(14|15):\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
|
||||
/* { dg-output "\.c:16:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\.c:(13|16):\[0-9]*: \[^\n\r]*store to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
|
||||
/* { dg-output "\.c:23:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\.c:(29|30):\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\.c:30:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\.c:31:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\.c:37:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment" } */
|
|
@ -0,0 +1,66 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
|
||||
|
||||
int c;
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f1 (int *a, char *b)
|
||||
{
|
||||
__builtin_memcpy (a, b, sizeof (*a));
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f2 (int *a, char *b)
|
||||
{
|
||||
__builtin_memcpy (b, a, sizeof (*a));
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f3 (char *b)
|
||||
{
|
||||
__builtin_memcpy (&c, b, sizeof (c));
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f4 (char *b)
|
||||
{
|
||||
__builtin_memcpy (b, &c, sizeof (c));
|
||||
}
|
||||
|
||||
struct T
|
||||
{
|
||||
char a;
|
||||
short b;
|
||||
int c;
|
||||
long d;
|
||||
long long e;
|
||||
short f;
|
||||
float g;
|
||||
double h;
|
||||
long double i;
|
||||
} __attribute__((packed));
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
f5 (struct T *p)
|
||||
{
|
||||
return p->a + p->b + p->c + p->d + p->e + p->f + p->g + p->h + p->i;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
struct S { int a; char b[sizeof (int) + 1]; } s;
|
||||
s.a = 6;
|
||||
f2 (&s.a, &s.b[1]);
|
||||
f1 (&s.a, &s.b[1]);
|
||||
c = s.a + 1;
|
||||
f4 (&s.b[1]);
|
||||
f3 (&s.b[1]);
|
||||
if (c != 7 || s.a != 6)
|
||||
__builtin_abort ();
|
||||
struct U { long long a; long double b; char c; struct T d; } u;
|
||||
__builtin_memset (&u, 0, sizeof (u));
|
||||
if (f5 (&u.d) != 0)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/* Limit this to known non-strict alignment targets. */
|
||||
/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
|
||||
/* { dg-options "-fsanitize=null,alignment" } */
|
||||
|
||||
#include "align-2.c"
|
||||
|
||||
/* { dg-output "\.c:(14|15):\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:16:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:(13|16):\[0-9]*: \[^\n\r]*store to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:23:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:(29|30):\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:30:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:31:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
|
||||
/* { dg-output "\[^\n\r]*\.c:37:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment" } */
|
|
@ -0,0 +1,15 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-fno-sanitize=null -fsanitize=alignment -O2" } */
|
||||
/* Check that when optimizing if we know the alignment is right
|
||||
and we are not doing -fsanitize=null instrumentation we don't
|
||||
instrument the alignment check. */
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
foo (char *p)
|
||||
{
|
||||
p = (char *) __builtin_assume_aligned (p, __alignof__(int));
|
||||
int *q = (int *) p;
|
||||
return *q;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
|
|
@ -0,0 +1,15 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-fsanitize=undefined" } */
|
||||
|
||||
/* Test that we don't instrument functions marked with
|
||||
no_sanitize_undefined attribute. */
|
||||
|
||||
struct S { int a[16]; };
|
||||
|
||||
__attribute__((no_sanitize_undefined)) long long
|
||||
foo (int *a, long long *b, struct S *c)
|
||||
{
|
||||
return a[1] + *b + c->a[a[0]];
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
|
|
@ -0,0 +1,27 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
|
||||
|
||||
typedef const long int L;
|
||||
int a = 1;
|
||||
L b = 2;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int *p = &a;
|
||||
L *l = &b;
|
||||
|
||||
int &r = *p;
|
||||
auto &r2 = *p;
|
||||
L &lr = *l;
|
||||
|
||||
// Try an rvalue reference.
|
||||
auto &&r3 = *p;
|
||||
|
||||
// Don't evaluate the reference initializer twice.
|
||||
int i = 1;
|
||||
int *q = &i;
|
||||
int &qr = ++*q;
|
||||
if (i != 2)
|
||||
__builtin_abort ();
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Limit this to known non-strict alignment targets.
|
||||
// { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
|
||||
// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
|
||||
|
||||
typedef const long int L;
|
||||
struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
|
||||
struct T { char a; int b; long int c; } __attribute__((packed));
|
||||
struct U { long int a; struct T b; } u;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int *p = (int *) &s.buf[1];
|
||||
L *l = (L *) &s.buf[1 + sizeof(int)];
|
||||
|
||||
int &r = *p;
|
||||
auto &r2 = *p;
|
||||
L &lr = *l;
|
||||
|
||||
// Try an rvalue reference.
|
||||
auto &&r3 = *p;
|
||||
|
||||
// Don't evaluate the reference initializer twice.
|
||||
int i = 1;
|
||||
int *q = &i;
|
||||
int &qr = ++*q;
|
||||
if (i != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
int *s = &u.b.b;
|
||||
L *t = &u.b.c;
|
||||
int &r4 = *s;
|
||||
auto &r5 = *s;
|
||||
L &lr2 = *t;
|
||||
auto &&r6 = *s;
|
||||
}
|
||||
|
||||
// { dg-output "\.C:16:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:17:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:18:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'const L', which requires \[48] byte alignment.*" }
|
||||
// { dg-output "\.C:21:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:32:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:33:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:34:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'const L', which requires \[48] byte alignment.*" }
|
||||
// { dg-output "\.C:35:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment" }
|
|
@ -0,0 +1,45 @@
|
|||
// Limit this to known non-strict alignment targets.
|
||||
// { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
|
||||
// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
|
||||
|
||||
#include <new>
|
||||
|
||||
struct U
|
||||
{
|
||||
int a;
|
||||
void foo () {}
|
||||
};
|
||||
struct V
|
||||
{
|
||||
V () : a (0) {};
|
||||
~V () { a = 0; };
|
||||
int a;
|
||||
void foo () {}
|
||||
static void bar () {}
|
||||
};
|
||||
struct S { long int l; char buf[1 + sizeof (U) + 2 * sizeof (V)]; } s;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
U *p = (U *) &s.buf[1];
|
||||
p->foo ();
|
||||
char *q = &s.buf[1 + sizeof (U)];
|
||||
V *u = new (q) V;
|
||||
u->a = 1;
|
||||
u->~V ();
|
||||
V *v = new (&s.buf[1 + sizeof (U) + sizeof (V)]) V;
|
||||
v->foo ();
|
||||
v->bar (); // We don't instrument this right now.
|
||||
v->~V ();
|
||||
}
|
||||
|
||||
// { dg-output "\.C:26:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct U', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:28:\[0-9]*:\[\^\n\r]*constructor call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:14:\[0-9]*:\[\^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:29:\[0-9]*:\[\^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:30:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:15:\[0-9]*:\[\^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:31:\[0-9]*:\[\^\n\r]*constructor call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:32:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
|
||||
// { dg-output "\.C:34:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment" }
|
|
@ -0,0 +1,27 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-fsanitize=undefined -Wall -Wno-unused-variable -std=c++11" }
|
||||
|
||||
typedef const long int L;
|
||||
|
||||
__attribute__((no_sanitize_undefined)) void
|
||||
foo (int *p, L *l)
|
||||
{
|
||||
int &r = *p;
|
||||
auto &r2 = *p;
|
||||
L &lr = *l;
|
||||
auto &&r3 = *p;
|
||||
}
|
||||
|
||||
struct U
|
||||
{
|
||||
int a;
|
||||
void foo () {}
|
||||
};
|
||||
|
||||
__attribute__((no_sanitize_undefined)) void
|
||||
bar (U *p)
|
||||
{
|
||||
p->foo ();
|
||||
}
|
||||
|
||||
// { dg-final { scan-assembler-not "__ubsan_handle" } }
|
|
@ -0,0 +1,30 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-fsanitize=null -Wall -Wno-unused-variable -std=c++11" }
|
||||
|
||||
typedef const long int L;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int *p = 0;
|
||||
L *l = 0;
|
||||
|
||||
int &r = *p;
|
||||
auto &r2 = *p;
|
||||
L &lr = *l;
|
||||
|
||||
// Try an rvalue reference.
|
||||
auto &&r3 = *p;
|
||||
|
||||
// Don't evaluate the reference initializer twice.
|
||||
int i = 1;
|
||||
int *q = &i;
|
||||
int &qr = ++*q;
|
||||
if (i != 2)
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
// { dg-output "reference binding to null pointer of type 'int'(\n|\r\n|\r)" }
|
||||
// { dg-output "\[^\n\r]*reference binding to null pointer of type 'int'(\n|\r\n|\r)" }
|
||||
// { dg-output "\[^\n\r]*reference binding to null pointer of type 'const L'(\n|\r\n|\r)" }
|
||||
// { dg-output "\[^\n\r]*reference binding to null pointer of type 'int'(\n|\r\n|\r)" }
|
|
@ -0,0 +1,39 @@
|
|||
// Limit this to known non-strict alignment targets.
|
||||
// { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
|
||||
// { dg-options "-fsanitize=null -Wall -Wno-unused-variable -std=c++11" }
|
||||
|
||||
#include <new>
|
||||
|
||||
struct U
|
||||
{
|
||||
int a;
|
||||
void foo () {}
|
||||
};
|
||||
struct V
|
||||
{
|
||||
V () {};
|
||||
~V () {};
|
||||
int a;
|
||||
void foo () {}
|
||||
static void bar () {}
|
||||
};
|
||||
struct S { long int l; char buf[1 + sizeof (U) + 2 * sizeof (V)]; } s;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
U *p = 0;
|
||||
p->foo ();
|
||||
char *q = 0;
|
||||
V *u = new (q) V;
|
||||
u->~V ();
|
||||
V *v = new (q) V;
|
||||
v->foo ();
|
||||
v->bar (); // We don't instrument this right now.
|
||||
v->~V ();
|
||||
}
|
||||
|
||||
// { dg-output "\.C:26:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct U'.*" }
|
||||
// { dg-output "\.C:29:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct V'.*" }
|
||||
// { dg-output "\.C:31:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct V'.*" }
|
||||
// { dg-output "\.C:33:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct V'" }
|
175
gcc/ubsan.c
175
gcc/ubsan.c
|
@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "intl.h"
|
||||
#include "realmpfr.h"
|
||||
#include "dfp.h"
|
||||
#include "builtins.h"
|
||||
|
||||
/* Map from a tree to a VAR_DECL tree. */
|
||||
|
||||
|
@ -586,7 +587,7 @@ is_ubsan_builtin_p (tree t)
|
|||
|
||||
/* Expand the UBSAN_BOUNDS special builtin function. */
|
||||
|
||||
void
|
||||
bool
|
||||
ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsi);
|
||||
|
@ -645,21 +646,52 @@ ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
|
|||
|
||||
/* Point GSI to next logical statement. */
|
||||
*gsi = gsi_start_bb (fallthru_bb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Expand UBSAN_NULL internal call. */
|
||||
/* Expand UBSAN_NULL internal call. The type is kept on the ckind
|
||||
argument which is a constant, because the middle-end treats pointer
|
||||
conversions as useless and therefore the type of the first argument
|
||||
could be changed to any other pointer type. */
|
||||
|
||||
void
|
||||
ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
|
||||
bool
|
||||
ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
|
||||
{
|
||||
gimple_stmt_iterator gsi = *gsip;
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
location_t loc = gimple_location (stmt);
|
||||
gcc_assert (gimple_call_num_args (stmt) == 2);
|
||||
gcc_assert (gimple_call_num_args (stmt) == 3);
|
||||
tree ptr = gimple_call_arg (stmt, 0);
|
||||
tree ckind = gimple_call_arg (stmt, 1);
|
||||
tree align = gimple_call_arg (stmt, 2);
|
||||
tree check_align = NULL_TREE;
|
||||
bool check_null;
|
||||
|
||||
basic_block cur_bb = gsi_bb (gsi);
|
||||
|
||||
gimple g;
|
||||
if (!integer_zerop (align))
|
||||
{
|
||||
unsigned int ptralign = get_pointer_alignment (ptr) / BITS_PER_UNIT;
|
||||
if (compare_tree_int (align, ptralign) == 1)
|
||||
{
|
||||
check_align = make_ssa_name (pointer_sized_int_node, NULL);
|
||||
g = gimple_build_assign_with_ops (NOP_EXPR, check_align,
|
||||
ptr, NULL_TREE);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
|
||||
}
|
||||
}
|
||||
check_null = (flag_sanitize & SANITIZE_NULL) != 0;
|
||||
|
||||
if (check_align == NULL_TREE && !check_null)
|
||||
{
|
||||
gsi_remove (gsip, true);
|
||||
/* Unlink the UBSAN_NULLs vops before replacing it. */
|
||||
unlink_stmt_vdef (stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Split the original block holding the pointer dereference. */
|
||||
edge e = split_block (cur_bb, stmt);
|
||||
|
||||
|
@ -689,12 +721,11 @@ ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
|
|||
|
||||
/* Update dominance info for the newly created then_bb; note that
|
||||
fallthru_bb's dominance info has already been updated by
|
||||
split_bock. */
|
||||
split_block. */
|
||||
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. */
|
||||
gimple g;
|
||||
if (flag_sanitize_undefined_trap_on_error)
|
||||
g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
|
||||
else
|
||||
|
@ -705,54 +736,115 @@ ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
|
|||
: BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
|
||||
tree fn = builtin_decl_implicit (bcode);
|
||||
const struct ubsan_mismatch_data m
|
||||
= { build_zero_cst (pointer_sized_int_node), ckind };
|
||||
= { align, fold_convert (unsigned_char_type_node, ckind) };
|
||||
tree data
|
||||
= ubsan_create_data ("__ubsan_null_data", &loc, &m,
|
||||
ubsan_type_descriptor (TREE_TYPE (ptr),
|
||||
ubsan_type_descriptor (TREE_TYPE (ckind),
|
||||
UBSAN_PRINT_POINTER),
|
||||
NULL_TREE);
|
||||
data = build_fold_addr_expr_loc (loc, data);
|
||||
g = gimple_build_call (fn, 2, data,
|
||||
build_zero_cst (pointer_sized_int_node));
|
||||
check_align ? check_align
|
||||
: build_zero_cst (pointer_sized_int_node));
|
||||
}
|
||||
gimple_set_location (g, loc);
|
||||
gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
|
||||
gimple_set_location (g, loc);
|
||||
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);
|
||||
if (check_null)
|
||||
{
|
||||
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);
|
||||
/* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
|
||||
gsi_replace (&gsi, g, false);
|
||||
}
|
||||
|
||||
if (check_align)
|
||||
{
|
||||
if (check_null)
|
||||
{
|
||||
/* Split the block with the condition again. */
|
||||
e = split_block (cond_bb, stmt);
|
||||
basic_block cond1_bb = e->src;
|
||||
basic_block cond2_bb = e->dest;
|
||||
|
||||
/* Make an edge coming from the 'cond1 block' into the 'then block';
|
||||
this edge is unlikely taken, so set up the probability
|
||||
accordingly. */
|
||||
e = make_edge (cond1_bb, then_bb, EDGE_TRUE_VALUE);
|
||||
e->probability = PROB_VERY_UNLIKELY;
|
||||
|
||||
/* Set up the fallthrough basic block. */
|
||||
e = find_edge (cond1_bb, cond2_bb);
|
||||
e->flags = EDGE_FALSE_VALUE;
|
||||
e->count = cond1_bb->count;
|
||||
e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY;
|
||||
|
||||
/* Update dominance info. */
|
||||
if (dom_info_available_p (CDI_DOMINATORS))
|
||||
{
|
||||
set_immediate_dominator (CDI_DOMINATORS, fallthru_bb, cond1_bb);
|
||||
set_immediate_dominator (CDI_DOMINATORS, then_bb, cond1_bb);
|
||||
}
|
||||
|
||||
gsi2 = gsi_start_bb (cond2_bb);
|
||||
}
|
||||
|
||||
tree mask = build_int_cst (pointer_sized_int_node,
|
||||
tree_to_uhwi (align) - 1);
|
||||
g = gimple_build_assign_with_ops (BIT_AND_EXPR,
|
||||
make_ssa_name (pointer_sized_int_node,
|
||||
NULL),
|
||||
check_align, mask);
|
||||
gimple_set_location (g, loc);
|
||||
if (check_null)
|
||||
gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
|
||||
else
|
||||
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
|
||||
|
||||
g = gimple_build_cond (NE_EXPR, gimple_assign_lhs (g),
|
||||
build_int_cst (pointer_sized_int_node, 0),
|
||||
NULL_TREE, NULL_TREE);
|
||||
gimple_set_location (g, loc);
|
||||
if (check_null)
|
||||
gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
|
||||
else
|
||||
/* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
|
||||
gsi_replace (&gsi, g, false);
|
||||
}
|
||||
return 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
|
||||
/* Instrument a memory reference. BASE is the base of MEM, 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)
|
||||
instrument_mem_ref (tree mem, tree base, 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))))
|
||||
unsigned int align = 0;
|
||||
if (flag_sanitize & SANITIZE_ALIGNMENT)
|
||||
{
|
||||
align = min_align_of_type (TREE_TYPE (base));
|
||||
if (align <= 1)
|
||||
align = 0;
|
||||
}
|
||||
if (align == 0 && (flag_sanitize & SANITIZE_NULL) == 0)
|
||||
return;
|
||||
tree t = TREE_OPERAND (base, 0);
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (t)))
|
||||
return;
|
||||
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (t))) && mem != base)
|
||||
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);
|
||||
tree kind = build_int_cst (TREE_TYPE (t), ikind);
|
||||
tree alignt = build_int_cst (pointer_sized_int_node, align);
|
||||
gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 3, t, kind, alignt);
|
||||
gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
}
|
||||
|
@ -764,15 +856,11 @@ instrument_null (gimple_stmt_iterator gsi, bool is_lhs)
|
|||
{
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
tree t = is_lhs ? gimple_get_lhs (stmt) : gimple_assign_rhs1 (stmt);
|
||||
t = get_base_address (t);
|
||||
const enum tree_code code = TREE_CODE (t);
|
||||
tree base = get_base_address (t);
|
||||
const enum tree_code code = TREE_CODE (base);
|
||||
if (code == MEM_REF
|
||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
|
||||
instrument_mem_ref (TREE_OPERAND (t, 0), &gsi, is_lhs);
|
||||
else if (code == ADDR_EXPR
|
||||
&& POINTER_TYPE_P (TREE_TYPE (t))
|
||||
&& TREE_CODE (TREE_TYPE (TREE_TYPE (t))) == METHOD_TYPE)
|
||||
instrument_member_call (&gsi);
|
||||
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
|
||||
instrument_mem_ref (t, base, &gsi, is_lhs);
|
||||
}
|
||||
|
||||
/* Build an ubsan builtin call for the signed-integer-overflow
|
||||
|
@ -1147,7 +1235,8 @@ public:
|
|||
virtual bool gate (function *)
|
||||
{
|
||||
return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW
|
||||
| SANITIZE_BOOL | SANITIZE_ENUM)
|
||||
| SANITIZE_BOOL | SANITIZE_ENUM
|
||||
| SANITIZE_ALIGNMENT)
|
||||
&& current_function_decl != NULL_TREE
|
||||
&& !lookup_attribute ("no_sanitize_undefined",
|
||||
DECL_ATTRIBUTES (current_function_decl));
|
||||
|
@ -1180,7 +1269,7 @@ pass_ubsan::execute (function *fun)
|
|||
&& is_gimple_assign (stmt))
|
||||
instrument_si_overflow (gsi);
|
||||
|
||||
if (flag_sanitize & SANITIZE_NULL)
|
||||
if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
|
||||
{
|
||||
if (gimple_store_p (stmt))
|
||||
instrument_null (gsi, true);
|
||||
|
|
|
@ -27,7 +27,8 @@ enum ubsan_null_ckind {
|
|||
UBSAN_STORE_OF,
|
||||
UBSAN_REF_BINDING,
|
||||
UBSAN_MEMBER_ACCESS,
|
||||
UBSAN_MEMBER_CALL
|
||||
UBSAN_MEMBER_CALL,
|
||||
UBSAN_CTOR_CALL
|
||||
};
|
||||
|
||||
/* This controls how ubsan prints types. Used in ubsan_type_descriptor. */
|
||||
|
@ -43,8 +44,8 @@ struct ubsan_mismatch_data {
|
|||
tree ckind;
|
||||
};
|
||||
|
||||
extern void ubsan_expand_bounds_ifn (gimple_stmt_iterator *);
|
||||
extern void ubsan_expand_null_ifn (gimple_stmt_iterator);
|
||||
extern bool ubsan_expand_bounds_ifn (gimple_stmt_iterator *);
|
||||
extern bool ubsan_expand_null_ifn (gimple_stmt_iterator *);
|
||||
extern tree ubsan_instrument_unreachable (location_t);
|
||||
extern tree ubsan_create_data (const char *, const location_t *,
|
||||
const struct ubsan_mismatch_data *, ...);
|
||||
|
|
Loading…
Reference in New Issue