We were looking for the reasons why a Forth might crash and portable ways to prevent the crash during development. 6 ways were suggested together with some test cases. Tests were also suggested for divide by zero and out of range, although a Forth which crashes on these has not been reported.
A number of freely-available Forths were tested to see whether extra crash-proofing was worthwhile. The latest results are appended. An ideal Forth environment would yield only 0s or -2s. We don't have any results for commercial Forths. Are they better than free ones in this respect?
Ways to prevent BadReturn and BadExecute were suggested. The check which evolved for BadExecute was quite elegant, saving execution tokens at run-time as generated by ' ['] FIND and SEARCH-WORDLIST and checking against these before use by EXECUTE CATCH and DEFER.
The systems tested mostly detected BadExecute and recovered gracefully, so perhaps the elegant solution is not needed after all.
Most of the systems tested failed to recover after code was overwritten. The transition from 16-bit DOS (with code and data in separate segments) to 32-bit Forths has weakened most Forths in this respect. It seems that overwriting code is the easiest way to crash a modern Forth. Perhaps we should think about a way to protect against this, especially for beginners.
\ Find a value not likely to be an execution token.
1 ALIGNED CONSTANT NotAnXT
\ Find an address likely to be outside the data space.
-4 ALIGNED CONSTANT NotADataAddress
\ Find an address which is likely to be unaligned.
HERE ALIGNED 1+ CONSTANT NotAligned
\ Create a : word which cannot be a macro.
: _DROP DROP ;
: BadExecute ( -- ) NotAnXT EXECUTE ;
: BadAddress ( -- ) NotADataAddress @ DROP ;
: BadAlign ( -- ) NotAligned @ DROP ;
: BadReturn ( -- ) NotAnXT >R ;
: BadCode ( -- ) ['] _DROP 20 0 FILL 0 ['] _DROP EXECUTE ; \ Try executing it
: BadRes1 ( -- n1 n2 ) 9 0 /MOD ; \ Divide by zero
: BadRes2 ( -- ) 0 1 1 UM/MOD ; \ Out of range
: BadBreak ( -- u1 u2 ) BEGIN AGAIN ; \ Try to interrupt loop
: BadNumb ( -- ) 1 1 BASE ! . ; \ Loops forever?
|0||harmless, no need to detect action.|
|-2||prevents action, reports cause and location, continues at Forth prompt.|
|-3||prevents action, reports cause only, continues at Forth prompt.|
|-4||prevents action, reports "Error found", continues at Forth prompt.|
|-6||executes action, but values returned are incorrect.|
|-7||prevents action, reports cause only, empties dictionary, continues at Forth prompt.|
|-10||prevents action, reports cause and location, exits Forth.|
|-11||prevents action, reports cause only, exits Forth.|
|-12||prevents action, reports "Error found", exits Forth.|
|-14||no message, exits Forth.|
|-16||no message, hangs Forth but computer need not be re-booted.|
|-18||no message, hangs Forth and computer must be re-booted.|
|-20||no message, corrupts Forth which hangs at some later time.|
|Compiler||Bad Execute||Bad Address||Bad Align||Bad Return||Bad Code||Bad Res1||Bad Res2||Bad Break||Bad Numb|
|F-PC for DOS v3.5 (from Chris Jakeman)||-18||0||0||-18||0||-4||-6||-18||-18|
|GForth for Unix v0.3.0 (from Bernd Paysan)||-4||-4||0||-4||-16||-3||-6||-3||-6|
|GForth for Win32 v0.3.0(1)||-16||-16||0||-16||-16||-16||-6||-16||-6|
|GForth for DOS v0.3.0||-4||-4||0||-4||-18||-3||-6||-3||-6|
|iForth v1.07 Linux (from Marcel Hendrix)||-3||-3||0||-3||-20||-3||-3||-11(2)||-11|
|iForth v5.0 Win32 (from Marcel Hendrix)||-2||0||0||-2||-6(3)||0(4)||-4||-14(5)||-2|
|mxForth v2.4 Linux (from Marcel Hendrix)||-7||-7||0||-7||-20||-7||-7||-11(2)||-11|
|4tH v3.62.2 (from Hans Bezemer)||-2||-2||0||-2||0||-2||-6||-14||-2|