Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket.send freezes string unexpectedly (RuntimeError: can't modify frozen string) #3249

Closed
boazsegev opened this issue Aug 13, 2015 · 2 comments

Comments

@boazsegev
Copy link

The issue
Opening a TCPSocket and using the send method, freezes the string being sent on JRuby 9000.

This is unexpected and isn't experienced in MRI.

This issue doesn't occur when using socket.write (blocks until done, inherited from the IO class).

How to replicate

  1. Open a TCPSocket object.
  2. Create a long string (so string is a pointer).
  3. Send string using socket.send data, 0
  4. Try to modify string.

Example code

It's possible to replicate the error using the following code:

require 'socket'
Thread.new do
    begin
        server = TCPServer.new 3000
        while sock = server.accept
            sleep 10
            sock.close
        end
    rescue => e
        server.close
    end
end

long_string = "
JRuby is an implementation of the Ruby language using the JVM.

It aims to be a complete, correct and fast implementation of Ruby, at the same time as providing powerful new features such as concurrency without a global-interpreter-lock, true parallelism, and tight integration to the Java language to allow you to uses Java classes in your Ruby program and to allow JRuby to be embedded into a Java application.

You can use JRuby simply as a faster version of Ruby, you can use it to run Ruby on the JVM and access powerful JVM libraries such as highly tuned concurrency primitives, you can use it to embed Ruby as a scripting language in your Java program, or many other possibilites.
"

20.times do |i|
    begin
        s = TCPSocket.new 'localhost', 3000
        str = long_string.dup
        s.send str, 0
        str.clear
        # => JRUBY: RuntimeError: can't modify frozen string
        # => MRI: ""
    rescue => e
        puts "Test \##{i} raised an exception: #{e.message}"
    ensure
        s.close
    end
end
@boazsegev boazsegev changed the title Socket.send freezes string unexpectedly (RuntimeError: can't modify frozen string) Socket.send SOMETIMES freezes string unexpectedly (RuntimeError: can't modify frozen string) Aug 13, 2015
@boazsegev boazsegev changed the title Socket.send SOMETIMES freezes string unexpectedly (RuntimeError: can't modify frozen string) Socket.send freezes string unexpectedly (RuntimeError: can't modify frozen string) Aug 13, 2015
@headius
Copy link
Member

headius commented Aug 18, 2015

I see the problem; it's supposed to create a dup'ed frozen version of the original string, not freeze it in place. Bad porting on my part. Will fix.

@headius headius added this to the JRuby 9.0.1.0 milestone Aug 18, 2015
@boazsegev
Copy link
Author

I'm happy I could help.

One question:

Do you think it would be better to move the Dup+freeze to the write_nonblock?

It seems to me that since syswrite is a blocking method, then data integrity should be assumed and no duplication nor freezing should be required (unless the string is modified, which doesn't seem to be the case).

On the other hand, the write_nonblock should probably Dup+freeze before returning, to maintain data integrity.

This is a micro-optomization that might create data integrity risks if the string is accessed by more than one thread - but these are integrity issues that should probably be handled by the multi-threaded code rather than by JRuby. In fact, I believe that having JRuby protect data integrity on a blocking method will probably result in double the protection when multi-threading is an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants