Skip to content

Commit

Permalink
Fix ByteBuffer string conversions on JRuby
Browse files Browse the repository at this point in the history
The getBytes() method this was previously using converts according to
Java's default charset, which means it is potentially not binary-safe.

It has been replaced with a conversion based on a ByteList rather than
an intermediate Java String type, which should sidestep all
encoding-related issues..
  • Loading branch information
tarcieri committed Dec 13, 2017
1 parent b51180f commit 29aabe2
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 4 deletions.
1 change: 1 addition & 0 deletions ext/nio4r/bytebuffer.c
Expand Up @@ -265,6 +265,7 @@ static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

StringValue(string);
length = RSTRING_LEN(string);

if(length > buffer->limit - buffer->position) {
Expand Down
4 changes: 1 addition & 3 deletions ext/nio4r/org/nio4r/ByteBuffer.java
Expand Up @@ -163,10 +163,8 @@ public IRubyObject fetch(ThreadContext context, IRubyObject index) {

@JRubyMethod(name = "<<")
public IRubyObject put(ThreadContext context, IRubyObject str) {
String string = str.asJavaString();

try {
this.byteBuffer.put(string.getBytes());
this.byteBuffer.put(str.convertToString().getByteList().bytes());
} catch(BufferOverflowException e) {
throw ByteBuffer.newOverflowError(context, "buffer is full");
}
Expand Down
9 changes: 8 additions & 1 deletion lib/nio/bytebuffer.rb
Expand Up @@ -111,15 +111,22 @@ def [](index)

# Add a String to the buffer
#
# @param str [#to_str] data to add to the buffer
#
# @raise [TypeError] given a non-string type
# @raise [NIO::ByteBuffer::OverflowError] buffer is full
#
# @return [self]
def <<(str)
def put(str)
raise TypeError, "expected String, got #{str.class}" unless str.respond_to?(:to_str)
str = str.to_str

raise OverflowError, "buffer is full" if str.length > @limit - @position
@buffer[@position...str.length] = str
@position += str.length
self
end
alias << put

# Perform a non-blocking read from the given IO object into the buffer
# Reads as much data as is immediately available and returns
Expand Down
5 changes: 5 additions & 0 deletions spec/nio/bytebuffer_spec.rb
Expand Up @@ -180,6 +180,11 @@
expect(bytebuffer.limit).to eq capacity
end

it "raises TypeError if given a non-String type" do
expect { bytebuffer << 42 }.to raise_error(TypeError)
expect { bytebuffer << nil }.to raise_error(TypeError)
end

it "raises NIO::ByteBuffer::OverflowError if the buffer is full" do
bytebuffer << "X" * (capacity - 1)
expect { bytebuffer << "X" }.not_to raise_error
Expand Down

0 comments on commit 29aabe2

Please sign in to comment.