diff mbox series

[COMMITTED] PR tree-optimization/101741 - Ensure toupper and tolower follow the expected pattern.

Message ID 49b8d18d-98fe-84de-6a00-34d08fc2cfc7@redhat.com
State New
Headers show
Series [COMMITTED] PR tree-optimization/101741 - Ensure toupper and tolower follow the expected pattern. | expand

Commit Message

Andrew MacLeod Aug. 9, 2021, 8:25 p.m. UTC
The user has overridden the function name "toupper" . Its marked as a 
builtin function, presumably because it matches the name.  In range 
folding, we were assuming the LHS and the parameter were compatible 
types...  but they are not in this case..

I don't know if we should be marking such a thing as a builtin function, 
but regardless.. we shouldn't be trapping.  If the type of the argument 
is not compatible with  the LHS, then we'll simply assume nothing about 
the function.

Bootstraps with no regression on x86_64-pc-linux-gnu.  pushed.

Andrew

Comments

Richard Biener Aug. 10, 2021, 7:45 a.m. UTC | #1
On Mon, Aug 9, 2021 at 10:31 PM Andrew MacLeod via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> The user has overridden the function name "toupper" . Its marked as a
> builtin function, presumably because it matches the name.  In range
> folding, we were assuming the LHS and the parameter were compatible
> types...  but they are not in this case..
>
> I don't know if we should be marking such a thing as a builtin function,
> but regardless.. we shouldn't be trapping.  If the type of the argument
> is not compatible with  the LHS, then we'll simply assume nothing about
> the function.
>
> Bootstraps with no regression on x86_64-pc-linux-gnu.  pushed.

I wonder why the gimple_call_combined_fn verification
using gimple_builtin_call_types_compatible_p isn't enough here?
Yes, it's matching is a bit lazy, but only with respect to promotion
of arguments to 'int'.

Richard.

> Andrew
>
>
>
Andrew MacLeod Aug. 10, 2021, 1:21 p.m. UTC | #2
On 8/10/21 3:45 AM, Richard Biener wrote:
> On Mon, Aug 9, 2021 at 10:31 PM Andrew MacLeod via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>> The user has overridden the function name "toupper" . Its marked as a
>> builtin function, presumably because it matches the name.  In range
>> folding, we were assuming the LHS and the parameter were compatible
>> types...  but they are not in this case..
>>
>> I don't know if we should be marking such a thing as a builtin function,
>> but regardless.. we shouldn't be trapping.  If the type of the argument
>> is not compatible with  the LHS, then we'll simply assume nothing about
>> the function.
>>
>> Bootstraps with no regression on x86_64-pc-linux-gnu.  pushed.
> I wonder why the gimple_call_combined_fn verification
> using gimple_builtin_call_types_compatible_p isn't enough here?
> Yes, it's matching is a bit lazy, but only with respect to promotion
> of arguments to 'int'.
>
> Richard.
>
I set a breakpoint on the return type field for the builtin... A quick 
check shows the return type of the builtin is being changed to "unsigned 
int" here:

#0  merge_decls (newdecl=0x7fffe9f67100, olddecl=0x7fffe9ed2100, 
newtype=0x7fffe9e3ae70, oldtype=0x7fffe9e3ae70) at 
/gcc/master/gcc/gcc/c/c-decl.c:2598
#1  0x0000000000a0628d in duplicate_decls (newdecl=0x7fffe9f67100, 
olddecl=0x7fffe9ed2100) at /gcc/master/gcc/gcc/c/c-decl.c:2963
#2  0x0000000000a07464 in pushdecl (x=0x7fffe9f67100) at 
/gcc/master/gcc/gcc/c/c-decl.c:3256
#3  0x0000000000a1d113 in start_function (declspecs=0x37728b0, 
declarator=0x3772ae0, attributes=0x0) at /gcc/master/gcc/gcc/c/c-decl.c:9644
#4  0x0000000000a8667c in c_parser_declaration_or_fndef 
(parser=0x7ffff7ff7ab0, fndef_ok=true, static_assert_ok=true, 
empty_ok=true, nested=false, start_attr_ok=true, 
objc_foreach_object_declaration=0x0,
     omp_declare_simd_clauses=0x0, have_attrs=false, attrs=0x0, 
oacc_routine_data=0x0, fallthru_attr_p=0x0) at 
/gcc/master/gcc/gcc/c/c-parser.c:2444


It would appear that merge_decls is merging the olddecl (the bultin) 
with newdecl  and results in changing the LHS to unsigned int, so now it 
thinks the builtin matches.   eeeks.

I don't know what the correct thing to do is, but a quick hack to check 
if old_decl is a builtin and return false from duplicate_decl also seems 
to resolve the problem:

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 221a67fe57b..27ab6ac9f1a 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2960,6 +2960,9 @@ duplicate_decls (tree newdecl, tree olddecl)
        return false;
      }

+  if (DECL_BUILT_IN_CLASS (olddecl) != NOT_BUILT_IN)
+    return false;
+
    merge_decls (newdecl, olddecl, newtype, oldtype);

    /* The NEWDECL will no longer be needed.
Richard Biener Aug. 10, 2021, 2:14 p.m. UTC | #3
On Tue, Aug 10, 2021 at 3:21 PM Andrew MacLeod <amacleod@redhat.com> wrote:
>
> On 8/10/21 3:45 AM, Richard Biener wrote:
> > On Mon, Aug 9, 2021 at 10:31 PM Andrew MacLeod via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> >> The user has overridden the function name "toupper" . Its marked as a
> >> builtin function, presumably because it matches the name.  In range
> >> folding, we were assuming the LHS and the parameter were compatible
> >> types...  but they are not in this case..
> >>
> >> I don't know if we should be marking such a thing as a builtin function,
> >> but regardless.. we shouldn't be trapping.  If the type of the argument
> >> is not compatible with  the LHS, then we'll simply assume nothing about
> >> the function.
> >>
> >> Bootstraps with no regression on x86_64-pc-linux-gnu.  pushed.
> > I wonder why the gimple_call_combined_fn verification
> > using gimple_builtin_call_types_compatible_p isn't enough here?
> > Yes, it's matching is a bit lazy, but only with respect to promotion
> > of arguments to 'int'.
> >
> > Richard.
> >
> I set a breakpoint on the return type field for the builtin... A quick
> check shows the return type of the builtin is being changed to "unsigned
> int" here:

OK, so gimple_builtin_call_types_compatible_p only checks that the
call is consistent with the fndecl type - iff the declaration is incompatible
with the declaration as specified by builtins.def then that's of course
not detected by that check (this check is to catch cases where a
formerly indirect call through an incompatible type is now known to
be to a builtin).

IIRC that is a recurring issue and indeed my opinion is that frontends
should not mark function decls as BUILT_IN if the definition/declaration
signature is not compatible.

> #0  merge_decls (newdecl=0x7fffe9f67100, olddecl=0x7fffe9ed2100,
> newtype=0x7fffe9e3ae70, oldtype=0x7fffe9e3ae70) at
> /gcc/master/gcc/gcc/c/c-decl.c:2598
> #1  0x0000000000a0628d in duplicate_decls (newdecl=0x7fffe9f67100,
> olddecl=0x7fffe9ed2100) at /gcc/master/gcc/gcc/c/c-decl.c:2963
> #2  0x0000000000a07464 in pushdecl (x=0x7fffe9f67100) at
> /gcc/master/gcc/gcc/c/c-decl.c:3256
> #3  0x0000000000a1d113 in start_function (declspecs=0x37728b0,
> declarator=0x3772ae0, attributes=0x0) at /gcc/master/gcc/gcc/c/c-decl.c:9644
> #4  0x0000000000a8667c in c_parser_declaration_or_fndef
> (parser=0x7ffff7ff7ab0, fndef_ok=true, static_assert_ok=true,
> empty_ok=true, nested=false, start_attr_ok=true,
> objc_foreach_object_declaration=0x0,
>      omp_declare_simd_clauses=0x0, have_attrs=false, attrs=0x0,
> oacc_routine_data=0x0, fallthru_attr_p=0x0) at
> /gcc/master/gcc/gcc/c/c-parser.c:2444
>
>
> It would appear that merge_decls is merging the olddecl (the bultin)
> with newdecl  and results in changing the LHS to unsigned int, so now it
> thinks the builtin matches.   eeeks.
>
> I don't know what the correct thing to do is, but a quick hack to check
> if old_decl is a builtin and return false from duplicate_decl also seems
> to resolve the problem:

Yeah, but that's of course too harsh - we do want correct user declarations of
say 'malloc' to be classified as built-in.

The odd thing is that we merge int foo() and unsigned foo () using
composite_type.  diagnose_mismatched_decls should be made
more strict here although it explicitly mentions

          /* Accept "harmless" mismatches in function types such
             as missing qualifiers or int vs long when they're the same
             size.  However, diagnose return and argument types that are
             incompatible according to language rules.  */

whatever 'language rules' means here.

Anyway, this function is where we should avoid making newdecl built-in
(and we should of course not adjust olddecl either).

Richard.

> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> index 221a67fe57b..27ab6ac9f1a 100644
> --- a/gcc/c/c-decl.c
> +++ b/gcc/c/c-decl.c
> @@ -2960,6 +2960,9 @@ duplicate_decls (tree newdecl, tree olddecl)
>         return false;
>       }
>
> +  if (DECL_BUILT_IN_CLASS (olddecl) != NOT_BUILT_IN)
> +    return false;
> +
>     merge_decls (newdecl, olddecl, newtype, oldtype);
>
>     /* The NEWDECL will no longer be needed.
>
>
Jakub Jelinek Aug. 10, 2021, 2:25 p.m. UTC | #4
On Tue, Aug 10, 2021 at 04:14:15PM +0200, Richard Biener via Gcc-patches wrote:
> OK, so gimple_builtin_call_types_compatible_p only checks that the
> call is consistent with the fndecl type - iff the declaration is incompatible
> with the declaration as specified by builtins.def then that's of course
> not detected by that check (this check is to catch cases where a
> formerly indirect call through an incompatible type is now known to
> be to a builtin).
> 
> IIRC that is a recurring issue and indeed my opinion is that frontends
> should not mark function decls as BUILT_IN if the definition/declaration
> signature is not compatible.

Different FEs use different strictness for what is or is not compatible.
And we can't be too strict, because e.g. of FILE * arguments where the
FILE type isn't pre-declared for the builtins.
On severe mismatches I think the FEs already don't mark it built in
(say double vs. int etc.), and e.g. const char * vs. char * differences
should be allowed (e.g. consider C++ vs. C strchr).
But perhaps we should consider as incompatible somethng that doesn't
pass useless_type_conversion_p too...

	Jakub
diff mbox series

Patch

commit c86c95edd165d674614516cda0b1fcb6616c1096
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Mon Aug 9 15:53:42 2021 -0400

    Ensure toupper and tolower follow the expected pattern.
    
    If the parameter is not compatible with the LHS, assume this is not really a
    builtin function to avoid a trap.
    
            gcc/
            PR tree-optimization/101741
            * gimple-range-fold.cc (fold_using_range::range_of_builtin_call): Check
            type of parameter for toupper/tolower.
    
            gcc/testsuite/
            * gcc.dg/pr101741.c: New.

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 410bc4ddca4..d3e3e14ff64 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -894,6 +894,9 @@  fold_using_range::range_of_builtin_call (irange &r, gcall *call,
     case CFN_BUILT_IN_TOUPPER:
       {
 	arg = gimple_call_arg (call, 0);
+	// If the argument isn't compatible with the LHS, do nothing.
+	if (!range_compatible_p (type, TREE_TYPE (arg)))
+	  return false;
 	if (!src.get_operand (r, arg))
 	  return false;
 
@@ -913,6 +916,9 @@  fold_using_range::range_of_builtin_call (irange &r, gcall *call,
      case CFN_BUILT_IN_TOLOWER:
       {
 	arg = gimple_call_arg (call, 0);
+	// If the argument isn't compatible with the LHS, do nothing.
+	if (!range_compatible_p (type, TREE_TYPE (arg)))
+	  return false;
 	if (!src.get_operand (r, arg))
 	  return false;
 
diff --git a/gcc/testsuite/gcc.dg/pr101741.c b/gcc/testsuite/gcc.dg/pr101741.c
new file mode 100644
index 00000000000..6587dca77d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101741.c
@@ -0,0 +1,16 @@ 
+/* PR tree-optimization/101741 */
+/* { dg-do compile } */
+/* { dg-options "-O2 " } */
+
+int
+foo (void);
+
+unsigned int
+toupper (int c)
+{
+  c = foo ();
+  while (c)
+    c = toupper (c);
+
+  return c;
+}