forked from quickjs-ng/quickjs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinterrupt-test.c
More file actions
134 lines (123 loc) · 3.7 KB
/
Copy pathinterrupt-test.c
File metadata and controls
134 lines (123 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <stdlib.h>
#include "quickjs.h"
#define MAX_TIME 10
#define expect(condition) \
do { \
if (!(condition)) { \
fprintf(stderr, "Failed: %s, file %s, line %d\n", \
#condition, __FILE__, __LINE__); \
exit(EXIT_FAILURE); \
} \
} while (0)
static int timeout_interrupt_handler(JSRuntime *rt, void *opaque)
{
int *time = (int *)opaque;
if (*time <= MAX_TIME)
*time += 1;
return *time > MAX_TIME;
}
static void sync_call(void)
{
const char *code =
"(function() { \
try { \
while (true) {} \
} catch (e) {} \
})();";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
int time = 0;
JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time);
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
expect(time > MAX_TIME);
expect(JS_IsException(ret));
JS_FreeValue(ctx, ret);
expect(JS_HasException(ctx));
JSValue e = JS_GetException(ctx);
expect(JS_IsUncatchableError(ctx, e));
JS_FreeValue(ctx, e);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void async_call(void)
{
const char *code =
"(async function() { \
const loop = async () => { \
await Promise.resolve(); \
while (true) {} \
}; \
await loop().catch(() => {}); \
})();";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
int time = 0;
JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time);
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
expect(!JS_IsException(ret));
JS_FreeValue(ctx, ret);
expect(JS_IsJobPending(rt));
int r = 0;
while (JS_IsJobPending(rt)) {
r = JS_ExecutePendingJob(rt, &ctx);
}
expect(time > MAX_TIME);
expect(r == -1);
expect(JS_HasException(ctx));
JSValue e = JS_GetException(ctx);
expect(JS_IsUncatchableError(ctx, e));
JS_FreeValue(ctx, e);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static JSValue save_value(JSContext *ctx, JSValue this_val, int argc, JSValue *argv)
{
expect(argc == 1);
JSValue *p = (JSValue *)JS_GetContextOpaque(ctx);
*p = JS_DupValue(ctx, argv[0]);
return JS_UNDEFINED;
}
static void async_call_stack_overflow(void)
{
const char *code =
"(async function() { \
const f = () => f(); \
try { \
await Promise.resolve(); \
f(); \
} catch (e) { \
save_value(e); \
} \
})();";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JS_SetMaxStackSize(rt, 128 * 1024);
JS_UpdateStackTop(rt);
JSValue value = JS_UNDEFINED;
JS_SetContextOpaque(ctx, &value);
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "save_value", JS_NewCFunction(ctx, save_value, "save_value", 1));
JS_FreeValue(ctx, global);
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
expect(!JS_IsException(ret));
JS_FreeValue(ctx, ret);
expect(JS_IsJobPending(rt));
int r = 0;
while (JS_IsJobPending(rt)) {
r = JS_ExecutePendingJob(rt, &ctx);
}
expect(r == 1);
expect(!JS_HasException(ctx));
expect(JS_IsError(ctx, value)); /* StackOverflow should be caught */
JS_FreeValue(ctx, value);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
int main()
{
sync_call();
async_call();
async_call_stack_overflow();
printf("interrupt-test passed\n");
return 0;
}