Garret Wilson created THRIFT-4856:
-------------------------------------

             Summary: Java protocol implementation ByteBuffer usage makes 
assumptions.
                 Key: THRIFT-4856
                 URL: https://issues.apache.org/jira/browse/THRIFT-4856
             Project: Thrift
          Issue Type: Bug
          Components: Java - Library
    Affects Versions: 0.12.0
            Reporter: Garret Wilson


In all the Java concrete implementations of {{TProtocol.writeBinary(ByteBuffer 
buf)}}, the code makes assumptions about the state of the byte buffer. In other 
words, it only works because relies on assumptions about the implementation of 
the code calling it. The code could break at any time.

All the Java implementations of {{TProtocol.writeBinary(ByteBuffer buf)}} look 
something like this (example from {{TBinaryProtocol}}):

{code}
  public void writeBinary(ByteBuffer bin) throws TException {
    int length = bin.limit() - bin.position();
    writeI32(length);
    trans_.write(bin.array(), bin.position() + bin.arrayOffset(), length);
  }
{code}

Note that the code blindly grabs {{bin.array()}}. But the API documentation for 
[ByteBuffer.array()|https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/ByteBuffer.html#array()]
 clearly states that this is an optional operation, and even says:

{quote}
Invoke the 
[hasArray|https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/ByteBuffer.html#hasArray()]
 method before invoking this method in order to ensure that this buffer has an 
accessible backing array.
{quote}

This is explained on Stack Overflow at [ByteBuffer to byte 
array|https://stackoverflow.com/q/28940174/421049], [Gets byte array from a 
ByteBuffer in java|https://stackoverflow.com/q/679298/421049], and [Convert 
ByteBuffer to byte array java|https://stackoverflow.com/q/28744096/421049], 
among others.

To fix this you'll first need to call 
[ByteBuffer.hasArray()|https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/ByteBuffer.html#hasArray()]
 to see if the byte buffer even has a backing array, and if not, you'll need to 
copy the bytes as explained at the Stack Overflow links above.

You might say, "but {{TProtocol.writeBinary(ByteBuffer buf)}} requires that the 
caller only send byte buffers that are backed by arrays". Fine, but that's not 
what the contract to {{TProtocol.writeBinary(ByteBuffer buf)}} says. In fact … 
it doesn't say anything!! Here is the definition in {{TProtocol}}

{code}
public abstract void writeBinary(ByteBuffer buf) throws TException;
{code}

If you want to keep the implementations you have and require that the byte 
buffer always be backed by an array, that needs to explicitly be added to the 
method contract, e.g.:

{code}
/**
 * Writes a Thrift binary value to the underlying transport.
 * <p>This method requires that the provided buffer be backed by an array;
 * that is, <code>buf.hasArray()</code> returns <code>true</code>.</p>
 * @param buf The byte buffer containing the bytes to write.
 * @throws TException if there is an error writing the bytes.
 */
public abstract void writeBinary(ByteBuffer buf) throws TException;
{code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to