From patchwork Fri Dec 4 17:32:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Vyukov X-Patchwork-Id: 552827 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 57328140213 for ; Sat, 5 Dec 2015 04:33:13 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=tFUWYvxZ; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:in-reply-to:references:from:date:message-id :subject:to:cc:content-type; q=dns; s=default; b=hWCnqRsQ7R09+Km 7zv8zLOu9ok1FNb1hKZQCrS2PwoiNA9/cX/Oyi3dBo98xrkrWJIeAcgu3w4jAT2q YzRD1sQebeZQLWgS2nxTptFcytdODTQZggVsSMheY0sVjqfSvvLEbOoLGVKIhzaS dxOG3ytVfHEKhdI5vFSeiEOowNYI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:in-reply-to:references:from:date:message-id :subject:to:cc:content-type; s=default; bh=4Xp6JMKeiXN+PJMDPHfCU yFcKu8=; b=tFUWYvxZURIO+uAF1y5arTnnFimQNPSXZbNRo+5B79Iin1/Y/7ywT ZvAbHWBrHEU7iNU1Z+//vL19Z6riDP9ix2dr3kTATpMlxGMxoNhOHtvcyzpO1aLk CXedgZzikU4WZmuv37zZjWk+HBAnaXMtbeg4iWYF8IR1HnbSvazBC0= Received: (qmail 4395 invoked by alias); 4 Dec 2015 17:33:05 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 4363 invoked by uid 89); 4 Dec 2015 17:33:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: Yes, score=6.3 required=5.0 tests=AWL, BAYES_99, BAYES_999, KAM_ASCII_DIVIDERS, RAZOR2_CF_RANGE_51_100, RAZOR2_CF_RANGE_E8_51_100, RAZOR2_CHECK, RCVD_IN_DNSWL_LOW, SEM_URI, SEM_URIRED, SPF_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mail-wm0-f48.google.com Received: from mail-wm0-f48.google.com (HELO mail-wm0-f48.google.com) (74.125.82.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Fri, 04 Dec 2015 17:33:01 +0000 Received: by wmuu63 with SMTP id u63so71014328wmu.0 for ; Fri, 04 Dec 2015 09:32:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-type; bh=4+dgnIPjihvxvNSrFVglen0GjHkXGKZ2qrI8x4SSB7M=; b=fQqYZokzwzJjJ7x0GUbq0tpWk3IXplW0er1vrzjAH1ZpS1yUjcU5CdBV4ZtbhW3ipk Kdttg9UYJ+Z6HzdVauhoodRloY6J5Ai18TR5KQrYxEI1qbGA/dqpZq35LQ6XeoJuAS7K CtjIl9qaQ1hHFI2Byv6zN5D7Fc1bky+RhqngPAaePhYJtw0XuzYjO++ZYBsT/Mh4ByZE 0GSoqnuz2dZ/0ekzOf9eIRk+MZBaCCWb14916UQAL0kBQn5a2C6cfTuSUimDz65YHfC6 1A3/ChQaYLq3bMNf7D3NJ34vOglPey3P5euesqLqeUyJXKnf+S78Jbmxh/tzrekkyvh7 bceA== X-Gm-Message-State: ALoCoQkiBhBOLuS5L87e7yrcEKpN223cbAoQeKq+YQi7gQ83bKdLpiRLXBb/uxKmlGbMyr1Yq77Q X-Received: by 10.28.54.165 with SMTP id y37mr6885570wmh.55.1449250378119; Fri, 04 Dec 2015 09:32:58 -0800 (PST) MIME-Version: 1.0 Received: by 10.194.0.238 with HTTP; Fri, 4 Dec 2015 09:32:38 -0800 (PST) In-Reply-To: <20151204134118.GM5675@tucnak.redhat.com> References: <565F20BA.7040108@redhat.com> <565F2641.2040703@redhat.com> <56602BF9.40306@redhat.com> <20151204134118.GM5675@tucnak.redhat.com> From: Dmitry Vyukov Date: Fri, 4 Dec 2015 18:32:38 +0100 Message-ID: Subject: Re: Add fuzzing coverage support To: Jakub Jelinek Cc: Bernd Schmidt , GCC Patches , Yuri Gribov , Kostya Serebryany , Alexander Potapenko , Andrey Ryabinin , Jiri Slaby , Quentin Casasnovas , Sasha Levin , syzkaller X-IsSubscribed: yes On Fri, Dec 4, 2015 at 2:41 PM, Jakub Jelinek wrote: > Hi! > > While this has been posted after stage1 closed and I'm not really happy > that it missed the deadline, I'm willing to grant an exception, the patch > is small enough that it is ok at this point of stage3. That said, next time > please try to submit new features in time. Sorry. Thanks! > Are there any plans for GCC 7 for the other -fsanitize-coverage= options, > or are those just LLVM alternatives to GCC's gcov/-fprofile-generate etc.? No, they are not alternatives to gcov. Other coverage modes are backed by sanitizer_common runtime and libFuzzer, which together allow to do efficient in-process fuzzing. We don't have plans to port other options at the moment per se. Though, that's doable and we could sync sanitizer library for runtime support. > On Thu, Dec 03, 2015 at 08:17:06PM +0100, Dmitry Vyukov wrote: >> +unsigned sancov_pass (function *fun) > > Formatting: > unsigned > sancov_pass (function *fun) Missed this. Done. >> +{ >> + basic_block bb; >> + gimple_stmt_iterator gsi; >> + gimple *stmt, *f; >> + static bool inited; >> + >> + if (!inited) >> + { >> + inited = true; >> + initialize_sanitizer_builtins (); >> + } > > You can call this unconditionally, it will return as the first thing > if it is already initialized, no need for another guard. Done >> + >> + /* Insert callback into beginning of every BB. */ >> + FOR_EACH_BB_FN (bb, fun) >> + { >> + gsi = gsi_after_labels (bb); >> + if (gsi_end_p (gsi)) >> + continue; >> + stmt = gsi_stmt (gsi); >> + f = gimple_build_call (builtin_decl_implicit ( >> + BUILT_IN_SANITIZER_COV_TRACE_PC), 0); > > I (personally) prefer no ( at the end of line unless really needed. > In this case you can just do: > tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC); > gimple *g = gimple_build_call (fndecl, 0); > which is same number of lines, but looks nicer. > Also, please move also the gsi, stmt and f (better g or gcall) > declarations to the first assignment to them, they aren't used outside of > the loop. Done >> --- 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 } } */ > > I don't like these, we have lots of targets, and different targets have > different instructions for making calls, different whitespace in between > the insn name and called function, sometimes some extra decoration on the fn > name, (say sometimes an extra _ prefix), etc. IMHO much better to add > -fdump-tree-optimized and scan-tree-dump-times instead for the calls in the > optimized dump. Affects all tests. Done Much better now. > Please repost a patch with these changes fixed, it will be hopefully ackable > then. New patch is attached. Code review is updated: https://codereview.appspot.com/280140043 Test are passing. Also compiled and booted kernel with this. Also applied clang-format to sancov.c. Please take another look. Index: ChangeLog =================================================================== --- ChangeLog (revision 231277) +++ ChangeLog (working copy) @@ -1,3 +1,15 @@ +2015-12-04 Dmitry Vyukov + + * sancov.c: New file. + * Makefile.in (OBJS): Add sancov.o. + * invoke.texi (-fsanitize-coverage=trace-pc): Describe. + * passes.def (sancov_pass): Add. + * tree-pass.h (sancov_pass): Add. + * common.opt (-fsanitize-coverage=trace-pc): Add. + * sanitizer.def (BUILT_IN_SANITIZER_COV_TRACE_PC): Add. + * builtins.def (DEF_SANITIZER_BUILTIN): Enable for + flag_sanitize_coverage. + 2015-12-04 Jeff Law * tree-ssa-reassoc.c (maybe_optimize_range_tests): Return boolean @@ -593,7 +605,6 @@ * tree-ssa-structalias.c (find_func_aliases_for_builtin_call) (find_func_clobbers, ipa_pta_execute): Handle BUILT_IN_GOACC_PARALLEL. ->>>>>>> .r231221 2015-12-02 Segher Boessenkool * config/rs6000/rs6000.md (cstore_si_as_di): New expander. Index: Makefile.in =================================================================== --- Makefile.in (revision 231277) +++ Makefile.in (working copy) @@ -1427,6 +1427,7 @@ tsan.o \ ubsan.o \ sanopt.o \ + sancov.o \ tree-call-cdce.o \ tree-cfg.o \ tree-cfgcleanup.o \ @@ -2400,6 +2401,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 231277) +++ 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 231277) +++ 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 code instrumentation. +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: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 231277) +++ doc/invoke.texi (working copy) @@ -6135,6 +6135,11 @@ @code{libubsan} library is not needed and is not linked in, so this is usable even in freestanding environments. +@item -fsanitize-coverage=trace-pc +@opindex fsanitize-coverage=trace-pc +Enable coverage-guided fuzzing code instrumentation. +Inserts call to __sanitizer_cov_trace_pc into every basic block. + @item -fcheck-pointer-bounds @opindex fcheck-pointer-bounds @opindex fno-check-pointer-bounds Index: passes.def =================================================================== --- passes.def (revision 231277) +++ 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,108 @@ +/* Code coverage instrumentation for fuzzing. + Copyright (C) 2015 Free Software Foundation, Inc. + Contributed by Dmitry Vyukov + +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 +. */ + +#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) +{ + 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_after_labels (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); + } + return 0; +} + +template class pass_sancov : public gimple_opt_pass +{ +public: + pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {} + + static const pass_data data; + opt_pass * + clone () + { + return new pass_sancov (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 + +template +const pass_data pass_sancov::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 */ +}; + +} // anon namespace + +gimple_opt_pass * +make_pass_sancov (gcc::context *ctxt) +{ + return new pass_sancov (ctxt); +} + +gimple_opt_pass * +make_pass_sancov_O0 (gcc::context *ctxt) +{ + return new pass_sancov (ctxt); +} Index: sanitizer.def =================================================================== --- sanitizer.def (revision 231277) +++ sanitizer.def (working copy) @@ -510,3 +510,8 @@ "__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_SANITIZER_COV_TRACE_PC, + "__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,18 @@ +/* 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 -fdump-tree-optimized" } */ + +void foo(volatile int *a, int *b) +{ + *a = 1; + if (*b) + *a = 2; +} + +/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_pc \\(\\)" 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4 \\(" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store4 \\(" 1 "optimized" } } */ 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,9 @@ +/* Basic test on number of inserted callbacks. */ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-coverage=trace-pc -fdump-tree-optimized" } */ + +void foo(void) +{ +} + +/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_pc \\(\\)" 1 "optimized" } } */ 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,12 @@ +/* Basic test on number of inserted callbacks. */ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-coverage=trace-pc -fdump-tree-optimized" } */ + +void foo (int *a, int *b, int *c) +{ + *a = 1; + if (*b) + *c = 2; +} + +/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_pc \\(\\)" 3 "optimized" } } */ 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,14 @@ +/* Basic test on number of inserted callbacks. */ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-coverage=trace-pc -fdump-tree-optimized" } */ + +void foo(int *a, int *b, int *c, int *d) +{ + *a = 1; + if (*b) + *c = 2; + else + *d = 3; +} + +/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_pc \\(\\)" 4 "optimized" } } */ 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 +# . + +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 231277) +++ 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);