Tcl Source Code

View Ticket
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Ticket UUID: 67fd4f973ac46efd5999060ce4aafd4e0093a0a5
Title: incorrect results of 'info exists' when unset env var in one interp and check for existence from another interp
Type: Bug Version: 8.5.x, 8.6.x, 8.7.x
Submitter: GrAnd Created on: 2019-05-20 17:48:50
Subsystem: 17. Commands I-L Assigned To: nobody
Priority: 5 Medium Severity: Severe
Status: Open Last Modified: 2019-05-20 17:48:50
Resolution: None Closed By: nobody
    Closed on:
Description:

There are 2 interpreters main and slave. If I do "set ::env(FOO) bar", it appears in both interps ("info exists ::env(FOO)" reports 1 and I can actually read the var. Then, if I do "unset ::env(FOO)" in any interp, this var fully disappears in that interp ("info exists ::env(FOO)" returns 0 and on read an error is generated). But, in another interp "info exists ::env(FOO)" still claims that the var exists (returns 1), but if I actually try to read that variable I get an error.

Test script:

#!/bin/bash
#\
exec tclsh "$0"

puts "TCL version: [info patchlevel]\n"

proc checkGlobal {name} { puts -nonewline "${::context}: exists: [expr {[info exists ::env($name)]?"YES":" NO"}]" puts " | read: [expr {[catch {set ::env($name)} err]?"ERROR: $err":"OK"}]" } proc setGlobal {name} { set ::env($name) "Value" puts "${::context}: set" } proc unsetGlobal {name} { unset ::env($name) puts "${::context}: unset" }

set context "GLOBAL" set name "SOME_DUMMY_VAR_GLOBAL" puts "Checking Interp ${context}| var $name" checkGlobal $name setGlobal $name checkGlobal $name unsetGlobal $name checkGlobal $name puts ""

set I [interp create] # alias 3 procs above from global space and create the same procs in slave interp foreach p {check set unset} { interp alias $I ${p}Global {} ${p}Global $I eval [subst { proc ${p}Slave [list [info args ${p}Global]] [list [info body ${p}Global]] }] }

$I eval { proc checkBoth {name} { checkSlave $name checkGlobal $name }

set context "SLAVE " set name "SOME_DUMMY_VAR_SLAVE" puts "Checking Interp ${context}| var $name" checkBoth $name puts "" setSlave $name checkBoth $name unsetSlave $name checkBoth $name puts "" setGlobal $name checkBoth $name unsetGlobal $name checkBoth $name puts "" setSlave $name checkBoth $name puts "WORKAROUND: unset twice (in both interps)" unsetSlave $name unsetGlobal $name checkBoth $name puts "" }

And the output of script above:

TCL version: 8.7a1

Checking Interp GLOBAL| var SOME_DUMMY_VAR_GLOBAL GLOBAL: exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_GLOBAL)": no such variable GLOBAL: set GLOBAL: exists: YES | read: OK GLOBAL: unset GLOBAL: exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_GLOBAL)": no such variable

Checking Interp SLAVE | var SOME_DUMMY_VAR_SLAVE SLAVE : exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable GLOBAL: exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable

SLAVE : set SLAVE : exists: YES | read: OK GLOBAL: exists: YES | read: OK SLAVE : unset SLAVE : exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable GLOBAL: exists: YES | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable <<<<<<<<<< ????

GLOBAL: set SLAVE : exists: YES | read: OK GLOBAL: exists: YES | read: OK GLOBAL: unset SLAVE : exists: YES | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable <<<<<<<<<< ???? GLOBAL: exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable

SLAVE : set SLAVE : exists: YES | read: OK GLOBAL: exists: YES | read: OK WORKAROUND: unset twice (in both interps) SLAVE : unset GLOBAL: unset SLAVE : exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable GLOBAL: exists: NO | read: ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable