Skip to content

Commit 3dc7ef1

Browse files
author
Fabrice Bellard
committed
more robust out of memory handling (#406)
1 parent 1572aa8 commit 3dc7ef1

File tree

2 files changed

+113
-42
lines changed

2 files changed

+113
-42
lines changed

quickjs.c

Lines changed: 110 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5352,6 +5352,10 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
53525352
if (!name)
53535353
name = "";
53545354
name_atom = JS_NewAtom(ctx, name);
5355+
if (name_atom == JS_ATOM_NULL) {
5356+
JS_FreeValue(ctx, func_obj);
5357+
return JS_EXCEPTION;
5358+
}
53555359
js_function_set_properties(ctx, func_obj, name_atom, length);
53565360
JS_FreeAtom(ctx, name_atom);
53575361
return func_obj;
@@ -6882,20 +6886,27 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
68826886
const char *str1;
68836887
JSObject *p;
68846888

6889+
if (!JS_IsObject(error_obj))
6890+
return; /* protection in the out of memory case */
6891+
68856892
js_dbuf_init(ctx, &dbuf);
68866893
if (filename) {
68876894
dbuf_printf(&dbuf, " at %s", filename);
68886895
if (line_num != -1)
68896896
dbuf_printf(&dbuf, ":%d:%d", line_num, col_num);
68906897
dbuf_putc(&dbuf, '\n');
68916898
str = JS_NewString(ctx, filename);
6899+
if (JS_IsException(str))
6900+
return;
68926901
/* Note: SpiderMonkey does that, could update once there is a standard */
6893-
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
6894-
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6895-
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
6896-
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6897-
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
6898-
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6902+
if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
6903+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
6904+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
6905+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
6906+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
6907+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
6908+
return;
6909+
}
68996910
}
69006911
for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
69016912
if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER)
@@ -6980,9 +6991,9 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
69806991
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
69816992
JS_NewString(ctx, buf),
69826993
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6983-
}
6984-
if (add_backtrace) {
6985-
build_backtrace(ctx, obj, NULL, 0, 0, 0);
6994+
if (add_backtrace) {
6995+
build_backtrace(ctx, obj, NULL, 0, 0, 0);
6996+
}
69866997
}
69876998
ret = JS_Throw(ctx, obj);
69886999
return ret;
@@ -8454,6 +8465,8 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
84548465
JSAtom atom;
84558466
JSValue ret;
84568467
atom = JS_NewAtom(ctx, prop);
8468+
if (atom == JS_ATOM_NULL)
8469+
return JS_EXCEPTION;
84578470
ret = JS_GetProperty(ctx, this_obj, atom);
84588471
JS_FreeAtom(ctx, atom);
84598472
return ret;
@@ -9273,6 +9286,10 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
92739286
JSAtom atom;
92749287
int ret;
92759288
atom = JS_NewAtom(ctx, prop);
9289+
if (atom == JS_ATOM_NULL) {
9290+
JS_FreeValue(ctx, val);
9291+
return -1;
9292+
}
92769293
ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
92779294
JS_FreeAtom(ctx, atom);
92789295
return ret;
@@ -9829,6 +9846,10 @@ int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
98299846
JSAtom atom;
98309847
int ret;
98319848
atom = JS_NewAtom(ctx, prop);
9849+
if (atom == JS_ATOM_NULL) {
9850+
JS_FreeValue(ctx, val);
9851+
return -1;
9852+
}
98329853
ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
98339854
JS_FreeAtom(ctx, atom);
98349855
return ret;
@@ -20971,6 +20992,7 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
2097120992
{
2097220993
uint32_t c;
2097320994
StringBuffer b_s, *b = &b_s;
20995+
JSValue str;
2097420996

2097520997
/* p points to the first byte of the template part */
2097620998
if (string_buffer_init(s->ctx, b, 32))
@@ -21013,9 +21035,12 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
2101321035
if (string_buffer_putc(b, c))
2101421036
goto fail;
2101521037
}
21038+
str = string_buffer_end(b);
21039+
if (JS_IsException(str))
21040+
return -1;
2101621041
s->token.val = TOK_TEMPLATE;
2101721042
s->token.u.str.sep = c;
21018-
s->token.u.str.str = string_buffer_end(b);
21043+
s->token.u.str.str = str;
2101921044
s->buf_ptr = p;
2102021045
return 0;
2102121046

@@ -21034,7 +21059,8 @@ static __exception int js_parse_string(JSParseState *s, int sep,
2103421059
uint32_t c;
2103521060
StringBuffer b_s, *b = &b_s;
2103621061
const uint8_t *p_escape;
21037-
21062+
JSValue str;
21063+
2103821064
/* string */
2103921065
if (string_buffer_init(s->ctx, b, 32))
2104021066
goto fail;
@@ -21141,9 +21167,12 @@ static __exception int js_parse_string(JSParseState *s, int sep,
2114121167
if (string_buffer_putc(b, c))
2114221168
goto fail;
2114321169
}
21170+
str = string_buffer_end(b);
21171+
if (JS_IsException(str))
21172+
return -1;
2114421173
token->val = TOK_STRING;
2114521174
token->u.str.sep = c;
21146-
token->u.str.str = string_buffer_end(b);
21175+
token->u.str.str = str;
2114721176
*pp = p;
2114821177
return 0;
2114921178

@@ -21171,6 +21200,7 @@ static __exception int js_parse_regexp(JSParseState *s)
2117121200
StringBuffer b_s, *b = &b_s;
2117221201
StringBuffer b2_s, *b2 = &b2_s;
2117321202
uint32_t c;
21203+
JSValue body_str, flags_str;
2117421204

2117521205
p = s->buf_ptr;
2117621206
p++;
@@ -21252,9 +21282,17 @@ static __exception int js_parse_regexp(JSParseState *s)
2125221282
p = p_next;
2125321283
}
2125421284

21285+
body_str = string_buffer_end(b);
21286+
flags_str = string_buffer_end(b2);
21287+
if (JS_IsException(body_str) ||
21288+
JS_IsException(flags_str)) {
21289+
JS_FreeValue(s->ctx, body_str);
21290+
JS_FreeValue(s->ctx, flags_str);
21291+
return -1;
21292+
}
2125521293
s->token.val = TOK_REGEXP;
21256-
s->token.u.regexp.body = string_buffer_end(b);
21257-
s->token.u.regexp.flags = string_buffer_end(b2);
21294+
s->token.u.regexp.body = body_str;
21295+
s->token.u.regexp.flags = flags_str;
2125821296
s->buf_ptr = p;
2125921297
return 0;
2126021298
fail:
@@ -22362,7 +22400,7 @@ BOOL JS_DetectModule(const char *input, size_t input_len)
2236222400
}
2236322401

2236422402
static inline int get_prev_opcode(JSFunctionDef *fd) {
22365-
if (fd->last_opcode_pos < 0)
22403+
if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
2236622404
return OP_invalid;
2236722405
else
2236822406
return fd->byte_code.buf[fd->last_opcode_pos];
@@ -22427,7 +22465,11 @@ static void emit_op(JSParseState *s, uint8_t val)
2242722465

2242822466
static void emit_atom(JSParseState *s, JSAtom name)
2242922467
{
22430-
emit_u32(s, JS_DupAtom(s->ctx, name));
22468+
DynBuf *bc = &s->cur_func->byte_code;
22469+
if (dbuf_realloc(bc, bc->size + 4))
22470+
return; /* not enough memory : don't duplicate the atom */
22471+
put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
22472+
bc->size += 4;
2243122473
}
2243222474

2243322475
static int update_label(JSFunctionDef *s, int label, int delta)
@@ -22441,29 +22483,33 @@ static int update_label(JSFunctionDef *s, int label, int delta)
2244122483
return ls->ref_count;
2244222484
}
2244322485

22444-
static int new_label_fd(JSFunctionDef *fd, int label)
22486+
static int new_label_fd(JSFunctionDef *fd)
2244522487
{
22488+
int label;
2244622489
LabelSlot *ls;
2244722490

22448-
if (label < 0) {
22449-
if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
22450-
sizeof(fd->label_slots[0]),
22451-
&fd->label_size, fd->label_count + 1))
22452-
return -1;
22453-
label = fd->label_count++;
22454-
ls = &fd->label_slots[label];
22455-
ls->ref_count = 0;
22456-
ls->pos = -1;
22457-
ls->pos2 = -1;
22458-
ls->addr = -1;
22459-
ls->first_reloc = NULL;
22460-
}
22491+
if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
22492+
sizeof(fd->label_slots[0]),
22493+
&fd->label_size, fd->label_count + 1))
22494+
return -1;
22495+
label = fd->label_count++;
22496+
ls = &fd->label_slots[label];
22497+
ls->ref_count = 0;
22498+
ls->pos = -1;
22499+
ls->pos2 = -1;
22500+
ls->addr = -1;
22501+
ls->first_reloc = NULL;
2246122502
return label;
2246222503
}
2246322504

2246422505
static int new_label(JSParseState *s)
2246522506
{
22466-
return new_label_fd(s->cur_func, -1);
22507+
int label;
22508+
label = new_label_fd(s->cur_func);
22509+
if (unlikely(label < 0)) {
22510+
dbuf_set_error(&s->cur_func->byte_code);
22511+
}
22512+
return label;
2246722513
}
2246822514

2246922515
/* don't update the last opcode and don't emit line number info */
@@ -22491,8 +22537,11 @@ static int emit_label(JSParseState *s, int label)
2249122537
static int emit_goto(JSParseState *s, int opcode, int label)
2249222538
{
2249322539
if (js_is_live_code(s)) {
22494-
if (label < 0)
22540+
if (label < 0) {
2249522541
label = new_label(s);
22542+
if (label < 0)
22543+
return -1;
22544+
}
2249622545
emit_op(s, opcode);
2249722546
emit_u32(s, label);
2249822547
s->cur_func->label_slots[label].ref_count++;
@@ -24533,6 +24582,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
2453324582
switch(opcode) {
2453424583
case OP_scope_get_var:
2453524584
label = new_label(s);
24585+
if (label < 0)
24586+
return -1;
2453624587
emit_op(s, OP_scope_make_ref);
2453724588
emit_atom(s, name);
2453824589
emit_u32(s, label);
@@ -24565,6 +24616,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
2456524616
switch(opcode) {
2456624617
case OP_scope_get_var:
2456724618
label = new_label(s);
24619+
if (label < 0)
24620+
return -1;
2456824621
emit_op(s, OP_scope_make_ref);
2456924622
emit_atom(s, name);
2457024623
emit_u32(s, label);
@@ -28338,6 +28391,8 @@ JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
2833828391
if (name == JS_ATOM_NULL)
2833928392
return NULL;
2834028393
m = js_new_module_def(ctx, name);
28394+
if (!m)
28395+
return NULL;
2834128396
m->init_func = func;
2834228397
return m;
2834328398
}
@@ -30641,6 +30696,8 @@ static void free_bytecode_atoms(JSRuntime *rt,
3064130696
case OP_FMT_atom_u16:
3064230697
case OP_FMT_atom_label_u8:
3064330698
case OP_FMT_atom_label_u16:
30699+
if ((pos + 1 + 4) > bc_len)
30700+
break; /* may happen if there is not enough memory when emiting bytecode */
3064430701
atom = get_u32(bc_buf + pos + 1);
3064530702
JS_FreeAtomRT(rt, atom);
3064630703
break;
@@ -31430,7 +31487,13 @@ static void var_object_test(JSContext *ctx, JSFunctionDef *s,
3143031487
{
3143131488
dbuf_putc(bc, get_with_scope_opcode(op));
3143231489
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31433-
*plabel_done = new_label_fd(s, *plabel_done);
31490+
if (*plabel_done < 0) {
31491+
*plabel_done = new_label_fd(s);
31492+
if (*plabel_done < 0) {
31493+
dbuf_set_error(bc);
31494+
return;
31495+
}
31496+
}
3143431497
dbuf_put_u32(bc, *plabel_done);
3143531498
dbuf_putc(bc, is_with);
3143631499
update_label(s, *plabel_done, 1);
@@ -32475,8 +32538,11 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
3247532538
evaluating the module so that the exported functions are
3247632539
visible if there are cyclic module references */
3247732540
if (s->module) {
32478-
label_next = new_label_fd(s, -1);
32479-
32541+
label_next = new_label_fd(s);
32542+
if (label_next < 0) {
32543+
dbuf_set_error(bc);
32544+
return;
32545+
}
3248032546
/* if 'this' is true, initialize the global variables and return */
3248132547
dbuf_putc(bc, OP_push_this);
3248232548
dbuf_putc(bc, OP_if_false);
@@ -38001,17 +38067,22 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
3800138067
return 0;
3800238068
}
3800338069

38004-
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
38005-
const JSCFunctionListEntry *tab, int len)
38070+
int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
38071+
const JSCFunctionListEntry *tab, int len)
3800638072
{
38007-
int i;
38073+
int i, ret;
3800838074

3800938075
for (i = 0; i < len; i++) {
3801038076
const JSCFunctionListEntry *e = &tab[i];
3801138077
JSAtom atom = find_atom(ctx, e->name);
38012-
JS_InstantiateFunctionListItem(ctx, obj, atom, e);
38078+
if (atom == JS_ATOM_NULL)
38079+
return -1;
38080+
ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
3801338081
JS_FreeAtom(ctx, atom);
38082+
if (ret)
38083+
return -1;
3801438084
}
38085+
return 0;
3801538086
}
3801638087

3801738088
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,

quickjs.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,9 +1113,9 @@ typedef struct JSCFunctionListEntry {
11131113
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }
11141114
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }
11151115

1116-
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
1117-
const JSCFunctionListEntry *tab,
1118-
int len);
1116+
int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
1117+
const JSCFunctionListEntry *tab,
1118+
int len);
11191119

11201120
/* C module definition */
11211121

0 commit comments

Comments
 (0)