[#907] Prevent IllegalBufferAccessException which could be triggered if inboundBufferUpdated(), flush(..), write(..) was triggered after the channel was closed

This commit is contained in:
Norman Maurer 2013-01-17 15:10:11 +01:00
parent 8a9e602a66
commit 677886f470

View File

@ -1054,7 +1054,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
private void fireInboundBufferUpdated0() { private void fireInboundBufferUpdated0() {
final DefaultChannelHandlerContext next = findContextInbound(); final DefaultChannelHandlerContext next = findContextInbound();
if (next != null) { if (next != null && !next.isInboundBufferFreed()) {
next.fillBridge(); next.fillBridge();
// This comparison is safe because this method is always executed from the executor. // This comparison is safe because this method is always executed from the executor.
if (next.executor == executor) { if (next.executor == executor) {
@ -1082,7 +1082,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} catch (Throwable t) { } catch (Throwable t) {
pipeline.notifyHandlerException(t); pipeline.notifyHandlerException(t);
} finally { } finally {
if (handler instanceof ChannelInboundByteHandler) { if (handler instanceof ChannelInboundByteHandler && !isInboundBufferFreed()) {
try { try {
((ChannelInboundByteHandler) handler).discardInboundReadBytes(this); ((ChannelInboundByteHandler) handler).discardInboundReadBytes(this);
} catch (Throwable t) { } catch (Throwable t) {
@ -1383,6 +1383,11 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
private void invokePrevFlush(ChannelPromise promise, Thread currentThread) { private void invokePrevFlush(ChannelPromise promise, Thread currentThread) {
DefaultChannelHandlerContext prev = findContextOutbound(); DefaultChannelHandlerContext prev = findContextOutbound();
if (prev.isOutboundBufferFreed()) {
promise.setFailure(new ChannelPipelineException(
"Unable to flush as outbound buffer of next handler was freed already"));
return;
}
prev.fillBridge(); prev.fillBridge();
prev.invokeFlush(promise, currentThread); prev.invokeFlush(promise, currentThread);
} }
@ -1537,6 +1542,11 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
return; return;
} }
if (isOutboundBufferFreed()) {
promise.setFailure(new ChannelPipelineException(
"Unable to write as outbound buffer of next handler was freed already"));
return;
}
if (msgBuf) { if (msgBuf) {
outboundMessageBuffer().add(message); outboundMessageBuffer().add(message);
} else { } else {
@ -1635,6 +1645,26 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
return channel().newFailedFuture(cause); return channel().newFailedFuture(cause);
} }
private boolean isInboundBufferFreed() {
if (hasInboundByteBuffer()) {
return inboundByteBuffer().isFreed();
}
if (hasInboundMessageBuffer()) {
return inboundMessageBuffer().isFreed();
}
return false;
}
private boolean isOutboundBufferFreed() {
if (hasOutboundByteBuffer()) {
return outboundByteBuffer().isFreed();
}
if (hasOutboundMessageBuffer()) {
return outboundMessageBuffer().isFreed();
}
return false;
}
private void validateFuture(ChannelFuture future) { private void validateFuture(ChannelFuture future) {
if (future == null) { if (future == null) {
throw new NullPointerException("future"); throw new NullPointerException("future");