helly           Fri Mar  3 21:35:16 2006 UTC

  Added files:                 
    /php-src/ext/spl/tests      iterator_030.phpt iterator_031.phpt 

  Modified files:              
    /php-src/ext/spl    config.m4 spl_iterators.c spl_iterators.h 
  Log:
  - Fix SEGV with AppendIterator when base class constructor was not called
  - Generic check to prevent double call to constructors of SPL iterators
  
  
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/config.m4?r1=1.17&r2=1.18&diff_format=u
Index: php-src/ext/spl/config.m4
diff -u php-src/ext/spl/config.m4:1.17 php-src/ext/spl/config.m4:1.18
--- php-src/ext/spl/config.m4:1.17      Fri Jan  6 14:03:28 2006
+++ php-src/ext/spl/config.m4   Fri Mar  3 21:35:16 2006
@@ -1,4 +1,4 @@
-dnl $Id: config.m4,v 1.17 2006/01/06 14:03:28 sniper Exp $
+dnl $Id: config.m4,v 1.18 2006/03/03 21:35:16 helly Exp $
 dnl config.m4 for extension SPL
 
 PHP_ARG_ENABLE(spl, enable SPL suppport,
@@ -18,15 +18,17 @@
 }
   ], [
     ac_result=1
-    AC_MSG_RESULT(yes)
   ],[
     ac_result=0
-    AC_MSG_RESULT(no)
   ], [
     ac_result=0
-    AC_MSG_RESULT(no)
   ])
   CPPFLAGS=$old_CPPFLAGS
+  if test "$ac_result"; then
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+  fi
   AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct 
_zend_object_value is packed])
   AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) 
support]) 
   PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c 
spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c 
spl_observer.c, $ext_shared)
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/spl_iterators.c?r1=1.115&r2=1.116&diff_format=u
Index: php-src/ext/spl/spl_iterators.c
diff -u php-src/ext/spl/spl_iterators.c:1.115 
php-src/ext/spl/spl_iterators.c:1.116
--- php-src/ext/spl/spl_iterators.c:1.115       Tue Feb 21 20:12:42 2006
+++ php-src/ext/spl/spl_iterators.c     Fri Mar  3 21:35:16 2006
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: spl_iterators.c,v 1.115 2006/02/21 20:12:42 dmitry Exp $ */
+/* $Id: spl_iterators.c,v 1.116 2006/03/03 21:35:16 helly Exp $ */
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
@@ -823,7 +823,7 @@
                
                success = SUCCESS;
        } else {
-               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call 
%s::%s()", intern->inner.ce->name, method);
+               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call 
%v::%s()", intern->inner.ce->name, method);
                success = FAILURE;
        }
 
@@ -832,20 +832,33 @@
 }
 #endif
 
+#define SPL_CHECK_CTOR(intern, classname) \
+       if (intern->dit_type == DIT_Unknown) { \
+               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 
TSRMLS_CC, "Classes derived from %v must call %v::__construct()", \
+                               (spl_ce_##classname)->name, 
(spl_ce_##classname)->name); \
+               return; \
+       }
+
+#define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
+
 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more 
TSRMLS_DC);
 
-static inline spl_dual_it_object* 
spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_inner, 
dual_it_type dit_type)
+inline spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, 
zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type)
 {
        zval                 *zobject, *retval;
        spl_dual_it_object   *intern;
        zend_class_entry     *ce = NULL;
        int                   inc_refcount = 1;
 
+       intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() 
TSRMLS_CC);
+       
+       if (intern->dit_type != DIT_Unknown) {
+               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 
TSRMLS_CC, "%v::getIterator() must be called exactly once per instance", 
ce_base->name);
+               return NULL;
+       }
 
        php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException 
TSRMLS_CC);
 
-       intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() 
TSRMLS_CC);
-
        intern->dit_type = dit_type;
        switch (dit_type) {
                case DIT_LimitIterator: {
@@ -910,7 +923,7 @@
                                if (instanceof_function(ce, zend_ce_aggregate 
TSRMLS_CC)) {
                                        
zend_call_method_with_0_params(&zobject, ce, 
&ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
                                        if (!retval || Z_TYPE_P(retval) != 
IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable 
TSRMLS_CC)) {
-                                               
zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() 
must return an object that implememnts Traversable", ce->name);
+                                               
zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%v::getIterator() 
must return an object that implememnts Traversable", ce->name);
                                                
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
                                                return NULL;
                                        }
@@ -968,9 +981,9 @@
 
 /* {{{ proto FilterIterator::__construct(Iterator it) 
    Create an Iterator from another iterator */
-SPL_METHOD(dual_it, __construct)
+SPL_METHOD(FilterIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_Default);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
 } /* }}} */
 
 /* {{{ proto Iterator FilterIterator::getInnerIterator() 
@@ -1212,7 +1225,7 @@
    Create a RecursiveFilterIterator from a RecursiveIterator */
 SPL_METHOD(RecursiveFilterIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveIterator, DIT_Default);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, 
DIT_RecursiveFilterIterator);
 } /* }}} */
 
 /* {{{ proto boolean RecursiveFilterIterator::hasChildren()
@@ -1246,7 +1259,7 @@
    Create a ParentIterator from a RecursiveIterator */
 SPL_METHOD(ParentIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveIterator, DIT_Default);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
 } /* }}} */
 
 /* {{{ proto boolean ParentIterator::hasChildren()
@@ -1281,7 +1294,7 @@
    Create an RegExIterator from another iterator and a regular expression */
 SPL_METHOD(RegExIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_RegExIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RegExIterator, zend_ce_iterator, DIT_RegExIterator);
 } /* }}} */
 
 /* {{{ proto bool RegExIterator::accept()
@@ -1331,7 +1344,7 @@
    Create an RecursiveRegExIterator from another recursive iterator and a 
regular expression */
 SPL_METHOD(RecursiveRegExIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveIterator, DIT_RecursiveRegExIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveRegExIterator, spl_ce_RecursiveIterator, 
DIT_RecursiveRegExIterator);
 } /* }}} */
 #endif
 
@@ -1352,7 +1365,9 @@
        
        if (object->dit_type == DIT_AppendIterator) {
                
object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
-               zval_ptr_dtor(&object->u.append.zarrayit);
+               if (object->u.append.zarrayit) {
+                       zval_ptr_dtor(&object->u.append.zarrayit);
+               }
        }
 
        if (object->dit_type == DIT_CachingIterator || object->dit_type == 
DIT_RecursiveCachingIterator) {
@@ -1387,6 +1402,7 @@
        intern = emalloc(sizeof(spl_dual_it_object));
        memset(intern, 0, sizeof(spl_dual_it_object));
        intern->std.ce = class_type;
+       intern->dit_type = DIT_Unknown;
 
        ALLOC_HASHTABLE(intern->std.properties);
        zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
@@ -1404,7 +1420,7 @@
 ZEND_END_ARG_INFO();
 
 static zend_function_entry spl_funcs_FilterIterator[] = {
-       SPL_ME(dual_it,         __construct,      
arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
+       SPL_ME(FilterIterator,  __construct,      
arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
        SPL_ME(FilterIterator,  rewind,           NULL, ZEND_ACC_PUBLIC)
        SPL_ME(dual_it,         valid,            NULL, ZEND_ACC_PUBLIC)
        SPL_ME(dual_it,         key,              NULL, ZEND_ACC_PUBLIC)
@@ -1510,7 +1526,7 @@
    Construct a LimitIterator from an Iterator with a given starting offset and 
optionally a maximum count */
 SPL_METHOD(LimitIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_LimitIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
 } /* }}} */
 
 /* {{{ proto void LimitIterator::rewind() 
@@ -1693,7 +1709,7 @@
    Construct a CachingIterator from an Iterator */
 SPL_METHOD(CachingIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_CachingIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
 } /* }}} */
 
 /* {{{ proto void CachingIterator::rewind()
@@ -1963,7 +1979,7 @@
    Create an iterator from a RecursiveIterator */
 SPL_METHOD(RecursiveCachingIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, 
DIT_RecursiveCachingIterator);
 } /* }}} */
 
 /* {{{ proto bolean RecursiveCachingIterator::hasChildren()
@@ -2009,7 +2025,7 @@
    Create an iterator from anything that is traversable */
 SPL_METHOD(IteratorIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_traversable, DIT_IteratorIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
 } /* }}} */
 
 static
@@ -2032,7 +2048,7 @@
    Create an iterator from another iterator */
 SPL_METHOD(NoRewindIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_NoRewindIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
 } /* }}} */
 
 /* {{{ proto void NoRewindIterator::rewind()
@@ -2124,7 +2140,7 @@
    Create an iterator from another iterator */
 SPL_METHOD(InfiniteIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_InfiniteIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
 } /* }}} */
 
 /* {{{ proto InfiniteIterator::next()
@@ -2247,7 +2263,7 @@
    Create an AppendIterator */
 SPL_METHOD(AppendIterator, __construct)
 {
-       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
zend_ce_iterator, DIT_AppendIterator);
+       spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
 } /* }}} */
 
 /* {{{ proto void AppendIterator::append(Iterator it)
@@ -2258,6 +2274,8 @@
        zval *it;
 
        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() 
TSRMLS_CC);
+       
+       APPENDIT_CHECK_CTOR(intern);
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, 
zend_ce_iterator) == FAILURE) {
                return;
@@ -2319,6 +2337,7 @@
 
        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() 
TSRMLS_CC);
 
+       APPENDIT_CHECK_CTOR(intern);
        spl_array_iterator_key(intern->u.append.zarrayit, return_value 
TSRMLS_CC);
 } /* }}} */
 
@@ -2330,6 +2349,7 @@
 
        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() 
TSRMLS_CC);
 
+       APPENDIT_CHECK_CTOR(intern);
        RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
 } /* }}} */
 
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/spl_iterators.h?r1=1.29&r2=1.30&diff_format=u
Index: php-src/ext/spl/spl_iterators.h
diff -u php-src/ext/spl/spl_iterators.h:1.29 
php-src/ext/spl/spl_iterators.h:1.30
--- php-src/ext/spl/spl_iterators.h:1.29        Tue Feb 21 20:12:42 2006
+++ php-src/ext/spl/spl_iterators.h     Fri Mar  3 21:35:16 2006
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: spl_iterators.h,v 1.29 2006/02/21 20:12:42 dmitry Exp $ */
+/* $Id: spl_iterators.h,v 1.30 2006/03/03 21:35:16 helly Exp $ */
 
 #ifndef SPL_ITERATORS_H
 #define SPL_ITERATORS_H
@@ -59,6 +59,9 @@
 
 typedef enum {
        DIT_Default = 0,
+       DIT_FilterIterator = DIT_Default,
+       DIT_RecursiveFilterIterator = DIT_Default,
+       DIT_ParentIterator = DIT_Default,
        DIT_LimitIterator,
        DIT_CachingIterator,
        DIT_RecursiveCachingIterator,
@@ -70,6 +73,7 @@
        DIT_RegExIterator,
        DIT_RecursiveRegExIterator,
 #endif
+       DIT_Unknown = ~0
 } dual_it_type;
 
 enum {

http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/tests/iterator_030.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/iterator_030.phpt
+++ php-src/ext/spl/tests/iterator_030.phpt
--TEST--
SPL: EmptyIterator access
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php

$it = new EmptyIterator;

var_dump($it->valid());
$it->rewind();
var_dump($it->valid());
$it->next();
var_dump($it->valid());

try
{
        var_dump($it->key());
}
catch(BadMethodCallException $e)
{
        echo $e->getMessage() . "\n";
}

try
{
        var_dump($it->current());
}
catch(BadMethodCallException $e)
{
        echo $e->getMessage() . "\n";
}

var_dump($it->valid());

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
bool(false)
bool(false)
bool(false)
Accessing the key of an EmptyIterator
Accessing the value of an EmptyIterator
bool(false)
===DONE===

http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/tests/iterator_031.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/iterator_031.phpt
+++ php-src/ext/spl/tests/iterator_031.phpt
--TEST--
SPL: AppendIterator::append() rewinds when neccessary
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php

class MyArrayIterator extends ArrayIterator
{
        function rewind()
        {
                echo __METHOD__ . "\n";
                parent::rewind();
        }
}

$it = new MyArrayIterator(array(1,2));

foreach($it as $k=>$v)
{
        echo "$k=>$v\n";
}

class MyAppendIterator extends AppendIterator
{
        function __construct()
        {
                echo __METHOD__ . "\n";
        }

        function rewind()
        {
                echo __METHOD__ . "\n";
                parent::rewind();
        }

        function valid()
        {
                echo __METHOD__ . "\n";
                return parent::valid();
        }
        
        function append(Iterator $what)
        {
                echo __METHOD__ . "\n";
                parent::append($what);
        }
        
        function parent__construct()
        {
                parent::__construct();
        }
}

$ap = new MyAppendIterator;

try
{
        $ap->append($it);
}
catch(BadMethodCallException $e)
{
        echo $e->getMessage() . "\n";
}

$ap->parent__construct();

try
{
        $ap->parent__construct($it);
}
catch(BadMethodCallException $e)
{
        echo $e->getMessage() . "\n";
}

$ap->append($it);
$ap->append($it);
$ap->append($it);

foreach($ap as $k=>$v)
{
        echo "$k=>$v\n";
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
MyArrayIterator::rewind
0=>1
1=>2
MyAppendIterator::__construct
MyAppendIterator::append
Classes derived from AppendIterator must call AppendIterator::__construct()
AppendIterator::getIterator() must be called exactly once per instance
MyAppendIterator::append
MyArrayIterator::rewind
MyAppendIterator::append
MyAppendIterator::append
MyAppendIterator::rewind
MyArrayIterator::rewind
MyAppendIterator::valid
0=>1
MyAppendIterator::valid
1=>2
MyArrayIterator::rewind
MyAppendIterator::valid
0=>1
MyAppendIterator::valid
1=>2
MyArrayIterator::rewind
MyAppendIterator::valid
0=>1
MyAppendIterator::valid
1=>2
MyAppendIterator::valid
===DONE===

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to