core: fix NPE in ConfigSelectingClientCall

Fix the following bug:

ManagedChannelImpl.ConfigSelectingClientCall may return early in start() leaving delegate null, and fails request() method after start().

Currently the bug can only be triggered when using xDS.
This commit is contained in:
ZHANG Dapeng 2021-04-14 23:06:37 -07:00 committed by GitHub
parent d4fa0ecc07
commit d25ebaf57d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 0 deletions

View File

@ -1179,6 +1179,7 @@ final class ManagedChannelImpl extends ManagedChannel implements
return delegate;
}
@SuppressWarnings("unchecked")
@Override
public void start(Listener<RespT> observer, Metadata headers) {
PickSubchannelArgs args = new PickSubchannelArgsImpl(method, headers, callOptions);
@ -1186,6 +1187,7 @@ final class ManagedChannelImpl extends ManagedChannel implements
Status status = result.getStatus();
if (!status.isOk()) {
executeCloseObserverInContext(observer, status);
delegate = (ClientCall<ReqT, RespT>) NOOP_CALL;
return;
}
ClientInterceptor interceptor = result.getInterceptor();
@ -1226,6 +1228,29 @@ final class ManagedChannelImpl extends ManagedChannel implements
}
}
private static final ClientCall<Object, Object> NOOP_CALL = new ClientCall<Object, Object>() {
@Override
public void start(Listener<Object> responseListener, Metadata headers) {}
@Override
public void request(int numMessages) {}
@Override
public void cancel(String message, Throwable cause) {}
@Override
public void halfClose() {}
@Override
public void sendMessage(Object message) {}
// Always returns {@code false}, since this is only used when the startup of the call fails.
@Override
public boolean isReady() {
return false;
}
};
/**
* Terminate the channel if termination conditions are met.
*/

View File

@ -135,6 +135,9 @@ public class ConfigSelectingClientCallTest {
ArgumentCaptor<Status> statusCaptor = ArgumentCaptor.forClass(null);
verify(callListener).onClose(statusCaptor.capture(), any(Metadata.class));
assertThat(statusCaptor.getValue().getCode()).isEqualTo(Status.Code.FAILED_PRECONDITION);
// The call should not delegate to null and fail methods with NPE.
configSelectingClientCall.request(1);
}
private final class TestChannel extends Channel {