[ruby-core:85537] [Ruby trunk Bug#14472][Rejected] `File::open` closes the file too early when used with callcc

From: nobu@...
Date: 2018-02-14 01:37:44 UTC
List: ruby-core #85537
Issue #14472 has been updated by nobu (Nobuyoshi Nakada).

Status changed from Open to Rejected

blackenedgold (Sunrin SHIMURA) wrote:
> This code throws an IOError, but expected to exit normally:

`callcc` rollbacks `ensure`s.

> The bugging code is useful to rewrite nested `open` blocks to flat style like this:
> 
> ~~~ ruby
> f1 = callcc {|k| File::open("test1", 'w') {|f| k.(f)}}
> f2 = callcc {|k| File::open("test2", 'w') {|f| k.(f)}}
> f1.write("hello")
> f2.write("hello")
> ~~~

You can do it by `File.open` without a block.
If `callcc` weren't fire `ensure`s, it's unpredictable when `f1` and `f2` will get closed.
It's same as w/o-block form `open`.


----------------------------------------
Bug #14472: `File::open` closes the file too early when used with callcc
https://bugs.ruby-lang.org/issues/14472#change-70326

* Author: blackenedgold (Sunrin SHIMURA)
* Status: Rejected
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.3.3p222 (2016-11-21) [x86_64-linux-gnu]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
First of all, I know `callcc` is deprecated feature and I'm not in trouble with this bug.
I was just curious and happened to find this bug.

# Bug Description

This code throws an IOError, but expected to exit normally:

~~~ ruby
require 'continuation'
f1 = callcc {|k| File::open("test1", 'w') {|f| k.(f)}}
f1.write("hello")
~~~

~~~
$ ruby openfile_cont.rb                   
/usr/lib/x86_64-linux-gnu/ruby/2.3.0/continuation.so: warning: callcc is obsolete; use Fiber instead
openfile_cont.rb:14:in `write': closed stream (IOError)
        from openfile_cont.rb:14:in `<main>'
~~~

I think this is a bug because the code above must be the same as code below, which works fine:

~~~ ruby
File::open("test1", 'w') {|f1| f1.write("hello")}
~~~

In fact, an equivalent scheme code works fine:

~~~scheme
(let* ((f1 (call/cc (lambda (k) (call-with-output-file "test1" k)))))
  (display "hello" f1))
~~~

~~~
$ gosh openfile_cont.scm 
$ cat test1 
hello
~~~


# Importance
Again, I'm not in trouble with this bug.

The bugging code is useful to rewrite nested `open` blocks to flat style like this:

~~~ ruby
File::open("test1", 'w') do |f1|
  File::open("test2", 'w') do |f2|
    f1.write("hello")
    f2.write("hello")
  end
end

~~~

~~~ ruby
f1 = callcc {|k| File::open("test1", 'w') {|f| k.(f)}}
f2 = callcc {|k| File::open("test2", 'w') {|f| k.(f)}}
f1.write("hello")
f2.write("hello")
~~~

Or, even code that cannot be written with nested `open`s can be written with callcc:

~~~ ruby
["test1", "test2", "test3"].map{|path| callcc {|k| File::open(path, 'w') {|f| k.(f)}}}.each do |f|
  f.write("hello")
end
~~~

Again, equivalent scheme code works fine:

~~~
(let ((paths '("test1" "test2" "test3")))
 (let ((ports (map (lambda (path) (call/cc (lambda (k) (call-with-output-file path k)))) paths)))
   (dolist (port ports)
           (display "hello" port))))
~~~




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

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

In This Thread

Prev Next