From 2e79183de21f56f13c19dc59371b3700c09cfeea Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 13 Nov 2022 08:22:30 -0500 Subject: [PATCH] Also reject negative format values in APCuIterator This would affect applications that accidentally or deliberately pass in negative values for $format (e.g. PHP_INT_MIN on 64-bit builds) The apc_error macro surprisingly calls php_verror, which is a fatal error. Switch this to zend_throw_error instead - this still supports PHP 8.0 so ValueError is too new. --- apc_iterator.c | 11 ++++++----- apc_iterator.h | 4 ++-- package.xml | 1 + php_apc.c | 4 ++-- tests/iterator_012.phpt | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 tests/iterator_012.phpt diff --git a/apc_iterator.c b/apc_iterator.c index 07bd0e4e..b0e29655 100644 --- a/apc_iterator.c +++ b/apc_iterator.c @@ -316,7 +316,7 @@ static void apc_iterator_totals(apc_iterator_t *iterator) { } /* }}} */ -void apc_iterator_obj_init(apc_iterator_t *iterator, zval *search, zend_long format, size_t chunk_size, zend_long list) +void apc_iterator_obj_init(apc_iterator_t *iterator, zval *search, zend_ulong format, size_t chunk_size, zend_long list) { if (!APCG(enabled)) { zend_throw_error(NULL, "APC must be enabled to use APCUIterator"); @@ -324,7 +324,7 @@ void apc_iterator_obj_init(apc_iterator_t *iterator, zval *search, zend_long for } if (format > APC_ITER_ALL) { - apc_error("APCUIterator format is invalid"); + zend_throw_error(NULL, "APCUIterator format is invalid"); return; } @@ -354,9 +354,10 @@ void apc_iterator_obj_init(apc_iterator_t *iterator, zval *search, zend_long for iterator->pce = pcre_get_compiled_regex_cache(iterator->regex); if (!iterator->pce) { - apc_error("Could not compile regular expression: %s", Z_STRVAL_P(search)); + zend_throw_error(NULL, "Could not compile regular expression: %s", Z_STRVAL_P(search)); zend_string_release(iterator->regex); iterator->regex = NULL; + return; } #if PHP_VERSION_ID >= 70300 @@ -385,7 +386,7 @@ PHP_METHOD(APCUIterator, __construct) { ZEND_PARSE_PARAMETERS_END(); if (chunk_size < 0) { - apc_error("APCUIterator chunk size must be 0 or greater"); + zend_throw_error(NULL, "APCUIterator chunk size must be 0 or greater"); return; } @@ -580,7 +581,7 @@ int apc_iterator_delete(zval *zobj) { apc_iterator_item_t *item; if (!ce || !instanceof_function(ce, apc_iterator_ce)) { - apc_error("apc_delete object argument must be instance of APCUIterator."); + apc_warning("apcu_delete object argument must be an instance of APCUIterator."); return 0; } iterator = apc_iterator_fetch(zobj); diff --git a/apc_iterator.h b/apc_iterator.h index 9feda387..e4b563cb 100644 --- a/apc_iterator.h +++ b/apc_iterator.h @@ -49,7 +49,7 @@ /* {{{ apc_iterator_t */ typedef struct _apc_iterator_t { short int initialized; /* sanity check in case __construct failed */ - zend_long format; /* format bitmask of the return values ie: key, value, info */ + zend_ulong format; /* format bitmask of the return values ie: key, value, info */ size_t (*fetch)(struct _apc_iterator_t *iterator); /* fetch callback to fetch items from cache slots or lists */ size_t slot_idx; /* index to the slot array or linked list */ @@ -84,7 +84,7 @@ typedef struct _apc_iterator_item_t { PHP_APCU_API void apc_iterator_obj_init( apc_iterator_t *iterator, zval *search, - zend_long format, + zend_ulong format, size_t chunk_size, zend_long list); PHP_APCU_API zend_class_entry* apc_iterator_get_ce(void); diff --git a/package.xml b/package.xml index 358786c7..186e9a80 100644 --- a/package.xml +++ b/package.xml @@ -116,6 +116,7 @@ + diff --git a/php_apc.c b/php_apc.c index 081b62a5..3c5808bb 100644 --- a/php_apc.c +++ b/php_apc.c @@ -748,7 +748,7 @@ PHP_FUNCTION(apcu_delete) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), hentry) { ZVAL_DEREF(hentry); if (Z_TYPE_P(hentry) != IS_STRING) { - apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance"); + apc_warning("apcu_delete() expects a string, array of strings, or APCUIterator instance"); add_next_index_zval(return_value, hentry); Z_TRY_ADDREF_P(hentry); } else if (apc_cache_delete(apc_user_cache, Z_STR_P(hentry)) != 1) { @@ -759,7 +759,7 @@ PHP_FUNCTION(apcu_delete) { } else if (Z_TYPE_P(keys) == IS_OBJECT) { RETURN_BOOL(apc_iterator_delete(keys) != 0); } else { - apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance"); + apc_warning("apcu_delete() expects a string, array of strings, or APCUIterator instance"); RETURN_FALSE; } } diff --git a/tests/iterator_012.phpt b/tests/iterator_012.phpt new file mode 100644 index 00000000..691deed9 --- /dev/null +++ b/tests/iterator_012.phpt @@ -0,0 +1,40 @@ +--TEST-- +APC: APCIterator throws for invalid flags +--SKIPIF-- + +--INI-- +apc.enabled=1 +apc.enable_cli=1 +--FILE-- +getMessage()); + } +} +foreach ([[[]], 4.2, new stdClass()] as $delete) { + try { + apcu_delete($delete); + } catch (Throwable $e) { + printf("Caught %s: %s\n", get_class($e), $e->getMessage()); + } +} +?> +--EXPECTF-- +Caught Error: APCUIterator format is invalid +Caught Error: APCUIterator format is invalid + +Warning: APCUIterator::__construct(): No ending delimiter '/' found in %s on line 4 +Caught Error: Could not compile regular expression: /invalidRegex +Caught Error: APCUIterator chunk size must be 0 or greater + +Warning: apcu_delete(): apcu_delete() expects a string, array of strings, or APCUIterator instance in %s on line 11 + +Warning: apcu_delete(): apcu_delete() expects a string, array of strings, or APCUIterator instance in %s on line 11 + +Warning: apcu_delete(): apcu_delete object argument must be an instance of APCUIterator. in %s on line 11