This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Add fuzzing coverage support
- From: Dmitry Vyukov <dvyukov at google dot com>
- To: Bernd Schmidt <bschmidt at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, Jakub Jelinek <jakub at redhat dot com>, Yuri Gribov <tetra2005 at gmail dot com>, Kostya Serebryany <kcc at google dot com>, Alexander Potapenko <glider at google dot com>, Andrey Ryabinin <ryabinin dot a dot a at gmail dot com>, Jiri Slaby <jslaby at suse dot cz>, Quentin Casasnovas <quentin dot casasnovas at oracle dot com>, Sasha Levin <sasha dot levin at oracle dot com>, syzkaller <syzkaller at googlegroups dot com>
- Date: Wed, 2 Dec 2015 17:55:29 +0100
- Subject: Re: Add fuzzing coverage support
- Authentication-results: sourceware.org; auth=none
- References: <CACT4Y+ZW4oRSD0TpEubnZjHmLsgVy_A4MQvUxZHWYgxxj_CCcA at mail dot gmail dot com> <CACT4Y+YB5N-wi7U=HiLJgpBMt5fnZ1F5k4mKUy1TY-fd_ji81Q at mail dot gmail dot com> <CACT4Y+biFo__boRhvyoVh03s-psybWzo4bqhOPbXzY7wwY-2Xw at mail dot gmail dot com> <565F20BA dot 7040108 at redhat dot com>
On Wed, Dec 2, 2015 at 5:47 PM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 12/02/2015 05:10 PM, Dmitry Vyukov wrote:
>>
>> ping
>
>
> I do not see the original submission in my archives.
That's strange. I don't see it in gcc-patches archives as well.
The original email contained a plain-text patch attachment. Attaching it again.
> This one comes too late
> to make it into gcc-6. I can make some initial comments.
>
>>>> This patch adds support for coverage-guided fuzzing:
>>>> https://codereview.appspot.com/280140043
>
>
> Please send patches with the mail (the best method is usually a text/plain
> attachment) so that they can be quoted.
>
> From what I can tell this is relatively straight-forward. You'll want to fix
> a number of issues with coding style (formatting, and lack of function
> comments).
>
> There's no documentation in invoke.texi.
Will fix.
Can you point to some concrete coding style violations (besides
function comments)?
> We seem to have no established process for deciding whether we want a new
> feature. I am not sure how to approach such a question, and it comes up
> quite often. Somehow the default answer usually seems to be to accept
> anything.
Index: ChangeLog
===================================================================
--- ChangeLog (revision 231000)
+++ ChangeLog (working copy)
@@ -1,3 +1,13 @@
+2015-11-27 Dmitry Vyukov <dvyukov@google.com>
+
+ * sancov.c: add file.
+ * Makefile.in: add sancov.c.
+ * passes.def: add sancov pass.
+ * tree-pass.h: add sancov pass.
+ * common.opt: add -fsanitize-coverage=trace-pc flag.
+ * sanitizer.def: add __sanitizer_cov_trace_pc builtin.
+ * builtins.def: enable sanitizer builtins when coverage is enabled.
+
2015-11-27 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/68552
Index: Makefile.in
===================================================================
--- Makefile.in (revision 231000)
+++ Makefile.in (working copy)
@@ -1426,6 +1426,7 @@
tsan.o \
ubsan.o \
sanopt.o \
+ sancov.o \
tree-call-cdce.o \
tree-cfg.o \
tree-cfgcleanup.o \
@@ -2399,6 +2400,7 @@
$(srcdir)/ubsan.c \
$(srcdir)/tsan.c \
$(srcdir)/sanopt.c \
+ $(srcdir)/sancov.c \
$(srcdir)/ipa-devirt.c \
$(srcdir)/internal-fn.h \
@all_gtfiles@
Index: builtins.def
===================================================================
--- builtins.def (revision 231000)
+++ builtins.def (working copy)
@@ -210,7 +210,8 @@
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
true, true, true, ATTRS, true, \
(flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
- | SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT)))
+ | SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT) \
+ || flag_sanitize_coverage))
#undef DEF_CILKPLUS_BUILTIN
#define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
Index: common.opt
===================================================================
--- common.opt (revision 231000)
+++ common.opt (working copy)
@@ -225,6 +225,11 @@
Variable
unsigned int flag_sanitize_recover = SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT | SANITIZE_KERNEL_ADDRESS
+fsanitize-coverage=trace-pc
+Common Report Var(flag_sanitize_coverage)
+Enable coverage-guided fuzzing support.
+Inserts call to __sanitizer_cov_trace_pc into every basic block.
+
; Flag whether a prefix has been added to dump_base_name
Variable
bool dump_base_name_prefixed = false
Index: passes.def
===================================================================
--- passes.def (revision 231000)
+++ passes.def (working copy)
@@ -237,6 +237,7 @@
NEXT_PASS (pass_split_crit_edges);
NEXT_PASS (pass_pre);
NEXT_PASS (pass_sink_code);
+ NEXT_PASS (pass_sancov);
NEXT_PASS (pass_asan);
NEXT_PASS (pass_tsan);
/* Pass group that runs when 1) enabled, 2) there are loops
@@ -346,6 +347,7 @@
to forward object-size and builtin folding results properly. */
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_dce);
+ NEXT_PASS (pass_sancov);
NEXT_PASS (pass_asan);
NEXT_PASS (pass_tsan);
/* ??? We do want some kind of loop invariant motion, but we possibly
@@ -369,6 +371,7 @@
NEXT_PASS (pass_lower_vaarg);
NEXT_PASS (pass_lower_vector);
NEXT_PASS (pass_lower_complex_O0);
+ NEXT_PASS (pass_sancov_O0);
NEXT_PASS (pass_asan_O0);
NEXT_PASS (pass_tsan_O0);
NEXT_PASS (pass_sanopt);
Index: sancov.c
===================================================================
--- sancov.c (revision 0)
+++ sancov.c (working copy)
@@ -0,0 +1,116 @@
+/* Code coverage instrumentation for fuzzing.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ Contributed by Dmitry Vyukov <dvyukov@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "basic-block.h"
+#include "options.h"
+#include "flags.h"
+#include "stmt.h"
+#include "gimple-iterator.h"
+#include "tree-cfg.h"
+#include "tree-pass.h"
+#include "tree-iterator.h"
+#include "asan.h"
+
+namespace {
+
+unsigned sancov_pass (function *fun)
+{
+ basic_block bb;
+ gimple_stmt_iterator gsi;
+ gimple *stmt, *f;
+ static bool inited;
+
+ if (!inited)
+ {
+ inited = true;
+ initialize_sanitizer_builtins ();
+ }
+
+ /* Insert callback into beginning of every BB. */
+ FOR_EACH_BB_FN (bb, fun)
+ {
+ gsi = gsi_start_bb (bb);
+ stmt = gsi_stmt (gsi);
+ while (stmt && dyn_cast <glabel *> (stmt))
+ {
+ gsi_next (&gsi);
+ stmt = gsi_stmt (gsi);
+ }
+ if (!stmt)
+ continue;
+ f = gimple_build_call (builtin_decl_implicit (BUILT_IN_SANCOV_TRACE), 0);
+ gimple_set_location (f, gimple_location (stmt));
+ gsi_insert_before (&gsi, f, GSI_SAME_STMT);
+ }
+ return 0;
+}
+
+template<bool O0>
+class pass_sancov : public gimple_opt_pass
+{
+public:
+ static pass_data pd ()
+ {
+ static const pass_data data =
+ {
+ GIMPLE_PASS, /* type */
+ O0 ? "sancov_O0" : "sancov", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ ( PROP_cfg ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa, /* todo_flags_finish */
+ };
+ return data;
+ }
+
+ pass_sancov (gcc::context *ctxt)
+ : gimple_opt_pass (pd(), ctxt)
+ {}
+
+ opt_pass * clone () { return new pass_sancov<O0> (m_ctxt); }
+ virtual bool gate (function *)
+ {
+ return flag_sanitize_coverage && (!O0 || !optimize);
+ }
+ virtual unsigned int execute (function *fun) { return sancov_pass (fun); }
+}; // class pass_sancov
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_sancov (gcc::context *ctxt)
+{
+ return new pass_sancov<false> (ctxt);
+}
+
+gimple_opt_pass *
+make_pass_sancov_O0 (gcc::context *ctxt)
+{
+ return new pass_sancov<true> (ctxt);
+}
Index: sanitizer.def
===================================================================
--- sanitizer.def (revision 231000)
+++ sanitizer.def (working copy)
@@ -510,3 +510,7 @@
"__ubsan_handle_dynamic_type_cache_miss_abort",
BT_FN_VOID_PTR_PTR_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST)
+
+/* Sanitizer coverage */
+DEF_SANITIZER_BUILTIN(BUILT_IN_SANCOV_TRACE, "__sanitizer_cov_trace_pc",
+ BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
Index: testsuite/gcc.dg/sancov/asan.c
===================================================================
--- testsuite/gcc.dg/sancov/asan.c (revision 0)
+++ testsuite/gcc.dg/sancov/asan.c (working copy)
@@ -0,0 +1,21 @@
+/* Test coverage/asan interaction:
+ - coverage instruments __asan_init ctor (thus 4 covarage callbacks)
+ - coverage does not instrument asan-emitted basic blocks
+ - asan considers coverage callback as "nonfreeing" (thus 1 asan store
+ callback. */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize-coverage=trace-pc -fsanitize=address" } */
+
+void notailcall ();
+
+void foo(volatile int *a, int *b)
+{
+ *a = 1;
+ if (*b)
+ *a = 2;
+ notailcall ();
+}
+
+/* { dg-final { scan-assembler-times "call __sanitizer_cov_trace_pc" 4 } } */
+/* { dg-final { scan-assembler-times "call __asan_report_load4" 1 } } */
+/* { dg-final { scan-assembler-times "call __asan_report_store4" 1 } } */
Index: testsuite/gcc.dg/sancov/basic0.c
===================================================================
--- testsuite/gcc.dg/sancov/basic0.c (revision 0)
+++ testsuite/gcc.dg/sancov/basic0.c (working copy)
@@ -0,0 +1,12 @@
+/* Basic test on number of inserted callbacks. */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize-coverage=trace-pc" } */
+
+void notailcall ();
+
+void foo(void)
+{
+ notailcall ();
+}
+
+/* { dg-final { scan-assembler-times "call __sanitizer_cov_trace_pc" 1 } } */
Index: testsuite/gcc.dg/sancov/basic1.c
===================================================================
--- testsuite/gcc.dg/sancov/basic1.c (revision 0)
+++ testsuite/gcc.dg/sancov/basic1.c (working copy)
@@ -0,0 +1,15 @@
+/* Basic test on number of inserted callbacks. */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize-coverage=trace-pc" } */
+
+void notailcall ();
+
+void foo (int *a, int *b, int *c)
+{
+ *a = 1;
+ if (*b)
+ *c = 2;
+ notailcall ();
+}
+
+/* { dg-final { scan-assembler-times "call __sanitizer_cov_trace_pc" 3 } } */
Index: testsuite/gcc.dg/sancov/basic2.c
===================================================================
--- testsuite/gcc.dg/sancov/basic2.c (revision 0)
+++ testsuite/gcc.dg/sancov/basic2.c (working copy)
@@ -0,0 +1,17 @@
+/* Basic test on number of inserted callbacks. */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize-coverage=trace-pc" } */
+
+void notailcall ();
+
+void foo(int *a, int *b, int *c, int *d)
+{
+ *a = 1;
+ if (*b)
+ *c = 2;
+ else
+ *d = 3;
+ notailcall ();
+}
+
+/* { dg-final { scan-assembler-times "call __sanitizer_cov_trace_pc" 4 } } */
Index: testsuite/gcc.dg/sancov/sancov.exp
===================================================================
--- testsuite/gcc.dg/sancov/sancov.exp (revision 0)
+++ testsuite/gcc.dg/sancov/sancov.exp (working copy)
@@ -0,0 +1,37 @@
+# Copyright (C) 2015 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+load_lib torture-options.exp
+
+dg-init
+torture-init
+set-torture-options [list \
+ { -O0 } \
+ { -O1 } \
+ { -O2 } \
+ { -O3 } \
+ { -O0 -g } \
+ { -O1 -g } \
+ { -O2 -g } \
+ { -O3 -g } ]
+
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] "" ""
+
+torture-finish
+dg-finish
Index: tree-pass.h
===================================================================
--- tree-pass.h (revision 231000)
+++ tree-pass.h (working copy)
@@ -351,6 +351,8 @@
extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_sancov_O0 (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_cf (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_refactor_eh (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_eh (gcc::context *ctxt);