Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29386 Discussions

Trying to catch use of uninitialized variables

ferrad
New User
5,049 Views
To return myself to a former era where I could regularly trap the use of uninitialized variables (it was in Salford...), I decided to try out the equivalent in Intel (/RTCu as per the docs).I switched it on for all files in my DLL, then ran, just to see if we had any problems. The application ran just fine without trapping anything. Being distrustful, I forced the use of an uninitialized variable and reran. But it didn't catch this. So I'm now wondering exactly how this /RTCu option is supposed to work.
My entire compilation line is:
ifort /nologo /c /iface:cvf /Z7 /Tfplacemen.for /define:INTEL9 /Qsave /Foplacemen.obj /fpconstant /real_size:64 /4Yb /RTCu /Zi /4R8
Is another option I'm using negating /RTCu?

Adrian
0 Kudos
40 Replies
Steven_L_Intel1
Employee
2,758 Views
If you're seeing nothing at all, then it may be that the compiler isn't noticing your uninitialized use. To get anything more than a "user breakpoint" error, you have to build with /dbglibs and run under the VS.NET debugger. That will change in the future.
0 Kudos
ferrad
New User
2,758 Views

I am running in the the debugger. I'm not sure about /dbglibs, I'll check into that.

Another problem: I decided to swicth on /check:all as well. The debugger brought up a window informing me that I was accessing element 0 of an array. I click OK, but nothing happens. So then I click the break button (||). It breaks, but not in my source, but in some nodebug runtime library where all I see is assembler. In CVF, clicking OK after encountering the error brought me directly to the line in the source code where the error lay. What is the problem?

BTW: I haven'tupgraded my version from that on theCD yet, maybe I need to do that?

Adrian

0 Kudos
Steven_L_Intel1
Employee
2,758 Views
The break on array bounds error is something we have also seen and are working on. Sometimes it works and sometimes it doesn't.

Yes, please do update to the current version, 9.0.025, but this won't make much difference for uninitialized variable checking, I think. (Actually, it may make it worse in that the name of the reported variable will be wrong.) But the newer version fixes many other issues.
0 Kudos
ferrad
New User
2,758 Views

I managed to upgrade to the latest version, but yes as you say, there is still the problem.

So here's my question: I am responsiblefor signaling the time for, and making the change in our organization to switch from DVF6.1 to Intel. I think both of these issues are essential for debugging (especially the ability to take the user to the problem line in the source). Maybe v9.x is not yet mature enough? Should we beswitching tov8.0 instead?

Adrian

0 Kudos
Steven_L_Intel1
Employee
2,758 Views
9.0 is much better than 8.0. My guess is that there's an undiscovered bug in your code. If you'd like us to investigate, please submit an example to Intel premier Support.
0 Kudos
ferrad
New User
2,758 Views

Yes, I'm sure there are undiscovered bugs in our code, I'm trying to find them!

You say you have seen this behavior already so I guess there's no need for me to send a specific case. How long for the fix?

Adrian

0 Kudos
jim_dempsey
Beginner
2,758 Views
Ferrad,
I have had good success in finding uninitialized variables and subscript errors using Visual Studio .NET 2003, and it's debugger. What the debugger will not catch gracefuly is when your application passes in a reference to an invalid address when calling a .DLL or other system function that does not have debug information.
When this occures look at the call stack. If the call stack appears to contain routines from your code (above stuff you don't recognise) then open the closest routine you recognize. If this is of little help then open up the Dissassembly window. You may also have to click on the yellow right arrow to get the focus in the assembly window to the line that caused the problem.
You do not have to under stand much about assembly to find statement in your Fortran program thatprecipitated the error.
The strategy to use is to"Set Next Statement" to the proper position to return from the current routine. Then single step out of the current routine. Then once properly in the context of the next level up check the call stack again. If you seeFortran routines thenclose the Disassemblywindow and click on the Yellow right arrow to find the Fortran statement.
More than likely you will have to step out of the next higher routine and keep doing so until the call stack looks like Fortran code.
Note, as you step out do not use the run until return button. As this assumes the the faulty routine that caused the break had completed it's job. Each time as you pop up a routine level then look for return code in the disassembly window and do the "Set Next Statement" thing. Repeat until you see Fortran routines in the Call Stack or until you flub-up and crash the call stack (then start over).
There are several ways assembly code performs it'sreturns. You have to be careful to place the Next Statement at the correct position in order to return properly. Examples follow:
Code:
 00475455 8B E5            mov         esp,ebp ! <- Set Next Statement here
00475457 5D               pop         ebp  
00475458 8B E3            mov         esp,ebx 
0047545A 5B               pop         ebx  
0047545B C3               ret              


Code:
0047533F C9               leave     ! <- Set Next Statemen here
00475340 C3               ret              

Or you may simply see a "ret" alone. i.e. if you see
mov esp,ebp
you must position there and single step past the ret to the caller.
failing that if you see "leave" then place the next statement there and single step to the caller. Failing that, place the next statement on the "ret" and then single step out to the caller.
Wait, not done yet. At times when you get back to the caller, the calling code may cleanup the stack of the arguments. If upon returnyou see an "add esp, nn" then you must step through that instruction before attempting to return from the next level.
Good luck bug hunting
Jim Dempsey

0 Kudos
ferrad
New User
2,758 Views

Thanks, Jim. While not pretending to follow everything you wrote, I did follow some of it, but as my call stack is probably 50 deep, and these are mostly system dll's, it is very difficult to set the correct return positions. I miss one, and it goes back right to the top again.

In the meantime, I have sent a "Show-Stopper" bug report into premier.intel.com, with an example - hopefully they'll sort it out soon. I believe it is pretty much a requirement of any debugger that it stops at the line of offending code when it encounters an exception, I'm amazed that v9.0 was released at all with this problem.

0 Kudos
Steven_L_Intel1
Employee
2,758 Views
It does stop when there is an exception. It does not stop when there is no exception.
0 Kudos
ferrad
New User
2,758 Views

Yes it stops, but not in the correct place!

Adrian

0 Kudos
ferrad
New User
2,758 Views
I get the attached window when it hits the exception. Any idea why I don't get line numbers? All files are compiled with full debug.
Adrian
0 Kudos
jim_dempsey
Beginner
2,758 Views

Although your call stack is of little use you do have an indication the the error involves a subscript error with subscript 2on ACID_CONCENTRATION. If there are only a few places where ACID_CONCENTRATION is referenced then you can place some diagnostic code that conditionaly compiles infront of the references. This can do a quick range check and bugcheck when appropriate.

Jim Dempsey

0 Kudos
ferrad
New User
2,758 Views

Yes, this is what I've being doing for 3 days now...

Unfortunately in most cases there are many references to the variable listed inthe exception window. I've being putting write statements before every occurrence, to find out which one is causing the problem. Also I can only find one at a time - I fix this one, then move onto the next. I've found 6 bits of bad code in 3 days, not a very efficient way to debug.

In my opinion, this is exactly the type of problem the Intel debugger is supposed to identify and stop (which it does), *and* point to the actual line where the problem occurs. CVF had no problem with this - it also used to give line numbers in the exception window.

Steve, please tell me this is being fixed as a matter of urgency...

Adrian

0 Kudos
Steven_L_Intel1
Employee
2,758 Views
It is being actively investigated. The problem seems to have appeared sometime after the initial 9.0 release.
0 Kudos
jim_dempsey
Beginner
2,758 Views
My experience is using VS .NET 2003 and it's debugger on WinXP and running consol apps. The array subscripting is caught and the source line shown by the debugger. What you may be experiencing is something a little different. And when you fix it in one place in your program the same problem may be throught the program. In which case you don't rely so much on the debugger to catch the errors.
The particular thing about uninitialized variables and is the exception is thrown when the variable is dereferenced. This will not catch uninitialized variables from being passed in to a stack of subroutines only to fail somewhere down deep.
Subscript errors can also occur late if you call a routine with the base of an array plus additional args that subscript the array. These typicaly will not show up as subscript errors but will show up as (usualy) data corruption errors.
Here is a nifyt little programming trick to help find your problem
1) enable the fortran preprocessor
2) locate the declaration of the array with indexing errors. e.g. YOUR_ARRAY
3) change the name of the array. e.g. was_YOUR_ARRAY
4) create subscript check functions for the indexes
function subchk1(i)
integer :: subchk1, i
if((i .lt. 1) .or. (i .gt. iMax1Whatever)) call bugcheck()
subchk1 = i
end function subchk1
function subchk1(i)
integer :: subchk1, i
if((i .lt. 1) .or. (i .gt. iMax2Whatever)) call bugcheck()
subchk2 = i
end function subchk2
function subchk3(i)
integer :: subchk1, i
if((i .lt. 1) .or. (i .gt. iMax3Whatever)) call bugcheck()
subchk3 = i
end function subchk3
5) define a macro for referencing your array. e.g.
#define YOUR_ARRAY(i,j,k) was_YOUR_ARRAY(subchk1(i),subchk2(j),subchk3(k))
Place the macro deffinition into a common header file.
With this technique you have no source code changes to catch the bug.
Other than the changes in a common header file.
Jim Dempsey
0 Kudos
Steven_L_Intel1
Employee
2,758 Views
There is a real problem that, in some circumstances, when an array bounds violation occurs that the breakpoint is in the middle of some system code and there is no way to determine where in the user code the problem occurred. I have seen this myself - but some examples show it and some do not. We do consider this a serious problem and are investigating.
0 Kudos
ferrad
New User
2,758 Views

Yes, that's exactly what I did yesterday! Seems like we old Fortran diehards have learnt all the same tricks...

The only problem with this approach is that it only works when the array isread (eg. if(subchk1(i)) then...). When it s written to, you have to change all these to the new variable name. But that wasn't such a problem, and it enabled me to catch a number of array over/underuns in one routine.

I await the fix with aniticipation...

Adrian
0 Kudos
jim_dempsey
Beginner
2,758 Views

The replacement macro works on the left side the the = too.

Code:

module aModule
    real(8) :: array(100)

contains
function TheArray(index)
    real(8) :: TheArray
    integer :: index
    TheArray = array(index)
end function TheArray

function iIndex(i)
    integer :: iIndex, i
    iIndex = i+1
end function iIndex
end module aModule

program FuncTest
    use aModule

    implicit none
    ! Variables
    integer :: i

    ! Body of FuncTest
    do i=1,10
        array(iIndex(i)) = real(i)
    end do
    do i=1,10
        write(*,*) TheArray(i)
    end do
end program FuncTest


You should see 0., 1., 2., ...

Recode the indexing functions to suit your array. You could make it generic whereby the test function also test shape, rank, etc.. as well as allocation.

The macro method is quite useful becase you can enable and disable it with one compiler variable.

Jim Dempsey


0 Kudos
Steven_L_Intel1
Employee
2,758 Views
Adrian, I tried the example you sent to Premier Support and it works for me (debugger context is fine.) I have another example where it is not. We are still investigating.
0 Kudos
jim_dempsey
Beginner
2,676 Views

Here is a better example

Code:

module aModule
    real(8) :: was_array(10)

contains
function iChk(i)
    integer :: iChk, i
    iChk = i
    if((i .lt. lbound(was_array,dim=1)) .or. (i .gt. ubound(was_array,dim=1))) then
        write(*,*) "gotcha - i=", i
#ifdef _DEBUG
        iChk = lbound(was_array,dim=1)
#else
        stop
#endif
    endif
end function iChk
end module aModule
! in common header file
#define array(i) was_array(iChk(i))
program FuncTest
    use aModule

    implicit none
    ! Variables
    integer :: i

    ! Body of FuncTest
    do i=1,10
        array(i) = real(i)
    end do
    do i=1,10
        write(*,*) array(i)
    end do
    array(0) = 0.
    array(11) = 11.
    array(-1) = -1.
end program FuncTest


Jim Dempsey


0 Kudos
Reply