mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-17 20:11:06 +08:00
asan.c (pass_sanopt::execute): Handle IFN_UBSAN_OBJECT_SIZE.
* asan.c (pass_sanopt::execute): Handle IFN_UBSAN_OBJECT_SIZE. * doc/invoke.texi: Document -fsanitize=object-size. * flag-types.h (enum sanitize_code): Add SANITIZE_OBJECT_SIZE and or it into SANITIZE_UNDEFINED. * gimple-fold.c (gimple_fold_call): Optimize IFN_UBSAN_OBJECT_SIZE. * internal-fn.c (expand_UBSAN_OBJECT_SIZE): New function. * internal-fn.def (UBSAN_OBJECT_SIZE): Define. * opts.c (common_handle_option): Handle -fsanitize=object-size. * ubsan.c: Include tree-object-size.h. (ubsan_type_descriptor): Call tree_to_uhwi instead of tree_to_shwi. (ubsan_expand_bounds_ifn): Use false instead of 0. (ubsan_expand_objsize_ifn): New function. (instrument_object_size): New function. (pass_ubsan::execute): Add object size instrumentation. * ubsan.h (ubsan_expand_objsize_ifn): Declare. testsuite/ * c-c++-common/ubsan/object-size-1.c: New test. * c-c++-common/ubsan/object-size-2.c: New test. * c-c++-common/ubsan/object-size-3.c: New test. * c-c++-common/ubsan/object-size-4.c: New test. * c-c++-common/ubsan/object-size-5.c: New test. * c-c++-common/ubsan/object-size-6.c: New test. * c-c++-common/ubsan/object-size-7.c: New test. * c-c++-common/ubsan/object-size-8.c: New test. * c-c++-common/ubsan/object-size-9.c: New test. * g++.dg/ubsan/object-size-1.C: New test. * gcc.dg/ubsan/object-size-9.c: New test. From-SVN: r216099
This commit is contained in:
parent
c95e71bef8
commit
0e82f08971
@ -1,3 +1,21 @@
|
||||
2014-10-10 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* asan.c (pass_sanopt::execute): Handle IFN_UBSAN_OBJECT_SIZE.
|
||||
* doc/invoke.texi: Document -fsanitize=object-size.
|
||||
* flag-types.h (enum sanitize_code): Add SANITIZE_OBJECT_SIZE and
|
||||
or it into SANITIZE_UNDEFINED.
|
||||
* gimple-fold.c (gimple_fold_call): Optimize IFN_UBSAN_OBJECT_SIZE.
|
||||
* internal-fn.c (expand_UBSAN_OBJECT_SIZE): New function.
|
||||
* internal-fn.def (UBSAN_OBJECT_SIZE): Define.
|
||||
* opts.c (common_handle_option): Handle -fsanitize=object-size.
|
||||
* ubsan.c: Include tree-object-size.h.
|
||||
(ubsan_type_descriptor): Call tree_to_uhwi instead of tree_to_shwi.
|
||||
(ubsan_expand_bounds_ifn): Use false instead of 0.
|
||||
(ubsan_expand_objsize_ifn): New function.
|
||||
(instrument_object_size): New function.
|
||||
(pass_ubsan::execute): Add object size instrumentation.
|
||||
* ubsan.h (ubsan_expand_objsize_ifn): Declare.
|
||||
|
||||
2014-10-10 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR target/63404
|
||||
|
@ -2879,6 +2879,9 @@ pass_sanopt::execute (function *fun)
|
||||
case IFN_UBSAN_BOUNDS:
|
||||
no_next = ubsan_expand_bounds_ifn (&gsi);
|
||||
break;
|
||||
case IFN_UBSAN_OBJECT_SIZE:
|
||||
no_next = ubsan_expand_objsize_ifn (&gsi);
|
||||
break;
|
||||
case IFN_ASAN_CHECK:
|
||||
{
|
||||
no_next = asan_expand_check_ifn (&gsi, use_calls);
|
||||
|
@ -5578,6 +5578,12 @@ 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=object-size
|
||||
@opindex fsanitize=object-size
|
||||
This option enables instrumentation of memory references using the
|
||||
@code{__builtin_object_size} function. Various out of bounds pointer
|
||||
accesses are detected.
|
||||
|
||||
@item -fsanitize=float-divide-by-zero
|
||||
@opindex fsanitize=float-divide-by-zero
|
||||
Detect floating-point division by zero. Unlike other similar options,
|
||||
|
@ -236,12 +236,14 @@ enum sanitize_code {
|
||||
SANITIZE_ALIGNMENT = 1 << 17,
|
||||
SANITIZE_NONNULL_ATTRIBUTE = 1 << 18,
|
||||
SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1 << 19,
|
||||
SANITIZE_OBJECT_SIZE = 1 << 20,
|
||||
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
|
||||
| SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
|
||||
| SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
|
||||
| SANITIZE_BOUNDS | SANITIZE_ALIGNMENT
|
||||
| SANITIZE_NONNULL_ATTRIBUTE
|
||||
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE,
|
||||
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
|
||||
| SANITIZE_OBJECT_SIZE,
|
||||
SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
|
||||
};
|
||||
|
||||
|
@ -2662,6 +2662,19 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
|
||||
gimple_call_arg (stmt, 1),
|
||||
gimple_call_arg (stmt, 2));
|
||||
break;
|
||||
case IFN_UBSAN_OBJECT_SIZE:
|
||||
if (integer_all_onesp (gimple_call_arg (stmt, 2))
|
||||
|| (TREE_CODE (gimple_call_arg (stmt, 1)) == INTEGER_CST
|
||||
&& TREE_CODE (gimple_call_arg (stmt, 2)) == INTEGER_CST
|
||||
&& tree_int_cst_le (gimple_call_arg (stmt, 1),
|
||||
gimple_call_arg (stmt, 2))))
|
||||
{
|
||||
gsi_replace (gsi, gimple_build_nop (), true);
|
||||
unlink_stmt_vdef (stmt);
|
||||
release_defs (stmt);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case IFN_UBSAN_CHECK_ADD:
|
||||
subcode = PLUS_EXPR;
|
||||
break;
|
||||
|
@ -183,6 +183,14 @@ expand_UBSAN_BOUNDS (gimple stmt ATTRIBUTE_UNUSED)
|
||||
|
||||
/* This should get expanded in the sanopt pass. */
|
||||
|
||||
static void
|
||||
expand_UBSAN_OBJECT_SIZE (gimple stmt ATTRIBUTE_UNUSED)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* This should get expanded in the sanopt pass. */
|
||||
|
||||
static void
|
||||
expand_ASAN_CHECK (gimple stmt ATTRIBUTE_UNUSED)
|
||||
{
|
||||
|
@ -53,6 +53,7 @@ DEF_INTERNAL_FN (UBSAN_BOUNDS, ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (UBSAN_CHECK_ADD, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (UBSAN_CHECK_SUB, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (UBSAN_CHECK_MUL, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
|
||||
DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".W...")
|
||||
|
@ -1513,6 +1513,8 @@ common_handle_option (struct gcc_options *opts,
|
||||
{ "returns-nonnull-attribute",
|
||||
SANITIZE_RETURNS_NONNULL_ATTRIBUTE,
|
||||
sizeof "returns-nonnull-attribute" - 1 },
|
||||
{ "object-size", SANITIZE_OBJECT_SIZE,
|
||||
sizeof "object-size" - 1 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
const char *comma;
|
||||
|
@ -1,3 +1,17 @@
|
||||
2014-10-10 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* c-c++-common/ubsan/object-size-1.c: New test.
|
||||
* c-c++-common/ubsan/object-size-2.c: New test.
|
||||
* c-c++-common/ubsan/object-size-3.c: New test.
|
||||
* c-c++-common/ubsan/object-size-4.c: New test.
|
||||
* c-c++-common/ubsan/object-size-5.c: New test.
|
||||
* c-c++-common/ubsan/object-size-6.c: New test.
|
||||
* c-c++-common/ubsan/object-size-7.c: New test.
|
||||
* c-c++-common/ubsan/object-size-8.c: New test.
|
||||
* c-c++-common/ubsan/object-size-9.c: New test.
|
||||
* g++.dg/ubsan/object-size-1.C: New test.
|
||||
* gcc.dg/ubsan/object-size-9.c: New test.
|
||||
|
||||
2014-10-10 Max Ostapenko <m.ostapenko@partner.samsung.com>
|
||||
|
||||
* lib/asan-dg.exp (asan_link_flags): Save ld_library_path.
|
||||
|
125
gcc/testsuite/c-c++-common/ubsan/object-size-1.c
Normal file
125
gcc/testsuite/c-c++-common/ubsan/object-size-1.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=undefined" } */
|
||||
|
||||
/* Sanity-test -fsanitize=object-size. We use -fsanitize=undefined option
|
||||
to check that this feature doesn't clash with -fsanitize=bounds et al. */
|
||||
|
||||
#define N 20
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f1 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
char *p, *orig;
|
||||
orig = p = (char *) __builtin_calloc (N, 1);
|
||||
j = *(p + i);
|
||||
j = p[i];
|
||||
p++;
|
||||
j = p[i - 1];
|
||||
j = *(p + i - 1);
|
||||
__builtin_free (orig);
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f2 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
char a[N];
|
||||
__builtin_memset (a, 0, N);
|
||||
j = *(a + i);
|
||||
char *p = a;
|
||||
j = *(p + i);
|
||||
j = p[i];
|
||||
p += 10;
|
||||
j = *(p + i - 10);
|
||||
j = p[i - 10];
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f3 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
int *p = (int *) __builtin_calloc (N, sizeof (*p));
|
||||
int *o = &p[i];
|
||||
j = *o;
|
||||
j = o[0];
|
||||
__builtin_free (p);
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f4 (void)
|
||||
{
|
||||
/* The second argument to __builtin_calloc is intentional. */
|
||||
int *p = (int *) __builtin_calloc (3, 1);
|
||||
*p = 42;
|
||||
__builtin_free (p);
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*store to address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f5 (int *p)
|
||||
{
|
||||
/* This is not instrumented. But don't ICE, etc. */
|
||||
volatile int i = p[N];
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
f1 (N);
|
||||
f2 (N);
|
||||
f3 (N);
|
||||
f4 ();
|
||||
int *p = (int *) __builtin_calloc (N, sizeof (*p));
|
||||
f5 (p);
|
||||
__builtin_free (p);
|
||||
return 0;
|
||||
}
|
10
gcc/testsuite/c-c++-common/ubsan/object-size-2.c
Normal file
10
gcc/testsuite/c-c++-common/ubsan/object-size-2.c
Normal file
@ -0,0 +1,10 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=undefined" } */
|
||||
|
||||
void
|
||||
foo (unsigned long ul)
|
||||
{
|
||||
unsigned int u;
|
||||
u = *(unsigned long *) ul;
|
||||
}
|
56
gcc/testsuite/c-c++-common/ubsan/object-size-3.c
Normal file
56
gcc/testsuite/c-c++-common/ubsan/object-size-3.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=object-size -fno-sanitize-recover" } */
|
||||
|
||||
/* Test valid uses. */
|
||||
|
||||
#define N 20
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f1 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
char *p, *orig;
|
||||
orig = p = (char *) __builtin_calloc (N, 1);
|
||||
j = *(p + i);
|
||||
j = p[i];
|
||||
p++;
|
||||
j = p[i - 1];
|
||||
j = *(p + i - 1);
|
||||
__builtin_free (orig);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f2 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
char a[N];
|
||||
__builtin_memset (a, 0, N);
|
||||
j = *(a + i);
|
||||
char *p = a;
|
||||
j = *(p + i);
|
||||
j = p[i];
|
||||
p += 10;
|
||||
j = *(p + i - 10);
|
||||
j = p[i - 10];
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f3 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
int *p = (int *) __builtin_calloc (N, sizeof (*p));
|
||||
int *o = &p[i];
|
||||
j = *o;
|
||||
j = o[0];
|
||||
__builtin_free (p);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
f1 (N - 1);
|
||||
f2 (N - 1);
|
||||
f3 (N - 1);
|
||||
return 0;
|
||||
}
|
31
gcc/testsuite/c-c++-common/ubsan/object-size-4.c
Normal file
31
gcc/testsuite/c-c++-common/ubsan/object-size-4.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=object-size" } */
|
||||
|
||||
/* Test that we instrument flexible array members. */
|
||||
|
||||
struct T { int l; int a[]; };
|
||||
struct U { int l; int a[0]; };
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
volatile int i;
|
||||
struct T *t = (struct T *) __builtin_calloc (sizeof (struct T)
|
||||
+ sizeof (int), 1);
|
||||
i = t->a[1];
|
||||
|
||||
struct U *u = (struct U *) __builtin_calloc (sizeof (struct U)
|
||||
+ sizeof (int), 1);
|
||||
i = u->a[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
38
gcc/testsuite/c-c++-common/ubsan/object-size-5.c
Normal file
38
gcc/testsuite/c-c++-common/ubsan/object-size-5.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=object-size" } */
|
||||
|
||||
/* Test structures with -fsanitize=object-size. */
|
||||
|
||||
#define N 20
|
||||
|
||||
struct S { char *p; int i; };
|
||||
struct T { struct S *s; };
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
f1 (int i)
|
||||
{
|
||||
volatile int j;
|
||||
struct S s;
|
||||
s.p = (char *) __builtin_calloc (N, 1);
|
||||
j = s.p[i];
|
||||
j = *(s.p + i);
|
||||
__builtin_free (s.p);
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
f1 (N);
|
||||
f1 (N - 1);
|
||||
return 0;
|
||||
}
|
9
gcc/testsuite/c-c++-common/ubsan/object-size-6.c
Normal file
9
gcc/testsuite/c-c++-common/ubsan/object-size-6.c
Normal file
@ -0,0 +1,9 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=object-size" } */
|
||||
|
||||
char
|
||||
foo (void *v)
|
||||
{
|
||||
return *(char *) v;
|
||||
}
|
29
gcc/testsuite/c-c++-common/ubsan/object-size-7.c
Normal file
29
gcc/testsuite/c-c++-common/ubsan/object-size-7.c
Normal file
@ -0,0 +1,29 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=object-size" } */
|
||||
|
||||
#define N 20
|
||||
|
||||
struct S { int a; };
|
||||
|
||||
__attribute__((noinline, noclone)) struct S
|
||||
f1 (int i)
|
||||
{
|
||||
struct S a[N];
|
||||
struct S *p = a;
|
||||
struct S s;
|
||||
s = p[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
f1 (N);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
32
gcc/testsuite/c-c++-common/ubsan/object-size-8.c
Normal file
32
gcc/testsuite/c-c++-common/ubsan/object-size-8.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=undefined" } */
|
||||
|
||||
struct S { int a; int b; };
|
||||
|
||||
static inline __attribute__((always_inline)) int
|
||||
foo (struct S *p)
|
||||
{
|
||||
volatile int a;
|
||||
a = p->a; /* OK */
|
||||
return p->b;
|
||||
}
|
||||
|
||||
int
|
||||
bar (void)
|
||||
{
|
||||
struct S *p = (struct S *) __builtin_calloc (sizeof (int) + sizeof (int) / 2, 1);
|
||||
return foo (p);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
bar ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
97
gcc/testsuite/c-c++-common/ubsan/object-size-9.c
Normal file
97
gcc/testsuite/c-c++-common/ubsan/object-size-9.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=undefined" } */
|
||||
|
||||
/* Test PARM_DECLs and RESULT_DECLs. */
|
||||
|
||||
struct T { char d[8]; int e; };
|
||||
struct T t = { "abcdefg", 1 };
|
||||
#ifdef __cplusplus
|
||||
struct C { C () : d("abcdefg"), e(1) {} C (const C &x) { __builtin_memcpy (d, x.d, 8); e = x.e; } ~C () {} char d[8]; int e; };
|
||||
#endif
|
||||
struct U { int a : 5; int b : 19; int c : 8; };
|
||||
struct S { struct U d[10]; };
|
||||
struct S s;
|
||||
|
||||
int
|
||||
f1 (struct T x, int i)
|
||||
{
|
||||
char *p = x.d;
|
||||
p += i;
|
||||
return *p;
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
#ifdef __cplusplus
|
||||
struct C
|
||||
f2 (int i)
|
||||
{
|
||||
struct C x;
|
||||
x.d[i] = 'z';
|
||||
return x;
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*index 12 out of bounds for type 'char \\\[8\\\]'\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*store to address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
|
||||
struct C
|
||||
f3 (int i)
|
||||
{
|
||||
struct C x;
|
||||
char *p = x.d;
|
||||
p += i;
|
||||
*p = 'z';
|
||||
return x;
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*store to address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" { target { c++ } } } */
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
f4 (int i)
|
||||
{
|
||||
return s.d[i].b;
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*index 12 out of bounds for type 'U \\\[10\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
int
|
||||
f5 (int i)
|
||||
{
|
||||
struct U *u = s.d;
|
||||
u += i;
|
||||
return u->b;
|
||||
}
|
||||
|
||||
/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1 (t, 12);
|
||||
#ifdef __cplusplus
|
||||
f2 (12);
|
||||
f3 (12);
|
||||
#endif
|
||||
f4 (12);
|
||||
f5 (12);
|
||||
return 0;
|
||||
}
|
18
gcc/testsuite/g++.dg/ubsan/object-size-1.C
Normal file
18
gcc/testsuite/g++.dg/ubsan/object-size-1.C
Normal file
@ -0,0 +1,18 @@
|
||||
// { dg-do compile }
|
||||
// { dg-options "-fsanitize=undefined -fpermissive" }
|
||||
|
||||
struct T { int c; char d[]; };
|
||||
|
||||
struct T t = { 1, "a" }; // { dg-warning "initializer-string for array of chars is too long" }
|
||||
|
||||
int
|
||||
baz (int i)
|
||||
{
|
||||
return t.d[i];
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
baz (3);
|
||||
}
|
24
gcc/testsuite/gcc.dg/ubsan/object-size-9.c
Normal file
24
gcc/testsuite/gcc.dg/ubsan/object-size-9.c
Normal file
@ -0,0 +1,24 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
|
||||
/* { dg-options "-fsanitize=undefined" } */
|
||||
|
||||
struct T { int c; char d[]; };
|
||||
struct T t = { 1, "a" };
|
||||
|
||||
int
|
||||
baz (int i)
|
||||
{
|
||||
return t.d[i];
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
baz (2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
|
212
gcc/ubsan.c
212
gcc/ubsan.c
@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "realmpfr.h"
|
||||
#include "dfp.h"
|
||||
#include "builtins.h"
|
||||
#include "tree-object-size.h"
|
||||
|
||||
/* Map from a tree to a VAR_DECL tree. */
|
||||
|
||||
@ -391,7 +392,7 @@ ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle)
|
||||
tree dom = TYPE_DOMAIN (t);
|
||||
if (dom && TREE_CODE (TYPE_MAX_VALUE (dom)) == INTEGER_CST)
|
||||
pos += sprintf (&pretty_name[pos], HOST_WIDE_INT_PRINT_DEC,
|
||||
tree_to_shwi (TYPE_MAX_VALUE (dom)) + 1);
|
||||
tree_to_uhwi (TYPE_MAX_VALUE (dom)) + 1);
|
||||
else
|
||||
/* ??? We can't determine the variable name; print VLA unspec. */
|
||||
pretty_name[pos++] = '*';
|
||||
@ -614,12 +615,12 @@ ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
|
||||
/* Create condition "if (index > bound)". */
|
||||
basic_block then_bb, fallthru_bb;
|
||||
gimple_stmt_iterator cond_insert_point
|
||||
= create_cond_insert_point (gsi, 0/*before_p*/, false, true,
|
||||
= create_cond_insert_point (gsi, false, false, true,
|
||||
&then_bb, &fallthru_bb);
|
||||
index = fold_convert (TREE_TYPE (bound), index);
|
||||
index = force_gimple_operand_gsi (&cond_insert_point, index,
|
||||
true/*simple_p*/, NULL_TREE,
|
||||
false/*before*/, GSI_NEW_STMT);
|
||||
true, NULL_TREE,
|
||||
false, GSI_NEW_STMT);
|
||||
gimple g = gimple_build_cond (GT_EXPR, index, bound, NULL_TREE, NULL_TREE);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
|
||||
@ -830,6 +831,76 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Expand UBSAN_OBJECT_SIZE internal call. */
|
||||
|
||||
bool
|
||||
ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsi);
|
||||
location_t loc = gimple_location (stmt);
|
||||
gcc_assert (gimple_call_num_args (stmt) == 4);
|
||||
|
||||
tree ptr = gimple_call_arg (stmt, 0);
|
||||
tree offset = gimple_call_arg (stmt, 1);
|
||||
tree size = gimple_call_arg (stmt, 2);
|
||||
tree ckind = gimple_call_arg (stmt, 3);
|
||||
gimple_stmt_iterator gsi_orig = *gsi;
|
||||
gimple g;
|
||||
|
||||
/* See if we can discard the check. */
|
||||
if (TREE_CODE (size) != INTEGER_CST
|
||||
|| integer_all_onesp (size))
|
||||
/* Yes, __builtin_object_size couldn't determine the
|
||||
object size. */;
|
||||
else
|
||||
{
|
||||
/* if (offset > objsize) */
|
||||
basic_block then_bb, fallthru_bb;
|
||||
gimple_stmt_iterator cond_insert_point
|
||||
= create_cond_insert_point (gsi, false, false, true,
|
||||
&then_bb, &fallthru_bb);
|
||||
g = gimple_build_cond (GT_EXPR, offset, size, NULL_TREE, NULL_TREE);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
|
||||
|
||||
/* Generate __ubsan_handle_type_mismatch call. */
|
||||
*gsi = gsi_after_labels (then_bb);
|
||||
if (flag_sanitize_undefined_trap_on_error)
|
||||
g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
||||
else
|
||||
{
|
||||
tree data
|
||||
= ubsan_create_data ("__ubsan_objsz_data", 1, &loc,
|
||||
ubsan_type_descriptor (TREE_TYPE (ptr),
|
||||
UBSAN_PRINT_POINTER),
|
||||
NULL_TREE,
|
||||
build_zero_cst (pointer_sized_int_node),
|
||||
ckind,
|
||||
NULL_TREE);
|
||||
data = build_fold_addr_expr_loc (loc, data);
|
||||
enum built_in_function bcode
|
||||
= flag_sanitize_recover
|
||||
? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH
|
||||
: BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
|
||||
tree p = make_ssa_name (pointer_sized_int_node, NULL);
|
||||
g = gimple_build_assign_with_ops (NOP_EXPR, p, ptr, NULL_TREE);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_before (gsi, g, GSI_SAME_STMT);
|
||||
g = gimple_build_call (builtin_decl_explicit (bcode), 2, data, p);
|
||||
}
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_before (gsi, g, GSI_SAME_STMT);
|
||||
|
||||
/* Point GSI to next logical statement. */
|
||||
*gsi = gsi_start_bb (fallthru_bb);
|
||||
}
|
||||
|
||||
/* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */
|
||||
unlink_stmt_vdef (stmt);
|
||||
gsi_remove (&gsi_orig, true);
|
||||
return gsi_end_p (*gsi);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
@ -1339,6 +1410,128 @@ instrument_nonnull_return (gimple_stmt_iterator *gsi)
|
||||
flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
|
||||
}
|
||||
|
||||
/* Instrument memory references. Here we check whether the pointer
|
||||
points to an out-of-bounds location. */
|
||||
|
||||
static void
|
||||
instrument_object_size (gimple_stmt_iterator *gsi, bool is_lhs)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsi);
|
||||
location_t loc = gimple_location (stmt);
|
||||
tree t = is_lhs ? gimple_get_lhs (stmt) : gimple_assign_rhs1 (stmt);
|
||||
tree type;
|
||||
HOST_WIDE_INT size_in_bytes;
|
||||
|
||||
type = TREE_TYPE (t);
|
||||
if (VOID_TYPE_P (type))
|
||||
return;
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case COMPONENT_REF:
|
||||
if (TREE_CODE (t) == COMPONENT_REF
|
||||
&& DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
|
||||
{
|
||||
tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
|
||||
t = build3 (COMPONENT_REF, TREE_TYPE (repr), TREE_OPERAND (t, 0),
|
||||
repr, NULL_TREE);
|
||||
}
|
||||
break;
|
||||
case ARRAY_REF:
|
||||
case INDIRECT_REF:
|
||||
case MEM_REF:
|
||||
case VAR_DECL:
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
size_in_bytes = int_size_in_bytes (type);
|
||||
if (size_in_bytes <= 0)
|
||||
return;
|
||||
|
||||
HOST_WIDE_INT bitsize, bitpos;
|
||||
tree offset;
|
||||
enum machine_mode mode;
|
||||
int volatilep = 0, unsignedp = 0;
|
||||
tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
|
||||
&unsignedp, &volatilep, false);
|
||||
|
||||
if (bitpos % BITS_PER_UNIT != 0
|
||||
|| bitsize != size_in_bytes * BITS_PER_UNIT)
|
||||
return;
|
||||
|
||||
bool decl_p = DECL_P (inner);
|
||||
tree base = decl_p ? inner : TREE_OPERAND (inner, 0);
|
||||
tree ptr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)), t);
|
||||
|
||||
while (TREE_CODE (base) == SSA_NAME)
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (base);
|
||||
if (gimple_assign_ssa_name_copy_p (def_stmt)
|
||||
|| (gimple_assign_cast_p (def_stmt)
|
||||
&& POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
|
||||
|| (is_gimple_assign (def_stmt)
|
||||
&& gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR))
|
||||
base = gimple_assign_rhs1 (def_stmt);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (base)) && !DECL_P (base))
|
||||
return;
|
||||
|
||||
tree sizet;
|
||||
tree base_addr = base;
|
||||
if (decl_p)
|
||||
base_addr = build1 (ADDR_EXPR,
|
||||
build_pointer_type (TREE_TYPE (base)), base);
|
||||
unsigned HOST_WIDE_INT size = compute_builtin_object_size (base_addr, 0);
|
||||
if (size != (unsigned HOST_WIDE_INT) -1)
|
||||
sizet = build_int_cst (sizetype, size);
|
||||
else if (optimize)
|
||||
{
|
||||
if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION)
|
||||
loc = input_location;
|
||||
/* Generate __builtin_object_size call. */
|
||||
sizet = builtin_decl_explicit (BUILT_IN_OBJECT_SIZE);
|
||||
sizet = build_call_expr_loc (loc, sizet, 2, base_addr,
|
||||
integer_zero_node);
|
||||
sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true,
|
||||
GSI_SAME_STMT);
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
/* Generate UBSAN_OBJECT_SIZE (ptr, ptr+sizeof(*ptr)-base, objsize, ckind)
|
||||
call. */
|
||||
/* ptr + sizeof (*ptr) - base */
|
||||
t = fold_build2 (MINUS_EXPR, sizetype,
|
||||
fold_convert (pointer_sized_int_node, ptr),
|
||||
fold_convert (pointer_sized_int_node, base_addr));
|
||||
t = fold_build2 (PLUS_EXPR, sizetype, t, TYPE_SIZE_UNIT (type));
|
||||
|
||||
/* Perhaps we can omit the check. */
|
||||
if (TREE_CODE (t) == INTEGER_CST
|
||||
&& TREE_CODE (sizet) == INTEGER_CST
|
||||
&& tree_int_cst_le (t, sizet))
|
||||
return;
|
||||
|
||||
/* Nope. Emit the check. */
|
||||
t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, true,
|
||||
GSI_SAME_STMT);
|
||||
ptr = force_gimple_operand_gsi (gsi, ptr, true, NULL_TREE, true,
|
||||
GSI_SAME_STMT);
|
||||
tree ckind = build_int_cst (unsigned_char_type_node,
|
||||
is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF);
|
||||
gimple g = gimple_build_call_internal (IFN_UBSAN_OBJECT_SIZE, 4,
|
||||
ptr, t, sizet, ckind);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_before (gsi, g, GSI_SAME_STMT);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const pass_data pass_data_ubsan =
|
||||
@ -1368,7 +1561,8 @@ public:
|
||||
| SANITIZE_BOOL | SANITIZE_ENUM
|
||||
| SANITIZE_ALIGNMENT
|
||||
| SANITIZE_NONNULL_ATTRIBUTE
|
||||
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
|
||||
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
|
||||
| SANITIZE_OBJECT_SIZE)
|
||||
&& current_function_decl != NULL_TREE
|
||||
&& !lookup_attribute ("no_sanitize_undefined",
|
||||
DECL_ATTRIBUTES (current_function_decl));
|
||||
@ -1431,6 +1625,14 @@ pass_ubsan::execute (function *fun)
|
||||
bb = gimple_bb (stmt);
|
||||
}
|
||||
|
||||
if (flag_sanitize & SANITIZE_OBJECT_SIZE)
|
||||
{
|
||||
if (gimple_store_p (stmt))
|
||||
instrument_object_size (&gsi, true);
|
||||
if (gimple_assign_load_p (stmt))
|
||||
instrument_object_size (&gsi, false);
|
||||
}
|
||||
|
||||
gsi_next (&gsi);
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ enum ubsan_print_style {
|
||||
|
||||
extern bool ubsan_expand_bounds_ifn (gimple_stmt_iterator *);
|
||||
extern bool ubsan_expand_null_ifn (gimple_stmt_iterator *);
|
||||
extern bool ubsan_expand_objsize_ifn (gimple_stmt_iterator *);
|
||||
extern tree ubsan_instrument_unreachable (location_t);
|
||||
extern tree ubsan_create_data (const char *, int, const location_t *, ...);
|
||||
extern tree ubsan_type_descriptor (tree, enum ubsan_print_style = UBSAN_PRINT_NORMAL);
|
||||
|
Loading…
x
Reference in New Issue
Block a user