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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: sfox@php.net
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2025 The PHP Group
All rights reserved.
Last updated: Mon Apr 28 17:01:33 2025 UTC