From 2975308e1adff7d06197810017a63308a2ac72a3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gustavo=20Andr=C3=A9=20dos=20Santos=20Lopes?= Date: Mon, 4 Apr 2011 02:50:27 +0000 Subject: [PATCH] - Fixed bug #54384 (Dual iterators, GlobIterator, SplFileObject and SplTempFileObject crash when user-space classes don't call the paren constructor). --- NEWS | 3 + ext/spl/spl_directory.c | 44 +++++++- ext/spl/spl_iterators.c | 134 +++++++++++++++---------- ext/spl/tests/bug54384.phpt | 171 ++++++++++++++++++++++++++++++++ ext/spl/tests/iterator_031.phpt | 4 +- 5 files changed, 297 insertions(+), 59 deletions(-) create mode 100644 ext/spl/tests/bug54384.phpt diff --git a/NEWS b/NEWS index 534e075ae9..963314cec5 100644 --- a/NEWS +++ b/NEWS @@ -68,6 +68,9 @@ PHP NEWS . Fixed bug #51958 (socket_accept() fails on IPv6 server sockets). (Gustavo) - SPL extension: + . Fixed bug #54384 (Dual iterators, GlobIterator, SplFileObject and + SplTempFileObject crash when user-space classes don't call the paren + constructor). (Gustavo) . Fixed bug #54292 (Wrong parameter causes crash in SplFileObject::__construct()). (Felipe) . Fixed bug #54291 (Crash iterating DirectoryIterator for dir name starting diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 1c25e82a2b..4360e10ef0 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -48,6 +48,8 @@ /* declare the class handlers */ static zend_object_handlers spl_filesystem_object_handlers; +/* includes handler to validate object state when retrieving methods */ +static zend_object_handlers spl_filesystem_object_check_handlers; /* decalre the class entry */ PHPAPI zend_class_entry *spl_ce_SplFileInfo; @@ -162,6 +164,16 @@ static zend_object_value spl_filesystem_object_new(zend_class_entry *class_type } /* }}} */ +/* {{{ spl_filesystem_object_new_ex */ +static zend_object_value spl_filesystem_object_new_check(zend_class_entry *class_type TSRMLS_DC) +{ + zend_object_value ret = spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC); + ret.handlers = &spl_filesystem_object_check_handlers; + return ret; +} +/* }}} */ + + PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, int *len TSRMLS_DC) /* {{{ */ { #ifdef HAVE_GLOB @@ -617,6 +629,19 @@ static HashTable* spl_filesystem_object_get_debug_info(zval *obj, int *is_temp T } /* }}} */ +zend_function *spl_filesystem_object_get_method_check(zval **object_ptr, char *method, int method_len TSRMLS_DC) /* {{{ */ +{ + spl_filesystem_object *fsobj = zend_object_store_get_object(*object_ptr TSRMLS_CC); + + if (fsobj->u.dir.entry.d_name[0] == '\0' && fsobj->orig_path == NULL) { + method = "_bad_state_ex"; + method_len = sizeof("_bad_state_ex") - 1; + } + + return zend_get_std_object_handlers()->get_method(object_ptr, method, method_len TSRMLS_CC); +} +/* }}} */ + #define DIT_CTOR_FLAGS 0x00000001 #define DIT_CTOR_GLOB 0x00000002 @@ -1354,6 +1379,15 @@ SPL_METHOD(SplFileInfo, getPathInfo) } /* }}} */ +/* {{{ */ +SPL_METHOD(SplFileInfo, _bad_state_ex) +{ + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, + "The parent constructor was not called: the object is in an " + "invalid state "); +} +/* }}} */ + /* {{{ proto void FilesystemIterator::__construct(string path [, int flags]) Cronstructs a new dir iterator from a path. */ SPL_METHOD(FilesystemIterator, __construct) @@ -1891,6 +1925,7 @@ static const zend_function_entry spl_SplFileInfo_functions[] = { SPL_ME(SplFileInfo, openFile, arginfo_info_openFile, ZEND_ACC_PUBLIC) SPL_ME(SplFileInfo, setFileClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) SPL_ME(SplFileInfo, setInfoClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, _bad_state_ex, NULL, ZEND_ACC_PUBLIC) SPL_MA(SplFileInfo, __toString, SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; @@ -2922,13 +2957,16 @@ PHP_MINIT_FUNCTION(spl_directory) REGISTER_SPL_SUB_CLASS_EX(RecursiveDirectoryIterator, FilesystemIterator, spl_filesystem_object_new, spl_RecursiveDirectoryIterator_functions); REGISTER_SPL_IMPLEMENTS(RecursiveDirectoryIterator, RecursiveIterator); + + memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers)); + spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check; #ifdef HAVE_GLOB - REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new, spl_GlobIterator_functions); + REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new_check, spl_GlobIterator_functions); REGISTER_SPL_IMPLEMENTS(GlobIterator, Countable); #endif - REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new, spl_SplFileObject_functions); + REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new_check, spl_SplFileObject_functions); REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator); REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator); @@ -2937,7 +2975,7 @@ PHP_MINIT_FUNCTION(spl_directory) REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY", SPL_FILE_OBJECT_SKIP_EMPTY); REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV", SPL_FILE_OBJECT_READ_CSV); - REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new, spl_SplTempFileObject_functions); + REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new_check, spl_SplTempFileObject_functions); return SUCCESS; } /* }}} */ diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 9383d71992..944997c731 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -125,6 +125,17 @@ typedef struct _spl_recursive_it_iterator { static zend_object_handlers spl_handlers_rec_it_it; static zend_object_handlers spl_handlers_dual_it; +#define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \ + do { \ + spl_dual_it_object *it = zend_object_store_get_object((objzval) TSRMLS_CC); \ + if (it->dit_type == DIT_Unknown) { \ + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, \ + "The object is in an invalid state as the parent constructor was not called"); \ + return; \ + } \ + (var) = it; \ + } while (0) + static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC) { spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter; @@ -406,6 +417,10 @@ static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, } iterator = emalloc(sizeof(spl_recursive_it_iterator)); object = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC); + if (object->iterators == NULL) { + zend_error(E_ERROR, "The object to be iterated is in an invalid state: " + "the parent constructor has not been called"); + } Z_ADDREF_P(zobject); iterator->intern.data = (void*)object; @@ -1516,12 +1531,12 @@ SPL_METHOD(FilterIterator, __construct) SPL_METHOD(dual_it, getInnerIterator) { spl_dual_it_object *intern; - - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_parse_parameters_none() == FAILURE) { return; } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->inner.zobject) { RETVAL_ZVAL(intern->inner.zobject, 1, 0); @@ -1620,13 +1635,13 @@ static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRM SPL_METHOD(dual_it, rewind) { spl_dual_it_object *intern; - - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_parse_parameters_none() == FAILURE) { return; } + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + spl_dual_it_rewind(intern TSRMLS_CC); spl_dual_it_fetch(intern, 1 TSRMLS_CC); } /* }}} */ @@ -1644,7 +1659,7 @@ SPL_METHOD(dual_it, valid) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_BOOL(intern->current.data); } /* }}} */ @@ -1665,7 +1680,7 @@ SPL_METHOD(dual_it, key) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->current.data) { if (intern->current.key_type == HASH_KEY_IS_STRING) { @@ -1693,7 +1708,7 @@ SPL_METHOD(dual_it, current) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->current.data) { RETVAL_ZVAL(intern->current.data, 1, 0); @@ -1714,7 +1729,7 @@ SPL_METHOD(dual_it, next) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_dual_it_next(intern, 1 TSRMLS_CC); spl_dual_it_fetch(intern, 1 TSRMLS_CC); @@ -1763,7 +1778,7 @@ SPL_METHOD(FilterIterator, rewind) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_filter_it_rewind(getThis(), intern TSRMLS_CC); } /* }}} */ @@ -1777,7 +1792,7 @@ SPL_METHOD(FilterIterator, next) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_filter_it_next(getThis(), intern TSRMLS_CC); } /* }}} */ @@ -1799,7 +1814,7 @@ SPL_METHOD(RecursiveFilterIterator, hasChildren) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); if (retval) { @@ -1820,7 +1835,7 @@ SPL_METHOD(RecursiveFilterIterator, getChildren) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); if (!EG(exception) && retval) { @@ -1850,7 +1865,7 @@ SPL_METHOD(RegexIterator, __construct) Match (string)current() against regular expression */ SPL_METHOD(RegexIterator, accept) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; char *subject, tmp[32], *result; int subject_len, use_copy, count = 0, result_len; zval subject_copy, zcount, *replacement; @@ -1859,6 +1874,8 @@ SPL_METHOD(RegexIterator, accept) return; } + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + if (intern->current.data == NULL) { RETURN_FALSE; } @@ -1950,12 +1967,14 @@ SPL_METHOD(RegexIterator, accept) Returns current operation mode */ SPL_METHOD(RegexIterator, getMode) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + RETURN_LONG(intern->u.regex.mode); } /* }}} */ @@ -1963,7 +1982,7 @@ SPL_METHOD(RegexIterator, getMode) Set new operation mode */ SPL_METHOD(RegexIterator, setMode) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; long mode; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) { @@ -1974,6 +1993,8 @@ SPL_METHOD(RegexIterator, setMode) zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode); return;/* NULL */ } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); intern->u.regex.mode = mode; } /* }}} */ @@ -1982,12 +2003,14 @@ SPL_METHOD(RegexIterator, setMode) Returns current operation flags */ SPL_METHOD(RegexIterator, getFlags) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + RETURN_LONG(intern->u.regex.flags); } /* }}} */ @@ -1995,12 +2018,14 @@ SPL_METHOD(RegexIterator, getFlags) Set operation flags */ SPL_METHOD(RegexIterator, setFlags) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; long flags; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) { return; } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); intern->u.regex.flags = flags; } /* }}} */ @@ -2009,11 +2034,13 @@ SPL_METHOD(RegexIterator, setFlags) Returns current PREG flags (if in use or NULL) */ SPL_METHOD(RegexIterator, getPregFlags) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->u.regex.use_flags) { RETURN_LONG(intern->u.regex.preg_flags); @@ -2026,12 +2053,14 @@ SPL_METHOD(RegexIterator, getPregFlags) Set PREG flags */ SPL_METHOD(RegexIterator, setPregFlags) { - spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_dual_it_object *intern; long preg_flags; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) { return; } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); intern->u.regex.preg_flags = preg_flags; intern->u.regex.use_flags = 1; @@ -2055,7 +2084,7 @@ SPL_METHOD(RecursiveRegexIterator, getChildren) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); if (!EG(exception)) { @@ -2292,7 +2321,7 @@ SPL_METHOD(LimitIterator, rewind) { spl_dual_it_object *intern; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_dual_it_rewind(intern TSRMLS_CC); spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC); } /* }}} */ @@ -2303,7 +2332,7 @@ SPL_METHOD(LimitIterator, valid) { spl_dual_it_object *intern; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); /* RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/ RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data); @@ -2315,7 +2344,7 @@ SPL_METHOD(LimitIterator, next) { spl_dual_it_object *intern; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_dual_it_next(intern, 1 TSRMLS_CC); if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) { @@ -2334,7 +2363,7 @@ SPL_METHOD(LimitIterator, seek) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_limit_it_seek(intern, pos TSRMLS_CC); RETURN_LONG(intern->current.pos); } /* }}} */ @@ -2344,7 +2373,7 @@ SPL_METHOD(LimitIterator, seek) SPL_METHOD(LimitIterator, getPosition) { spl_dual_it_object *intern; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_LONG(intern->current.pos); } /* }}} */ @@ -2499,7 +2528,7 @@ SPL_METHOD(CachingIterator, rewind) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_caching_it_rewind(intern TSRMLS_CC); } /* }}} */ @@ -2514,7 +2543,7 @@ SPL_METHOD(CachingIterator, valid) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS); } /* }}} */ @@ -2529,7 +2558,7 @@ SPL_METHOD(CachingIterator, next) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_caching_it_next(intern TSRMLS_CC); } /* }}} */ @@ -2544,7 +2573,7 @@ SPL_METHOD(CachingIterator, hasNext) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS); } /* }}} */ @@ -2555,7 +2584,7 @@ SPL_METHOD(CachingIterator, __toString) { spl_dual_it_object *intern; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2590,7 +2619,7 @@ SPL_METHOD(CachingIterator, offsetSet) uint nKeyLength; zval *value; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2615,7 +2644,7 @@ SPL_METHOD(CachingIterator, offsetGet) uint nKeyLength; zval **value; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2643,7 +2672,7 @@ SPL_METHOD(CachingIterator, offsetUnset) char *arKey; uint nKeyLength; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2666,7 +2695,7 @@ SPL_METHOD(CachingIterator, offsetExists) char *arKey; uint nKeyLength; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2691,7 +2720,7 @@ SPL_METHOD(CachingIterator, getCache) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2712,7 +2741,7 @@ SPL_METHOD(CachingIterator, getFlags) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_LONG(intern->u.caching.flags); } @@ -2725,7 +2754,7 @@ SPL_METHOD(CachingIterator, setFlags) spl_dual_it_object *intern; long flags; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) { return; @@ -2761,7 +2790,7 @@ SPL_METHOD(CachingIterator, count) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); @@ -2828,7 +2857,7 @@ SPL_METHOD(RecursiveCachingIterator, hasChildren) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_BOOL(intern->u.caching.zchildren); } /* }}} */ @@ -2843,7 +2872,7 @@ SPL_METHOD(RecursiveCachingIterator, getChildren) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->u.caching.zchildren) { RETURN_ZVAL(intern->u.caching.zchildren, 1, 0); @@ -2913,7 +2942,7 @@ SPL_METHOD(NoRewindIterator, valid) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS); } /* }}} */ @@ -2927,7 +2956,7 @@ SPL_METHOD(NoRewindIterator, key) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->inner.iterator->funcs->get_current_key) { char *str_key; @@ -2959,7 +2988,7 @@ SPL_METHOD(NoRewindIterator, current) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC); if (data && *data) { RETURN_ZVAL(*data, 1, 0); @@ -2976,7 +3005,7 @@ SPL_METHOD(NoRewindIterator, next) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC); } /* }}} */ @@ -3012,7 +3041,7 @@ SPL_METHOD(InfiniteIterator, next) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_dual_it_next(intern, 1 TSRMLS_CC); if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { @@ -3151,9 +3180,7 @@ SPL_METHOD(AppendIterator, append) spl_dual_it_object *intern; zval *it; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - - APPENDIT_CHECK_CTOR(intern); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) { return; @@ -3181,7 +3208,7 @@ SPL_METHOD(AppendIterator, rewind) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC); if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) { @@ -3199,7 +3226,7 @@ SPL_METHOD(AppendIterator, valid) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); RETURN_BOOL(intern->current.data); } /* }}} */ @@ -3214,7 +3241,7 @@ SPL_METHOD(AppendIterator, next) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); spl_append_it_next(intern TSRMLS_CC); } /* }}} */ @@ -3229,7 +3256,7 @@ SPL_METHOD(AppendIterator, getIteratorIndex) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); APPENDIT_CHECK_CTOR(intern); spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC); @@ -3245,9 +3272,8 @@ SPL_METHOD(AppendIterator, getArrayIterator) return; } - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); - APPENDIT_CHECK_CTOR(intern); RETURN_ZVAL(intern->u.append.zarrayit, 1, 0); } /* }}} */ diff --git a/ext/spl/tests/bug54384.phpt b/ext/spl/tests/bug54384.phpt new file mode 100644 index 0000000000..a1ce7edff3 --- /dev/null +++ b/ext/spl/tests/bug54384.phpt @@ -0,0 +1,171 @@ +--TEST-- +Bug #54384: Several SPL classes crash when the parent constructor is not called +--FILE-- +rewind(); +} ); + +echo "FilterIterator... "; +class FilterIteratorTest extends FilterIterator { + function __construct(){} + function accept(){} +} +test( function() { + $o = new FilterIteratorTest; + $o->rewind(); +} ); + +echo "RecursiveFilterIterator... "; +class RecursiveFilterIteratorTest extends RecursiveFilterIterator { + function __construct(){} + function accept(){} +} +test( function() { +$o = new RecursiveFilterIteratorTest; +$o->hasChildren(); +} ); + +echo "ParentIterator... "; +class ParentIteratorTest extends ParentIterator { + function __construct(){} +} +test ( function() { +$o = new ParentIteratorTest; +$o->accept(); +} ); + +echo "LimitIterator... "; +class LimitIteratorTest extends LimitIterator { + function __construct(){} +} +test ( function() { +$o = new LimitIteratorTest; +$o->rewind(); +} ); + +echo "CachingIterator... "; +class CachingIteratorTest extends CachingIterator { + function __construct(){} +} +test ( function() { +$o = new CachingIteratorTest; +$o->rewind(); +} ); + +echo "RecursiveCachingIterator... "; +class RecursiveCachingIteratorTest extends RecursiveCachingIterator { + function __construct(){} +} +test ( function() { +$o = new RecursiveCachingIteratorTest; +$o->rewind(); +} ); + +echo "NoRewindIterator... "; +class NoRewindIteratorTest extends NoRewindIterator { + function __construct(){} +} +test ( function() { +$o = new NoRewindIteratorTest; +$o->valid(); +} ); + +echo "RegexIterator... "; +class RegexIteratorTest extends RegexIterator { + function __construct(){} +} +test ( function() { +$o = new RegexIteratorTest; +$o->rewind(); +} ); + +echo "RecursiveRegexIterator... "; +class RecursiveRegexIteratorTest extends RecursiveRegexIterator { + function __construct(){} +} +test ( function() { +$o = new RecursiveRegexIteratorTest; +$o->hasChildren(); +} ); + +echo "GlobIterator... "; +class GlobIteratorTest extends GlobIterator { + function __construct(){} +} +test ( function() { +$o = new GlobIteratorTest; +$o->count(); +} ); + +echo "SplFileObject... "; +class SplFileObjectTest extends SplFileObject { + function __construct(){} +} +test ( function() { +$o = new SplFileObjectTest; +$o->rewind(); +} ); + +echo "SplTempFileObject... "; +class SplTempFileObjectTest extends SplTempFileObject { + function __construct(){} +} +test ( function() { +$o = new SplTempFileObjectTest; +$o->rewind(); +} ); + +echo "AppendIterator... "; +class AppendIteratorTest extends AppendIterator { + function __construct(){} +} +test ( function() { +$o = new AppendIteratorTest; +foreach ($o as $a) { +echo $a,"\n"; +} +} ); + +echo "InfiniteIterator... "; +class InfiniteIteratorTest extends InfiniteIterator { + function __construct(){} +} +test ( function() { +$o = new InfiniteIteratorTest; +foreach ($o as $a) { +echo $a,"\n"; +} +} ); + +--EXPECT-- +IteratorIterator... exception (expected) +FilterIterator... exception (expected) +RecursiveFilterIterator... exception (expected) +ParentIterator... exception (expected) +LimitIterator... exception (expected) +CachingIterator... exception (expected) +RecursiveCachingIterator... exception (expected) +NoRewindIterator... exception (expected) +RegexIterator... exception (expected) +RecursiveRegexIterator... exception (expected) +GlobIterator... exception (expected) +SplFileObject... exception (expected) +SplTempFileObject... exception (expected) +AppendIterator... exception (expected) +InfiniteIterator... exception (expected) diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt index 458f071b76..40342f4bb4 100755 --- a/ext/spl/tests/iterator_031.phpt +++ b/ext/spl/tests/iterator_031.phpt @@ -56,7 +56,7 @@ try { $ap->append($it); } -catch(BadMethodCallException $e) +catch(LogicException $e) { echo $e->getMessage() . "\n"; } @@ -90,7 +90,7 @@ MyArrayIterator::rewind 1=>2 MyAppendIterator::__construct MyAppendIterator::append -Classes derived from AppendIterator must call AppendIterator::__construct() +The object is in an invalid state as the parent constructor was not called AppendIterator::getIterator() must be called exactly once per instance MyAppendIterator::append MyArrayIterator::rewind -- 2.40.0