Stop an armed TRAP from swallowing parse errors whole
A program with TRAP set and a line that would not parse printed nothing at all and exited zero. No error line, because akbasic_runtime_error() intercepts for the trap and deliberately prints nothing; and no handler, because the parse branch of process_line_run() then set run_finished_mode regardless -- QUIT for a file -- so the next line boundary the handler would have been entered at never came. Arming an error handler made errors disappear. The guard is to set the finished mode only when the error was actually reported. The runtime path was always right: report_and_reraise() never touched the mode. The same branch also never recorded the status, so the handler that now runs was handed ER# 0. It sets lasterrorstatus from the context the way report_and_reraise() does, and a trapped SCALE with no arguments reports 512. Found while writing the error-code appendix -- documenting what ER# can hold means provoking each code, and this is what happened on the way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -834,6 +834,7 @@ akerr_ErrorContext *akbasic_runtime_process_line_repl(akbasic_Runtime *obj)
|
||||
} HANDLE_DEFAULT(errctx) {
|
||||
char message[AKERR_MAX_ERROR_CONTEXT_STRING_LENGTH];
|
||||
snprintf(message, sizeof(message), "%s", errctx->message);
|
||||
obj->lasterrorstatus = errctx->status;
|
||||
IGNORE(akbasic_runtime_error(obj, AKBASIC_ERRCLASS_PARSE, message));
|
||||
} FINISH(errctx, false);
|
||||
if ( obj->errclass != AKBASIC_ERRCLASS_NONE ) {
|
||||
@@ -930,8 +931,26 @@ akerr_ErrorContext *akbasic_runtime_process_line_run(akbasic_Runtime *obj)
|
||||
} HANDLE_DEFAULT(errctx) {
|
||||
char message[AKERR_MAX_ERROR_CONTEXT_STRING_LENGTH];
|
||||
snprintf(message, sizeof(message), "%s", errctx->message);
|
||||
/*
|
||||
* What ER# reports, recorded before the context goes -- the same line
|
||||
* report_and_reraise() carries for a runtime error, and it was missing
|
||||
* here, so a trapped parse error handed the handler ER# 0.
|
||||
*/
|
||||
obj->lasterrorstatus = errctx->status;
|
||||
IGNORE(akbasic_runtime_error(obj, AKBASIC_ERRCLASS_PARSE, message));
|
||||
IGNORE(akbasic_runtime_set_mode(obj, obj->run_finished_mode));
|
||||
/*
|
||||
* Only when the error was actually reported. An armed TRAP intercepts
|
||||
* inside akbasic_runtime_error() and leaves `errclass` clear, meaning
|
||||
* "the handler runs at the next line boundary" -- and ending the run
|
||||
* here reaches that boundary never. Setting the mode unconditionally
|
||||
* made a parse error under a TRAP vanish outright: no error line,
|
||||
* because the trap suppressed it, and no handler, because
|
||||
* run_finished_mode for a file is QUIT. Arming an error handler made
|
||||
* errors disappear, which is the opposite of what it is for.
|
||||
*/
|
||||
if ( obj->errclass != AKBASIC_ERRCLASS_NONE ) {
|
||||
IGNORE(akbasic_runtime_set_mode(obj, obj->run_finished_mode));
|
||||
}
|
||||
} FINISH(errctx, false);
|
||||
if ( obj->errclass != AKBASIC_ERRCLASS_NONE ) {
|
||||
SUCCEED_RETURN(errctx);
|
||||
|
||||
Reference in New Issue
Block a user