|
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Sat Dec 05, 2015 3:31 am Post subject: |
|
|
If you read the Microsoft page that I referred to above, you can see something that may answer you: "The system commits additional pages from the reserved stack memory as they are needed, until either the stack reaches the reserved size minus one page (which is used as a guard page to prevent stack overflow)". I am not knowledgeable about corner cases where reserve size = commit size, etc., nor do I know if the description on that MS page applies to all versions of their VC compilers and tools.
When I write a program, I try to keep the stack small by using allocatable or statically allocated, saved arrays. However, when helping with some old F77 or F66 code, I find it necessary to specify a large enough stack to allow the program to be run with few changes. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Sat Dec 05, 2015 3:32 am Post subject: |
|
|
Mecej4, you might be on to something. I have a small routine that reports the stack as an integer. It turns out that after 1 particular WRITE into a character array, the stack comes back corrupted.
I stripped the code out and got the problem to duplicate!
Code: |
!FTN95 application...
PROGRAM main
external my_routine
integer*4 my_routine
character*256 raw_data
character*12 quad
character*4 state
logid=1
quad='hndsh'
state='ky'
i=my_routine() ! return the stack pointer
write(*,'(z16)')i
WRITE(RAW_DATA,55055)trim(quad),logid,trim(state)
55055 format(a,i4.4,'_',a)
i=my_routine() ! return the stack pointer
write(*,'(z16)')i
END PROGRAM main
integer function my_routine()
integer i
code
mov eax%,esp%
mov i,eax%
edoc
my_routine = i
return
end
|
I do a number of other WRITE's like this one, but with different formats and only 1 item in the IO list.
Compiled under Plato with /CHECKMATE, the stack pointer is not the same after the formatted WRITE. Under /RELEASE, the stack pointer is the same. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Sat Dec 05, 2015 3:50 am Post subject: |
|
|
It may have something to do with the trim() on the last IO list item (state). If I remove that trim(), then the stack remains the same value.
I tried this using * instead of raw_data and gets the same stack difference. So, it's at least consistent. |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Sat Dec 05, 2015 4:43 am Post subject: |
|
|
Two comments: 1. You can report the %esp value more accurately by placing the following three lines once before the WRITE and once after.
Code: |
code
mov i, esp%
edoc
|
In your version, the call pushes a return address, then in the subroutine EBP is saved on to the stack. Then space is allocated for the local variable i on the stack, and it is only after all this happens that the value of ESP is returned as the function value.
2. To test the problem further, I placed a DO logid=1,100 around the WRITE statements. With /CHECKMATE, I found that each iteration causes ESP to be decreased by 16. Without /CHECKMATE, ESP stays unchanged. Same (unchanged) with /CHECK.
Although it is acceptable for the compiler to generate code that keeps throwing stuff on the stack, it can become problematic if the stack clean up is delayed, particularly when the code concerned is inside a loop that is executed a large number of times. |
|
Back to top |
|
|
JohnCampbell
Joined: 16 Feb 2006 Posts: 2554 Location: Sydney
|
Posted: Sat Dec 05, 2015 5:12 am Post subject: |
|
|
mecej4,
Thanks for the information on stack and how to change it; this is very helpful, but again the results of changing the stack size are not as I would expect.
Why is it that for:
"/stack:0x40000,0x20000" crashes with stack overflow.
"/stack:0x40000,0x40000" the program runs,
My understanding after reading the link you provided is that both provide for the same available stack size, although the first case initially has a smaller allocation (and for what reason?)
"/stack:0x40000" what would this be equivalent to?
This reproduces the confusion I have had with this in the past.
I shall look at using integer*4 function get_stack_pointer(), based on your example and see if that helps.
John |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Sat Dec 05, 2015 1:25 pm Post subject: |
|
|
mecej4,
Yes, I was fully aware that the ESP reflects the stack pointer in the called routine. Rather than get the actual value at the point of call, I chose to use the fact that, relatively, the stack should be the same regardless of the actual value. In this way, I can more easily remove the trace simply by changing the one routine (my_routine) to always return the same value. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Sat Dec 05, 2015 8:35 pm Post subject: |
|
|
I expanded the code trials a bit more, putting in a few variations, explicit use of the non-blank length (len_trim), etc.
The results, while clear, are not consistent. Using len_trim() to set the character count is no better than using trim(), but using trim() then concatenating those results appears to work just fine.
Code: Code: |
!FTN95 application...
PROGRAM main
external my_routine
integer*4 my_routine
character*256 raw_data
character*12 quad
character*4 state
integer i,j
logid=1
quad='hndsh'
state='ky'
raw_data = ' xyz'
99000 format(z16)
write(*,99000)my_routine()
print *,"Use 2 trim() calls"
WRITE(*,55055)trim(quad),trim(state),'0'
55055 format(a,a,a)
write(*,99000)my_routine()
print *,"Trim and len_trim",trim(quad),logid,state(1:len_trim(state))
write(*,99000)my_routine()
print *,"Use len_trim",quad(1:len_trim(quad)),logid,state(1:len_trim(state))
write(*,99000)my_routine()
i=len_trim(quad)
j=len_trim(state)
print *,"Used len_trim to get lexplicit engths"
write(*,99000)my_routine()
print *,"Use explicit lengths",quad(1:i),logid,state(1:j)
write(*,99000)my_routine()
raw_data = quad//state//trim(raw_data)
print *,"Concatenation only as assignment"
write(*,99000)my_routine()
print *,"concat trims and print",trim(quad)//trim(state)!//trim(raw_data)
write(*,99000)my_routine()
print *,"Just plain print",quad,state
write(*,99000)my_routine()
print *,"trim only quad",trim(quad),state
write(*,99000)my_routine()
print *,"trim only quad, output state twice",trim(quad),state,state
write(*,99000)my_routine()
print *,"len_trim only quad",quad(1:i),state
write(*,99000)my_routine()
END PROGRAM main
integer function my_routine()
integer i
code
mov eax%,esp%
mov i,eax%
edoc
my_routine = i
return
end
|
Results:
Code: |
360F578
Use 2 trim() calls
hndshky0
360F568
Trim and len_trimhndsh 1ky
360F558
Use len_trimhndsh 1ky
360F548
Used len_trim to get lexplicit engths
360F548
Use explicit lengthshndsh 1ky
360F538
Concatenation only as assignment
360F538
concat trims and printhndshky
360F538
Just plain printhndsh ky
360F538
trim only quadhndshky
360F538
trim only quad, output state twicehndshky ky
360F538
len_trim only quadhndshky
360F538
|
By trying different numbers of trim() strings and other variables, the number of variables that affect the stack (i.e. the trim() or len_trim() ones) are affected by the number of successfully output data of other types, including character data. Given the right number of each, the stack is unaffected.
So, for me, at least at this time, there is no good fix for the code, other than using the /RELEASE version. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Sat Dec 12, 2015 12:54 am Post subject: |
|
|
Paul, I'm wondering if you might have tried the code and have seen the same results that I have.
Bill |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7924 Location: Salford, UK
|
Posted: Sat Dec 12, 2015 8:49 am Post subject: |
|
|
Bill
I have not tried your code but will aim to do so on Monday.
Having said that, from a brief look at your post, I am not clear about what I will be looking for. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Sat Dec 12, 2015 2:08 pm Post subject: |
|
|
Paul, fair enough.
The basis for the request is that , while in a function/subroutine, the stack pointer should remain at the same value. However, using the sample program, you will find that, for whatever reason and only when running /CHECKMATE, the stack gets corrupted. Specifically, the stack will decrement under specific circumstances. My issue was that as my original code was running, it was performing tens/hundreds of thousands of the suspect IO statements until a stack overflow exception was generated. Running the same test code under /RELEASE will show that the stack pointer remains the same throughout the run. That was my experience; if I ran the /RELEASE version, all went well.
The problem I encountered was specifically found to be using TRIM() in an IO list. The first PRINT ("Using 2 trim() calls)" shows that the stack pointer returns after the PRINT decremented by 16. Later on, I found that other combinations of PRINT and use of TRIM() or just specifying the length of the character string in the IO list can cause the same problem, or make the problem disappear.
Specifically, "concat trims and print" uses three TRIM() calls, concatenating the data, but no stack problem was encountered. Also, "trim only quad" uses TRIM() to output the first data item then outputs a full data item, and the stack is unaltered. So, in my small number of tests, it would appear that if you use TRIM() or a specified character length at the end of the IO list, then the stack pointer is badly altered.
I hope this helps to clarify. |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7924 Location: Salford, UK
|
Posted: Mon Dec 14, 2015 11:34 am Post subject: |
|
|
Bill
The problem is replicated on my machine and needs fixing so I will make a note of this.
In the meantime I suggest that you write your output to a string buffer and then use a single TRIM when PRINTing the buffer. That should allow you to continue to use /CHECKMATE. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Mon Dec 14, 2015 4:19 pm Post subject: |
|
|
Paul, the problem also occurs writing to a string buffer using the WRITE(char_data,format) form as well as to a file. This was how I identified the problem initially.
Or, I may have misunderstood your response. |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7924 Location: Salford, UK
|
Posted: Mon Dec 14, 2015 6:23 pm Post subject: |
|
|
OK. Can you find a way to avoid multiple calls to TRIM in an output list? |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Mon Dec 14, 2015 6:51 pm Post subject: |
|
|
Since this also happens even when the length of the string is specified (i.e. ABCD(1:10), or ABCD(1:I)), it becomes nightmare to recode all the formatted writes.
One interesting thing is that even though the stack is negatively affected, if I call a routine that manifests this effect, upon return, the stack is "normal" in the calling routine. So, something is happening (and I kind of see this in the /CHECKMATE listing files I've looked at) where the stack is "fixed" prior to return to the caller.
What I might be able to do is recode the huge, major loop in which this problem manifests itself most readily, breaking it into smaller routines that will contain the TRIM() functions and get called/fixed.
I've informed my external testers that this issue might manifest itself and have offered a "fix"; don't process so much data, or run the /RELEASE version also supplied to them.
I have a couple of other routines that process massive amounts of data as well. These will be much more difficult to recode, but so far, they have not yet crashed due to this stack fault issue.
Thanks for pursuing the fix, Paul. I'll get by until then! |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1217 Location: Morrison, CO, USA
|
Posted: Mon Dec 14, 2015 7:07 pm Post subject: |
|
|
Temporarily, I've placed code that saves the ESP register as the major loop starts and restores it before the loop end. It is certainly temporary.
This has totally eliminated the stack fault. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|