Skip to content

Commit 43eca19

Browse files
committed
Merge branch 'PHP-7.4'
* PHP-7.4: Fix #79571: FFI: var_dumping unions may segfault
2 parents 6549891 + d530087 commit 43eca19

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

ext/ffi/ffi.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ret(void *p
458458
}
459459
/* }}} */
460460

461-
static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, void *ptr, zend_ffi_type *type, int read_type, zval *rv, zend_ffi_flags flags, zend_bool is_ret) /* {{{ */
461+
static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, void *ptr, zend_ffi_type *type, int read_type, zval *rv, zend_ffi_flags flags, zend_bool is_ret, zend_bool debug_union) /* {{{ */
462462
{
463463
if (read_type == BP_VAR_R) {
464464
zend_ffi_type_kind kind = type->kind;
@@ -513,6 +513,9 @@ static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, voi
513513
if (*(void**)ptr == NULL) {
514514
ZVAL_NULL(rv);
515515
return;
516+
} else if (debug_union) {
517+
ZVAL_STR(rv, zend_strpprintf(0, "%p", *(void**)ptr));
518+
return;
516519
} else if ((type->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
517520
ZVAL_STRING(rv, *(char**)ptr);
518521
return;
@@ -863,7 +866,7 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
863866

864867
ZEND_HASH_FOREACH_PTR(callback_data->type->func.args, arg_type) {
865868
arg_type = ZEND_FFI_TYPE(arg_type);
866-
zend_ffi_cdata_to_zval(NULL, args[n], arg_type, BP_VAR_R, &fci.params[n], (zend_ffi_flags)(arg_type->attr & ZEND_FFI_ATTR_CONST), 0);
869+
zend_ffi_cdata_to_zval(NULL, args[n], arg_type, BP_VAR_R, &fci.params[n], (zend_ffi_flags)(arg_type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
867870
n++;
868871
} ZEND_HASH_FOREACH_END();
869872
}
@@ -997,7 +1000,7 @@ static zval *zend_ffi_cdata_get(zend_object *obj, zend_string *member, int read_
9971000
return &EG(uninitialized_zval);;
9981001
}
9991002

1000-
zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0);
1003+
zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0, 0);
10011004
return rv;
10021005
}
10031006
/* }}} */
@@ -1159,7 +1162,7 @@ static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name
11591162
}
11601163
}
11611164
ptr = (void*)(((char*)ptr) + field->offset);
1162-
zend_ffi_cdata_to_zval(NULL, ptr, field_type, read_type, rv, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)field->is_const, 0);
1165+
zend_ffi_cdata_to_zval(NULL, ptr, field_type, read_type, rv, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)field->is_const, 0, 0);
11631166
} else {
11641167
zend_ffi_bit_field_to_zval(ptr, field, rv);
11651168
}
@@ -1288,7 +1291,7 @@ static zval *zend_ffi_cdata_read_dim(zend_object *obj, zval *offset, int read_ty
12881291
return &EG(uninitialized_zval);
12891292
}
12901293

1291-
zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0);
1294+
zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0, 0);
12921295
return rv;
12931296
}
12941297
/* }}} */
@@ -1835,7 +1838,7 @@ static zval *zend_ffi_cdata_it_get_current_data(zend_object_iterator *it) /* {{{
18351838
ptr = (void*)((char*)cdata->ptr + dim_type->size * iter->it.index);
18361839

18371840
zval_ptr_dtor(&iter->value);
1838-
zend_ffi_cdata_to_zval(NULL, ptr, dim_type, iter->by_ref ? BP_VAR_RW : BP_VAR_R, &iter->value, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST), 0);
1841+
zend_ffi_cdata_to_zval(NULL, ptr, dim_type, iter->by_ref ? BP_VAR_RW : BP_VAR_R, &iter->value, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
18391842
return &iter->value;
18401843
}
18411844
/* }}} */
@@ -1930,7 +1933,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp)
19301933
case ZEND_FFI_TYPE_SINT32:
19311934
case ZEND_FFI_TYPE_UINT64:
19321935
case ZEND_FFI_TYPE_SINT64:
1933-
zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0);
1936+
zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
19341937
ht = zend_new_array(1);
19351938
zend_hash_str_add(ht, "cdata", sizeof("cdata")-1, &tmp);
19361939
*is_temp = 1;
@@ -1950,7 +1953,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp)
19501953
*is_temp = 1;
19511954
return ht;
19521955
} else {
1953-
zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0);
1956+
zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
19541957
ht = zend_new_array(1);
19551958
zend_hash_index_add_new(ht, 0, &tmp);
19561959
*is_temp = 1;
@@ -1963,7 +1966,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp)
19631966
if (key) {
19641967
if (!f->bits) {
19651968
void *f_ptr = (void*)(((char*)ptr) + f->offset);
1966-
zend_ffi_cdata_to_zval(NULL, f_ptr, ZEND_FFI_TYPE(f->type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0);
1969+
zend_ffi_cdata_to_zval(NULL, f_ptr, ZEND_FFI_TYPE(f->type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, type->attr & ZEND_FFI_ATTR_UNION);
19671970
zend_hash_add(ht, key, &tmp);
19681971
} else {
19691972
zend_ffi_bit_field_to_zval(ptr, f, &tmp);
@@ -1976,7 +1979,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp)
19761979
case ZEND_FFI_TYPE_ARRAY:
19771980
ht = zend_new_array(type->array.length);
19781981
for (n = 0; n < type->array.length; n++) {
1979-
zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0);
1982+
zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
19801983
zend_hash_index_add(ht, n, &tmp);
19811984
ptr = (void*)(((char*)ptr) + ZEND_FFI_TYPE(type->array.type)->size);
19821985
}
@@ -2346,7 +2349,7 @@ static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read
23462349
}
23472350

23482351
if (sym->kind == ZEND_FFI_SYM_VAR) {
2349-
zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0);
2352+
zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0, 0);
23502353
} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
23512354
zend_ffi_cdata *cdata;
23522355
zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type));
@@ -2714,7 +2717,7 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
27142717
free_alloca(arg_values, arg_values_use_heap);
27152718
}
27162719

2717-
zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1);
2720+
zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0);
27182721
free_alloca(ret, ret_use_heap);
27192722

27202723
exit:

ext/ffi/tests/bug79571.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Bug #79571 (FFI: var_dumping unions may segfault)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('ffi')) die('skip ffi extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
$ffi = FFI::cdef(<<<EOF
10+
typedef union {
11+
int num;
12+
char *str;
13+
} my_union;
14+
EOF);
15+
16+
$union = $ffi->new('my_union');
17+
$union->num = 42;
18+
var_dump($union);
19+
var_dump($union->num);
20+
?>
21+
--EXPECTF--
22+
object(FFI\CData:union <anonymous>)#%d (2) {
23+
["num"]=>
24+
int(42)
25+
["str"]=>
26+
string(4) "0x2a"
27+
}
28+
int(42)

0 commit comments

Comments
 (0)