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:
parent
5ab8342798
commit
f8ff834f03
@ -1172,6 +1172,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf duplicate() {
|
public ByteBuf duplicate() {
|
||||||
|
ensureAccessible();
|
||||||
return new UnpooledDuplicatedByteBuf(this);
|
return new UnpooledDuplicatedByteBuf(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,11 +141,13 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf slice(int index, int length) {
|
public ByteBuf slice(int index, int length) {
|
||||||
|
ensureAccessible();
|
||||||
// All reference count methods should be inherited from this object (this is the "parent").
|
// All reference count methods should be inherited from this object (this is the "parent").
|
||||||
return new PooledNonRetainedSlicedByteBuf(this, unwrap(), index, length);
|
return new PooledNonRetainedSlicedByteBuf(this, unwrap(), index, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ByteBuf duplicate0() {
|
final ByteBuf duplicate0() {
|
||||||
|
ensureAccessible();
|
||||||
// All reference count methods should be inherited from this object (this is the "parent").
|
// All reference count methods should be inherited from this object (this is the "parent").
|
||||||
return new PooledNonRetainedDuplicateByteBuf(this, unwrap());
|
return new PooledNonRetainedDuplicateByteBuf(this, unwrap());
|
||||||
}
|
}
|
||||||
@ -199,6 +201,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf duplicate() {
|
public ByteBuf duplicate() {
|
||||||
|
ensureAccessible();
|
||||||
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
|
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +212,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf slice(int index, int length) {
|
public ByteBuf slice(int index, int length) {
|
||||||
checkIndex0(index, length);
|
checkIndex(index, length);
|
||||||
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
|
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +278,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf duplicate() {
|
public ByteBuf duplicate() {
|
||||||
|
ensureAccessible();
|
||||||
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
|
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
|
||||||
.setIndex(idx(readerIndex()), idx(writerIndex()));
|
.setIndex(idx(readerIndex()), idx(writerIndex()));
|
||||||
}
|
}
|
||||||
@ -286,7 +290,7 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf slice(int index, int length) {
|
public ByteBuf slice(int index, int length) {
|
||||||
checkIndex0(index, length);
|
checkIndex(index, length);
|
||||||
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
|
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
@Test
|
||||||
public void testSliceRelease() {
|
public void testSliceRelease() {
|
||||||
ByteBuf buf = newBuffer(8);
|
ByteBuf buf = newBuffer(8);
|
||||||
|
Loading…
Reference in New Issue
Block a user