Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Deallocation of pointer failes

Status
Not open for further replies.

gummibaer

Programmer
Jan 5, 2007
394
DE
I am using a lot of linked lists in my prog and usually apply a certain procedure to deallocate them when no longer needed. But with this one list, this does not work. It sends my program crashing with the message 'debug assertion failed' from windows VisualC++ library.

the code, that has worked with dozens of other lists is

Code:
    ppTPTTemp => ppTPTHead                       !(1)
    do while (associated (ppTPTTemp))            !(2)
        ppTPTTemp => ppTPTTemp.pNext             !(3)
        deallocate (ppTPTHead, stat = irslt)     !(4)
        ppTPTHead => ppTPTTemp                   !(5)
   enddo                                         !(6)
   nullify (ppTPTTail)                           !(7)

This is supposed to set the temporary pointer to the head of the list (1), then, while it is associated, it is set to the next element. The head of the list gets deallocated (4) and the head-pointer is then set to the temporary pointer (5). Then, as long as the temporary pointer (and headpointer) are allocated the loop runs, deleteing the linked list from head to tail. Finally the tail gets nulliffied.

In this occasion however I get the a.m. error on the first deallocation of the head-pointer. When running in the debugger I can witness, that after execution of line (3) the headpointer is still pointing to valid data, but still the prog crashes in line (4). (The debugger moves to some assembler code then that I could not make head or tail of). The crash is that hard, that I do not get any information from the stat = irslt clause when I tried to check the returned value (these lines are not shown here).

What could be the problem here ?

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Hhhhmmm...I have never worked with pointers in Fortran and I have not used C in a loooong time.

So, pointer still pointing to data after line 3...I presume you already discarded the possibility of a spelling error? Is that truly pNext? or should it be just Next?

Other than that, I am afraid I can't be of much help.
 
Most of the time, when a deallocation fails in a well tested code part, it means that a memory error occurs before, sometimes at a totally different location.

I suggest the use of the tool valgrind, as well as the usual "checkbound" compiling option

François Jacq
 
Germàn,
this my private naming convention and is not a typo (;-). I add a p to any name of a pointer to indicate a pointer, pp means this is a pointer but defined in a module and available in more than one routine, while p indicates a local one or one within a derived type. T indicates this is a pointer to a derived type. I am not just a little happy that I managed to build a comprehensive naming convention for my current project right from the start so I can recognise the type of any of my variables at one glance. (If someone would ask me......)

Francois
Is valgrind available for FORTRAN in a Windows environment ? Wikipedia says only Linux and Mac ??

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Have you had a look at the compiler options. There isn't much but under compiler options, you could try
[ul]
[li]switching on floating point stack check[/li]
[li]initialize stack values to an unusual value[/li]
[li]Yes to everything under Run-time[/li]
[/ul]
 
Thanks folks.

As I continued my work I had to modify some code that deals with the linked list, evaluates values, enlarges and reduces it and such stuff, I had this piece of code commented off. Making it active again deletion of the list works fine now.

Well, on first sight this is fine, buuuut as I do not know which modification of my code brought it around this leaves me with a kind of unearthly feeling. For all I know, I did not do anything to affect the list's head or tail. So I can only hope - not ensure by certain steps - this never comes back.

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Well, good luck; but, this does look like a typical symptom of a memory problem, too...you move code around and the problem goes away...at least, the problem you were looking at...maybe a memory problem will pop-up somewhere else...but maybe not. It depends on whether the code that you made active ACTUALLY fixed the problem or just moved it somewhere else...you know how it goes...I have made memory problems disappeared by adding trivial write statements, for example.
 
Sorry, did not mean to worry you [sad] I am sure you will not rest until you get to the bottom of this and prove to yourself the problem is gone, anyway.
 
maybe a memory problem will pop-up somewhere else...but maybe not

... that is where my uncool feeling comes from

I am sure you will not rest until you get to the bottom of this and prove to yourself the problem is gone, anyway.

... if only I knew how to set about. :)
You know, hunting down something that does not manifest itself offers a challenge I feel not quite up to with my engineering background. Maybe if I was a theologian I would be more in practice with such tasks.

:) :)
Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Well, I am back on the design engineering realm myself, but for about 8 years, I was the maintainer of all the design programs my engineer colleagues used (and now me, again). We don't quite use Computer Scientists to maintain engineering fotran programs...we feel it is best to have an engineer do it, for a few reasons.

ANYWAY, my point being that "there is more than one way to skin a cat". So, you are not a full blown Computer Scientist with great computer tricks or memory manipulation knowledge...neither am I, and I am yet to face a bug I never found...I have found that just about any programming bug can be found with just patience! I, sometimes, have had to "start from scratch"...open a new file and start copying chunks from the other one and compiling and running every time until the memory problem appears.

Do you have the practice of keeping previous running versions of your program before implementing a new change/enhancement?
Do you ever use difference viewer programs? (e.g. diff, tkdiff, Winmerge)
Are you able to reproduce your problem at this time?

Germán

p.s. How come your smileys work and mine don't? I just click on the provided icons.

 
Germàn,
Easy thing first: I type in the smiley from my keyboard : - ) without the blanks between the keys. And this seems to do the trick.

My background is mechanical engineering and I have been in charge of product development. Now, after my retirement, I persue my hobby more deeply and started this project here. Got a little bit out of hand cause my prog has about 40,000 lines of code now (you know how the developer's genes work), I estimate more than half of this is to do the GUI. I plan to offer my prog for sale, not a big thing, just to improve my position in case of an argument about spending too much money on my hobby.

So in fact, my knowledge of programming is much limited to FORTRAN and I added Windows API and OpenGL to it only recently. What is happening in the processor, graphic cards, stacks and other memory in general is far beyond me. I have some limited understanding there as you get it when you track bugs and read and try to understand the documentation of the compiler or windows documentation.

Yes I have the standing practice to save my program at the end of every day when I worked on it, so I have the version that caused this error available still. I am using visual studio as it came with my compiler some years back. This offers an online debugger wich allowed to track down any bug up to now.

Currently I do not use any difference viewing program, I will have to download one to do so.

I gues I will do right that tomorrow.

Thanks for your support, Germàn.

Norbert



The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Well, I can create an error now, that looks like the one I had. Trying to condense what I found into this program.

Code:
program testrun

implicit none

integer iError			! error indicator
integer j				! loop counter
type MyData
	integer iDat1
	integer iDat2
	type (MyData), pointer :: pNext
	type (MyData), pointer :: pLAst
endtype
type (MyData), pointer :: pTestHead, pTestTemp, pTestTail
type (MyData), pointer :: pBackUp
!---------------------------------------------------------- build linked list
allocate (pTestHead, stat = iError)
if (iError .ne. 0) write(*,*) ' Not your lucky day !!'
nullify (pTestHead%pLast)
nullify (pTestHead%pNext)
pTestTail => pTestHead
pTestTail.iDat1 = 1
pTestTail.iDat2 = 2

do j = 1, 5
	allocate (pTestTail.pNext, stat = iError)
	if (iError .ne. 0) write(*,*) ' No, really not !!'
	pTestTemp => pTestTail
	pTestTail => pTestTail.pNext
	nullify (pTestTail%pNext)
	pTestTail.pLast => pTestTemp
	pTestTail.iDat1 = 2 * j + 1
	pTestTail.iDat2 = 2 * j + 2
end do
!---------------------------------------------------------- (1) copy data of head to backuppointer
allocate (pBackUp, stat = iError)
if (iError .ne. 0) write(*,*) ' ... but could have been worse !!'
pBackup = pTestHead
!---------------------------------------------------------- (2) user modifies data
pTestHead => pTestHead.pNext  ! <---------- this is the error
!---------------------------------------------------------- (3) trying to recreate data
pTestHead = pBackup
write (*,*) pTestHead.iDat1, pTestHead.iDat2
!---------------------------------------------------------- (4) now trying to delete data
pTestTemp => pTestHead
do while (associated (pTestTemp))
	write (*,*) pTestTemp.iDat1, pTestTemp.iDat2
	pTestTemp => pTestTemp.pNext
	deallocate (pTestHead)
	pTestHead => pTestTemp
enddo

end

I was trying to save the data of the element of the linked list that the user works upon by copying it to a backup pointer. If the user selected to cancel, I wanted to rebuild the data from this copy like in (3). If the rearrangement is faulty - because the headpointer was moved to another element - this creates such an 'Debug Assertion Failed' error - and not an access violation which is more familiar to me.

Only one thing is not yet clear: In my program I could see valid data in the debugger immediately before the crash, this here shows garbage. But at least I have an idea what kind of error i Am looking for.

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Well, I am yet to start using pointers in Fortran...but a first at compiling your sample program with g95 gave a few compilation errors right away. Apparently, pointer's content is not accessed via a point , but a percent

pTestTail.iDat1 = 1
pTestTail.iDat2 = 2


pTestTail%iDat1 = 1
pTestTail%iDat2 = 2

Is this correct?

 
@salgerman : yes, the write way is the use of % . Few compilers accept the dot but this is an extension...

François Jacq
 
My compiler allows to use '.' instead of '%' as a non-standard extension. I prefer the dots however, because they result in better legibility when the names get longer. The Compaq compiler has just one bug in that the nullify-statement does not accept the dot.

nullify (pTestTail.pNext) ! this causes an error at compilation

nullify (pTestTail%pNext) ! this does not

Norbert




The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Now I got it.
It was still deeper down in my code. For those interested here is the example code what point.

As said before I have a - possibly long - linked list of dataobjects running from head-pointer to tail-pointer. The user can select a subset of this running from a new start-pointer to a new end-pointer. The code to do this was spread across many a page, here is a condensed example of how it is supposed to work:

Code:
program testrun

implicit none

integer iError			! error indicator
integer j				! loop counter
type MyData
	integer iDat1
	integer iDat2
	logical lEnd		! to be set true for the End-Item
	logical lStart		! to be set true for the Start item
	type (MyData), pointer :: pNext
	type (MyData), pointer :: pLAst
endtype
type (MyData), pointer :: pTestHead, pTestTemp, pTestTail
type (MyData), pointer :: pStart, pEnd
!---------------------------------------------------------- build linked list
allocate (pTestHead, stat = iError)
if (iError .ne. 0) write(*,*) ' Not your lucky day !!'
nullify (pTestHead%pLast)
nullify (pTestHead%pNext)
pTestTail => pTestHead
pTestTail%iDat1 = 1
pTestTail%iDat2 = 2

do j = 1, 10
	allocate (pTestTail%pNext, stat = iError)
	if (iError .ne. 0) write(*,*) ' No, really not !!'
	pTestTemp => pTestTail
	pTestTail => pTestTail%pNext
	nullify (pTestTail%pNext)
	pTestTail%pLast => pTestTemp
	pTestTail%iDat1 = 2 * j + 1
	pTestTail%iDat2 = 2 * j + 2
	pTestTail%lSTart = .false.
	pTestTail%lEnd = .false.
end do
write (*,*) 'Original List :'
pTestTemp => pTestHEad
do while (associated (pTestTemp))
	write (*,*) pTestTEmp%iDat1, pTestTemp%iDat2
	pTestTemp => pTestTEmp%pNExt
enddo
!---------------------------------------------------------- (1) allocate memory for alternative start and end
allocate (pStart, stat = iError)
allocate (pEnd, stat = iError)
!---------------------------------------------------------- (2) set user-start to third element of linked list
pTestTemp => pTestHead%pNext%pNext	         ! move temporary pointer to third element
nullify (pStart%pLast)
pStart = pTestTEmp			         ! copy the data, (the user might modify them temporarily)
pStart%pNext => pTestTemp%pNext		! connect to next item in line
pStart%pLast => pTestTemp			! need this for restoration of original list
pTestTemp => pTestTemp%pNext		! detour the back connection from the element before
pTestTemp%pLast => pStart
pTestTemp%lStart = .true.			! flag the startelement
!-----------------------------------------------------------(3) set user-end to third element before last
pTestTemp => pTestTail%pLast%pLast
nullify (pEnd%pNext)
pEnd = pTestTemp				! copy data, the user might modify them.
pEnd%pLast => pTestTemp%pLast		! connect to last element before
pEnd%pNext => pTestTEmp			! need this for restoration of original list
pTestTemp => pTestTemp%pLast		! detour the forward connection of the element before		
pTestTemp%pNext => pEnd
pTestTemp%lEnd = .true.
!---------------------------------------------------------- (4) use subset
write (*,*)
write (*,*) 'Subset List:'
pTestTemp => pStart
do while (associated (pTestTemp))	! emergency exit
	write (*,*) pTestTemp%iDat1, pTestTemp%iDat2
	if (pTestTemp%lEnd) exit		! regular exit
	pTestTemp => pTestTemp%pNExt
enddo
!---------------------------------------------------------- (5) restore original list
pTestTemp => pStart%pNext
pTestTemp%pLast => pStart%pLast		! restore the detoured backward connection
deallocate (pStart)					! do not need it any more
pTestTemp => pEnd%pLast
pTestTemp%pNext => pEnd%pNext		! restore the detoured forward connection    <<< Error sourdce
deallocate (pEnd)
!----------------------------------------------------------- (6) use restored list		
write (*,*) 
write (*,*) 'Restored List :'
pTestTemp => pTestHEad
do while (associated (pTestTemp))
	write (*,*) pTestTEmp%iDat1, pTestTemp%iDat2
	pTestTemp => pTestTEmp%pNExt
enddo
!-----------------------------------------------------------(7) clear memory
pTestTemp => pTestHead
do while (associated (pTestTemp))
	pTestTemp => pTestTemp%pNext
	deallocate (pTestHead)
	pTestHead => pTestTemp
enddo

end

Commenting out the line indicated 'error source' in block 5 gives an error in the subsequent write statement, which represents usage of the restored list. If this usage does not occur the error manifests itself in the subsequent deletion process and has the same look and feel as I got it.

Quite happy now.
Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top