XSharpPublic icon indicating copy to clipboard operation
XSharpPublic copied to clipboard

Problem calling error handler from BEGIN...END SEQUENCE

Open cpyrgas opened this issue 11 months ago • 5 comments

https://www.xsharp.eu/forum/topic?p=32646#p32646

Following code prints in X#:

before BEGIN SEQUENCE .F. 
in BEGIN SEQUENCE .T. 
in RECOVER .F. 
after END SEQUENCE .F. 

so the ErrorHandler() function is not called at all, as it does in VO:

before BEGIN SEQUENCE .F. 
in BEGIN SEQUENCE .T. 
in ErrorHandler .T. // why is this line missing in X#?
in RECOVER .F. 
after END SEQUENCE .F. 
FUNCTION Start()  AS INT
	LOCAL oCB AS CODEBLOCK
	LOCAL err AS USUAL

	oCB := ErrorBlock( {|err| ErrorHandler(err) } )
	? "before BEGIN SEQUENCE", CanBreak()
	BEGIN SEQUENCE
		? "in BEGIN SEQUENCE", CanBreak()
		Error{}:Throw()
	RECOVER USING err      
		? "in RECOVER", CanBreak()
	END SEQUENCE
	ErrorBlock( oCB )
	?  "after END SEQUENCE", CanBreak() 
RETURN 0
	
FUNCTION ErrorHandler(err) AS USUAL
	?  "in ErrorHandler", CanBreak() 
	_Break(err)
	?  "in ErrorHandler after _break", CanBreak() 
RETURN NIL

cpyrgas avatar Jan 24 '25 01:01 cpyrgas

Some comments: This should have worked as expected when the /vo17 compiler option (VO compatible BEGIN SEQUENCE .. END SEQUENCE) was enabled, but I see now that the code that gets generated is not correctly doing what it is supposed to do.

RobertvanderHulst avatar Jan 24 '25 08:01 RobertvanderHulst

AFAIK the errorhandler is being called - only CanDefault() is FALSE during its execution and _break() thus doesn't jump to RECOVER but exits the application.

My current workaround ist this:

FUNCTION _SequenceError(e AS Exception) AS USUAL
    LOCAL oError AS error
    LOCAL uRueck AS USUAL
    
    oError := error{e}
    aadd( gaErrorProcLineInfo, getErrorProcLineInfo( oError ) )
    uRueck := eval( ErrorBlock(), oError )
    asize( gaErrorProcLineInfo, max(0,alen( gaErrorProcLineInfo )-1 ) )
    
    RETURN u

This calls a function retrieving the actual error line (because later in the errorhandler the call stack points to the BEGIN SEQUENCE line in stead of the one which threw the error) and puts it on a stack before moving on to the real error handler. Our own stack handler reads this and makes sure that any stack in protocols which are written during error handling remains useful.

We also have replaced _break() with _ErrorBlockAwareBreak everywhere in our code:

FUNCTION _ErrorBlockAwareBreak( uValue := NIL AS USUAL ) AS VOID
    IF CanBreak() .OR. Empty( gaErrorProcLineInfo )
        _break( uValue )
    ENDIF
    RETURN

This makes the code in the called errorblock() running to its end and then jumping back to RECOVER USING. It would also still work once CanBreak() delivers a true value in the future. It's not satisfying, though, because we needed to modify all our errorhandlers because now code after a _break() call would still be executed. IMO all this could be solved if CanBreak() and _break() behave properly.

SUngemach avatar Jan 31 '25 10:01 SUngemach

Stefan, I am aware of this. Unfortunately, this requires a not so easy change in the compiler.

RobertvanderHulst avatar Jan 31 '25 15:01 RobertvanderHulst

Has there been any progress since then? So far all of our error handling (which is hundreds of begin/sequence loops) still doesn't work in 2.24, causing major trouble. Bug search takes hours and days for every case since applications just shutdown...

SUngemach avatar Jul 27 '25 08:07 SUngemach

Stefan, We have not changed this for X# 2, because a change in this area has a great risk of breaking existing X# code. I promise to look at this for X# 3.

RobertvanderHulst avatar Jul 27 '25 09:07 RobertvanderHulst