Skip to content

Commit d905e77

Browse files
committed
Enforce types when writing to mysqli dynamic properties
Previously this just assumed that the value was of a certain type. I'm doing this in a generic way that checks against the declared property type -- the handler function can then assume the value to be of the correct type.
1 parent 0fc3818 commit d905e77

File tree

3 files changed

+42
-49
lines changed

3 files changed

+42
-49
lines changed

ext/mysqli/mysqli.c

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -287,61 +287,56 @@ static int mysqli_read_na(mysqli_object *obj, zval *retval, bool quiet)
287287
}
288288
/* }}} */
289289

290-
/* {{{ mysqli_write_na */
291-
static int mysqli_write_na(mysqli_object *obj, zval *newval)
292-
{
293-
zend_throw_error(NULL, "Cannot write property");
294-
295-
return FAILURE;
296-
}
297-
/* }}} */
298-
299290
/* {{{ mysqli_read_property */
300291
zval *mysqli_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
301292
{
302-
zval *retval;
303-
mysqli_object *obj;
304-
mysqli_prop_handler *hnd = NULL;
305-
306-
obj = php_mysqli_fetch_object(object);
307-
308-
if (obj->prop_handler != NULL) {
309-
hnd = zend_hash_find_ptr(obj->prop_handler, name);
310-
}
311-
312-
if (hnd) {
313-
if (hnd->read_func(obj, rv, type == BP_VAR_IS) == SUCCESS) {
314-
retval = rv;
315-
} else {
316-
retval = &EG(uninitialized_zval);
293+
mysqli_object *obj = php_mysqli_fetch_object(object);
294+
if (obj->prop_handler) {
295+
mysqli_prop_handler *hnd = zend_hash_find_ptr(obj->prop_handler, name);
296+
if (hnd) {
297+
if (hnd->read_func(obj, rv, type == BP_VAR_IS) == SUCCESS) {
298+
return rv;
299+
} else {
300+
return &EG(uninitialized_zval);
301+
}
317302
}
318-
} else {
319-
retval = zend_std_read_property(object, name, type, cache_slot, rv);
320303
}
321304

322-
return retval;
305+
return zend_std_read_property(object, name, type, cache_slot, rv);
323306
}
324307
/* }}} */
325308

326309
/* {{{ mysqli_write_property */
327310
zval *mysqli_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
328311
{
329-
mysqli_object *obj;
330-
mysqli_prop_handler *hnd = NULL;
331-
332-
obj = php_mysqli_fetch_object(object);
333-
334-
if (obj->prop_handler != NULL) {
335-
hnd = zend_hash_find_ptr(obj->prop_handler, name);
336-
}
312+
mysqli_object *obj = php_mysqli_fetch_object(object);
313+
if (obj->prop_handler) {
314+
const mysqli_prop_handler *hnd = zend_hash_find_ptr(obj->prop_handler, name);
315+
if (hnd) {
316+
if (!hnd->write_func) {
317+
zend_throw_error(NULL, "Cannot write read-only property %s::$%s",
318+
ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
319+
return &EG(error_zval);
320+
}
337321

338-
if (hnd) {
339-
hnd->write_func(obj, value);
340-
} else {
341-
value = zend_std_write_property(object, name, value, cache_slot);
322+
zend_property_info *prop = zend_get_property_info(object->ce, name, /* silent */ true);
323+
if (prop && ZEND_TYPE_IS_SET(prop->type)) {
324+
zval tmp;
325+
ZVAL_COPY(&tmp, value);
326+
if (!zend_verify_property_type(prop, &tmp,
327+
ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)))) {
328+
zval_ptr_dtor(&tmp);
329+
return &EG(error_zval);
330+
}
331+
hnd->write_func(obj, &tmp);
332+
zval_ptr_dtor(&tmp);
333+
} else {
334+
hnd->write_func(obj, value);
335+
}
336+
return value;
337+
}
342338
}
343-
344-
return value;
339+
return zend_std_write_property(object, name, value, cache_slot);
345340
}
346341
/* }}} */
347342

@@ -351,7 +346,7 @@ void mysqli_add_property(HashTable *h, const char *pname, size_t pname_len, mysq
351346

352347
p.name = zend_string_init_interned(pname, pname_len, 1);
353348
p.read_func = (r_func) ? r_func : mysqli_read_na;
354-
p.write_func = (w_func) ? w_func : mysqli_write_na;
349+
p.write_func = w_func;
355350
zend_hash_add_mem(h, p.name, &p, sizeof(mysqli_prop_handler));
356351
zend_string_release_ex(p.name, 1);
357352
}

ext/mysqli/mysqli.stub.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ final class mysqli_driver
1010

1111
public int $driver_version;
1212

13-
/** @var bool */
14-
public $reconnect = false;
13+
public bool $reconnect = false;
1514

16-
/** @var int */
17-
public $report_mode = 0;
15+
public int $report_mode = 0;
1816
}
1917

2018
class mysqli

ext/mysqli/mysqli_arginfo.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: b9583854314bc54295c1e1a4ec7f6b8c0ce6187c */
2+
* Stub hash: 1c01e60c65f87e4f59435c3712296137d265dfdc */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING)
55
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
@@ -1069,13 +1069,13 @@ static zend_class_entry *register_class_mysqli_driver(void)
10691069
zval property_reconnect_default_value;
10701070
ZVAL_BOOL(&property_reconnect_default_value, 0);
10711071
zend_string *property_reconnect_name = zend_string_init("reconnect", sizeof("reconnect") - 1, 1);
1072-
zend_declare_property_ex(class_entry, property_reconnect_name, &property_reconnect_default_value, ZEND_ACC_PUBLIC, NULL);
1072+
zend_declare_typed_property(class_entry, property_reconnect_name, &property_reconnect_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
10731073
zend_string_release(property_reconnect_name);
10741074

10751075
zval property_report_mode_default_value;
10761076
ZVAL_LONG(&property_report_mode_default_value, 0);
10771077
zend_string *property_report_mode_name = zend_string_init("report_mode", sizeof("report_mode") - 1, 1);
1078-
zend_declare_property_ex(class_entry, property_report_mode_name, &property_report_mode_default_value, ZEND_ACC_PUBLIC, NULL);
1078+
zend_declare_typed_property(class_entry, property_report_mode_name, &property_report_mode_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
10791079
zend_string_release(property_report_mode_name);
10801080

10811081
return class_entry;

0 commit comments

Comments
 (0)