Steve Hatcher
Steve Hatcher

Reputation: 715

Where is FORTRAN getting these values from?

I am an absolute beginner to FORTRAN and am painstakingly converting a 1000 line FORTRAN source file to MATLAB for my own use. I have been going fine so far by putting in heaps of PRINT statements to keep track of variables and ensure the maths is working correctly. I have come to a strange happening in FORTRAN which I cannot work out.

There is a subroutine which is defined as so

subroutine addprc 
complex tmat,b,ci,c1,c2,cim,ab1(50),ab2(50),acans(10,2),fg1(50),fg2(50)
common dtr,rtd,pi 
common /mtxcom/ nrank,nranki,tmat(50,50),b(50,50),cmxnrm(25)
common /cmvcom/ nm,kmv,cmv,twm,prodm 

There is a bit more common and dimension allocations below but they shouldn't be relevant. The very first time the ab1(50) array is defined is in this subroutine. For my MATLAB script I have initialized it as ab1=zeros(1,50);. It is then used in this loop (in FORTRAN):

do 20 n = 1,nrank 
np = n+nrank 
cn = real(n)
n1 = n+1 
c1 = 4.0*ci**n 
c2 = 4.0*ci**n1 
p1 = cn*costh*pnmllg(n1)-(cn+cmv)*pnmllg(n) 
p2 = cmv*pnmllg(n1) 
ab1(n-ij) = c1*p2*uu1 
ab1(np-ijt) = -c2*p1*uu1 
ab2(n-ij) = -c1*p1*uu2 
ab2(np-ijt) = c2*p2*uu2 

I have checked the values of all the other variables at this point and they agree with my MATLAB script. Working backwards I have discovred the problem that somehow the ab1 already contains values. A print command just before the loop e.g.

PRINT *,'before ab1', SUM(ab1)
do 20 n = 1,1

returns (107.500008, 5.38305187). It is a complex number so the two values are fine, but whats not fine is the fact it has anything in it at all? Infact the only time ab1 is used at all is in this block of code.

Is there anything I am missing here? I looked in the source file (ctrl-f: ab1) to find any instances of it. The original source is a .for file, and I have compiled them under Eclipse using gfortran. Thanks for your time.

Upvotes: 0

Views: 438

Answers (2)

Hristo Iliev
Hristo Iliev

Reputation: 74455

ab1 is small array (50 * 8 = 400 bytes) and is therefore most likely allocated on the program stack. The stack is used to store local variables as well as the return address of the caller whenever a subroutine is called. Initially the stack pages contain all zeros but as subroutines get called it grows and is populated with some numbers. Later when the subroutine returns the stack pointer is changed but the values remain on the stack and are later overwritten by the new calls. When ab1 is allocated, its memory would initially be populated with old stack values that come from previously called subroutines. Most FORTRAN compilers do not generate by default instructions to initialise stack variables as it could be an expensive operation.

If your program is completely deterministic, i.e. there are no subroutine calls that depend on the value of some (pseudo-)random numbers or the initial PRNG seed is always the same, then sans the return addresses all other content of the stack is going to be the same between many executions of your program, e.g. one in the evening and one in the morning.

That's why SUM(ab1) always returns (107.500008, 5.38305187). And it is actually a GoodThing(tm) - it shows that your computer is a deterministic device, i.e. it reproduces the output given the same algorithm and the same input and therefore could be used to execute programming tasks. This is also a BadThing(tm) since predictable stack values lie in the base of many attacks on the OS security, but that lies way outside the scope of your problem.

Upvotes: 2

ZyX
ZyX

Reputation: 53644

Just wondering: what you would expect there instead?

These values come from memory. When you call something (function/program/subroutine) that defines a variable some piece of memory is associated with defined variable, but until you assign something to the variable it will use whatever was present in memory before. As computer memory is constantly being reused without being reset you may get there value from a variable from the other called function/subroutine that already ended, a piece of memory from other process (with the exception of some pages that must be emptied by kernel as they may contain private data) or anything else. The general rule is that nobody will do such an expensive operation as setting memory to some value unless he deadly needs this (e.g. like here where you do set memory associated with variables to numbers you need or when not erasing memory is a potential security flaw).

As a summary: these values come from uninitialized memory. Exact contents is undefined.

You do not get errors at accessing uninitialized memory because checking whether memory is initialized is a very expensive operation. But there are tools that will show you errors in this case:

  1. If you want to know whether your program accesses uninitialized memory you may run it under valgrind. Note that such checks are very expensive: under valgrind you easily get your program running worse then an order of magnitude slower.
  2. There is also clang MemorySanitizer filter that claims to do this job with only 3x slowdown, but you will need to translate fortran program to C (e.g. with f2c) before using clang as it is C/C++ compiler. You also need to compile all libraries your program uses with clang with this filter enabled.

Upvotes: 1

Related Questions