From b6dbfc916331d74a8fb641a374431d0695078a48 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 17 Oct 2023 16:43:26 -0700 Subject: [PATCH] [promises] Handle double scheduling of GRPC_OP_RECV_STATUS_ON_CLIENT (#34680) --- src/core/lib/surface/call.cc | 7 +++++ .../client_fuzzer_corpus/5760937752592384 | 27 +++++++++++++++++++ test/core/end2end/fuzzers/fuzzing_common.cc | 1 + 3 files changed, 35 insertions(+) create mode 100644 test/core/end2end/fuzzers/client_fuzzer_corpus/5760937752592384 diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index edf67460824..c3a536d0055 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -2836,6 +2836,7 @@ class ClientPromiseBasedCall final : public PromiseBasedCall { Pipe client_to_server_messages_{arena()}; Pipe server_to_client_messages_{arena()}; bool is_trailers_only_ = false; + bool scheduled_receive_status_ = false; // True once the promise for the call is started. // This corresponds to sending initial metadata, or cancelling before doing // so. @@ -2906,8 +2907,13 @@ grpc_call_error ClientPromiseBasedCall::ValidateBatch(const grpc_op* ops, case GRPC_OP_RECV_INITIAL_METADATA: case GRPC_OP_RECV_MESSAGE: case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; + break; case GRPC_OP_RECV_STATUS_ON_CLIENT: if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; + if (scheduled_receive_status_) { + return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + } break; case GRPC_OP_RECV_CLOSE_ON_SERVER: case GRPC_OP_SEND_STATUS_FROM_SERVER: @@ -2950,6 +2956,7 @@ void ClientPromiseBasedCall::CommitBatch(const grpc_op* ops, size_t nops, spawner); } break; case GRPC_OP_RECV_STATUS_ON_CLIENT: { + scheduled_receive_status_ = true; StartRecvStatusOnClient(completion, op.data.recv_status_on_client, spawner); } break; diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5760937752592384 b/test/core/end2end/fuzzers/client_fuzzer_corpus/5760937752592384 new file mode 100644 index 00000000000..b376cfcaea1 --- /dev/null +++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5760937752592384 @@ -0,0 +1,27 @@ +api_actions { + create_call { + method { + value: "http" + } + timeout: 1862270974 + } +} +api_actions { + queue_batch { + operations { + receive_status_on_client { + } + } + } +} +api_actions { + queue_batch { + operations { + receive_status_on_client { + } + } + } +} +config_vars { + experiments: 4702337453602635775 +} diff --git a/test/core/end2end/fuzzers/fuzzing_common.cc b/test/core/end2end/fuzzers/fuzzing_common.cc index 683dce5e3a9..4df71831b2f 100644 --- a/test/core/end2end/fuzzers/fuzzing_common.cc +++ b/test/core/end2end/fuzzers/fuzzing_common.cc @@ -655,6 +655,7 @@ bool BasicFuzzer::Continue() { BasicFuzzer::Result BasicFuzzer::ExecuteAction( const api_fuzzer::Action& action) { + gpr_log(GPR_DEBUG, "EXECUTE_ACTION: %s", action.DebugString().c_str()); switch (action.type_case()) { case api_fuzzer::Action::TYPE_NOT_SET: return BasicFuzzer::Result::kFailed;