Skip to content

Commit

Permalink
Fix bug with top-level-await with class variable init
Browse files Browse the repository at this point in the history
* Prevent native stack overflow
* Fix bug in ExecutionState::inPauserScope

Signed-off-by: Seonghyun Kim <[email protected]>
  • Loading branch information
ksh8281 committed Oct 24, 2023
1 parent cdb47df commit d8ea09f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 29 deletions.
56 changes: 29 additions & 27 deletions src/runtime/ExecutionPauser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,43 +74,45 @@ ExecutionPauser::ExecutionPauser(ExecutionState& state, Object* sourceObject, Ex
{
}

class ExecutionPauserExecutionStateParentBinder {
public:
ExecutionPauserExecutionStateParentBinder(ExecutionState& state, ExecutionState* originalState)
: m_originalState(originalState)
{
m_oldParent = m_originalState->parent();


ExecutionState* pstate = m_originalState;
while (pstate) {
if (pstate == &state) {
// AsyncGeneratorObject::asyncGeneratorResolve can make loop
return;

Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Object* source, const Value& resumeValue, bool isAbruptReturn, bool isAbruptThrow, StartFrom from)
{
class ExecutionPauserExecutionStateParentAndStackLimitBinder {
public:
ExecutionPauserExecutionStateParentAndStackLimitBinder(ExecutionState& state, ExecutionState* originalState)
: m_originalState(originalState)
{
m_oldParent = m_originalState->parent();

ExecutionState* pstate = m_originalState;
m_originalState->m_stackLimit = state.context()->vmInstance()->stackLimit();
while (pstate) {
if (pstate == &state) {
// AsyncGeneratorObject::asyncGeneratorResolve can make loop
return;
}
pstate = pstate->parent();
}
pstate = pstate->parent();
}

m_originalState->setParent(&state);
}
m_originalState->setParent(&state);
}

~ExecutionPauserExecutionStateParentBinder()
{
m_originalState->setParent(m_oldParent);
}
~ExecutionPauserExecutionStateParentAndStackLimitBinder()
{
m_originalState->setParent(m_oldParent);
m_originalState->m_stackLimit = 0;
}

ExecutionState* m_originalState;
ExecutionState* m_oldParent;
};
ExecutionState* m_originalState;
ExecutionState* m_oldParent;
};

Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Object* source, const Value& resumeValue, bool isAbruptReturn, bool isAbruptThrow, StartFrom from)
{
ExecutionState* originalState = self->m_executionState;
while (!originalState->pauseSource()) {
originalState = originalState->parent();
}

ExecutionPauserExecutionStateParentBinder parentBinder(state, originalState);
ExecutionPauserExecutionStateParentAndStackLimitBinder parentBinder(state, originalState);

if (self->m_resumeValueIndex != REGISTER_LIMIT) {
self->m_registerFile[self->m_resumeValueIndex] = resumeValue;
Expand Down
6 changes: 5 additions & 1 deletion src/runtime/ExecutionState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,11 @@ bool ExecutionState::inPauserScope()
auto env = state->lexicalEnvironment();
auto record = env->record();
if (record->isGlobalEnvironmentRecord() || record->isModuleEnvironmentRecord()) {
return state->hasRareData() && state->rareData()->m_pauseSource;
// class variable initializer can call {GlobalEnvironment, ModuleEnvironment}
// so we should check above of {GlobalEnvironment, ModuleEnvironment}
if (state->hasRareData() && state->rareData()->m_pauseSource) {
return true;
}
} else if (record->isDeclarativeEnvironmentRecord() && record->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) {
return record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord()->functionObject()->isScriptGeneratorFunctionObject()
|| record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord()->functionObject()->isScriptAsyncFunctionObject()
Expand Down
2 changes: 1 addition & 1 deletion test/vendortest

0 comments on commit d8ea09f

Please sign in to comment.