diff options
author | Zoltan Herczeg <zherczeg.u-szeged@partner.samsung.com> | 2021-10-15 22:25:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-15 22:25:20 +0200 |
commit | b52c1144231d3d4f12cb62fd1290a2de42ea79ea (patch) | |
tree | 935ba7930e3c4b18767eaa85723afeddce77303e | |
parent | fe3a5c08b2df474340bc77bdd8e25e483e671c40 (diff) |
Implement eval check for ECMAScript code (#4788)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
-rw-r--r-- | docs/02.API-REFERENCE.md | 56 | ||||
-rw-r--r-- | jerry-core/api/jerry.c | 22 | ||||
-rw-r--r-- | jerry-core/include/jerryscript-core.h | 1 | ||||
-rw-r--r-- | jerry-core/parser/js/byte-code.h | 3 | ||||
-rw-r--r-- | jerry-core/parser/js/js-parser.c | 5 | ||||
-rw-r--r-- | tests/unit-core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/unit-core/test-is-eval-code.c | 110 |
7 files changed, 196 insertions, 2 deletions
diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index f18358e6..e518a605 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -12035,7 +12035,7 @@ is no longer needed. jerry_value_t jerry_get_user_value (const jerry_value_t value); ``` -- `value` - script / module / function value which executes JavaScript +- `value` - script / module / function value which executes ECMAScript code (native modules / functions do not have user value). - return - user value - if available, @@ -12084,6 +12084,60 @@ main (void) - [jerry_generate_snapshot](#jerry_generate_snapshot) - [jerry_exec_snapshot](#jerry_exec_snapshot) +## jerry_is_eval_code + +**Summary** + +Checks whether an ECMAScript code is compiled by eval like (eval, new Function, +[jerry_eval](#jerry_eval), etc.) command. + +**Prototype** + +```c +bool jerry_is_eval_code (const jerry_value_t value); +``` +- `value` - script / module / function value which executes ECMAScript code +- return + - true - if code is compiled by eval like command + - false - otherwise + +*New in version [[NEXT_RELEASE]]*. + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + const jerry_char_t script[] = "eval('(function (a) { return a; })')"; + + jerry_value_t script_value = jerry_parse (script, sizeof (script) - 1, NULL); + jerry_value_t function_value = jerry_run (script_value); + jerry_release_value (script_value); + + if (jerry_is_eval_code (function_value)) + { + /* Code enters here. */ + } + + jerry_release_value (function_value); + jerry_cleanup (); + return 0; +} +``` + +**See also** + +- [jerry_parse](#jerry_parse) +- [jerry_generate_snapshot](#jerry_generate_snapshot) +- [jerry_exec_snapshot](#jerry_exec_snapshot) + ## jerry_get_source_info **Summary** diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 37043a34..c9c2b0b9 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -5566,6 +5566,28 @@ jerry_get_user_value (const jerry_value_t value) /**< jerry api value */ } /* jerry_get_user_value */ /** + * Checks whether an ECMAScript code is compiled by eval + * like (eval, new Function, jerry_eval, etc.) command. + * + * @return true, if code is compiled by eval like command + * false, otherwise + */ +bool +jerry_is_eval_code (const jerry_value_t value) /**< jerry api value */ +{ + ecma_value_t script_value = ecma_script_get_from_value (value); + + if (script_value == JMEM_CP_NULL) + { + return false; + } + + const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value); + + return (script_p->refs_and_type & CBC_SCRIPT_IS_EVAL_CODE) != 0; +} /* jerry_is_eval_code */ + +/** * Returns a newly created source info structure corresponding to the passed script/module/function. * * @return a newly created source info, if at least one field is available, NULL otherwise diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 0a4393e0..f1dbdfe6 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -364,6 +364,7 @@ bool jerry_backtrace_is_strict (jerry_backtrace_frame_t *frame_p); void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency); jerry_value_t jerry_get_resource_name (const jerry_value_t value); jerry_value_t jerry_get_user_value (const jerry_value_t value); +bool jerry_is_eval_code (const jerry_value_t value); jerry_source_info_t *jerry_get_source_info (const jerry_value_t value); void jerry_free_source_info (jerry_source_info_t *source_info_p); diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 062e27ac..5dc68da6 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -1004,12 +1004,13 @@ typedef enum CBC_SCRIPT_USER_VALUE_IS_OBJECT = (1 << 1), /**< user value is object */ CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS = (1 << 2), /**< script is a function with arguments source code */ CBC_SCRIPT_HAS_IMPORT_META = (1 << 3), /**< script is a module with import.meta object */ + CBC_SCRIPT_IS_EVAL_CODE = (1 << 4), /**< script is compiled by eval like (eval, new Function, etc.) expression */ } cbc_script_type; /** * Value for increasing or decreasing the script reference counter. */ -#define CBC_SCRIPT_REF_ONE 0x10 +#define CBC_SCRIPT_REF_ONE 0x20 /** * Maximum value of script reference counter. diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 10eb517f..2f7c1f28 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2108,6 +2108,11 @@ parser_parse_source (void *source_p, /**< source code */ CBC_SCRIPT_SET_TYPE (context.script_p, context.user_value, CBC_SCRIPT_REF_ONE); + if (context.global_status_flags & (ECMA_PARSE_EVAL | ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE)) + { + context.script_p->refs_and_type |= CBC_SCRIPT_IS_EVAL_CODE; + } + #if JERRY_BUILTIN_REALMS context.script_p->realm_p = (ecma_object_t *) JERRY_CONTEXT (global_object_p); #endif /* JERRY_BUILTIN_REALMS */ diff --git a/tests/unit-core/CMakeLists.txt b/tests/unit-core/CMakeLists.txt index 3bff7249..782a7a72 100644 --- a/tests/unit-core/CMakeLists.txt +++ b/tests/unit-core/CMakeLists.txt @@ -53,6 +53,7 @@ set(SOURCE_UNIT_TEST_MAIN_MODULES test-get-own-property.c test-has-property.c test-internal-properties.c + test-is-eval-code.c test-jmem.c test-json.c test-lit-char-helpers.c diff --git a/tests/unit-core/test-is-eval-code.c b/tests/unit-core/test-is-eval-code.c new file mode 100644 index 00000000..224356b5 --- /dev/null +++ b/tests/unit-core/test-is-eval-code.c @@ -0,0 +1,110 @@ +/* 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. + */ + +#include "config.h" +#include "jerryscript.h" + +#include "test-common.h" + +static jerry_value_t +check_eval (const jerry_call_info_t *call_info_p, /**< call information */ + const jerry_value_t args_p[], /**< arguments list */ + const jerry_length_t args_cnt) /**< arguments length */ +{ + JERRY_UNUSED (call_info_p); + + TEST_ASSERT (args_cnt == 2 && jerry_is_eval_code (args_p[0]) == jerry_value_is_true (args_p[1])); + return jerry_create_boolean (true); +} /* check_eval */ + +static void +test_parse (const char *source_p, /**< source code */ + jerry_parse_options_t *options_p) /**< options passed to jerry_parse */ +{ + jerry_value_t parse_result = jerry_parse ((const jerry_char_t *) source_p, strlen (source_p), options_p); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + TEST_ASSERT (!jerry_is_eval_code (parse_result)); + + jerry_value_t result; + + if (options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST) + { + jerry_value_t this_value = jerry_create_undefined (); + result = jerry_call_function (parse_result, this_value, NULL, 0); + jerry_release_value (this_value); + } + else if (options_p->options & JERRY_PARSE_MODULE) + { + result = jerry_module_link (parse_result, NULL, NULL); + TEST_ASSERT (!jerry_value_is_error (result)); + jerry_release_value (result); + result = jerry_module_evaluate (parse_result); + } + else + { + result = jerry_run (parse_result); + } + + TEST_ASSERT (!jerry_value_is_error (result)); + + jerry_release_value (parse_result); + jerry_release_value (result); +} /* test_parse */ + +int +main (void) +{ + TEST_INIT (); + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object_value = jerry_get_global_object (); + + jerry_value_t function_value = jerry_create_external_function (check_eval); + jerry_value_t function_name_value = jerry_create_string ((const jerry_char_t *) "check_eval"); + jerry_release_value (jerry_set_property (global_object_value, function_name_value, function_value)); + + jerry_release_value (function_name_value); + jerry_release_value (function_value); + jerry_release_value (global_object_value); + + jerry_parse_options_t parse_options; + const char *source_p = TEST_STRING_LITERAL ("eval('check_eval(function() {}, true)')\n" + "check_eval(function() {}, false)"); + + parse_options.options = JERRY_PARSE_NO_OPTS; + test_parse (source_p, &parse_options); + + if (jerry_is_feature_enabled (JERRY_FEATURE_MODULE)) + { + parse_options.options = JERRY_PARSE_MODULE; + test_parse (source_p, &parse_options); + } + + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) ""); + test_parse (source_p, &parse_options); + jerry_release_value (parse_options.argument_list); + + parse_options.options = JERRY_PARSE_NO_OPTS; + source_p = TEST_STRING_LITERAL ("check_eval(new Function('a', 'return a'), true)"); + test_parse (source_p, &parse_options); + + source_p = TEST_STRING_LITERAL ("check_eval(function() {}, true)"); + jerry_release_value (jerry_eval ((const jerry_char_t *) source_p, strlen (source_p), JERRY_PARSE_NO_OPTS)); + + jerry_cleanup (); + return 0; +} /* main */ |