[Fortran,F08] PR 85537: Invalid memory reference at runtime when calling subroutine through procedure pointer

Message ID CAKwh3qgMxH74fKko6gQd3Y79iAdctWWmTdWYRws6K2=u1eXcPQ@mail.gmail.com
State New
Headers show
Series
  • [Fortran,F08] PR 85537: Invalid memory reference at runtime when calling subroutine through procedure pointer
Related show

Commit Message

Janus Weil March 27, 2019, 9:35 p.m.
Hi all,

the attached patch implements some missing constraints from Fortran
2008 concerning procedure pointer initialization (cf. the standard
quote in comment #18), thus fixing two accepts-invalid and
ICE-on-invalid problems.

It regtests cleanly on x86_64-linux-gnu. Ok for trunk?

Cheers,
Janus

Comments

Steve Kargl March 27, 2019, 9:51 p.m. | #1
On Wed, Mar 27, 2019 at 10:35:33PM +0100, Janus Weil wrote:
> 

> the attached patch implements some missing constraints from Fortran

> 2008 concerning procedure pointer initialization (cf. the standard

> quote in comment #18), thus fixing two accepts-invalid and

> ICE-on-invalid problems.

> 

> It regtests cleanly on x86_64-linux-gnu. Ok for trunk?


Looks OK to me.  Just minor comment.  If there are numbered
constraints in either F2008 or F2018 for each of the if()
conditionals, can you add a comment.  Perhaps, something
like.

         /* F2008:C1089. */
> +      if (attr.proc == PROC_INTERNAL)

> +	{

> +	  gfc_error ("Internal procedure %qs is invalid in "

> +		     "procedure pointer initialization at %L",

> +		     rvalue->symtree->name, &rvalue->where);

> +	  return false;

> +	}


         /* F2008:C1142. */
> +      if (attr.dummy)

> +	{

> +	  gfc_error ("Dummy procedure %qs is invalid in "

> +		     "procedure pointer initialization at %L",

> +		     rvalue->symtree->name, &rvalue->where);

> +	  return false;

> +	}

>      }


-- 
Steve
20170425 https://www.youtube.com/watch?v=VWUpyCsUKR4
20161221 https://www.youtube.com/watch?v=IbCHE-hONow
Thomas Koenig March 27, 2019, 9:54 p.m. | #2
Hi Janus,

> the attached patch implements some missing constraints from Fortran

> 2008 concerning procedure pointer initialization (cf. the standard

> quote in comment #18), thus fixing two accepts-invalid and

> ICE-on-invalid problems.


I do not think this is correct.

F2008:

# 12.2.2.4 Procedure pointers

#  A procedure pointer is a procedure that has the EXTERNAL and POINTER
# attributes; it may be pointer associated with an external procedure, # 
# an internal procedure, [...]

So a procedure pointer can be associated with an internal procedure.

Comment#18 from the PR does not quote anything that says that
a procedure pointer cannot be associated with an internal procedure.

Also, for clarification, see Note 12.8, which states

# An internal procedure cannot be invoked using a procedure pointer from
# either Fortran or C after the host instance completes execution,
# because the pointer is then undefined. While the host instance is
# active, however, the internal procedure may be invoked from outside of
# the host procedure scoping unit if that internal procedure was passed
# as an actual argument or is the target of a procedure pointer.

So, we have to support this.

Regards

	Thomas
Janus Weil March 27, 2019, 10:12 p.m. | #3
Hi Steve,

> > the attached patch implements some missing constraints from Fortran

> > 2008 concerning procedure pointer initialization (cf. the standard

> > quote in comment #18), thus fixing two accepts-invalid and

> > ICE-on-invalid problems.

> >

> > It regtests cleanly on x86_64-linux-gnu. Ok for trunk?

>

> Looks OK to me.  Just minor comment.  If there are numbered

> constraints in either F2008 or F2018 for each of the if()

> conditionals, can you add a comment.


I fully agree. Luckily the reference to F08:C1220 is already present
in gfc_check_assign_symbol (but unfortunately not visible in the
diff), and it applies in the same way to the one IF clause that is
already there as well as the two new ones I'm adding, which is why I'm
not putting in an additional reference.

Cheers,
Janus
Janus Weil March 27, 2019, 10:22 p.m. | #4
Hi Thomas,

> > the attached patch implements some missing constraints from Fortran

> > 2008 concerning procedure pointer initialization (cf. the standard

> > quote in comment #18), thus fixing two accepts-invalid and

> > ICE-on-invalid problems.

>

> I do not think this is correct.

>

> F2008:

>

> # 12.2.2.4 Procedure pointers

>

> #  A procedure pointer is a procedure that has the EXTERNAL and POINTER

> # attributes; it may be pointer associated with an external procedure, #

> # an internal procedure, [...]

>

> So a procedure pointer can be associated with an internal procedure.

>

> Comment#18 from the PR does not quote anything that says that

> a procedure pointer cannot be associated with an internal procedure.


Absolutely, a procedure pointer can in principle be associated with an
internal procedure, and my patch does not change that. What the patch
rejects is the ('static' in the C sense) pointer initialization of a
procedure pointer with an internal procedure, which is forbidden per
F2008:C1220.

procedure(..), pointer :: pp => internal_proc

A normal pointer assignment is still allowed per F2008:C729:

pp => internal_proc

Hope you agree (and sorry for not being more verbose in my explanation
in the first place).

Cheers,
Janus
Steve Kargl March 27, 2019, 10:24 p.m. | #5
On Wed, Mar 27, 2019 at 11:12:38PM +0100, Janus Weil wrote:
> Hi Steve,

> 

> > > the attached patch implements some missing constraints from Fortran

> > > 2008 concerning procedure pointer initialization (cf. the standard

> > > quote in comment #18), thus fixing two accepts-invalid and

> > > ICE-on-invalid problems.

> > >

> > > It regtests cleanly on x86_64-linux-gnu. Ok for trunk?

> >

> > Looks OK to me.  Just minor comment.  If there are numbered

> > constraints in either F2008 or F2018 for each of the if()

> > conditionals, can you add a comment.

> 

> I fully agree. Luckily the reference to F08:C1220 is already present

> in gfc_check_assign_symbol (but unfortunately not visible in the

> diff), and it applies in the same way to the one IF clause that is

> already there as well as the two new ones I'm adding, which is why I'm

> not putting in an additional reference.

> 


Ah, ok.  Thanks for the reply.

-- 
Steve
Steve Kargl March 27, 2019, 10:28 p.m. | #6
On Wed, Mar 27, 2019 at 11:22:49PM +0100, Janus Weil wrote:
> 

> > > the attached patch implements some missing constraints from Fortran

> > > 2008 concerning procedure pointer initialization (cf. the standard

> > > quote in comment #18), thus fixing two accepts-invalid and

> > > ICE-on-invalid problems.

> >

> > I do not think this is correct.

> >

> > F2008:

> >

> > # 12.2.2.4 Procedure pointers

> >

> > #  A procedure pointer is a procedure that has the EXTERNAL and POINTER

> > # attributes; it may be pointer associated with an external procedure, #

> > # an internal procedure, [...]

> >

> > So a procedure pointer can be associated with an internal procedure.

> >

> > Comment#18 from the PR does not quote anything that says that

> > a procedure pointer cannot be associated with an internal procedure.

> 

> Absolutely, a procedure pointer can in principle be associated with an

> internal procedure, and my patch does not change that. What the patch

> rejects is the ('static' in the C sense) pointer initialization of a

> procedure pointer with an internal procedure, which is forbidden per

> F2008:C1220.

> 

> procedure(..), pointer :: pp => internal_proc

> 

> A normal pointer assignment is still allowed per F2008:C729:

> 

> pp => internal_proc

> 

> Hope you agree (and sorry for not being more verbose in my explanation

> in the first place).

> 


Just to add to the confusion/clarification.  Janus's patch
is concerned with an initial-proc-target, which is has restriction
that do not apply to a proc-target.

-- 
Steve
Thomas Koenig March 27, 2019, 10:32 p.m. | #7
Am 27.03.19 um 22:54 schrieb Thomas Koenig:
> I do not think this is correct.


... and I missed the point that this was specifically about
initializations.

So, OK from my side.  Thanks!

Regards

	Thomas
Janus Weil March 27, 2019, 10:41 p.m. | #8
Am Mi., 27. März 2019 um 23:32 Uhr schrieb Thomas Koenig
<tkoenig@netcologne.de>:
>

> Am 27.03.19 um 22:54 schrieb Thomas Koenig:

> > I do not think this is correct.

>

> ... and I missed the point that this was specifically about

> initializations.

>

> So, OK from my side.  Thanks!


Great. Thanks for the reviews, everyone! Committed to trunk as r269980.

Cheers,
Janus

Patch

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index e1fdb93f3d0..372c517487f 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,9 @@ 
+2019-03-27  Janus Weil  <janus@gcc.gnu.org>
+
+	PR fortran/85537
+	* expr.c (gfc_check_assign_symbol): Reject internal and dummy procedures
+	in procedure pointer initialization.
+
 2019-03-27  Paul Thomas  <pault@gcc.gnu.org>
 
 	PR fortran/88247
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index f54affae18d..478a5557723 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -4407,6 +4407,20 @@  gfc_check_assign_symbol (gfc_symbol *sym, gfc_component *comp, gfc_expr *rvalue)
 		     "may not be a procedure pointer", &rvalue->where);
 	  return false;
 	}
+      if (attr.proc == PROC_INTERNAL)
+	{
+	  gfc_error ("Internal procedure %qs is invalid in "
+		     "procedure pointer initialization at %L",
+		     rvalue->symtree->name, &rvalue->where);
+	  return false;
+	}
+      if (attr.dummy)
+	{
+	  gfc_error ("Dummy procedure %qs is invalid in "
+		     "procedure pointer initialization at %L",
+		     rvalue->symtree->name, &rvalue->where);
+	  return false;
+	}
     }
 
   return true;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0679cb72e52..f6df0b1281c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@ 
+2019-03-27  Janus Weil  <janus@gcc.gnu.org>
+
+	PR fortran/85537
+	* gfortran.dg/dummy_procedure_11.f90: Fix test case.
+	* gfortran.dg/pointer_init_11.f90: New test case.
+
 2019-03-27  Richard Biener  <rguenther@suse.de>
 
 	* gcc.dg/torture/20190327-1.c: New testcase.
diff --git a/gcc/testsuite/gfortran.dg/dummy_procedure_11.f90 b/gcc/testsuite/gfortran.dg/dummy_procedure_11.f90
index f51c5455c05..3e4b2b1d6f0 100644
--- a/gcc/testsuite/gfortran.dg/dummy_procedure_11.f90
+++ b/gcc/testsuite/gfortran.dg/dummy_procedure_11.f90
@@ -5,16 +5,18 @@ 
 ! Contributed by Vladimir Fuka <vladimir.fuka@gmail.com>
 
 type :: t
-  procedure(g), pointer, nopass :: ppc => g
+  procedure(g), pointer, nopass :: ppc
 end type
 
-procedure(g), pointer :: pp => g
+procedure(g), pointer :: pp
 type(t)::x
 
 print *, f(g)
 print *, f(g())      ! { dg-error "Expected a procedure for argument" }
+pp => g
 print *, f(pp)
 print *, f(pp())     ! { dg-error "Expected a procedure for argument" }
+x%ppc => g
 print *, f(x%ppc)
 print *, f(x%ppc())  ! { dg-error "Expected a procedure for argument" }
 
diff --git a/gcc/testsuite/gfortran.dg/pointer_init_11.f90 b/gcc/testsuite/gfortran.dg/pointer_init_11.f90
new file mode 100644
index 00000000000..3113e157687
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pointer_init_11.f90
@@ -0,0 +1,44 @@ 
+! { dg-do compile }
+!
+! PR 85537: [F08] Invalid memory reference at runtime when calling subroutine through procedure pointer
+!
+! Contributed by Tiziano Müller <dev-zero@gentoo.org>
+
+module m1
+    implicit none
+contains
+    subroutine foo()
+      integer :: a
+
+      abstract interface
+        subroutine ibar()
+        end subroutine
+      end interface
+
+      procedure(ibar), pointer :: bar_ptr => bar_impl  ! { dg-error "invalid in procedure pointer initialization" }
+
+    contains
+      subroutine bar_impl()
+        write (*,*) "foo"
+        a = a + 1
+      end subroutine
+
+    end subroutine
+end module
+
+
+module m2
+    implicit none
+contains
+    subroutine foo(dbar)
+      interface
+        subroutine dbar()
+        end subroutine
+      end interface
+
+      procedure(dbar), pointer :: bar_ptr => dbar  ! { dg-error "invalid in procedure pointer initialization" }
+
+      call bar_ptr()
+
+    end subroutine
+end module