summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2016-05-06 18:38:26 +0800
committerXinchen Hui <laruence@gmail.com>2016-05-06 18:38:26 +0800
commit459a7cc209da130256d66c1f896199540f4dadbc (patch)
treef13908f7c8f108e31e064a0b05f04bdbda132f8d
parent627b5aae3f5f3986f5d57c86d567f0bf7d376cca (diff)
downloadphp-git-459a7cc209da130256d66c1f896199540f4dadbc.tar.gz
Fixed bug #72170 (JsonSerializable may inc apply count without dec it)
I don't want use zend_try here, but seems I have no choice :<
-rw-r--r--NEWS2
-rw-r--r--ext/json/json_encoder.c83
-rw-r--r--ext/json/tests/bug72170.phpt32
3 files changed, 79 insertions, 38 deletions
diff --git a/NEWS b/NEWS
index fb88681b07..3878228836 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ PHP NEWS
. Fixed bug #72157 (use-after-free caused by dba_open). (Shm, Laruence)
- JSON:
+ . Fixed bug #72170 (JsonSerializable may inc apply count without dec it).
+ (Laruence)
. Fixed bug #72069 (Behavior \JsonSerializable different from json_encode).
(Laruence)
diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c
index ae9e086fc0..58ea67a04a 100644
--- a/ext/json/json_encoder.c
+++ b/ext/json/json_encoder.c
@@ -157,26 +157,8 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{
ZEND_HASH_INC_APPLY_COUNT(tmp_ht);
}
- if (r == PHP_JSON_OUTPUT_ARRAY) {
- if (need_comma) {
- smart_str_appendc(buf, ',');
- } else {
- need_comma = 1;
- }
-
- 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' && Z_TYPE_P(val) == IS_OBJECT) {
- /* Skip protected and private members. */
- if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
- ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
- }
- continue;
- }
-
+ zend_try {
+ if (r == PHP_JSON_OUTPUT_ARRAY) {
if (need_comma) {
smart_str_appendc(buf, ',');
} else {
@@ -185,33 +167,58 @@ 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' && Z_TYPE_P(val) == IS_OBJECT) {
+ /* Skip protected and private members. */
+ if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
+ ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
+ }
+ continue;
+ }
- php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key), options & ~PHP_JSON_NUMERIC_CHECK);
- smart_str_appendc(buf, ':');
+ if (need_comma) {
+ smart_str_appendc(buf, ',');
+ } else {
+ need_comma = 1;
+ }
- php_json_pretty_print_char(buf, options, ' ');
+ php_json_pretty_print_char(buf, options, '\n');
+ php_json_pretty_print_indent(buf, options);
- php_json_encode(buf, data, options);
- } else {
- if (need_comma) {
- smart_str_appendc(buf, ',');
+ 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 {
- need_comma = 1;
- }
+ if (need_comma) {
+ smart_str_appendc(buf, ',');
+ } else {
+ need_comma = 1;
+ }
- php_json_pretty_print_char(buf, options, '\n');
- php_json_pretty_print_indent(buf, options);
+ php_json_pretty_print_char(buf, options, '\n');
+ php_json_pretty_print_indent(buf, options);
- smart_str_appendc(buf, '"');
- smart_str_append_long(buf, (zend_long) index);
- smart_str_appendc(buf, '"');
- smart_str_appendc(buf, ':');
+ 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, ' ');
+ php_json_pretty_print_char(buf, options, ' ');
- php_json_encode(buf, data, options);
+ php_json_encode(buf, data, options);
+ }
}
- }
+ } zend_catch {
+ if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
+ ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
+ }
+ zend_bailout();
+ } zend_end_try();
if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
diff --git a/ext/json/tests/bug72170.phpt b/ext/json/tests/bug72170.phpt
new file mode 100644
index 0000000000..a7c25c2061
--- /dev/null
+++ b/ext/json/tests/bug72170.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #72170 (JsonSerializable may inc apply count without dec it)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+class Dummy implements JsonSerializable{
+ public function jsonSerialize() {
+ global $flag;
+ if ($flag) {
+ exit;
+ } else {
+ return "okey";
+ }
+ }
+}
+
+$array = array();
+$array[] = new Dummy;
+
+register_shutdown_function(function() use($array) {
+ global $flag;
+ $flag = 0;
+ var_dump(json_encode(array($array)));
+});
+
+$flag = 1;
+json_encode(array($array));
+?>
+--EXPECT--
+string(10) "[["okey"]]"