From: Ilia Alshanetsky Date: Tue, 5 Feb 2008 16:01:21 +0000 (+0000) Subject: MFB: Fixed bug #44046 (crash inside array_slice() function with an invalid X-Git-Tag: php-5.2.6RC1~98 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5b0fbbefe1d0ad045ce17b8ec3bba85fa92b572d;p=php MFB: Fixed bug #44046 (crash inside array_slice() function with an invalid by-ref offset). --- diff --git a/NEWS b/NEWS index 5970df8cd5..72b2e14d8b 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,8 @@ PHP NEWS which to group by data is specified. (Ilia) - Upgraded PCRE to version 7.6 (Nuno) +- Fixed bug #44046 (crash inside array_slice() function with an invalid + by-ref offset). (Ilia) - Fixed bug #44028 (crash inside stream_socket_enable_crypto() when enabling encryption without crypto type). (Ilia) - Fixed bug #43954 (Memory leak when sending the same HTTP status code diff --git a/ext/standard/array.c b/ext/standard/array.c index 99124120ce..0208acfa99 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2201,103 +2201,79 @@ PHP_FUNCTION(array_splice) Returns elements specified by offset and length */ PHP_FUNCTION(array_slice) { - zval **input, /* Input array */ - **offset, /* Offset to get elements from */ - **length, /* How many elements to get */ - **entry, /* An array entry */ - **z_preserve_keys; /* Whether to preserve keys while copying to the new array or not */ - int offset_val, /* Value of the offset argument */ - length_val, /* Value of the length argument */ - num_in, /* Number of elements in the input array */ - pos, /* Current position in the array */ - argc; /* Number of function arguments */ - + zval *input, /* Input array */ + **entry; /* An array entry */ + long offset, /* Offset to get elements from */ + length = NULL; /* How many elements to get */ + zend_bool preserve_keys = 0; /* Whether to preserve keys while copying to the new array or not */ + int num_in, /* Number of elements in the input array */ + pos; /* Current position in the array */ char *string_key; uint string_key_len; ulong num_key; HashPosition hpos; - zend_bool preserve_keys = 0; - /* Get the arguments and do error-checking */ - argc = ZEND_NUM_ARGS(); - if (argc < 2 || argc > 4 || zend_get_parameters_ex(argc, &input, &offset, &length, &z_preserve_keys)) { - WRONG_PARAM_COUNT; - } - - if (Z_TYPE_PP(input) != IS_ARRAY) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array"); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lb", &input, &offset, &length, &preserve_keys) == FAILURE) { return; } - - /* Make sure offset and length are integers and assume - we want all entries from offset to the end if length - is not passed */ - convert_to_long_ex(offset); - offset_val = Z_LVAL_PP(offset); - if (argc >= 3 && Z_TYPE_PP(length) != IS_NULL) { - convert_to_long_ex(length); - length_val = Z_LVAL_PP(length); - } else { - length_val = zend_hash_num_elements(Z_ARRVAL_PP(input)); - } - if (ZEND_NUM_ARGS() > 3) { - convert_to_boolean_ex(z_preserve_keys); - preserve_keys = Z_BVAL_PP(z_preserve_keys); + /* Get number of entries in the input hash */ + num_in = zend_hash_num_elements(Z_ARRVAL_P(input)); + + /* We want all entries from offset to the end if length is not passed or is null */ + if (length == NULL) { + length = num_in; } - + /* Initialize returned array */ array_init(return_value); - - /* Get number of entries in the input hash */ - num_in = zend_hash_num_elements(Z_ARRVAL_PP(input)); - + /* Clamp the offset.. */ - if (offset_val > num_in) + if (offset > num_in) { return; - else if (offset_val < 0 && (offset_val = (num_in + offset_val)) < 0) - offset_val = 0; - + } else if (offset < 0 && (offset = (num_in + offset)) < 0) { + offset = 0; + } + /* ..and the length */ - if (length_val < 0) { - length_val = num_in - offset_val + length_val; - } else if (((unsigned)offset_val + (unsigned)length_val) > (unsigned)num_in) { - length_val = num_in - offset_val; + if (length < 0) { + length = num_in - offset + length; + } else if (((unsigned) offset + (unsigned) length) > (unsigned) num_in) { + length = num_in - offset; } - - if (length_val == 0) + + if (length == 0) { return; - + } + /* Start at the beginning and go until we hit offset */ pos = 0; - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &hpos); - while (pos < offset_val && zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &hpos) == SUCCESS) { + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &hpos); + while (pos < offset && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) { pos++; - zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &hpos); + zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos); } - + /* Copy elements from input array to the one that's returned */ - while (pos < offset_val+length_val && zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &hpos) == SUCCESS) { - - (*entry)->refcount++; + while (pos < offset + length && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) { - switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(input), &string_key, &string_key_len, &num_key, 0, &hpos)) { + zval_add_ref(entry); + + switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &hpos)) { case HASH_KEY_IS_STRING: - zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, - entry, sizeof(zval *), NULL); + zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, entry, sizeof(zval *), NULL); break; - + case HASH_KEY_IS_LONG: - if (preserve_keys) - zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, - entry, sizeof(zval *), NULL); - else - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), - entry, sizeof(zval *), NULL); + if (preserve_keys) { + zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(zval *), NULL); + } else { + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL); + } break; } pos++; - zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &hpos); + zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos); } } /* }}} */