From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 70433 invoked by alias); 14 Jul 2017 12:23:48 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 69469 invoked by uid 89); 14 Jul 2017 12:23:47 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.6 required=5.0 tests=AWL,BAYES_00,BODY_8BITS,GARBLED_BODY,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,RCVD_IN_DNSWL_NONE,RCVD_IN_SORBS_SPAM,RP_MATCHES_RCVD,SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mail-oi0-f50.google.com Received: from mail-oi0-f50.google.com (HELO mail-oi0-f50.google.com) (209.85.218.50) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 14 Jul 2017 12:23:43 +0000 Received: by mail-oi0-f50.google.com with SMTP id x187so69748806oig.3 for ; Fri, 14 Jul 2017 05:23:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=OmMkTvWdH9zlqpGMT1/O42fm/JiJPPNErl3HOBySm+E=; b=J7vePjaqHHsh7WkF/9Mcj1QYa6/HaWeZBw8/HEV9UEilm8wDbfnCg9EIfYY2QWuRa3 SBpOlcnj489JgWe/Oe8Jv4NBFR6gN7k6ho4Zks8wpHM3EkuQVABZciDwryanYxjzfUxw /yq3RtPH7AVNMZSCkLdPnji2pQhxkiloOR0J1wo9oJMCGq/ThY2x/boTo0hOQjGbosQM JesA8wolBe0vNvDP+eNQZ0MI3PyTR1m5p1LAJO3OjWLjVI3SFDj227Y2RzKnhw7plKzD EwJzDEQBa5p5CLjUv/v8GqDeXYEd10qpZ4h1/cwUYIu4eGFkxRNo+sF8s6OaL3w5QhVT tYoQ== X-Gm-Message-State: AIVw113lgJTa3razHMuWJHTiE8WvF9cQbG4cU1qhtJxfgl2ft6XVqE+V aNDdKkPCkU2HU00X+maQsRUiw+kPC/Aw X-Received: by 10.202.81.138 with SMTP id f132mr6110805oib.94.1500035020976; Fri, 14 Jul 2017 05:23:40 -0700 (PDT) MIME-Version: 1.0 Received: by 10.74.64.65 with HTTP; Fri, 14 Jul 2017 05:23:20 -0700 (PDT) In-Reply-To: References: <234840fd-a06a-4dfd-a1c5-254e26144754.weixi.wwx@antfin.com> From: "Dmitry Vyukov via gcc-patches" Reply-To: Dmitry Vyukov Date: Fri, 14 Jul 2017 12:23:00 -0000 Message-ID: Subject: Re: Add support to trace comparison instructions and switch statements To: Kostya Serebryany Cc: Wish Wu , gcc , gcc-patches , weixi.wwx@antfin.com, Alexander Potapenko , andreyknvl , Victor Chibotaru , Yuri Gribov Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2017-07/txt/msg00820.txt.bz2 On Thu, Jul 13, 2017 at 11:18 PM, Kostya Serebryany wrote: >> > Hi >> > >> > I wrote a test for "-fsanitize-coverage=3Dtrace-cmp" . >> > >> > Is there anybody tells me if these codes could be merged into gcc ? >> >> >> Nice! >> >> We are currently working on Linux kernel fuzzing that use the >> comparison tracing. We use clang at the moment, but having this >> support in gcc would be great for kernel land. >> >> One concern I have: do we want to do some final refinements to the API >> before we implement this in both compilers? >> >> 2 things we considered from our perspective: >> - communicating to the runtime which operands are constants >> - communicating to the runtime which comparisons are counting loop chec= ks >> >> First is useful if you do "find one operand in input and replace with >> the other one" thing. Second is useful because counting loop checks >> are usually not useful (at least all but one). >> In the original Go implementation I also conveyed signedness of >> operands, exact comparison operation (<, >, etc): >> https://github.com/dvyukov/go-fuzz/blob/master/go-fuzz-defs/defs.go#L13 >> But I did not find any use for that. >> I also gave all comparisons unique IDs: >> https://github.com/dvyukov/go-fuzz/blob/master/go-fuzz-dep/sonar.go#L24 >> That turned out to be useful. And there are chances we will want this >> for C/C++ as well. >> >> Kostya, did anything like this pop up in your work on libfuzzer? >> Can we still change the clang API? At least add an additional argument >> to the callbacks? > > > I'd prefer not to change the API, but extend it (new compiler flag, new > callbacks), if absolutely needed. > Probably make it trace-cmp-guard (similar to trace-pc-guard, with an extra > parameter that has the ID). > I don't like the approach with compiler-generated constant IDs. Yes, if we do it for C/C++, we need to create globals and pass pointer to a global to the callbacks. IDs do not work for C/C++. > Yes, it's a bit more efficient, but much less flexible in presence of > multiple modules, DSOs, dlopen, etc. > > I was also looking at completely inlining this instrumentation because it= 's > pretty expensive even in it's current form > (adding more parameters will make things worse). > This is going to be much less flexible, of course, so I'll attack it only > once I settle on the algorithm to handle CMPs in libFuzzer. This will require a new, completely different API for compiler<->runtime anyway, so we can put this aside for now. >> At the very least I would suggest that we add an additional arg that >> contains some flags (1/2 arg is a const, this is counting loop check, >> etc). If we do that we can also have just 1 callback that accepts >> uint64's for args because we can pass operand size in the flags: > > > How many flag combinations do we need and do we *really* need them? > > If the number of flag combinations is small, I'd prefer to have separate > callbacks (__sanitizer_cov_trace_cmp_loop_bound ?) > > Do we really need to know that one arg is a const? > It could well be a constant in fact, but compiler won't see it. > > int foo(int n) { ... if (i < n) ... } > ... > foo(42); // not inlined. > > We need to handle both cases the same way. Well, following this line of reasoning we would need only __asan_load/storeN callbacks for asan and remove __asan_load/store1/2/4/8, because compiler might not know the size at compile time. Constant-ness is only an optimization. If compiler does not know that something is a const, fine. Based on my experience with go-fuzz and our early experience with kernel, we badly need const hint. Otherwise fuzzer generates gazillions of candidates based on comparison arguments. Note that kernel is several order of magnitude larger than what people usually fuzz in user-space, inputs are more complex and at the same time execution speed is several order of magnitude lower. We can't rely on raw speed. Thinking of this more, I don't thing that globals will be useful in the kernel context (the main problem is that we have multiple transient isolated kernels). If we track per-comparison site information, we will probably use PCs. So I am ready to give up on this. Both of you expressed concerns about performance. Kostya says we should not break existing clang API. If we limit this to only constant-ness, then I think we can make this both forward and backward compatible, which means we don't need to handle it now. E.g. we can: - if both operands are const (if it's possible at all), don't emit any cal= lback - if only one is const, emit __sanitizer_cov_trace_cmp_const1 and pass the const in a known position (i.e. always first/second arg) - if none are const, emit callback __sanitizer_cov_trace_cmp_dyn1 Then compiler emits weak aliases form __sanitizer_cov_trace_cmp_const/dyn1 to the old __sanitizer_cov_trace_cmp1, which makes it backwards compatible. New runtimes that implement __sanitizer_cov_trace_cmp_const/dyn1, also need to provide the old __sanitizer_cov_trace_cmp1 for old compilers. Similarly for counting loops, we can emit a new callback and provide a weak alias to the old callback. No performance hit. Works both ways. So let's proceed with the current implementation. >> void __sanitizer_cov_trace_cmp(uint64 arg1, uint64 arg2, uint64 flags); >> >> But I wonder if 3 uint64 args will be too inefficient for 32 bit archs?.= .. >> >> If we create a global per comparison then we could put the flags into >> the global: >> >> void __sanitizer_cov_trace_cmp(uint64 arg1, uint64 arg2, something_t >> *global); >> >> Thoughts? >> >> >> >> >> > Index: gcc/testsuite/gcc.dg/sancov/basic3.c >> > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> > --- gcc/testsuite/gcc.dg/sancov/basic3.c (nonexistent) >> > +++ gcc/testsuite/gcc.dg/sancov/basic3.c (working copy) >> > @@ -0,0 +1,42 @@ >> > +/* Basic test on number of inserted callbacks. */ >> > +/* { dg-do compile } */ >> > +/* { dg-options "-fsanitize-coverage=3Dtrace-cmp -fdump-tree-optimize= d" } >> > */ >> > + >> > +void foo(char *a, short *b, int *c, long long *d, float *e, double *f) >> > +{ >> > + if (*a) >> > + *a +=3D 1; >> > + if (*b) >> > + *b =3D *a; >> > + if (*c) >> > + *c +=3D 1; >> > + if(*d) >> > + *d =3D *c; >> > + if(*e =3D=3D *c) >> > + *e =3D *c; >> > + if(*f =3D=3D *e) >> > + *f =3D *e; >> > + switch(*a) >> > + { >> > + case 2: >> > + *b +=3D 2; >> > + break; >> > + default: >> > + break; >> > + } >> > + switch(*d) >> > + { >> > + case 3: >> > + *d +=3D 3; >> > + case -4: >> > + *d -=3D 4; >> > + } >> > +} >> > + >> > +/* { dg-final { scan-tree-dump-times >> > "__builtin___sanitizer_cov_trace_cmp1 \\(" 1 "optimized" } } */ >> > +/* { dg-final { scan-tree-dump-times >> > "__builtin___sanitizer_cov_trace_cmp2 \\(" 1 "optimized" } } */ >> > +/* { dg-final { scan-tree-dump-times >> > "__builtin___sanitizer_cov_trace_cmp4 \\(" 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_switch \\(" 2 "optimized" } } */ >> > >> > >> > With Regards >> > Wish Wu >> > >> > On Mon, Jul 10, 2017 at 8:07 PM, =E5=90=B4=E6=BD=8D=E6=B5=A0(=E6=AD=A4= =E5=BD=BC) wrote: >> >> Hi >> >> >> >> I write some codes to make gcc support comparison-guided fuzzing. >> >> It is very like >> >> http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow . >> >> With -fsanitize-coverage=3Dtrace-cmp the compiler will insert extra >> >> instrumentation around comparison instructions and switch statements. >> >> I think it is useful for fuzzing. :D >> >> >> >> Patch is below, I may supply test cases later. >> >> >> >> With Regards >> >> Wish Wu >> >> >> >> Index: gcc/asan.c >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/asan.c (revision 250082) >> >> +++ gcc/asan.c (working copy) >> >> @@ -2705,6 +2705,29 @@ initialize_sanitizer_builtins (void) >> >> tree BT_FN_SIZE_CONST_PTR_INT >> >> =3D build_function_type_list (size_type_node, const_ptr_type_nod= e, >> >> integer_type_node, NULL_TREE); >> >> + >> >> + tree BT_FN_VOID_UINT8_UINT8 >> >> + =3D build_function_type_list (void_type_node, >> >> unsigned_char_type_node, >> >> + unsigned_char_type_node, NULL_TREE); >> >> + tree BT_FN_VOID_UINT16_UINT16 >> >> + =3D build_function_type_list (void_type_node, uint16_type_node, >> >> + uint16_type_node, NULL_TREE); >> >> + tree BT_FN_VOID_UINT32_UINT32 >> >> + =3D build_function_type_list (void_type_node, uint32_type_node, >> >> + uint32_type_node, NULL_TREE); >> >> + tree BT_FN_VOID_UINT64_UINT64 >> >> + =3D build_function_type_list (void_type_node, uint64_type_node, >> >> + uint64_type_node, NULL_TREE); >> >> + tree BT_FN_VOID_FLOAT_FLOAT >> >> + =3D build_function_type_list (void_type_node, float_type_node, >> >> + float_type_node, NULL_TREE); >> >> + tree BT_FN_VOID_DOUBLE_DOUBLE >> >> + =3D build_function_type_list (void_type_node, double_type_node, >> >> + double_type_node, NULL_TREE); >> >> + tree BT_FN_VOID_UINT64_PTR >> >> + =3D 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: gcc/builtin-types.def >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/builtin-types.def (revision 250082) >> >> +++ gcc/builtin-types.def (working copy) >> >> @@ -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: gcc/common.opt >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/common.opt (revision 250082) >> >> +++ gcc/common.opt (working copy) >> >> @@ -226,10 +226,9 @@ unsigned int flag_sanitize >> >> Variable >> >> unsigned int flag_sanitize_recover =3D (SANITIZE_UNDEFINED | >> >> SANITIZE_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & >> >> ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN) >> >> >> >> -fsanitize-coverage=3Dtrace-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 >> >> @@ -975,6 +974,10 @@ fsanitize=3D >> >> Common Driver Report Joined >> >> Select what to sanitize. >> >> >> >> +fsanitize-coverage=3D >> >> +Common Driver Report Joined >> >> +Select what to coverage sanitize. >> >> + >> >> fasan-shadow-offset=3D >> >> Common Joined RejectNegative Var(common_deferred_options) Defer >> >> -fasan-shadow-offset=3D Use custom shadow memory offset. >> >> Index: gcc/flag-types.h >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/flag-types.h (revision 250082) >> >> +++ gcc/flag-types.h (working copy) >> >> @@ -250,6 +250,14 @@ enum sanitize_code { >> >> | SANITIZE_BOUNDS_STRICT >> >> }; >> >> >> >> +/* Different trace modes */ >> >> +enum sanitize_coverage_code { >> >> + /* Trace PC */ >> >> + SANITIZE_COV_TRACE_PC =3D 1UL << 0, >> >> + /* Trace Compare */ >> >> + SANITIZE_COV_TRACE_CMP =3D 1UL << 1 >> >> +}; >> >> + >> >> /* flag_vtable_verify initialization levels. */ >> >> enum vtv_priority { >> >> VTV_NO_PRIORITY =3D 0, /* i.E. Do NOT do vtable verificatio= n. >> >> */ >> >> Index: gcc/opts.c >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/opts.c (revision 250082) >> >> +++ gcc/opts.c (working copy) >> >> @@ -1518,6 +1518,17 @@ const struct sanitizer_opts_s sanitizer_opts[]= =3D >> >> { NULL, 0U, 0UL, false } >> >> }; >> >> >> >> +/* -f{,no-}sanitize-coverage=3D suboptions. */ >> >> +const struct sanitizer_opts_s coverage_sanitizer_opts[] =3D >> >> +{ >> >> +#define SANITIZER_OPT(name, flags, recover) \ >> >> + { #name, flags, sizeof #name - 1, recover } >> >> + SANITIZER_OPT (trace-pc, SANITIZE_COV_TRACE_PC, false), >> >> + SANITIZER_OPT (trace-cmp, SANITIZE_COV_TRACE_CMP, false), >> >> +#undef SANITIZER_OPT >> >> + { NULL, 0U, 0UL, false } >> >> +}; >> >> + >> >> /* A struct for describing a run of chars within a string. */ >> >> >> >> struct string_fragment >> >> @@ -1665,6 +1676,85 @@ parse_sanitizer_options (const char *p, >> >> location_t >> >> return flags; >> >> } >> >> >> >> +/* Given ARG, an unrecognized coverage sanitizer option, return the >> >> best >> >> + matching coverage sanitizer option, or NULL if there isn't one. >> >> + VALUE is non-zero for the regular form of the option, zero >> >> + for the "no-" form (e.g. "-fno-sanitize-coverage=3D"). */ >> >> + >> >> +static const char * >> >> +get_closest_coverage_sanitizer_option (const string_fragment &arg, i= nt >> >> value) >> >> +{ >> >> + best_match bm (arg); >> >> + for (int i =3D 0; coverage_sanitizer_opts[i].name !=3D NULL; ++i) >> >> + { >> >> + bm.consider (coverage_sanitizer_opts[i].name); >> >> + } >> >> + return bm.get_best_meaningful_candidate (); >> >> +} >> >> + >> >> +/* Parse comma separated sanitizer suboptions from P for option SCOD= E, >> >> + adjust previous FLAGS and return new ones. If COMPLAIN is false, >> >> + don't issue diagnostics. */ >> >> + >> >> +unsigned int >> >> +parse_coverage_sanitizer_options (const char *p, location_t loc, >> >> + unsigned int flags, int value, bool complain) >> >> +{ >> >> + while (*p !=3D 0) >> >> + { >> >> + size_t len, i; >> >> + bool found =3D false; >> >> + const char *comma =3D strchr (p, ','); >> >> + >> >> + if (comma =3D=3D NULL) >> >> + len =3D strlen (p); >> >> + else >> >> + len =3D comma - p; >> >> + if (len =3D=3D 0) >> >> + { >> >> + p =3D comma + 1; >> >> + continue; >> >> + } >> >> + >> >> + /* Check to see if the string matches an option class name. */ >> >> + for (i =3D 0; coverage_sanitizer_opts[i].name !=3D NULL; ++i) >> >> + if (len =3D=3D coverage_sanitizer_opts[i].len >> >> + && memcmp (p, coverage_sanitizer_opts[i].name, len) =3D= =3D 0) >> >> + { >> >> + if (value) >> >> + flags |=3D coverage_sanitizer_opts[i].flag; >> >> + else >> >> + flags &=3D ~coverage_sanitizer_opts[i].flag; >> >> + found =3D true; >> >> + break; >> >> + } >> >> + >> >> + if (! found && complain) >> >> + { >> >> + const char *hint >> >> + =3D get_closest_coverage_sanitizer_option (string_fragment >> >> (p, len), >> >> + value); >> >> + >> >> + if (hint) >> >> + error_at (loc, >> >> + "unrecognized argument to -f%ssanitize-coverage= =3D >> >> option: %q.*s;" >> >> + " did you mean %qs?", >> >> + value ? "" : "no-", >> >> + (int) len, p, hint); >> >> + else >> >> + error_at (loc, >> >> + "unrecognized argument to -f%ssanitize-coverage= =3D >> >> option: %q.*s", >> >> + value ? "" : "no-", >> >> + (int) len, p); >> >> + } >> >> + >> >> + if (comma =3D=3D NULL) >> >> + break; >> >> + p =3D comma + 1; >> >> + } >> >> + return flags; >> >> +} >> >> + >> >> /* Parse string values of no_sanitize attribute passed in VALUE. >> >> Values are separated with comma. Wrong argument is stored to >> >> WRONG_ARGUMENT variable. */ >> >> @@ -1942,6 +2032,12 @@ common_handle_option (struct gcc_options *opts, >> >> &=3D ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); >> >> break; >> >> >> >> + case OPT_fsanitize_coverage_: >> >> + opts->x_flag_sanitize_coverage >> >> + =3D parse_coverage_sanitizer_options (arg, loc, >> >> + opts->x_flag_sanitize_coverage, >> >> value, true); >> >> + break; >> >> + >> >> case OPT_O: >> >> case OPT_Os: >> >> case OPT_Ofast: >> >> Index: gcc/sancov.c >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/sancov.c (revision 250082) >> >> +++ gcc/sancov.c (working copy) >> >> @@ -29,31 +29,194 @@ along with GCC; see the file COPYING3. If not s= ee >> >> #include "flags.h" >> >> #include "stmt.h" >> >> #include "gimple-iterator.h" >> >> +#include "tree-core.h" >> >> #include "tree-cfg.h" >> >> #include "tree-pass.h" >> >> #include "tree-iterator.h" >> >> +#include "fold-const.h" >> >> +#include "stringpool.h" >> >> +#include "output.h" >> >> +#include "cgraph.h" >> >> #include "asan.h" >> >> >> >> namespace { >> >> >> >> +static void >> >> +instrument_cond (gimple_stmt_iterator *gsi, gimple *stmt) >> >> +{ >> >> + tree lhs =3D gimple_cond_lhs (stmt); >> >> + tree rhs =3D gimple_cond_rhs (stmt); >> >> + unsigned int bitno =3D TYPE_PRECISION (TREE_TYPE (lhs)) > >> >> TYPE_PRECISION (TREE_TYPE (rhs)) ? >> >> + TYPE_PRECISION (TREE_TYPE (lhs)) : >> >> TYPE_PRECISION (TREE_TYPE (rhs)); >> >> + if (TREE_CODE (TREE_TYPE (lhs)) =3D=3D INTEGER_TYPE) >> >> + { >> >> + enum built_in_function fncode; >> >> + switch (bitno) >> >> + { >> >> + case 8: >> >> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP1; >> >> + break; >> >> + >> >> + case 16: >> >> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP2; >> >> + break; >> >> + >> >> + case 32: >> >> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP4; >> >> + break; >> >> + >> >> + case 64: >> >> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP8; >> >> + break; >> >> + >> >> + default: >> >> + return; >> >> + break; >> >> + } >> >> + tree fndecl =3D builtin_decl_implicit (fncode); >> >> + gimple *gcall =3D gimple_build_call (fndecl, 2, lhs, rhs); >> >> + gimple_set_location (gcall, gimple_location (stmt)); >> >> + gsi_insert_before (gsi, gcall, GSI_SAME_STMT); >> >> + } >> >> + else if (TREE_CODE (TREE_TYPE (lhs)) =3D=3D REAL_TYPE) >> >> + { >> >> + enum built_in_function fncode; >> >> + switch (bitno) >> >> + { >> >> + case 32: >> >> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMPF; >> >> + break; >> >> + >> >> + case 64: >> >> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMPD; >> >> + break; >> >> + >> >> + default: >> >> + return; >> >> + break; >> >> + } >> >> + tree fndecl =3D builtin_decl_implicit (fncode); >> >> + gimple *gcall =3D gimple_build_call (fndecl, 2, lhs, rhs); >> >> + gimple_set_location (gcall, gimple_location (stmt)); >> >> + gsi_insert_before (gsi, gcall, GSI_SAME_STMT); >> >> + } >> >> +} >> >> + >> >> +static void >> >> +instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function >> >> *fun) >> >> +{ >> >> + gswitch *switch_stmt =3D as_a (stmt); >> >> + tree index =3D gimple_switch_index (switch_stmt); >> >> + unsigned bitno =3D TYPE_PRECISION (TREE_TYPE (index)); >> >> + unsigned i, n =3D gimple_switch_num_labels (switch_stmt), num =3D = 0; >> >> + for (i =3D 0; i < n; ++i) >> >> + { >> >> + tree label =3D gimple_switch_label (switch_stmt, i); >> >> + tree low_case =3D CASE_LOW (label); >> >> + if (low_case !=3D NULL_TREE) >> >> + num++; >> >> + tree high_case =3D CASE_HIGH (label); >> >> + if (high_case !=3D NULL_TREE) >> >> + num++; >> >> + } >> >> + >> >> + tree case_array_elem_type =3D build_type_variant (uint64_type_node= , 1, >> >> 0); >> >> + tree case_array_type =3D build_array_type (case_array_elem_type, >> >> + build_index_type (size_int >> >> (num + 2 - 1))); >> >> + char name[64]; >> >> + static size_t case_array_count =3D 0; >> >> + snprintf(name, sizeof(name) - 1, >> >> "__sanitizer_cov_trace_switch_array%lu", case_array_count++); >> >> + tree case_array_var =3D build_decl (UNKNOWN_LOCATION, VAR_DECL, >> >> + get_identifier (name), >> >> case_array_type); >> >> + TREE_STATIC (case_array_var) =3D 1; >> >> + TREE_PUBLIC (case_array_var) =3D 0; >> >> + TREE_CONSTANT (case_array_var) =3D 1; >> >> + TREE_READONLY (case_array_var) =3D 1; >> >> + DECL_EXTERNAL (case_array_var) =3D 0; >> >> + DECL_ARTIFICIAL (case_array_var) =3D 1; >> >> + DECL_IGNORED_P (case_array_var) =3D 1; >> >> + >> >> + vec *v =3D 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, bitno)); >> >> + for (i =3D 0; i < n; ++i) >> >> + { >> >> + tree label =3D gimple_switch_label (switch_stmt, i); >> >> + >> >> + tree low_case =3D CASE_LOW (label); >> >> + if (low_case !=3D NULL_TREE) >> >> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, >> >> + build_int_cst (uint64_type_node, >> >> TREE_INT_CST_LOW (low_case))); >> >> + >> >> + tree high_case =3D CASE_HIGH (label); >> >> + if (high_case !=3D NULL_TREE) >> >> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, >> >> + build_int_cst (uint64_type_node, >> >> TREE_INT_CST_LOW (high_case))); >> >> + } >> >> + tree ctor =3D build_constructor (case_array_type, v); >> >> + TREE_STATIC (ctor) =3D 1; >> >> + TREE_PUBLIC (ctor) =3D 0; >> >> + TREE_CONSTANT (ctor) =3D 1; >> >> + TREE_READONLY (ctor) =3D 1; >> >> + DECL_EXTERNAL (ctor) =3D 0; >> >> + DECL_INITIAL (case_array_var) =3D ctor; >> >> + varpool_node::finalize_decl (case_array_var); >> >> + >> >> + tree case_array_var_ref =3D build_fold_addr_expr (case_array_var); >> >> + add_local_decl (fun, case_array_var); >> >> + tree fndecl =3D builtin_decl_implicit >> >> (BUILT_IN_SANITIZER_COV_TRACE_SWITCH); >> >> + gimple *gcall =3D gimple_build_call (fndecl, 2, index, >> >> case_array_var_ref); >> >> + gimple_set_location (gcall, gimple_location (stmt)); >> >> + gsi_insert_before(gsi, gcall, GSI_SAME_STMT); >> >> +} >> >> + >> >> unsigned >> >> sancov_pass (function *fun) >> >> { >> >> initialize_sanitizer_builtins (); >> >> >> >> + basic_block bb; >> >> + >> >> /* Insert callback into beginning of every BB. */ >> >> - tree fndecl =3D 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 =3D gsi_start_nondebug_after_labels_bb >> >> (bb); >> >> - if (gsi_end_p (gsi)) >> >> - continue; >> >> - gimple *stmt =3D gsi_stmt (gsi); >> >> - gimple *gcall =3D gimple_build_call (fndecl, 0); >> >> - gimple_set_location (gcall, gimple_location (stmt)); >> >> - gsi_insert_before (&gsi, gcall, GSI_SAME_STMT); >> >> + tree fndecl =3D builtin_decl_implicit >> >> (BUILT_IN_SANITIZER_COV_TRACE_PC); >> >> + FOR_EACH_BB_FN (bb, fun) >> >> + { >> >> + gimple_stmt_iterator gsi =3D >> >> gsi_start_nondebug_after_labels_bb (bb); >> >> + if (gsi_end_p (gsi)) >> >> + continue; >> >> + gimple *stmt =3D gsi_stmt (gsi); >> >> + gimple *gcall =3D gimple_build_call (fndecl, 0); >> >> + gimple_set_location (gcall, gimple_location (stmt)); >> >> + gsi_insert_before (&gsi, gcall, GSI_SAME_STMT); >> >> + } >> >> } >> >> + >> >> + /* Insert callback to every compare statments. */ >> >> + if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP) >> >> + { >> >> + FOR_EACH_BB_FN (bb, fun) >> >> + { >> >> + gimple_stmt_iterator gsi; >> >> + for (gsi =3D gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next >> >> (&gsi)) >> >> + { >> >> + gimple *stmt =3D gsi_stmt (gsi); >> >> + switch (gimple_code (stmt)) >> >> + { >> >> + case GIMPLE_COND: >> >> + instrument_cond (&gsi, stmt); >> >> + break; >> >> + case GIMPLE_SWITCH: >> >> + instrument_switch (&gsi, stmt, fun); >> >> + break; >> >> + default: >> >> + break; >> >> + } >> >> + } >> >> + } >> >> + } >> >> return 0; >> >> } >> >> >> >> Index: gcc/sanitizer.def >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> >> --- gcc/sanitizer.def (revision 250082) >> >> +++ gcc/sanitizer.def (working copy) >> >> @@ -529,6 +529,27 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNA= MI >> >> 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_LIS= T) >> >> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP4, >> >> + "__sanitizer_cov_trace_cmp4", >> >> + BT_FN_VOID_UINT32_UINT32, ATTR_NOTHROW_LEAF_LIS= T) >> >> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP8, >> >> + "__sanitizer_cov_trace_cmp8", >> >> + BT_FN_VOID_UINT64_UINT64, ATTR_NOTHROW_LEAF_LIS= T) >> >> +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_LIS= T) >> >> +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) > >