]> granicus.if.org Git - php/commitdiff
- Fixed bug #54384 (Dual iterators, GlobIterator, SplFileObject and
authorGustavo André dos Santos Lopes <cataphract@php.net>
Mon, 4 Apr 2011 02:50:27 +0000 (02:50 +0000)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Mon, 4 Apr 2011 02:50:27 +0000 (02:50 +0000)
  SplTempFileObject crash when user-space classes don't call the paren
  constructor).

NEWS
ext/spl/spl_directory.c
ext/spl/spl_iterators.c
ext/spl/tests/bug54384.phpt [new file with mode: 0644]
ext/spl/tests/iterator_031.phpt

diff --git a/NEWS b/NEWS
index 534e075ae9e6195d3a4d4b0a16a2507d7656589a..963314cec5cacaeae3153b1b384de7ddcbba8002 100644 (file)
--- 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
index 1c25e82a2bbf6785884975a93b97a5809fbb380f..4360e10ef087bd23b8d0acfe9d5eda1594ef4eb1 100755 (executable)
@@ -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;
 }
 /* }}} */
index 9383d71992b3b3520cd4460e84c3a70799d83639..944997c731b9163e3495129b0fa3ef4cd45dd51d 100755 (executable)
@@ -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 (file)
index 0000000..a1ce7ed
--- /dev/null
@@ -0,0 +1,171 @@
+--TEST--
+Bug #54384: Several SPL classes crash when the parent constructor is not called
+--FILE--
+<?php
+
+function test($f) {
+       try {
+               $f();
+               echo "ran normally (unexpected)\n\n";
+       } catch (LogicException $e) {
+               echo "exception (expected)\n";
+       }
+}
+
+echo "IteratorIterator... ";
+class IteratorIteratorTest extends IteratorIterator {
+    function __construct(){}
+}
+test( function() {
+       $o = new IteratorIteratorTest;
+       $o->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)
index 458f071b76f8a46cadc3872aad981b4124972667..40342f4bb47e46fadaba9ccf0fda2492bff359d7 100755 (executable)
@@ -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