Skip to content

Commit

Permalink
Checks accessibility in the #slice and #duplicate methods of ByteBuf (n…
Browse files Browse the repository at this point in the history
…etty#7846)

Motivation:
The `ByteBuf#slice` and `ByteBuf#duplicate` methods should check
an accessibility to prevent creation slice or duplicate
of released buffer. At now this works not in the all scenarios.

Modifications:
Add missed checks.

Result:
More correct and consistent behavior of `ByteBuf` methods.
  • Loading branch information
fenik17 authored and normanmaurer committed Apr 10, 2018
1 parent 5ab8342 commit f8ff834
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 2 deletions.
1 change: 1 addition & 0 deletions buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,7 @@ public ByteBuf copy() {

@Override
public ByteBuf duplicate() {
ensureAccessible();
return new UnpooledDuplicatedByteBuf(this);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,13 @@ public final ByteBuf retainedSlice() {

@Override
public ByteBuf slice(int index, int length) {
ensureAccessible();
// All reference count methods should be inherited from this object (this is the "parent").
return new PooledNonRetainedSlicedByteBuf(this, unwrap(), index, length);
}

final ByteBuf duplicate0() {
ensureAccessible();
// All reference count methods should be inherited from this object (this is the "parent").
return new PooledNonRetainedDuplicateByteBuf(this, unwrap());
}
Expand Down Expand Up @@ -199,6 +201,7 @@ boolean release0(int decrement) {

@Override
public ByteBuf duplicate() {
ensureAccessible();
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
}

Expand All @@ -209,7 +212,7 @@ public ByteBuf retainedDuplicate() {

@Override
public ByteBuf slice(int index, int length) {
checkIndex0(index, length);
checkIndex(index, length);
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
}

Expand Down Expand Up @@ -275,6 +278,7 @@ boolean release0(int decrement) {

@Override
public ByteBuf duplicate() {
ensureAccessible();
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
.setIndex(idx(readerIndex()), idx(writerIndex()));
}
Expand All @@ -286,7 +290,7 @@ public ByteBuf retainedDuplicate() {

@Override
public ByteBuf slice(int index, int length) {
checkIndex0(index, length);
checkIndex(index, length);
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
}

Expand Down
218 changes: 218 additions & 0 deletions buffer/src/test/java/io/netty/buffer/AbstractByteBufTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3317,6 +3317,224 @@ public void testMemoryAddressAfterRelease() {
}
}

@Test(expected = IllegalReferenceCountException.class)
public void testSliceAfterRelease() {
releasedBuffer().slice();
}

@Test(expected = IllegalReferenceCountException.class)
public void testSliceAfterRelease2() {
releasedBuffer().slice(0, 1);
}

private static void assertSliceFailAfterRelease(ByteBuf... bufs) {
for (ByteBuf buf : bufs) {
if (buf.refCnt() > 0) {
buf.release();
}
}
for (ByteBuf buf : bufs) {
try {
assertEquals(0, buf.refCnt());
buf.slice();
fail();
} catch (IllegalReferenceCountException ignored) {
// as expected
}
}
}

@Test
public void testSliceAfterReleaseRetainedSlice() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
assertSliceFailAfterRelease(buf, buf2);
}

@Test
public void testSliceAfterReleaseRetainedSliceDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
ByteBuf buf3 = buf2.duplicate();
assertSliceFailAfterRelease(buf, buf2, buf3);
}

@Test
public void testSliceAfterReleaseRetainedSliceRetainedDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
ByteBuf buf3 = buf2.retainedDuplicate();
assertSliceFailAfterRelease(buf, buf2, buf3);
}

@Test
public void testSliceAfterReleaseRetainedDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
assertSliceFailAfterRelease(buf, buf2);
}

@Test
public void testSliceAfterReleaseRetainedDuplicateSlice() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
ByteBuf buf3 = buf2.slice(0, 1);
assertSliceFailAfterRelease(buf, buf2, buf3);
}

@Test(expected = IllegalReferenceCountException.class)
public void testRetainedSliceAfterRelease() {
releasedBuffer().retainedSlice();
}

@Test(expected = IllegalReferenceCountException.class)
public void testRetainedSliceAfterRelease2() {
releasedBuffer().retainedSlice(0, 1);
}

private static void assertRetainedSliceFailAfterRelease(ByteBuf... bufs) {
for (ByteBuf buf : bufs) {
if (buf.refCnt() > 0) {
buf.release();
}
}
for (ByteBuf buf : bufs) {
try {
assertEquals(0, buf.refCnt());
buf.retainedSlice();
fail();
} catch (IllegalReferenceCountException ignored) {
// as expected
}
}
}

@Test
public void testRetainedSliceAfterReleaseRetainedSlice() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
assertRetainedSliceFailAfterRelease(buf, buf2);
}

@Test
public void testRetainedSliceAfterReleaseRetainedSliceDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
ByteBuf buf3 = buf2.duplicate();
assertRetainedSliceFailAfterRelease(buf, buf2, buf3);
}

@Test
public void testRetainedSliceAfterReleaseRetainedSliceRetainedDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
ByteBuf buf3 = buf2.retainedDuplicate();
assertRetainedSliceFailAfterRelease(buf, buf2, buf3);
}

@Test
public void testRetainedSliceAfterReleaseRetainedDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
assertRetainedSliceFailAfterRelease(buf, buf2);
}

@Test
public void testRetainedSliceAfterReleaseRetainedDuplicateSlice() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
ByteBuf buf3 = buf2.slice(0, 1);
assertRetainedSliceFailAfterRelease(buf, buf2, buf3);
}

@Test(expected = IllegalReferenceCountException.class)
public void testDuplicateAfterRelease() {
releasedBuffer().duplicate();
}

@Test(expected = IllegalReferenceCountException.class)
public void testRetainedDuplicateAfterRelease() {
releasedBuffer().retainedDuplicate();
}

private static void assertDuplicateFailAfterRelease(ByteBuf... bufs) {
for (ByteBuf buf : bufs) {
if (buf.refCnt() > 0) {
buf.release();
}
}
for (ByteBuf buf : bufs) {
try {
assertEquals(0, buf.refCnt());
buf.duplicate();
fail();
} catch (IllegalReferenceCountException ignored) {
// as expected
}
}
}

@Test
public void testDuplicateAfterReleaseRetainedSliceDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
ByteBuf buf3 = buf2.duplicate();
assertDuplicateFailAfterRelease(buf, buf2, buf3);
}

@Test
public void testDuplicateAfterReleaseRetainedDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
assertDuplicateFailAfterRelease(buf, buf2);
}

@Test
public void testDuplicateAfterReleaseRetainedDuplicateSlice() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
ByteBuf buf3 = buf2.slice(0, 1);
assertDuplicateFailAfterRelease(buf, buf2, buf3);
}

private static void assertRetainedDuplicateFailAfterRelease(ByteBuf... bufs) {
for (ByteBuf buf : bufs) {
if (buf.refCnt() > 0) {
buf.release();
}
}
for (ByteBuf buf : bufs) {
try {
assertEquals(0, buf.refCnt());
buf.retainedDuplicate();
fail();
} catch (IllegalReferenceCountException ignored) {
// as expected
}
}
}

@Test
public void testRetainedDuplicateAfterReleaseRetainedDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedDuplicate();
assertRetainedDuplicateFailAfterRelease(buf, buf2);
}

@Test
public void testRetainedDuplicateAfterReleaseDuplicate() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.duplicate();
assertRetainedDuplicateFailAfterRelease(buf, buf2);
}

@Test
public void testRetainedDuplicateAfterReleaseRetainedSlice() {
ByteBuf buf = newBuffer(1);
ByteBuf buf2 = buf.retainedSlice(0, 1);
assertRetainedDuplicateFailAfterRelease(buf, buf2);
}

@Test
public void testSliceRelease() {
ByteBuf buf = newBuffer(8);
Expand Down

0 comments on commit f8ff834

Please sign in to comment.