From 4b83480db748878ae7a2fab6e8deaa3fd8c2ddcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sun, 28 Feb 2021 23:14:29 +0100 Subject: [PATCH 1/3] Declare SNMP properties --- ext/snmp/snmp.stub.php | 16 +++++++++++++ ext/snmp/snmp_arginfo.h | 50 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/ext/snmp/snmp.stub.php b/ext/snmp/snmp.stub.php index 1378f34ff9989..32dc8123db9b7 100644 --- a/ext/snmp/snmp.stub.php +++ b/ext/snmp/snmp.stub.php @@ -75,6 +75,22 @@ function snmp_read_mib(string $filename): bool {} class SNMP { + public array $info; + /** @var int|null */ + public $max_oids; + /** @var int */ + public $valueretrieval; + /** @var bool */ + public $quick_print; + /** @var bool */ + public $enum_print; + /** @var int */ + public $oid_output_format; + /** @var bool */ + public $oid_increasing_check = true; + /** @var int */ + public $exceptions_enabled = 0; + public function __construct(int $version, string $hostname, string $community, int $timeout = -1, int $retries = -1) {} /** @return bool */ diff --git a/ext/snmp/snmp_arginfo.h b/ext/snmp/snmp_arginfo.h index 0f076ca2a4b72..757678c7610e4 100644 --- a/ext/snmp/snmp_arginfo.h +++ b/ext/snmp/snmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 08192d87d2ac5d35092cfcf4a2cdcc50f7ec4ada */ + * Stub hash: e413f4e60b0f04dc3f3cfd1bb90b8f896c3fd7f0 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_snmpget, 0, 3, stdClass, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_BOOL) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) @@ -249,6 +249,54 @@ static zend_class_entry *register_class_SNMP(void) INIT_CLASS_ENTRY(ce, "SNMP", class_SNMP_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); + zval property_info_default_value; + ZVAL_UNDEF(&property_info_default_value); + zend_string *property_info_name = zend_string_init("info", sizeof("info") - 1, 1); + zend_declare_typed_property(class_entry, property_info_name, &property_info_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_info_name); + + zval property_max_oids_default_value; + ZVAL_NULL(&property_max_oids_default_value); + zend_string *property_max_oids_name = zend_string_init("max_oids", sizeof("max_oids") - 1, 1); + zend_declare_property_ex(class_entry, property_max_oids_name, &property_max_oids_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_max_oids_name); + + zval property_valueretrieval_default_value; + ZVAL_NULL(&property_valueretrieval_default_value); + zend_string *property_valueretrieval_name = zend_string_init("valueretrieval", sizeof("valueretrieval") - 1, 1); + zend_declare_property_ex(class_entry, property_valueretrieval_name, &property_valueretrieval_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_valueretrieval_name); + + zval property_quick_print_default_value; + ZVAL_NULL(&property_quick_print_default_value); + zend_string *property_quick_print_name = zend_string_init("quick_print", sizeof("quick_print") - 1, 1); + zend_declare_property_ex(class_entry, property_quick_print_name, &property_quick_print_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_quick_print_name); + + zval property_enum_print_default_value; + ZVAL_NULL(&property_enum_print_default_value); + zend_string *property_enum_print_name = zend_string_init("enum_print", sizeof("enum_print") - 1, 1); + zend_declare_property_ex(class_entry, property_enum_print_name, &property_enum_print_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_enum_print_name); + + zval property_oid_output_format_default_value; + ZVAL_NULL(&property_oid_output_format_default_value); + zend_string *property_oid_output_format_name = zend_string_init("oid_output_format", sizeof("oid_output_format") - 1, 1); + zend_declare_property_ex(class_entry, property_oid_output_format_name, &property_oid_output_format_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_oid_output_format_name); + + zval property_oid_increasing_check_default_value; + ZVAL_BOOL(&property_oid_increasing_check_default_value, 1); + zend_string *property_oid_increasing_check_name = zend_string_init("oid_increasing_check", sizeof("oid_increasing_check") - 1, 1); + zend_declare_property_ex(class_entry, property_oid_increasing_check_name, &property_oid_increasing_check_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_oid_increasing_check_name); + + zval property_exceptions_enabled_default_value; + ZVAL_LONG(&property_exceptions_enabled_default_value, 0); + zend_string *property_exceptions_enabled_name = zend_string_init("exceptions_enabled", sizeof("exceptions_enabled") - 1, 1); + zend_declare_property_ex(class_entry, property_exceptions_enabled_name, &property_exceptions_enabled_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_exceptions_enabled_name); + return class_entry; } From 7722d6e8be1931ffd117fda9601e63d5f31ca709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 27 Apr 2021 11:58:41 +0200 Subject: [PATCH 2/3] Make properties typed --- ext/snmp/snmp.c | 46 ++++++----- ext/snmp/snmp.stub.php | 22 ++---- ext/snmp/snmp_arginfo.h | 30 ++++---- ext/snmp/tests/snmp-object-error.phpt | 6 +- .../tests/snmp-object-properties-error.phpt | 77 +++++++++++++++++++ ext/snmp/tests/snmp-object-properties.phpt | 2 +- 6 files changed, 130 insertions(+), 53 deletions(-) create mode 100644 ext/snmp/tests/snmp-object-properties-error.phpt diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index ae41a8d5351de..bbe030b9b6627 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -1677,19 +1677,30 @@ zval *php_snmp_write_property(zend_object *object, zend_string *name, zval *valu obj = php_snmp_fetch_object(object); hnd = zend_hash_find_ptr(&php_snmp_properties, name); - if (hnd && hnd->write_func) { - hnd->write_func(obj, value); - /* - if (!PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) { - Z_ADDREF_P(value); - zval_ptr_dtor(&value); + if (hnd) { + if (!hnd->write_func) { + zend_throw_error(NULL, "Cannot write read-only property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name)); + return &EG(error_zval); } - */ - } else { - value = zend_std_write_property(object, name, value, cache_slot); + + zend_property_info *prop = zend_get_property_info(object->ce, name, /* silent */ true); + if (prop && ZEND_TYPE_IS_SET(prop->type)) { + zval tmp; + ZVAL_COPY(&tmp, value); + if (!zend_verify_property_type(prop, &tmp, + ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)))) { + zval_ptr_dtor(&tmp); + return &EG(error_zval); + } + hnd->write_func(obj, &tmp); + zval_ptr_dtor(&tmp); + } else { + hnd->write_func(obj, value); + } + return value; } - return value; + return zend_std_write_property(object, name, value, cache_slot); } /* }}} */ @@ -1820,14 +1831,6 @@ PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(valueretrieval) PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(oid_output_format) PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(exceptions_enabled) -/* {{{ */ -static int php_snmp_write_info(php_snmp_object *snmp_object, zval *newval) -{ - zend_throw_error(NULL, "SNMP::$info property is read-only"); - return FAILURE; -} -/* }}} */ - /* {{{ */ static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval) { @@ -1841,7 +1844,7 @@ static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval) lval = zval_get_long(newval); if (lval <= 0) { - zend_value_error("max_oids must be greater than 0 or null"); + zend_value_error("SNMP::$max_oids must be greater than 0 or null"); return FAILURE; } snmp_object->max_oids = lval; @@ -1924,8 +1927,11 @@ static void free_php_snmp_properties(zval *el) /* {{{ */ #define PHP_SNMP_PROPERTY_ENTRY_RECORD(name) \ { "" #name "", sizeof("" #name "") - 1, php_snmp_read_##name, php_snmp_write_##name } +#define PHP_SNMP_READONLY_PROPERTY_ENTRY_RECORD(name) \ + { "" #name "", sizeof("" #name "") - 1, php_snmp_read_##name, NULL } + const php_snmp_prop_handler php_snmp_property_entries[] = { - PHP_SNMP_PROPERTY_ENTRY_RECORD(info), + PHP_SNMP_READONLY_PROPERTY_ENTRY_RECORD(info), PHP_SNMP_PROPERTY_ENTRY_RECORD(max_oids), PHP_SNMP_PROPERTY_ENTRY_RECORD(valueretrieval), PHP_SNMP_PROPERTY_ENTRY_RECORD(quick_print), diff --git a/ext/snmp/snmp.stub.php b/ext/snmp/snmp.stub.php index 32dc8123db9b7..db61d1c0d6a1a 100644 --- a/ext/snmp/snmp.stub.php +++ b/ext/snmp/snmp.stub.php @@ -75,21 +75,15 @@ function snmp_read_mib(string $filename): bool {} class SNMP { + /** @readonly */ public array $info; - /** @var int|null */ - public $max_oids; - /** @var int */ - public $valueretrieval; - /** @var bool */ - public $quick_print; - /** @var bool */ - public $enum_print; - /** @var int */ - public $oid_output_format; - /** @var bool */ - public $oid_increasing_check = true; - /** @var int */ - public $exceptions_enabled = 0; + public ?int $max_oids; + public int $valueretrieval; + public bool $quick_print; + public bool $enum_print; + public int $oid_output_format; + public bool $oid_increasing_check; + public int $exceptions_enabled; public function __construct(int $version, string $hostname, string $community, int $timeout = -1, int $retries = -1) {} diff --git a/ext/snmp/snmp_arginfo.h b/ext/snmp/snmp_arginfo.h index 757678c7610e4..8088755169fb9 100644 --- a/ext/snmp/snmp_arginfo.h +++ b/ext/snmp/snmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e413f4e60b0f04dc3f3cfd1bb90b8f896c3fd7f0 */ + * Stub hash: 5258c5796aca15e369dd72c0a8ed4dc1df31ce9d */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_snmpget, 0, 3, stdClass, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_BOOL) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) @@ -256,45 +256,45 @@ static zend_class_entry *register_class_SNMP(void) zend_string_release(property_info_name); zval property_max_oids_default_value; - ZVAL_NULL(&property_max_oids_default_value); + ZVAL_UNDEF(&property_max_oids_default_value); zend_string *property_max_oids_name = zend_string_init("max_oids", sizeof("max_oids") - 1, 1); - zend_declare_property_ex(class_entry, property_max_oids_name, &property_max_oids_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_max_oids_name, &property_max_oids_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); zend_string_release(property_max_oids_name); zval property_valueretrieval_default_value; - ZVAL_NULL(&property_valueretrieval_default_value); + ZVAL_UNDEF(&property_valueretrieval_default_value); zend_string *property_valueretrieval_name = zend_string_init("valueretrieval", sizeof("valueretrieval") - 1, 1); - zend_declare_property_ex(class_entry, property_valueretrieval_name, &property_valueretrieval_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_valueretrieval_name, &property_valueretrieval_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_valueretrieval_name); zval property_quick_print_default_value; - ZVAL_NULL(&property_quick_print_default_value); + ZVAL_UNDEF(&property_quick_print_default_value); zend_string *property_quick_print_name = zend_string_init("quick_print", sizeof("quick_print") - 1, 1); - zend_declare_property_ex(class_entry, property_quick_print_name, &property_quick_print_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_quick_print_name, &property_quick_print_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_quick_print_name); zval property_enum_print_default_value; - ZVAL_NULL(&property_enum_print_default_value); + ZVAL_UNDEF(&property_enum_print_default_value); zend_string *property_enum_print_name = zend_string_init("enum_print", sizeof("enum_print") - 1, 1); - zend_declare_property_ex(class_entry, property_enum_print_name, &property_enum_print_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_enum_print_name, &property_enum_print_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_enum_print_name); zval property_oid_output_format_default_value; - ZVAL_NULL(&property_oid_output_format_default_value); + ZVAL_UNDEF(&property_oid_output_format_default_value); zend_string *property_oid_output_format_name = zend_string_init("oid_output_format", sizeof("oid_output_format") - 1, 1); - zend_declare_property_ex(class_entry, property_oid_output_format_name, &property_oid_output_format_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_oid_output_format_name, &property_oid_output_format_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_oid_output_format_name); zval property_oid_increasing_check_default_value; - ZVAL_BOOL(&property_oid_increasing_check_default_value, 1); + ZVAL_UNDEF(&property_oid_increasing_check_default_value); zend_string *property_oid_increasing_check_name = zend_string_init("oid_increasing_check", sizeof("oid_increasing_check") - 1, 1); - zend_declare_property_ex(class_entry, property_oid_increasing_check_name, &property_oid_increasing_check_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_oid_increasing_check_name, &property_oid_increasing_check_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_oid_increasing_check_name); zval property_exceptions_enabled_default_value; - ZVAL_LONG(&property_exceptions_enabled_default_value, 0); + ZVAL_UNDEF(&property_exceptions_enabled_default_value); zend_string *property_exceptions_enabled_name = zend_string_init("exceptions_enabled", sizeof("exceptions_enabled") - 1, 1); - zend_declare_property_ex(class_entry, property_exceptions_enabled_name, &property_exceptions_enabled_default_value, ZEND_ACC_PUBLIC, NULL); + zend_declare_typed_property(class_entry, property_exceptions_enabled_name, &property_exceptions_enabled_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_exceptions_enabled_name); return class_entry; diff --git a/ext/snmp/tests/snmp-object-error.phpt b/ext/snmp/tests/snmp-object-error.phpt index b170f9a08323b..77e2d6bf4f7e8 100644 --- a/ext/snmp/tests/snmp-object-error.phpt +++ b/ext/snmp/tests/snmp-object-error.phpt @@ -75,7 +75,7 @@ $session = new SNMP(SNMP::VERSION_2c, $hostname, $community, $timeout, $retries) var_dump($session->max_oids); try { $session->max_oids = "ttt"; -} catch (\ValueError $e) { +} catch (TypeError $e) { echo $e->getMessage() . \PHP_EOL; } try { @@ -103,6 +103,6 @@ Closing session bool(true) Invalid or uninitialized SNMP object NULL -max_oids must be greater than 0 or null -max_oids must be greater than 0 or null +Cannot assign string to property SNMP::$max_oids of type ?int +SNMP::$max_oids must be greater than 0 or null NULL diff --git a/ext/snmp/tests/snmp-object-properties-error.phpt b/ext/snmp/tests/snmp-object-properties-error.phpt new file mode 100644 index 0000000000000..ca911c12a1736 --- /dev/null +++ b/ext/snmp/tests/snmp-object-properties-error.phpt @@ -0,0 +1,77 @@ +--TEST-- +Test SNMP object property errors +--SKIPIF-- + +--FILE-- +info = []; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->max_oids = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->max_oids = -1; +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->valueretrieval = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->quick_print = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->enum_print = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->oid_output_format = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->oid_increasing_check = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $session->exceptions_enabled = []; +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot write read-only property SNMP::$info +Cannot assign array to property SNMP::$max_oids of type ?int +SNMP::$max_oids must be greater than 0 or null +Cannot assign array to property SNMP::$valueretrieval of type int +Cannot assign array to property SNMP::$quick_print of type bool +Cannot assign array to property SNMP::$enum_print of type bool +Cannot assign array to property SNMP::$oid_output_format of type int +Cannot assign array to property SNMP::$oid_increasing_check of type bool +Cannot assign array to property SNMP::$exceptions_enabled of type int diff --git a/ext/snmp/tests/snmp-object-properties.phpt b/ext/snmp/tests/snmp-object-properties.phpt index 47c6dc663870c..af37eaac565df 100644 --- a/ext/snmp/tests/snmp-object-properties.phpt +++ b/ext/snmp/tests/snmp-object-properties.phpt @@ -192,5 +192,5 @@ NULL bool(false) SNMP retrieval method must be a bitmask of SNMP_VALUE_LIBRARY, SNMP_VALUE_PLAIN, and SNMP_VALUE_OBJECT SNMP output print format must be an SNMP_OID_OUTPUT_* constant -SNMP::$info property is read-only +Cannot write read-only property SNMP::$info NULL From e5336b202d5ca093c0b62fe1f26a8e68ecbdd19c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Fri, 14 May 2021 15:32:00 +0200 Subject: [PATCH 3/3] Add get_property_ptr_ptr handler --- ext/snmp/snmp.c | 21 ++++++++++++------- .../tests/snmp-object-properties-error.phpt | 6 ++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index bbe030b9b6627..c4afb2b171120 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -1667,15 +1667,11 @@ zval *php_snmp_read_property(zend_object *object, zend_string *name, int type, v } /* }}} */ -/* {{{ php_snmp_write_property(zval *object, zval *member, zval *value[, const zend_literal *key]) - Generic object property writer */ +/* {{{ Generic object property writer */ zval *php_snmp_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot) { - php_snmp_object *obj; - php_snmp_prop_handler *hnd; - - obj = php_snmp_fetch_object(object); - hnd = zend_hash_find_ptr(&php_snmp_properties, name); + php_snmp_object *obj = php_snmp_fetch_object(object); + php_snmp_prop_handler *hnd = zend_hash_find_ptr(&php_snmp_properties, name); if (hnd) { if (!hnd->write_func) { @@ -1773,6 +1769,16 @@ static HashTable *php_snmp_get_properties(zend_object *object) } /* }}} */ +static zval *php_snmp_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) +{ + php_snmp_prop_handler *hnd = zend_hash_find_ptr(&php_snmp_properties, name); + if (hnd == NULL) { + return zend_std_get_property_ptr_ptr(object, name, type, cache_slot); + } + + return NULL; +} + /* {{{ */ static int php_snmp_read_info(php_snmp_object *snmp_object, zval *retval) { @@ -1967,6 +1973,7 @@ PHP_MINIT_FUNCTION(snmp) memcpy(&php_snmp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_snmp_object_handlers.read_property = php_snmp_read_property; php_snmp_object_handlers.write_property = php_snmp_write_property; + php_snmp_object_handlers.get_property_ptr_ptr = php_snmp_get_property_ptr_ptr; php_snmp_object_handlers.has_property = php_snmp_has_property; php_snmp_object_handlers.get_properties = php_snmp_get_properties; php_snmp_object_handlers.get_gc = php_snmp_get_gc; diff --git a/ext/snmp/tests/snmp-object-properties-error.phpt b/ext/snmp/tests/snmp-object-properties-error.phpt index ca911c12a1736..67770b6f924b4 100644 --- a/ext/snmp/tests/snmp-object-properties-error.phpt +++ b/ext/snmp/tests/snmp-object-properties-error.phpt @@ -28,6 +28,12 @@ try { echo $exception->getMessage() . "\n"; } +try { + $session->max_oids += 1; +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} + try { $session->valueretrieval = []; } catch (TypeError $exception) {