[#2589] LocalServerChannel.doClose() throws NPE when localAddress == null

Motivation:

LocalServerChannel.doClose() calls LocalChannelRegistry.unregister(localAddress); without check if localAddress is null and so produce a NPE when pass null the used ConcurrentHashMapV8

Modification:
Check for localAddress != null before try to remove it from Map. Also added a unit test which showed the stacktrace of the error.

Result:

No more NPE during doClose().
This commit is contained in:
Norman Maurer 2014-06-20 20:03:22 +02:00
parent 19a1b603d0
commit 58f4b4b7d9
2 changed files with 33 additions and 2 deletions

View File

@ -96,8 +96,10 @@ public class LocalServerChannel extends AbstractServerChannel {
protected void doClose() throws Exception { protected void doClose() throws Exception {
if (state <= 1) { if (state <= 1) {
// Update all internal state before the closeFuture is notified. // Update all internal state before the closeFuture is notified.
if (localAddress != null) {
LocalChannelRegistry.unregister(localAddress); LocalChannelRegistry.unregister(localAddress);
localAddress = null; localAddress = null;
}
state = 2; state = 2;
} }
} }

View File

@ -29,12 +29,15 @@ import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalEventLoopGroup; import io.netty.channel.local.LocalEventLoopGroup;
import io.netty.channel.local.LocalServerChannel; import io.netty.channel.local.LocalServerChannel;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
public class BootstrapTest { public class BootstrapTest {
@ -161,6 +164,32 @@ public class BootstrapTest {
} }
} }
@Test
public void testLateRegisterFailed() throws Exception {
final TestLocalEventLoopGroup group = new TestLocalEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(group);
bootstrap.channel(LocalServerChannel.class);
bootstrap.childHandler(new DummyHandler());
bootstrap.localAddress(new LocalAddress("1"));
ChannelFuture future = bootstrap.bind();
Assert.assertFalse(future.isDone());
group.promise.setFailure(new IllegalStateException());
final BlockingQueue<Boolean> queue = new LinkedBlockingQueue<Boolean>();
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
queue.add(group.next().inEventLoop(Thread.currentThread()));
}
});
Assert.assertFalse(queue.take());
} finally {
group.shutdownGracefully();
group.terminationFuture().sync();
}
}
private static final class TestLocalEventLoopGroup extends LocalEventLoopGroup { private static final class TestLocalEventLoopGroup extends LocalEventLoopGroup {
ChannelPromise promise; ChannelPromise promise;
TestLocalEventLoopGroup() { TestLocalEventLoopGroup() {