From 12697541ad407c8d3b1f942c0cd3edb918f3b98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gannaz?= Date: Tue, 20 Mar 2012 11:41:06 +0100 Subject: [PATCH 1/3] Enable a test (for bug #40531) which was skipped --- ext/mbstring/tests/mb_str_functions_opt-parameter.phpt | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/mbstring/tests/mb_str_functions_opt-parameter.phpt b/ext/mbstring/tests/mb_str_functions_opt-parameter.phpt index e4a235df308d7..5fb642f9b2ef3 100644 --- a/ext/mbstring/tests/mb_str_functions_opt-parameter.phpt +++ b/ext/mbstring/tests/mb_str_functions_opt-parameter.phpt @@ -28,5 +28,3 @@ baz baz foo ==DONE== ---XFAIL-- -mb functions fail to allow null instead of actual value From a61c0e9dcd9b253bfff86ecf7949f526017940f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gannaz?= Date: Tue, 20 Mar 2012 11:52:22 +0100 Subject: [PATCH 2/3] Allow type check for IS_LONG in zend_verify_arg_type() zend_verify_arg_type() only accepted to verify arg types as classes, arrays or objects. Now it accepts integers. This is necessary to check wether an argument is an integer or null, which can't be done at a higher level like zend_parse_parameters(...,"l"). --- Zend/zend_execute.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d72fc7369aff7..62c4fd4b9265a 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -628,6 +628,17 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva } } else if (cur_arg_info->type_hint) { switch(cur_arg_info->type_hint) { + case IS_LONG: + if (!arg) { + return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type long", "", "none", "" TSRMLS_CC); + } + + if (Z_TYPE_P(arg) != IS_LONG && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) + && (Z_TYPE_P(arg) != IS_STRING || is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), NULL, NULL, 0)) == 0) { + return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type long", "", zend_zval_type_name(arg), "" TSRMLS_CC); + } + break; + case IS_ARRAY: if (!arg) { return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC); From 027284f2d7ba11f4c7928139ac13b4a8bec9d7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gannaz?= Date: Tue, 20 Mar 2012 12:00:34 +0100 Subject: [PATCH 3/3] Fix bug #40531 mb_substr optional parameters To distinguish between null and 0 for an integer parameter, we have to use the "z!" type instead of "l" in zend_parse_parameters(). So the type checks are now done in the prototype with ZEND_ARG_TYPE_INFO(). The prototype is more strict than before. An non integer (or a string that isn't purely numeric) will lead to a fatal error, whereas there was previously a simple warning. --- ext/mbstring/mbstring.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 0d2b53a7ca929..2790f2a3faf4d 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -325,14 +325,14 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr, 0, 0, 2) ZEND_ARG_INFO(0, str) ZEND_ARG_INFO(0, start) - ZEND_ARG_INFO(0, length) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_ARG_INFO(0, encoding) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strcut, 0, 0, 2) ZEND_ARG_INFO(0, str) ZEND_ARG_INFO(0, start) - ZEND_ARG_INFO(0, length) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_ARG_INFO(0, encoding) ZEND_END_ARG_INFO() @@ -2714,10 +2714,11 @@ PHP_FUNCTION(mb_substr) size_t argc = ZEND_NUM_ARGS(); char *str, *encoding; long from, len; + zval *zlen = NULL; int mblen, str_len, encoding_len; mbfl_string string, result, *ret; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls", &str, &str_len, &from, &len, &encoding, &encoding_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|z!s", &str, &str_len, &from, &zlen, &encoding, &encoding_len) == FAILURE) { return; } @@ -2736,8 +2737,10 @@ PHP_FUNCTION(mb_substr) string.val = (unsigned char *)str; string.len = str_len; - if (argc < 3) { + if (argc < 3 || !zlen) { len = str_len; + } else { + len = Z_LVAL_P(zlen); } /* measures length */ @@ -2787,6 +2790,7 @@ PHP_FUNCTION(mb_strcut) size_t argc = ZEND_NUM_ARGS(); char *encoding; long from, len; + zval *zlen = NULL; int encoding_len; mbfl_string string, result, *ret; @@ -2794,7 +2798,7 @@ PHP_FUNCTION(mb_strcut) string.no_language = MBSTRG(language); string.no_encoding = MBSTRG(current_internal_encoding)->no_encoding; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls", (char **)&string.val, (int **)&string.len, &from, &len, &encoding, &encoding_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|z!s", (char **)&string.val, (int **)&string.len, &from, &zlen, &encoding, &encoding_len) == FAILURE) { return; } @@ -2806,8 +2810,10 @@ PHP_FUNCTION(mb_strcut) } } - if (argc < 3) { + if (argc < 3 || !zlen) { len = string.len; + } else { + len = Z_LVAL_P(zlen); } /* if "from" position is negative, count start position from the end