Skip to content

Commit 22cd6ab

Browse files
authored
Fix global property access crash in raw context (#915)
A raw context doesn't contain anything but that doesn't mean property access is allowed to crash. Rename interrupt-test.c to api-test.c and add some tests. Fixes: #914
1 parent 9c25179 commit 22cd6ab

File tree

4 files changed

+71
-49
lines changed

4 files changed

+71
-49
lines changed

.github/workflows/ci.yml

+14-14
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ jobs:
165165
./build/qjs -c examples/hello.js -o hello
166166
./hello
167167
168-
- name: test interrupt
168+
- name: test api
169169
run: |
170-
./build/interrupt-test
170+
./build/api-test
171171
172172
windows-msvc:
173173
runs-on: windows-latest
@@ -197,9 +197,9 @@ jobs:
197197
run: |
198198
build\${{matrix.buildType}}\qjs.exe -c examples\hello.js -o hello.exe
199199
.\hello.exe
200-
- name: test interrupt
200+
- name: test api
201201
run: |
202-
build\${{matrix.buildType}}\interrupt-test.exe
202+
build\${{matrix.buildType}}\api-test.exe
203203
- name: Set up Visual Studio shell
204204
uses: egor-tensin/vs-shell@v2
205205
with:
@@ -262,9 +262,9 @@ jobs:
262262
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
263263
build\${{matrix.buildType}}\run-test262.exe -c tests.conf
264264
build\${{matrix.buildType}}\function_source.exe
265-
- name: test interrupt
265+
- name: test api
266266
run: |
267-
build\${{matrix.buildType}}\interrupt-test.exe
267+
build\${{matrix.buildType}}\api-test.exe
268268
269269
windows-ninja:
270270
runs-on: windows-latest
@@ -294,9 +294,9 @@ jobs:
294294
build\qjs.exe examples\test_point.js
295295
build\run-test262.exe -c tests.conf
296296
build\function_source.exe
297-
- name: test interrupt
297+
- name: test api
298298
run: |
299-
build\interrupt-test.exe
299+
build\api-test.exe
300300
301301
windows-sdk:
302302
runs-on: windows-latest
@@ -327,9 +327,9 @@ jobs:
327327
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
328328
build\${{matrix.buildType}}\run-test262.exe -c tests.conf
329329
build\${{matrix.buildType}}\function_source.exe
330-
- name: test interrupt
330+
- name: test api
331331
run: |
332-
build\${{matrix.buildType}}\interrupt-test.exe
332+
build\${{matrix.buildType}}\api-test.exe
333333
334334
windows-mingw:
335335
runs-on: windows-latest
@@ -380,9 +380,9 @@ jobs:
380380
run: |
381381
./build/qjs -c examples/hello.js -o hello.exe
382382
./hello
383-
- name: test interrupt
383+
- name: test api
384384
run: |
385-
./build/interrupt-test
385+
./build/api-test
386386
windows-mingw-shared:
387387
runs-on: windows-latest
388388
defaults:
@@ -467,9 +467,9 @@ jobs:
467467
- name: test
468468
run: make test
469469

470-
- name: test interrupt
470+
- name: test api
471471
run: |
472-
./build/interrupt-test
472+
./build/api-test
473473
474474
openbsd:
475475
runs-on: ubuntu-latest

CMakeLists.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,11 @@ endif()
308308
# Interrupt test
309309
#
310310

311-
add_executable(interrupt-test
312-
interrupt-test.c
311+
add_executable(api-test
312+
api-test.c
313313
)
314-
target_compile_definitions(interrupt-test PRIVATE ${qjs_defines})
315-
target_link_libraries(interrupt-test qjs)
314+
target_compile_definitions(api-test PRIVATE ${qjs_defines})
315+
target_link_libraries(api-test qjs)
316316

317317
# Unicode generator
318318
#

interrupt-test.c api-test.c

+51-28
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1+
#ifdef NDEBUG
2+
#undef NDEBUG
3+
#endif
4+
#include <assert.h>
15
#include <stdlib.h>
26
#include "quickjs.h"
37

48
#define MAX_TIME 10
59

6-
#define expect(condition) \
7-
do { \
8-
if (!(condition)) { \
9-
fprintf(stderr, "Failed: %s, file %s, line %d\n", \
10-
#condition, __FILE__, __LINE__); \
11-
exit(EXIT_FAILURE); \
12-
} \
13-
} while (0)
14-
1510
static int timeout_interrupt_handler(JSRuntime *rt, void *opaque)
1611
{
1712
int *time = (int *)opaque;
@@ -34,12 +29,12 @@ static void sync_call(void)
3429
int time = 0;
3530
JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time);
3631
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
37-
expect(time > MAX_TIME);
38-
expect(JS_IsException(ret));
32+
assert(time > MAX_TIME);
33+
assert(JS_IsException(ret));
3934
JS_FreeValue(ctx, ret);
40-
expect(JS_HasException(ctx));
35+
assert(JS_HasException(ctx));
4136
JSValue e = JS_GetException(ctx);
42-
expect(JS_IsUncatchableError(ctx, e));
37+
assert(JS_IsUncatchableError(ctx, e));
4338
JS_FreeValue(ctx, e);
4439
JS_FreeContext(ctx);
4540
JS_FreeRuntime(rt);
@@ -61,26 +56,26 @@ static void async_call(void)
6156
int time = 0;
6257
JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time);
6358
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
64-
expect(!JS_IsException(ret));
59+
assert(!JS_IsException(ret));
6560
JS_FreeValue(ctx, ret);
66-
expect(JS_IsJobPending(rt));
61+
assert(JS_IsJobPending(rt));
6762
int r = 0;
6863
while (JS_IsJobPending(rt)) {
6964
r = JS_ExecutePendingJob(rt, &ctx);
7065
}
71-
expect(time > MAX_TIME);
72-
expect(r == -1);
73-
expect(JS_HasException(ctx));
66+
assert(time > MAX_TIME);
67+
assert(r == -1);
68+
assert(JS_HasException(ctx));
7469
JSValue e = JS_GetException(ctx);
75-
expect(JS_IsUncatchableError(ctx, e));
70+
assert(JS_IsUncatchableError(ctx, e));
7671
JS_FreeValue(ctx, e);
7772
JS_FreeContext(ctx);
7873
JS_FreeRuntime(rt);
7974
}
8075

8176
static JSValue save_value(JSContext *ctx, JSValue this_val, int argc, JSValue *argv)
8277
{
83-
expect(argc == 1);
78+
assert(argc == 1);
8479
JSValue *p = (JSValue *)JS_GetContextOpaque(ctx);
8580
*p = JS_DupValue(ctx, argv[0]);
8681
return JS_UNDEFINED;
@@ -109,26 +104,54 @@ static void async_call_stack_overflow(void)
109104
JS_SetPropertyStr(ctx, global, "save_value", JS_NewCFunction(ctx, save_value, "save_value", 1));
110105
JS_FreeValue(ctx, global);
111106
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
112-
expect(!JS_IsException(ret));
107+
assert(!JS_IsException(ret));
113108
JS_FreeValue(ctx, ret);
114-
expect(JS_IsJobPending(rt));
109+
assert(JS_IsJobPending(rt));
115110
int r = 0;
116111
while (JS_IsJobPending(rt)) {
117112
r = JS_ExecutePendingJob(rt, &ctx);
118113
}
119-
expect(r == 1);
120-
expect(!JS_HasException(ctx));
121-
expect(JS_IsError(ctx, value)); /* StackOverflow should be caught */
114+
assert(r == 1);
115+
assert(!JS_HasException(ctx));
116+
assert(JS_IsError(ctx, value)); // stack overflow should be caught
122117
JS_FreeValue(ctx, value);
123118
JS_FreeContext(ctx);
124119
JS_FreeRuntime(rt);
125120
}
126121

127-
int main()
122+
// https://github.com/quickjs-ng/quickjs/issues/914
123+
static void raw_context_global_var(void)
124+
{
125+
JSRuntime *rt = JS_NewRuntime();
126+
JSContext *ctx = JS_NewContextRaw(rt);
127+
JS_AddIntrinsicEval(ctx);
128+
{
129+
static const char code[] = "globalThis";
130+
JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL);
131+
assert(JS_IsException(ret));
132+
JS_FreeValue(ctx, ret);
133+
}
134+
{
135+
static const char code[] = "var x = 42";
136+
JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL);
137+
assert(JS_IsUndefined(ret));
138+
JS_FreeValue(ctx, ret);
139+
}
140+
{
141+
static const char code[] = "function f() {}";
142+
JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL);
143+
assert(JS_IsUndefined(ret));
144+
JS_FreeValue(ctx, ret);
145+
}
146+
JS_FreeContext(ctx);
147+
JS_FreeRuntime(rt);
148+
}
149+
150+
int main(void)
128151
{
129152
sync_call();
130153
async_call();
131154
async_call_stack_overflow();
132-
printf("interrupt-test passed\n");
155+
raw_context_global_var();
133156
return 0;
134-
}
157+
}

quickjs.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -51399,6 +51399,8 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
5139951399
int i;
5140051400

5140151401
ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
51402+
ctx->global_obj = JS_NewObject(ctx);
51403+
ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
5140251404
ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
5140351405
JS_CFUNC_generic, 0,
5140451406
ctx->class_proto[JS_CLASS_OBJECT]);
@@ -51458,9 +51460,6 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
5145851460
JS_FreeValue(ctx, obj1);
5145951461
JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, &ctx->throw_type_error, 1));
5146051462

51461-
ctx->global_obj = JS_NewObject(ctx);
51462-
ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
51463-
5146451463
/* Object */
5146551464
obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
5146651465
ctx->class_proto[JS_CLASS_OBJECT]);

0 commit comments

Comments
 (0)