4tH

Crashproofing Forth © 1997 Chris Jakeman

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.

TEST RESULTS

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?

BADEXECUTE

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.

BADCODE

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.


CRASH-PROOFING TEST RESULTS (1997-08-21, updated 2014-02-24)


\ 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?


Result Codes
0harmless, no need to detect action.
-2prevents action, reports cause and location, continues at Forth prompt.
-3prevents action, reports cause only, continues at Forth prompt.
-4prevents action, reports "Error found", continues at Forth prompt.
-6executes action, but values returned are incorrect.
-7prevents action, reports cause only, empties dictionary, continues at Forth prompt.
-10prevents action, reports cause and location, exits Forth.
-11prevents action, reports cause only, exits Forth.
-12prevents action, reports "Error found", exits Forth.
-14no message, exits Forth.
-16no message, hangs Forth but computer need not be re-booted.
-18no message, hangs Forth and computer must be re-booted.
-20no message, corrupts Forth which hangs at some later time.


CompilerBad ExecuteBad AddressBad AlignBad ReturnBad CodeBad Res1Bad Res2Bad BreakBad Numb
F-PC for DOS v3.5 (from Chris Jakeman)-1800-180-4-6-18-18
Win32Forth v3.5-2-20-2-18-2-2-16-6
GForth for Unix v0.3.0 (from Bernd Paysan)-4-40-4-16-3-6-3-6
GForth for Win32 v0.3.0(1)-16-160-16-16-16-6-16-6
GForth for DOS v0.3.0-4-40-4-18-3-6-3-6
iForth v1.07 Linux (from Marcel Hendrix)-3-30-3-20-3-3-11(2)-11
iForth v5.0 Win32 (from Marcel Hendrix)-200-2-6(3)0(4)-4-14(5)-2
mxForth v2.4 Linux (from Marcel Hendrix)-7-70-7-20-7-7-11(2)-11
4tH v3.62.2 (from Hans Bezemer)-2-20-20-2-6-14-2
  1. The Win32 results are much worse than the Unix ones due to a bug in the cygwin32 library, not GForth.
  2. Under NT it is not possible to achieve -11, but only -14.
  3. Returns with two numbers on the stack. What is the correct response?
  4. iForth can't compile this code (exception at compile time).
  5. Results on Linux should be much better.