]> granicus.if.org Git - php/commitdiff
zend_parse_parameters: allow ! for non pointers
authorGustavo André dos Santos Lopes <cataphract@php.net>
Wed, 18 Jul 2012 19:42:36 +0000 (21:42 +0200)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Wed, 18 Jul 2012 21:30:03 +0000 (23:30 +0200)
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.

Zend/zend_API.c

index 98a33e544508f85ece7b9f4f4256c83010bdb4b0..d7170eb2cc72048c379b58151cd5d7793814e542 100644 (file)
@@ -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;