Tcl Source Code

View Ticket
Login
Ticket UUID: 8e666d7c956372d0df195e27d36a53fdbad9164d
Title: Redefining proc ::history locks the interpreter into a tight loop
Type: Patch Version: 8.6.13, 8.7
Submitter: kjnash Created on: 2024-02-03 14:36:50
Subsystem: 19. [history] Assigned To: jan.nijtmans
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2024-02-07 13:06:45
Resolution: Fixed Closed By: jan.nijtmans
    Closed on: 2024-02-07 13:06:45
Description:
While investigating [fe4d7305a8], which has been fixed, I found another bug.

::history is a proc that calls the namespace ensemble ::tcl::history whose components are procs ::tcl::Hist*.  All these commands are defined in file library/history.tcl, are listed (except ::tcl::history) in library/tclIndex, and are loaded on demand by the autoloader.

File library/history.tcl also sets a trace on command ::history, so that if it is deleted, all the related commands ::tcl::* are deleted, and the array ::tcl::history that stores the command history is unset.

If ::history is renamed or deleted, the autoloader reloads it when the next command is entered into the interactive interpreter.

The user should be able to redefine proc ::history, to provide an alternative to the Tcl built-in command.  However, the attempt may cause the interpreter to cease functioning, notably when the new proc is identical to the old.  The interpreter enters a tight CPU-consuming loop, and never reaches the point where it can accept another command.

What seems to be happening is that the tailcall in ::history attempts to evaluate "history" in namespace ::tcl, expecting to evaluate ::tcl::history, but because that command is absent it evaluates ::history instead, leading to infinite recursion.  A fix is:

1. To list ::tcl::history in library/tclIndex

2. To request ::tcl::history explicitly in the tailcall

The fix is in the attached patch, which is listed below.

Other matters:

(a) Does the trace on ::history (deleting all dependencies ::tcl::*) serve any useful purpose, apart from saving memory?  I suggest removing it.

(b) The interpreter usually catches infinite recursion.  In this case it does not.

In view of the importance of ::history, I would appreciate review before committing this change.  If nobody objects I will also remove the trace mentioned above.


diff -Naur original/library/history.tcl patched/library/history.tcl
--- original/library/history.tcl        2024-01-18 17:18:18.000000000 +0000
+++ patched/library/history.tcl 2024-02-03 16:53:40.144116588 +0000
@@ -53,7 +53,7 @@
     }
 
     # Tricky stuff needed to make stack and errors come out right!
-    tailcall apply {arglist {tailcall history {*}$arglist} ::tcl} $args
+    tailcall apply {arglist {tailcall ::tcl::history {*}$arglist} ::tcl} $args
 }
 

 # (unnamed) --
diff -Naur original/library/tclIndex patched/library/tclIndex
--- original/library/tclIndex   2024-01-18 17:18:18.000000000 +0000
+++ patched/library/tclIndex    2024-02-03 16:45:46.591373179 +0000
@@ -20,6 +20,7 @@
 set auto_index(::auto_mkindex_parser::commandInit) [list source [file join $dir auto.tcl]]
 set auto_index(::auto_mkindex_parser::fullname) [list source [file join $dir auto.tcl]]
 set auto_index(history) [list source [file join $dir history.tcl]]
+set auto_index(::tcl::history) [list source [file join $dir history.tcl]]
 set auto_index(::tcl::HistAdd) [list source [file join $dir history.tcl]]
 set auto_index(::tcl::HistKeep) [list source [file join $dir history.tcl]]
 set auto_index(::tcl::HistClear) [list source [file join $dir history.tcl]]
User Comments: jan.nijtmans added on 2024-02-07 13:06:45:

Fixed [3fe9d2e41913336b|here]. Thanks for the thorough analysis, and the patch!

> (b) A separate issue really ....

Yes, a separate issue. I have no idea whether the interpreter should/could catch this.


kjnash added on 2024-02-07 12:09:53:
(a) OK, let's keep the trace, it was just a bit confusing when trying to understand the bug!

(b) A separate issue really.  Is it expected that the interpreter does not catch the infinite recursion in this case?

jan.nijtmans added on 2024-02-06 13:41:11:

> If nobody objects I will also remove the trace mentioned above.

It looks like this trace was added on purpose: https://core.tcl-lang.org/tcl/info/3135d5681f5949c8

Therefore, I think removing it is a bad idea (but better ask @dkf, as he did this commit)

Patch looks OK to me. Committed to a branch now.


Attachments: