Trapping "the index was outside the bounds of the array" error

I am getting exception error. The log file says “the index was outside the bounds of the array”

image

Is this error can be trapped with FatalErrorHook or PROP:LastChanceHook ?

For the case of PROP:LastChanceHook , i did put the following codes :

  1. in the after global include
    INCLUDE('CWEXCPT.INT'),ONCE

  2. Before global data
    oldHandler LONG
    continue BOOL(FALSE)

  3. Inside Global Map
    MyHandler(*ICWExceptionInfo),LONG

  4. Program Routines

MyHandler   PROCEDURE(*ICWExceptionInfo info) 
 CODE
 SYSTEM{PROP:LastChanceHook} = oldHandler
 continue = TRUE
 RETURN 1
  1. 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

jason
c11.0

No. This is the run-time error rather than exception. It can be caught using the PROP:FatalErrorHook.

Thank you for your response.
Any sample or example code that i can refer to use prop:fatalerrorhook?

Why you need a hook function to find where the error occurred? Just use the “Debug” variant of CLARUN.DLL.

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:

image

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?

RaiseException(UNSIGNED dwExceptionCode, UNSIGNED dwExceptionFlags, UNSIGNED nNumberOfArguments, LONG Address_lpArguments ),RAW,PASCAL,DLL(1)        
EXCEPTION_ARRAY_BOUNDS_EXCEEDED  EQUATE(0C000008Ch)
EXCEPTION_NONCONTINUABLE         EQUATE(1)          !Noncontinuable exception

   RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_NONCONTINUABLE, 0,0)

LogExceptionAndFatalError_20230606.ZIP (6.6 KB)

2 Likes

thank you very much @CarlBarnes and @also
great help.

Jason

Running your test project on the debugger it shows the exception:

I think the Remarks section has the explanation

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:

  1. The system first attempts to notify the process’s debugger, if any.
  2. 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.
  3. 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.
  4. 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.
1 Like

Thanks! I should have thought of the Debuger.

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.

@also 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)

LogExceptionAndFatalError_20230607.ZIP (6.8 KB)

1 Like

There are 2 reasons why the EXCEPTION_ARRAY_BOUNDS_EXCEEDED is no catching by the hook function set to the PROP:LastChanceHook property:

  1. 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.
  2. 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.

I do not see reasons for that.

This part of Clarion RTL is called sometime after calling RaiseException:

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)