Skip to content

Commit a9533e7

Browse files
Merge pull request grpc#20249 from HannahShiSFB/enable-debug-19970-19248
PHP: fix zend_hash_str_del() segfault
2 parents a53effe + d254303 commit a9533e7

File tree

1 file changed

+46
-18
lines changed

1 file changed

+46
-18
lines changed

src/php/ext/grpc/channel.c

+46-18
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,21 @@ php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
9898
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel, channel_ce_handlers);
9999
}
100100

101+
static bool php_grpc_not_channel_arg_key(const char* key) {
102+
static const char* ignoredKeys[] = {
103+
"credentials",
104+
"force_new",
105+
"grpc_target_persist_bound",
106+
};
107+
108+
for (int i = 0; i < sizeof(ignoredKeys) / sizeof(ignoredKeys[0]); i++) {
109+
if (strcmp(key, ignoredKeys[i]) == 0) {
110+
return true;
111+
}
112+
}
113+
return false;
114+
}
115+
101116
int php_grpc_read_args_array(zval *args_array,
102117
grpc_channel_args *args TSRMLS_DC) {
103118
HashTable *array_hash;
@@ -108,8 +123,8 @@ int php_grpc_read_args_array(zval *args_array,
108123
"array_hash is NULL", 1 TSRMLS_CC);
109124
return FAILURE;
110125
}
111-
args->num_args = zend_hash_num_elements(array_hash);
112-
args->args = ecalloc(args->num_args, sizeof(grpc_arg));
126+
127+
args->args = ecalloc(zend_hash_num_elements(array_hash), sizeof(grpc_arg));
113128
args_index = 0;
114129

115130
char *key = NULL;
@@ -122,6 +137,11 @@ int php_grpc_read_args_array(zval *args_array,
122137
"args keys must be strings", 1 TSRMLS_CC);
123138
return FAILURE;
124139
}
140+
141+
if (php_grpc_not_channel_arg_key(key)) {
142+
continue;
143+
}
144+
125145
args->args[args_index].key = key;
126146
switch (Z_TYPE_P(data)) {
127147
case IS_LONG:
@@ -139,6 +159,7 @@ int php_grpc_read_args_array(zval *args_array,
139159
}
140160
args_index++;
141161
PHP_GRPC_HASH_FOREACH_END()
162+
args->num_args = args_index;
142163
return SUCCESS;
143164
}
144165

@@ -322,7 +343,6 @@ PHP_METHOD(Channel, __construct) {
322343
(void **)&creds_obj) == SUCCESS) {
323344
if (Z_TYPE_P(creds_obj) == IS_NULL) {
324345
creds = NULL;
325-
php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
326346
} else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
327347
grpc_ce_channel_credentials) {
328348
zend_throw_exception(spl_ce_InvalidArgumentException,
@@ -333,15 +353,13 @@ PHP_METHOD(Channel, __construct) {
333353
Z_ADDREF(*creds_obj);
334354
creds = PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel_credentials,
335355
creds_obj);
336-
php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
337356
}
338357
}
339358
if (php_grpc_zend_hash_find(array_hash, "force_new", sizeof("force_new"),
340359
(void **)&force_new_obj) == SUCCESS) {
341360
if (PHP_GRPC_BVAL_IS_TRUE(force_new_obj)) {
342361
force_new = true;
343362
}
344-
php_grpc_zend_hash_del(array_hash, "force_new", sizeof("force_new"));
345363
}
346364

347365
if (php_grpc_zend_hash_find(array_hash, "grpc_target_persist_bound",
@@ -353,8 +371,6 @@ PHP_METHOD(Channel, __construct) {
353371
1 TSRMLS_CC);
354372
}
355373
target_upper_bound = (int)Z_LVAL_P(force_new_obj);
356-
php_grpc_zend_hash_del(array_hash, "grpc_target_persist_bound",
357-
sizeof("grpc_target_persist_bound"));
358374
}
359375

360376
// parse the rest of the channel args array
@@ -366,18 +382,31 @@ PHP_METHOD(Channel, __construct) {
366382
// Construct a hashkey for the persistent channel
367383
// Currently, the hashkey contains 3 parts:
368384
// 1. hostname
369-
// 2. hash value of the channel args array (excluding "credentials"
370-
// and "force_new")
385+
// 2. hash value of the channel args (args_array excluding "credentials",
386+
// "force_new" and "grpc_target_persist_bound")
371387
// 3. (optional) hash value of the ChannelCredentials object
372-
php_serialize_data_t var_hash;
373-
smart_str buf = {0};
374-
PHP_VAR_SERIALIZE_INIT(var_hash);
375-
PHP_GRPC_VAR_SERIALIZE(&buf, args_array, &var_hash);
376-
PHP_VAR_SERIALIZE_DESTROY(var_hash);
377388

378-
char sha1str[41];
379-
generate_sha1_str(sha1str, PHP_GRPC_SERIALIZED_BUF_STR(buf),
380-
PHP_GRPC_SERIALIZED_BUF_LEN(buf));
389+
char sha1str[41] = { 0 };
390+
unsigned char digest[20] = { 0 };
391+
PHP_SHA1_CTX context;
392+
PHP_SHA1Init(&context);
393+
for (int i = 0; i < args.num_args; i++) {
394+
PHP_GRPC_SHA1Update(&context, args.args[i].key, strlen(args.args[i].key) + 1);
395+
switch (args.args[i].type) {
396+
case GRPC_ARG_INTEGER:
397+
PHP_GRPC_SHA1Update(&context, &args.args[i].value.integer, 4);
398+
break;
399+
case GRPC_ARG_STRING:
400+
PHP_GRPC_SHA1Update(&context, args.args[i].value.string, strlen(args.args[i].value.string) + 1);
401+
break;
402+
default:
403+
zend_throw_exception(spl_ce_InvalidArgumentException,
404+
"args values must be int or string", 1 TSRMLS_CC);
405+
return;
406+
}
407+
};
408+
PHP_SHA1Final(digest, &context);
409+
make_sha1_digest(sha1str, digest);
381410

382411
php_grpc_int key_len = target_length + strlen(sha1str);
383412
if (creds != NULL && creds->hashstr != NULL) {
@@ -405,7 +434,6 @@ PHP_METHOD(Channel, __construct) {
405434
}
406435

407436
gpr_mu_init(&channel->wrapper->mu);
408-
smart_str_free(&buf);
409437
if (force_new || (creds != NULL && creds->has_call_creds)) {
410438
// If the ChannelCredentials object was composed with a CallCredentials
411439
// object, there is no way we can tell them apart. Do NOT persist

0 commit comments

Comments
 (0)