From: "吴潍浠(此彼)" <weixi.wwx@antfin.com>
To: "Jakub Jelinek" <jakub@redhat.com>
Cc: "Dmitry Vyukov" <dvyukov@google.com>,
"gcc-patches" <gcc-patches@gcc.gnu.org>,
"Jeff Law" <law@redhat.com>, "wishwu007" <wishwu007@gmail.com>
Subject: Re: Add support to trace comparison instructions and switch statements
Date: Wed, 06 Sep 2017 11:47:00 -0000 [thread overview]
Message-ID: <b64d81ca-1fab-4d19-af52-be31740da539.weixi.wwx@antfin.com> (raw)
In-Reply-To: 20170905214401.GK2323@tucnak
Hi Jakub
I compiled libjpeg-turbo and libdng_sdk with options "-g -O3 -Wall -fsanitize-coverage=trace-pc,trace-cmp -fsanitize=address".
And run my fuzzer with pc and cmp feedbacks for hours. It works fine.
About __sanitizer_cov_trace_cmp{f,d} , yes, it isn't provided by llvm. But once we trace integer comparisons, why not real type comparisons.
I remember Dmitry said it is not enough useful to trace real type comparisons because it is rare to see them in programs.
But libdng_sdk really has real type comparisons. So I want to keep them and implementing __sanitizer_cov_trace_const_cmp{f,d} may be necessary.
And thanks again for your professional help.
Wish Wu
------------------------------------------------------------------
From:Jakub Jelinek <jakub@redhat.com>
Time:2017 Sep 6 (Wed) 05:44
To:Wish Wu <weixi.wwx@antfin.com>
Cc:Dmitry Vyukov <dvyukov@google.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Jeff Law <law@redhat.com>; wishwu007 <wishwu007@gmail.com>
Subject:Re: Add support to trace comparison instructions and switch statements
On Tue, Sep 05, 2017 at 09:03:52PM +0800, 吴潍浠(此彼) wrote:
> Attachment is my updated path.
> The implementation of parse_sanitizer_options is not elegance enough. Mixing handling flags of fsanitize is easy to make mistakes.
To avoid too many further iterations, I took the liberty to tweak your
patch. From https://clang.llvm.org/docs/SanitizerCoverage.html
I've noticed that since 2017-08-11 clang/llvm wants to emit
__sanitizer_cov_trace_const_cmpN with the first argument a constant
if one of the comparison operands is a constant, so the patch implements
that too.
I wonder about the __sanitizer_cov_trace_cmp{f,d} entry-points, because
I can't find them on that page nor in llvm sources.
I've also added handling of COND_EXPRs and added some documentation.
I've bootstrapped/regtested the patch on x86_64-linux and i686-linux.
Can you test it on whatever you want to use the patch for?
2017-09-05 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.
* gcc.dg/sancov/cmp0.c: New test.
--- gcc/asan.c.jj 2017-09-04 09:55:26.600687479 +0200
+++ gcc/asan.c 2017-09-05 15:39:32.452612728 +0200
@@ -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];
--- gcc/builtin-types.def.jj 2017-06-28 09:05:45.249396972 +0200
+++ gcc/builtin-types.def 2017-09-05 15:39:32.453612716 +0200
@@ -338,8 +338,20 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTRMODE_
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,
--- gcc/common.opt.jj 2017-09-01 09:26:48.441614145 +0200
+++ gcc/common.opt 2017-09-05 15:39:32.454612704 +0200
@@ -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.
--- gcc/flag-types.h.jj 2017-07-28 12:35:27.562412268 +0200
+++ gcc/flag-types.h 2017-09-05 15:39:32.454612704 +0200
@@ -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. */
--- gcc/fold-const.c.jj 2017-09-01 09:25:46.275345134 +0200
+++ gcc/fold-const.c 2017-09-05 15:39:32.457612668 +0200
@@ -5394,6 +5394,7 @@ fold_range_test (location_t loc, enum tr
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)
@@ -8035,6 +8036,7 @@ fold_truth_andor (location_t loc, enum t
return tem;
if (LOGICAL_OP_NON_SHORT_CIRCUIT
+ && !flag_sanitize_coverage
&& (code == TRUTH_AND_EXPR
|| code == TRUTH_ANDIF_EXPR
|| code == TRUTH_OR_EXPR
--- gcc/opts.c.jj 2017-09-01 09:26:28.041854018 +0200
+++ gcc/opts.c 2017-09-05 15:53:18.752765907 +0200
@@ -1526,6 +1526,17 @@ const struct sanitizer_opts_s sanitizer_
{ 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
/* 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,
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,
}
/* 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,
-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,
{
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
&= ~(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:
--- gcc/sancov.c.jj 2017-09-01 09:26:48.603612240 +0200
+++ gcc/sancov.c 2017-09-05 17:51:02.209865830 +0200
@@ -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.
#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)
- {
- 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);
+ if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
+ {
+ 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;
}
--- gcc/sanitizer.def.jj 2017-07-28 12:35:27.565412232 +0200
+++ gcc/sanitizer.def 2017-09-05 17:01:51.281308488 +0200
@@ -537,6 +537,39 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN
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)
--- gcc/tree-ssa-ifcombine.c.jj 2017-06-30 09:49:28.004662123 +0200
+++ gcc/tree-ssa-ifcombine.c 2017-09-05 15:39:32.460612633 +0200
@@ -560,7 +560,7 @@ ifcombine_ifandif (basic_block inner_con
{
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)))
--- gcc/doc/invoke.texi.jj 2017-09-04 09:55:25.000000000 +0200
+++ gcc/doc/invoke.texi 2017-09-05 18:22:02.863499354 +0200
@@ -11161,6 +11161,20 @@ is usable even in freestanding environme
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
--- gcc/testsuite/gcc.dg/sancov/cmp0.c.jj 2017-09-05 17:54:00.906717081 +0200
+++ gcc/testsuite/gcc.dg/sancov/cmp0.c 2017-09-05 18:04:15.319329045 +0200
@@ -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" } } */
Jakub
next prev parent reply other threads:[~2017-09-06 11:47 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-10 12:08 吴潍浠(此彼)
2017-07-11 12:00 ` Wish Wu
2017-07-13 8:10 ` Dmitry Vyukov via gcc-patches
2017-07-13 10:04 ` Wish Wu
2017-07-13 10:41 ` Wish Wu
2017-07-13 10:47 ` Dmitry Vyukov via gcc-patches
[not found] ` <CAN=P9pj-PUHS_UWU8cS5VLNuJrL3LSq8Wj3G+G7cr-kCNV_4jQ@mail.gmail.com>
2017-07-14 12:23 ` Dmitry Vyukov via gcc-patches
2017-07-14 21:17 ` Kostya Serebryany via gcc-patches
2017-07-15 5:41 ` Dmitry Vyukov via gcc-patches
2017-07-15 7:22 ` 吴潍浠(此彼)
2017-07-15 7:43 ` Dmitry Vyukov via gcc-patches
2017-07-14 7:37 ` Jeff Law
2017-07-21 5:38 ` 吴潍浠(此彼)
2017-07-21 13:14 ` David Edelsohn
2017-09-01 16:23 ` Jakub Jelinek
2017-09-03 8:50 ` Dmitry Vyukov via gcc-patches
2017-09-03 10:01 ` Jakub Jelinek
2017-09-03 10:19 ` Dmitry Vyukov via gcc-patches
2017-09-03 10:21 ` Dmitry Vyukov via gcc-patches
2017-09-03 10:38 ` 吴潍浠(此彼)
2017-09-03 11:05 ` Dmitry Vyukov via gcc-patches
2017-09-04 13:17 ` 吴潍浠(此彼)
2017-09-04 13:37 ` 吴潍浠(此彼)
2017-09-04 17:34 ` Jakub Jelinek
2017-09-05 13:04 ` 吴潍浠(此彼)
2017-09-05 21:44 ` Jakub Jelinek
2017-09-06 11:47 ` 吴潍浠(此彼) [this message]
2017-09-06 14:37 ` Jakub Jelinek
2017-09-06 14:38 ` Jakub Jelinek
2017-09-07 7:02 ` 吴潍浠(此彼)
2017-09-12 14:33 ` Dmitry Vyukov via gcc-patches
2017-09-12 14:50 ` Dmitry Vyukov via gcc-patches
2017-09-12 16:35 ` Kostya Serebryany via gcc-patches
[not found] ` <DB6PR0802MB23094E428EAB2B1D9206B8C3FF600@DB6PR0802MB2309.eurprd08.prod.outlook.com>
2017-09-19 13:14 ` Tamar Christina
2017-09-19 13:31 ` Martin Liška
2017-09-19 13:41 ` Tamar Christina
2017-08-05 9:53 ` 吴潍浠(此彼)
2017-08-30 22:36 ` Dmitry Vyukov via gcc-patches
2017-09-06 20:08 David Edelsohn
2017-09-06 21:24 ` Jakub Jelinek
2017-09-07 16:58 ` Rainer Orth
2017-09-07 20:17 ` David Edelsohn
2017-09-08 8:38 ` Rainer Orth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b64d81ca-1fab-4d19-af52-be31740da539.weixi.wwx@antfin.com \
--to=weixi.wwx@antfin.com \
--cc=dvyukov@google.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=law@redhat.com \
--cc=wishwu007@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).