Skip to content

Several read-only methods fail if StringIO is frozen #120

Open
@headius

Description

@headius

Problem

While fixing a small regression from my recent StringIO fixes I discovered that a large number of read-only methods will fail if the StringIO is frozen. A few examples:

$ ruby -rstringio -e 's = StringIO.new; p s.lineno; s.freeze; p s.lineno' 
0
-e:1:in 'StringIO#lineno': can't modify frozen StringIO: #<StringIO:0x0000000103711ea8> (FrozenError)
	from -e:1:in '<main>'
$ ruby -rstringio -e 's = StringIO.new; p s.closed?; s.freeze; p s.closed?'
false
-e:1:in 'StringIO#closed?': can't modify frozen StringIO: #<StringIO:0x00000001008c1e68> (FrozenError)
	from -e:1:in '<main>'
$ ruby -rstringio -e 's = StringIO.new; p s.eof?; s.freeze; p s.eof?'
true
-e:1:in 'StringIO#eof?': can't modify frozen StringIO: #<StringIO:0x000000011c171e80> (FrozenError)
	from -e:1:in '<main>'
$ ruby -rstringio -e 's = StringIO.new; p s.pos; s.freeze; p s.pos'
0
-e:1:in 'StringIO#pos': can't modify frozen StringIO: #<StringIO:0x0000000105551df0> (FrozenError)
	from -e:1:in '<main>'

Cause

This is because the StringIO macro calls get_strio which calls rb_io_taint_check which calls rb_check_frozen. The StringIO macro is used in almost every method to access the rb_stringio_t data structure.

A list of methods I believe should be operable when the StringIO is frozen (in stringio.c definition order):

  • string (returns underlying String but does not mutate anything)
  • lineno
  • pos
  • closed?/closed_read?/closed_write?
  • eof/eof?
  • sync
  • pid (a dummy method but it writes nothing)
  • fileno (dummy)
  • pread (by definition does not modify state)
  • isatty/tty?
  • size/length
  • external_encoding
  • internal_encoding

In addition, initialize_copy probably should not require the original StringIO be writable:

$ cx 3.4 ruby -rstringio -e 's = StringIO.new("foo"); s.freeze; p s.dup'                                                                                           
-e:1:in 'StringIO#initialize_copy': can't modify frozen StringIO: #<StringIO:0x0000000102eb1df8> (FrozenError)
	from -e:1:in 'Kernel#initialize_dup'
	from -e:1:in 'Kernel#dup'
	from -e:1:in '<main>'

The data from the original StringIO is unmodified by initialize_copy, other than the reference-counting ptr->count (which should not be subject to frozen checks).

Origin

I believe most of these cases are caused by this change from 2011 that added frozen checks to StringIO (the class and the macro).
ruby/ruby@d8d9bac

Fix

Assuming we agree these read-only methods should work with a frozen, I'll modify them in the JRuby extension to do the equivalent of check_strio which only confirms the ptr has been initialized. Perhaps a StringIOReadOnly macro would make sense for CRuby.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions