diff options
-rw-r--r-- | ext/ffi/ffi.c | 27 | ||||
-rw-r--r-- | ext/ffi/tests/bug79571.phpt | 28 |
2 files changed, 43 insertions, 12 deletions
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 7784c7b389..2d33694764 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -458,7 +458,7 @@ static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ret(void *p } /* }}} */ -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) /* {{{ */ +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) /* {{{ */ { if (read_type == BP_VAR_R) { zend_ffi_type_kind kind = type->kind; @@ -513,6 +513,9 @@ again: if (*(void**)ptr == NULL) { ZVAL_NULL(rv); return; + } else if (debug_union) { + ZVAL_STR(rv, zend_strpprintf(0, "%p", *(void**)ptr)); + return; } else if ((type->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) { ZVAL_STRING(rv, *(char**)ptr); return; @@ -863,7 +866,7 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v ZEND_HASH_FOREACH_PTR(callback_data->type->func.args, arg_type) { arg_type = ZEND_FFI_TYPE(arg_type); - 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); + 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); n++; } ZEND_HASH_FOREACH_END(); } @@ -997,7 +1000,7 @@ static zval *zend_ffi_cdata_get(zend_object *obj, zend_string *member, int read_ return &EG(uninitialized_zval);; } - zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0); + zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0, 0); return rv; } /* }}} */ @@ -1159,7 +1162,7 @@ static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name } } ptr = (void*)(((char*)ptr) + field->offset); - 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); + 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); } else { zend_ffi_bit_field_to_zval(ptr, field, rv); } @@ -1288,7 +1291,7 @@ static zval *zend_ffi_cdata_read_dim(zend_object *obj, zval *offset, int read_ty return &EG(uninitialized_zval); } - zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0); + zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0, 0); return rv; } /* }}} */ @@ -1835,7 +1838,7 @@ static zval *zend_ffi_cdata_it_get_current_data(zend_object_iterator *it) /* {{{ ptr = (void*)((char*)cdata->ptr + dim_type->size * iter->it.index); zval_ptr_dtor(&iter->value); - 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); + 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); return &iter->value; } /* }}} */ @@ -1930,7 +1933,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) case ZEND_FFI_TYPE_SINT32: case ZEND_FFI_TYPE_UINT64: case ZEND_FFI_TYPE_SINT64: - zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0); + zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0); ht = zend_new_array(1); zend_hash_str_add(ht, "cdata", sizeof("cdata")-1, &tmp); *is_temp = 1; @@ -1950,7 +1953,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) *is_temp = 1; return ht; } else { - zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0); + zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0); ht = zend_new_array(1); zend_hash_index_add_new(ht, 0, &tmp); *is_temp = 1; @@ -1963,7 +1966,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) if (key) { if (!f->bits) { void *f_ptr = (void*)(((char*)ptr) + f->offset); - zend_ffi_cdata_to_zval(NULL, f_ptr, ZEND_FFI_TYPE(f->type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0); + 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); zend_hash_add(ht, key, &tmp); } else { 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) case ZEND_FFI_TYPE_ARRAY: ht = zend_new_array(type->array.length); for (n = 0; n < type->array.length; n++) { - zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0); + zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0); zend_hash_index_add(ht, n, &tmp); ptr = (void*)(((char*)ptr) + ZEND_FFI_TYPE(type->array.type)->size); } @@ -2346,7 +2349,7 @@ static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read } if (sym->kind == ZEND_FFI_SYM_VAR) { - zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0); + zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0, 0); } else if (sym->kind == ZEND_FFI_SYM_FUNC) { zend_ffi_cdata *cdata; zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type)); @@ -2714,7 +2717,7 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */ free_alloca(arg_values, arg_values_use_heap); } - zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1); + zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0); free_alloca(ret, ret_use_heap); exit: diff --git a/ext/ffi/tests/bug79571.phpt b/ext/ffi/tests/bug79571.phpt new file mode 100644 index 0000000000..cff3fab43e --- /dev/null +++ b/ext/ffi/tests/bug79571.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #79571 (FFI: var_dumping unions may segfault) +--SKIPIF-- +<?php +if (!extension_loaded('ffi')) die('skip ffi extension not available'); +?> +--FILE-- +<?php +$ffi = FFI::cdef(<<<EOF + typedef union { + int num; + char *str; + } my_union; +EOF); + +$union = $ffi->new('my_union'); +$union->num = 42; +var_dump($union); +var_dump($union->num); +?> +--EXPECTF-- +object(FFI\CData:union <anonymous>)#%d (2) { + ["num"]=> + int(42) + ["str"]=> + string(4) "0x2a" +} +int(42) |