Ticket UUID: | 86b3c15f0c99a64f3aeb09eba009bccc1b726148 | |||
Title: | ::unknown has infinite recursion in a corner case | |||
Type: | Patch | Version: | all | |
Submitter: | kjnash | Created on: | 2024-02-02 19:14:38 | |
Subsystem: | 18. Commands M-Z | Assigned To: | jan.nijtmans | |
Priority: | 5 Medium | Severity: | Minor | |
Status: | Closed | Last Modified: | 2024-02-06 15:08:08 | |
Resolution: | Fixed | Closed By: | jan.nijtmans | |
Closed on: | 2024-02-06 15:08:08 | |||
Description: |
The command ::unknown is careful to evaluate commands in the namespace of the caller - with one exception, which in a corner case can lead to infinite recursion. The corner case is unusual but not perverse - it occurs when ::unknown is renamed into a different namespace. Sometimes a package renames ::unknown - e.g. TclReadLine (a pure-Tcl replacement for GNU readline, https://wiki.tcl-lang.org/20215 ) renames ::unknown to ::_unknown and replaces it with its own ::unknown command, which calls ::_unknown. While experimenting with improvements to TclReadLine, I decided to rename ::unknown into the ::TclReadLine namespace, in order to avoid pollution of the global namespace. This exposes the bug. If the user types a command that exists in the ::TclReadLine namespace but not in the global namespace, the renamed ::unknown goes into infinite recursion: it believes it has found the command, but when it tries to execute it, it is not there. A simple demonstration is to type these commands in an interactive shell: namespace eval ::foo {} rename unknown ::foo::unknown interp alias {} unknown {} ::foo::unknown proc ::foo::bar {} {} bar The fix is simple, and is in the patch attached. The bug is found in all versions of Tcl. In view of the importance of ::unknown, I would appreciate review before committing this change. diff -Naur original/library/init.tcl patched/library/init.tcl --- original/library/init.tcl 2023-08-21 02:45:35.424433637 +0100 +++ patched/library/init.tcl 2024-02-02 18:41:18.049045928 +0000 @@ -371,7 +371,10 @@ return -options $::tcl::UnknownOptions $::tcl::UnknownResult } - set ret [catch {set candidates [info commands $name*]} msg] + set ret [catch [list uplevel 1 [list info commands $name*]] msg] + if {$ret == 0} { + set candidates $msg + } if {$name eq "::"} { set name "" } | |||
User Comments: |
jan.nijtmans added on 2024-02-06 15:08:08:
Fixed [524d68410a678b23|here]. Thanks for the report and the patch! |
Attachments:
- init-unknown-86.patch [download] added by kjnash on 2024-02-02 19:15:48. [details]