]> granicus.if.org Git - php/commitdiff
Add initial failure checking for json_encode
authorJakub Zelenka <bukka@php.net>
Wed, 24 Aug 2016 19:46:33 +0000 (20:46 +0100)
committerJakub Zelenka <bukka@php.net>
Mon, 29 Aug 2016 13:49:40 +0000 (14:49 +0100)
ext/json/json.c
ext/json/json_encoder.c
ext/json/php_json_encoder.h

index 2acfb5e79f9381ee07f7e2075b539fe03c6f3231..3bbe532d97523a7d4c17ba18618d3ab464091f50 100644 (file)
@@ -186,9 +186,7 @@ static PHP_MINFO_FUNCTION(json)
 
 PHP_JSON_API int php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
 {
-       php_json_encode_zval(buf, val, options);
-
-       return JSON_G(error_code) > 0 ? FAILURE : SUCCESS;
+       return php_json_encode_zval(buf, val, options);
 }
 /* }}} */
 
index 7cf76732350b9550a98e2c944a00c8badf2e7878..fd9669f9d6f52baf7a64df374db26e80df572fd9 100644 (file)
@@ -33,7 +33,7 @@
 
 static const char digits[] = "0123456789abcdef";
 
-static void php_json_escape_string(smart_str *buf, char *s, size_t len, int options);
+static int php_json_escape_string(smart_str *buf, char *s, size_t len, int options);
 
 static int php_json_determine_array_type(zval *val) /* {{{ */
 {
@@ -108,7 +108,7 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options)
 }
 /* }}} */
 
-static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ */
+static int php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ */
 {
        int i, r, need_comma = 0;
        HashTable *myht;
@@ -124,7 +124,7 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
        if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) {
                JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
                smart_str_appendl(buf, "null", 4);
-               return;
+               return FAILURE;
        }
 
        if (r == PHP_JSON_OUTPUT_ARRAY) {
@@ -159,7 +159,6 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
 
                                php_json_pretty_print_char(buf, options, '\n');
                                php_json_pretty_print_indent(buf, options);
-                               php_json_encode(buf, data, options);
                        } else if (r == PHP_JSON_OUTPUT_OBJECT) {
                                if (key) {
                                        if (ZSTR_VAL(key)[0] == '\0' && ZSTR_LEN(key) > 0 && Z_TYPE_P(val) == IS_OBJECT) {
@@ -180,11 +179,6 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
                                        php_json_pretty_print_indent(buf, options);
 
                                        php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key), options & ~PHP_JSON_NUMERIC_CHECK);
-                                       smart_str_appendc(buf, ':');
-
-                                       php_json_pretty_print_char(buf, options, ' ');
-
-                                       php_json_encode(buf, data, options);
                                } else {
                                        if (need_comma) {
                                                smart_str_appendc(buf, ',');
@@ -198,12 +192,14 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
                                        smart_str_appendc(buf, '"');
                                        smart_str_append_long(buf, (zend_long) index);
                                        smart_str_appendc(buf, '"');
-                                       smart_str_appendc(buf, ':');
+                               }
 
-                                       php_json_pretty_print_char(buf, options, ' ');
+                               smart_str_appendc(buf, ':');
+                               php_json_pretty_print_char(buf, options, ' ');
+                       }
 
-                                       php_json_encode(buf, data, options);
-                               }
+                       if (php_json_encode(buf, data, options) == FAILURE && (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
+                               return FAILURE;
                        }
 
                        if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
@@ -214,6 +210,9 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
 
        if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) {
                JSON_G(error_code) = PHP_JSON_ERROR_DEPTH;
+               if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                       return FAILURE;
+               }
        }
        --JSON_G(encoder_depth);
 
@@ -228,6 +227,8 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
        } else {
                smart_str_appendc(buf, '}');
        }
+
+       return SUCCESS;
 }
 /* }}} */
 
@@ -268,7 +269,7 @@ static int php_json_utf8_to_utf16(unsigned short *utf16, char utf8[], size_t len
 }
 /* }}} */
 
-static void php_json_escape_string(smart_str *buf, char *s, size_t len, int options) /* {{{ */
+static int php_json_escape_string(smart_str *buf, char *s, size_t len, int options) /* {{{ */
 {
        int status;
        unsigned int us;
@@ -276,7 +277,7 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
 
        if (len == 0) {
                smart_str_appendl(buf, "\"\"", 2);
-               return;
+               return SUCCESS;
        }
 
        if (options & PHP_JSON_NUMERIC_CHECK) {
@@ -287,10 +288,10 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
                if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
                        if (type == IS_LONG) {
                                smart_str_append_long(buf, p);
-                               return;
+                               return SUCCESS;
                        } else if (type == IS_DOUBLE && php_json_is_valid_double(d)) {
                                php_json_encode_double(buf, d, options);
-                               return;
+                               return SUCCESS;
                        }
                }
 
@@ -300,8 +301,10 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
                /* validate UTF-8 string first */
                if (php_json_utf8_to_utf16(NULL, s, len) < 0) {
                        JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
-                       smart_str_appendl(buf, "null", 4);
-                       return;
+                       if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                               smart_str_appendl(buf, "null", 4);
+                       }
+                       return FAILURE;
                }
        }
 
@@ -322,8 +325,10 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
                                        ZSTR_LEN(buf->s) = checkpoint;
                                }
                                JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
-                               smart_str_appendl(buf, "null", 4);
-                               return;
+                               if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                                       smart_str_appendl(buf, "null", 4);
+                               }
+                               return FAILURE;
                        }
                        /* Escape U+2028/U+2029 line terminators, UNLESS both
                           JSON_UNESCAPED_UNICODE and
@@ -442,10 +447,12 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
        } while (pos < len);
 
        smart_str_appendc(buf, '"');
+
+       return SUCCESS;
 }
 /* }}} */
 
-static void php_json_encode_serializable_object(smart_str *buf, zval *val, int options) /* {{{ */
+static int php_json_encode_serializable_object(smart_str *buf, zval *val, int options) /* {{{ */
 {
        zend_class_entry *ce = Z_OBJCE_P(val);
        zval retval, fname;
@@ -460,8 +467,10 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o
 
        if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) {
                JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
-               smart_str_appendl(buf, "null", 4);
-               return;
+               if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                       smart_str_appendl(buf, "null", 4);
+               }
+               return FAILURE;
        }
 
 
@@ -470,9 +479,12 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o
        origin_error_code = JSON_G(error_code);
        if (FAILURE == call_user_function_ex(EG(function_table), val, &fname, &retval, 0, NULL, 1, NULL) || Z_TYPE(retval) == IS_UNDEF) {
                zend_throw_exception_ex(NULL, 0, "Failed calling %s::jsonSerialize()", ZSTR_VAL(ce->name));
-               smart_str_appendl(buf, "null", sizeof("null") - 1);
                zval_ptr_dtor(&fname);
-               return;
+
+               if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                       smart_str_appendl(buf, "null", 4);
+               }
+               return FAILURE;
        }
 
        JSON_G(error_code) = origin_error_code;
@@ -480,8 +492,11 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o
                /* Error already raised */
                zval_ptr_dtor(&retval);
                zval_ptr_dtor(&fname);
-               smart_str_appendl(buf, "null", sizeof("null") - 1);
-               return;
+
+               if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                       smart_str_appendl(buf, "null", 4);
+               }
+               return FAILURE;
        }
 
        if ((Z_TYPE(retval) == IS_OBJECT) &&
@@ -495,10 +510,12 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o
 
        zval_ptr_dtor(&retval);
        zval_ptr_dtor(&fname);
+
+       return SUCCESS;
 }
 /* }}} */
 
-void php_json_encode_zval(smart_str *buf, zval *val, int options) /* {{{ */
+int php_json_encode_zval(smart_str *buf, zval *val, int options) /* {{{ */
 {
 again:
        switch (Z_TYPE_P(val))
@@ -528,18 +545,15 @@ again:
                        break;
 
                case IS_STRING:
-                       php_json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options);
-                       break;
+                       return php_json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options);
 
                case IS_OBJECT:
                        if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce)) {
-                               php_json_encode_serializable_object(buf, val, options);
-                               break;
+                               return php_json_encode_serializable_object(buf, val, options);
                        }
                        /* fallthrough -- Non-serializable object */
                case IS_ARRAY:
-                       php_json_encode_array(buf, val, options);
-                       break;
+                       return php_json_encode_array(buf, val, options);
 
                case IS_REFERENCE:
                        val = Z_REFVAL_P(val);
@@ -547,11 +561,13 @@ again:
 
                default:
                        JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE;
-                       smart_str_appendl(buf, "null", 4);
-                       break;
+                       if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
+                               smart_str_appendl(buf, "null", 4);
+                       }
+                       return FAILURE;
        }
 
-       return;
+       return SUCCESS;
 }
 /* }}} */
 
index b10f7a614adeddbb94d5d8471a49a3694b162392..0fec9174b534dff274fdd8f86406a846cac45b3e 100644 (file)
@@ -22,6 +22,6 @@
 #include "php.h"
 #include "zend_smart_str.h"
 
-void php_json_encode_zval(smart_str *buf, zval *val, int options);
+int php_json_encode_zval(smart_str *buf, zval *val, int options);
 
 #endif /* PHP_JSON_ENCODER_H */