From: Gustavo André dos Santos Lopes Date: Wed, 18 Jul 2012 19:42:36 +0000 (+0200) Subject: zend_parse_parameters: allow ! for non pointers X-Git-Tag: php-5.5.0alpha4~5^2~2^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=980dc7111bc1d1e759c5b6044f6e7d203915d81f;p=php zend_parse_parameters: allow ! for non pointers This commit allows getting information about whether a certain value was a NULL value by using the ! modifier together with the l/L, d and b. Example: long l; zend_bool is_null; zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l!", &l, &is_null) For the specifiers l/L, d and b, NULL values are reported as 0, 0., or false. But sometimes one wants to distinguish NULL from those other values -- for instance, to give NULL the same effect as the argument not having been passed. The usual way this problem is handled is by fetching the parameter with 'z' or 'Z', check if it is NULL and if not use convert_to_long_ex()/convert_to_double_ex(), etc. Unfortunately, this is not equivalent. convert_to_long_ex() does a cast, while zpp() is stricter. For instance, zpp will not accept 'foo' for a long argument, and it will emit a notice when encountering '5foo'. In fact, the only way to otherwise zpp semantics (without duplicating its logic) is to fetch the raw zval from the stack and check whether it's NULL (with zpp itself or its relatives) and then run zpp again. That is not an elegant solution. --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 98a33e5445..d7170eb2cc 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -306,16 +306,14 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con { const char *spec_walk = *spec; char c = *spec_walk++; - int return_null = 0; + int check_null = 0; /* scan through modifiers */ while (1) { if (*spec_walk == '/') { SEPARATE_ZVAL_IF_NOT_REF(arg); } else if (*spec_walk == '!') { - if (Z_TYPE_PP(arg) == IS_NULL) { - return_null = 1; - } + check_null = 1; } else { break; } @@ -327,6 +325,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'L': { long *p = va_arg(*va, long *); + + if (check_null) { + zend_bool *p = va_arg(*va, zend_bool *); + *p = (Z_TYPE_PP(arg) == IS_NULL); + } + switch (Z_TYPE_PP(arg)) { case IS_STRING: { @@ -380,6 +384,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'd': { double *p = va_arg(*va, double *); + + if (check_null) { + zend_bool *p = va_arg(*va, zend_bool *); + *p = (Z_TYPE_PP(arg) == IS_NULL); + } + switch (Z_TYPE_PP(arg)) { case IS_STRING: { @@ -418,7 +428,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con int *pl = va_arg(*va, int *); switch (Z_TYPE_PP(arg)) { case IS_NULL: - if (return_null) { + if (check_null) { *p = NULL; *pl = 0; break; @@ -462,6 +472,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'b': { zend_bool *p = va_arg(*va, zend_bool *); + + if (check_null) { + zend_bool *p = va_arg(*va, zend_bool *); + *p = (Z_TYPE_PP(arg) == IS_NULL); + } + switch (Z_TYPE_PP(arg)) { case IS_NULL: case IS_STRING: @@ -484,7 +500,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'r': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -499,7 +515,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'a': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -514,7 +530,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'h': { HashTable **p = va_arg(*va, HashTable **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -534,7 +550,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'o': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -551,7 +567,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con zval **p = va_arg(*va, zval **); zend_class_entry *ce = va_arg(*va, zend_class_entry *); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -573,7 +589,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con zend_class_entry **lookup, **pce = va_arg(*va, zend_class_entry **); zend_class_entry *ce_base = *pce; - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *pce = NULL; break; } @@ -607,7 +623,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *); char *is_callable_error = NULL; - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { fci->size = 0; fcc->initialized = 0; break; @@ -637,7 +653,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'z': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; } else { *p = *arg; @@ -648,7 +664,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'Z': { zval ***p = va_arg(*va, zval ***); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; } else { *p = arg;