Bug #14353
closed$SAFE should stay at least thread-local for compatibility
Description
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:
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):
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 (Koichi Sasada) Can we switch it back to thread-local for compatibility, avoiding headaches and keeping it usable with multiple threads?
Updated by Eregon (Benoit Daloze) almost 7 years ago
- Assignee set to ko1 (Koichi Sasada)
Updated by Eregon (Benoit Daloze) almost 7 years ago
- Related to Feature #14250: Make `$SAFE` process global state and allow to set 0 again added
Updated by shevegen (Robert A. Heiler) almost 7 years ago
I have seen $VERBOSE used in ways very similar as you described though and have used
it myself; most commonly I used it e. g. when I would use syck for yaml files rather
than psych, in order to suppress warnings I'd get during loading. It never felt very
elegant though to use the re-assignment trick. Can't think of a more elegant
solution either.
Updated by ko1 (Koichi Sasada) almost 7 years ago
- Assignee changed from ko1 (Koichi Sasada) to matz (Yukihiro Matsumoto)
Of course, I proposed $SAFE
as Fiber
local.
However, Matz said process global is enough.
akr also said nobody use $SAFE
correctly, so that such incompatibility is not a matter.
I'm neutral. Matz, please decide it.
Updated by Eregon (Benoit Daloze) almost 7 years ago
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.
Updated by vo.x (Vit Ondruch) almost 6 years ago
Just FTR, as per this discussion:
The global $SAFE breaks gettext testsuite:
https://github.com/ruby-gettext/gettext/commit/49b9f4ca66583395ddfa91503afd7593f069de18
As well as there are issues in postgresql-plruby:
https://github.com/devrimgunduz/postgresql-plruby/blob/master/extconf.rb#L21
Updated by matz (Yukihiro Matsumoto) almost 6 years ago
I understand the compatibility situation. But I don't think it's worth effort for development. I vote for making $SAFE no effect (in 2.7).
Matz.
Updated by k0kubun (Takashi Kokubun) almost 6 years ago
- Is duplicate of Feature #5455: $SAFE should be removed added
Updated by jeremyevans0 (Jeremy Evans) about 5 years ago
- Status changed from Open to Closed
$SAFE
is being deprecated in 2.7 and will revert to normal global variable in 3.0, so this can be closed.