Skip to content
This repository was archived by the owner on Dec 12, 2022. It is now read-only.

Commit da70f29

Browse files
committed
Fix numerous bugs in the ByteBufAdaptor
1 parent 45074e4 commit da70f29

File tree

3 files changed

+125
-41
lines changed

3 files changed

+125
-41
lines changed

src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java

Lines changed: 75 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@
3838
public final class ByteBufAdaptor extends ByteBuf {
3939
private final ByteBufAllocatorAdaptor alloc;
4040
private final Buffer buffer;
41+
private final boolean hasMemoryAddress;
4142

4243
public ByteBufAdaptor(ByteBufAllocatorAdaptor alloc, Buffer buffer) {
4344
this.alloc = alloc;
4445
this.buffer = buffer;
46+
hasMemoryAddress = buffer.nativeAddress() != 0;
4547
}
4648

4749
/**
@@ -70,7 +72,14 @@ public int capacity() {
7072
public ByteBuf capacity(int newCapacity) {
7173
int diff = newCapacity - capacity() - buffer.writableBytes();
7274
if (diff > 0) {
73-
buffer.ensureWritable(diff);
75+
try {
76+
buffer.ensureWritable(diff);
77+
} catch (IllegalStateException e) {
78+
if (!buffer.isOwned()) {
79+
throw new UnsupportedOperationException(e);
80+
}
81+
throw e;
82+
}
7483
}
7584
return this;
7685
}
@@ -103,7 +112,7 @@ public ByteBuf unwrap() {
103112

104113
@Override
105114
public boolean isDirect() {
106-
return buffer.nativeAddress() != 0;
115+
return hasMemoryAddress;
107116
}
108117

109118
@Override
@@ -186,6 +195,7 @@ public ByteBuf clear() {
186195

187196
@Override
188197
public ByteBuf discardReadBytes() {
198+
checkAccess();
189199
buffer.compact();
190200
return this;
191201
}
@@ -197,9 +207,10 @@ public ByteBuf discardSomeReadBytes() {
197207

198208
@Override
199209
public ByteBuf ensureWritable(int minWritableBytes) {
200-
try {
201-
if (writableBytes() < minWritableBytes) {
202-
int borrows = buffer.countBorrows();
210+
checkAccess();
211+
if (writableBytes() < minWritableBytes) {
212+
int borrows = buffer.countBorrows();
213+
try {
203214
if (borrows == 0) {
204215
// Good place.
205216
buffer.ensureWritable(minWritableBytes);
@@ -212,9 +223,9 @@ public ByteBuf ensureWritable(int minWritableBytes) {
212223
retain(borrows);
213224
}
214225
}
226+
} catch (IllegalArgumentException e) {
227+
throw new IndexOutOfBoundsException(e.getMessage());
215228
}
216-
} catch (IllegalStateException e) {
217-
throw new IllegalReferenceCountException(e);
218229
}
219230
return this;
220231
}
@@ -453,6 +464,9 @@ public ByteBuf getBytes(int index, byte[] dst) {
453464

454465
@Override
455466
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
467+
if (index < 0 || capacity() < index + length) {
468+
throw new IndexOutOfBoundsException();
469+
}
456470
for (int i = 0; i < length; i++) {
457471
dst[dstIndex + i] = getByte(index + i);
458472
}
@@ -636,9 +650,7 @@ public ByteBuf setDouble(int index, double value) {
636650

637651
@Override
638652
public ByteBuf setBytes(int index, ByteBuf src) {
639-
if (!buffer.isAccessible()) {
640-
throw new IllegalReferenceCountException();
641-
}
653+
checkAccess();
642654
while (src.isReadable() && index < capacity()) {
643655
setByte(index++, src.readByte());
644656
}
@@ -647,6 +659,7 @@ public ByteBuf setBytes(int index, ByteBuf src) {
647659

648660
@Override
649661
public ByteBuf setBytes(int index, ByteBuf src, int length) {
662+
checkAccess();
650663
for (int i = 0; i < length; i++) {
651664
setByte(index + i, src.readByte());
652665
}
@@ -685,13 +698,15 @@ public ByteBuf setBytes(int index, ByteBuffer src) {
685698

686699
@Override
687700
public int setBytes(int index, InputStream in, int length) throws IOException {
701+
checkAccess();
688702
byte[] bytes = in.readNBytes(length);
689703
setBytes(index, bytes, 0, length);
690704
return bytes.length;
691705
}
692706

693707
@Override
694708
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
709+
checkAccess();
695710
ByteBuffer transfer = ByteBuffer.allocate(length);
696711
int bytes = in.read(transfer);
697712
transfer.flip();
@@ -701,6 +716,7 @@ public int setBytes(int index, ScatteringByteChannel in, int length) throws IOEx
701716

702717
@Override
703718
public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
719+
checkAccess();
704720
ByteBuffer transfer = ByteBuffer.allocate(length);
705721
int bytes = in.read(transfer, position);
706722
transfer.flip();
@@ -925,8 +941,9 @@ public double readDouble() {
925941
@Override
926942
public ByteBuf readBytes(int length) {
927943
Buffer copy = preferredBufferAllocator().allocate(length);
928-
buffer.copyInto(0, copy, 0, length);
929-
return wrap(copy);
944+
buffer.copyInto(0, copy, readerIndex(), length);
945+
readerIndex(readerIndex() + length);
946+
return wrap(copy).writerIndex(length);
930947
}
931948

932949
@Override
@@ -1262,6 +1279,9 @@ public int writeBytes(FileChannel in, long position, int length) throws IOExcept
12621279

12631280
@Override
12641281
public ByteBuf writeZero(int length) {
1282+
if (length < 0) {
1283+
throw new IllegalArgumentException();
1284+
}
12651285
ensureWritable(length);
12661286
for (int i = 0; i < length; i++) {
12671287
writeByte(0);
@@ -1278,7 +1298,32 @@ public int writeCharSequence(CharSequence sequence, Charset charset) {
12781298

12791299
@Override
12801300
public int indexOf(int fromIndex, int toIndex, byte value) {
1281-
for (int i = fromIndex; i < toIndex; i++) {
1301+
if (!buffer.isAccessible()) {
1302+
return -1;
1303+
}
1304+
int inc, start, end;
1305+
if (fromIndex <= toIndex) {
1306+
inc = 1;
1307+
start = fromIndex;
1308+
end = toIndex - 1;
1309+
if (start < 0) {
1310+
start = 0; // Required to pass regression tests.
1311+
}
1312+
if (capacity() <= end) {
1313+
throw new IndexOutOfBoundsException();
1314+
}
1315+
} else {
1316+
inc = -1;
1317+
start = fromIndex - 1;
1318+
end = toIndex;
1319+
if (capacity() <= start) {
1320+
start = capacity() - 1; // Required to pass regression tests.
1321+
}
1322+
if (end < 0) {
1323+
throw new IndexOutOfBoundsException();
1324+
}
1325+
}
1326+
for (int i = start; i != end; i += inc) {
12821327
if (getByte(i) == value) {
12831328
return i;
12841329
}
@@ -1307,38 +1352,30 @@ public int bytesBefore(int index, int length, byte value) {
13071352

13081353
@Override
13091354
public int forEachByte(ByteProcessor processor) {
1310-
if (!buffer.isAccessible()) {
1311-
throw new IllegalReferenceCountException();
1312-
}
1355+
checkAccess();
13131356
int index = readerIndex();
13141357
int bytes = buffer.openCursor().process(processor);
13151358
return bytes == -1 ? -1 : index + bytes;
13161359
}
13171360

13181361
@Override
13191362
public int forEachByte(int index, int length, ByteProcessor processor) {
1320-
if (!buffer.isAccessible()) {
1321-
throw new IllegalReferenceCountException();
1322-
}
1363+
checkAccess();
13231364
int bytes = buffer.openCursor(index, length).process(processor);
13241365
return bytes == -1 ? -1 : index + bytes;
13251366
}
13261367

13271368
@Override
13281369
public int forEachByteDesc(ByteProcessor processor) {
1329-
if (!buffer.isAccessible()) {
1330-
throw new IllegalReferenceCountException();
1331-
}
1370+
checkAccess();
13321371
int index = readerIndex();
13331372
int bytes = buffer.openReverseCursor().process(processor);
13341373
return bytes == -1 ? -1 : index - bytes;
13351374
}
13361375

13371376
@Override
13381377
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
1339-
if (!buffer.isAccessible()) {
1340-
throw new IllegalReferenceCountException();
1341-
}
1378+
checkAccess();
13421379
int bytes = buffer.openReverseCursor(index, length).process(processor);
13431380
return bytes == -1 ? -1 : index - bytes;
13441381
}
@@ -1350,9 +1387,7 @@ public ByteBuf copy() {
13501387

13511388
@Override
13521389
public ByteBuf copy(int index, int length) {
1353-
if (!buffer.isAccessible()) {
1354-
throw new IllegalReferenceCountException();
1355-
}
1390+
checkAccess();
13561391
try {
13571392
BufferAllocator allocator = preferredBufferAllocator();
13581393
Buffer copy = allocator.allocate(length);
@@ -1374,9 +1409,7 @@ public ByteBuf slice() {
13741409

13751410
@Override
13761411
public ByteBuf retainedSlice() {
1377-
if (!buffer.isAccessible()) {
1378-
throw new IllegalReferenceCountException();
1379-
}
1412+
checkAccess();
13801413
return wrap(buffer.slice());
13811414
}
13821415

@@ -1389,6 +1422,7 @@ public ByteBuf slice(int index, int length) {
13891422

13901423
@Override
13911424
public ByteBuf retainedSlice(int index, int length) {
1425+
checkAccess();
13921426
try {
13931427
return wrap(buffer.slice(index, length));
13941428
} catch (IllegalStateException e) {
@@ -1405,7 +1439,7 @@ public ByteBuf duplicate() {
14051439

14061440
@Override
14071441
public ByteBuf retainedDuplicate() {
1408-
return retainedSlice(0, capacity());
1442+
return retainedSlice(0, capacity()).setIndex(readerIndex(), writerIndex());
14091443
}
14101444

14111445
@Override
@@ -1420,9 +1454,7 @@ public ByteBuffer nioBuffer() {
14201454

14211455
@Override
14221456
public ByteBuffer nioBuffer(int index, int length) {
1423-
if (!buffer.isAccessible()) {
1424-
throw new IllegalReferenceCountException();
1425-
}
1457+
checkAccess();
14261458
ByteBuffer copy = isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
14271459
while (index < length) {
14281460
copy.put(getByte(index++));
@@ -1432,9 +1464,7 @@ public ByteBuffer nioBuffer(int index, int length) {
14321464

14331465
@Override
14341466
public ByteBuffer internalNioBuffer(int index, int length) {
1435-
if (!buffer.isAccessible()) {
1436-
throw new IllegalReferenceCountException();
1437-
}
1467+
checkAccess();
14381468
if (readerIndex() <= index && index < writerIndex() && length <= readableBytes()) {
14391469
// We wish to read from the internal buffer.
14401470
if (buffer.countReadableComponents() != 1) {
@@ -1504,7 +1534,7 @@ public int arrayOffset() {
15041534

15051535
@Override
15061536
public boolean hasMemoryAddress() {
1507-
return buffer.nativeAddress() != 0;
1537+
return hasMemoryAddress;
15081538
}
15091539

15101540
@Override
@@ -1612,6 +1642,12 @@ public boolean release(int decrement) {
16121642
return !buffer.isAccessible();
16131643
}
16141644

1645+
private void checkAccess() {
1646+
if (!buffer.isAccessible()) {
1647+
throw new IllegalReferenceCountException();
1648+
}
1649+
}
1650+
16151651
private ByteBufAdaptor wrap(Buffer copy) {
16161652
return new ByteBufAdaptor(alloc, copy);
16171653
}

src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import io.netty.buffer.CompositeByteBuf;
2121
import io.netty.buffer.api.BufferAllocator;
2222

23+
import static java.nio.ByteOrder.BIG_ENDIAN;
24+
2325
public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable {
2426
private final BufferAllocator onheap;
2527
private final BufferAllocator offheap;
@@ -53,7 +55,7 @@ public boolean isClosed() {
5355

5456
@Override
5557
public ByteBuf buffer(int initialCapacity) {
56-
return new ByteBufAdaptor(this, onheap.allocate(initialCapacity));
58+
return new ByteBufAdaptor(this, onheap.allocate(initialCapacity).order(BIG_ENDIAN));
5759
}
5860

5961
@Override
@@ -98,7 +100,7 @@ public ByteBuf directBuffer() {
98100

99101
@Override
100102
public ByteBuf directBuffer(int initialCapacity) {
101-
return new ByteBufAdaptor(this, offheap.allocate(initialCapacity));
103+
return new ByteBufAdaptor(this, offheap.allocate(initialCapacity).order(BIG_ENDIAN));
102104
}
103105

104106
@Override

src/test/java/io/netty/buffer/api/adaptor/ByteBufAdaptorTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
1+
/*
2+
* Copyright 2021 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
116
package io.netty.buffer.api.adaptor;
217

318
import io.netty.buffer.AbstractByteBufTest;
419
import io.netty.buffer.ByteBuf;
520
import org.junit.AfterClass;
621
import org.junit.BeforeClass;
22+
import org.junit.Ignore;
723

824
public class ByteBufAdaptorTest extends AbstractByteBufTest {
925
static ByteBufAllocatorAdaptor alloc;
@@ -22,4 +38,34 @@ public static void tearDownAllocator() throws Exception {
2238
protected ByteBuf newBuffer(int capacity, int maxCapacity) {
2339
return alloc.buffer(capacity, capacity);
2440
}
41+
42+
@Ignore("new buffers not thread-safe like this")
43+
@Override
44+
public void testSliceReadGatheringByteChannelMultipleThreads() throws Exception {
45+
}
46+
47+
@Ignore("new buffers not thread-safe like this")
48+
@Override
49+
public void testDuplicateReadGatheringByteChannelMultipleThreads() throws Exception {
50+
}
51+
52+
@Ignore("new buffers not thread-safe like this")
53+
@Override
54+
public void testSliceReadOutputStreamMultipleThreads() throws Exception {
55+
}
56+
57+
@Ignore("new buffers not thread-safe like this")
58+
@Override
59+
public void testDuplicateReadOutputStreamMultipleThreads() throws Exception {
60+
}
61+
62+
@Ignore("new buffers not thread-safe like this")
63+
@Override
64+
public void testSliceBytesInArrayMultipleThreads() throws Exception {
65+
}
66+
67+
@Ignore("new buffers not thread-safe like this")
68+
@Override
69+
public void testDuplicateBytesInArrayMultipleThreads() throws Exception {
70+
}
2571
}

0 commit comments

Comments
 (0)