diff mbox

[Fortran,pr78672,ctp1,v1] Gfortran test suite failures with a sanitized compiler

Message ID 20161208143937.0153b2a8@vepi2
State New
Headers show

Commit Message

Andre Vehreschild Dec. 8, 2016, 1:39 p.m. UTC
Hi all, hi Dominique,

this is the "compile time part 1" (ctp1) patch to fix the issues reported in
gfortran by a sanitized compiler when compiling the testsuite. The patch
addresses all issues besides leaks (ASAN_OPTIONS="detect_leaks=false". Most of
the issues were about assuming certain kinds of data without explicitly
checking, e.g., taking a component-ref for an array-ref and similar.

So this patch only addresses the -fsanitize=address,undefined reports (without
leaks) for running the compiler. I liked to keep this patch small to get it
reviewed quickly. 

I see some other areas of work:

compile time part 2: address the leaks
testsuite run time: address the runtime issues (might have to be split in
	others and leaks, too)

So far, is this patch bootstrapping and regtesting fine on x86_64-linux/f23. Ok
for trunk?

Regards,
	Andre

PS: @Dominique: I will not commit before you are better and had the time to
test this.
-- 
Andre Vehreschild * Email: vehre ad gmx dot de
gcc/fortran/ChangeLog:

2016-12-08  Andre Vehreschild  <vehre@gcc.gnu.org>

	PR fortran/78672
	* data.c (create_character_initializer): Prevent accessing NULL-ptr.
	* interface.c (compare_actual_formal): Access the last array-ref.
	Prevent taking a REF_COMPONENT for a REF_ARRAY.  Correct indentation.
	* module.c (load_omp_udrs): Clear typespec before reading into it.
	* trans-decl.c (gfc_build_qualified_array): Prevent accessing the array
	when it is a coarray.
	* trans-expr.c (gfc_conv_cst_int_power): Use wi::abs()-function instead
	of crutch preventing sanitizer's bickering here.
	* trans-stmt.c (gfc_trans_deallocate): Only get data-component when it
	is a descriptor-array here.

Comments

Mikael Morin Dec. 8, 2016, 10:49 p.m. UTC | #1
Le 08/12/2016 à 14:39, Andre Vehreschild a écrit :
> Hi all, hi Dominique,

>

> this is the "compile time part 1" (ctp1) patch to fix the issues reported in

> gfortran by a sanitized compiler when compiling the testsuite. The patch

> addresses all issues besides leaks (ASAN_OPTIONS="detect_leaks=false". Most of

> the issues were about assuming certain kinds of data without explicitly

> checking, e.g., taking a component-ref for an array-ref and similar.

>

> So this patch only addresses the -fsanitize=address,undefined reports (without

> leaks) for running the compiler. I liked to keep this patch small to get it

> reviewed quickly.

>

> I see some other areas of work:

>

> compile time part 2: address the leaks

> testsuite run time: address the runtime issues (might have to be split in

> 	others and leaks, too)

>

> So far, is this patch bootstrapping and regtesting fine on x86_64-linux/f23. Ok

> for trunk?

>

> Regards,

> 	Andre

>

> PS: @Dominique: I will not commit before you are better and had the time to

> test this.

>

>

> diff --git a/gcc/fortran/data.c b/gcc/fortran/data.c

> index 139ce88..4f835b3 100644

> --- a/gcc/fortran/data.c

> +++ b/gcc/fortran/data.c

> @@ -186,7 +186,7 @@ create_character_initializer (gfc_expr *init, gfc_typespec *ts,

>        for (i = 0; i < len; i++)

>  	dest[start+i] = rvalue->representation.string[i];

>      }

> -  else

> +  else if (rvalue->value.character.string)

This one looks fishy.
Either rvalue is a character constant and its string should be set, or 
it’s not a character constant and the value.character.string should not 
be accessed at all.


>      memcpy (&dest[start], rvalue->value.character.string,

>  	    len * sizeof (gfc_char_t));

>

> diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c

> index 8afba84..4e4d17c 100644

> --- a/gcc/fortran/interface.c

> +++ b/gcc/fortran/interface.c

> @@ -2803,6 +2803,7 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,

>    int i, n, na;

>    unsigned long actual_size, formal_size;

>    bool full_array = false;

> +  gfc_ref *actual_arr_ref;

>

>    actual = *ap;

>

> @@ -2942,37 +2943,38 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,

>  	 and assumed-shape dummies, the string length needs to match

>  	 exactly.  */

>        if (a->expr->ts.type == BT_CHARACTER

> -	   && a->expr->ts.u.cl && a->expr->ts.u.cl->length

> -	   && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT

> -	   && f->sym->ts.u.cl && f->sym->ts.u.cl && f->sym->ts.u.cl->length

> -	   && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT

> -	   && (f->sym->attr.pointer || f->sym->attr.allocatable

> -	       || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

> -	   && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,

> -			f->sym->ts.u.cl->length->value.integer) != 0))

> -	 {

> -	   if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))

> -	     gfc_warning (OPT_Wargument_mismatch,

> -			  "Character length mismatch (%ld/%ld) between actual "

> -			  "argument and pointer or allocatable dummy argument "

> -			  "%qs at %L",

> -			  mpz_get_si (a->expr->ts.u.cl->length->value.integer),

> -			  mpz_get_si (f->sym->ts.u.cl->length->value.integer),

> -			  f->sym->name, &a->expr->where);

> -	   else if (where)

> -	     gfc_warning (OPT_Wargument_mismatch,

> -			  "Character length mismatch (%ld/%ld) between actual "

> -			  "argument and assumed-shape dummy argument %qs "

> -			  "at %L",

> -			  mpz_get_si (a->expr->ts.u.cl->length->value.integer),

> -			  mpz_get_si (f->sym->ts.u.cl->length->value.integer),

> -			  f->sym->name, &a->expr->where);

> -	   return 0;

> -	 }

> +	  && a->expr->ts.u.cl && a->expr->ts.u.cl->length

> +	  && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT

> +	  && f->sym->ts.type == BT_CHARACTER && f->sym->ts.u.cl

> +	  && f->sym->ts.u.cl->length

> +	  && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT

> +	  && (f->sym->attr.pointer || f->sym->attr.allocatable

> +	      || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

> +	  && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,

> +		       f->sym->ts.u.cl->length->value.integer) != 0))

> +	{

> +	  if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))

> +	    gfc_warning (OPT_Wargument_mismatch,

> +			 "Character length mismatch (%ld/%ld) between actual "

> +			 "argument and pointer or allocatable dummy argument "

> +			 "%qs at %L",

> +			 mpz_get_si (a->expr->ts.u.cl->length->value.integer),

> +			 mpz_get_si (f->sym->ts.u.cl->length->value.integer),

> +			 f->sym->name, &a->expr->where);

> +	  else if (where)

> +	    gfc_warning (OPT_Wargument_mismatch,

> +			 "Character length mismatch (%ld/%ld) between actual "

> +			 "argument and assumed-shape dummy argument %qs "

> +			 "at %L",

> +			 mpz_get_si (a->expr->ts.u.cl->length->value.integer),

> +			 mpz_get_si (f->sym->ts.u.cl->length->value.integer),

> +			 f->sym->name, &a->expr->where);

> +	  return 0;

> +	}

>

>        if ((f->sym->attr.pointer || f->sym->attr.allocatable)

> -	    && f->sym->ts.deferred != a->expr->ts.deferred

> -	    && a->expr->ts.type == BT_CHARACTER)

> +	  && f->sym->ts.deferred != a->expr->ts.deferred

> +	  && a->expr->ts.type == BT_CHARACTER)

>  	{

>  	  if (where)

>  	    gfc_error ("Actual argument at %L to allocatable or "

That one was just reformatting, right?

> @@ -3039,13 +3041,28 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,

>  	  return 0;

>  	}

>

> +      /* Find the last array_ref.  */

> +      actual_arr_ref = NULL;

> +      if (a->expr->ref)

> +	{

> +	  gfc_ref *ref = a->expr->ref;

> +

> +	  do

> +	    {

> +	      if (ref->type == REF_ARRAY)

> +		actual_arr_ref = ref;

> +	      ref = ref->next;

> +	    }

> +	  while (ref != NULL);

> +	}

beware, for the expression foo%c(:)%c2(1), this returns the array ref on 
c2, not the one on c. Is it what you want?
If not, maybe you can use gfc_find_array_ref.

> +

>        if (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE

>  	  && a->expr->expr_type == EXPR_VARIABLE

>  	  && a->expr->symtree->n.sym->as

>  	  && a->expr->symtree->n.sym->as->type == AS_ASSUMED_SIZE

> -	  && (a->expr->ref == NULL

> -	      || (a->expr->ref->type == REF_ARRAY

> -		  && a->expr->ref->u.ar.type == AR_FULL)))

> +	  && (actual_arr_ref == NULL

> +	      || (actual_arr_ref->type == REF_ARRAY

> +		  && actual_arr_ref->u.ar.type == AR_FULL)))

If I understand the code correctly, it’s trying to detect variables with 
assumed size, but I think you break that. In the case of an expression 
foo(1)%c(:), where foo is assumed size, the if condition would be true.


>  	{

>  	  if (where)

>  	    gfc_error ("Actual argument for %qs cannot be an assumed-size"

> @@ -3196,14 +3213,14 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,

>  	}

>

>        if (f->sym->attr.volatile_

> -	  && a->expr->ref && a->expr->ref->u.ar.type == AR_SECTION

> +	  && actual_arr_ref && actual_arr_ref->u.ar.type == AR_SECTION

>  	  && !(f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

>  	{

>  	  if (where)

>  	    gfc_error ("Array-section actual argument at %L is "

>  		       "incompatible with the non-assumed-shape "

>  		       "dummy argument %qs due to VOLATILE attribute",

> -		       &a->expr->where,f->sym->name);

> +		       &a->expr->where, f->sym->name);

>  	  return 0;

>  	}

>

> diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c

> index e727ade..713f272 100644

> --- a/gcc/fortran/module.c

> +++ b/gcc/fortran/module.c

> @@ -4710,6 +4710,7 @@ load_omp_udrs (void)

>

>        mio_lparen ();

>        mio_pool_string (&name);

> +      gfc_clear_ts (&ts);

>        mio_typespec (&ts);

>        if (strncmp (name, "operator ", sizeof ("operator ") - 1) == 0)

>  	{

> diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c

> index 2e6ef2a..8173ba9 100644

> --- a/gcc/fortran/trans-decl.c

> +++ b/gcc/fortran/trans-decl.c

> @@ -1019,7 +1019,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym)

>        layout_type (type);

>      }

>

> -  if (TYPE_NAME (type) != NULL_TREE

> +  if (TYPE_NAME (type) != NULL_TREE && as->rank > 0

I suppose one should replace as->rank with as->rank + as->corank instead 
of this.

>        && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE

>        && VAR_P (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)))

>      {


> diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c

> index 5ca716b..d953ec8 100644

> --- a/gcc/fortran/trans-stmt.c

> +++ b/gcc/fortran/trans-stmt.c

> @@ -6464,7 +6464,8 @@ gfc_trans_deallocate (gfc_code *code)

>  		    && !(!last && expr->symtree->n.sym->attr.pointer))

>  		{

>  		  if (is_coarray && expr->rank == 0

> -		      && (!last || !last->u.c.component->attr.dimension))

> +		      && (!last || !last->u.c.component->attr.dimension)

> +		      && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)))

I’m a bit surprised by the need for this. Are there cases where coarrays 
don’t have a descriptor?

>  		    {

>  		      /* Add the ref to the data member only, when this is not

>  			 a regular array or deallocate_alloc_comp will try to


The rest looks good.

Mikael
Mikael Morin Dec. 9, 2016, 7:54 a.m. UTC | #2
Hello,

Le 08/12/2016 à 23:49, Mikael Morin a écrit :
> Le 08/12/2016 à 14:39, Andre Vehreschild a écrit :

>> diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c

>> index 2e6ef2a..8173ba9 100644

>> --- a/gcc/fortran/trans-decl.c

>> +++ b/gcc/fortran/trans-decl.c

>> @@ -1019,7 +1019,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol

>> * sym)

>>        layout_type (type);

>>      }

>>

>> -  if (TYPE_NAME (type) != NULL_TREE

>> +  if (TYPE_NAME (type) != NULL_TREE && as->rank > 0

> I suppose one should replace as->rank with as->rank + as->corank instead

> of this.

>

I remember now that rank can be negative, so your change is fine.

>>        && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE

>>        && VAR_P (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)))

>>      {

>

Mikael
Andre Vehreschild Dec. 9, 2016, 10:55 a.m. UTC | #3
Hi Mikael,

thanks a lot for your comments. Note I also have added the reply to your latest
email here.

On Thu, 8 Dec 2016 23:49:57 +0100
Mikael Morin <morin-mikael@orange.fr> wrote:

<snipp>

> > diff --git a/gcc/fortran/data.c b/gcc/fortran/data.c

> > index 139ce88..4f835b3 100644

> > --- a/gcc/fortran/data.c

> > +++ b/gcc/fortran/data.c

> > @@ -186,7 +186,7 @@ create_character_initializer (gfc_expr *init,

> > gfc_typespec *ts, for (i = 0; i < len; i++)

> >  	dest[start+i] = rvalue->representation.string[i];

> >      }

> > -  else

> > +  else if (rvalue->value.character.string)  

> This one looks fishy.

> Either rvalue is a character constant and its string should be set, or 

> it’s not a character constant and the value.character.string should not 

> be accessed at all.


You are completely right. This can *only* occur when invalid-code is given to
the compiler. In this case the offending code was:

 data c / = NULL() / 

The syntax may not be correct (just out of my head), but I hope you get the
idea. The sanitizers complaint was that the second argument to the memcpy below
must not be NULL. The above if () makes sure the memcpy does not get called in
this case. So this merely to prevent the compiler from ICEing on systems whose
memcpy is not robust. 

> >      memcpy (&dest[start], rvalue->value.character.string,

> >  	    len * sizeof (gfc_char_t));

> >

> > diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c

> > index 8afba84..4e4d17c 100644

> > --- a/gcc/fortran/interface.c

> > +++ b/gcc/fortran/interface.c

> > @@ -2803,6 +2803,7 @@ compare_actual_formal (gfc_actual_arglist **ap,

> > gfc_formal_arglist *formal, int i, n, na;

> >    unsigned long actual_size, formal_size;

> >    bool full_array = false;

> > +  gfc_ref *actual_arr_ref;

> >

> >    actual = *ap;

> >

> > @@ -2942,37 +2943,38 @@ compare_actual_formal (gfc_actual_arglist **ap,

> > gfc_formal_arglist *formal, and assumed-shape dummies, the string length

> > needs to match exactly.  */

> >        if (a->expr->ts.type == BT_CHARACTER

> > -	   && a->expr->ts.u.cl && a->expr->ts.u.cl->length

> > -	   && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT

> > -	   && f->sym->ts.u.cl && f->sym->ts.u.cl && f->sym->ts.u.cl->length

> > -	   && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT

> > -	   && (f->sym->attr.pointer || f->sym->attr.allocatable

> > -	       || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

> > -	   && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,

> > -			f->sym->ts.u.cl->length->value.integer) != 0))

> > -	 {

> > -	   if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))

> > -	     gfc_warning (OPT_Wargument_mismatch,

> > -			  "Character length mismatch (%ld/%ld) between

> > actual "

> > -			  "argument and pointer or allocatable dummy

> > argument "

> > -			  "%qs at %L",

> > -			  mpz_get_si

> > (a->expr->ts.u.cl->length->value.integer),

> > -			  mpz_get_si

> > (f->sym->ts.u.cl->length->value.integer),

> > -			  f->sym->name, &a->expr->where);

> > -	   else if (where)

> > -	     gfc_warning (OPT_Wargument_mismatch,

> > -			  "Character length mismatch (%ld/%ld) between

> > actual "

> > -			  "argument and assumed-shape dummy argument %qs "

> > -			  "at %L",

> > -			  mpz_get_si

> > (a->expr->ts.u.cl->length->value.integer),

> > -			  mpz_get_si

> > (f->sym->ts.u.cl->length->value.integer),

> > -			  f->sym->name, &a->expr->where);

> > -	   return 0;

> > -	 }

> > +	  && a->expr->ts.u.cl && a->expr->ts.u.cl->length

> > +	  && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT



> > +	  && f->sym->ts.type == BT_CHARACTER && f->sym->ts.u.cl


             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> > +	  && f->sym->ts.u.cl->length

> > +	  && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT

> > +	  && (f->sym->attr.pointer || f->sym->attr.allocatable

> > +	      || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

> > +	  && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,

> > +		       f->sym->ts.u.cl->length->value.integer) != 0))

> > +	{


<snip>

> > +	  && a->expr->ts.type == BT_CHARACTER)

> >  	{

> >  	  if (where)

> >  	    gfc_error ("Actual argument at %L to allocatable or "  

> That one was just reformatting, right?


No, the check for the correct has been added at ^^^. I agree that reformatting
and the change was not a good idea. 

> 

> > @@ -3039,13 +3041,28 @@ compare_actual_formal (gfc_actual_arglist **ap,

> > gfc_formal_arglist *formal, return 0;

> >  	}

> >

> > +      /* Find the last array_ref.  */

> > +      actual_arr_ref = NULL;

> > +      if (a->expr->ref)

> > +	{

> > +	  gfc_ref *ref = a->expr->ref;

> > +

> > +	  do

> > +	    {

> > +	      if (ref->type == REF_ARRAY)

> > +		actual_arr_ref = ref;

> > +	      ref = ref->next;

> > +	    }

> > +	  while (ref != NULL);

> > +	}  

> beware, for the expression foo%c(:)%c2(1), this returns the array ref on 

> c2, not the one on c. Is it what you want?

> If not, maybe you can use gfc_find_array_ref.


Well, I am actually not quite sure, what I need here. This phase of the
compilation is quite new to me. The intention of the code above was to reliably
get the array-ref. The checks further down did not always care that the ref
they looked at (always the first one in the expression) was an array-ref. So I
tried to get the array-ref here. Can you propose a way to get the array-ref in
expressions like the one you gave suitable for the checks below? I understand
that in our example the array-ref we look at should be c(:) and not the scalar
ultimate one.
 
> > +

> >        if (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE

> >  	  && a->expr->expr_type == EXPR_VARIABLE

> >  	  && a->expr->symtree->n.sym->as

> >  	  && a->expr->symtree->n.sym->as->type == AS_ASSUMED_SIZE

> > -	  && (a->expr->ref == NULL

> > -	      || (a->expr->ref->type == REF_ARRAY

> > -		  && a->expr->ref->u.ar.type == AR_FULL)))

> > +	  && (actual_arr_ref == NULL

> > +	      || (actual_arr_ref->type == REF_ARRAY

> > +		  && actual_arr_ref->u.ar.type == AR_FULL)))  

> If I understand the code correctly, it’s trying to detect variables with 

> assumed size, but I think you break that. In the case of an expression 

> foo(1)%c(:), where foo is assumed size, the if condition would be true.


Well, I am not sure, whether I understand completely. Please mind the
background why I propose these changes: The sanitizer complained about the
code. So what would be needed to also catch expressions like bar(5)%foo(1)%c(:)?

<snip>

> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c

> > index 2e6ef2a..8173ba9 100644

> > --- a/gcc/fortran/trans-decl.c

> > +++ b/gcc/fortran/trans-decl.c

> > @@ -1019,7 +1019,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol *

> > sym) layout_type (type);

> >      }

> >

> > -  if (TYPE_NAME (type) != NULL_TREE

> > +  if (TYPE_NAME (type) != NULL_TREE && as->rank > 0  

> I suppose one should replace as->rank with as->rank + as->corank instead 

> of this.


That would not prevent the error. The as->rank > 0 is guarding the next two
line against accessing the array of ubounds with and index of -1. For a corank
to my knowledge only the lbound is set for the right-most dimension. So that
would at least access a NULL-pointer then.

From your follow-up mail:
> I remember now that rank can be negative, so your change is fine.


Well, that is not the reason the change is mandated: When the rank is 0 but a
corank is present, then the above still holds.

> 

> >        && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE

> >        && VAR_P (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)))

> >      {  

> 

> > diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c

> > index 5ca716b..d953ec8 100644

> > --- a/gcc/fortran/trans-stmt.c

> > +++ b/gcc/fortran/trans-stmt.c

> > @@ -6464,7 +6464,8 @@ gfc_trans_deallocate (gfc_code *code)

> >  		    && !(!last && expr->symtree->n.sym->attr.pointer))

> >  		{

> >  		  if (is_coarray && expr->rank == 0

> > -		      && (!last || !last->u.c.component->attr.dimension))

> > +		      && (!last || !last->u.c.component->attr.dimension)

> > +		      && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)))  

> I’m a bit surprised by the need for this. Are there cases where coarrays 

> don’t have a descriptor?


With my recently added support of allocatable components for coarrays of derived
types such an allocatable component can be a scalar. It is not a full coarray
because the coarray is one of its father objects.

I hope my comments helped a bit to shed some light why I propose these changes.
I am happy to get better solutions!

Improvements, comments and ideas are very welcome!!!

Regards,
	Andre
-- 
Andre Vehreschild * Email: vehre ad gmx dot de
Mikael Morin Dec. 10, 2016, 10:09 p.m. UTC | #4
Hello,

Le 09/12/2016 à 11:55, Andre Vehreschild a écrit :
> Hi Mikael,

>

> thanks a lot for your comments. Note I also have added the reply to your latest

> email here.

>

> On Thu, 8 Dec 2016 23:49:57 +0100

> Mikael Morin <morin-mikael@orange.fr> wrote:

>

> <snipp>

>

>>> diff --git a/gcc/fortran/data.c b/gcc/fortran/data.c

>>> index 139ce88..4f835b3 100644

>>> --- a/gcc/fortran/data.c

>>> +++ b/gcc/fortran/data.c

>>> @@ -186,7 +186,7 @@ create_character_initializer (gfc_expr *init,

>>> gfc_typespec *ts, for (i = 0; i < len; i++)

>>>  	dest[start+i] = rvalue->representation.string[i];

>>>      }

>>> -  else

>>> +  else if (rvalue->value.character.string)

>> This one looks fishy.

>> Either rvalue is a character constant and its string should be set, or

>> it’s not a character constant and the value.character.string should not

>> be accessed at all.

>

> You are completely right. This can *only* occur when invalid-code is given to

> the compiler. In this case the offending code was:

>

>  data c / = NULL() /

>

> The syntax may not be correct (just out of my head), but I hope you get the

> idea. The sanitizers complaint was that the second argument to the memcpy below

> must not be NULL. The above if () makes sure the memcpy does not get called in

> this case. So this merely to prevent the compiler from ICEing on systems whose

> memcpy is not robust.


Ok, I have been able to reproduce this case, and indeed the function is 
called with null() as rvalue expression.
But my comment still holds. Accessing rvalue->value.character.string 
when rvalue hasn’t type EXPR_CONSTANT is undefined.
A slightly better patch would use rvalue->expr_type == EXPR_CONSTANT as 
else if condition, but the problem remains earlier in the function in 
the assignment to len.
I think the function just should not be called if rvalue is null().

>

>>>      memcpy (&dest[start], rvalue->value.character.string,

>>>  	    len * sizeof (gfc_char_t));

>>>

>>> diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c

>>> index 8afba84..4e4d17c 100644

>>> --- a/gcc/fortran/interface.c

>>> +++ b/gcc/fortran/interface.c

>>> @@ -2803,6 +2803,7 @@ compare_actual_formal (gfc_actual_arglist **ap,

>>> gfc_formal_arglist *formal, int i, n, na;

>>>    unsigned long actual_size, formal_size;

>>>    bool full_array = false;

>>> +  gfc_ref *actual_arr_ref;

>>>

>>>    actual = *ap;

>>>

>>> @@ -2942,37 +2943,38 @@ compare_actual_formal (gfc_actual_arglist **ap,

>>> gfc_formal_arglist *formal, and assumed-shape dummies, the string length

>>> needs to match exactly.  */

>>>        if (a->expr->ts.type == BT_CHARACTER

>>> -	   && a->expr->ts.u.cl && a->expr->ts.u.cl->length

>>> -	   && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT

>>> -	   && f->sym->ts.u.cl && f->sym->ts.u.cl && f->sym->ts.u.cl->length

>>> -	   && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT

>>> -	   && (f->sym->attr.pointer || f->sym->attr.allocatable

>>> -	       || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

>>> -	   && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,

>>> -			f->sym->ts.u.cl->length->value.integer) != 0))

>>> -	 {

>>> -	   if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))

>>> -	     gfc_warning (OPT_Wargument_mismatch,

>>> -			  "Character length mismatch (%ld/%ld) between

>>> actual "

>>> -			  "argument and pointer or allocatable dummy

>>> argument "

>>> -			  "%qs at %L",

>>> -			  mpz_get_si

>>> (a->expr->ts.u.cl->length->value.integer),

>>> -			  mpz_get_si

>>> (f->sym->ts.u.cl->length->value.integer),

>>> -			  f->sym->name, &a->expr->where);

>>> -	   else if (where)

>>> -	     gfc_warning (OPT_Wargument_mismatch,

>>> -			  "Character length mismatch (%ld/%ld) between

>>> actual "

>>> -			  "argument and assumed-shape dummy argument %qs "

>>> -			  "at %L",

>>> -			  mpz_get_si

>>> (a->expr->ts.u.cl->length->value.integer),

>>> -			  mpz_get_si

>>> (f->sym->ts.u.cl->length->value.integer),

>>> -			  f->sym->name, &a->expr->where);

>>> -	   return 0;

>>> -	 }

>>> +	  && a->expr->ts.u.cl && a->expr->ts.u.cl->length

>>> +	  && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT

>

>

>>> +	  && f->sym->ts.type == BT_CHARACTER && f->sym->ts.u.cl

>

>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>

>>> +	  && f->sym->ts.u.cl->length

>>> +	  && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT

>>> +	  && (f->sym->attr.pointer || f->sym->attr.allocatable

>>> +	      || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))

>>> +	  && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,

>>> +		       f->sym->ts.u.cl->length->value.integer) != 0))

>>> +	{

>

> <snip>

>

>>> +	  && a->expr->ts.type == BT_CHARACTER)

>>>  	{

>>>  	  if (where)

>>>  	    gfc_error ("Actual argument at %L to allocatable or "

>> That one was just reformatting, right?

>

> No, the check for the correct has been added at ^^^. I agree that reformatting

> and the change was not a good idea.

>

>>

>>> @@ -3039,13 +3041,28 @@ compare_actual_formal (gfc_actual_arglist **ap,

>>> gfc_formal_arglist *formal, return 0;

>>>  	}

>>>

>>> +      /* Find the last array_ref.  */

>>> +      actual_arr_ref = NULL;

>>> +      if (a->expr->ref)

>>> +	{

>>> +	  gfc_ref *ref = a->expr->ref;

>>> +

>>> +	  do

>>> +	    {

>>> +	      if (ref->type == REF_ARRAY)

>>> +		actual_arr_ref = ref;

>>> +	      ref = ref->next;

>>> +	    }

>>> +	  while (ref != NULL);

>>> +	}

>> beware, for the expression foo%c(:)%c2(1), this returns the array ref on

>> c2, not the one on c. Is it what you want?

>> If not, maybe you can use gfc_find_array_ref.

>

> Well, I am actually not quite sure, what I need here. This phase of the

> compilation is quite new to me. The intention of the code above was to reliably

> get the array-ref.

That’s exactly my point, the code above doesn’t get it reliably. You 
have to exclude array element references like it’s done in 
gfc_find_array_ref for example.

> The checks further down did not always care that the ref

> they looked at (always the first one in the expression) was an array-ref. So I

> tried to get the array-ref here. Can you propose a way to get the array-ref in

> expressions like the one you gave suitable for the checks below? I understand

> that in our example the array-ref we look at should be c(:) and not the scalar

> ultimate one.

>

Well, it depends on how/where it is used.

>>> +

>>>        if (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE

>>>  	  && a->expr->expr_type == EXPR_VARIABLE

>>>  	  && a->expr->symtree->n.sym->as

>>>  	  && a->expr->symtree->n.sym->as->type == AS_ASSUMED_SIZE

>>> -	  && (a->expr->ref == NULL

>>> -	      || (a->expr->ref->type == REF_ARRAY

>>> -		  && a->expr->ref->u.ar.type == AR_FULL)))

>>> +	  && (actual_arr_ref == NULL

>>> +	      || (actual_arr_ref->type == REF_ARRAY

>>> +		  && actual_arr_ref->u.ar.type == AR_FULL)))

>> If I understand the code correctly, it’s trying to detect variables with

>> assumed size, but I think you break that. In the case of an expression

>> foo(1)%c(:), where foo is assumed size, the if condition would be true.

>

> Well, I am not sure, whether I understand completely. Please mind the

> background why I propose these changes: The sanitizer complained about the

> code. So what would be needed to also catch expressions like bar(5)%foo(1)%c(:)?

>

For example, here we want to catch assumed size arrays, which are dummy 
argument arrays, so the array ref can only be the first one.  [There is 
a side question whether assumed_size%component is assumed size, but I’m 
not sure I want to ask it.]
There is a check that the reference is an array reference, so I don’t 
see what the sanitizer complains about. I think the condition bu 
originally written is the more correct one.

Regarding the other use of actual_arr_ref, I agree that your changes is 
an improvement (with the remark above).

> <snip>

>

>>> diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c

>>> index 2e6ef2a..8173ba9 100644

>>> --- a/gcc/fortran/trans-decl.c

>>> +++ b/gcc/fortran/trans-decl.c

>>> @@ -1019,7 +1019,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol *

>>> sym) layout_type (type);

>>>      }

>>>

>>> -  if (TYPE_NAME (type) != NULL_TREE

>>> +  if (TYPE_NAME (type) != NULL_TREE && as->rank > 0

>> I suppose one should replace as->rank with as->rank + as->corank instead

>> of this.

>

> That would not prevent the error. The as->rank > 0 is guarding the next two

> line against accessing the array of ubounds with and index of -1. For a corank

> to my knowledge only the lbound is set for the right-most dimension. So that

> would at least access a NULL-pointer then.

>

> From your follow-up mail:

>> I remember now that rank can be negative, so your change is fine.

>

> Well, that is not the reason the change is mandated: When the rank is 0 but a

> corank is present, then the above still holds.

>

Ok, you win the point.
>>

>>>        && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE

>>>        && VAR_P (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)))

>>>      {

>>

>>> diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c

>>> index 5ca716b..d953ec8 100644

>>> --- a/gcc/fortran/trans-stmt.c

>>> +++ b/gcc/fortran/trans-stmt.c

>>> @@ -6464,7 +6464,8 @@ gfc_trans_deallocate (gfc_code *code)

>>>  		    && !(!last && expr->symtree->n.sym->attr.pointer))

>>>  		{

>>>  		  if (is_coarray && expr->rank == 0

>>> -		      && (!last || !last->u.c.component->attr.dimension))

>>> +		      && (!last || !last->u.c.component->attr.dimension)

>>> +		      && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)))

>> I’m a bit surprised by the need for this. Are there cases where coarrays

>> don’t have a descriptor?

>

> With my recently added support of allocatable components for coarrays of derived

> types such an allocatable component can be a scalar. It is not a full coarray

> because the coarray is one of its father objects.

>

And here as well.

Mikael
diff mbox

Patch

diff --git a/gcc/fortran/data.c b/gcc/fortran/data.c
index 139ce88..4f835b3 100644
--- a/gcc/fortran/data.c
+++ b/gcc/fortran/data.c
@@ -186,7 +186,7 @@  create_character_initializer (gfc_expr *init, gfc_typespec *ts,
       for (i = 0; i < len; i++)
 	dest[start+i] = rvalue->representation.string[i];
     }
-  else
+  else if (rvalue->value.character.string)
     memcpy (&dest[start], rvalue->value.character.string,
 	    len * sizeof (gfc_char_t));
 
diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
index 8afba84..4e4d17c 100644
--- a/gcc/fortran/interface.c
+++ b/gcc/fortran/interface.c
@@ -2803,6 +2803,7 @@  compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
   int i, n, na;
   unsigned long actual_size, formal_size;
   bool full_array = false;
+  gfc_ref *actual_arr_ref;
 
   actual = *ap;
 
@@ -2942,37 +2943,38 @@  compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
 	 and assumed-shape dummies, the string length needs to match
 	 exactly.  */
       if (a->expr->ts.type == BT_CHARACTER
-	   && a->expr->ts.u.cl && a->expr->ts.u.cl->length
-	   && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT
-	   && f->sym->ts.u.cl && f->sym->ts.u.cl && f->sym->ts.u.cl->length
-	   && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT
-	   && (f->sym->attr.pointer || f->sym->attr.allocatable
-	       || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))
-	   && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,
-			f->sym->ts.u.cl->length->value.integer) != 0))
-	 {
-	   if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))
-	     gfc_warning (OPT_Wargument_mismatch,
-			  "Character length mismatch (%ld/%ld) between actual "
-			  "argument and pointer or allocatable dummy argument "
-			  "%qs at %L",
-			  mpz_get_si (a->expr->ts.u.cl->length->value.integer),
-			  mpz_get_si (f->sym->ts.u.cl->length->value.integer),
-			  f->sym->name, &a->expr->where);
-	   else if (where)
-	     gfc_warning (OPT_Wargument_mismatch,
-			  "Character length mismatch (%ld/%ld) between actual "
-			  "argument and assumed-shape dummy argument %qs "
-			  "at %L",
-			  mpz_get_si (a->expr->ts.u.cl->length->value.integer),
-			  mpz_get_si (f->sym->ts.u.cl->length->value.integer),
-			  f->sym->name, &a->expr->where);
-	   return 0;
-	 }
+	  && a->expr->ts.u.cl && a->expr->ts.u.cl->length
+	  && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT
+	  && f->sym->ts.type == BT_CHARACTER && f->sym->ts.u.cl
+	  && f->sym->ts.u.cl->length
+	  && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT
+	  && (f->sym->attr.pointer || f->sym->attr.allocatable
+	      || (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))
+	  && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,
+		       f->sym->ts.u.cl->length->value.integer) != 0))
+	{
+	  if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))
+	    gfc_warning (OPT_Wargument_mismatch,
+			 "Character length mismatch (%ld/%ld) between actual "
+			 "argument and pointer or allocatable dummy argument "
+			 "%qs at %L",
+			 mpz_get_si (a->expr->ts.u.cl->length->value.integer),
+			 mpz_get_si (f->sym->ts.u.cl->length->value.integer),
+			 f->sym->name, &a->expr->where);
+	  else if (where)
+	    gfc_warning (OPT_Wargument_mismatch,
+			 "Character length mismatch (%ld/%ld) between actual "
+			 "argument and assumed-shape dummy argument %qs "
+			 "at %L",
+			 mpz_get_si (a->expr->ts.u.cl->length->value.integer),
+			 mpz_get_si (f->sym->ts.u.cl->length->value.integer),
+			 f->sym->name, &a->expr->where);
+	  return 0;
+	}
 
       if ((f->sym->attr.pointer || f->sym->attr.allocatable)
-	    && f->sym->ts.deferred != a->expr->ts.deferred
-	    && a->expr->ts.type == BT_CHARACTER)
+	  && f->sym->ts.deferred != a->expr->ts.deferred
+	  && a->expr->ts.type == BT_CHARACTER)
 	{
 	  if (where)
 	    gfc_error ("Actual argument at %L to allocatable or "
@@ -3039,13 +3041,28 @@  compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
 	  return 0;
 	}
 
+      /* Find the last array_ref.  */
+      actual_arr_ref = NULL;
+      if (a->expr->ref)
+	{
+	  gfc_ref *ref = a->expr->ref;
+
+	  do
+	    {
+	      if (ref->type == REF_ARRAY)
+		actual_arr_ref = ref;
+	      ref = ref->next;
+	    }
+	  while (ref != NULL);
+	}
+
       if (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE
 	  && a->expr->expr_type == EXPR_VARIABLE
 	  && a->expr->symtree->n.sym->as
 	  && a->expr->symtree->n.sym->as->type == AS_ASSUMED_SIZE
-	  && (a->expr->ref == NULL
-	      || (a->expr->ref->type == REF_ARRAY
-		  && a->expr->ref->u.ar.type == AR_FULL)))
+	  && (actual_arr_ref == NULL
+	      || (actual_arr_ref->type == REF_ARRAY
+		  && actual_arr_ref->u.ar.type == AR_FULL)))
 	{
 	  if (where)
 	    gfc_error ("Actual argument for %qs cannot be an assumed-size"
@@ -3196,14 +3213,14 @@  compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
 	}
 
       if (f->sym->attr.volatile_
-	  && a->expr->ref && a->expr->ref->u.ar.type == AR_SECTION
+	  && actual_arr_ref && actual_arr_ref->u.ar.type == AR_SECTION
 	  && !(f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))
 	{
 	  if (where)
 	    gfc_error ("Array-section actual argument at %L is "
 		       "incompatible with the non-assumed-shape "
 		       "dummy argument %qs due to VOLATILE attribute",
-		       &a->expr->where,f->sym->name);
+		       &a->expr->where, f->sym->name);
 	  return 0;
 	}
 
diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c
index e727ade..713f272 100644
--- a/gcc/fortran/module.c
+++ b/gcc/fortran/module.c
@@ -4710,6 +4710,7 @@  load_omp_udrs (void)
 
       mio_lparen ();
       mio_pool_string (&name);
+      gfc_clear_ts (&ts);
       mio_typespec (&ts);
       if (strncmp (name, "operator ", sizeof ("operator ") - 1) == 0)
 	{
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 2e6ef2a..8173ba9 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -1019,7 +1019,7 @@  gfc_build_qualified_array (tree decl, gfc_symbol * sym)
       layout_type (type);
     }
 
-  if (TYPE_NAME (type) != NULL_TREE
+  if (TYPE_NAME (type) != NULL_TREE && as->rank > 0
       && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE
       && VAR_P (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)))
     {
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 8d7e881..3064e50 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -2864,9 +2864,7 @@  gfc_conv_cst_int_power (gfc_se * se, tree lhs, tree rhs)
     return 0;
 
   m = wrhs.to_shwi ();
-  /* There's no ABS for HOST_WIDE_INT, so here we go. It also takes care
-     of the asymmetric range of the integer type.  */
-  n = (unsigned HOST_WIDE_INT) (m < 0 ? -m : m);
+  n = wi::abs (wrhs).to_shwi ();
 
   type = TREE_TYPE (lhs);
   sgn = tree_int_cst_sgn (rhs);
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 5ca716b..d953ec8 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -6464,7 +6464,8 @@  gfc_trans_deallocate (gfc_code *code)
 		    && !(!last && expr->symtree->n.sym->attr.pointer))
 		{
 		  if (is_coarray && expr->rank == 0
-		      && (!last || !last->u.c.component->attr.dimension))
+		      && (!last || !last->u.c.component->attr.dimension)
+		      && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)))
 		    {
 		      /* Add the ref to the data member only, when this is not
 			 a regular array or deallocate_alloc_comp will try to