mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Fix continue/break at first instruction of env-allocating block (Issue #1571)
A continue/break that is the first instruction inside a lexical block which
allocates an environment (e.g. `for(;c;){ continue; eval(); const x=1; }`) was
emitted as a plain Jump, skipping the block's CloseLexicalEnvironment. The
leaked environment then caused a subsequent outer-scope `const` to initialize
in the wrong environment, producing a spurious
`ReferenceError: Cannot access '...' before initialization`.
registerJumpPositionsToComplexCase compared jump positions against frontlimit
(= lexicalBlockStartPosition, the first body instruction) with strict `>`, so a
jump located exactly at the first body instruction was never morphed into a
JumpComplexCase and the block environment was left un-popped. Use `>=` for
break/continue/labelledBreak/labelledContinue.
With the environment now unwound correctly, the hasBinding guard band-aid in
InterpreterSlowPath::initializeByName is no longer needed and is removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
60b1202a72
commit
b30b63fc63
2 changed files with 12 additions and 8 deletions
|
|
@ -183,26 +183,33 @@ struct ByteCodeGenerateContext {
|
|||
void registerJumpPositionsToComplexCase(size_t frontlimit)
|
||||
{
|
||||
ASSERT(tryCatchWithBlockStatementCount());
|
||||
// `frontlimit` is the byte position of the first instruction of the block body
|
||||
// (i.e. lexicalBlockStartPosition, set right after the BlockOperation opcode).
|
||||
// A break/continue jump located at exactly that position is the very first
|
||||
// statement of the block body and therefore IS inside the block, so it must be
|
||||
// morphed into a JumpComplexCase to unwind the block's lexical environment.
|
||||
// Using strictly greater-than (`>`) here would skip such a jump and leave the
|
||||
// block environment un-popped (Issue #1571), so the comparison must be `>=`.
|
||||
for (unsigned i = 0; i < m_breakStatementPositions.size(); i++) {
|
||||
if (m_breakStatementPositions[i] > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_breakStatementPositions[i]) == m_complexCaseStatementPositions.end()) {
|
||||
if (m_breakStatementPositions[i] >= (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_breakStatementPositions[i]) == m_complexCaseStatementPositions.end()) {
|
||||
m_complexCaseStatementPositions.insert(std::make_pair(m_breakStatementPositions[i], tryCatchWithBlockStatementCount()));
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_continueStatementPositions.size(); i++) {
|
||||
if (m_continueStatementPositions[i] > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_continueStatementPositions[i]) == m_complexCaseStatementPositions.end()) {
|
||||
if (m_continueStatementPositions[i] >= (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_continueStatementPositions[i]) == m_complexCaseStatementPositions.end()) {
|
||||
m_complexCaseStatementPositions.insert(std::make_pair(m_continueStatementPositions[i], tryCatchWithBlockStatementCount()));
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_labelledBreakStatmentPositions.size(); i++) {
|
||||
if (m_labelledBreakStatmentPositions[i].second > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labelledBreakStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
|
||||
if (m_labelledBreakStatmentPositions[i].second >= (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labelledBreakStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
|
||||
m_complexCaseStatementPositions.insert(std::make_pair(m_labelledBreakStatmentPositions[i].second, tryCatchWithBlockStatementCount()));
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_labelledContinueStatmentPositions.size(); i++) {
|
||||
if (m_labelledContinueStatmentPositions[i].second > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labelledContinueStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
|
||||
if (m_labelledContinueStatmentPositions[i].second >= (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labelledContinueStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
|
||||
m_complexCaseStatementPositions.insert(std::make_pair(m_labelledContinueStatmentPositions[i].second, tryCatchWithBlockStatementCount()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1840,10 +1840,7 @@ NEVER_INLINE void InterpreterSlowPath::storeByName(ExecutionState& state, Lexica
|
|||
NEVER_INLINE void InterpreterSlowPath::initializeByName(ExecutionState& state, LexicalEnvironment* env, const AtomicString& name, bool isLexicallyDeclaredName, const Value& value)
|
||||
{
|
||||
if (isLexicallyDeclaredName) {
|
||||
auto result = state.lexicalEnvironment()->record()->hasBinding(state, name);
|
||||
if (result.m_index != SIZE_MAX) {
|
||||
state.lexicalEnvironment()->record()->initializeBinding(state, name, value);
|
||||
}
|
||||
state.lexicalEnvironment()->record()->initializeBinding(state, name, value);
|
||||
} else {
|
||||
while (env) {
|
||||
if (env->record()->isVarDeclarationTarget()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue