Issue #14353 has been updated by Eregon (Benoit Daloze).


> Of course, I proposed $SAFE as Fiber local.

:)

If $SAFE had no effect at all, then I think it would be fine to make $SAFE a normal process-wide global variable.
But this is not the case, $SAFE still causes SecurityError.
Therefore any library/code setting $SAFE will potentially break other threads, which is quite incompatible.

I think a more compatible way to remove $SAFE is:
* Warn that $SAFE is deprecated.
* Make it Fiber-local or Thread-local. (because very few people expect it frame-local and it incurs a cost)
* Warn that $SAFE is has no longer any effect (or maybe even raise when $SAFE is set, like for levels 2-4) and remove $SAFE checks, so the value of $SAFE has no effect.
* Remove the variable entirely or let it be process global.

Something like

    ruby -e 'Thread.new{ $SAFE=1 }.join; Thread.new{ load "test.rb".taint }.join'

fails, prints no warning and could happen in any big application if $SAFE is set to 1 in some Thread.
This doesn't seem worth breaking. Even more so without a warning.

----------------------------------------
Bug #14353: $SAFE should stay at least thread-local for compatibility
https://bugs.ruby-lang.org/issues/14353#change-69600

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 2.6
* ruby -v: 
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
In #14250 $SAFE changed from a frame+thread-local variable to a process-wide global variable.

This feels wrong and breaks the most common usage of $SAFE in tests:

~~~ ruby
Thread.new {
  $SAFE = 1
  sth that should be checked to work under $SAFE==1
}.join
~~~

It is very clear this is incompatible given how many files (33!) had to be changed in r61510.
And it has wide ranging confusing side-effects, one example: https://travis-ci.org/ruby/spec/jobs/328524568

I agree frame-local is too much for $SAFE.

But removing thread-local seems to only introduce large incompatibilities.

It also makes it impossible to use it in a thread-safe way.
The common pattern (not necessarily for $SAFE, more often for $VERBOSE):

~~~ ruby
begin
  old = $SAFE
  $SAFE = 1
  something under SAFE==1
ensure
  $SAFE = old
end
~~~

is unsafe if two threads run it concurrently (The last thread executing `$SAFE = old` might restore to 1 even though it should be 0).

(Actually I believe most built-in variables (e.g. $VERBOSE) should be thread-local and not process-wide due to this)

Since $SAFE is being deprecated and removed, I don't see any reason to make it more incompatible than needed.

@ko1 Can we switch it back to thread-local for compatibility, avoiding headaches and keeping it usable with multiple threads?



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>