php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #43541 array_slice() length parameter's messed up
Submitted: 2007-12-09 01:01 UTC Modified: 2007-12-11 09:47 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: sfox@php.net Assigned: jani (profile)
Status: Closed Package: Arrays related
PHP Version: 5.3CVS-2007-12-09 (CVS) OS: irrelevant
Private report: No CVE-ID: None
 [2007-12-09 01:01 UTC] sfox@php.net
Description:
------------
If the length argument fed to array_slice() isn't of PHP type integer, array_slice() fails silently.

This was broken during Jani's major backporting session from CVS HEAD on Nov 2nd (i.e. it looks like HEAD's broken this way too). In the 5_2 branch there's a less clean API but the Z_LVAL_P is explicitly converted to long.

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/array.c?r1=1.308.2.21.2.37.2.5&r2=1.308.2.21.2.37.2.6&pathrev=PHP_5_3

I've a trivial fix for it that involves making the zval length parameter  a long. It's impossible to tell from the test suite whether this breaks anything that wasn't broken before (looking at how it's used, I can't see how it could.) Patch should apply cleanly to HEAD also, apart from the length initialization (already exists in HEAD but not in 5_3).


Reproduce code:
---------------
Basic, but illustrates the problem:

<?php

$arr = array(1, 2, 3, 4, 5, 6);

var_dump(array_slice($arr, 0, (float)2));
var_dump(array_slice($arr, 0, (int)2));

?>


Expected result:
----------------
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}


Actual result:
--------------
array(0) {
}
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-12-09 01:03 UTC] sfox@php.net
Forgot to post patch. (Is there no way to upload files?)

Index: ext/standard/array.c
===================================================================
RCS file: /repository/php-src/ext/standard/array.c,v
retrieving revision 1.308.2.21.2.37.2.11
diff -u -r1.308.2.21.2.37.2.11 array.c
--- ext/standard/array.c	5 Dec 2007 19:55:31 -0000	1.308.2.21.2.37.2.11
+++ ext/standard/array.c	8 Dec 2007 23:10:28 -0000
@@ -2101,17 +2101,16 @@
 	zval	 *input,		/* Input array */
 			**entry;		/* An array entry */
 	long	 offset,		/* Offset to get elements from */
-			 length;		/* How many elements to get */
+			 length = 0;	/* 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 */
-	zval	*length_param;
 	char *string_key;
 	uint string_key_len;
 	ulong num_key;
 	HashPosition hpos;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|zb", &input, &offset, &length_param, &preserve_keys) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lb", &input, &offset, &length, &preserve_keys) == FAILURE) {
 		return;
 	}
 
@@ -2119,9 +2118,7 @@
 	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 (ZEND_NUM_ARGS() >= 3 && Z_TYPE_P(length_param) != IS_NULL) {
-		length = Z_LVAL_P(length_param);
-	} else {
+	if (!ZEND_NUM_ARGS() >= 3 || length == IS_NULL) {
 		length = num_in;
 	}
 [2007-12-09 23:35 UTC] sfox@php.net
Fixed tests and reduced patch. I still think the initial implementation was wrong, but fixing it breaks long-established behaviour :\

Patch and tests sent to internals@.

http://news.php.net/php.internals/33887
 [2007-12-09 23:40 UTC] sfox@php.net
It's just not my day.

Index: ext/standard/array.c
===================================================================
RCS file: /repository/php-src/ext/standard/array.c,v
retrieving revision 1.308.2.21.2.37.2.11
diff -u -r1.308.2.21.2.37.2.11 array.c
--- ext/standard/array.c	5 Dec 2007 19:55:31 -0000	1.308.2.21.2.37.2.11
+++ ext/standard/array.c	9 Dec 2007 23:07:13 -0000
@@ -2120,6 +2120,7 @@
 
 	/* We want all entries from offset to the end if length is not passed or is null */
 	if (ZEND_NUM_ARGS() >= 3 && Z_TYPE_P(length_param) != IS_NULL) {
+		convert_to_long_ex(&length_param);
 		length = Z_LVAL_P(length_param);
 	} else {
 		length = num_in;
 [2007-12-10 20:35 UTC] sfox@php.net
Adding this for the sake of completeness, just in case there's a decision taken to dump the zval.

Index: ext/standard/array.c
===================================================================
RCS file: /repository/php-src/ext/standard/array.c,v
retrieving revision 1.308.2.21.2.37.2.11
diff -u -r1.308.2.21.2.37.2.11 array.c
--- ext/standard/array.c	5 Dec 2007 19:55:31 -0000	1.308.2.21.2.37.2.11
+++ ext/standard/array.c	10 Dec 2007 20:31:35 -0000
@@ -2101,17 +2101,16 @@
 	zval	 *input,		/* Input array */
 			**entry;		/* An array entry */
 	long	 offset,		/* Offset to get elements from */
-			 length;		/* How many elements to get */
+			 length = 0;	/* 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 */
-	zval	*length_param;
 	char *string_key;
 	uint string_key_len;
 	ulong num_key;
 	HashPosition hpos;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|zb", &input, &offset, &length_param, &preserve_keys) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lb", &input, &offset, &length, &preserve_keys) == FAILURE) {
 		return;
 	}
 
@@ -2119,9 +2118,7 @@
 	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 (ZEND_NUM_ARGS() >= 3 && Z_TYPE_P(length_param) != IS_NULL) {
-		length = Z_LVAL_P(length_param);
-	} else {
+	if (length == 0) {
 		length = num_in;
 	}
 [2007-12-11 08:22 UTC] jani@php.net
Even as I did NOT break this, I'll apply the patch. :)
 [2007-12-11 09:47 UTC] jani@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Apr 24 10:01:31 2024 UTC