Bug #14353


$SAFE should stay at least thread-local for compatibility

Added by Eregon (Benoit Daloze) about 5 years ago. Updated over 3 years ago.

Target version:


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: {
  $SAFE = 1
  sth that should be checked to work under $SAFE==1

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:

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):

  old = $SAFE
  $SAFE = 1
  something under SAFE==1
  $SAFE = old

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?

Related issues 2 (0 open2 closed)

Related to Ruby master - Feature #14250: Make `$SAFE` process global state and allow to set 0 againClosedko1 (Koichi Sasada)Actions
Is duplicate of Ruby master - Feature #5455: $SAFE should be removedRejectedmatz (Yukihiro Matsumoto)Actions

Updated by Eregon (Benoit Daloze) about 5 years ago

  • Assignee set to ko1 (Koichi Sasada)
Actions #2

Updated by Eregon (Benoit Daloze) about 5 years ago

  • Target version set to 2.6
Actions #3

Updated by Eregon (Benoit Daloze) about 5 years ago

  • Related to Feature #14250: Make `$SAFE` process global state and allow to set 0 again added

Updated by shevegen (Robert A. Heiler) about 5 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) about 5 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) about 5 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 '{ $SAFE=1 }.join;{ 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.

Actions #7

Updated by naruse (Yui NARUSE) about 4 years ago

  • Target version deleted (2.6)

Updated by matz (Yukihiro Matsumoto) almost 4 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).


Actions #10

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

Updated by jeremyevans0 (Jeremy Evans) over 3 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.


Also available in: Atom PDF