forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Stack error
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
mecej4



Joined: 31 Oct 2006
Posts: 1886

PostPosted: Sat Dec 05, 2015 3:31 am    Post subject: Reply with quote

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
View user's profile Send private message
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Sat Dec 05, 2015 3:32 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Sat Dec 05, 2015 3:50 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
mecej4



Joined: 31 Oct 2006
Posts: 1886

PostPosted: Sat Dec 05, 2015 4:43 am    Post subject: Reply with quote

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
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2554
Location: Sydney

PostPosted: Sat Dec 05, 2015 5:12 am    Post subject: Reply with quote

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
View user's profile Send private message
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Sat Dec 05, 2015 1:25 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Sat Dec 05, 2015 8:35 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Sat Dec 12, 2015 12:54 am    Post subject: Reply with quote

Paul, I'm wondering if you might have tried the code and have seen the same results that I have.

Bill
Back to top
View user's profile Send private message Visit poster's website
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7923
Location: Salford, UK

PostPosted: Sat Dec 12, 2015 8:49 am    Post subject: Reply with quote

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
View user's profile Send private message AIM Address
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Sat Dec 12, 2015 2:08 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7923
Location: Salford, UK

PostPosted: Mon Dec 14, 2015 11:34 am    Post subject: Reply with quote

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
View user's profile Send private message AIM Address
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Mon Dec 14, 2015 4:19 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7923
Location: Salford, UK

PostPosted: Mon Dec 14, 2015 6:23 pm    Post subject: Reply with quote

OK. Can you find a way to avoid multiple calls to TRIM in an output list?
Back to top
View user's profile Send private message AIM Address
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Mon Dec 14, 2015 6:51 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1217
Location: Morrison, CO, USA

PostPosted: Mon Dec 14, 2015 7:07 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
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