Index: README.PARAMETER_PARSING_API
===================================================================
RCS file: /repository/php-src/README.PARAMETER_PARSING_API,v
retrieving revision 1.26
diff -u -r1.26 README.PARAMETER_PARSING_API
--- README.PARAMETER_PARSING_API	24 Nov 2008 19:18:34 -0000	1.26
+++ README.PARAMETER_PARSING_API	29 May 2009 19:22:00 -0000
@@ -48,6 +48,7 @@
  h  - array (returned as HashTable*)
  H  - array or HASH_OF(object) (returned as HashTable*)
  l  - long (long)
+ L  - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (long)
  o  - object of any type (zval*)
  O  - object of specific type given by class entry (zval*, zend_class_entry)
  r  - resource (zval*)
Index: win32/build/config.w32
===================================================================
RCS file: /repository/php-src/win32/build/config.w32,v
retrieving revision 1.103
diff -u -r1.103 config.w32
--- win32/build/config.w32	24 Apr 2009 15:19:10 -0000	1.103
+++ win32/build/config.w32	17 May 2009 18:16:00 -0000
@@ -355,6 +355,10 @@
 	zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c \
 	zend_float.c");
 
+if (VCVERS == 1200) {
+	AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1);
+}
+
 ADD_SOURCES("main", "main.c snprintf.c spprintf.c fopen_wrappers.c \
 	php_scandir.c php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \
 	strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c network.c \
Index: Zend/Zend.m4
===================================================================
RCS file: /repository/ZendEngine2/Zend.m4,v
retrieving revision 1.69
diff -u -r1.69 Zend.m4
--- Zend/Zend.m4	19 May 2009 11:40:05 -0000	1.69
+++ Zend/Zend.m4	26 May 2009 18:20:20 -0000
@@ -117,6 +117,38 @@
 ZEND_FP_EXCEPT
 
 ZEND_CHECK_FLOAT_PRECISION
+
+dnl test whether double cast to long preserves least significant bits
+AC_MSG_CHECKING(whether double cast to long preserves least significant bits)
+
+AC_TRY_RUN([
+#include <limits.h>
+
+int main()
+{
+	if (sizeof(long) == 4) {
+		double d = (double) LONG_MIN * LONG_MIN + 2e9;
+
+		if ((long) d == 2e9 && (long) -d == -2e9) {
+			exit(0);
+		}
+	} else if (sizeof(long) == 8) {
+		double correct = 18e18 - ((double) LONG_MIN * -2); /* Subtract ULONG_MAX + 1 */
+
+		if ((long) 18e18 == correct) { /* On 64-bit, only check between LONG_MAX and ULONG_MAX */
+			exit(0);
+		}
+	}
+	exit(1);
+}
+], [
+  AC_DEFINE([ZEND_DVAL_TO_LVAL_CAST_OK], 1, [Define if double cast to long preserves least significant bits])
+  AC_MSG_RESULT(yes)
+], [
+  AC_MSG_RESULT(no)
+], [
+  AC_MSG_RESULT(no)
+])
 	
 ])
 
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.502
diff -u -r1.502 zend_API.c
--- Zend/zend_API.c	25 May 2009 14:32:13 -0000	1.502
+++ Zend/zend_API.c	26 May 2009 18:20:21 -0000
@@ -343,6 +343,7 @@
 
 	switch (c) {
 		case 'l':
+		case 'L':
 			{
 				long *p = va_arg(*va, long *);
 				switch (Z_TYPE_PP(arg)) {
@@ -354,7 +355,17 @@
 							if ((type = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), p, &d, -1)) == 0) {
 								return "long";
 							} else if (type == IS_DOUBLE) {
-								*p = (long) d;
+								if (c == 'L') {
+									if (d > LONG_MAX) {
+										*p = LONG_MAX;
+										break;
+									} else if (d < LONG_MIN) {
+										*p = LONG_MIN;
+										break;
+									}
+								}
+
+								*p = zend_dval_to_lval(d);
 							}
 						}
 						break;
@@ -367,14 +378,33 @@
 							if ((type = is_numeric_unicode(Z_USTRVAL_PP(arg), Z_USTRLEN_PP(arg), p, &d, -1)) == 0) {
 								return "long";
 							} else if (type == IS_DOUBLE) {
-								*p = (long) d;
+								if (c == 'L') {
+									if (d > LONG_MAX) {
+										*p = LONG_MAX;
+										break;
+									} else if (d < LONG_MIN) {
+										*p = LONG_MIN;
+										break;
+									}
+								}
+
+								*p = zend_dval_to_lval(d);
 							}
 						}
 						break;
 
+					case IS_DOUBLE:
+						if (c == 'L') {
+							if (Z_DVAL_PP(arg) > LONG_MAX) {
+								*p = LONG_MAX;
+								break;
+							} else if (Z_DVAL_PP(arg) < LONG_MIN) {
+								*p = LONG_MIN;
+								break;
+							}
+						}
 					case IS_NULL:
 					case IS_LONG:
-					case IS_DOUBLE:
 					case IS_BOOL:
 						convert_to_long_ex(arg);
 						*p = Z_LVAL_PP(arg);
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.859
diff -u -r1.859 zend_compile.c
--- Zend/zend_compile.c	27 May 2009 11:58:44 -0000	1.859
+++ Zend/zend_compile.c	29 May 2009 02:30:22 -0000
@@ -4209,7 +4209,6 @@
 	ALLOC_ZVAL(element);
 	*element = expr->u.constant;
 	if (offset) {
-		long l;
 		zend_uchar utype = Z_TYPE(offset->u.constant);
 
 		switch (Z_TYPE(offset->u.constant) & IS_CONSTANT_TYPE_MASK) {
@@ -4237,8 +4236,7 @@
 				zend_hash_index_update(Z_ARRVAL(result->u.constant), Z_LVAL(offset->u.constant), &element, sizeof(zval *), NULL);
 				break;
 			case IS_DOUBLE:
-				DVAL_TO_LVAL(Z_DVAL(offset->u.constant), l);
-				zend_hash_index_update(Z_ARRVAL(result->u.constant), l, &element, sizeof(zval *), NULL);
+				zend_hash_index_update(Z_ARRVAL(result->u.constant), zend_dval_to_lval(Z_DVAL(offset->u.constant)), &element, sizeof(zval *), NULL);
 				break;
 			case IS_CONSTANT_ARRAY:
 				zend_error(E_ERROR, "Illegal offset type");
Index: Zend/zend_execute.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute.c,v
retrieving revision 1.813
diff -u -r1.813 zend_execute.c
--- Zend/zend_execute.c	21 Apr 2009 09:40:33 -0000	1.813
+++ Zend/zend_execute.c	17 May 2009 17:58:21 -0000
@@ -925,10 +925,9 @@
 				efree(offset_key.v);
 			}
 			break;
-		case IS_DOUBLE: {
-			DVAL_TO_LVAL(Z_DVAL_P(dim), index);
+		case IS_DOUBLE:
+			index = zend_dval_to_lval(Z_DVAL_P(dim));
 			goto num_index;
-		}
 		case IS_RESOURCE:
 			zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(dim), Z_LVAL_P(dim));
 			/* Fall Through */
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.478
diff -u -r1.478 zend_execute_API.c
--- Zend/zend_execute_API.c	25 May 2009 14:32:13 -0000	1.478
+++ Zend/zend_execute_API.c	26 May 2009 18:20:22 -0000
@@ -698,7 +698,7 @@
 					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL_ZSTR, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL);
 					break;
 				case IS_DOUBLE:
-					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL_ZSTR, 0, (long)Z_DVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL);
+					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL_ZSTR, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL);
 					break;
 				case IS_NULL:
 					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, EMPTY_ZSTR, 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL);
Index: Zend/zend_operators.c
===================================================================
RCS file: /repository/ZendEngine2/zend_operators.c,v
retrieving revision 1.308
diff -u -r1.308 zend_operators.c
--- Zend/zend_operators.c	11 May 2009 08:31:03 -0000	1.308
+++ Zend/zend_operators.c	17 May 2009 18:04:40 -0000
@@ -274,7 +274,7 @@
 				Z_LVAL(holder) = 0;									\
 				break;												\
 			case IS_DOUBLE:											\
-				DVAL_TO_LVAL(Z_DVAL_P(op), Z_LVAL(holder));			\
+				Z_LVAL(holder) = zend_dval_to_lval(Z_DVAL_P(op));	\
 				break;												\
 			case IS_STRING:											\
 				Z_LVAL(holder) = strtol(Z_STRVAL_P(op), NULL, 10);	\
@@ -409,7 +409,7 @@
 		case IS_LONG:
 			break;
 		case IS_DOUBLE:
-			DVAL_TO_LVAL(Z_DVAL_P(op), Z_LVAL_P(op));
+			Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
 			break;
 		case IS_STRING:
 			{
@@ -1467,7 +1467,7 @@
 		ZVAL_LONG(result, ~Z_LVAL_P(op1));
 		return SUCCESS;
 	} else if (Z_TYPE_P(op1) == IS_DOUBLE) {
-		ZVAL_LONG(result, ~(long) Z_DVAL_P(op1));
+		ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
 		return SUCCESS;
 	} else if (Z_TYPE_P(op1) == IS_STRING) {
 		int i;
Index: Zend/zend_operators.h
===================================================================
RCS file: /repository/ZendEngine2/zend_operators.h,v
retrieving revision 1.140
diff -u -r1.140 zend_operators.h
--- Zend/zend_operators.h	25 May 2009 14:32:13 -0000	1.140
+++ Zend/zend_operators.h	26 May 2009 18:20:22 -0000
@@ -66,39 +66,25 @@
 ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr);
 END_EXTERN_C()
 
-/* {{{ DVAL_TO_LVAL */
-#define MAX_UNSIGNED_INT ((double) LONG_MAX * 2) + 1
-#ifdef _WIN64
-# define DVAL_TO_LVAL(d, l) \
-	if ((d) > LONG_MAX) { \
-		(l) = (long)(unsigned long)(__int64) (d); \
-	} else { \
-		(l) = (long) (d); \
-	}
-#elif !defined(_WIN64) && __WORDSIZE == 64
-# define DVAL_TO_LVAL(d, l) \
-	if ((d) >= LONG_MAX) { \
-		(l) = LONG_MAX; \
-	} else if ((d) <= LONG_MIN) { \
-		(l) = LONG_MIN; \
-	} else { \
-		(l) = (long) (d); \
+/* {{{ zend_dval_to_lval */
+#if ZEND_DVAL_TO_LVAL_CAST_OK
+# define zend_dval_to_lval(d) ((long) (d))
+#elif SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64)
+static zend_always_inline long zend_dval_to_lval(double d)
+{
+	if (d > LONG_MAX || d < LONG_MIN) {
+		return (long)(unsigned long)(zend_long64) d;
 	}
+	return (long) d;
+}
 #else
-# define DVAL_TO_LVAL(d, l) \
-	if ((d) > LONG_MAX) { \
-		if ((d) > MAX_UNSIGNED_INT) { \
-			(l) = LONG_MAX; \
-		} else { \
-			(l) = (unsigned long) (d); \
-		} \
-	} else { \
-		if((d) < LONG_MIN) { \
-			(l) = LONG_MIN; \
-		} else { \
-			(l) = (long) (d); \
-		} \
+static zend_always_inline long zend_dval_to_lval(double d)
+{
+	if (d > LONG_MAX) {
+		return (long)(unsigned long) d;
 	}
+	return (long) d;
+}
 #endif
 /* }}} */
 
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.266
diff -u -r1.266 zend_vm_def.h
--- Zend/zend_vm_def.h	1 Jun 2009 15:07:27 -0000	1.266
+++ Zend/zend_vm_def.h	3 Jun 2009 15:30:00 -0000
@@ -3169,11 +3169,9 @@
 		}
 	}
 	if (offset) {
-	  	long l;
 		switch (Z_TYPE_P(offset)) {
 			case IS_DOUBLE:
-			  	DVAL_TO_LVAL(Z_DVAL_P(offset), l);
-				zend_hash_index_update(Z_ARRVAL_P(array_ptr), l, &expr_ptr, sizeof(zval *), NULL);
+				zend_hash_index_update(Z_ARRVAL_P(array_ptr), zend_dval_to_lval(Z_DVAL_P(offset)), &expr_ptr, sizeof(zval *), NULL);
 				break;
 			case IS_LONG:
 			case IS_BOOL:
@@ -3537,7 +3535,6 @@
 	zend_free_op free_op1, free_op2;
 	zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
 	zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
-	long index;
 
 	if (OP1_TYPE != IS_VAR || container) {
 		if (OP1_TYPE == IS_CV && container != &EG(uninitialized_zval_ptr)) {
@@ -3549,14 +3546,12 @@
 
 				switch (Z_TYPE_P(offset)) {
 					case IS_DOUBLE:
-						index = (long) Z_DVAL_P(offset);
-						zend_hash_index_del(ht, index);
+						zend_hash_index_del(ht, zend_dval_to_lval(Z_DVAL_P(offset)));
 						break;
 					case IS_RESOURCE:
 					case IS_BOOL:
 					case IS_LONG:
-						index = Z_LVAL_P(offset);
-						zend_hash_index_del(ht, index);
+						zend_hash_index_del(ht, Z_LVAL_P(offset));
 						break;
 					case IS_STRING:
 					case IS_UNICODE: {
@@ -4071,7 +4066,6 @@
 	zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_IS);
 	zval **value = NULL;
 	int result = 0;
-	long index;
 
 	if (OP1_TYPE != IS_VAR || container) {
 		zend_free_op free_op2;
@@ -4085,16 +4079,14 @@
 
 			switch (Z_TYPE_P(offset)) {
 				case IS_DOUBLE:
-					index = (long) Z_DVAL_P(offset);
-					if (zend_hash_index_find(ht, index, (void **) &value) == SUCCESS) {
+					if (zend_hash_index_find(ht, zend_dval_to_lval(Z_DVAL_P(offset)), (void **) &value) == SUCCESS) {
 						isset = 1;
 					}
 					break;
 				case IS_RESOURCE:
 				case IS_BOOL:
 				case IS_LONG:
-					index = Z_LVAL_P(offset);
-					if (zend_hash_index_find(ht, index, (void **) &value) == SUCCESS) {
+					if (zend_hash_index_find(ht, Z_LVAL_P(offset), (void **) &value) == SUCCESS) {
 						isset = 1;
 					}
 					break;
