summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2020-05-11 14:35:27 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2020-05-11 16:24:46 +0200
commitd5300873c5a8a02cff0215327a0b8c730ec9de42 (patch)
treecad7401f1155dd5e37e682f946f7ea5523bee5dd
parentd050d744777e8c5f4e3bc0cb9fcdc06828feb6e1 (diff)
downloadphp-git-d5300873c5a8a02cff0215327a0b8c730ec9de42.tar.gz
Fix #79571: FFI: var_dumping unions may segfault
We must not attempt to access arbitrary union members when retrieving debug info, because that may not be valid. Therefore we do no longer dereference pointer types inside of unions, but report their address as string in `%p` format instead.
-rw-r--r--NEWS3
-rw-r--r--ext/ffi/ffi.c27
-rw-r--r--ext/ffi/tests/bug79571.phpt28
3 files changed, 46 insertions, 12 deletions
diff --git a/NEWS b/NEWS
index a80740376e..f9f43768d1 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ PHP NEWS
- Core:
. Fixed bug #79566 (Private SHM is not private on Windows). (cmb)
+- FFI:
+ . Fixed bug #79571 (FFI: var_dumping unions may segfault). (cmb)
+
- SimpleXML:
. Fixed bug #79528 (Different object of the same xml between 7.4.5 and
7.4.4). (cmb)
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index 9626c4b374..fa81868230 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -459,7 +459,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;
@@ -514,6 +514,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;
@@ -864,7 +867,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();
}
@@ -999,7 +1002,7 @@ static zval *zend_ffi_cdata_get(zval *object, zval *member, int read_type, void
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;
}
/* }}} */
@@ -1171,7 +1174,7 @@ static zval *zend_ffi_cdata_read_field(zval *object, zval *member, int read_type
}
}
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);
}
@@ -1312,7 +1315,7 @@ static zval *zend_ffi_cdata_read_dim(zval *object, zval *offset, int read_type,
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;
}
/* }}} */
@@ -1863,7 +1866,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;
}
/* }}} */
@@ -1958,7 +1961,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zval *object, 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;
@@ -1978,7 +1981,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zval *object, 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;
@@ -1991,7 +1994,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zval *object, 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);
@@ -2004,7 +2007,7 @@ static HashTable *zend_ffi_cdata_get_debug_info(zval *object, 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);
}
@@ -2373,7 +2376,7 @@ static zval *zend_ffi_read_var(zval *object, zval *member, int read_type, void *
zend_tmp_string_release(tmp_var_name);
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));
@@ -2746,7 +2749,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)