Skip to content

Commit ff94327

Browse files
fix incorrect stack manipulation in FRAME_TO_JSON for objects
1 parent fa212fd commit ff94327

1 file changed

Lines changed: 19 additions & 8 deletions

File tree

core/vm.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3301,20 +3301,31 @@ class Interpreter {
33013301
} break;
33023302
case Value::OBJECT:
33033303
const auto obj = static_cast<HeapObject *>(scratch.v.h);
3304-
// TODO: Do this by constructing a FRAME_INVARIANT here?
3305-
runInvariants(f.location, obj);
3304+
const auto loc = f.location;
3305+
3306+
f.kind = FRAME_OBJECT_TO_JSON;
3307+
f.first = true;
3308+
f.val = scratch;
3309+
f.str.clear();
33063310
std::map<UString, const Identifier *> fields;
33073311
for (const auto &field : objectFields(obj, true)) {
33083312
fields[field->name] = field;
33093313
}
3310-
if (fields.empty()) {
3314+
std::swap(f.manifestFields, fields); // Swap instead of deep copy.
3315+
3316+
// runInvariants re-enters evaluate() so it messes with the stack.
3317+
// Hence we need to make sure that the FRAME_OBJECT_TO_JSON is set up _first_,
3318+
// even if the object is "empty" (no fields to manifest).
3319+
// TODO: Do this by constructing a FRAME_INVARIANT here?
3320+
runInvariants(loc, obj);
3321+
3322+
// fields was already cleared above, and `f` may have been invalidated
3323+
// by the stack-manipulation inside runInvariants. So we need to explicitly
3324+
// look at stack.top().manifestFields.
3325+
if (stack.top().manifestFields.empty()) {
33113326
scratch = makeString(U"{ }");
33123327
} else {
3313-
f.kind = FRAME_OBJECT_TO_JSON;
3314-
f.first = true;
3315-
f.val = scratch;
3316-
f.str.clear();
3317-
std::swap(f.manifestFields, fields); // Swap instead of deep copy.
3328+
assert(stack.top().kind == FRAME_OBJECT_TO_JSON);
33183329
goto replaceframe;
33193330
}
33203331
break;

0 commit comments

Comments
 (0)