aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZoltan Herczeg <zherczeg.u-szeged@partner.samsung.com>2021-10-15 22:25:20 +0200
committerGitHub <noreply@github.com>2021-10-15 22:25:20 +0200
commitb52c1144231d3d4f12cb62fd1290a2de42ea79ea (patch)
tree935ba7930e3c4b18767eaa85723afeddce77303e
parentfe3a5c08b2df474340bc77bdd8e25e483e671c40 (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.md56
-rw-r--r--jerry-core/api/jerry.c22
-rw-r--r--jerry-core/include/jerryscript-core.h1
-rw-r--r--jerry-core/parser/js/byte-code.h3
-rw-r--r--jerry-core/parser/js/js-parser.c5
-rw-r--r--tests/unit-core/CMakeLists.txt1
-rw-r--r--tests/unit-core/test-is-eval-code.c110
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 */