From 90a0d58af81b03dfc8c1b0be4efa71cffc732aef Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sat, 26 Jul 2014 18:00:16 -0700 Subject: [PATCH] Fix SPL objects initialization checks --- ext/spl/spl_directory.c | 97 +++++++++++++++++++++++++++++++++--- ext/spl/spl_iterators.c | 98 +++++++++++++++++++++++++++++++------ ext/spl/tests/bug54281.phpt | 6 ++- 3 files changed, 178 insertions(+), 23 deletions(-) diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 4159d1ae34..495314abeb 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1617,7 +1617,7 @@ SPL_METHOD(GlobIterator, count) return; } - if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { + if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL)); } else { /* should not happen */ @@ -2098,7 +2098,7 @@ static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function zend_fcall_info fci; zend_fcall_info_cache fcic; zval z_fname; - zval * zresource_ptr = &intern->u.file.zresource, *retval; + zval * zresource_ptr = &intern->u.file.zresource, *retval = NULL; int result; int num_args = pass_num_args + (arg2 ? 2 : 1); @@ -2132,7 +2132,7 @@ static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function result = zend_call_function(&fci, &fcic TSRMLS_CC); - if (result == FAILURE) { + if (result == FAILURE || retval == NULL) { RETVAL_FALSE; } else { ZVAL_ZVAL(return_value, retval, 1, 1); @@ -2265,6 +2265,10 @@ static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern TSRMLS_DC) /* {{{ */ { + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } if (-1 == php_stream_rewind(intern->u.file.stream)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name); } else { @@ -2397,6 +2401,11 @@ SPL_METHOD(SplFileObject, eof) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + RETURN_BOOL(php_stream_eof(intern->u.file.stream)); } /* }}} */ @@ -2413,6 +2422,9 @@ SPL_METHOD(SplFileObject, valid) if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { RETURN_BOOL(intern->u.file.current_line || intern->u.file.current_zval); } else { + if(!intern->u.file.stream) { + RETURN_FALSE; + } RETVAL_BOOL(!php_stream_eof(intern->u.file.stream)); } } /* }}} */ @@ -2427,6 +2439,11 @@ SPL_METHOD(SplFileObject, fgets) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (spl_filesystem_file_read(intern, 0 TSRMLS_CC) == FAILURE) { RETURN_FALSE; } @@ -2443,6 +2460,11 @@ SPL_METHOD(SplFileObject, current) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (!intern->u.file.current_line && !intern->u.file.current_zval) { spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC); } @@ -2585,6 +2607,12 @@ SPL_METHOD(SplFileObject, fgetcsv) int d_len = 0, e_len = 0, esc_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) { + + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + switch(ZEND_NUM_ARGS()) { case 3: @@ -2726,6 +2754,11 @@ SPL_METHOD(SplFileObject, fflush) { spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + RETURN_BOOL(!php_stream_flush(intern->u.file.stream)); } /* }}} */ @@ -2734,7 +2767,14 @@ SPL_METHOD(SplFileObject, fflush) SPL_METHOD(SplFileObject, ftell) { spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - long ret = php_stream_tell(intern->u.file.stream); + long ret; + + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + + ret = php_stream_tell(intern->u.file.stream); if (ret == -1) { RETURN_FALSE; @@ -2754,6 +2794,11 @@ SPL_METHOD(SplFileObject, fseek) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + spl_filesystem_file_free_line(intern TSRMLS_CC); RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, whence)); } /* }}} */ @@ -2766,6 +2811,11 @@ SPL_METHOD(SplFileObject, fgetc) char buf[2]; int result; + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + spl_filesystem_file_free_line(intern TSRMLS_CC); result = php_stream_getc(intern->u.file.stream); @@ -2791,6 +2841,11 @@ SPL_METHOD(SplFileObject, fgetss) zval *arg2 = NULL; MAKE_STD_ZVAL(arg2); + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (intern->u.file.max_line_len > 0) { ZVAL_LONG(arg2, intern->u.file.max_line_len); } else { @@ -2811,6 +2866,11 @@ SPL_METHOD(SplFileObject, fpassthru) { spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + RETURN_LONG(php_stream_passthru(intern->u.file.stream)); } /* }}} */ @@ -2820,6 +2880,11 @@ SPL_METHOD(SplFileObject, fscanf) { spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + spl_filesystem_file_free_line(intern TSRMLS_CC); intern->u.file.current_line_num++; @@ -2840,6 +2905,11 @@ SPL_METHOD(SplFileObject, fwrite) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (ZEND_NUM_ARGS() > 1) { str_len = MAX(0, MIN(length, str_len)); } @@ -2859,6 +2929,11 @@ SPL_METHOD(SplFileObject, fread) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (length <= 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0"); RETURN_FALSE; @@ -2888,6 +2963,11 @@ SPL_METHOD(SplFileObject, ftruncate) return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (!php_stream_truncate_supported(intern->u.file.stream)) { zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't truncate file %s", intern->file_name); RETURN_FALSE; @@ -2902,15 +2982,20 @@ SPL_METHOD(SplFileObject, seek) { spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); long line_pos; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &line_pos) == FAILURE) { return; } + if(!intern->u.file.stream) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Object not initialized"); + return; + } + if (line_pos < 0) { zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't seek file %s to negative line %ld", intern->file_name, line_pos); RETURN_FALSE; } - + spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC); while(intern->u.file.current_line_num < line_pos) { diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index cade34efd4..3ca0bda3bd 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -139,6 +139,19 @@ static zend_object_handlers spl_handlers_dual_it; (var) = it; \ } while (0) +#define SPL_FETCH_SUB_ELEMENT(var, object, element) \ + do { \ + if(!(object)->iterators) { \ + 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) = (object)->iterators[(object)->level].element; \ + } while (0) + +#define SPL_FETCH_SUB_ITERATOR(var, object) SPL_FETCH_SUB_ELEMENT(var, object, iterator) + + static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC) { spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter; @@ -161,7 +174,10 @@ static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthi { zend_object_iterator *sub_iter; int level = object->level; - + + if(!object->iterators) { + return FAILURE; + } while (level >=0) { sub_iter = object->iterators[level].iterator; if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) { @@ -212,6 +228,8 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv zend_object_iterator *sub_iter; int has_children; + SPL_FETCH_SUB_ITERATOR(iterator, object); + while (!EG(exception)) { next_step: iterator = object->iterators[object->level].iterator; @@ -375,9 +393,7 @@ static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zt { zend_object_iterator *sub_iter; - if (!object->iterators) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_P(zthis)->name); - } + SPL_FETCH_SUB_ITERATOR(sub_iter, object); while (object->level) { sub_iter = object->iterators[object->level].iterator; @@ -597,7 +613,7 @@ SPL_METHOD(RecursiveIteratorIterator, rewind) SPL_METHOD(RecursiveIteratorIterator, valid) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -610,12 +626,14 @@ SPL_METHOD(RecursiveIteratorIterator, valid) SPL_METHOD(RecursiveIteratorIterator, key) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - zend_object_iterator *iterator = object->iterators[object->level].iterator; - + zend_object_iterator *iterator; + if (zend_parse_parameters_none() == FAILURE) { return; } + SPL_FETCH_SUB_ITERATOR(iterator, object); + if (iterator->funcs->get_current_key) { iterator->funcs->get_current_key(iterator, return_value TSRMLS_CC); } else { @@ -628,13 +646,15 @@ SPL_METHOD(RecursiveIteratorIterator, key) SPL_METHOD(RecursiveIteratorIterator, current) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - zend_object_iterator *iterator = object->iterators[object->level].iterator; + zend_object_iterator *iterator; zval **data; if (zend_parse_parameters_none() == FAILURE) { return; } + SPL_FETCH_SUB_ITERATOR(iterator, object); + iterator->funcs->get_current_data(iterator, &data TSRMLS_CC); if (data && *data) { RETURN_ZVAL(*data, 1, 0); @@ -673,6 +693,7 @@ SPL_METHOD(RecursiveIteratorIterator, getSubIterator) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); long level = object->level; + zval *zobject; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) { return; @@ -680,6 +701,13 @@ SPL_METHOD(RecursiveIteratorIterator, getSubIterator) if (level < 0 || level > object->level) { RETURN_NULL(); } + + if(!object->iterators) { + 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; + } + RETURN_ZVAL(object->iterators[level].zobject, 1, 0); } /* }}} */ @@ -688,13 +716,15 @@ SPL_METHOD(RecursiveIteratorIterator, getSubIterator) SPL_METHOD(RecursiveIteratorIterator, getInnerIterator) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - long level = object->level; + zval *zobject; if (zend_parse_parameters_none() == FAILURE) { return; } - - RETURN_ZVAL(object->iterators[level].zobject, 1, 0); + + SPL_FETCH_SUB_ELEMENT(zobject, object, zobject); + + RETURN_ZVAL(zobject, 1, 0); } /* }}} */ /* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration() @@ -722,13 +752,19 @@ SPL_METHOD(RecursiveIteratorIterator, endIteration) SPL_METHOD(RecursiveIteratorIterator, callHasChildren) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - zend_class_entry *ce = object->iterators[object->level].ce; + zend_class_entry *ce; zval *retval, *zobject; if (zend_parse_parameters_none() == FAILURE) { return; } + if (!object->iterators) { + RETURN_NULL(); + } + + SPL_FETCH_SUB_ELEMENT(ce, object, ce); + zobject = object->iterators[object->level].zobject; if (!zobject) { RETURN_FALSE; @@ -747,13 +783,15 @@ SPL_METHOD(RecursiveIteratorIterator, callHasChildren) SPL_METHOD(RecursiveIteratorIterator, callGetChildren) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - zend_class_entry *ce = object->iterators[object->level].ce; + zend_class_entry *ce; zval *retval, *zobject; if (zend_parse_parameters_none() == FAILURE) { return; } + SPL_FETCH_SUB_ELEMENT(ce, object, ce); + zobject = object->iterators[object->level].zobject; if (!zobject) { return; @@ -1072,6 +1110,13 @@ SPL_METHOD(RecursiveTreeIterator, getPrefix) if (zend_parse_parameters_none() == FAILURE) { return; } + + if(!object->iterators) { + 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; + } + spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC); } /* }}} */ @@ -1100,6 +1145,12 @@ SPL_METHOD(RecursiveTreeIterator, getEntry) if (zend_parse_parameters_none() == FAILURE) { return; } + + if(!object->iterators) { + 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; + } spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC); } /* }}} */ @@ -1113,6 +1164,12 @@ SPL_METHOD(RecursiveTreeIterator, getPostfix) if (zend_parse_parameters_none() == FAILURE) { return; } + + if(!object->iterators) { + 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; + } spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC); } /* }}} */ @@ -1130,10 +1187,17 @@ SPL_METHOD(RecursiveTreeIterator, current) return; } + if(!object->iterators) { + 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; + } + if (object->flags & RTIT_BYPASS_CURRENT) { - zend_object_iterator *iterator = object->iterators[object->level].iterator; + zend_object_iterator *iterator; zval **data; + SPL_FETCH_SUB_ITERATOR(iterator, object); iterator->funcs->get_current_data(iterator, &data TSRMLS_CC); if (data && *data) { RETURN_ZVAL(*data, 1, 0); @@ -1177,7 +1241,7 @@ SPL_METHOD(RecursiveTreeIterator, current) SPL_METHOD(RecursiveTreeIterator, key) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - zend_object_iterator *iterator = object->iterators[object->level].iterator; + zend_object_iterator *iterator; zval prefix, key, postfix, key_copy; char *str, *ptr; size_t str_len; @@ -1186,6 +1250,8 @@ SPL_METHOD(RecursiveTreeIterator, key) return; } + SPL_FETCH_SUB_ITERATOR(iterator, object); + if (iterator->funcs->get_current_key) { iterator->funcs->get_current_key(iterator, &key TSRMLS_CC); } else { @@ -1899,7 +1965,7 @@ SPL_METHOD(RecursiveCallbackFilterIterator, 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) { diff --git a/ext/spl/tests/bug54281.phpt b/ext/spl/tests/bug54281.phpt index d42d9e585d..71792eaa20 100644 --- a/ext/spl/tests/bug54281.phpt +++ b/ext/spl/tests/bug54281.phpt @@ -12,4 +12,8 @@ foreach($it as $k=>$v) { } ?> --EXPECTF-- -Fatal error: RecursiveIteratorIterator::rewind(): The RecursiveArrayIteratorIterator instance wasn't initialized properly in %s on line %d +Fatal error: Uncaught exception 'LogicException' with message 'The object is in an invalid state as the parent constructor was not called' in %s:%d +Stack trace: +#0 %s/bug54281.php(8): RecursiveIteratorIterator->rewind() +#1 {main} + thrown in %s/bug54281.php on line 8 -- 2.40.0