Bug #19441
closed
Closing an Tempfile#dup behaviour
Added by stac47 (Laurent Stacul) about 1 year ago.
Updated 6 months ago.
Description
Hello amazing ruby folks!
I classified that ticket as a "Bug" although it is perhaps something I did not understand.
Here is a ruby session:
irb(main):001:0> file = Tempfile.new
=> #<File:/var/folders/m2/bljzrgq160vbf0vk466k_7gw0000gn/T/20230216-39664-davfmj>
irb(main):002:0> file.fileno
=> 9
irb(main):003:0> dup = file.dup
=> #<File:/var/folders/m2/bljzrgq160vbf0vk466k_7gw0000gn/T/20230216-39664-davfmj>
irb(main):004:0> dup.fileno
=> 10
irb(main):005:0> dup.close
=> nil
irb(main):006:0> dup.closed?
=> false
irb(main):007:0> file.closed?
=> true
The two last lines are unexpected to me. I would have expected the converse:
irb(main):006:0> dup.closed?
=> true
irb(main):007:0> file.closed?
=> false
I tried this scenario in latest ruby but also in ruby 2.7.
Thanks in advance for helping me to understand this behaviour.
What do you expect for the dup
ped Tempfile
object?
An IO
to the same file?
Or another temporary file?
Provided #dup
generally returns an object of the same type, I would expect to have a Tempfile
object.
The unexpected thing was that if I replay the same scenario with File
, I have what I expect. I was just wondering whether the behaviour discrepancy between File
and Tempfile
was normal.
irb(main):001:0> file = File.new("a_file.txt", "w+")
=> #<File:a_file.txt>
irb(main):002:0> file.size
=> 0
irb(main):003:0> dup = file.dup
=> #<File:a_file.txt>
irb(main):004:0> dup.closed?
=> false
irb(main):005:0> file.closed?
=> false
irb(main):006:0> dup.close
=> nil
irb(main):007:0> dup.closed?
=> true
irb(main):008:0> file.closed?
=> false
A Tempfile
uses a finalizer to clean up the target file.
That is the file will be removed when a dup of Tempfile
is discarded (and also will be tried to remove again).
I don't think it is a good idea to use Tempfile#dup
.
What do you want to achieve by using this method?
- Subject changed from Closing an IO#dup behaviour to Closing an Tempfile#dup behaviour
Thanks nobu for your answer it makes perfect sense.
My case which led to the current question comes from a Rails application which has a controller receiving a file. My input params[:file]
hold an ActionDispatch::Http::UploadedFile
which itself has an attribute tempfile
.
In the controller, params[:file]
is passed to some functions (I don't have the control of) that can read and close the underlying tempfile
. As a matter a fact, the code calls ActionDispatch::Http::UploadedFile#open
(shortcut to tempfile#open
) after the calls that close the file.
I was wondering whether I could avoid calling #open
by providing the methods which can close the file with a dup
ed file descriptor so that the original ActionDispatch::Http::UploadedFile
is left untouched until I really use it in my own code.
The scenario in itself is not really interesting, it is just I was surprised by the behaviour when I used Tempfile#dup
but your explanation is acceptable. Thanks for this.
- Status changed from Open to Closed
Applied in changeset git|ddcfc9feabf22ed6cc1071e65948a1d512a906fe.
[ruby/tempfile] Fix Tempfile#{dup,clone}
Instead of storing the delegate in @tmpfile, use getobj, since
delegate library already handles dup/clone for that. Copy the
unlinked, mode, and opts instance variables to the returned object
when using dup/clone.
Split the close/unlink finalizer into two finalizers. The close
finalizer always closes when any Tempfile instance is GCed, since
each Tempfile instance uses a separate file descriptor. The unlink
finalizer unlinks only when the original and all duped/cloned
Tempfiles are GCed, since all share the same path.
For Tempfile#open, undefine the close finalizer after closing the
current file, the redefine the close finalizer with the new file.
Fixes [Bug #19441]
https://github.com/ruby/tempfile/commit/dafabf9c7b
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0Like0