in the procedure that produce the exception error, at timer oldHandler = SYSTEM{PROP:LastChanceHook} !Read address of oldhandler SYSTEM{PROP:LastChanceHook} = ADDRESS(MyHandler)!Call new handler
Only once The exception window popup and allow me to save to log. The rest of the time, the exception popup as blank window with no message or button. Thus i couldn’t use debug method.
The error is produced only at clients windows server 2019.
Not able to reproduce it at developer side.
Task manager shows program is running.
From your info, most likely, the “index out of range” error was a secondary error.
If you want to trap such kind of errors yourself, just set a function which shows a MESSAGE as a hook. When the MESSAGE appeared, attach the debugger to the program and look at why this happened.
I use Prop:LastChanceHook to hook the exception so before the user ever sees the Exception Message I can call ExInfo.LogException() to write the Exception Log file. That way I do not reply on the user to click “Log Info”. I also show a message more suited to End Users.
I attached small test project that displays this window to allow with Last Chance hooked and an option to use PROP:FatalErrorHook and cause an Index error:
Checking CHECK('Hook PROP:FatalErrorHook') my code gets the call and shows a simple message. The RTL passes no call stack and not much of details needed.
One idea was to have that Fatal message GPF with a Peek(0) which will throw an Exception so I get a call stack like below:
This adds FatalErrorTaker() to the call stack, but at least the original problem shows that was at line 88.
I don’t like using PEEK(0) as it shows the very common “Access Violation”. I took a quick try at causing an exception named “Array Bounds Exceeded”, but the below code just hung for a while then closed the program.
Does anyone know how to cause a specific exception?
The RaiseException function enables a process to use structured exception handling to handle private, software-generated, application-defined exceptions.
Raising an exception causes the exception dispatcher to go through the following search for an exception handler:
The system first attempts to notify the process’s debugger, if any.
If the process is not being debugged, or if the associated debugger does not handle the exception, the system attempts to locate a frame-based exception handler by searching the stack frames of the thread in which the exception occurred. The system searches the current stack frame first, then proceeds backward through preceding stack frames.
If no frame-based handler can be found, or no frame-based handler handles the exception, the system makes a second attempt to notify the process’s debugger.
If the process is not being debugged, or if the associated debugger does not handle the exception, the system provides default handling based on the exception type. For most exceptions, the default action is to call the ExitProcess function.
I guessed that the RTL Exception Handler was ignoring or eating the Array Bounds Exception. I changed to RaiseException(0C0000005h) and that worked as expected showing the normal Access Violation window. Your #4 confirms why Array Bounds just shuts down, thanks.
@anon77170705 is there some way to register with the RTL the Array Bounds Exception to be handled like an Access Violation? Or some RTL function to cause that exception?
Seems like it would be a nice Project Option to have those Runtime Checks throw an Exception with a good name like “Array Bounds Exceeded” instead of showing the Runtime Error window with “Index Out of Range”.
Attached revised test program so Index Fatal Error message has button for “Access Violation” that works calling RaiseException(EXCEPTION_ACCESS_VIOLATION,EXCEPTION_NONCONTINUABLE,0,0)
There are 2 reasons why the EXCEPTION_ARRAY_BOUNDS_EXCEEDED is no catching by the hook function set to the PROP:LastChanceHook property:
The RTL exception handler filters some exceptions and returns DISPOSITION_CONTINUE_SEARCH before showing them to the hook function and to the RTL internal exception stuff. Exceptions which are filtered are debug exceptions (e.g. EXCEPTION_BREAKPOINT) to allow the debugger do its work, known .NET internal exceptions - otherwise the AppGen could not work, and some others. Also, there are exceptions which the RTL is processing internally only without invoking the hook function.
Windows not passes some exceptions to the SEH handlers chain. The EXCEPTION_ARRAY_BOUNDS_EXCEEDED exception is among them. Such exceptions can be caught using another mechanism: vectored exception handling. The RTL uses VEH but not to catch EXCEPTION_ARRAY_BOUNDS_EXCEEDED. Also, it’s need to call the SetErrorMode function with the SEM_NOGPFAULTERRORBOX parameter to turn off default processing of such exceptions.
I could modify my variant of the RTL to allow catch exceptions initiated by program’s components by calling to RaiseException. It’s need to divide the exception filter function to two parts: one is calling before invoking possible hook function and other one - after. Also, I could route all exceptions caught by VEH mechanism to main exception stuff. Some time is required for that.
There you can see on the first part the codes that will not show the exception window, then a test if “flags” has the second bit toggled on* to show that window no matter with exception code it was, then a list of codes that shows the window: C0000005 and other internal codes.
*I thought a possibility to show that window would be to set the second bit of the flags, but:
RaiseException turns off any bit of flags past the first bit (resulting only in flags=0 or flags=1)
RaiseException prepares the Exception_Record structure based on the parameters, crop the flags and calls to RtlRaiseException…
I tryied preparing the structure manually without cropping the flags and calling RtlRaiseException, but if flags is other than 1, 128 or 129, it goes through another path and ends the program even if the exception code is C0000005… the execution doesn’t pass through clarion rtl PassThrough procedure, but through CPPEH::Unwind, so it doesn’t resulted as expected.
Adding vectored exception handler, it executed first, then the exception window expected (for C0000005 as always). The flags can be changed on the exception handler, but then it is evaluated and if it is not one it goes through Unwind and ends the program…
Here your test program adapted and 2 libs for calling those extra functions. LogExcept.zip (4,9 KB)