[#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:
parent
19a1b603d0
commit
58f4b4b7d9
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user