Skip to content

Commit b52c114

Browse files
authored
Implement eval check for ECMAScript code (#4788)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
1 parent fe3a5c0 commit b52c114

File tree

7 files changed

+196
-2
lines changed

7 files changed

+196
-2
lines changed

docs/02.API-REFERENCE.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12035,7 +12035,7 @@ is no longer needed.
1203512035
jerry_value_t
1203612036
jerry_get_user_value (const jerry_value_t value);
1203712037
```
12038-
- `value` - script / module / function value which executes JavaScript
12038+
- `value` - script / module / function value which executes ECMAScript
1203912039
code (native modules / functions do not have user value).
1204012040
- return
1204112041
- user value - if available,
@@ -12084,6 +12084,60 @@ main (void)
1208412084
- [jerry_generate_snapshot](#jerry_generate_snapshot)
1208512085
- [jerry_exec_snapshot](#jerry_exec_snapshot)
1208612086

12087+
## jerry_is_eval_code
12088+
12089+
**Summary**
12090+
12091+
Checks whether an ECMAScript code is compiled by eval like (eval, new Function,
12092+
[jerry_eval](#jerry_eval), etc.) command.
12093+
12094+
**Prototype**
12095+
12096+
```c
12097+
bool jerry_is_eval_code (const jerry_value_t value);
12098+
```
12099+
- `value` - script / module / function value which executes ECMAScript code
12100+
- return
12101+
- true - if code is compiled by eval like command
12102+
- false - otherwise
12103+
12104+
*New in version [[NEXT_RELEASE]]*.
12105+
12106+
**Example**
12107+
12108+
[doctest]: # ()
12109+
12110+
```c
12111+
#include "jerryscript.h"
12112+
12113+
int
12114+
main (void)
12115+
{
12116+
jerry_init (JERRY_INIT_EMPTY);
12117+
12118+
const jerry_char_t script[] = "eval('(function (a) { return a; })')";
12119+
12120+
jerry_value_t script_value = jerry_parse (script, sizeof (script) - 1, NULL);
12121+
jerry_value_t function_value = jerry_run (script_value);
12122+
jerry_release_value (script_value);
12123+
12124+
if (jerry_is_eval_code (function_value))
12125+
{
12126+
/* Code enters here. */
12127+
}
12128+
12129+
jerry_release_value (function_value);
12130+
jerry_cleanup ();
12131+
return 0;
12132+
}
12133+
```
12134+
12135+
**See also**
12136+
12137+
- [jerry_parse](#jerry_parse)
12138+
- [jerry_generate_snapshot](#jerry_generate_snapshot)
12139+
- [jerry_exec_snapshot](#jerry_exec_snapshot)
12140+
1208712141
## jerry_get_source_info
1208812142

1208912143
**Summary**

jerry-core/api/jerry.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5565,6 +5565,28 @@ jerry_get_user_value (const jerry_value_t value) /**< jerry api value */
55655565
return ecma_copy_value (CBC_SCRIPT_GET_USER_VALUE (script_p));
55665566
} /* jerry_get_user_value */
55675567

5568+
/**
5569+
* Checks whether an ECMAScript code is compiled by eval
5570+
* like (eval, new Function, jerry_eval, etc.) command.
5571+
*
5572+
* @return true, if code is compiled by eval like command
5573+
* false, otherwise
5574+
*/
5575+
bool
5576+
jerry_is_eval_code (const jerry_value_t value) /**< jerry api value */
5577+
{
5578+
ecma_value_t script_value = ecma_script_get_from_value (value);
5579+
5580+
if (script_value == JMEM_CP_NULL)
5581+
{
5582+
return false;
5583+
}
5584+
5585+
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
5586+
5587+
return (script_p->refs_and_type & CBC_SCRIPT_IS_EVAL_CODE) != 0;
5588+
} /* jerry_is_eval_code */
5589+
55685590
/**
55695591
* Returns a newly created source info structure corresponding to the passed script/module/function.
55705592
*

jerry-core/include/jerryscript-core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ bool jerry_backtrace_is_strict (jerry_backtrace_frame_t *frame_p);
364364
void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency);
365365
jerry_value_t jerry_get_resource_name (const jerry_value_t value);
366366
jerry_value_t jerry_get_user_value (const jerry_value_t value);
367+
bool jerry_is_eval_code (const jerry_value_t value);
367368
jerry_source_info_t *jerry_get_source_info (const jerry_value_t value);
368369
void jerry_free_source_info (jerry_source_info_t *source_info_p);
369370

jerry-core/parser/js/byte-code.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,12 +1004,13 @@ typedef enum
10041004
CBC_SCRIPT_USER_VALUE_IS_OBJECT = (1 << 1), /**< user value is object */
10051005
CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS = (1 << 2), /**< script is a function with arguments source code */
10061006
CBC_SCRIPT_HAS_IMPORT_META = (1 << 3), /**< script is a module with import.meta object */
1007+
CBC_SCRIPT_IS_EVAL_CODE = (1 << 4), /**< script is compiled by eval like (eval, new Function, etc.) expression */
10071008
} cbc_script_type;
10081009

10091010
/**
10101011
* Value for increasing or decreasing the script reference counter.
10111012
*/
1012-
#define CBC_SCRIPT_REF_ONE 0x10
1013+
#define CBC_SCRIPT_REF_ONE 0x20
10131014

10141015
/**
10151016
* Maximum value of script reference counter.

jerry-core/parser/js/js-parser.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,6 +2108,11 @@ parser_parse_source (void *source_p, /**< source code */
21082108

21092109
CBC_SCRIPT_SET_TYPE (context.script_p, context.user_value, CBC_SCRIPT_REF_ONE);
21102110

2111+
if (context.global_status_flags & (ECMA_PARSE_EVAL | ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE))
2112+
{
2113+
context.script_p->refs_and_type |= CBC_SCRIPT_IS_EVAL_CODE;
2114+
}
2115+
21112116
#if JERRY_BUILTIN_REALMS
21122117
context.script_p->realm_p = (ecma_object_t *) JERRY_CONTEXT (global_object_p);
21132118
#endif /* JERRY_BUILTIN_REALMS */

tests/unit-core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ set(SOURCE_UNIT_TEST_MAIN_MODULES
5353
test-get-own-property.c
5454
test-has-property.c
5555
test-internal-properties.c
56+
test-is-eval-code.c
5657
test-jmem.c
5758
test-json.c
5859
test-lit-char-helpers.c

tests/unit-core/test-is-eval-code.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#include "config.h"
17+
#include "jerryscript.h"
18+
19+
#include "test-common.h"
20+
21+
static jerry_value_t
22+
check_eval (const jerry_call_info_t *call_info_p, /**< call information */
23+
const jerry_value_t args_p[], /**< arguments list */
24+
const jerry_length_t args_cnt) /**< arguments length */
25+
{
26+
JERRY_UNUSED (call_info_p);
27+
28+
TEST_ASSERT (args_cnt == 2 && jerry_is_eval_code (args_p[0]) == jerry_value_is_true (args_p[1]));
29+
return jerry_create_boolean (true);
30+
} /* check_eval */
31+
32+
static void
33+
test_parse (const char *source_p, /**< source code */
34+
jerry_parse_options_t *options_p) /**< options passed to jerry_parse */
35+
{
36+
jerry_value_t parse_result = jerry_parse ((const jerry_char_t *) source_p, strlen (source_p), options_p);
37+
TEST_ASSERT (!jerry_value_is_error (parse_result));
38+
TEST_ASSERT (!jerry_is_eval_code (parse_result));
39+
40+
jerry_value_t result;
41+
42+
if (options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST)
43+
{
44+
jerry_value_t this_value = jerry_create_undefined ();
45+
result = jerry_call_function (parse_result, this_value, NULL, 0);
46+
jerry_release_value (this_value);
47+
}
48+
else if (options_p->options & JERRY_PARSE_MODULE)
49+
{
50+
result = jerry_module_link (parse_result, NULL, NULL);
51+
TEST_ASSERT (!jerry_value_is_error (result));
52+
jerry_release_value (result);
53+
result = jerry_module_evaluate (parse_result);
54+
}
55+
else
56+
{
57+
result = jerry_run (parse_result);
58+
}
59+
60+
TEST_ASSERT (!jerry_value_is_error (result));
61+
62+
jerry_release_value (parse_result);
63+
jerry_release_value (result);
64+
} /* test_parse */
65+
66+
int
67+
main (void)
68+
{
69+
TEST_INIT ();
70+
71+
jerry_init (JERRY_INIT_EMPTY);
72+
73+
jerry_value_t global_object_value = jerry_get_global_object ();
74+
75+
jerry_value_t function_value = jerry_create_external_function (check_eval);
76+
jerry_value_t function_name_value = jerry_create_string ((const jerry_char_t *) "check_eval");
77+
jerry_release_value (jerry_set_property (global_object_value, function_name_value, function_value));
78+
79+
jerry_release_value (function_name_value);
80+
jerry_release_value (function_value);
81+
jerry_release_value (global_object_value);
82+
83+
jerry_parse_options_t parse_options;
84+
const char *source_p = TEST_STRING_LITERAL ("eval('check_eval(function() {}, true)')\n"
85+
"check_eval(function() {}, false)");
86+
87+
parse_options.options = JERRY_PARSE_NO_OPTS;
88+
test_parse (source_p, &parse_options);
89+
90+
if (jerry_is_feature_enabled (JERRY_FEATURE_MODULE))
91+
{
92+
parse_options.options = JERRY_PARSE_MODULE;
93+
test_parse (source_p, &parse_options);
94+
}
95+
96+
parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST;
97+
parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "");
98+
test_parse (source_p, &parse_options);
99+
jerry_release_value (parse_options.argument_list);
100+
101+
parse_options.options = JERRY_PARSE_NO_OPTS;
102+
source_p = TEST_STRING_LITERAL ("check_eval(new Function('a', 'return a'), true)");
103+
test_parse (source_p, &parse_options);
104+
105+
source_p = TEST_STRING_LITERAL ("check_eval(function() {}, true)");
106+
jerry_release_value (jerry_eval ((const jerry_char_t *) source_p, strlen (source_p), JERRY_PARSE_NO_OPTS));
107+
108+
jerry_cleanup ();
109+
return 0;
110+
} /* main */

0 commit comments

Comments
 (0)