Provide -fcf-protection=branch,return.
Checks
Commit Message
Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
Ok for trunk?
gcc/ChangeLog:
PR target/89701
* common.opt: Refactor -fcf-protection= to support combination
of param.
* lto-wrapper.c (merge_and_complain): Adjusted.
* opts.c (parse_cf_protection_options): New.
(common_handle_option): Decode argument for -fcf-protection=.
* opts.h (parse_cf_protection_options): Declare.
gcc/testsuite/ChangeLog:
PR target/89701
* c-c++-common/fcf-protection-8.c: New test.
* c-c++-common/fcf-protection-9.c: New test.
* c-c++-common/fcf-protection-10.c: New test.
* gcc.target/i386/pr89701-1.c: New test.
* gcc.target/i386/pr89701-2.c: New test.
* gcc.target/i386/pr89701-3.c: New test.
* gcc.target/i386/pr89701-4.c: New test.
---
gcc/common.opt | 24 ++----
gcc/lto-wrapper.cc | 21 +++--
gcc/opts.cc | 79 +++++++++++++++++++
gcc/opts.h | 1 +
.../c-c++-common/fcf-protection-10.c | 3 +
.../c-c++-common/fcf-protection-11.c | 2 +
.../c-c++-common/fcf-protection-12.c | 2 +
gcc/testsuite/c-c++-common/fcf-protection-8.c | 3 +
gcc/testsuite/c-c++-common/fcf-protection-9.c | 3 +
gcc/testsuite/gcc.target/i386/pr89701-1.c | 4 +
gcc/testsuite/gcc.target/i386/pr89701-2.c | 4 +
gcc/testsuite/gcc.target/i386/pr89701-3.c | 5 ++
gcc/testsuite/gcc.target/i386/pr89701-4.c | 5 ++
13 files changed, 130 insertions(+), 26 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-10.c
create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-11.c
create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-12.c
create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-8.c
create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-9.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-1.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-2.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-3.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-4.c
Comments
On Thu, May 11, 2023 at 10:45 PM liuhongt via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
> Ok for trunk?
>
> gcc/ChangeLog:
>
> PR target/89701
> * common.opt: Refactor -fcf-protection= to support combination
> of param.
> * lto-wrapper.c (merge_and_complain): Adjusted.
> * opts.c (parse_cf_protection_options): New.
> (common_handle_option): Decode argument for -fcf-protection=.
> * opts.h (parse_cf_protection_options): Declare.
I think this could be simplified if you use either EnumSet or
EnumBitSet instead in common.opt for `-fcf-protection=`.
Thanks,
Andrew
>
> gcc/testsuite/ChangeLog:
>
> PR target/89701
> * c-c++-common/fcf-protection-8.c: New test.
> * c-c++-common/fcf-protection-9.c: New test.
> * c-c++-common/fcf-protection-10.c: New test.
> * gcc.target/i386/pr89701-1.c: New test.
> * gcc.target/i386/pr89701-2.c: New test.
> * gcc.target/i386/pr89701-3.c: New test.
> * gcc.target/i386/pr89701-4.c: New test.
> ---
> gcc/common.opt | 24 ++----
> gcc/lto-wrapper.cc | 21 +++--
> gcc/opts.cc | 79 +++++++++++++++++++
> gcc/opts.h | 1 +
> .../c-c++-common/fcf-protection-10.c | 3 +
> .../c-c++-common/fcf-protection-11.c | 2 +
> .../c-c++-common/fcf-protection-12.c | 2 +
> gcc/testsuite/c-c++-common/fcf-protection-8.c | 3 +
> gcc/testsuite/c-c++-common/fcf-protection-9.c | 3 +
> gcc/testsuite/gcc.target/i386/pr89701-1.c | 4 +
> gcc/testsuite/gcc.target/i386/pr89701-2.c | 4 +
> gcc/testsuite/gcc.target/i386/pr89701-3.c | 5 ++
> gcc/testsuite/gcc.target/i386/pr89701-4.c | 5 ++
> 13 files changed, 130 insertions(+), 26 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-10.c
> create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-11.c
> create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-12.c
> create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-8.c
> create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-9.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-1.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-2.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-3.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-4.c
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index a28ca13385a..ac12da52733 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -229,6 +229,10 @@ bool dump_base_name_prefixed = false
> Variable
> unsigned int flag_zero_call_used_regs
>
> +;; What the CF check should instrument
> +Variable
> +unsigned int flag_cf_protection = 0
> +
> ###
> Driver
>
> @@ -1886,28 +1890,10 @@ fcf-protection
> Common RejectNegative Alias(fcf-protection=,full)
>
> fcf-protection=
> -Common Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) Init(CF_NONE)
> +Common Joined
> -fcf-protection=[full|branch|return|none|check] Instrument functions with checks to verify jump/call/return control-flow transfer
> instructions have valid targets.
>
> -Enum
> -Name(cf_protection_level) Type(enum cf_protection_level) UnknownError(unknown Control-Flow Protection Level %qs)
> -
> -EnumValue
> -Enum(cf_protection_level) String(full) Value(CF_FULL)
> -
> -EnumValue
> -Enum(cf_protection_level) String(branch) Value(CF_BRANCH)
> -
> -EnumValue
> -Enum(cf_protection_level) String(return) Value(CF_RETURN)
> -
> -EnumValue
> -Enum(cf_protection_level) String(check) Value(CF_CHECK)
> -
> -EnumValue
> -Enum(cf_protection_level) String(none) Value(CF_NONE)
> -
> finstrument-functions
> Common Var(flag_instrument_function_entry_exit,1)
> Instrument function entry and exit with profiling calls.
> diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
> index 5186d040ce0..568c8af659d 100644
> --- a/gcc/lto-wrapper.cc
> +++ b/gcc/lto-wrapper.cc
> @@ -359,26 +359,33 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options,
> case OPT_fcf_protection_:
> /* Default to link-time option, else append or check identical. */
> if (!cf_protection_option
> - || cf_protection_option->value == CF_CHECK)
> + || !memcmp (cf_protection_option->arg, "check", 5))
> {
> + const char* parg = decoded_options[existing_opt].arg;
> if (existing_opt == -1)
> decoded_options.safe_push (*foption);
> - else if (decoded_options[existing_opt].value != foption->value)
> + else if ((strlen (parg) != strlen (foption->arg))
> + || memcmp (parg, foption->arg, strlen (foption->arg)))
> {
> if (cf_protection_option
> - && cf_protection_option->value == CF_CHECK)
> + && !memcmp (cf_protection_option->arg, "check", 5))
> fatal_error (input_location,
> "option %qs with mismatching values"
> " (%s, %s)",
> "-fcf-protection",
> - decoded_options[existing_opt].arg,
> + parg,
> foption->arg);
> else
> {
> /* Merge and update the -fcf-protection option. */
> - decoded_options[existing_opt].value
> - &= (foption->value & CF_FULL);
> - switch (decoded_options[existing_opt].value)
> + HOST_WIDE_INT flags1
> + = parse_cf_protection_options (foption->arg,
> + input_location);
> + HOST_WIDE_INT flags2
> + = parse_cf_protection_options (parg,
> + input_location);
> + flags2 &= (flags1 & CF_FULL);
> + switch (flags2)
> {
> case CF_NONE:
> decoded_options[existing_opt].arg = "none";
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 86b94d62b58..6389383bc92 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -2187,6 +2187,81 @@ get_closest_sanitizer_option (const string_fragment &arg,
> return bm.get_best_meaningful_candidate ();
> }
>
> +unsigned int
> +parse_cf_protection_options (const char *p, location_t loc)
> +{
> + unsigned int flags = 0;
> + bool combined = false;
> + while (*p != 0)
> + {
> + size_t len;
> + const char *comma = strchr (p, ',');
> + if (comma == NULL)
> + len = strlen (p);
> + else
> + {
> + combined = true;
> + len = comma - p;
> + }
> +
> + if (len == 0)
> + {
> + p = comma + 1;
> + continue;
> + }
> +
> + switch (len)
> + {
> + case 4:
> + if (!memcmp (p, "full", 4))
> + {
> + if (combined && flags != CF_NONE)
> + warning_at (loc, 0, "better to use %<-fcf-protection=%> "
> + "option: full alone instead of in a combination");
> + flags |= CF_FULL;
> + }
> + else if (!memcmp (p, "none", 4))
> + {
> + if (combined && flags != CF_NONE)
> + warning_at (loc, 0, "combination of %<-fcf-protection=%> "
> + "option: none is ignored");
> + }
> + else
> + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> + "option: %.4s", p);
> + break;
> + case 5:
> + if (!memcmp (p, "check", 5))
> + {
> + if (combined && flags != CF_CHECK)
> + error_at (loc, "Combination for %<-fcf-protection=%> "
> + "option: check is not valid");
> + flags |= CF_CHECK;
> + }
> + else
> + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> + "option: %.5s", p);
> + break;
> + case 6:
> + if (!memcmp (p, "branch", 6))
> + flags |= CF_BRANCH;
> + else if (!memcmp (p, "return", 6))
> + flags |= CF_RETURN;
> + else
> + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> + "option: %.6s", p);
> + break;
> + default:
> + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> + "option: %.*s", (int) len, p);
> + }
> +
> + if (comma == NULL)
> + break;
> + p = comma + 1;
> + }
> + return flags;
> +}
> /* Parse comma separated sanitizer suboptions from P for option SCODE,
> adjust previous FLAGS and return new ones. If COMPLAIN is false,
> don't issue diagnostics. */
> @@ -2671,6 +2746,10 @@ common_handle_option (struct gcc_options *opts,
> case OPT__completion_:
> break;
>
> + case OPT_fcf_protection_:
> + opts->x_flag_cf_protection
> + = parse_cf_protection_options (arg, loc);
> + break;
> case OPT_fsanitize_:
> opts_set->x_flag_sanitize = true;
> opts->x_flag_sanitize
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 9959a440ca1..00d396d95f8 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -425,6 +425,7 @@ extern void control_warning_option (unsigned int opt_index, int kind,
> extern char *write_langs (unsigned int mask);
> extern void print_ignored_options (void);
> extern void handle_common_deferred_options (void);
> +extern unsigned int parse_cf_protection_options (const char*, location_t);
> unsigned int parse_sanitizer_options (const char *, location_t, int,
> unsigned int, int, bool);
>
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-10.c b/gcc/testsuite/c-c++-common/fcf-protection-10.c
> new file mode 100644
> index 00000000000..8692a08374b
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-10.c
> @@ -0,0 +1,3 @@
> +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> +/* { dg-options "-fcf-protection=branch,check" } */
> +/* { dg-error "Combination for '-fcf-protection=' option: check is not valid" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-11.c b/gcc/testsuite/c-c++-common/fcf-protection-11.c
> new file mode 100644
> index 00000000000..2e566350ccd
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-11.c
> @@ -0,0 +1,2 @@
> +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> +/* { dg-options "-fcf-protection=branch,return" } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-12.c b/gcc/testsuite/c-c++-common/fcf-protection-12.c
> new file mode 100644
> index 00000000000..b39c2f8e25d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-12.c
> @@ -0,0 +1,2 @@
> +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> +/* { dg-options "-fcf-protection=return,branch" } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-8.c b/gcc/testsuite/c-c++-common/fcf-protection-8.c
> new file mode 100644
> index 00000000000..33e46223b6b
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-8.c
> @@ -0,0 +1,3 @@
> +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> +/* { dg-options "-fcf-protection=branch,none" } */
> +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-9.c b/gcc/testsuite/c-c++-common/fcf-protection-9.c
> new file mode 100644
> index 00000000000..7848fe4b959
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-9.c
> @@ -0,0 +1,3 @@
> +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> +/* { dg-options "-fcf-protection=branch,full" } */
> +/* { dg-warning "better to use '-fcf-protection=' option: full alone instead of in a combination" "" { target { *-*-* } } 0 } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr89701-1.c b/gcc/testsuite/gcc.target/i386/pr89701-1.c
> new file mode 100644
> index 00000000000..1879c9ab4d8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr89701-1.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-fcf-protection=branch,return" } */
> +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> +/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr89701-2.c b/gcc/testsuite/gcc.target/i386/pr89701-2.c
> new file mode 100644
> index 00000000000..d5100575028
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr89701-2.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-fcf-protection=return,branch" } */
> +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> +/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr89701-3.c b/gcc/testsuite/gcc.target/i386/pr89701-3.c
> new file mode 100644
> index 00000000000..1505051a2bb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr89701-3.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-fcf-protection=return,none" } */
> +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-linux* } } 0 } */
> +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> +/* { dg-final { scan-assembler-times ".long 0x2" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr89701-4.c b/gcc/testsuite/gcc.target/i386/pr89701-4.c
> new file mode 100644
> index 00000000000..242b8810abb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr89701-4.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-fcf-protection=branch,none" } */
> +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */
> +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> +/* { dg-final { scan-assembler-times ".long 0x1" 1 } } */
> --
> 2.39.1.388.g2fc9e9ca3c
>
On Fri, May 12, 2023 at 1:50 PM Andrew Pinski <pinskia@gmail.com> wrote:
>
> On Thu, May 11, 2023 at 10:45 PM liuhongt via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
> > Ok for trunk?
> >
> > gcc/ChangeLog:
> >
> > PR target/89701
> > * common.opt: Refactor -fcf-protection= to support combination
> > of param.
> > * lto-wrapper.c (merge_and_complain): Adjusted.
> > * opts.c (parse_cf_protection_options): New.
> > (common_handle_option): Decode argument for -fcf-protection=.
> > * opts.h (parse_cf_protection_options): Declare.
>
> I think this could be simplified if you use either EnumSet or
> EnumBitSet instead in common.opt for `-fcf-protection=`.
Thanks, I didn't know that, i'll try to refactor the patch to EnumSet
or EnumBitSet
>
> Thanks,
> Andrew
>
> >
> > gcc/testsuite/ChangeLog:
> >
> > PR target/89701
> > * c-c++-common/fcf-protection-8.c: New test.
> > * c-c++-common/fcf-protection-9.c: New test.
> > * c-c++-common/fcf-protection-10.c: New test.
> > * gcc.target/i386/pr89701-1.c: New test.
> > * gcc.target/i386/pr89701-2.c: New test.
> > * gcc.target/i386/pr89701-3.c: New test.
> > * gcc.target/i386/pr89701-4.c: New test.
> > ---
> > gcc/common.opt | 24 ++----
> > gcc/lto-wrapper.cc | 21 +++--
> > gcc/opts.cc | 79 +++++++++++++++++++
> > gcc/opts.h | 1 +
> > .../c-c++-common/fcf-protection-10.c | 3 +
> > .../c-c++-common/fcf-protection-11.c | 2 +
> > .../c-c++-common/fcf-protection-12.c | 2 +
> > gcc/testsuite/c-c++-common/fcf-protection-8.c | 3 +
> > gcc/testsuite/c-c++-common/fcf-protection-9.c | 3 +
> > gcc/testsuite/gcc.target/i386/pr89701-1.c | 4 +
> > gcc/testsuite/gcc.target/i386/pr89701-2.c | 4 +
> > gcc/testsuite/gcc.target/i386/pr89701-3.c | 5 ++
> > gcc/testsuite/gcc.target/i386/pr89701-4.c | 5 ++
> > 13 files changed, 130 insertions(+), 26 deletions(-)
> > create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-10.c
> > create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-11.c
> > create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-12.c
> > create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-8.c
> > create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-9.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-1.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-2.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-3.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-4.c
> >
> > diff --git a/gcc/common.opt b/gcc/common.opt
> > index a28ca13385a..ac12da52733 100644
> > --- a/gcc/common.opt
> > +++ b/gcc/common.opt
> > @@ -229,6 +229,10 @@ bool dump_base_name_prefixed = false
> > Variable
> > unsigned int flag_zero_call_used_regs
> >
> > +;; What the CF check should instrument
> > +Variable
> > +unsigned int flag_cf_protection = 0
> > +
> > ###
> > Driver
> >
> > @@ -1886,28 +1890,10 @@ fcf-protection
> > Common RejectNegative Alias(fcf-protection=,full)
> >
> > fcf-protection=
> > -Common Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) Init(CF_NONE)
> > +Common Joined
> > -fcf-protection=[full|branch|return|none|check] Instrument functions with checks to verify jump/call/return control-flow transfer
> > instructions have valid targets.
> >
> > -Enum
> > -Name(cf_protection_level) Type(enum cf_protection_level) UnknownError(unknown Control-Flow Protection Level %qs)
> > -
> > -EnumValue
> > -Enum(cf_protection_level) String(full) Value(CF_FULL)
> > -
> > -EnumValue
> > -Enum(cf_protection_level) String(branch) Value(CF_BRANCH)
> > -
> > -EnumValue
> > -Enum(cf_protection_level) String(return) Value(CF_RETURN)
> > -
> > -EnumValue
> > -Enum(cf_protection_level) String(check) Value(CF_CHECK)
> > -
> > -EnumValue
> > -Enum(cf_protection_level) String(none) Value(CF_NONE)
> > -
> > finstrument-functions
> > Common Var(flag_instrument_function_entry_exit,1)
> > Instrument function entry and exit with profiling calls.
> > diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
> > index 5186d040ce0..568c8af659d 100644
> > --- a/gcc/lto-wrapper.cc
> > +++ b/gcc/lto-wrapper.cc
> > @@ -359,26 +359,33 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options,
> > case OPT_fcf_protection_:
> > /* Default to link-time option, else append or check identical. */
> > if (!cf_protection_option
> > - || cf_protection_option->value == CF_CHECK)
> > + || !memcmp (cf_protection_option->arg, "check", 5))
> > {
> > + const char* parg = decoded_options[existing_opt].arg;
> > if (existing_opt == -1)
> > decoded_options.safe_push (*foption);
> > - else if (decoded_options[existing_opt].value != foption->value)
> > + else if ((strlen (parg) != strlen (foption->arg))
> > + || memcmp (parg, foption->arg, strlen (foption->arg)))
> > {
> > if (cf_protection_option
> > - && cf_protection_option->value == CF_CHECK)
> > + && !memcmp (cf_protection_option->arg, "check", 5))
> > fatal_error (input_location,
> > "option %qs with mismatching values"
> > " (%s, %s)",
> > "-fcf-protection",
> > - decoded_options[existing_opt].arg,
> > + parg,
> > foption->arg);
> > else
> > {
> > /* Merge and update the -fcf-protection option. */
> > - decoded_options[existing_opt].value
> > - &= (foption->value & CF_FULL);
> > - switch (decoded_options[existing_opt].value)
> > + HOST_WIDE_INT flags1
> > + = parse_cf_protection_options (foption->arg,
> > + input_location);
> > + HOST_WIDE_INT flags2
> > + = parse_cf_protection_options (parg,
> > + input_location);
> > + flags2 &= (flags1 & CF_FULL);
> > + switch (flags2)
> > {
> > case CF_NONE:
> > decoded_options[existing_opt].arg = "none";
> > diff --git a/gcc/opts.cc b/gcc/opts.cc
> > index 86b94d62b58..6389383bc92 100644
> > --- a/gcc/opts.cc
> > +++ b/gcc/opts.cc
> > @@ -2187,6 +2187,81 @@ get_closest_sanitizer_option (const string_fragment &arg,
> > return bm.get_best_meaningful_candidate ();
> > }
> >
> > +unsigned int
> > +parse_cf_protection_options (const char *p, location_t loc)
> > +{
> > + unsigned int flags = 0;
> > + bool combined = false;
> > + while (*p != 0)
> > + {
> > + size_t len;
> > + const char *comma = strchr (p, ',');
> > + if (comma == NULL)
> > + len = strlen (p);
> > + else
> > + {
> > + combined = true;
> > + len = comma - p;
> > + }
> > +
> > + if (len == 0)
> > + {
> > + p = comma + 1;
> > + continue;
> > + }
> > +
> > + switch (len)
> > + {
> > + case 4:
> > + if (!memcmp (p, "full", 4))
> > + {
> > + if (combined && flags != CF_NONE)
> > + warning_at (loc, 0, "better to use %<-fcf-protection=%> "
> > + "option: full alone instead of in a combination");
> > + flags |= CF_FULL;
> > + }
> > + else if (!memcmp (p, "none", 4))
> > + {
> > + if (combined && flags != CF_NONE)
> > + warning_at (loc, 0, "combination of %<-fcf-protection=%> "
> > + "option: none is ignored");
> > + }
> > + else
> > + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> > + "option: %.4s", p);
> > + break;
> > + case 5:
> > + if (!memcmp (p, "check", 5))
> > + {
> > + if (combined && flags != CF_CHECK)
> > + error_at (loc, "Combination for %<-fcf-protection=%> "
> > + "option: check is not valid");
> > + flags |= CF_CHECK;
> > + }
> > + else
> > + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> > + "option: %.5s", p);
> > + break;
> > + case 6:
> > + if (!memcmp (p, "branch", 6))
> > + flags |= CF_BRANCH;
> > + else if (!memcmp (p, "return", 6))
> > + flags |= CF_RETURN;
> > + else
> > + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> > + "option: %.6s", p);
> > + break;
> > + default:
> > + error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
> > + "option: %.*s", (int) len, p);
> > + }
> > +
> > + if (comma == NULL)
> > + break;
> > + p = comma + 1;
> > + }
> > + return flags;
> > +}
> > /* Parse comma separated sanitizer suboptions from P for option SCODE,
> > adjust previous FLAGS and return new ones. If COMPLAIN is false,
> > don't issue diagnostics. */
> > @@ -2671,6 +2746,10 @@ common_handle_option (struct gcc_options *opts,
> > case OPT__completion_:
> > break;
> >
> > + case OPT_fcf_protection_:
> > + opts->x_flag_cf_protection
> > + = parse_cf_protection_options (arg, loc);
> > + break;
> > case OPT_fsanitize_:
> > opts_set->x_flag_sanitize = true;
> > opts->x_flag_sanitize
> > diff --git a/gcc/opts.h b/gcc/opts.h
> > index 9959a440ca1..00d396d95f8 100644
> > --- a/gcc/opts.h
> > +++ b/gcc/opts.h
> > @@ -425,6 +425,7 @@ extern void control_warning_option (unsigned int opt_index, int kind,
> > extern char *write_langs (unsigned int mask);
> > extern void print_ignored_options (void);
> > extern void handle_common_deferred_options (void);
> > +extern unsigned int parse_cf_protection_options (const char*, location_t);
> > unsigned int parse_sanitizer_options (const char *, location_t, int,
> > unsigned int, int, bool);
> >
> > diff --git a/gcc/testsuite/c-c++-common/fcf-protection-10.c b/gcc/testsuite/c-c++-common/fcf-protection-10.c
> > new file mode 100644
> > index 00000000000..8692a08374b
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/fcf-protection-10.c
> > @@ -0,0 +1,3 @@
> > +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> > +/* { dg-options "-fcf-protection=branch,check" } */
> > +/* { dg-error "Combination for '-fcf-protection=' option: check is not valid" "" { target *-*-* } 0 } */
> > diff --git a/gcc/testsuite/c-c++-common/fcf-protection-11.c b/gcc/testsuite/c-c++-common/fcf-protection-11.c
> > new file mode 100644
> > index 00000000000..2e566350ccd
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/fcf-protection-11.c
> > @@ -0,0 +1,2 @@
> > +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> > +/* { dg-options "-fcf-protection=branch,return" } */
> > diff --git a/gcc/testsuite/c-c++-common/fcf-protection-12.c b/gcc/testsuite/c-c++-common/fcf-protection-12.c
> > new file mode 100644
> > index 00000000000..b39c2f8e25d
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/fcf-protection-12.c
> > @@ -0,0 +1,2 @@
> > +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> > +/* { dg-options "-fcf-protection=return,branch" } */
> > diff --git a/gcc/testsuite/c-c++-common/fcf-protection-8.c b/gcc/testsuite/c-c++-common/fcf-protection-8.c
> > new file mode 100644
> > index 00000000000..33e46223b6b
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/fcf-protection-8.c
> > @@ -0,0 +1,3 @@
> > +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> > +/* { dg-options "-fcf-protection=branch,none" } */
> > +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */
> > diff --git a/gcc/testsuite/c-c++-common/fcf-protection-9.c b/gcc/testsuite/c-c++-common/fcf-protection-9.c
> > new file mode 100644
> > index 00000000000..7848fe4b959
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/fcf-protection-9.c
> > @@ -0,0 +1,3 @@
> > +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
> > +/* { dg-options "-fcf-protection=branch,full" } */
> > +/* { dg-warning "better to use '-fcf-protection=' option: full alone instead of in a combination" "" { target { *-*-* } } 0 } */
> > diff --git a/gcc/testsuite/gcc.target/i386/pr89701-1.c b/gcc/testsuite/gcc.target/i386/pr89701-1.c
> > new file mode 100644
> > index 00000000000..1879c9ab4d8
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr89701-1.c
> > @@ -0,0 +1,4 @@
> > +/* { dg-do compile { target *-*-linux* } } */
> > +/* { dg-options "-fcf-protection=branch,return" } */
> > +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> > +/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */
> > diff --git a/gcc/testsuite/gcc.target/i386/pr89701-2.c b/gcc/testsuite/gcc.target/i386/pr89701-2.c
> > new file mode 100644
> > index 00000000000..d5100575028
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr89701-2.c
> > @@ -0,0 +1,4 @@
> > +/* { dg-do compile { target *-*-linux* } } */
> > +/* { dg-options "-fcf-protection=return,branch" } */
> > +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> > +/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */
> > diff --git a/gcc/testsuite/gcc.target/i386/pr89701-3.c b/gcc/testsuite/gcc.target/i386/pr89701-3.c
> > new file mode 100644
> > index 00000000000..1505051a2bb
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr89701-3.c
> > @@ -0,0 +1,5 @@
> > +/* { dg-do compile { target *-*-linux* } } */
> > +/* { dg-options "-fcf-protection=return,none" } */
> > +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-linux* } } 0 } */
> > +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> > +/* { dg-final { scan-assembler-times ".long 0x2" 1 } } */
> > diff --git a/gcc/testsuite/gcc.target/i386/pr89701-4.c b/gcc/testsuite/gcc.target/i386/pr89701-4.c
> > new file mode 100644
> > index 00000000000..242b8810abb
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr89701-4.c
> > @@ -0,0 +1,5 @@
> > +/* { dg-do compile { target *-*-linux* } } */
> > +/* { dg-options "-fcf-protection=branch,none" } */
> > +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */
> > +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
> > +/* { dg-final { scan-assembler-times ".long 0x1" 1 } } */
> > --
> > 2.39.1.388.g2fc9e9ca3c
> >
@@ -229,6 +229,10 @@ bool dump_base_name_prefixed = false
Variable
unsigned int flag_zero_call_used_regs
+;; What the CF check should instrument
+Variable
+unsigned int flag_cf_protection = 0
+
###
Driver
@@ -1886,28 +1890,10 @@ fcf-protection
Common RejectNegative Alias(fcf-protection=,full)
fcf-protection=
-Common Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) Init(CF_NONE)
+Common Joined
-fcf-protection=[full|branch|return|none|check] Instrument functions with checks to verify jump/call/return control-flow transfer
instructions have valid targets.
-Enum
-Name(cf_protection_level) Type(enum cf_protection_level) UnknownError(unknown Control-Flow Protection Level %qs)
-
-EnumValue
-Enum(cf_protection_level) String(full) Value(CF_FULL)
-
-EnumValue
-Enum(cf_protection_level) String(branch) Value(CF_BRANCH)
-
-EnumValue
-Enum(cf_protection_level) String(return) Value(CF_RETURN)
-
-EnumValue
-Enum(cf_protection_level) String(check) Value(CF_CHECK)
-
-EnumValue
-Enum(cf_protection_level) String(none) Value(CF_NONE)
-
finstrument-functions
Common Var(flag_instrument_function_entry_exit,1)
Instrument function entry and exit with profiling calls.
@@ -359,26 +359,33 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options,
case OPT_fcf_protection_:
/* Default to link-time option, else append or check identical. */
if (!cf_protection_option
- || cf_protection_option->value == CF_CHECK)
+ || !memcmp (cf_protection_option->arg, "check", 5))
{
+ const char* parg = decoded_options[existing_opt].arg;
if (existing_opt == -1)
decoded_options.safe_push (*foption);
- else if (decoded_options[existing_opt].value != foption->value)
+ else if ((strlen (parg) != strlen (foption->arg))
+ || memcmp (parg, foption->arg, strlen (foption->arg)))
{
if (cf_protection_option
- && cf_protection_option->value == CF_CHECK)
+ && !memcmp (cf_protection_option->arg, "check", 5))
fatal_error (input_location,
"option %qs with mismatching values"
" (%s, %s)",
"-fcf-protection",
- decoded_options[existing_opt].arg,
+ parg,
foption->arg);
else
{
/* Merge and update the -fcf-protection option. */
- decoded_options[existing_opt].value
- &= (foption->value & CF_FULL);
- switch (decoded_options[existing_opt].value)
+ HOST_WIDE_INT flags1
+ = parse_cf_protection_options (foption->arg,
+ input_location);
+ HOST_WIDE_INT flags2
+ = parse_cf_protection_options (parg,
+ input_location);
+ flags2 &= (flags1 & CF_FULL);
+ switch (flags2)
{
case CF_NONE:
decoded_options[existing_opt].arg = "none";
@@ -2187,6 +2187,81 @@ get_closest_sanitizer_option (const string_fragment &arg,
return bm.get_best_meaningful_candidate ();
}
+unsigned int
+parse_cf_protection_options (const char *p, location_t loc)
+{
+ unsigned int flags = 0;
+ bool combined = false;
+ while (*p != 0)
+ {
+ size_t len;
+ const char *comma = strchr (p, ',');
+ if (comma == NULL)
+ len = strlen (p);
+ else
+ {
+ combined = true;
+ len = comma - p;
+ }
+
+ if (len == 0)
+ {
+ p = comma + 1;
+ continue;
+ }
+
+ switch (len)
+ {
+ case 4:
+ if (!memcmp (p, "full", 4))
+ {
+ if (combined && flags != CF_NONE)
+ warning_at (loc, 0, "better to use %<-fcf-protection=%> "
+ "option: full alone instead of in a combination");
+ flags |= CF_FULL;
+ }
+ else if (!memcmp (p, "none", 4))
+ {
+ if (combined && flags != CF_NONE)
+ warning_at (loc, 0, "combination of %<-fcf-protection=%> "
+ "option: none is ignored");
+ }
+ else
+ error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+ "option: %.4s", p);
+ break;
+ case 5:
+ if (!memcmp (p, "check", 5))
+ {
+ if (combined && flags != CF_CHECK)
+ error_at (loc, "Combination for %<-fcf-protection=%> "
+ "option: check is not valid");
+ flags |= CF_CHECK;
+ }
+ else
+ error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+ "option: %.5s", p);
+ break;
+ case 6:
+ if (!memcmp (p, "branch", 6))
+ flags |= CF_BRANCH;
+ else if (!memcmp (p, "return", 6))
+ flags |= CF_RETURN;
+ else
+ error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+ "option: %.6s", p);
+ break;
+ default:
+ error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+ "option: %.*s", (int) len, p);
+ }
+
+ if (comma == NULL)
+ break;
+ p = comma + 1;
+ }
+ return flags;
+}
/* Parse comma separated sanitizer suboptions from P for option SCODE,
adjust previous FLAGS and return new ones. If COMPLAIN is false,
don't issue diagnostics. */
@@ -2671,6 +2746,10 @@ common_handle_option (struct gcc_options *opts,
case OPT__completion_:
break;
+ case OPT_fcf_protection_:
+ opts->x_flag_cf_protection
+ = parse_cf_protection_options (arg, loc);
+ break;
case OPT_fsanitize_:
opts_set->x_flag_sanitize = true;
opts->x_flag_sanitize
@@ -425,6 +425,7 @@ extern void control_warning_option (unsigned int opt_index, int kind,
extern char *write_langs (unsigned int mask);
extern void print_ignored_options (void);
extern void handle_common_deferred_options (void);
+extern unsigned int parse_cf_protection_options (const char*, location_t);
unsigned int parse_sanitizer_options (const char *, location_t, int,
unsigned int, int, bool);
new file mode 100644
@@ -0,0 +1,3 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,check" } */
+/* { dg-error "Combination for '-fcf-protection=' option: check is not valid" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,2 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,return" } */
new file mode 100644
@@ -0,0 +1,2 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=return,branch" } */
new file mode 100644
@@ -0,0 +1,3 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,none" } */
+/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */
new file mode 100644
@@ -0,0 +1,3 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,full" } */
+/* { dg-warning "better to use '-fcf-protection=' option: full alone instead of in a combination" "" { target { *-*-* } } 0 } */
new file mode 100644
@@ -0,0 +1,4 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=branch,return" } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */
new file mode 100644
@@ -0,0 +1,4 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=return,branch" } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=return,none" } */
+/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-linux* } } 0 } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long 0x2" 1 } } */
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=branch,none" } */
+/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long 0x1" 1 } } */