Issues sending -1

I looked around and couldn’t find anything about this.

I just wasted hours trying to see why when I called a function with -1, i.e.

call foo(-1)

Inside foo, it prints that value as 1.

I cannot replicate this in a small case (I tried.)

The actual code is

call fstfield_read_emiss (LAT, iun, 'LAT', -1, -1, nsourc, datestt, 0)

where the two -1’s are for the arguments ip2 and ip3. Inside the fstfield_read_emiss function, these are read in as 1. I checked with printing them out, using the debugger, etc.

I’m 100% sure that the right line of code was being called, and that there were being read as 1. I can’t explain it.

I tried declaring an interface for that function in the caller function (this is code I got from somewhere else where they don’t define their interfaces), I then tried calling with key-value pairs, i.e.

call fstfield_read_emiss (FLD=LAT, IUN=iun, IP2=-1, IP3_TMP=-1, VAR='LAT', NSOURC=nsourc, DATESTT=datestt, KT=0)

I re-ordered some of the inputs in the key/value version just to check to see if one was “bleeding” into the other or something (was getting desperate.)

So ya, I can’t replicate it, but I can’t explain it and I’m worried it could happen again.

I’m on a CentOS 5.7 system, using PGI 12.3.

The code was compiled with -g -O0

The only way I could get it to work was to change the -1’s to variables, i.e.

ip2=-1; ip3=-1
call fstfield_read_emiss (LAT, iun, 'LAT', ip2, ip3, nsourc, datestt, 0)

Has anyone ever seen this before?

Hi khea_actua1,

Has anyone ever seen this before?

While I can’t say for sure, I can guess. In Fortran, values are passed by reference, including constant literals. In other words, you are not passing “-1” but the address to “-1” (stored in the .bss section of your program). So if the subroutine updates the variable, then “-1” will be changed.

Here’s an example:

$ cat test.f90 

program foo
    call setval(-1)
    call printval(-1)
end program

subroutine setval(ival)
   integer ival
   ival=10
end subroutine

subroutine printval(ival)
   integer ival
   print *, ival
end subroutine

$ pgf90 test.f90; a.out
           10

Do you pass a “-1” to any other routines that might be modifying it?

  • Mat

Even constants are by reference? Weird.

In this routine, it’s the first time I pass -1, but the same was occurring with the calls below it that were also sending -1.

Is there any way to check to see if that was the actual problem? (can I view the .bss section of the code somehow?)

Try calling a dummy routine at the start of your program where you pass in a “-1”. Break in this function and the set a hwatch on the variable’s address. The debugger will then break if anything is written to this address.

$ cat test.f90 

program foo
    call printval(-1)
    call setval(-1)
    call printval(-1)
end program

subroutine setval(ival)
   integer ival
   ival=10
end subroutine

subroutine printval(ival)
   integer ival
   print *, ival
end subroutine
  
$ pgf90 test.f90 -g
$ pgdbg -text a.out
PGDBG 12.3-0 x86-64 (Workstation, 8 Process)
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2012, STMicroelectronics, Inc. All Rights Reserved.
Loaded: a.out

pgdbg> b main
(1)breakpoint set at: foo line: "test.f90"@3 address: 0x4023F2 
1
pgdbg> run
libpthread.so.0 loaded by ld-linux-x86-64.so.2.
librt.so.1 loaded by ld-linux-x86-64.so.2.
libm.so.6 loaded by ld-linux-x86-64.so.2.
libc.so.6 loaded by ld-linux-x86-64.so.2.
Breakpoint at 0x4023F2, function foo, file test.f90, line 3
 #3:         call printval(-1)

pgdbg> s
Stopped at 0x40244C, function printval, file test.f90, line 15
 #15:        print *, ival

pgdbg> p &ival
(integer*4 ) 0x655814 -1
pgdbg> hwatch 0x655814 
Initial value at 0x655814 : 0x74736574ffffffff
hwatch (write) set for addresses [ 0x655814 .. 0x65581B ].
2
pgdbg> c
           -1

hwatch write: 0x655814
Previous value at 0x655814 : 0x74736574ffffffff
Current value at 0x655814 : 0x747365740000000a
Stopped at 0x402432, function setval, file test.f90, line 11
 #11:     end subroutine

pgdbg> list
 #6:     end program
 #7:     
 #8:     subroutine setval(ival)
 #9:        integer ival
 #10:        ival=10
 #11:==>> end subroutine
 #12:     
 #13:     subroutine printval(ival)
 #14:        integer ival
 #15:        print *, ival

pgdbg>

Not weird at all, in Fortran. It is common to pass subroutine arguments by reference, although the Fortran standard does not require that.

A subroutine does not know which arguments are constants and which are variables. In fact, you can have three calls to the same subroutine with, say, the third actual argument being a constant in the first call, an expression in the second, and a variable in the third.

Thus, when an expression (and, as a special case of an expression, a constant) is an actual argument, a temporary variable is created, if necessary, to hold the value of the expression, and a reference to the temporary variable (or the constant, in the special case) is passed as the actual argument. Therefore, a constant should never be used as an actual argument if the corresponding formal argument in the subprogram is liable to be changed.

Some compilers help you to catch errors of this type by giving you the option of write-protecting constants used as arguments. You can then pinpoint the source code line where the offending subroutine call is made, and rectify the code.