Silverfrost Forums

Welcome to our forums

Spurious integer overflow: Short new reproducer

8 Nov 2022 7:25 (Edited: 8 Nov 2022 12:27) #29596

Paul,

I have succeeded in constructing a short reproducer for the false integer overflow bug that I reported recently ( http://forums.silverfrost.com/viewtopic.php?p=33464 ). The new reproducer is straight Fortran 77, with less than 100 lines. To see the bug, please compile with /check, link and run. The program aborts with integer overflow on line 71.

Thanks.

      program main

      implicit none
      integer  lrw, neq
      real     y(2), rwork(50)
      EXTERNAL fsub
!
      lrw  = 50
      neq  = 2
      y(1) = 2.0
      y(2) = 0.0
      call dvode (fsub, neq, y, rwork, lrw)
      stop
!
      end !program main

      subroutine dvode(func, neq, y, rwork, lrw)

      implicit none
      integer   neq, lrw, i, lf0
      real      y(neq), rwork(lrw)
      integer   n, lewt, lyh

      EXTERNAL func

      n = neq
      lyh = 21
      lewt = lyh + 13*n
      lf0 = lyh + n
      call func (y, rwork(lf0))
      do i = 1,n
         rwork(lyh+i-1) = y(i)
      end do
      do i = 1, n
         rwork(i+lewt-1) = 1.0e6
         rwork(lf0+i-1) = 3.0e-6*rwork(lf0+i-1)
      end do
      call dvstep (y, rwork(lyh), n, func)   ! section of 1-D work array passed for 2-D array in callee
      return

      end !subroutine dvode

      subroutine dvstep(y, yh, ldyh, func)

      implicit none
      integer   ldyh
      real      y(2), yh(ldyh,2)

      integer i

      EXTERNAL func

      do i = 1, ldyh
          yh(i,1) = yh(i,1) + yh(i,2)
      end do
      call dvnlsd (y, yh, ldyh, func)
      return

      end !subroutine dvstep
!
!the subroutine arg func is not used in this bug reproducer, but needs to be present
!to preserve the overflow bug
!
      subroutine dvnlsd(y, yh, ldyh, func)

!      implicit none  ==>> activating this line makes bug disappear
      integer  ldyh
      real     y(ldyh), yh(ldyh,*) !replacing '*' by 2 makes bug disappear

      EXTERNAL func
      call dcopy (2, yh(1, 1), y) ! Integer overflow here with /check
      stop 'Normal completion'

      end !subroutine dvnlsd

      subroutine dcopy(n, dx, dy)

      implicit none
      integer  n, i
      real     dx(n), dy(n)

      do i = 1, n
         dy(i) = dx(i)
      end do

      return
      end !subroutine dcopy

      subroutine fsub(y, ydot)

      implicit none
      real  y(2), ydot(2)

      ydot(1) = y(2)
      ydot(2) = 3.0*(1.0 - y(1)*y(1))*y(2) - y(1)

      return
      end !subroutine fsub
8 Nov 2022 10:07 #29599

mecej4,

In subroutine dvnlsd(y, yh, ldyh, func) You define EXTERNAL func, but the function is never used/referenced. Have you made the reproduced too brief ?

Also, fsub is a subroutine, not a function. I have only used EXTERNAL for a function in the very limited cases where I have used EXTERNAL to define a dummy argument.

Is this an extension to the use of EXTERNAL for a dummy subroutine name ?

8 Nov 2022 10:33 #29600

mecej4

Thank you for the new reduced code.

In the main program fsub is passed as an argument in the call to dvode. In dvode fsub (now func) is passed as an argument in the call to dvstep. In dvstep func is passed as an argument in the call to dvnlsd. dvnlsd has a 'star-sized' assumed size array yh.

Part of /CHECK mode works by passing extra arguments to provide array bounds checking but the compiler should suppress this check when calling a subroutine that is passed an argument. It looks like this program is just too complex for the compiler and only part of the checking code has been planted.

This issue is on the list for further investigation but in the meantime /inhibit_check 5 (or 6) must be used for this program when using /check.

8 Nov 2022 12:55 (Edited: 8 Nov 2022 2:05) #29601

Quoted from JohnCampbell ..., fsub is a subroutine, not a function. I have only used EXTERNAL for a function in the very limited cases where I have used EXTERNAL to define a dummy argument.

Is this an extension to the use of EXTERNAL for a dummy subroutine name ?

John, thanks for your interest. We may think of EXTERNAL as a type similar to CHARACTER or LOGICAL. The only 'arithmetic' that one can do with this type is to CALL it, JUMP to it (not in Fortran, but in assembly) or pass it along. EXTERNAL serves to prevent one from applying implicit typing rules to such a variable. There was no other means of describing it in early versions of Fortran, prior to the introduction of INTERFACE declarations. You may find the following quotation (page 7.6, PDF page 84) from the DEC-10 Fortran manual http://www.bitsavers.org/www.computer.museum.uq.edu.au/pdf/DEC-10-AFDO-D%20decsystem10%20FORTRAN%20IV%20Programmer%27s%20Reference%20Manual.pdf quite clear:

(http://www.bitsavers.org/www.computer.museum.uq.edu.au/pdf/DEC-10-AFDO-D%20decsystem10%20FORTRAN%20IV%20Programmer%27s%20Reference%20Manual.pdf) quite clear:

[quote:5ba60c0e8f]7.7 EXTERNAL STATEMENT

FUNCTION and SUBROUTINE subprogram names may be used as the actual arguments of subprograms. Such subprogram names must be distinguished from ordinary variables by their appearance in an EXTERNAL statement. The EXTERNAL statement has the form:

EXTERNAL identifier , identifier, .•• , identifier

This statement declares the listed identifiers to be subprogram names. Any subprogram name given as an argument to another subprogram must have previously appeared in an external declaration in the calling program (i.e., as an identifier in an EXTERNAL or CALL statement or as a function name in an expression).

Note that this description does not attempt to make any distinction between subroutines versus functions. In C, the matter is handled by providing the void type declaration, the comma operator, etc.

For the nonsensical context in my bug reproducer, EXTERNAL is syntactic sugar. Its presence may also serve as a 'keep away' warning to a future programmer who may be tempted to misuse such a non-data-type variable in arithmetic expressions.

8 Nov 2022 1:34 #29602

Quoted from PaulLaidler mecej4

... This issue is on the list for further investigation but in the meantime /inhibit_check 5 (or 6) must be used for this program when using /check.

Thanks, Paul. Specifying /inhibit_check 5 seems to have no effect with this code -- this is probably as it should be, since there are no argument type/size mismatches in the test program. However, /inhibit_check 6 did work.

The compiler is rather rigid about the placement of options in the command line.

It rejects the following version:

T:\ODE\LLNLVODE\V90\CULL>ftn95 /check /inhibit_check 5 sovfl.f
[FTN95/Win32 Ver. 8.92.0 Copyright (c) Silverfrost Ltd 1993-2022]
*** No source file specified
*** Usage: ftn95 <file-name> [/option [/option ...]]
*** Or:    ftn95 /? for more information on command-line options.

but accepts

T:\ODE\LLNLVODE\V90\CULL>ftn95 sovfl.f /check /inhibit_check 5
[FTN95/Win32 Ver. 8.92.0 Copyright (c) Silverfrost Ltd 1993-2022]
    NO ERRORS  [<MAIN> FTN95 v8.92.0]
    NO ERRORS  [<DVODE> FTN95 v8.92.0]
    NO ERRORS  [<DVSTEP> FTN95 v8.92.0]
WARNING T:\ODE\LLNLVODE\V90\CULL\sovfl.F 63:  The argument FUNC has not been used
    NO ERRORS, 1 WARNING  [<DVNLSD> FTN95 v8.92.0]
    NO ERRORS  [<DCOPY> FTN95 v8.92.0]
    NO ERRORS  [<FSUB> FTN95 v8.92.0] 
8 Nov 2022 2:23 #29603

Quoted from PaulLaidler mecej4

In **dvstep ** **func **is passed as an argument in the call to dvnlsd. **dvnlsd **has a 'star-sized' assumed size array yh.

Part of /CHECK mode works by passing extra arguments to provide array bounds checking but the compiler should suppress this check when calling a subroutine that is passed an argument.

Putting these comments from you together with what I saw in the assembly window of SDBG in the location where the overflow occurs gives me an idea for a potential solution.

Usually, when a Fortran program contains '' in the declarations of array dummy arguments, checking whether subscripts in that dimension are within bounds is not possible with the limited information available. The '' is equivalent to the programmer telling the compiler, 'Don't bother checking the bounds for that specific variable'. When the compiler-inserted checking code loads the array bound into a register, for such a 'star-sized' argument it will probably load 0x80808080 in the 32-bit case and 0x8080808080808080 in the 64-bit case. It could add a couple of instructions in the subscript checking code to test for this 'undefined' signifier 0x80808080, and suspend the subscript range checking for that particular argument when a match occurs. Once this value is detected, it is inevitable that multiplying by 4 or 8 (byte sizes for scalar integer/real, double real) will cause integer overflow.

8 Nov 2022 4:08 #29604

mecej4

In the latest version of FTN95 (8.92), inhibiting 5 also inhibits 6 and vice-versa. This might change in the future.

FTN95 /check will check the bounds for star-sized arrays but the cleverness involved in do this could be the root of the current failure.

p.s. It might be the latest version on my machine not v8.92.

Please login to reply.