Skip to content

Commit 3c78c95

Browse files
past-dueFabrice Bellard
andauthored
Cherry-pick OOM handling and memory leak fixes (#1069)
Partial cherry-picks of commits: bellard/quickjs@db3d3f0 bellard/quickjs@3dc7ef1 Co-Authored-By: Fabrice Bellard <[email protected]>
1 parent 8a01f56 commit 3c78c95

File tree

2 files changed

+94
-27
lines changed

2 files changed

+94
-27
lines changed

quickjs.c

Lines changed: 93 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5287,6 +5287,10 @@ JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
52875287
if (!name)
52885288
name = "";
52895289
name_atom = JS_NewAtom(ctx, name);
5290+
if (name_atom == JS_ATOM_NULL) {
5291+
JS_FreeValue(ctx, func_obj);
5292+
return JS_EXCEPTION;
5293+
}
52905294
js_function_set_properties(ctx, func_obj, name_atom, length);
52915295
JS_FreeAtom(ctx, name_atom);
52925296
return func_obj;
@@ -8489,6 +8493,8 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
84898493
JSAtom atom;
84908494
JSValue ret;
84918495
atom = JS_NewAtom(ctx, prop);
8496+
if (atom == JS_ATOM_NULL)
8497+
return JS_EXCEPTION;
84928498
ret = JS_GetProperty(ctx, this_obj, atom);
84938499
JS_FreeAtom(ctx, atom);
84948500
return ret;
@@ -9276,6 +9282,10 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
92769282
JSAtom atom;
92779283
int ret;
92789284
atom = JS_NewAtom(ctx, prop);
9285+
if (atom == JS_ATOM_NULL) {
9286+
JS_FreeValue(ctx, val);
9287+
return -1;
9288+
}
92799289
ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
92809290
JS_FreeAtom(ctx, atom);
92819291
return ret;
@@ -9827,6 +9837,10 @@ int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
98279837
JSAtom atom;
98289838
int ret;
98299839
atom = JS_NewAtom(ctx, prop);
9840+
if (atom == JS_ATOM_NULL) {
9841+
JS_FreeValue(ctx, val);
9842+
return -1;
9843+
}
98309844
ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
98319845
JS_FreeAtom(ctx, atom);
98329846
return ret;
@@ -20585,6 +20599,7 @@ static __exception int js_parse_template_part(JSParseState *s,
2058520599
const uint8_t *p_next;
2058620600
uint32_t c;
2058720601
StringBuffer b_s, *b = &b_s;
20602+
JSValue str;
2058820603

2058920604
/* p points to the first byte of the template part */
2059020605
if (string_buffer_init(s->ctx, b, 32))
@@ -20630,9 +20645,12 @@ static __exception int js_parse_template_part(JSParseState *s,
2063020645
if (string_buffer_putc(b, c))
2063120646
goto fail;
2063220647
}
20648+
str = string_buffer_end(b);
20649+
if (JS_IsException(str))
20650+
return -1;
2063320651
s->token.val = TOK_TEMPLATE;
2063420652
s->token.u.str.sep = c;
20635-
s->token.u.str.str = string_buffer_end(b);
20653+
s->token.u.str.str = str;
2063620654
s->buf_ptr = p;
2063720655
return 0;
2063820656

@@ -20651,6 +20669,7 @@ static __exception int js_parse_string(JSParseState *s, int sep,
2065120669
int ret;
2065220670
uint32_t c;
2065320671
StringBuffer b_s, *b = &b_s;
20672+
JSValue str;
2065420673

2065520674
/* string */
2065620675
if (string_buffer_init(s->ctx, b, 32))
@@ -20759,9 +20778,12 @@ static __exception int js_parse_string(JSParseState *s, int sep,
2075920778
if (string_buffer_putc(b, c))
2076020779
goto fail;
2076120780
}
20781+
str = string_buffer_end(b);
20782+
if (JS_IsException(str))
20783+
return -1;
2076220784
token->val = TOK_STRING;
2076320785
token->u.str.sep = c;
20764-
token->u.str.str = string_buffer_end(b);
20786+
token->u.str.str = str;
2076520787
*pp = p;
2076620788
return 0;
2076720789

@@ -20789,6 +20811,7 @@ static __exception int js_parse_regexp(JSParseState *s)
2078920811
StringBuffer b_s, *b = &b_s;
2079020812
StringBuffer b2_s, *b2 = &b2_s;
2079120813
uint32_t c;
20814+
JSValue body_str, flags_str;
2079220815

2079320816
p = s->buf_ptr;
2079420817
p++;
@@ -20861,9 +20884,17 @@ static __exception int js_parse_regexp(JSParseState *s)
2086120884
p = p_next;
2086220885
}
2086320886

20887+
body_str = string_buffer_end(b);
20888+
flags_str = string_buffer_end(b2);
20889+
if (JS_IsException(body_str) ||
20890+
JS_IsException(flags_str)) {
20891+
JS_FreeValue(s->ctx, body_str);
20892+
JS_FreeValue(s->ctx, flags_str);
20893+
return -1;
20894+
}
2086420895
s->token.val = TOK_REGEXP;
20865-
s->token.u.regexp.body = string_buffer_end(b);
20866-
s->token.u.regexp.flags = string_buffer_end(b2);
20896+
s->token.u.regexp.body = body_str;
20897+
s->token.u.regexp.flags = flags_str;
2086720898
s->buf_ptr = p;
2086820899
return 0;
2086920900
fail:
@@ -21893,7 +21924,7 @@ static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
2189321924
}
2189421925

2189521926
static inline int get_prev_opcode(JSFunctionDef *fd) {
21896-
if (fd->last_opcode_pos < 0)
21927+
if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
2189721928
return OP_invalid;
2189821929
else
2189921930
return fd->byte_code.buf[fd->last_opcode_pos];
@@ -21954,7 +21985,11 @@ static void emit_op(JSParseState *s, uint8_t val)
2195421985

2195521986
static void emit_atom(JSParseState *s, JSAtom name)
2195621987
{
21957-
emit_u32(s, JS_DupAtom(s->ctx, name));
21988+
DynBuf *bc = &s->cur_func->byte_code;
21989+
if (dbuf_realloc(bc, bc->size + 4))
21990+
return; /* not enough memory : don't duplicate the atom */
21991+
put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
21992+
bc->size += 4;
2195821993
}
2195921994

2196021995
static int update_label(JSFunctionDef *s, int label, int delta)
@@ -21968,29 +22003,33 @@ static int update_label(JSFunctionDef *s, int label, int delta)
2196822003
return ls->ref_count;
2196922004
}
2197022005

21971-
static int new_label_fd(JSFunctionDef *fd, int label)
22006+
static int new_label_fd(JSFunctionDef *fd)
2197222007
{
22008+
int label;
2197322009
LabelSlot *ls;
2197422010

21975-
if (label < 0) {
21976-
if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
22011+
if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
2197722012
sizeof(fd->label_slots[0]),
2197822013
&fd->label_size, fd->label_count + 1))
21979-
return -1;
21980-
label = fd->label_count++;
21981-
ls = &fd->label_slots[label];
21982-
ls->ref_count = 0;
21983-
ls->pos = -1;
21984-
ls->pos2 = -1;
21985-
ls->addr = -1;
21986-
ls->first_reloc = NULL;
21987-
}
22014+
return -1;
22015+
label = fd->label_count++;
22016+
ls = &fd->label_slots[label];
22017+
ls->ref_count = 0;
22018+
ls->pos = -1;
22019+
ls->pos2 = -1;
22020+
ls->addr = -1;
22021+
ls->first_reloc = NULL;
2198822022
return label;
2198922023
}
2199022024

2199122025
static int new_label(JSParseState *s)
2199222026
{
21993-
return new_label_fd(s->cur_func, -1);
22027+
int label;
22028+
label = new_label_fd(s->cur_func);
22029+
if (unlikely(label < 0)) {
22030+
dbuf_set_error(&s->cur_func->byte_code);
22031+
}
22032+
return label;
2199422033
}
2199522034

2199622035
/* don't update the last opcode and don't emit line number info */
@@ -22018,8 +22057,11 @@ static int emit_label(JSParseState *s, int label)
2201822057
static int emit_goto(JSParseState *s, int opcode, int label)
2201922058
{
2202022059
if (js_is_live_code(s)) {
22021-
if (label < 0)
22060+
if (label < 0) {
2202222061
label = new_label(s);
22062+
if (label < 0)
22063+
return -1;
22064+
}
2202322065
emit_op(s, opcode);
2202422066
emit_u32(s, label);
2202522067
s->cur_func->label_slots[label].ref_count++;
@@ -24154,6 +24196,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
2415424196
switch(opcode) {
2415524197
case OP_scope_get_var:
2415624198
label = new_label(s);
24199+
if (label < 0)
24200+
return -1;
2415724201
emit_op(s, OP_scope_make_ref);
2415824202
emit_atom(s, name);
2415924203
emit_u32(s, label);
@@ -24189,6 +24233,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
2418924233
switch(opcode) {
2419024234
case OP_scope_get_var:
2419124235
label = new_label(s);
24236+
if (label < 0)
24237+
return -1;
2419224238
emit_op(s, OP_scope_make_ref);
2419324239
emit_atom(s, name);
2419424240
emit_u32(s, label);
@@ -27894,6 +27940,8 @@ JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
2789427940
if (name == JS_ATOM_NULL)
2789527941
return NULL;
2789627942
m = js_new_module_def(ctx, name);
27943+
if (!m)
27944+
return NULL;
2789727945
m->init_func = func;
2789827946
return m;
2789927947
}
@@ -29997,6 +30045,8 @@ static void free_bytecode_atoms(JSRuntime *rt,
2999730045
case OP_FMT_atom_u16:
2999830046
case OP_FMT_atom_label_u8:
2999930047
case OP_FMT_atom_label_u16:
30048+
if ((pos + 1 + 4) > bc_len)
30049+
break; /* may happen if there is not enough memory when emiting bytecode */
3000030050
atom = get_u32(bc_buf + pos + 1);
3000130051
JS_FreeAtomRT(rt, atom);
3000230052
break;
@@ -30814,7 +30864,13 @@ static void var_object_test(JSContext *ctx, JSFunctionDef *s,
3081430864
{
3081530865
dbuf_putc(bc, get_with_scope_opcode(op));
3081630866
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30817-
*plabel_done = new_label_fd(s, *plabel_done);
30867+
if (*plabel_done < 0) {
30868+
*plabel_done = new_label_fd(s);
30869+
if (*plabel_done < 0) {
30870+
dbuf_set_error(bc);
30871+
return;
30872+
}
30873+
}
3081830874
dbuf_put_u32(bc, *plabel_done);
3081930875
dbuf_putc(bc, is_with);
3082030876
update_label(s, *plabel_done, 1);
@@ -31858,7 +31914,11 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
3185831914
evaluating the module so that the exported functions are
3185931915
visible if there are cyclic module references */
3186031916
if (s->module) {
31861-
label_next = new_label_fd(s, -1);
31917+
label_next = new_label_fd(s);
31918+
if (label_next < 0) {
31919+
dbuf_set_error(bc);
31920+
return;
31921+
}
3186231922

3186331923
/* if 'this' is true, initialize the global variables and return */
3186431924
dbuf_putc(bc, OP_push_this);
@@ -37578,17 +37638,22 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
3757837638
return 0;
3757937639
}
3758037640

37581-
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
37641+
int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
3758237642
const JSCFunctionListEntry *tab, int len)
3758337643
{
37584-
int i;
37644+
int i, ret;
3758537645

3758637646
for (i = 0; i < len; i++) {
3758737647
const JSCFunctionListEntry *e = &tab[i];
3758837648
JSAtom atom = find_atom(ctx, e->name);
37589-
JS_InstantiateFunctionListItem(ctx, obj, atom, e);
37649+
if (atom == JS_ATOM_NULL)
37650+
return -1;
37651+
ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
3759037652
JS_FreeAtom(ctx, atom);
37653+
if (ret)
37654+
return -1;
3759137655
}
37656+
return 0;
3759237657
}
3759337658

3759437659
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
@@ -42989,7 +43054,9 @@ static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
4298943054
JSString *p1 = JS_VALUE_GET_STRING(val);
4299043055

4299143056
obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
42992-
if (!JS_IsException(obj)) {
43057+
if (JS_IsException(obj)) {
43058+
JS_FreeValue(ctx, val);
43059+
} else {
4299343060
JS_SetObjectData(ctx, obj, val);
4299443061
JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, js_int32(p1->len), 0);
4299543062
}

quickjs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ typedef struct JSCFunctionListEntry {
12291229
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, -1 } } }
12301230
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, base } } }
12311231

1232-
JS_EXTERN void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
1232+
JS_EXTERN int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
12331233
const JSCFunctionListEntry *tab,
12341234
int len);
12351235

0 commit comments

Comments
 (0)