Hi guys,

as it stands the ticket, the user has implemented an iterator which easily
accepts floats for seek and other iterator methods. Normal iterator can
only work with integers as all the storage for positions is long or int.
As result a statement like this

new LimitIterator(new ArrayIterator(array(42)), 10000000000000000000);

will just convert that big float to some integer, so the original iterator
wouldn't work properly.

This is of course not the case with iterators implemented internally in
SPL as they only work with long (ulong for instance with the
ArrayIterator). But any user space iterators might break this. Just like
in the ticket the iterator itself works as expected and gives

10000000000
10000000001
10000000002

Where passing it to the LimitIterator gives back

1410065408
1410065409
1410065410

Also please consider the fact that the documentation states both start and
offset params of the LimitIterator as int.

I'm on the way to revert this, but the issue stays. May be the patch
should be just extended to check if it's a numeric string and try to
convert it. The same for a float - check if it overflows the integer
range.

Or how would you solve this?

Regards

Anatoliy

Am Mi, 11.07.2012, 23:25 schrieb Nikita Popov:
> Hi Anatoliy!
>
> I'm not sure that this change is right. As it is now one could no
> longer pass in "123" (as a string) or 123.0 (as a float) as
> limit/offset. This goes against usual PHP semantics.
>
> Also I'm not exactly sure what the problem was in the first place.
>
> Nikita
>
> On Wed, Jul 11, 2012 at 10:25 PM, Anatoliy Belsky <a...@php.net> wrote:
>> Commit:    b383ddf1e5175abf1d000e887961fdcebae646a0
>> Author:    Anatoliy Belsky <a...@php.net>         Wed, 11 Jul 2012
>> 22:25:31 +0200
>> Parents:   bcf5853eaa8b8be793d4a1bd325eaea68cfe57bb
>> Branches:  PHP-5.3 PHP-5.4 master
>>
>> Link:
>> http://git.php.net/?p=php-src.git;a=commitdiff;h=b383ddf1e5175abf1d000e887961fdcebae646a0
>>
>> Log:
>> Fixed bug #62477 LimitIterator int overflow
>>
>> Bugs:
>> https://bugs.php.net/62477
>>
>> Changed paths:
>>   M  ext/spl/spl_iterators.c
>>   M  ext/spl/spl_iterators.h
>>   A  ext/spl/tests/bug62477_1.phpt
>>   A  ext/spl/tests/bug62477_2.phpt
>>
>>
>> Diff:
>> diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
>> index eecd483..1cbb2e4 100755
>> --- a/ext/spl/spl_iterators.c
>> +++ b/ext/spl/spl_iterators.c
>> @@ -1380,12 +1380,31 @@ static spl_dual_it_object*
>> spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
>>         intern->dit_type = dit_type;
>>         switch (dit_type) {
>>                 case DIT_LimitIterator: {
>> +                       zval *tmp_offset, *tmp_count;
>>                         intern->u.limit.offset = 0; /* start at
>> beginning */
>>                         intern->u.limit.count = -1; /* get all */
>> -                       if (zend_parse_parameters(ZEND_NUM_ARGS()
>> TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset,
>> &intern->u.limit.count) == FAILURE) {
>> +                       if (zend_parse_parameters(ZEND_NUM_ARGS()
>> TSRMLS_CC, "O|zz", &zobject, ce_inner, &tmp_offset, &tmp_count) ==
>> FAILURE) {
>>                                 zend_restore_error_handling(&error_handling
>> TSRMLS_CC);
>>                                 return NULL;
>>                         }
>> +                       if (tmp_offset && Z_TYPE_P(tmp_offset) !=
>> IS_NULL) {
>> +                               if (Z_TYPE_P(tmp_offset) != IS_LONG) {
>> +
>> zend_throw_exception(spl_ce_OutOfRangeException, "offset param must be
>> of type int", 0 TSRMLS_CC);
>> +
>> zend_restore_error_handling(&error_handling TSRMLS_CC);
>> +                                       return NULL;
>> +                               } else {
>> +                                       intern->u.limit.offset =
>> Z_LVAL_P(tmp_offset);
>> +                               }
>> +                       }
>> +                       if (tmp_count && Z_TYPE_P(tmp_count) != IS_NULL)
>> {
>> +                               if (Z_TYPE_P(tmp_count) != IS_LONG) {
>> +
>> zend_throw_exception(spl_ce_OutOfRangeException, "count param must be of
>> type int", 0 TSRMLS_CC);
>> +
>> zend_restore_error_handling(&error_handling TSRMLS_CC);
>> +                                       return NULL;
>> +                               } else {
>> +                                       intern->u.limit.count =
>> Z_LVAL_P(tmp_count);
>> +                               }
>> +                       }
>>                         if (intern->u.limit.offset < 0) {
>>                                 
>> zend_throw_exception(spl_ce_OutOfRangeException,
>> "Parameter offset must be >= 0", 0
>> TSRMLS_CC);
>>                                 zend_restore_error_handling(&error_handling
>> TSRMLS_CC);
>> diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h
>> index 525a25c..9494b26 100755
>> --- a/ext/spl/spl_iterators.h
>> +++ b/ext/spl/spl_iterators.h
>> @@ -128,7 +128,7 @@ typedef struct _spl_dual_it_object {
>>                 uint                 str_key_len;
>>                 ulong                int_key;
>>                 int                  key_type; /* HASH_KEY_IS_STRING or
>> HASH_KEY_IS_LONG */
>> -               int                  pos;
>> +               long                  pos;
>>         } current;
>>         dual_it_type             dit_type;
>>         union {
>> diff --git a/ext/spl/tests/bug62477_1.phpt
>> b/ext/spl/tests/bug62477_1.phpt
>> new file mode 100644
>> index 0000000..1b768a7
>> --- /dev/null
>> +++ b/ext/spl/tests/bug62477_1.phpt
>> @@ -0,0 +1,12 @@
>> +--TEST--
>> +Bug #62477 LimitIterator int overflow when float is passed (1)
>> +--FILE--
>> +<?php
>> +
>> +$it = new LimitIterator(new ArrayIterator(array(42)),
>> 10000000000000000000);
>> +--EXPECTF--
>> +Fatal error: Uncaught exception 'OutOfRangeException' with message
>> 'offset param must be of type int' in %sbug62477_1.php:%d
>> +Stack trace:
>> +#0 %sbug62477_1.php(%d):
>> LimitIterator->__construct(Object(ArrayIterator), %f)
>> +#1 {main}
>> +  thrown in %sbug62477_1.php on line %d
>> diff --git a/ext/spl/tests/bug62477_2.phpt
>> b/ext/spl/tests/bug62477_2.phpt
>> new file mode 100644
>> index 0000000..aa3468a
>> --- /dev/null
>> +++ b/ext/spl/tests/bug62477_2.phpt
>> @@ -0,0 +1,12 @@
>> +--TEST--
>> +Bug #62477 LimitIterator int overflow when float is passed (2)
>> +--FILE--
>> +<?php
>> +
>> +$it = new LimitIterator(new ArrayIterator(array(42)), 0,
>> 10000000000000000000);
>> +--EXPECTF--
>> +Fatal error: Uncaught exception 'OutOfRangeException' with message
>> 'count param must be of type int' in %sbug62477_2.php:%d
>> +Stack trace:
>> +#0 %sbug62477_2.php(%d):
>> LimitIterator->__construct(Object(ArrayIterator), 0, %f)
>> +#1 {main}
>> +  thrown in %sbug62477_2.php on line %d
>>
>>
>> --
>> PHP CVS Mailing List (http://www.php.net/)
>> To unsubscribe, visit: http://www.php.net/unsub.php
>>
>


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

Reply via email to