Checks accessibility in the #slice and #duplicate methods of ByteBuf (#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.
This commit is contained in:
Nikolay Fedorovskikh 2018-04-10 13:41:50 +05:00 committed by Norman Maurer
parent 5ab8342798
commit f8ff834f03
3 changed files with 225 additions and 2 deletions

View File

@ -1172,6 +1172,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override
public ByteBuf duplicate() {
ensureAccessible();
return new UnpooledDuplicatedByteBuf(this);
}

View File

@ -141,11 +141,13 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
@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());
}
@ -199,6 +201,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
@Override
public ByteBuf duplicate() {
ensureAccessible();
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
}
@ -209,7 +212,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
@Override
public ByteBuf slice(int index, int length) {
checkIndex0(index, length);
checkIndex(index, length);
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
}
@ -275,6 +278,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
@Override
public ByteBuf duplicate() {
ensureAccessible();
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
.setIndex(idx(readerIndex()), idx(writerIndex()));
}
@ -286,7 +290,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
@Override
public ByteBuf slice(int index, int length) {
checkIndex0(index, length);
checkIndex(index, length);
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
}

View File

@ -3317,6 +3317,224 @@ public abstract class AbstractByteBufTest {
}
}
@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);