asan.c (initialize_sanitizer_builtins): Add BT_FN_VOID_UINT8_UINT8...
authorWish Wu <wishwu007@gmail.com>
Wed, 6 Sep 2017 14:30:46 +0000 (14:30 +0000)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 6 Sep 2017 14:30:46 +0000 (16:30 +0200)
* 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

13 files changed:
gcc/ChangeLog
gcc/asan.c
gcc/builtin-types.def
gcc/common.opt
gcc/doc/invoke.texi
gcc/flag-types.h
gcc/fold-const.c
gcc/opts.c
gcc/sancov.c
gcc/sanitizer.def
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/sancov/cmp0.c [new file with mode: 0644]
gcc/tree-ssa-ifcombine.c

index 69713c188dab4eff8dea0d391de3b9c388298ccf..c8851e6cb07caf4421dcc0875e95af2dc5360ac5 100644 (file)
@@ -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
index bebacd6c390c422980c3db30ceeea0f0d3af2066..2aa0a795af2016140b9fb743ea66c8f29f60556c 100644 (file)
@@ -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];
index a0d7d40ac36a0778cd537f6577ed5cb5b5a49da4..1894603350280c738b14d3bab9570105647516c4 100644 (file)
@@ -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,
index 1331008f81107a13371da3d70cf71c4eb6231e1e..0873fb9436fff16602f4d5650627529c58af24bd 100644 (file)
@@ -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.
index ed438d4bfc8058616c3278c426f3ce4e02052ebc..88edc937d862e959883c7f2d08cd833469c347c4 100644 (file)
@@ -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
index 6372d3cb1783d324e1ace4dbe6591edb15fceb9d..4938f69b1b6f5adad96243c8f2f1d454949bd201 100644 (file)
@@ -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. */
index 0cb2301a518d2fa3f2b6cc84f6d9f3a8a9841406..16bf45694bfe5e301caa527542d861be49c0647d 100644 (file)
@@ -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
index a7f926b587fb3b60b7570639562cd5fa60c524af..5aa5d066dbe29efd284cca231867021f0da4b0d1 100644 (file)
@@ -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:
index b19de8bbbc5fc99416b4440c98dca0e9a3dfc8ea..2f8d5681e4f18028b738af5fbfaa6d49033359de 100644 (file)
@@ -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;
 }
index c90fa94c4a9b9f6a1533709437c57ca0fc97c32f..9d963f05c21d67d667c653344740fac7cd096357 100644 (file)
@@ -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)
index 0c8f4798d8c191fa9105a8a7b071d9b13fe9b008..cd283c0a4093cc89df44ff4a5924f8016e6f3435 100644 (file)
@@ -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
diff --git a/gcc/testsuite/gcc.dg/sancov/cmp0.c b/gcc/testsuite/gcc.dg/sancov/cmp0.c
new file mode 100644 (file)
index 0000000..3a17de9
--- /dev/null
@@ -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" } } */
index c564ea104bce63f3a112ba2ef81d4d09ca0b8c57..a211335889b1d4c1fce2fa3c0e37f3f3c30f103d 100644 (file)
@@ -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)))