I was befuddled by a OpenGL error. The program would crash when a Fortran I/O statement was executed after about 150 iterations. If I removed the I/O statement, it works well. I suspected a stack issue.

So, I put in a stack checker, in-line assembly code that allows me to save the ESP register. I'd used this before with a different stack issue, to good success.

I simplified the first section of the code, generating a OpenGL window. Each Winio@ call causes the stack pointer to change. FYI: the OpenGL calls also do the same. I suspect this causes the crash when looping. If this were in a subroutine, the stack pointer is always returned to the proper value just prior to the return.

N.B.: When I moved the looped sections of OpenGL from the Main to a subroutine (so the routine will get called 360 times), the program crashed after the first iteration. Moving the code back into Main means that I get the stack overflow eventually, but more than 1 iteration works.

Just as another possible reason why I can get things to crash (or not), it appears that the HEAP and STACK are allocated after the .reloc (reference the Section Map), and in that order, HEAP first, then STACK.

If the program over-runs the STACK, then it starts into the HEAP, then other data (if it doesn't crash first).

Do I have the ordering correct?

Because what I think I'm seeing with my "crashes" is the call(s) to OpenGL routines likely use the stack heavily to allocate temporaries, and if the stack is insufficient, this corrupts the heap and/or other data areas.

Bill, monitoring the stack pointer the way that you did can provide useful information, but one should not put too much value on that information. A wandering ESP value does not provide proof of memory leakage or incorrect stack management.

Before the 80386, one could not use the stack pointer in the R/M field of an instruction. You had to move the value of SP to BP, adjust the bias if necessary, and use BP in the R/M field. That changed with the 80386, and now EBP could be used as just another register instead of being dedicated to use as a frame pointer. Gfortran does, in fact, have the option -fomit-frame-pointer.

For a CDECL call on the 8086, we had PUSH arg1; PUSH arg2;...;CALL ..; ADD SP,nn. With the 80386 and later, the code emitted by compilers shows a more relaxed attitude, and ESP is restored many instructions after the CALL or not at all. When the code contains a number of Fortran CALLS with few other statements, ESP may be restored after all the calls have been executed.

I have not studied the code emitted by FTN95 often enough to say whether the above comments apply to it, but the modern relaxed view of ESP and EBP is something to keep in mind when inserting very short CODE ... EDOC sequences in Fortran code..

There can be negative ramifications for the stack pointer being manipulated/"adjusted" while the current routine is running. If the stack pointer is incremented (equivalent of a POP), then the contents of the stack can/will be trashed, resulting in many bad things happening when the module is exited.

Or, in the case I brought up a couple of years ago, the constant decrement of the stack pointer can eventually result in the stack intruding into the data apace, corrupting those data.

What I'm seeing in the OpenGL crashes are instruction addresses that appear to be in the data space. This would be consistent with the stack being hammered by, perhaps, the PUSH of a data item address into the return address. There are a myriad of possibilities.

In the OpenGL module where I am having issues, the stack appears to be totally trashed. Meaning the stack pointer after the OpenGL calls is greater than the stack pointer upon entry to the test_routine. This would look like 1 or more POP instructions. Which means that a subsequent call will wipe out one or more addresses/registers on the stack, and possibly altering the return address for the current module.

The value of the stack pointer is important.

Of greater concern is the OpenGL calls, which leave the stack pointer decremented by way too much.

I'm working on a smaller version of the OpenGL issue that can be posted here showing the issues.

Note that the last calculation shown is NOT the proper value (shown as 269709653, S/B -8. This is the example of how the stack pointer can affect the results. If I restore the stack pointer just prior to this last set of statements, the results show:

The code clarifies things, thanks. You are concerned specifically about ESP changing after returning from a call to an OpenGL or Winio@ routine, rather than during the course of a sequence of assignment statements.

I do not use graphics routines/libraries with FTN95, so I can only remark that the correct interfaces must be used. The interface module and the DLL that provides the OpenGL routines must be consistent. Since I see a number of senior users discussing Clearwin usage, I assumed that matters were in great shape.

Just to see the effect, I replaced your USE OPENGL$ by USE XGL, where xgl.mod was produced by compiling a three-line file containing

module xgl
include 'opengl.ins'
end

I found that the stack convention was quite different from that which I saw when I had USE OPENGL$. The EXE produced with XGL uses STDCALL for OpenGL calls whereas the OPENGL$ and WINIO@ calls appear to be CDECL.

Silverfrost should be able to clarify this issue, unless the answers are already in the help file. I agree, Bill, that a Fortran CALL should result in ESP being restored to its value after the execution of the previous statement. Perhaps, Eddie or Dan can provide their opinions.

P.S. (after reading Eddie's response below): There is a table showing how to provide the proper OpenGL interfaces for 64bit Fortran compilers other than FTN95 at https://www.silverfrost.com/ftn95-help/clearwinp/util/64bit.aspx (I found that page through Google Search, and I hope to find a similar page for 32-bit calls). Much of the information on that page is date-sensitive, and we may only infer the date from the download information for a particular distribution of GFortran -- around 2011. A README.TXT, updated for each release of FTN95, with a catalog of the files included and their intended purpose, would be helpful in avoiding what Wahorger did, namely, using with FTN95 a MOD file meant for use with Gfortran -- OPENGL$.mod . The recently released 8.30 compiler does include a README.TXT; please read it!

Last edited by mecej4 on Sat Apr 28, 2018 12:14 pm; edited 3 times in total

The (gFortran) file opengl$.mod looks a first sight to be wrong. It may be built from third party code that uses the wrong binding. I will make a note that this needs investigating. However, there is no need to use this particular file when compiling with FTN95.

The whole of the Silverfrost ClearWin+ library uses C_EXTERNAL (i.e. CDECL) binding and this includes winio@.

If I am not mistaken, I think that there is a longstanding problem here.

This is what I see happening when the Fortran source contains calls to WINIO@ and is compiled for 32-bit. The arguments are pushed on the stack in the usual CDECL way. Then, two additional hidden arguments are pushed before the CALL is made. This first of these is a count of the arguments, and the second hidden argument is a null-terminated string, apparently containing information regarding the argument types. After returning from the WINIO@ routine, one of these hidden arguments is not accounted for when the usual ADD ESP, nn adjustment is made.

For example, for the Fortran statement i=winio@('%sp&',0, 0), six items are pushed on the stack:

1) The integer 4, which is the hidden string length argument;
2), 3) The integer 0, twice;
4) The address of the string '%sp&';
5) The integer 3, which is the number of arguments;
6) The string "*C*I*I\x00", which seems to indicate that the arguments are a pointer to a character variable and two pointers to integers.

After the call to WINDOW_PRINTF@@ with these arguments, the stack adjustment is done with add esp,=20, and we have lost 4 bytes, as Wahorger pointed out. We should have seen add esp,=24, instead.

The fifth and sixth items above appear to be intended for calling library routines with generic names and/or optional arguments.

Last edited by mecej4 on Sat Apr 28, 2018 9:28 am; edited 1 time in total

I tried including the opengl.ins, but my source is .for, with wide_source enabled and the include file doesn't support this. I've run into this before, and could use some insight into how to turn the .ins file into a .mod file! I've looked, but not found, a method.

Perhaps that is the reason why all this is going on with the OpenGL!

Still doesn't quite explain the winio@ stack stuff. Then again, it's not likely to have hundreds or thousands of winio@ calls that muck up the stack!

I'm sorry to say that I've never been able to fathom OpenGL, and lost interest in trying when I discovered that different graphics cards support (or don't) different features, so in a race to the bottom, the common factor wasn't that much different to the GDI, which is guaranteed to be present on every Windows PC. I had hoped to learn from a regular contributor to the forum, but he died some years ago. Almost certainly if he'd lived he would be on to 64 bit and OpenGL.

My basic position on anything to do with Fortran, graphics, Windows, life, the Universe and everything is that if it is there it should work, whether I personally need it or not. In the case where something did work, but now doesn't, or never worked at all, it is far easier to live with if one can find out about it before spending weeks struggling, and if there is a criticism in this it is about the failure to use the knowledgebase in the Forum or elsewhere to point out such issues. Take for example the Clearwin+ handle issue - it was public knowledge, and that was lost in the depths of the forum. Now it resurrected it is going to be dealt with. I must add that SF and Paul are good at addressing issues that are raised and the documentation does get updated, but less obviously.

module opengl
include <opengl.ins>
end module opengl
options(wide_source)
program main
use opengl
print*,"123456789012345678901234567890123456789012345678901234567890",GL_ACCUM
end

be split into two pieces, with the first piece being just

Code:

module opengl
include <opengl.ins>
end module opengl

Doing so will give two benefits: no imposing of the source format needs of one part on the other; no need to run large fixed content files such as OPENGL.INS through the compiler whenever a user program is recompiled.

I tried including the opengl.ins, but my source is .for, with wide_source enabled and the include file doesn't support this. I've run into this before, and could use some insight into how to turn the .ins file into a .mod file! I've looked, but not found, a method.

This is a repetition of what has been stated in other responses, but I don't want you to miss it:

1. Create a separate source file in the same form as that of the INS file, with just three lines.

Code:

module opengl
include <opengl.ins>
end module opengl

Compile this file, and USE the module, instead of including OPENGL.INS in your regular Fortran source files.

2. Do not use MOD files with '$' in the name if your code is to be compiled with FTN95.