asan.c (initialize_sanitizer_builtins): Add BT_FN_VOID_UINT8_UINT8...
* asan.c (initialize_sanitizer_builtins): Add BT_FN_VOID_UINT8_UINT8, BT_FN_VOID_UINT16_UINT16, BT_FN_VOID_UINT32_UINT32, BT_FN_VOID_UINT64_UINT64, BT_FN_VOID_FLOAT_FLOAT, BT_FN_VOID_DOUBLE_DOUBLE and BT_FN_VOID_UINT64_PTR variables. * builtin-types.def (BT_FN_VOID_UINT8_UINT8): New fn type. (BT_FN_VOID_UINT16_UINT16): Likewise. (BT_FN_VOID_UINT32_UINT32): Likewise. (BT_FN_VOID_FLOAT_FLOAT): Likewise. (BT_FN_VOID_DOUBLE_DOUBLE): Likewise. (BT_FN_VOID_UINT64_PTR): Likewise. * common.opt (flag_sanitize_coverage): New variable. (fsanitize-coverage=trace-pc): Remove. (fsanitize-coverage=): Add. * flag-types.h (enum sanitize_coverage_code): New enum. * fold-const.c (fold_range_test): Disable non-short-circuit optimization if flag_sanitize_coverage. (fold_truth_andor): Likewise. * tree-ssa-ifcombine.c (ifcombine_ifandif): Likewise. * opts.c (COVERAGE_SANITIZER_OPT): Define. (coverage_sanitizer_opts): New array. (get_closest_sanitizer_option): Add OPTS argument, handle also OPT_fsanitize_coverage_. (parse_sanitizer_options): Adjusted to also handle OPT_fsanitize_coverage_. (common_handle_option): Add OPT_fsanitize_coverage_. * sancov.c (instrument_comparison, instrument_switch): New function. (sancov_pass): Add trace-cmp support. * sanitizer.def (BUILT_IN_SANITIZER_COV_TRACE_CMP1, BUILT_IN_SANITIZER_COV_TRACE_CMP2, BUILT_IN_SANITIZER_COV_TRACE_CMP4, BUILT_IN_SANITIZER_COV_TRACE_CMP8, BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1, BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2, BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4, BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8, BUILT_IN_SANITIZER_COV_TRACE_CMPF, BUILT_IN_SANITIZER_COV_TRACE_CMPD, BUILT_IN_SANITIZER_COV_TRACE_SWITCH): New builtins. * doc/invoke.texi: Document -fsanitize-coverage=trace-cmp. * gcc.dg/sancov/cmp0.c: New test. Co-Authored-By: Jakub Jelinek <jakub@redhat.com> From-SVN: r251801
This commit is contained in:
parent
1816130969
commit
f6e50a7d64
@ -1,3 +1,45 @@
|
||||
2017-09-06 Wish Wu <wishwu007@gmail.com>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* asan.c (initialize_sanitizer_builtins): Add
|
||||
BT_FN_VOID_UINT8_UINT8, BT_FN_VOID_UINT16_UINT16,
|
||||
BT_FN_VOID_UINT32_UINT32, BT_FN_VOID_UINT64_UINT64,
|
||||
BT_FN_VOID_FLOAT_FLOAT, BT_FN_VOID_DOUBLE_DOUBLE and
|
||||
BT_FN_VOID_UINT64_PTR variables.
|
||||
* builtin-types.def (BT_FN_VOID_UINT8_UINT8): New fn type.
|
||||
(BT_FN_VOID_UINT16_UINT16): Likewise.
|
||||
(BT_FN_VOID_UINT32_UINT32): Likewise.
|
||||
(BT_FN_VOID_FLOAT_FLOAT): Likewise.
|
||||
(BT_FN_VOID_DOUBLE_DOUBLE): Likewise.
|
||||
(BT_FN_VOID_UINT64_PTR): Likewise.
|
||||
* common.opt (flag_sanitize_coverage): New variable.
|
||||
(fsanitize-coverage=trace-pc): Remove.
|
||||
(fsanitize-coverage=): Add.
|
||||
* flag-types.h (enum sanitize_coverage_code): New enum.
|
||||
* fold-const.c (fold_range_test): Disable non-short-circuit
|
||||
optimization if flag_sanitize_coverage.
|
||||
(fold_truth_andor): Likewise.
|
||||
* tree-ssa-ifcombine.c (ifcombine_ifandif): Likewise.
|
||||
* opts.c (COVERAGE_SANITIZER_OPT): Define.
|
||||
(coverage_sanitizer_opts): New array.
|
||||
(get_closest_sanitizer_option): Add OPTS argument, handle also
|
||||
OPT_fsanitize_coverage_.
|
||||
(parse_sanitizer_options): Adjusted to also handle
|
||||
OPT_fsanitize_coverage_.
|
||||
(common_handle_option): Add OPT_fsanitize_coverage_.
|
||||
* sancov.c (instrument_comparison, instrument_switch): New function.
|
||||
(sancov_pass): Add trace-cmp support.
|
||||
* sanitizer.def (BUILT_IN_SANITIZER_COV_TRACE_CMP1,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CMP2, BUILT_IN_SANITIZER_COV_TRACE_CMP4,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CMP8,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_CMPF, BUILT_IN_SANITIZER_COV_TRACE_CMPD,
|
||||
BUILT_IN_SANITIZER_COV_TRACE_SWITCH): New builtins.
|
||||
* doc/invoke.texi: Document -fsanitize-coverage=trace-cmp.
|
||||
|
||||
2017-09-06 Richard Earnshaw <rearnsha@arm.com>
|
||||
|
||||
* config/arm/parsecpu.awk (fatal): Note that we've encountered an
|
||||
|
23
gcc/asan.c
23
gcc/asan.c
@ -2709,6 +2709,29 @@ initialize_sanitizer_builtins (void)
|
||||
tree BT_FN_SIZE_CONST_PTR_INT
|
||||
= build_function_type_list (size_type_node, const_ptr_type_node,
|
||||
integer_type_node, NULL_TREE);
|
||||
|
||||
tree BT_FN_VOID_UINT8_UINT8
|
||||
= build_function_type_list (void_type_node, unsigned_char_type_node,
|
||||
unsigned_char_type_node, NULL_TREE);
|
||||
tree BT_FN_VOID_UINT16_UINT16
|
||||
= build_function_type_list (void_type_node, uint16_type_node,
|
||||
uint16_type_node, NULL_TREE);
|
||||
tree BT_FN_VOID_UINT32_UINT32
|
||||
= build_function_type_list (void_type_node, uint32_type_node,
|
||||
uint32_type_node, NULL_TREE);
|
||||
tree BT_FN_VOID_UINT64_UINT64
|
||||
= build_function_type_list (void_type_node, uint64_type_node,
|
||||
uint64_type_node, NULL_TREE);
|
||||
tree BT_FN_VOID_FLOAT_FLOAT
|
||||
= build_function_type_list (void_type_node, float_type_node,
|
||||
float_type_node, NULL_TREE);
|
||||
tree BT_FN_VOID_DOUBLE_DOUBLE
|
||||
= build_function_type_list (void_type_node, double_type_node,
|
||||
double_type_node, NULL_TREE);
|
||||
tree BT_FN_VOID_UINT64_PTR
|
||||
= build_function_type_list (void_type_node, uint64_type_node,
|
||||
ptr_type_node, NULL_TREE);
|
||||
|
||||
tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
|
||||
tree BT_FN_IX_CONST_VPTR_INT[5];
|
||||
tree BT_FN_IX_VPTR_IX_INT[5];
|
||||
|
@ -338,8 +338,20 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTRMODE_PTR,
|
||||
BT_VOID, BT_PTRMODE, BT_PTR)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTRMODE,
|
||||
BT_VOID, BT_PTR, BT_PTRMODE)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT8_UINT8,
|
||||
BT_VOID, BT_UINT8, BT_UINT8)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT16_UINT16,
|
||||
BT_VOID, BT_UINT16, BT_UINT16)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT32_UINT32,
|
||||
BT_VOID, BT_UINT32, BT_UINT32)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT64_UINT64,
|
||||
BT_VOID, BT_UINT64, BT_UINT64)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_FLOAT_FLOAT,
|
||||
BT_VOID, BT_FLOAT, BT_FLOAT)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_DOUBLE_DOUBLE,
|
||||
BT_VOID, BT_DOUBLE, BT_DOUBLE)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT64_PTR,
|
||||
BT_VOID, BT_UINT64, BT_PTR)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VALIST_REF_VALIST_ARG,
|
||||
BT_VOID, BT_VALIST_REF, BT_VALIST_ARG)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_LONG_LONG_LONG,
|
||||
|
@ -233,10 +233,9 @@ unsigned int flag_sanitize
|
||||
Variable
|
||||
unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN)
|
||||
|
||||
fsanitize-coverage=trace-pc
|
||||
Common Report Var(flag_sanitize_coverage)
|
||||
Enable coverage-guided fuzzing code instrumentation.
|
||||
Inserts call to __sanitizer_cov_trace_pc into every basic block.
|
||||
; What the coverage sanitizers should instrument
|
||||
Variable
|
||||
unsigned int flag_sanitize_coverage
|
||||
|
||||
; Flag whether a prefix has been added to dump_base_name
|
||||
Variable
|
||||
@ -982,6 +981,10 @@ fsanitize=
|
||||
Common Driver Report Joined
|
||||
Select what to sanitize.
|
||||
|
||||
fsanitize-coverage=
|
||||
Common Report Joined
|
||||
Select what to coverage sanitize.
|
||||
|
||||
fasan-shadow-offset=
|
||||
Common Joined RejectNegative Var(common_deferred_options) Defer
|
||||
-fasan-shadow-offset=<number> Use custom shadow memory offset.
|
||||
|
@ -11169,6 +11169,20 @@ is usable even in freestanding environments.
|
||||
Enable coverage-guided fuzzing code instrumentation.
|
||||
Inserts a call to @code{__sanitizer_cov_trace_pc} into every basic block.
|
||||
|
||||
@item -fsanitize-coverage=trace-cmp
|
||||
@opindex fsanitize-coverage=trace-cmp
|
||||
Enable dataflow guided fuzzing code instrumentation.
|
||||
Inserts a call to @code{__sanitizer_cov_trace_cmp1},
|
||||
@code{__sanitizer_cov_trace_cmp2}, @code{__sanitizer_cov_trace_cmp4} or
|
||||
@code{__sanitizer_cov_trace_cmp8} for integral comparison with both operands
|
||||
variable or @code{__sanitizer_cov_trace_const_cmp1},
|
||||
@code{__sanitizer_cov_trace_const_cmp2},
|
||||
@code{__sanitizer_cov_trace_const_cmp4} or
|
||||
@code{__sanitizer_cov_trace_const_cmp8} for integral comparison with one
|
||||
operand constant, @code{__sanitizer_cov_trace_cmpf} or
|
||||
@code{__sanitizer_cov_trace_cmpd} for float or double comparisons and
|
||||
@code{__sanitizer_cov_trace_switch} for switch statements.
|
||||
|
||||
@item -fbounds-check
|
||||
@opindex fbounds-check
|
||||
For front ends that support it, generate additional code to check that
|
||||
|
@ -252,6 +252,14 @@ enum sanitize_code {
|
||||
| SANITIZE_BOUNDS_STRICT
|
||||
};
|
||||
|
||||
/* Different trace modes. */
|
||||
enum sanitize_coverage_code {
|
||||
/* Trace PC. */
|
||||
SANITIZE_COV_TRACE_PC = 1 << 0,
|
||||
/* Trace Comparison. */
|
||||
SANITIZE_COV_TRACE_CMP = 1 << 1
|
||||
};
|
||||
|
||||
/* flag_vtable_verify initialization levels. */
|
||||
enum vtv_priority {
|
||||
VTV_NO_PRIORITY = 0, /* i.E. Do NOT do vtable verification. */
|
||||
|
@ -5394,6 +5394,7 @@ fold_range_test (location_t loc, enum tree_code code, tree type,
|
||||
short-circuited branch and the underlying object on both sides
|
||||
is the same, make a non-short-circuit operation. */
|
||||
else if (LOGICAL_OP_NON_SHORT_CIRCUIT
|
||||
&& !flag_sanitize_coverage
|
||||
&& lhs != 0 && rhs != 0
|
||||
&& (code == TRUTH_ANDIF_EXPR
|
||||
|| code == TRUTH_ORIF_EXPR)
|
||||
@ -8047,6 +8048,7 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type,
|
||||
return tem;
|
||||
|
||||
if (LOGICAL_OP_NON_SHORT_CIRCUIT
|
||||
&& !flag_sanitize_coverage
|
||||
&& (code == TRUTH_AND_EXPR
|
||||
|| code == TRUTH_ANDIF_EXPR
|
||||
|| code == TRUTH_OR_EXPR
|
||||
|
70
gcc/opts.c
70
gcc/opts.c
@ -1526,6 +1526,17 @@ const struct sanitizer_opts_s sanitizer_opts[] =
|
||||
{ NULL, 0U, 0UL, false }
|
||||
};
|
||||
|
||||
/* -f{,no-}sanitize-coverage= suboptions. */
|
||||
const struct sanitizer_opts_s coverage_sanitizer_opts[] =
|
||||
{
|
||||
#define COVERAGE_SANITIZER_OPT(name, flags) \
|
||||
{ #name, flags, sizeof #name - 1, true }
|
||||
COVERAGE_SANITIZER_OPT (trace-pc, SANITIZE_COV_TRACE_PC),
|
||||
COVERAGE_SANITIZER_OPT (trace-cmp, SANITIZE_COV_TRACE_CMP),
|
||||
#undef COVERAGE_SANITIZER_OPT
|
||||
{ NULL, 0U, 0UL, false }
|
||||
};
|
||||
|
||||
/* A struct for describing a run of chars within a string. */
|
||||
|
||||
struct string_fragment
|
||||
@ -1556,31 +1567,34 @@ struct edit_distance_traits<const string_fragment &>
|
||||
|
||||
/* Given ARG, an unrecognized sanitizer option, return the best
|
||||
matching sanitizer option, or NULL if there isn't one.
|
||||
CODE is OPT_fsanitize_ or OPT_fsanitize_recover_.
|
||||
OPTS is array of candidate sanitizer options.
|
||||
CODE is OPT_fsanitize_, OPT_fsanitize_recover_ or
|
||||
OPT_fsanitize_coverage_.
|
||||
VALUE is non-zero for the regular form of the option, zero
|
||||
for the "no-" form (e.g. "-fno-sanitize-recover="). */
|
||||
|
||||
static const char *
|
||||
get_closest_sanitizer_option (const string_fragment &arg,
|
||||
const struct sanitizer_opts_s *opts,
|
||||
enum opt_code code, int value)
|
||||
{
|
||||
best_match <const string_fragment &, const char*> bm (arg);
|
||||
for (int i = 0; sanitizer_opts[i].name != NULL; ++i)
|
||||
for (int i = 0; opts[i].name != NULL; ++i)
|
||||
{
|
||||
/* -fsanitize=all is not valid, so don't offer it. */
|
||||
if (sanitizer_opts[i].flag == ~0U
|
||||
&& code == OPT_fsanitize_
|
||||
if (code == OPT_fsanitize_
|
||||
&& opts[i].flag == ~0U
|
||||
&& value)
|
||||
continue;
|
||||
|
||||
/* For -fsanitize-recover= (and not -fno-sanitize-recover=),
|
||||
don't offer the non-recoverable options. */
|
||||
if (!sanitizer_opts[i].can_recover
|
||||
&& code == OPT_fsanitize_recover_
|
||||
if (code == OPT_fsanitize_recover_
|
||||
&& !opts[i].can_recover
|
||||
&& value)
|
||||
continue;
|
||||
|
||||
bm.consider (sanitizer_opts[i].name);
|
||||
bm.consider (opts[i].name);
|
||||
}
|
||||
return bm.get_best_meaningful_candidate ();
|
||||
}
|
||||
@ -1594,6 +1608,13 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
|
||||
unsigned int flags, int value, bool complain)
|
||||
{
|
||||
enum opt_code code = (enum opt_code) scode;
|
||||
|
||||
const struct sanitizer_opts_s *opts;
|
||||
if (code == OPT_fsanitize_coverage_)
|
||||
opts = coverage_sanitizer_opts;
|
||||
else
|
||||
opts = sanitizer_opts;
|
||||
|
||||
while (*p != 0)
|
||||
{
|
||||
size_t len, i;
|
||||
@ -1611,12 +1632,11 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
|
||||
}
|
||||
|
||||
/* Check to see if the string matches an option class name. */
|
||||
for (i = 0; sanitizer_opts[i].name != NULL; ++i)
|
||||
if (len == sanitizer_opts[i].len
|
||||
&& memcmp (p, sanitizer_opts[i].name, len) == 0)
|
||||
for (i = 0; opts[i].name != NULL; ++i)
|
||||
if (len == opts[i].len && memcmp (p, opts[i].name, len) == 0)
|
||||
{
|
||||
/* Handle both -fsanitize and -fno-sanitize cases. */
|
||||
if (value && sanitizer_opts[i].flag == ~0U)
|
||||
if (value && opts[i].flag == ~0U)
|
||||
{
|
||||
if (code == OPT_fsanitize_)
|
||||
{
|
||||
@ -1633,14 +1653,14 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
|
||||
-fsanitize-recover=return if -fsanitize-recover=undefined
|
||||
is selected. */
|
||||
if (code == OPT_fsanitize_recover_
|
||||
&& sanitizer_opts[i].flag == SANITIZE_UNDEFINED)
|
||||
&& opts[i].flag == SANITIZE_UNDEFINED)
|
||||
flags |= (SANITIZE_UNDEFINED
|
||||
& ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN));
|
||||
else
|
||||
flags |= sanitizer_opts[i].flag;
|
||||
flags |= opts[i].flag;
|
||||
}
|
||||
else
|
||||
flags &= ~sanitizer_opts[i].flag;
|
||||
flags &= ~opts[i].flag;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -1649,21 +1669,27 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
|
||||
{
|
||||
const char *hint
|
||||
= get_closest_sanitizer_option (string_fragment (p, len),
|
||||
code, value);
|
||||
opts, code, value);
|
||||
|
||||
const char *suffix;
|
||||
if (code == OPT_fsanitize_recover_)
|
||||
suffix = "-recover";
|
||||
else if (code == OPT_fsanitize_coverage_)
|
||||
suffix = "-coverage";
|
||||
else
|
||||
suffix = "";
|
||||
|
||||
if (hint)
|
||||
error_at (loc,
|
||||
"unrecognized argument to -f%ssanitize%s= option: %q.*s;"
|
||||
" did you mean %qs?",
|
||||
value ? "" : "no-",
|
||||
code == OPT_fsanitize_ ? "" : "-recover",
|
||||
(int) len, p, hint);
|
||||
suffix, (int) len, p, hint);
|
||||
else
|
||||
error_at (loc,
|
||||
"unrecognized argument to -f%ssanitize%s= option: %q.*s",
|
||||
value ? "" : "no-",
|
||||
code == OPT_fsanitize_ ? "" : "-recover",
|
||||
(int) len, p);
|
||||
suffix, (int) len, p);
|
||||
}
|
||||
|
||||
if (comma == NULL)
|
||||
@ -1956,6 +1982,12 @@ common_handle_option (struct gcc_options *opts,
|
||||
&= ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT);
|
||||
break;
|
||||
|
||||
case OPT_fsanitize_coverage_:
|
||||
opts->x_flag_sanitize_coverage
|
||||
= parse_sanitizer_options (arg, loc, code,
|
||||
opts->x_flag_sanitize_coverage, value, true);
|
||||
break;
|
||||
|
||||
case OPT_O:
|
||||
case OPT_Os:
|
||||
case OPT_Ofast:
|
||||
|
262
gcc/sancov.c
262
gcc/sancov.c
@ -1,6 +1,7 @@
|
||||
/* Code coverage instrumentation for fuzzing.
|
||||
Copyright (C) 2015-2017 Free Software Foundation, Inc.
|
||||
Contributed by Dmitry Vyukov <dvyukov@google.com>
|
||||
Contributed by Dmitry Vyukov <dvyukov@google.com> and
|
||||
Wish Wu <wishwu007@gmail.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
@ -29,32 +30,271 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "flags.h"
|
||||
#include "stmt.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "gimple-builder.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "tree-pass.h"
|
||||
#include "tree-iterator.h"
|
||||
#include "fold-const.h"
|
||||
#include "stringpool.h"
|
||||
#include "attribs.h"
|
||||
#include "output.h"
|
||||
#include "cgraph.h"
|
||||
#include "asan.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/* Instrument one comparison operation, which compares lhs and rhs.
|
||||
Call the instrumentation function with the comparison operand.
|
||||
For integral comparisons if exactly one of the comparison operands is
|
||||
constant, call __sanitizer_cov_trace_const_cmp* instead of
|
||||
__sanitizer_cov_trace_cmp*. */
|
||||
|
||||
static void
|
||||
instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
|
||||
{
|
||||
tree type = TREE_TYPE (lhs);
|
||||
enum built_in_function fncode = END_BUILTINS;
|
||||
tree to_type = NULL_TREE;
|
||||
bool c = false;
|
||||
|
||||
if (INTEGRAL_TYPE_P (type))
|
||||
{
|
||||
c = (is_gimple_min_invariant (lhs)
|
||||
^ is_gimple_min_invariant (rhs));
|
||||
switch (int_size_in_bytes (type))
|
||||
{
|
||||
case 1:
|
||||
fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
|
||||
: BUILT_IN_SANITIZER_COV_TRACE_CMP1;
|
||||
to_type = unsigned_char_type_node;
|
||||
break;
|
||||
case 2:
|
||||
fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
|
||||
: BUILT_IN_SANITIZER_COV_TRACE_CMP2;
|
||||
to_type = uint16_type_node;
|
||||
break;
|
||||
case 4:
|
||||
fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
|
||||
: BUILT_IN_SANITIZER_COV_TRACE_CMP4;
|
||||
to_type = uint32_type_node;
|
||||
break;
|
||||
default:
|
||||
fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
|
||||
: BUILT_IN_SANITIZER_COV_TRACE_CMP8;
|
||||
to_type = uint64_type_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (SCALAR_FLOAT_TYPE_P (type))
|
||||
{
|
||||
if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
|
||||
{
|
||||
fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
|
||||
to_type = float_type_node;
|
||||
}
|
||||
else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
|
||||
{
|
||||
fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
|
||||
to_type = double_type_node;
|
||||
}
|
||||
}
|
||||
|
||||
if (to_type != NULL_TREE)
|
||||
{
|
||||
gimple_seq seq = NULL;
|
||||
|
||||
if (!useless_type_conversion_p (to_type, type))
|
||||
{
|
||||
if (TREE_CODE (lhs) == INTEGER_CST)
|
||||
lhs = fold_convert (to_type, lhs);
|
||||
else
|
||||
{
|
||||
gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
|
||||
lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
|
||||
}
|
||||
|
||||
if (TREE_CODE (rhs) == INTEGER_CST)
|
||||
rhs = fold_convert (to_type, rhs);
|
||||
else
|
||||
{
|
||||
gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
|
||||
rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
|
||||
}
|
||||
}
|
||||
|
||||
if (c && !is_gimple_min_invariant (lhs))
|
||||
std::swap (lhs, rhs);
|
||||
|
||||
tree fndecl = builtin_decl_implicit (fncode);
|
||||
gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
|
||||
gimple_seq_add_stmt (&seq, gcall);
|
||||
|
||||
gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
|
||||
gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Instrument switch statement. Call __sanitizer_cov_trace_switch with
|
||||
the value of the index and array that contains number of case values,
|
||||
the bitsize of the index and the case values converted to uint64_t. */
|
||||
|
||||
static void
|
||||
instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
|
||||
{
|
||||
gswitch *switch_stmt = as_a<gswitch *> (stmt);
|
||||
tree index = gimple_switch_index (switch_stmt);
|
||||
HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
|
||||
if (size_in_bytes == -1 || size_in_bytes > 8)
|
||||
return;
|
||||
|
||||
location_t loc = gimple_location (stmt);
|
||||
unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
|
||||
for (i = 1; i < n; ++i)
|
||||
{
|
||||
tree label = gimple_switch_label (switch_stmt, i);
|
||||
|
||||
tree low_case = CASE_LOW (label);
|
||||
if (low_case != NULL_TREE)
|
||||
num++;
|
||||
|
||||
tree high_case = CASE_HIGH (label);
|
||||
if (high_case != NULL_TREE)
|
||||
num++;
|
||||
}
|
||||
|
||||
tree case_array_type
|
||||
= build_array_type (build_type_variant (uint64_type_node, 1, 0),
|
||||
build_index_type (size_int (num + 2 - 1)));
|
||||
|
||||
char name[64];
|
||||
static size_t case_array_count = 0;
|
||||
ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
|
||||
tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
|
||||
case_array_type);
|
||||
TREE_STATIC (case_array_var) = 1;
|
||||
TREE_PUBLIC (case_array_var) = 0;
|
||||
TREE_CONSTANT (case_array_var) = 1;
|
||||
TREE_READONLY (case_array_var) = 1;
|
||||
DECL_EXTERNAL (case_array_var) = 0;
|
||||
DECL_ARTIFICIAL (case_array_var) = 1;
|
||||
DECL_IGNORED_P (case_array_var) = 1;
|
||||
|
||||
vec <constructor_elt, va_gc> *v = NULL;
|
||||
vec_alloc (v, num + 2);
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
|
||||
build_int_cst (uint64_type_node, num));
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
|
||||
build_int_cst (uint64_type_node,
|
||||
size_in_bytes * BITS_PER_UNIT));
|
||||
for (i = 1; i < n; ++i)
|
||||
{
|
||||
tree label = gimple_switch_label (switch_stmt, i);
|
||||
|
||||
tree low_case = CASE_LOW (label);
|
||||
if (low_case != NULL_TREE)
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
|
||||
fold_convert (uint64_type_node, low_case));
|
||||
|
||||
tree high_case = CASE_HIGH (label);
|
||||
if (high_case != NULL_TREE)
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
|
||||
fold_convert (uint64_type_node, high_case));
|
||||
}
|
||||
tree ctor = build_constructor (case_array_type, v);
|
||||
TREE_STATIC (ctor) = 1;
|
||||
TREE_PUBLIC (ctor) = 0;
|
||||
TREE_CONSTANT (ctor) = 1;
|
||||
TREE_READONLY (ctor) = 1;
|
||||
DECL_INITIAL (case_array_var) = ctor;
|
||||
varpool_node::finalize_decl (case_array_var);
|
||||
add_local_decl (fun, case_array_var);
|
||||
|
||||
gimple_seq seq = NULL;
|
||||
|
||||
if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
|
||||
{
|
||||
if (TREE_CODE (index) == INTEGER_CST)
|
||||
index = fold_convert (uint64_type_node, index);
|
||||
else
|
||||
{
|
||||
gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
|
||||
index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
|
||||
}
|
||||
}
|
||||
|
||||
tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
|
||||
gimple *gcall = gimple_build_call (fndecl, 2, index,
|
||||
build_fold_addr_expr (case_array_var));
|
||||
gimple_seq_add_stmt (&seq, gcall);
|
||||
|
||||
gimple_seq_set_location (seq, loc);
|
||||
gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
|
||||
}
|
||||
|
||||
unsigned
|
||||
sancov_pass (function *fun)
|
||||
{
|
||||
initialize_sanitizer_builtins ();
|
||||
|
||||
/* Insert callback into beginning of every BB. */
|
||||
tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
|
||||
basic_block bb;
|
||||
FOR_EACH_BB_FN (bb, fun)
|
||||
if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
|
||||
if (gsi_end_p (gsi))
|
||||
continue;
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
gimple *gcall = gimple_build_call (fndecl, 0);
|
||||
gimple_set_location (gcall, gimple_location (stmt));
|
||||
gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
|
||||
basic_block bb;
|
||||
tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
|
||||
FOR_EACH_BB_FN (bb, fun)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
|
||||
if (gsi_end_p (gsi))
|
||||
continue;
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
gimple *gcall = gimple_build_call (fndecl, 0);
|
||||
gimple_set_location (gcall, gimple_location (stmt));
|
||||
gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert callback into every comparison related operation. */
|
||||
if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
|
||||
{
|
||||
basic_block bb;
|
||||
FOR_EACH_BB_FN (bb, fun)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
enum tree_code rhs_code;
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
case GIMPLE_ASSIGN:
|
||||
rhs_code = gimple_assign_rhs_code (stmt);
|
||||
if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
|
||||
instrument_comparison (&gsi,
|
||||
gimple_assign_rhs1 (stmt),
|
||||
gimple_assign_rhs2 (stmt));
|
||||
else if (rhs_code == COND_EXPR
|
||||
&& COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
|
||||
{
|
||||
tree cond = gimple_assign_rhs1 (stmt);
|
||||
instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
|
||||
TREE_OPERAND (cond, 1));
|
||||
}
|
||||
break;
|
||||
case GIMPLE_COND:
|
||||
instrument_comparison (&gsi,
|
||||
gimple_cond_lhs (stmt),
|
||||
gimple_cond_rhs (stmt));
|
||||
break;
|
||||
|
||||
case GIMPLE_SWITCH:
|
||||
instrument_switch (&gsi, stmt, fun);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -537,6 +537,39 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT,
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_PC,
|
||||
"__sanitizer_cov_trace_pc",
|
||||
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP1,
|
||||
"__sanitizer_cov_trace_cmp1",
|
||||
BT_FN_VOID_UINT8_UINT8, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP2,
|
||||
"__sanitizer_cov_trace_cmp2",
|
||||
BT_FN_VOID_UINT16_UINT16, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP4,
|
||||
"__sanitizer_cov_trace_cmp4",
|
||||
BT_FN_VOID_UINT32_UINT32, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP8,
|
||||
"__sanitizer_cov_trace_cmp8",
|
||||
BT_FN_VOID_UINT64_UINT64, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1,
|
||||
"__sanitizer_cov_trace_const_cmp1",
|
||||
BT_FN_VOID_UINT8_UINT8, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2,
|
||||
"__sanitizer_cov_trace_const_cmp2",
|
||||
BT_FN_VOID_UINT16_UINT16, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4,
|
||||
"__sanitizer_cov_trace_const_cmp4",
|
||||
BT_FN_VOID_UINT32_UINT32, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8,
|
||||
"__sanitizer_cov_trace_const_cmp8",
|
||||
BT_FN_VOID_UINT64_UINT64, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMPF,
|
||||
"__sanitizer_cov_trace_cmpf",
|
||||
BT_FN_VOID_FLOAT_FLOAT, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMPD,
|
||||
"__sanitizer_cov_trace_cmpd",
|
||||
BT_FN_VOID_DOUBLE_DOUBLE, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_SWITCH,
|
||||
"__sanitizer_cov_trace_switch",
|
||||
BT_FN_VOID_UINT64_PTR, ATTR_NOTHROW_LEAF_LIST)
|
||||
|
||||
/* This has to come after all the sanitizer builtins. */
|
||||
DEF_BUILTIN_STUB(END_SANITIZER_BUILTINS, (const char *)0)
|
||||
|
@ -1,3 +1,8 @@
|
||||
2017-09-06 Wish Wu <wishwu007@gmail.com>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.dg/sancov/cmp0.c: New test.
|
||||
|
||||
2017-09-06 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* gcc.c-torture/execute/20050604-1.c: Adjust to be a better
|
||||
|
92
gcc/testsuite/gcc.dg/sancov/cmp0.c
Normal file
92
gcc/testsuite/gcc.dg/sancov/cmp0.c
Normal file
@ -0,0 +1,92 @@
|
||||
/* Basic test on number of inserted callbacks. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-fsanitize-coverage=trace-cmp -fdump-tree-optimized" } */
|
||||
|
||||
void
|
||||
foo (char *a, short *b, int *c, long long *d, float *e, double *f)
|
||||
{
|
||||
if (*a)
|
||||
*a += 1;
|
||||
if (*b)
|
||||
*b = *a;
|
||||
if (*c)
|
||||
*c += 1;
|
||||
if (*d)
|
||||
*d = *c;
|
||||
if (*e == *c)
|
||||
*e = *c;
|
||||
if (*f == *e)
|
||||
*f = *e;
|
||||
switch (*a)
|
||||
{
|
||||
case 2:
|
||||
*b += 2;
|
||||
break;
|
||||
case 3:
|
||||
*b += 3;
|
||||
break;
|
||||
case 4:
|
||||
*b += 4;
|
||||
break;
|
||||
case 5:
|
||||
*b += 5;
|
||||
break;
|
||||
case 6:
|
||||
*b += 6;
|
||||
break;
|
||||
case 7 ... 24:
|
||||
*b += 7;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (*d)
|
||||
{
|
||||
case 3:
|
||||
*d += 3;
|
||||
case -4:
|
||||
*d -= 4;
|
||||
case -5:
|
||||
*d -= 5;
|
||||
case -6:
|
||||
*d -= 6;
|
||||
case -7:
|
||||
*d -= 7;
|
||||
case -8:
|
||||
*d -= 8;
|
||||
case -9:
|
||||
*d -= 9;
|
||||
case -10:
|
||||
*d -= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bar (int *c)
|
||||
{
|
||||
if (*c == 27)
|
||||
*c += 2;
|
||||
if (*c == 37)
|
||||
*c += 2;
|
||||
}
|
||||
|
||||
int
|
||||
baz (int *c, long long d, long long e)
|
||||
{
|
||||
*c = (*c == 48) ? 12 : 24;
|
||||
return d == e;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp1 \\(0, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp2 \\(0, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp4 \\(0, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp8 \\(0, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp4 \\(27, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp4 \\(37, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp4 \\(48, " 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_cmp8 \\(" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_cmpf \\(" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_cmpd \\(" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_const_cmp" 7 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_cmp" 3 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_switch \\(" 2 "optimized" } } */
|
@ -560,7 +560,7 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
|
||||
{
|
||||
tree t1, t2;
|
||||
gimple_stmt_iterator gsi;
|
||||
if (!LOGICAL_OP_NON_SHORT_CIRCUIT)
|
||||
if (!LOGICAL_OP_NON_SHORT_CIRCUIT || flag_sanitize_coverage)
|
||||
return false;
|
||||
/* Only do this optimization if the inner bb contains only the conditional. */
|
||||
if (!gsi_one_before_end_p (gsi_start_nondebug_after_labels_bb (inner_cond_bb)))
|
||||
|
Loading…
Reference in New Issue
Block a user