Array bounds check fails with 10.1/character length problem with 11.1

Array bounds check fails with 10.1/character length problem with 11.1

Hi,

we have a large Fortran project containing also a large number of old Fortran 77 routines. Now two problems occured one with the 10.1 version, another with the version 11.1.046:

1. bound check

Environment:
Compiler: ifort (IFORT) 10.1 20080312
Flags: -O2 -check all -check noarg_temp_created -fpe0 -no-ftz -error-limit 5 -traceback -fpic -no-ipo -nus -sox -assume noprotect_constants
Debugger: totalview

Now the runtime check for the array bounds failed for a specific situation:

A subroutine called for example "sub1" uses automatic arrays, the problem occurs with the array "order":

c ----------------------------------------------------------------------
      subroutine sub1(maxc,maxl,maxh,
     *		hdlins,limit,cols,lins,kcol,klin,coff,loff,yank,clear,
     *		hdtxt,ctype,cwide,cform,memoky,rdonly,trigger,order,
     *		iarray,rarray,larray,strbuf,sb,se,sl,icode,*)

      IMPLICIT NONE

c arguments
      integer	maxl,maxc,maxh,hdlins
      integer	limit,lins,cols,klin,kcol,coff,loff,yank,clear,icode
      integer	cwide(maxc),order(maxc)
...
      end subroutine

This sub is called from outside
out --> sub1(maxc=15,..)

From within this sub, another routine "sub2" is called
sub1 --> sub2

Now this "sub2" calls, nested in some subcalls, again the routine "sub1" but with different array sizes
sub2 --> ... --> sub1(maxc=12,..)

This should be no problem, since the arrays are local, the debugger proves that the adresses are different for "order" in sub1 called from sub2 and from out.

The overall call sequence is:
out
--> sub1(maxc=15,..)
----> sub2 --> ... --> sub1(maxc=12,..)
----> .. --> back to sub2
--> back to sub1

But the bound check gives a runtime failure check with:
"Subscript #1 of the array ORDER has value 13 which is greater than the upper bound of 12"

This is definitiv not true, the debugger shows the array with an upperbound of 15.

And with the g95 compiler, this error does not occur.

We solved the problem by telling the compiler "-check nobound", but this should not be a final solution.

2. character length
Its not possible to use the new 11.1 compiler because with that version we get another crucial error with wrong character length:

forrtl: severe (408): fort: (18): Dummy character variable 'OPCODE' has length 1 which is greater then actual variable length -1077594976
mtmonbot 08346C51 cssngl 11 cssngl.f90

This is the called routine:

subroutine cssngl(opcode,root,entry,column,single,error,*)
use m_cs, only: p_cs_common,cs_put_sngl,cs_get_sngl,cs_add_log
implicit none
character :: opcode
integer :: root
integer :: entry
integer :: column
integer :: single
integer :: error

if(opcode(1:1)=='P') then
call cs_put_sngl(p_cs_common,root,entry,column,single,error)
elseif(opcode(1:1)=='G') then
call cs_get_sngl(p_cs_common,root,entry,column,single,error)
else
error = -1
call cs_add_log(p_cs_common,"CSSNGL",error,"OPCODE INVALID")
endif

if(error/=0) then
return 1
endif

end subroutine

This is the call:
CALL CSSNGL('G',ROOBOU,1,5,IBMID(1),IDM,IERR,*99999)

What am I doing wrong?

Best regards,
Hendrik Dankowski

16 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Please provide complete test cases for both issues. I can't tell what the problem is based on these excerpts.

Steve

Quoting - Steve Lionel (Intel)
Please provide complete test cases for both issues. I can't tell what the problem is based on these excerpts.

Hi Steve,

I have a similar problem. Please see the attachement.

Thanks,
Zhanghong Tang

Attachments: 

AttachmentSize
Download test.zip86.43 MB

Quoting - hdankowski

subroutine cssngl(opcode,root,entry,column,single,error,*)

CALL CSSNGL('G',ROOBOU,1,5,IBMID(1),IDM,IERR,*99999)

If you want optional arguments, you must set it up with explicit interfaces, one way or another. Otherwise, you must make the argument lists match in the CALL and the subroutine. It looks like, in this case, you have the effect of receiving the address of the alternate return thunk code as the length of the character string.
With certain compilers of many years ago, the argument mis-match would have a different effect. It's a little strange to claim that this code should "work" as long as you don't use an up to date compiler.
With any compiler, new or old, if you enabled interface checking, it would be a bug if the compiler didn't diagnose this and refuse to compile.

Quoting - hdankowski
Hi,

we have a large Fortran project containing also a large number of old Fortran 77 routines.
A subroutine called for example "sub1" uses automatic arrays, the problem occurs with the array "order":

c ----------------------------------------------------------------------
      subroutine sub1(maxc,maxl,maxh,
     *		hdlins,limit,cols,lins,kcol,klin,coff,loff,yank,clear,
     *		hdtxt,ctype,cwide,cform,memoky,rdonly,trigger,order,
     *		iarray,rarray,larray,strbuf,sb,se,sl,icode,*)

      IMPLICIT NONE

c arguments
      integer	maxl,maxc,maxh,hdlins
      integer	limit,lins,cols,klin,kcol,coff,loff,yank,clear,icode
      integer	cwide(maxc),order(maxc)
...

Fortran 77 didn't permit automatic arrays, although a few compilers supported some version of it as an extension. There is no way for a current compiler to deal with code which "worked" only with some non-standard extension of a compiler from decades ago. As you saw in your second example, mis-matched argument lists are a big problem. Why not set /check options, or using -diag-enable sc, so as to start out with the compiler's own diagnosis of these problems?

Zhanghon,

You have a different problem - a coding error. When you called from C++ to Fortran, you failed to take into account that Fortran is expecing hidden arguments for character lengths at the end of the argument list. Since your C++ code does not supply this, garbage is picked up.

Add this line to the Fortran code after the declaration of name1 and name2:

!DEC$ ATTRIBUTES REFERENCE :: name1, name2

This tells Fortran to not expect lengths.

Steve

In #1, sub1 is being called recursively, but it is not declared RECURSIVE. Thus, there is no reason for the compiler to set things up to keep track of multiple simultaneous values of maxc, so the most recent one "wins". (To keep things simple, some compilers generate recursive or reentrant code even if a subroutine is not declared RECURSIVE. On such a compiler, this error might be benign.)

In #2, you are passing eight actual arguments to a subroutine with only seven dummy arguments. In this case, I believe the result is that cssngl is accepting *99999 in place of the hidden length argument for opcode. (Although the end of the argument list is perhaps the most common choice for where to put character lengths, it is not the only one. For example, some compilers put the length as the argument immediately after the address of the character argument in the argument list. On such a compiler, this error might prove benign.)

In other words, both of these examples have programming errors that might still allow the program to "work" under some implementation models, while failing miserably under others.

-Kurt

Quoting - hirchert
In #1, sub1 is being called recursively, but it is not declared RECURSIVE. Thus, there is no reason for the compiler to set things up to keep track of multiple simultaneous values of maxc, so the most recent one "wins". (To keep things simple, some compilers generate recursive or reentrant code even if a subroutine is not declared RECURSIVE.

Fortran 77 didn't support recursion or automatic arrays. This could work with certain f77 compilers, likely requiring a special option to support it. Supplying the RECURSIVE declaration would avoid depending on such options, and is required according to Fortran standard. Your automatic array would be over-written in each instance of recursion, as Kurt explained, but RECURSIVE would correct this.

Quoting - tangzhanghong98

I have a similar problem. Please see the attachement.

Fortran USE iso_c_interop
provides a standard means to avoid hidden character length arguments, so as to fix your argument parameter number mis-match.

Quoting - tim18

Fortran USE iso_c_interop
provides a standard means to avoid hidden character length arguments, so as to fix your argument parameter number mis-match.

I think you mean USE ISO_C_BINDING, but that isn't helpful here as it is just a set of declarations. You're really thinking of BIND(C), and it SHOULD cause the compiler to avoid hidden arguments, but in today's release, it doesn't. It will in the update later this month (mostly) - be sure to read the release notes for details when it comes out. There are still some issues, such as with functions retiurning COMPLEX, where the compiler doesn't always do the right thing.

Steve

Quoting - Steve Lionel (Intel)
Zhanghon,

You have a different problem - a coding error. When you called from C++ to Fortran, you failed to take into account that Fortran is expecing hidden arguments for character lengths at the end of the argument list. Since your C++ code does not supply this, garbage is picked up.

Add this line to the Fortran code after the declaration of name1 and name2:

!DEC$ ATTRIBUTES REFERENCE :: name1, name2

This tells Fortran to not expect lengths.

Hi Steve,

Thank you very much for your kindly reply. If the Fortran code can't be modified, what should I do in C++ code?

Thanks,
Zhanghong Tang

You need to pass the values 1 and 2 by value at the end of the argument list. I think this modification to stdafx.h would do it:

extern "C" void FTEST(int *n1, char *name1, int *n2, char *name2, double *a,double *b, int size1, int size2);
// TODO: reference additional headers your program requires here

class ctest
{
public:
	void mytest(int n1,char *name1,int n2,char *name2,double *a,double *b)
	{
		FTEST(&n2,name1,&n2,name2,a,b,1,2);
	}

Those "int" declarations for size1 and size2 should really be some type that is 32-bits on a 32-bit system and 64-bits on a 64-bit system. I am sure there is a C type for that but I don't know what it is offhand.

Steve

long int is a 32-bit type on 32-bit linux, and 64-bit on 64-bit linux. Ditto for size_t, and some pointer types. I fear the reasoning here is obscure.

Hi,

thanks to all of you, it was very helpful!

#1: bound check
In fact the recursive calling of the routine was a llittle bit hidden. But anyway it works, the debugger shows that different (first adress) automatic arrays are allocated on entry. The code works perfectly, F77 allows recursive calling of function without explicitly stating this. I attached a screenshot from debugging, it shows the bound check error on the left ("order" of size 12) and the array size determined by the debugger on the right (15).

#2: character length
My fault, I didn't really see the wrong argument list. Surprisingly it worked for years .. but there are a lot dirty things possible with F77 :-)
Would be great if this can be checked by the compiler someday.

Let me finish with some further questions:

1. IIs there any plan in the near future to introduce parameterized datatypes (PDT)?

2. And is there actually any drawbank in performance by using allocatable instead of static arrays in regard of looping these arrays? I actually performed some simple tests and there was not much difference. Are allocatable array elements sequentially stored in memory?

Thanks again,
Hendrik

Attachments: 

AttachmentSize
Download boundcheck.png189.34 KB
Best Reply

PDT is probably one of the last features we'll implement. It has been vexing for all of the vendors so far.

As for allocatable vs. static, allocatable arrays are allocated sequentially but there will be a small overhead due to having to look in the descriptor for address information. Most applications won't notice that.

Steve

Hi,

I just wanted to add my solutions to the described problems:

#1 array bound check: adding the "recursive" statement to the subroutine, even though this is not F77 std, fixed the bound check,

#2 the parameter calling list was wrong, correcting it fixed the problem.

Regards,
Hendrik

Login to leave a comment.