Tcl Source Code

View Ticket
Login
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: (text/x-fossil-wiki)
There are 2 interpreters main and slave.
If I do <tt>"set ::env(FOO) bar"</tt>, it appears in both interps (<tt>"info exists ::env(FOO)"</tt> reports 1 and I can actually read the var.
Then, if I do <tt>"unset ::env(FOO)"</tt> in any interp, this var fully disappears in that interp (<tt>"info exists ::env(FOO)"</tt> returns 0 and on read an error is generated). But, in another interp <tt>"info exists ::env(FOO)"</tt> still claims that the var exists (returns 1), but if I actually try to read that variable I get an error.

Test script:
<pre>
#!/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 ""
}
</pre>

And the output of script above:
<pre>
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
<span style="color: red;">GLOBAL: exists: YES   |    read:  ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable   <b><<<<<<<<<< ????</b></span>

GLOBAL: set
SLAVE : exists: YES   |    read:  OK
GLOBAL: exists: YES   |    read:  OK
GLOBAL: unset
<span style="color: red;">SLAVE : exists: YES   |    read:  ERROR: can't read "::env(SOME_DUMMY_VAR_SLAVE)": no such variable   <b><<<<<<<<<< ????</b></span>
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
</pre>