Fix setBytes when source is read-only ByteBuffer and target is pooled buffer

Motivation:

The method setBytes creates temporary heap buffer when source buffer is read-only.
But this temporary buffer is not used correctly and may lead to data corruption.
This problem occurs when target buffer is pooled and temporary buffer
arrayOffset() is not zero.

Modifications:

Use correct arrayOffset when calling PlatformDependent.copyMemory.
Unit test was added to test this case.

Result:

Setting buffer content works correctly when target is pooled buffer and source
is read-only ByteBuffer.
This commit is contained in:
Karas Lukáš 2016-03-21 18:48:45 +01:00 committed by Norman Maurer
parent 28d03adbfe
commit 42419d918d
2 changed files with 39 additions and 1 deletions

View File

@ -580,7 +580,7 @@ final class UnsafeByteBufUtil {
try {
byte[] tmp = tmpBuf.array();
src.get(tmp, tmpBuf.arrayOffset(), length); // moves the src position too
PlatformDependent.copyMemory(tmp, 0, addr, length);
PlatformDependent.copyMemory(tmp, tmpBuf.arrayOffset(), addr, length);
} finally {
tmpBuf.release();
}

View File

@ -21,6 +21,8 @@ import java.nio.ByteBuffer;
import static io.netty.util.internal.PlatformDependent.directBufferAddress;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class UnsafeByteBufUtilTest {
@ -45,4 +47,40 @@ public class UnsafeByteBufUtilTest {
targetBuffer.release();
}
}
@Test
public void testSetBytesOnReadOnlyByteBufferWithPooledAlloc() throws Exception {
byte[] testData = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int length = testData.length;
ByteBuffer readOnlyBuffer = ByteBuffer.wrap(testData).asReadOnlyBuffer();
int pageSize = 4096;
// create memory pool with one page
ByteBufAllocator alloc = new PooledByteBufAllocator(true, 1, 1, pageSize, 0);
UnpooledDirectByteBuf targetBuffer = new UnpooledDirectByteBuf(alloc, length, length);
ByteBuf b1 = alloc.heapBuffer(16);
ByteBuf b2 = alloc.heapBuffer(16);
try {
// just check that two following buffers share same array but different offset
assertEquals(b1.array().length, pageSize);
assertEquals(b1.array(), b2.array());
assertNotEquals(b1.arrayOffset(), b2.arrayOffset());
UnsafeByteBufUtil.setBytes(targetBuffer, directBufferAddress(targetBuffer.nioBuffer()), 0, readOnlyBuffer);
byte[] check = new byte[length];
targetBuffer.getBytes(0, check, 0, length);
assertArrayEquals("The byte array's copy does not equal the original", testData, check);
} finally {
targetBuffer.release();
b1.release();
b2.release();
}
}
}