From eff1969ddc57440666fb5f65cf09d151d526989d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 4 Feb 2025 15:13:46 -0500 Subject: [PATCH 1/2] PHPC:2498: Accept integer types for Document array access --- src/BSON/Document.c | 93 ++++++++++++------- .../bson/bson-document-array-access-004.phpt | 35 +++++++ .../bson/bson-document-array-access-005.phpt | 35 +++++++ .../bson-document-array-access_error-003.phpt | 6 -- .../bson-document-array-access_error-004.phpt | 6 -- 5 files changed, 130 insertions(+), 45 deletions(-) create mode 100644 tests/bson/bson-document-array-access-004.phpt create mode 100644 tests/bson/bson-document-array-access-005.phpt diff --git a/src/BSON/Document.c b/src/BSON/Document.c index a3b1ce524..36d48417e 100644 --- a/src/BSON/Document.c +++ b/src/BSON/Document.c @@ -192,6 +192,36 @@ static bool php_phongo_document_get(php_phongo_document_t* intern, char* key, si return true; } +static bool php_phongo_document_get_by_zval(php_phongo_document_t* intern, zval* key, zval* return_value, bool null_if_missing) +{ + if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_LONG) { + if (null_if_missing) { + ZVAL_NULL(return_value); + return true; + } + + phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", zend_zval_type_name(key)); + return false; + } + + zend_string* tmp_str; + zend_string* str = zval_try_get_tmp_string(key, &tmp_str); + + if (!str) { + // Exception already thrown + return false; + } + + if (!php_phongo_document_get(intern, ZSTR_VAL(str), ZSTR_LEN(str), return_value, null_if_missing)) { + // Exception already thrown + zend_tmp_string_release(tmp_str); + return false; + } + + zend_tmp_string_release(tmp_str); + return true; +} + static PHP_METHOD(MongoDB_BSON_Document, get) { php_phongo_document_t* intern; @@ -229,6 +259,30 @@ static bool php_phongo_document_has(php_phongo_document_t* intern, char* key, si return bson_iter_find_w_len(&iter, key, key_len); } +static bool php_phongo_document_has_by_zval(php_phongo_document_t* intern, zval* key) +{ + if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_LONG) { + return false; + } + + zend_string* tmp_str; + zend_string* str = zval_try_get_tmp_string(key, &tmp_str); + + if (!str) { + // Exception already thrown + return false; + } + + if (!php_phongo_document_has(intern, ZSTR_VAL(str), ZSTR_LEN(str))) { + // Exception may be thrown if BSON iterator could not be initialized + zend_tmp_string_release(tmp_str); + return false; + } + + zend_tmp_string_release(tmp_str); + return true; +} + static PHP_METHOD(MongoDB_BSON_Document, has) { php_phongo_document_t* intern; @@ -309,11 +363,7 @@ static PHP_METHOD(MongoDB_BSON_Document, offsetExists) intern = Z_DOCUMENT_OBJ_P(getThis()); - if (Z_TYPE_P(offset) != IS_STRING) { - RETURN_FALSE; - } - - RETURN_BOOL(php_phongo_document_has(intern, Z_STRVAL_P(offset), Z_STRLEN_P(offset))); + RETURN_BOOL(php_phongo_document_has_by_zval(intern, offset)); } static PHP_METHOD(MongoDB_BSON_Document, offsetGet) @@ -327,13 +377,8 @@ static PHP_METHOD(MongoDB_BSON_Document, offsetGet) intern = Z_DOCUMENT_OBJ_P(getThis()); - if (Z_TYPE_P(offset) != IS_STRING) { - phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", zend_zval_type_name(offset)); - return; - } - // May throw, in which case we do nothing - php_phongo_document_get(intern, Z_STRVAL_P(offset), Z_STRLEN_P(offset), return_value, false); + php_phongo_document_get_by_zval(intern, offset, return_value, false); } static PHP_METHOD(MongoDB_BSON_Document, offsetSet) @@ -588,21 +633,9 @@ void php_phongo_document_unset_property(zend_object* object, zend_string* member zval* php_phongo_document_read_dimension(zend_object* object, zval* offset, int type, zval* rv) { - php_phongo_document_t* intern; - - intern = Z_OBJ_DOCUMENT(object); - - if (Z_TYPE_P(offset) != IS_STRING) { - if (type == BP_VAR_IS) { - ZVAL_NULL(rv); - return rv; - } - - phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", zend_zval_type_name(offset)); - return &EG(uninitialized_zval); - } + php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); - if (!php_phongo_document_get(intern, Z_STRVAL_P(offset), Z_STRLEN_P(offset), rv, type == BP_VAR_IS)) { + if (!php_phongo_document_get_by_zval(intern, offset, rv, type == BP_VAR_IS)) { // Exception already thrown return &EG(uninitialized_zval); } @@ -617,15 +650,9 @@ void php_phongo_document_write_dimension(zend_object* object, zval* offset, zval int php_phongo_document_has_dimension(zend_object* object, zval* member, int check_empty) { - php_phongo_document_t* intern; - - intern = Z_OBJ_DOCUMENT(object); - - if (Z_TYPE_P(member) != IS_STRING) { - return false; - } + php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); - return php_phongo_document_has(intern, Z_STRVAL_P(member), Z_STRLEN_P(member)); + return php_phongo_document_has_by_zval(intern, member); } void php_phongo_document_unset_dimension(zend_object* object, zval* offset) diff --git a/tests/bson/bson-document-array-access-004.phpt b/tests/bson/bson-document-array-access-004.phpt new file mode 100644 index 000000000..0bebb4e0d --- /dev/null +++ b/tests/bson/bson-document-array-access-004.phpt @@ -0,0 +1,35 @@ +--TEST-- +MongoDB\BSON\Document array access with integers (dimension object accessors) +--FILE-- + 'foo', + '1' => 'bar', +]); + +// Use a variable to assert that conversion doesn't affect the original zval +$key = 1; + +var_dump(isset($document[0])); +var_dump(isset($document[$key])); +var_dump(isset($document[2])); + +var_dump($document[0]); +var_dump($document[$key]); + +var_dump($key); + +?> +===DONE=== + +--EXPECT-- +bool(true) +bool(true) +bool(false) +string(3) "foo" +string(3) "bar" +int(1) +===DONE=== diff --git a/tests/bson/bson-document-array-access-005.phpt b/tests/bson/bson-document-array-access-005.phpt new file mode 100644 index 000000000..c6a48a572 --- /dev/null +++ b/tests/bson/bson-document-array-access-005.phpt @@ -0,0 +1,35 @@ +--TEST-- +MongoDB\BSON\Document array access with integers (ArrayAccess methods) +--FILE-- + 'foo', + '1' => 'bar', +]); + +// Use a variable to assert that conversion doesn't affect the original zval +$key = 1; + +var_dump($document->offsetExists(0)); +var_dump($document->offsetExists($key)); +var_dump($document->offsetExists(2)); + +var_dump($document->offsetGet(0)); +var_dump($document->offsetGet($key)); + +var_dump($key); + +?> +===DONE=== + +--EXPECT-- +bool(true) +bool(true) +bool(false) +string(3) "foo" +string(3) "bar" +int(1) +===DONE=== diff --git a/tests/bson/bson-document-array-access_error-003.phpt b/tests/bson/bson-document-array-access_error-003.phpt index 26cb8d1ce..1637bc669 100644 --- a/tests/bson/bson-document-array-access_error-003.phpt +++ b/tests/bson/bson-document-array-access_error-003.phpt @@ -11,10 +11,6 @@ $document = MongoDB\BSON\Document::fromPHP([ 'int64' => new MongoDB\BSON\Int64(123), ]); -echo throws(function() use ($document) { - $document[0]; -}, MongoDB\Driver\Exception\RuntimeException::class), "\n"; - echo throws(function() use ($document) { $document[0.1]; }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; @@ -28,8 +24,6 @@ echo throws(function() use ($document) { --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException -Could not find key of type "int" in BSON document -OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "float" in BSON document OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "bool" in BSON document diff --git a/tests/bson/bson-document-array-access_error-004.phpt b/tests/bson/bson-document-array-access_error-004.phpt index bb9647c80..024d588a3 100644 --- a/tests/bson/bson-document-array-access_error-004.phpt +++ b/tests/bson/bson-document-array-access_error-004.phpt @@ -11,10 +11,6 @@ $document = MongoDB\BSON\Document::fromPHP([ 'int64' => new MongoDB\BSON\Int64(123), ]); -echo throws(function() use ($document) { - $document->offsetGet(0); -}, MongoDB\Driver\Exception\RuntimeException::class), "\n"; - echo throws(function() use ($document) { $document->offsetGet(0.1); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; @@ -28,8 +24,6 @@ echo throws(function() use ($document) { --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException -Could not find key of type "int" in BSON document -OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "float" in BSON document OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "bool" in BSON document From f8925ffbb70e1e690acf53d1fad1fede373d21d2 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 4 Feb 2025 15:17:38 -0500 Subject: [PATCH 2/2] Refactor Document::get() and property handlers --- src/BSON/Document.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/BSON/Document.c b/src/BSON/Document.c index 36d48417e..6fd8e38f5 100644 --- a/src/BSON/Document.c +++ b/src/BSON/Document.c @@ -234,10 +234,8 @@ static PHP_METHOD(MongoDB_BSON_Document, get) intern = Z_DOCUMENT_OBJ_P(getThis()); - if (!php_phongo_document_get(intern, key, key_len, return_value, false)) { - // Exception already thrown - RETURN_NULL(); - } + // May throw, in which case we do nothing + php_phongo_document_get(intern, key, key_len, return_value, false); } static PHP_METHOD(MongoDB_BSON_Document, getIterator) @@ -595,13 +593,9 @@ static HashTable* php_phongo_document_get_properties(zend_object* object) zval* php_phongo_document_read_property(zend_object* object, zend_string* member, int type, void** cache_slot, zval* rv) { - php_phongo_document_t* intern; - char* key = ZSTR_VAL(member); - size_t key_len = ZSTR_LEN(member); - - intern = Z_OBJ_DOCUMENT(object); + php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); - if (!php_phongo_document_get(intern, key, key_len, rv, type == BP_VAR_IS)) { + if (!php_phongo_document_get(intern, ZSTR_VAL(member), ZSTR_LEN(member), rv, type == BP_VAR_IS)) { // Exception already thrown return &EG(uninitialized_zval); } @@ -615,15 +609,11 @@ zval* php_phongo_document_write_property(zend_object* object, zend_string* membe return value; } -int php_phongo_document_has_property(zend_object* object, zend_string* name, int has_set_exists, void** cache_slot) +int php_phongo_document_has_property(zend_object* object, zend_string* member, int has_set_exists, void** cache_slot) { - php_phongo_document_t* intern; - char* key = ZSTR_VAL(name); - size_t key_len = ZSTR_LEN(name); - - intern = Z_OBJ_DOCUMENT(object); + php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); - return php_phongo_document_has(intern, key, key_len); + return php_phongo_document_has(intern, ZSTR_VAL(member), ZSTR_LEN(member)); } void php_phongo_document_unset_property(zend_object* object, zend_string* member, void** cache_slot)