From patchwork Sat Jul 13 21:47:29 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 258843 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 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 91F212C014F for ; Sun, 14 Jul 2013 07:47:53 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=wkj6iqyWqZa5A6GXS 3e/oWpnabgMB8wrdJZxIcurc9DkUkLngEe1fcWHtQD71/3MFMKceRp1lCZwz6arR aG8qDFwpZRHJBwp9eXP+MImSsBtuMOws1NjiUuz+DPMfKP6+L/ViUDVMO5viowek tRKE6oC2Yp73uTLn8ou0V58SOY= 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:date :from:to:cc:subject:message-id:reply-to:references:mime-version :content-type:in-reply-to; s=default; bh=ZVRrnvB4baGhf7DBkjhhLC9 IwRM=; b=eO+bORnfO6ywjh/5DbuiLGbOCE5EgixMffY7SGKx5YzJhiYfTudSNKJ MnK8TmDS0qABNjciCmhZvvoPU7x6F9xD3VAHe4yXYm0hvqCiualNHLYQ6G1gCDH/ gFkV3+Z5NXUlMI+ry76nWBYnoNoKrBgxujKPG7VoBOGacVhxjaso= Received: (qmail 5163 invoked by alias); 13 Jul 2013 21:47:47 -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 5154 invoked by uid 89); 13 Jul 2013 21:47:47 -0000 X-Spam-SWARE-Status: No, score=-5.8 required=5.0 tests=AWL, BAYES_00, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RDNS_NONE, SPF_HELO_PASS, SPF_PASS autolearn=no version=3.3.1 Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Sat, 13 Jul 2013 21:47:46 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r6DLlbp3016628 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sat, 13 Jul 2013 17:47:37 -0400 Received: from localhost.localdomain (vpn1-7-149.ams2.redhat.com [10.36.7.149]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r6DLlYL3032631 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 13 Jul 2013 17:47:37 -0400 Received: from localhost.localdomain (localhost [127.0.0.1]) by localhost.localdomain (8.14.7/8.14.7) with ESMTP id r6DLlVWl032625; Sat, 13 Jul 2013 23:47:32 +0200 Received: (from jakub@localhost) by localhost.localdomain (8.14.7/8.14.7/Submit) id r6DLlTS1032624; Sat, 13 Jul 2013 23:47:29 +0200 Date: Sat, 13 Jul 2013 23:47:29 +0200 From: Jakub Jelinek To: "Joseph S. Myers" Cc: Marek Polacek , GCC Patches Subject: Re: [PATCH] Add command line parsing of -fsanitize Message-ID: <20130713214729.GI2475@laptop.redhat.com> Reply-To: Jakub Jelinek References: <20130614190439.GE20883@redhat.com> <20130617145930.GV2336@tucnak.redhat.com> <20130617160110.GY2336@tucnak.redhat.com> <20130618144251.GB4072@redhat.com> <20130618202534.GH2336@tucnak.redhat.com> <20130619081715.GL2336@tucnak.redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20130619081715.GL2336@tucnak.redhat.com> User-Agent: Mutt/1.5.21 (2010-09-15) On Wed, Jun 19, 2013 at 10:17:15AM +0200, Jakub Jelinek wrote: > While it would be possible to define say %:sanitize(thread LIBTSAN_EARLY) > that would work roughly like %{fsanitize=thread:LIBTSAN_EARLY} worked > until now (variable number of arguments that would be concatenated together > if flag_sanitize & ..., otherwise return empty), we use e.g. %e inside > of the %{fsanitize=thread:...} etc. > So, I wonder if we couldn't extend the handle_braces, I think right now > empty atoms are disallowed for the first choice, so perhaps > %{%:function(args):...} > where %:function(args) would be expanded to either non-empty or empty string > and depending on that the condition would be then true resp. false. > As % is not considered part of the atom name, and we require after atom name > optional * and then only one of |, }, &, :, I think this wouldn't be > ambiguous in the grammar. > We could then have: > %{!%:function1():-lfoo;%:function2(bar baz):-lbar -lbaz;-lxxx} > and for the sanitizer purposes: > %{%:sanitize(address):LIBTSAN_EARLY} > %{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\ > %{static:%ecannot specify -static with -fsanitize=address}\ > %{%:sanitize(thread):%e-fsanitize=address is incompatible with -fsanitize=thread}}\ > %{%:sanitize(thread):" LIBTSAN_SPEC "\ > %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or > %-shared}}}}}" Here is a patch that implements that (of course on top of Marek's patch from June). 2013-07-13 Jakub Jelinek * gcc.c: Document %{%:function(args):X}. (SANITIZER_EARLY_SPEC, SANITIZER_SPEC): Use %:sanitize(address) instead of fsanitize=address and %:sanitize(thread) instead of fsanitize=thread. (static_spec_functions): Add sanitize. (handle_spec_function): Add retval_nonnull argument and if non-NULL, store funcval != NULL there. (do_spec_1): Adjust handle_spec_function caller. (handle_braces): Allow %:function(args) as condition. (sanitize_spec_function): New function. * common.opt (fsanitize=): Add Driver. * config/darwin.h (LINK_COMMAND_SPEC_A): Use %:sanitize(address) instead of fsanitize=address. * config/arm/linux-eabi.h (ASAN_CC1_SPEC): Use %:sanitize(address) instead of fsanitize=address*. Jakub --- gcc/gcc.c.jj 2013-07-12 21:10:00.000000000 +0200 +++ gcc/gcc.c 2013-07-13 20:52:56.571269353 +0200 @@ -215,7 +215,7 @@ static inline void process_marked_switch static const char *process_brace_body (const char *, const char *, const char *, int, int); static const struct spec_function *lookup_spec_function (const char *); static const char *eval_spec_function (const char *, const char *); -static const char *handle_spec_function (const char *); +static const char *handle_spec_function (const char *, bool *); static char *save_string (const char *, int); static void set_collect_gcc_options (void); static int do_spec_1 (const char *, int, const char *); @@ -253,6 +253,7 @@ static const char *convert_filename (con static const char *getenv_spec_function (int, const char **); static const char *if_exists_spec_function (int, const char **); static const char *if_exists_else_spec_function (int, const char **); +static const char *sanitize_spec_function (int, const char **); static const char *replace_outfile_spec_function (int, const char **); static const char *remove_outfile_spec_function (int, const char **); static const char *version_compare_spec_function (int, const char **); @@ -432,6 +433,10 @@ or with constant text in a single argume than the OR. If %* appears in X, all of the alternatives must be starred, and only the first matching alternative is substituted. + %{%:function(args):X} + Call function named FUNCTION with args ARGS. If the function + returns non-NULL, then X is substituted, if it returns + NULL, it isn't substituted. %{S:X; if S was given to GCC, substitutes X; T:Y; else if T was given to GCC, substitutes Y; :D} else substitutes D. There can be as many clauses as you need. @@ -708,17 +713,17 @@ proper position among the other output f /* Linker command line options for -fsanitize= early on the command line. */ #ifndef SANITIZER_EARLY_SPEC #define SANITIZER_EARLY_SPEC "\ -%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_EARLY_SPEC "} \ - %{fsanitize=thread:" LIBTSAN_EARLY_SPEC "}}}" +%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \ + %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "}}}" #endif /* Linker command line options for -fsanitize= late on the command line. */ #ifndef SANITIZER_SPEC #define SANITIZER_SPEC "\ -%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_SPEC "\ +%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\ %{static:%ecannot specify -static with -fsanitize=address}\ - %{fsanitize=thread:%e-fsanitize=address is incompatible with -fsanitize=thread}}\ - %{fsanitize=thread:" LIBTSAN_SPEC "\ + %{%:sanitize(thread):%e-fsanitize=address is incompatible with -fsanitize=thread}}\ + %{%:sanitize(thread):" LIBTSAN_SPEC "\ %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}" #endif @@ -1323,6 +1328,7 @@ static const struct spec_function static { "getenv", getenv_spec_function }, { "if-exists", if_exists_spec_function }, { "if-exists-else", if_exists_else_spec_function }, + { "sanitize", sanitize_spec_function }, { "replace-outfile", replace_outfile_spec_function }, { "remove-outfile", remove_outfile_spec_function }, { "version-compare", version_compare_spec_function }, @@ -5273,7 +5279,7 @@ do_spec_1 (const char *spec, int inswitc break; case ':': - p = handle_spec_function (p); + p = handle_spec_function (p, NULL); if (p == 0) return -1; break; @@ -5509,10 +5515,13 @@ eval_spec_function (const char *func, co ARGS is processed as a spec in a separate context and split into an argument vector in the normal fashion. The function returns a string containing a spec which we then process in the caller's context, or - NULL if no processing is required. */ + NULL if no processing is required. + + If RETVAL_NONNULL is not NULL, then store a bool whether function + returned non-NULL. */ static const char * -handle_spec_function (const char *p) +handle_spec_function (const char *p, bool *retval_nonnull) { char *func, *args; const char *endp, *funcval; @@ -5558,6 +5567,8 @@ handle_spec_function (const char *p) funcval = eval_spec_function (func, args); if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0) p = NULL; + if (retval_nonnull) + *retval_nonnull = funcval != NULL; free (func); free (args); @@ -5701,19 +5712,28 @@ handle_braces (const char *p) p++, a_is_negated = true; SKIP_WHITE(); - if (*p == '.') - p++, a_is_suffix = true; - else if (*p == ',') - p++, a_is_spectype = true; - - atom = p; - while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '=' - || *p == ',' || *p == '.' || *p == '@') - p++; - end_atom = p; + if (*p == '%' && p[1] == ':') + { + atom = NULL; + end_atom = NULL; + p = handle_spec_function (p + 2, &a_matched); + } + else + { + if (*p == '.') + p++, a_is_suffix = true; + else if (*p == ',') + p++, a_is_spectype = true; + + atom = p; + while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '=' + || *p == ',' || *p == '.' || *p == '@') + p++; + end_atom = p; - if (*p == '*') - p++, a_is_starred = 1; + if (*p == '*') + p++, a_is_starred = 1; + } SKIP_WHITE(); switch (*p) @@ -5738,7 +5758,7 @@ handle_braces (const char *p) if (ordered_set) goto invalid; - if (atom == end_atom) + if (atom && atom == end_atom) { if (!n_way_choice || disj_matched || *p == '|' || a_is_negated || a_is_suffix || a_is_spectype @@ -5763,7 +5783,9 @@ handle_braces (const char *p) match. */ if (!disj_matched && !n_way_matched) { - if (a_is_suffix) + if (atom == NULL) + /* a_matched is already set by handle_spec_function. */; + else if (a_is_suffix) a_matched = input_suffix_matches (atom, end_atom); else if (a_is_spectype) a_matched = input_spec_matches (atom, end_atom); @@ -8060,6 +8082,27 @@ if_exists_else_spec_function (int argc, return argv[1]; } +/* sanitize built-in spec function. + + This returns non-NULL, if sanitizing address, thread or + any of the undefined behavior sanitizers. */ + +static const char * +sanitize_spec_function (int argc, const char **argv) +{ + if (argc != 1) + return NULL; + + if (strcmp (argv[0], "address") == 0) + return (flag_sanitize & SANITIZE_ADDRESS) ? "" : NULL; + if (strcmp (argv[0], "thread") == 0) + return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL; + if (strcmp (argv[0], "undefined") == 0) + return (flag_sanitize & SANITIZE_UNDEFINED) ? "" : NULL; + + return NULL; +} + /* replace-outfile built-in spec function. This looks for the first argument in the outfiles array's name and --- gcc/common.opt.jj 2013-07-12 21:14:03.000000000 +0200 +++ gcc/common.opt 2013-07-13 23:06:26.907390535 +0200 @@ -855,6 +855,6 @@ Common Ignore Does nothing. Preserved for backward compatibility. fsanitize= -Common Report Joined +Common Driver Report Joined Select what to sanitize --- gcc/config/darwin.h.jj 2013-07-12 21:09:56.384669485 +0200 +++ gcc/config/darwin.h 2013-07-13 20:08:34.189050120 +0200 @@ -178,7 +178,7 @@ extern GTY(()) int darwin_ms_struct; %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \ %{fopenmp|ftree-parallelize-loops=*: \ %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \ - %{fsanitize=address: -lasan } \ + %{%:sanitize(address): -lasan } \ %{fgnu-tm: \ %{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \ %{!nostdlib:%{!nodefaultlibs:\ --- gcc/config/arm/linux-eabi.h.jj 2013-07-12 21:09:56.241669386 +0200 +++ gcc/config/arm/linux-eabi.h 2013-07-13 20:09:36.163074198 +0200 @@ -85,7 +85,7 @@ LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) #undef ASAN_CC1_SPEC -#define ASAN_CC1_SPEC "%{fsanitize=*:-funwind-tables}" +#define ASAN_CC1_SPEC "%{%:sanitize(address):-funwind-tables}" #undef CC1_SPEC #define CC1_SPEC \