TIP #290 Version 1.9: Registration of Custom Error Handler Scripts

This is not necessarily the current version of this TIP.


TIP:290
Title:Registration of Custom Error Handler Scripts
Version:$Revision: 1.9 $
Authors: Eckhard Lehmann <ecky-l at web dot de>
Larry W. Virden <lvirden at yahoo dot com>
State:Draft
Type:Project
Tcl-Version:8.5
Vote:Pending
Created:Sunday, 29 October 2006
Keywords:Tcl, error, trap

Abstract

This TIP proposes the possibility to register custom commands as error handlers.

Rationale

Errors are thrown in the Tcl interpreter through the error command or from a C extension that returns TCL_ERROR. When an error is thrown, the global errorInfo variable is filled with rudimentary stacktrace information and the error message itself. The global errorCode variable can contain an error code if this is provided by the command that has thrown the error.

Errors can be caught with the catch command. In this case, the errorInfo variable is still filled with the information mentioned above, but the error is not presented to the interpreter. If the error is not caught, it is presented to the interpreter and the execution of the current code is aborted immediately

The information in errorInfo is, in some simple cases, useful for reproducing and tracking down the error source and fixing the problem. In more complicated cases however, errorInfo does not include enough information to successfully reproduce the error - information about the application's state is missing.

In other languages such as LISP, this problem is addressed by stopping the execution at the position where the error was thrown (preserving the current callframe) and presenting the developer with a console that enables him to introspect the running program. Although Tcl has very good introspection capabilities, it is not possible to use them in an error case, because the execution just aborts and the stacktrace is unwound at once. For errors generated with the error command, it is possible to overwrite this command and provide more advanced functionality, but this is not possible if errors are generated in C code by return TCL_ERROR.

The proposed implementation addresses this problem by a custom error command that is executed whenever an error occurs in the execution of Tcl code. This opens a range of implementation possibilities for error handling, for instance:

Alternatives

  1. Overwriting of the error command As stated abovem, this works only for errors generated from Tcl code, whereas it does not work for errors from C extensions.

  2. Leavestep execution traces In Tcl >=8.4 it is possible to register execution traces on leavestep to commands. To implement part of the proposed functionality it would be possible to add a leavestep trace procedure, which - after each command - checks for the return code and acts accordingly. The problem with this approach is, that the procedure is called after each command, independent from whether it returned an error or not. This can slow down the program execution more or less significantly. Furthermore, it is not easy if at all possible to capture occurences of catch by this way, so it is complicated or impossible to react on caught errors.

It might be possible to get part or most of the proposed functionality by trace add execution leavestep or overwriting of error. But it is the responsibility of the core language (even more when it is a dynamic language) to provide customizable and advanced error handling. The TIP proposes in this direction.

Specification

The implementation consists of two parts: a registration command for the custom command and a place where the handler is called. For this to work, there are some minor changes necessary to the Tcl execution engine and to the Interp structure. For running the handler on caught and or uncaught errors (depending on how the user wants to have it) it is necessary to capture the current level of "catch"es that occure during execution.

The registration command is responsible for:

The changes in the execution engine should be done so that:

Reference Implementation

The reference implementation is available from sourceforge as a patch against Tcl 8.5a5 [1].

Usage Example

Here is a sample procedure that can be used to stop execution on error and introspect the program using stdin/stdout. It was implemented by Neil Madden as debug-repl and is available (with a short discussion on the topic) on [2]:

package provide debug 1.0

proc up {} {
    uplevel 2 {
        breakpoint
    }
}

proc down {} {
    return -code continue
}

proc breakpoint {args} {
    set cmd ""
    set level [expr {[info level]-1}]
    set prompt "Debug ($level) % "
    while {1} {
        puts -nonewline $prompt
        flush stdout
        gets stdin line
        append cmd $line\n
        if {[info complete $cmd]} {
            set code [catch {uplevel #$level $cmd} result]
            if {$code == 0 && [string length $result]} {
                puts stdout $result
            } elseif {$code == 3} {
                break
            } elseif {$code == 4} {
                # continue
                return
            } else {
                puts stderr $result
            }
            set prompt "Debug ($level) % "
            set cmd ""
        } else {
            set prompt "    "
        }
    }
}

To use it for uncaught errors, the breakpoint procedure can be registered as error command:

package re debug
::tcl::seterrorhandler -uncaught breakpoint

When an error raises, breakpoint is called in the current callframe and Tcl introspection commands like info vars etc. can be used to get information about the program state.

Copyright

This document has been placed in the public domain.


Powered by TclThis is not necessarily the current version of this TIP.

TIP AutoGenerator - written by Donal K. Fellows