Skip to content

Commit b4ee10b

Browse files
fix incorrect stack manipulation in FRAME_TO_JSON for objects
1 parent b401394 commit b4ee10b

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
@@ -3214,20 +3214,31 @@ class Interpreter {
32143214
} break;
32153215
case Value::OBJECT:
32163216
const auto obj = static_cast<HeapObject *>(scratch.v.h);
3217-
// TODO: Do this by constructing a FRAME_INVARIANT here?
3218-
runInvariants(f.location, obj);
3217+
const auto loc = f.location;
3218+
3219+
f.kind = FRAME_OBJECT_TO_JSON;
3220+
f.first = true;
3221+
f.val = scratch;
3222+
f.str.clear();
32193223
std::map<UString, const Identifier *> fields;
32203224
for (const auto &field : objectFields(obj, true)) {
32213225
fields[field->name] = field;
32223226
}
3223-
if (fields.empty()) {
3227+
std::swap(f.manifestFields, fields); // Swap instead of deep copy.
3228+
3229+
// runInvariants re-enters evaluate() so it messes with the stack.
3230+
// Hence we need to make sure that the FRAME_OBJECT_TO_JSON is set up _first_,
3231+
// even if the object is "empty" (no fields to manifest).
3232+
// TODO: Do this by constructing a FRAME_INVARIANT here?
3233+
runInvariants(loc, obj);
3234+
3235+
// fields was already cleared above, and `f` may have been invalidated
3236+
// by the stack-manipulation inside runInvariants. So we need to explicitly
3237+
// look at stack.top().manifestFields.
3238+
if (stack.top().manifestFields.empty()) {
32243239
scratch = makeString(U"{ }");
32253240
} else {
3226-
f.kind = FRAME_OBJECT_TO_JSON;
3227-
f.first = true;
3228-
f.val = scratch;
3229-
f.str.clear();
3230-
std::swap(f.manifestFields, fields); // Swap instead of deep copy.
3241+
assert(stack.top().kind == FRAME_OBJECT_TO_JSON);
32313242
goto replaceframe;
32323243
}
32333244
break;

0 commit comments

Comments
 (0)