@metaquotes dev: strange zero division exception inside terminal.exe *after* start() is already done

 

[1332] exception C000008E at 004CBF22 in C:\Programme\BestDirectMT4\terminal.exe

Could it be that there is some uncaught zero division somewhere inside terminal.exe happening when calculating the y scale of the indicator window?

I am having not much fun with a really ugly and ongoing debugging session here since weeks already. I have gone so far as to register my own exception handler to catch Windows exceptions before metatrader will see them, partially to catch and handle my own exceptions and partially to see why MT4 is still crashing although my DLL is now behaving well and no exceptions will escape it, and it seems these exceptions are indeed *NOT* directly caused by my DLL. They happen after my DLL has already returned and also after start() has returned but before start() is called the next time and they happen in the address space of terminal.exe.

My DLL is writing values to indicator buffers via pointers it receives from mql4 and it seems that the occurrence of this occasional zero division depends on what values I write to these buffers. Under certain conditions it can be that the buffer is filled completely with zero for *all* bars and then the zero division happens inside terminal.exe between two ticks. (there is no division in my dll and also not in my mql4, just in case anyone suspects this and the exception address (the instruction pointer) is clearly inside terminal.exe when it happens.)

Unfortunately I can not attach a debugger to MT4 to dig deeper into that but maybe one of the metaquotes programmers is reading this and could have a look at the code and tell me whether this can indeed happen.

 
I am now using 0.01 instead of 0 to fill the buffer and no exceptions so far
 

maybe only because the last value buffer[0] is then still filled with 0 after the dll is done with initializing the indicator buffer and I have an ugly "huge" step of 1 cent (it is displaying dollar amounts) at the very end. but the scale is now not infinite anymore.

Please metaquotes programmers look into the code that scales the indicator window and tell me whether you forgot a try/catch somewhere in there.

 

Further testing seems to confirm it: If I have only one of my 5 indicator buffers deviating only a tiny bit from zero in only one of the visible bars so that an y-axis scale could be calculated the exception won't happen anymore. But as soon as all indicator buffers contain zero on all bars metatrader will crash on the next incoming tick with STATUS_FLOAT_DIVIDE_BY_ZERO.


Is there a bug tracker somewhere where this can be reported?

 

Is there a bug tracker somewhere where this can be reported?

Look at the top of this page top right corner -- see your name, then "Tickets" and Messages and Profile etc.

...

There used to be a "BugTrack" page on https://www.metaquotes.net// but that seems to be gone with change in website.

 
I doubt it has anything to do with the value (The zero triggers the symptom.) I'd guess you're exceeding the array size and corrupting memory somewhere.
 
WHRoeder:
I doubt it has anything to do with the value (The zero triggers the symptom.) I'd guess you're exceeding the array size and corrupting memory somewhere.

No, I cannot exceed the array size, like I already wrote in my first posting I have made sure that this does not happen. Also this would throw an access violation and not a zero division and it would be thrown in my module (where I would catch it) and it would be thrown immediately and not half a second later after my function has returned and my mql4 has done half a dozen other things and start() finally returned. The zero division happens in metatrader and the symptoms are like i describe them. And they can be reliably reproduced by simply filling the buffer with all zero. Just try it yourself.


How would you explain the fact that the error completely goes away if I set only one (no matter which one) of the buffer values to 0.01 instead of 0 in the following mql4 after the DLL has already returned and it reliably reappears if I leave out this step?

 

It seems I have identified the cause of the problem:


Some language's runtime exception handling (one of them is Free Pascal) wants the Floating Point Unit to raise a hardware exception whenever a zero-division or other such error occurs. Some other languages want to catch floating point errors in a different way and do not expect a hardware exception to happen and do not have a handler for this.


MT4 seems to be one of these applications that do not want to handle FPU hardware exceptions and has therefore masked all FPU exceptions by setting the appropriate bits in the 8087 control word. My DLL on the other hand is made with FPC and since FPC exception handling wants to see all hardware exceptions from the FPU the generated code in DLLMain to initialize the RTL and exception handling will clear these bits in the FPU control word.


The result is that after such a DLL has been loaded any code in MT4's main thread that tries to gracefully catch a zero division by means of software will from this moment on fail and crash the entire program with an unhandled zero-division exception.


My solution for my DLL is now to simply re-initialize the control word to MT4's needs immediately after the RTL has done it's initializing:

initialization
  Set8087CW(Default8087CW or $3f);
end.

This will undo any side effect that was caused by loading my DLL.


The drawback is that I cannot simply catch any zero-divisions anymore in my DLL but this is not a problem, I simply make sure that they do not happen in the first place.


@MetaQuotes: Since this can also happen with DLLs created with some other compilers (Borland C++, Delphi) and the resulting behavior with the FPU suddenly gaining the ability to throw unexpected exceptions might look unexplainable if you don't know what caused it, it would be a good idea to simply save the 8087 control word whenever you do a LoadLibrary() and immediately restore it after this call or even better do the dll loading from a completely separate thread that is used for nothing else. Make yourself a SafeLoadLibrary() function that takes care of and nullifies such nasty side effects caused by other DLL's DLLMain() function.

I personally do not agree with the architects of the FPC RTL that it is ok to mess with any such global settings during library load and I am not the only one who has a problem with this and maybe there is some hope to get this behavior finally removed in some future version. At the moment this behavior seems to exist only to be bug-compatible to the Borland compilers.

Reason: