Skip to content

Commit 8d5ec2b

Browse files
committed
Handle missing and empty _Formals in dump format
The distinction matters when loading back: if _Formals was omitted, we don't want to load back an empty _Formals array for a function template because it then breaks function instance .length computation.
1 parent 38fa644 commit 8d5ec2b

1 file changed

Lines changed: 40 additions & 40 deletions

File tree

src-input/duk_api_bytecode.c

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define DUK__SER_STRING 0x00
2020
#define DUK__SER_NUMBER 0x01
2121
#define DUK__BYTECODE_INITIAL_ALLOC 256
22+
#define DUK__NO_FORMALS 0xffffffffUL
2223

2324
/*
2425
* Dump/load helpers, xxx_raw() helpers do no buffer checks
@@ -183,40 +184,44 @@ DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_b
183184

184185
tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
185186
if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
186-
duk_hobject *h;
187-
duk_uint_fast32_t i;
187+
duk_harray *h;
188+
duk_uint32_t i;
188189

189-
h = DUK_TVAL_GET_OBJECT(tv);
190+
/* Here we rely on _Formals being a dense array containing
191+
* strings. This should be the case unless _Formals has been
192+
* tweaked by the application (which we don't support right
193+
* now).
194+
*/
195+
h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv);
190196
DUK_ASSERT(h != NULL);
197+
DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
198+
DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
191199

192-
/* We know _Formals is dense and all entries will be in the
193-
* array part. GC and finalizers shouldn't affect _Formals
194-
* so side effects should be fine.
195-
*/
196-
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
200+
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
201+
DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
202+
DUK_RAW_WRITE_U32_BE(p, h->length);
203+
204+
for (i = 0; i < h->length; i++) {
197205
duk_tval *tv_val;
198206
duk_hstring *varname;
199207

200-
tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
208+
tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
201209
DUK_ASSERT(tv_val != NULL);
202-
if (DUK_TVAL_IS_STRING(tv_val)) {
203-
/* Array is dense and contains only strings, but ASIZE may
204-
* be larger than used part and there are UNUSED entries.
205-
*/
206-
varname = DUK_TVAL_GET_STRING(tv_val);
207-
DUK_ASSERT(varname != NULL);
208-
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); /* won't be confused with terminator */
209-
210-
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
211-
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
212-
p = duk__dump_hstring_raw(p, varname);
213-
}
210+
DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
211+
212+
varname = DUK_TVAL_GET_STRING(tv_val);
213+
DUK_ASSERT(varname != NULL);
214+
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
215+
216+
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
217+
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
218+
p = duk__dump_hstring_raw(p, varname);
214219
}
215220
} else {
216-
DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit empty list"));
221+
DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
222+
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
223+
DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
217224
}
218-
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
219-
DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
220225
return p;
221226
}
222227

@@ -394,6 +399,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
394399
duk_idx_t idx_base;
395400
duk_tval *tv1;
396401
duk_uarridx_t arr_idx;
402+
duk_uarridx_t arr_limit;
397403
duk_hobject *func_env;
398404
duk_bool_t need_pop;
399405

@@ -659,26 +665,20 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
659665
duk_compact_m1(ctx);
660666
duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
661667

662-
/* If _Formals wasn't present in the original function, the list
663-
* here will be empty. Same happens if _Formals was present but
664-
* had zero length. We can omit _Formals from the result if its
665-
* length is zero and matches nargs.
668+
/* _Formals may have been missing in the original function, which is
669+
* handled using a marker length.
666670
*/
667-
duk_push_array(ctx); /* _Formals */
668-
for (arr_idx = 0; ; arr_idx++) {
669-
/* XXX: awkward */
670-
p = duk__load_string_raw(ctx, p);
671-
if (duk_get_length(ctx, -1) == 0) {
672-
duk_pop(ctx);
673-
break;
671+
arr_limit = DUK_RAW_READ_U32_BE(p);
672+
if (arr_limit != DUK__NO_FORMALS) {
673+
duk_push_array(ctx); /* _Formals */
674+
for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
675+
p = duk__load_string_raw(ctx, p);
676+
duk_put_prop_index(ctx, -2, arr_idx);
674677
}
675-
duk_put_prop_index(ctx, -2, arr_idx);
676-
}
677-
if (arr_idx == 0 && h_fun->nargs == 0) {
678-
duk_pop(ctx);
679-
} else {
680678
duk_compact_m1(ctx);
681679
duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
680+
} else {
681+
DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
682682
}
683683

684684
/* Return with final function pushed on stack top. */

0 commit comments

Comments
 (0)