[ruby/tempfile] Ensure finalizer order in Tempfile
The Closer and Remover finalizers are defined on different objects in Tempfile. The Closer is defined on the Tempfile object while the Remover is defined on the finalizer_obj. This means that there is no guarantee of the finalizer order. On Windows, we must close the file before removing it because we cannot remove an open file. But since the order is not guaranteed, the GC may run the Remover finalizer first, which will fail with an Errno::EACCES (Permission denied @ apply2files). This commit changes it so that both the Closer and Remover finalizers are defined on the finalizer_obj, which guarantees the order that it is ran. https://github.com/ruby/tempfile/commit/eb2d8b1175
This commit is contained in:
parent
d6f18b226e
commit
41b427a264
@ -228,22 +228,25 @@ class Tempfile < DelegateClass(File)
|
||||
tmpfile = File.open(tmpname, @mode, **opts)
|
||||
@opts = opts.freeze
|
||||
end
|
||||
ObjectSpace.define_finalizer(@finalizer_obj, Remover.new(tmpfile.path))
|
||||
ObjectSpace.define_finalizer(self, Closer.new(tmpfile))
|
||||
|
||||
super(tmpfile)
|
||||
|
||||
define_finalizers
|
||||
end
|
||||
|
||||
private def define_finalizers
|
||||
ObjectSpace.define_finalizer(@finalizer_obj, Closer.new(__getobj__))
|
||||
ObjectSpace.define_finalizer(@finalizer_obj, Remover.new(__getobj__.path))
|
||||
end
|
||||
|
||||
def initialize_dup(other) # :nodoc:
|
||||
initialize_copy_iv(other)
|
||||
super(other)
|
||||
ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
|
||||
end
|
||||
|
||||
def initialize_clone(other) # :nodoc:
|
||||
initialize_copy_iv(other)
|
||||
super(other)
|
||||
ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
|
||||
end
|
||||
|
||||
private def initialize_copy_iv(other) # :nodoc:
|
||||
@ -256,10 +259,13 @@ class Tempfile < DelegateClass(File)
|
||||
# Opens or reopens the file with mode "r+".
|
||||
def open
|
||||
_close
|
||||
ObjectSpace.undefine_finalizer(self)
|
||||
|
||||
mode = @mode & ~(File::CREAT|File::EXCL)
|
||||
__setobj__(File.open(__getobj__.path, mode, **@opts))
|
||||
ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
|
||||
|
||||
ObjectSpace.undefine_finalizer(@finalizer_obj)
|
||||
define_finalizers
|
||||
|
||||
__getobj__
|
||||
end
|
||||
|
||||
@ -327,7 +333,10 @@ class Tempfile < DelegateClass(File)
|
||||
# may not be able to unlink on Windows; just ignore
|
||||
return
|
||||
end
|
||||
|
||||
ObjectSpace.undefine_finalizer(@finalizer_obj)
|
||||
ObjectSpace.define_finalizer(@finalizer_obj, Closer.new(__getobj__))
|
||||
|
||||
@unlinked = true
|
||||
end
|
||||
alias delete unlink
|
||||
|
Loading…
x
Reference in New Issue
Block a user