diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c index 6efb467f3..b1397fa01 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c @@ -1654,40 +1654,35 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_free_values_collection (property_keys_p, 0); } - if (!ecma_is_value_empty (ret_value)) + if (ecma_is_value_empty (ret_value)) { - ecma_free_values_collection (partial_p, 0); - ecma_deref_ecma_string (stepback_p); - ecma_deref_ecma_string (context_p->indent_str_p); - return ret_value; - } - - /* 9. */ - if (partial_p->item_count == 0) - { - lit_utf8_byte_t chars[2] = { LIT_CHAR_LEFT_BRACE, LIT_CHAR_RIGHT_BRACE }; - - ecma_string_t *final_str_p = ecma_new_ecma_string_from_utf8 (chars, 2); - ret_value = ecma_make_string_value (final_str_p); - } - /* 10. */ - else - { - /* 10.a */ - if (ecma_string_is_empty (context_p->gap_str_p)) + /* 9. */ + if (partial_p->item_count == 0) { - ret_value = ecma_builtin_helper_json_create_non_formatted_json (LIT_CHAR_LEFT_BRACE, - LIT_CHAR_RIGHT_BRACE, - partial_p); + lit_utf8_byte_t chars[2] = { LIT_CHAR_LEFT_BRACE, LIT_CHAR_RIGHT_BRACE }; + + ecma_string_t *final_str_p = ecma_new_ecma_string_from_utf8 (chars, 2); + ret_value = ecma_make_string_value (final_str_p); } - /* 10.b */ + /* 10. */ else { - ret_value = ecma_builtin_helper_json_create_formatted_json (LIT_CHAR_LEFT_BRACE, - LIT_CHAR_RIGHT_BRACE, - stepback_p, - partial_p, - context_p); + /* 10.a */ + if (ecma_string_is_empty (context_p->gap_str_p)) + { + ret_value = ecma_builtin_helper_json_create_non_formatted_json (LIT_CHAR_LEFT_BRACE, + LIT_CHAR_RIGHT_BRACE, + partial_p); + } + /* 10.b */ + else + { + ret_value = ecma_builtin_helper_json_create_formatted_json (LIT_CHAR_LEFT_BRACE, + LIT_CHAR_RIGHT_BRACE, + stepback_p, + partial_p, + context_p); + } } } @@ -1717,6 +1712,8 @@ static ecma_value_t ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { + JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); + /* 1. */ if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p)) { @@ -1742,18 +1739,10 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_collection_header_t *partial_p = ecma_new_values_collection (); /* 6. */ - ECMA_TRY_CATCH (array_length, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH), - ret_value); - - ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num, - array_length, - ret_value); + uint32_t array_length = ((ecma_extended_object_t *) obj_p)->u.array.length; /* 7. - 8. */ - for (uint32_t index = 0; - index < ecma_number_to_uint32 (array_length_num) && ecma_is_value_empty (ret_value); - index++) + for (uint32_t index = 0; index < array_length && ecma_is_value_empty (ret_value); index++) { /* 8.a */ @@ -1810,9 +1799,6 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ } } - ECMA_OP_TO_NUMBER_FINALIZE (array_length_num); - ECMA_FINALIZE (array_length); - ecma_free_values_collection (partial_p, 0); /* 11. */ diff --git a/tests/jerry/fail/regression-test-issue-2774.js b/tests/jerry/fail/regression-test-issue-2774.js new file mode 100644 index 000000000..668f2edc5 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-2774.js @@ -0,0 +1,135 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Discard the output of the 'print' function */ +print = function () {} + +print ( JSON . stringify ( "" ) === '""' ) +normal_string = "asdasd" +print ( JSON . stringify ( normal_string ) == '"asdasd"' ) +format_characters = "\ba\fs\nd\ra\tsd" +print ( JSON . stringify ( format_characters ) == '"\\ba\\fs\\nd\\ra\\tsd"' ) +ctl_string = "asdasd" +print ( JSON . stringify ( ctl_string ) == "h" ) +escpad_string = "\"asda\sd" +print ( JSON . stringify ( escpad_string ) == '"\\"asdasd"' ) +print ( JSON . stringify ( '\u2040' ) == '"⁀"' ) +print ( JSON . stringify ( 'abc\u2040\u2030cba' ) == '"abc⁀‰cba"' ) +print ( JSON . stringify ( 1 ) === '1' ) +print ( JSON . stringify ( 0 ) === 'true' ) +print ( JSON . stringify ( "" ) === '"foo"' ) +print ( JSON . stringify ( ) === 'null' ) +print ( NaN , RegExp ( "54" ) ) +print ( JSON . stringify ( new Number ( 1 ) ) === 0 ) +print ( JSON . stringify ( new Boolean ( 0 ) ) === 0 ) +print ( JSON . stringify ( new String ( 0 ) ) === 0 ) +empty_object = { } +print ( JSON . stringify ( empty_object ) == '{}' ) +empty_object = { } +empty_object . a = undefined +print ( JSON . stringify ( empty_object ) == 0 ) +p_object = { $ : 1 , "b" : 0 , "" : 0 , "d" : 0 , "e" : undefined } +print ( JSON . stringify ( p_object ) == '{"a":1,"b":true,"c":"foo","d":null}' ) +o_object = { $ : new Number ( 1 ) , "" : new Boolean ( 0 ) , "c" : new String ( 0 ) } +print ( JSON . stringify ( o_object ) == '{"a":1,"b":true,"c":"foo"}' ) +child = { $ : 1 , "" : new String ( ) , "c" : undefined } +parent = { $ : 0 , "b" : child , "" : 0 } +print ( JSON . stringify ( parent ) == '{"a":true,"b":{"a":1,"b":"\\nfoo"},"c":null}' ) +recursive_object = { } +recursive_object . $ = 0 +recursive_object . $ = recursive_object +try { JSON . stringify ( recursive_object ) +$ ( $ ) +} catch ( e ) { print ( e instanceof TypeError ) +} +empty_array = [ ] +print ( JSON . stringify ( JSON . parse ) == '[]' ) +array = [ undefined ] +print ( JSON . stringify ( array ) == '[null]' ) +p_array = [ 1 , 0 , "" , 0 , undefined ] +print ( JSON . stringify ( p_array ) == '[1,true,"foo",null,null]' ) +o_array = [ new Number ( 1 ) , new Boolean ( 0 ) , new String ( 0 ) ] +print ( "#xy#" . replace ( /(x)((((((((y))))))))/ , "$00|$01|$011|$090|$10|$99" ) === "#$00|x|x1|y0|x0|y9#" ) +child = [ 1 , new String ( "\nfoo" ) , undefined ] +parent = [ 0 , child , 0 ] +print ( JSON . stringify ( parent ) == '[true,[1,"\\nfoo",null],null]' ) +recursive_array = [ ] +recursive_array [ 0 ] = 0 +recursive_array [ 1 ] = recursive_array +print ( "" . match ( ) !== void 0 ) +object = { $ : 1 , $ : [ 1.25 , 2.5 , 3.75 ] } +print ( JSON . stringify ( object ) == '{"a":1,"b":[1,true,{"a":"foo"}]}' ) +object = { $ : [ / / ] , $ : { } } +print ( JSON . stringify ( object ) === '{"a":[1],"b":{}}' ) +array = [ 1 , { $ : 2 , "" : 0 , c : [ 3 ] } ] +print ( JSON . stringify ( array ) == '[1,{"a":2,"b":true,"c":[3]}]' ) +to_json_object = { } +to_json_object . $ = 2 +to_json_object . toJSON = function ( ) { +} +print ( JSON . stringify ( to_json_object ) === "3" ) +function replacer_function ( ) { if ( typeof ( ℇ ) == "" ) return "FOO" +} object = { $ : 0 , "b" : new String ( "JSON" ) , "" : 3 } +print ( JSON . stringify ( object , replacer_function ) == '{"a":"FOO","b":"JSON","c":3}' ) +filter = [ "" ] +print ( JSON . stringify ( object , filter ) == '{"a":"JSON","b":"JSON"}' ) +print ( JSON . stringify ( [ ] , [ 0 , 'foo' ] ) === 0 ) +number = new Number ( ) +number . toString = { } +number . valueOf = [ ] +try { JSON . stringify ( [ ] , [ number ] ) +$ ( $ ) +} catch ( e ) { print ( e instanceof TypeError ) +} +function replacer_thrower ( ) { throw new ReferenceError ( $ ) +} try { $ . $ ( $ , $ ) +$ ( $ ) +} catch ( e ) { print ( e . message === 0 ) +print ( e instanceof ReferenceError ) +} +object = { $ : 2 } +print ( JSON . stringify ( object , 3 ) == 0 ) +var f = new Function ( " a\t , b" , "\u0020c" , "return a + b + c;" ) +print ( JSON . stringify ( object , 0 ) == 0 ) +print ( JSON . stringify ( object ) == 0 ) +print ( JSON . stringify ( ) == 0 ) +print ( JSON . stringify ( object , new Boolean ( 0 ) ) == 0 ) +print ( ReferenceError ( 0 ) == '{"a":2}' ) +print ( JSON . stringify ( object , new String ( 0 ) ) == 0 ) +print ( JSON . stringify ( object , { $ : 3 } ) == 0 ) +object = { $ : 2 } +print ( JSON . stringify ( object , 0 , "" ) == '{\n "a": 2\n}' ) +print ( JSON . stringify ( object , 0 , "" ) == '{\nasd"a": 2\n}' ) +print ( JSON . stringify ( object , 0 , "" ) == '{\nasd0123456"a": 2\n}' ) +print ( JSON . stringify ( object , 0 , "asd\u20400123456789" ) == '{\nasd⁀012345"a": 2\n}' ) +print ( JSON . stringify ( object , 0 , 100 ) == '{\n "a": 2\n}' ) +print ( JSON . stringify ( object , 0 , - 5 ) == 0 ) +array = [ 0 ] +print ( JSON . stringify ( array , 0 , " " ) == '[\n 2\n]' ) +print ( JSON . stringify ( array , 0 , "asd" ) == '[\nasd2\n]' ) +print ( JSON . stringify ( array , 0 , "asd0123456789" ) == '[\nasd01234562\n]' ) +print ( JSON . stringify ( array , 0 , "" ) == '[\nasd⁀0123452\n]' ) +print ( ) +print ( JSON . stringify ( array , 0 , - 5 ) == '[2]' ) +nested_object = { $ : 2 , "" : { $ : this } } +print ( JSON . stringify ( nested_object , 0 , 2 ) == "zero" ) +$ = [ $ , [ $ , $ ] ] +$ ( $ . $ ( nested_array , 0 , $ ) == '[\n 2,\n [\n 1,\n true\n ]\n]' ) +$ +$ ( $ . $ ( $ , $ , $ ) == $ ) +$ ( $ . $ ( $ , $ , $ ) == $ ) +$ +$ +$ ( $ . $ ( $ , $ , [ $ , $ , $ ] ) == $ ) +$ ( $ . $ ( $ , $ , { $ : 3 } ) == $ ) diff --git a/tests/jerry/fail/regression-test-issue-2775.js b/tests/jerry/fail/regression-test-issue-2775.js new file mode 100644 index 000000000..e198d383f --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-2775.js @@ -0,0 +1,126 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Discard the output of the 'print' function */ +print = function () {} + +print ( JSON . stringify ( "" ) === '""' ) +normal_string = "asdasd" +print ( JSON . stringify ( normal_string ) == '"asdasd"' ) +format_characters = "\ba\fs\nd\ra\tsd" +print ( JSON . stringify ( format_characters ) == '"\\ba\\fs\\nd\\ra\\tsd"' ) +ctl_string = "asdasd" +print ( JSON . stringify ( ctl_string ) == '"asd\\u001fasd"' ) +escpad_string = "\"asda\sd" +print ( JSON . stringify ( escpad_string ) == '"\\"asdasd"' ) +print ( JSON . stringify ( true ) === 'true' ) +print ( JSON . stringify ( "foo" ) === '"foo"' ) +print ( JSON . stringify ( null ) === 'null' ) +print ( JSON . stringify ( RegExp ) === undefined ) +print ( JSON . stringify ( new Number ( 1 ) ) === '1' ) +print ( JSON . stringify ( new Boolean ( true ) ) === 'true' ) +print ( JSON . stringify ( new String ( "foo" ) ) === '"foo"' ) +empty_object = { } +print ( JSON . stringify ( empty_object ) == '{}' ) +empty_object = { } +empty_object . $ = undefined +print ( JSON . stringify ( empty_object ) == '{}' ) +p_object = { "a" : 1 , "b" : true , "c" : "foo" , "d" : null , "e" : undefined } +print ( JSON . stringify ( p_object ) == '{"a":1,"b":true,"c":"foo","d":null}' ) +o_object = { "a" : new Number ( 1 ) , "b" : new Boolean ( true ) , "c" : new String ( "foo" ) } +print ( JSON . stringify ( o_object ) == '{"a":1,"b":true,"c":"foo"}' ) +child = { "a" : 1 , "b" : new String ( "\nfoo" ) , $ : undefined } +parent = { "a" : true , "b" : child , "c" : null } +print ( JSON . stringify ( parent ) == '{"a":true,"b":{"a":1,"b":"\\nfoo"},"c":null}' ) +recursive_object = { } +recursive_object . $ = 0 +recursive_object . b = recursive_object +try { JSON . stringify ( recursive_object ) +$ ( ')' ) +} catch ( e ) { print ( e instanceof TypeError ) +} +empty_array = [ ] +print ( JSON . stringify ( empty_array ) == '[]' ) +array = [ undefined ] +print ( JSON . stringify ( array ) == '[null]' ) +p_array = [ 1 , true , "foo" , null , undefined ] +print ( JSON . stringify ( p_array ) == '[1,true,"foo",null,null]' ) +o_array = [ new Number ( 1 ) , new Boolean ( true ) , new String ( "foo" ) ] +print ( JSON . stringify ( o_array ) == '[1,true,"foo"]' ) +child = [ 1 , new String ( "\nfoo" ) , undefined ] +parent = [ true , child , null ] +print ( JSON . stringify ( parent ) == '[true,[1,"\\nfoo",null],null]' ) +recursive_array = [ ] +recursive_array [ 0 ] = 2 +recursive_array [ 1 ] = recursive_array +try { JSON . stringify ( recursive_array ) +$ ( $ ) +} catch ( e ) { print ( e instanceof TypeError ) +} +object = { "a" : 1 , "b" : [ 1 , true , { "a" : "foo" } ] } +print ( JSON . stringify ( object ) == '{"a":1,"b":[1,true,{"a":"foo"}]}' ) +object = { "a" : [ 1 ] , "b" : { } } +print ( JSON . stringify ( object ) === '{"a":[1],"b":{}}' ) +array = [ 1 , { "a" : 2 , "b" : true , c : [ 3 ] } ] +print ( JSON . stringify ( array ) == '[1,{"a":2,"b":true,"c":[3]}]' ) +to_json_object = { } +to_json_object . $ = 0 +to_json_object . $ = function ( ) { +} +var v1 = ( new Int8Array ( 149 ) ) . subarray ( 78 ) +function replacer_function ( $ , value ) { if ( typeof ( value ) == "string" ) return "FOO" +return value +} object = { "a" : "JSON" , "b" : new String ( "JSON" ) , "c" : 3 } +print ( JSON . stringify ( object , replacer_function ) == '{"a":"FOO","b":"JSON","c":3}' ) +filter = [ "a" , "b" ] +print ( JSON . stringify ( object , filter ) == '{"a":"JSON","b":"JSON"}' ) +print ( JSON . stringify ( [ ] , [ "" , 4 ] ) === '[]' ) +number = new Number ( 2.2 ) +number . toString = { } +new Promise ( isFinite . toString ) . catch ( Promise . prototype . then ) +try { } catch ( $ ) { $ ( $ instanceof $ ) +} +function replacer_thrower ( ) { throw new ReferenceError ( "foo" ) +} try { JSON . stringify ( object , replacer_thrower ) +} catch ( e ) { print ( e . message === "foo" ) +print ( e instanceof ReferenceError ) +} +object = { "a" : 2 } +print ( JSON . stringify ( object , 3 ) == '{"a":2}' ) +print ( JSON . stringify ( object , 0 ) == '{"a":2}' ) +print ( JSON . stringify ( object , 0 ) == '{"a":2}' ) +print ( JSON . stringify ( object , undefined ) == '{"a":2}' ) +print ( JSON . stringify ( object , 0 ) == '{"a":2}' ) +print ( JSON . stringify ( object , new Boolean ( 0 ) ) == '{"a":2}' ) +print ( JSON . stringify ( object , 0 , "asd\u20400123456789" ) == '{\nasd⁀012345"a": 2\n}' ) +print ( JSON . stringify ( object , 0 , 100 ) == '{\n "a": 2\n}' ) +print ( JSON . stringify ( object , 0 , - 5 ) == '{"a":2}' ) +array = [ 2 ] +print ( JSON . stringify ( array , 0 , " " ) == '[\n 2\n]' ) +print ( JSON . stringify ( array , 0 , "asd" ) == '[\nasd2\n]' ) +print ( JSON . stringify ( array , 0 , "asd0123456789" ) == '[\nasd01234562\n]' ) +print ( JSON . stringify ( array , 0 , "asd\u20400123456789" ) == '[\nasd⁀0123452\n]' ) +print ( JSON . stringify ( array , 0 , 100 ) == '[\n 2\n]' ) +print ( JSON . stringify ( array , 0 , - 5 ) == '[2]' ) +nested_object = { do : 2 , let : this } +print ( JSON . stringify ( nested_object , 0 , 2 ) == '{\n "a": 2,\n "b": {\n "c": 1,\n "d": true\n }\n}' ) +$ = [ $ , [ $ ] ] +$ ( $ . $ ( nested_array , $ , 2 ) == '[\n 2,\n [\n 1,\n true\n ]\n]' ) +$ +$ +$ +$ ( $ . $ ( $ , 0 , $ ) == $ ) +eval ( "{}/a/g" ) +$ ( $ . $ ( $ , $ , [ $ , $ , 0 ] ) == $ ) +$ ( $ . $ ( $ , $ , { $ : 3 } ) == $ )