|
|
@ -341,18 +341,39 @@ static void free_non_null(void *p) { |
|
|
|
gpr_free(p); |
|
|
|
gpr_free(p); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef enum { |
|
|
|
|
|
|
|
ROOT, CLIENT, SERVER |
|
|
|
|
|
|
|
} call_state_type; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct call_state { |
|
|
|
typedef struct call_state { |
|
|
|
grpc_call *client; |
|
|
|
call_state_type type; |
|
|
|
grpc_call *server; |
|
|
|
grpc_call *call; |
|
|
|
grpc_byte_buffer *recv_message[2]; |
|
|
|
grpc_byte_buffer *recv_message; |
|
|
|
grpc_status_code status; |
|
|
|
grpc_status_code status; |
|
|
|
grpc_metadata_array recv_initial_metadata; |
|
|
|
grpc_metadata_array recv_initial_metadata; |
|
|
|
grpc_metadata_array recv_trailing_metadata; |
|
|
|
grpc_metadata_array recv_trailing_metadata; |
|
|
|
char *recv_status_details; |
|
|
|
char *recv_status_details; |
|
|
|
size_t recv_status_details_capacity; |
|
|
|
size_t recv_status_details_capacity; |
|
|
|
int cancelled; |
|
|
|
int cancelled; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct call_state *next; |
|
|
|
|
|
|
|
struct call_state *prev; |
|
|
|
} call_state; |
|
|
|
} call_state; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static call_state *new_call(call_state *sibling, call_state_type type) { |
|
|
|
|
|
|
|
call_state *c = gpr_malloc(sizeof(*c)); |
|
|
|
|
|
|
|
memset(c, 0, sizeof(*c)); |
|
|
|
|
|
|
|
if (sibling != NULL) { |
|
|
|
|
|
|
|
c->next = sibling; |
|
|
|
|
|
|
|
c->prev = sibling->prev; |
|
|
|
|
|
|
|
c->next->prev = c->prev->next = c; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
c->next = c->prev = c; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
c->type = type; |
|
|
|
|
|
|
|
return c; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
grpc_test_only_set_metadata_hash_seed(0); |
|
|
|
grpc_test_only_set_metadata_hash_seed(0); |
|
|
|
if (squelch) gpr_set_log_function(dont_log); |
|
|
|
if (squelch) gpr_set_log_function(dont_log); |
|
|
@ -371,10 +392,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
int pending_pings = 0; |
|
|
|
int pending_pings = 0; |
|
|
|
int pending_ops = 0; |
|
|
|
int pending_ops = 0; |
|
|
|
|
|
|
|
|
|
|
|
#define MAX_CALLS 16 |
|
|
|
call_state *active_call = new_call(NULL, ROOT); |
|
|
|
call_state calls[MAX_CALLS]; |
|
|
|
|
|
|
|
int num_calls = 0; |
|
|
|
|
|
|
|
memset(calls, 0, sizeof(calls)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grpc_completion_queue *cq = grpc_completion_queue_create(NULL); |
|
|
|
grpc_completion_queue *cq = grpc_completion_queue_create(NULL); |
|
|
|
|
|
|
|
|
|
|
@ -545,14 +563,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
case 10: { |
|
|
|
case 10: { |
|
|
|
bool ok = true; |
|
|
|
bool ok = true; |
|
|
|
if (g_channel == NULL) ok = false; |
|
|
|
if (g_channel == NULL) ok = false; |
|
|
|
if (num_calls >= MAX_CALLS) ok = false; |
|
|
|
|
|
|
|
grpc_call *parent_call = NULL; |
|
|
|
grpc_call *parent_call = NULL; |
|
|
|
uint8_t pcidx = next_byte(&inp); |
|
|
|
if (active_call->type != ROOT) { |
|
|
|
if (pcidx > MAX_CALLS) |
|
|
|
if (active_call->call == NULL) { |
|
|
|
ok = false; |
|
|
|
end(&inp); |
|
|
|
else if (pcidx < MAX_CALLS) { |
|
|
|
break; |
|
|
|
parent_call = calls[pcidx].server; |
|
|
|
} |
|
|
|
if (parent_call == NULL) ok = false; |
|
|
|
parent_call = active_call->call; |
|
|
|
} |
|
|
|
} |
|
|
|
uint32_t propagation_mask = read_uint32(&inp); |
|
|
|
uint32_t propagation_mask = read_uint32(&inp); |
|
|
|
char *method = read_string(&inp); |
|
|
|
char *method = read_string(&inp); |
|
|
@ -562,8 +579,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN)); |
|
|
|
gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN)); |
|
|
|
|
|
|
|
|
|
|
|
if (ok) { |
|
|
|
if (ok) { |
|
|
|
GPR_ASSERT(calls[num_calls].client == NULL); |
|
|
|
call_state *cs = new_call(active_call, CLIENT); |
|
|
|
calls[num_calls].client = |
|
|
|
cs->call = |
|
|
|
grpc_channel_create_call(g_channel, parent_call, propagation_mask, |
|
|
|
grpc_channel_create_call(g_channel, parent_call, propagation_mask, |
|
|
|
cq, method, host, deadline, NULL); |
|
|
|
cq, method, host, deadline, NULL); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -573,29 +590,18 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
} |
|
|
|
} |
|
|
|
// switch the 'current' call
|
|
|
|
// switch the 'current' call
|
|
|
|
case 11: { |
|
|
|
case 11: { |
|
|
|
uint8_t new_current = next_byte(&inp); |
|
|
|
active_call = active_call->next; |
|
|
|
if (new_current == 0 || new_current >= num_calls) { |
|
|
|
|
|
|
|
end(&inp); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
GPR_SWAP(call_state, calls[0], calls[new_current]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// queue some ops on a call
|
|
|
|
// queue some ops on a call
|
|
|
|
case 12: { |
|
|
|
case 12: { |
|
|
|
|
|
|
|
if (active_call->type == ROOT || active_call->call == NULL) { |
|
|
|
|
|
|
|
end(&inp); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
size_t num_ops = next_byte(&inp); |
|
|
|
size_t num_ops = next_byte(&inp); |
|
|
|
grpc_op *ops = gpr_malloc(sizeof(grpc_op) * num_ops); |
|
|
|
grpc_op *ops = gpr_malloc(sizeof(grpc_op) * num_ops); |
|
|
|
bool ok = num_calls > 0; |
|
|
|
bool ok = true; |
|
|
|
uint8_t on_server = next_byte(&inp); |
|
|
|
|
|
|
|
if (on_server != 0 && on_server != 1) { |
|
|
|
|
|
|
|
ok = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (ok && on_server && calls[0].server == NULL) { |
|
|
|
|
|
|
|
ok = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (ok && !on_server && calls[0].client == NULL) { |
|
|
|
|
|
|
|
ok = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
size_t i; |
|
|
|
size_t i; |
|
|
|
grpc_op *op; |
|
|
|
grpc_op *op; |
|
|
|
for (i = 0; i < num_ops; i++) { |
|
|
|
for (i = 0; i < num_ops; i++) { |
|
|
@ -627,25 +633,25 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
case GRPC_OP_RECV_INITIAL_METADATA: |
|
|
|
case GRPC_OP_RECV_INITIAL_METADATA: |
|
|
|
op->op = GRPC_OP_RECV_INITIAL_METADATA; |
|
|
|
op->op = GRPC_OP_RECV_INITIAL_METADATA; |
|
|
|
op->data.recv_initial_metadata = &calls[0].recv_initial_metadata; |
|
|
|
op->data.recv_initial_metadata = &active_call->recv_initial_metadata; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case GRPC_OP_RECV_MESSAGE: |
|
|
|
case GRPC_OP_RECV_MESSAGE: |
|
|
|
op->op = GRPC_OP_RECV_MESSAGE; |
|
|
|
op->op = GRPC_OP_RECV_MESSAGE; |
|
|
|
op->data.recv_message = &calls[0].recv_message[on_server]; |
|
|
|
op->data.recv_message = &active_call->recv_message; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
|
|
|
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
|
|
|
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
|
|
|
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
|
|
|
op->data.recv_status_on_client.status = &calls[0].status; |
|
|
|
op->data.recv_status_on_client.status = &active_call->status; |
|
|
|
op->data.recv_status_on_client.trailing_metadata = |
|
|
|
op->data.recv_status_on_client.trailing_metadata = |
|
|
|
&calls[0].recv_trailing_metadata; |
|
|
|
&active_call->recv_trailing_metadata; |
|
|
|
op->data.recv_status_on_client.status_details = |
|
|
|
op->data.recv_status_on_client.status_details = |
|
|
|
&calls[0].recv_status_details; |
|
|
|
&active_call->recv_status_details; |
|
|
|
op->data.recv_status_on_client.status_details_capacity = |
|
|
|
op->data.recv_status_on_client.status_details_capacity = |
|
|
|
&calls[0].recv_status_details_capacity; |
|
|
|
&active_call->recv_status_details_capacity; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
|
|
|
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
|
|
|
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; |
|
|
|
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; |
|
|
|
op->data.recv_close_on_server.cancelled = &calls[0].cancelled; |
|
|
|
op->data.recv_close_on_server.cancelled = &active_call->cancelled; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
op->reserved = NULL; |
|
|
|
op->reserved = NULL; |
|
|
@ -655,7 +661,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
validator *v = create_validator(decrement, &pending_ops); |
|
|
|
validator *v = create_validator(decrement, &pending_ops); |
|
|
|
pending_ops++; |
|
|
|
pending_ops++; |
|
|
|
grpc_call_error error = grpc_call_start_batch( |
|
|
|
grpc_call_error error = grpc_call_start_batch( |
|
|
|
on_server ? calls[0].server : calls[0].client, ops, num_ops, |
|
|
|
active_call->call, ops, num_ops, |
|
|
|
v, NULL); |
|
|
|
v, NULL); |
|
|
|
if (error != GRPC_CALL_OK) { |
|
|
|
if (error != GRPC_CALL_OK) { |
|
|
|
v->validate(v->arg, false); |
|
|
|
v->validate(v->arg, false); |
|
|
@ -697,44 +703,26 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// cancel current call on client
|
|
|
|
// cancel current call
|
|
|
|
case 13: { |
|
|
|
case 13: { |
|
|
|
if (num_calls > 0 && calls[0].client) { |
|
|
|
if (active_call->type != ROOT && active_call->call != NULL) { |
|
|
|
grpc_call_cancel(calls[0].client, NULL); |
|
|
|
grpc_call_cancel(active_call->call, NULL); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
end(&inp); |
|
|
|
end(&inp); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// cancel current call on server
|
|
|
|
// get a calls peer
|
|
|
|
case 14: { |
|
|
|
case 14: { |
|
|
|
if (num_calls > 0 && calls[0].server) { |
|
|
|
if (active_call->type != ROOT && active_call->call != NULL) { |
|
|
|
grpc_call_cancel(calls[0].server, NULL); |
|
|
|
free_non_null(grpc_call_get_peer(active_call->call)); |
|
|
|
} else { |
|
|
|
|
|
|
|
end(&inp); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// get a calls peer on client
|
|
|
|
|
|
|
|
case 15: { |
|
|
|
|
|
|
|
if (num_calls > 0 && calls[0].client) { |
|
|
|
|
|
|
|
free_non_null(grpc_call_get_peer(calls[0].client)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
end(&inp); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// get a calls peer on server
|
|
|
|
|
|
|
|
case 16: { |
|
|
|
|
|
|
|
if (num_calls > 0 && calls[0].server) { |
|
|
|
|
|
|
|
free_non_null(grpc_call_get_peer(calls[0].server)); |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
end(&inp); |
|
|
|
end(&inp); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// get a channels target
|
|
|
|
// get a channels target
|
|
|
|
case 17: { |
|
|
|
case 15: { |
|
|
|
if (g_channel != NULL) { |
|
|
|
if (g_channel != NULL) { |
|
|
|
free_non_null(grpc_channel_get_target(g_channel)); |
|
|
|
free_non_null(grpc_channel_get_target(g_channel)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -743,7 +731,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// send a ping on a channel
|
|
|
|
// send a ping on a channel
|
|
|
|
case 18: { |
|
|
|
case 16: { |
|
|
|
if (g_channel != NULL) { |
|
|
|
if (g_channel != NULL) { |
|
|
|
pending_pings++; |
|
|
|
pending_pings++; |
|
|
|
grpc_channel_ping(g_channel, cq, |
|
|
|
grpc_channel_ping(g_channel, cq, |
|
|
@ -754,14 +742,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// enable a tracer
|
|
|
|
// enable a tracer
|
|
|
|
case 19: { |
|
|
|
case 17: { |
|
|
|
char *tracer = read_string(&inp); |
|
|
|
char *tracer = read_string(&inp); |
|
|
|
grpc_tracer_set_enabled(tracer, 1); |
|
|
|
grpc_tracer_set_enabled(tracer, 1); |
|
|
|
gpr_free(tracer); |
|
|
|
gpr_free(tracer); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// disable a tracer
|
|
|
|
// disable a tracer
|
|
|
|
case 20: { |
|
|
|
case 18: { |
|
|
|
char *tracer = read_string(&inp); |
|
|
|
char *tracer = read_string(&inp); |
|
|
|
grpc_tracer_set_enabled(tracer, 0); |
|
|
|
grpc_tracer_set_enabled(tracer, 0); |
|
|
|
gpr_free(tracer); |
|
|
|
gpr_free(tracer); |
|
|
|