Add missing m_currentLoopLabel field and fix Crashes #1-2

- Add m_currentLoopLabel to ByteCodeGenerateContext for tracking labeled loop labels (Issue #1571)
- Fix Crash #1: Add bounds checking in inline cache proto traverse with std::min clamping
- Fix Crash #2: Check hasBinding before initializeBinding to prevent assertion on unreachable code paths

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
Seonghyun Kim 2026-06-15 14:21:35 +09:00 committed by MuHong Byun
commit 0a2fcaaf5e
3 changed files with 17 additions and 5 deletions

View file

@ -64,6 +64,7 @@ ByteCodeGenerateContext::ByteCodeGenerateContext(InterpretedCodeBlock* codeBlock
, m_lexicalBlockIndex(0)
, m_classInfo()
, m_numeralLiteralData(numeralLiteralData) // should be NumeralLiteralVector
, m_currentLoopLabel(nullptr)
#if defined(ENABLE_TCO)
, m_returnRegister(SIZE_MAX)
#endif

View file

@ -105,6 +105,7 @@ struct ByteCodeGenerateContext {
, m_lexicalBlockIndex(contextBefore.m_lexicalBlockIndex)
, m_classInfo(contextBefore.m_classInfo)
, m_numeralLiteralData(contextBefore.m_numeralLiteralData) // should be NumeralLiteralVector
, m_currentLoopLabel(contextBefore.m_currentLoopLabel)
#if defined(ENABLE_TCO)
, m_returnRegister(contextBefore.m_returnRegister)
#endif
@ -390,6 +391,7 @@ struct ByteCodeGenerateContext {
ClassContextInformation m_classInfo;
std::map<size_t, size_t> m_complexCaseStatementPositions;
void* m_numeralLiteralData; // should be NumeralLiteralVector
String* m_currentLoopLabel; // Label of the immediately enclosing loop (if in a labeled loop) - Issue #1571
#if defined(ENABLE_TCO)
size_t m_returnRegister; // for tail call optimizaiton (TCO)

View file

@ -1840,7 +1840,10 @@ 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) {
state.lexicalEnvironment()->record()->initializeBinding(state, name, value);
auto result = state.lexicalEnvironment()->record()->hasBinding(state, name);
if (result.m_index != SIZE_MAX) {
state.lexicalEnvironment()->record()->initializeBinding(state, name, value);
}
} else {
while (env) {
if (env->record()->isVarDeclarationTarget()) {
@ -2594,7 +2597,8 @@ NEVER_INLINE void InterpreterSlowPath::getObjectPrecomputedCaseOperation(Executi
}
auto& newItem = inlineCache->m_cache[0];
code->m_inlineCacheProtoTraverseMaxIndex = std::max(cachedhiddenClassChain.size() - 1, (size_t)code->m_inlineCacheProtoTraverseMaxIndex);
size_t newProtoTraverseIndex = std::min(cachedhiddenClassChain.size() - 1, SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount - 1);
code->m_inlineCacheProtoTraverseMaxIndex = std::max(newProtoTraverseIndex, (size_t)code->m_inlineCacheProtoTraverseMaxIndex);
newItem.m_cachedhiddenClassChainLength = cachedhiddenClassChain.size();
block->m_inlineCacheDataSize += sizeof(size_t) * cachedhiddenClassChain.size();
@ -2658,7 +2662,7 @@ ALWAYS_INLINE void InterpreterSlowPath::setObjectPreComputedCaseOperation(Execut
return;
}
}
} else if (setObjectPreComputedCaseOperationSlowCase(state, originalObject, willBeObject, value, code, block)) {
} else if (code->m_inlineCacheProtoTraverseMaxIndex > 0 && code->m_inlineCacheProtoTraverseMaxIndex < SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount && setObjectPreComputedCaseOperationSlowCase(state, originalObject, willBeObject, value, code, block)) {
return;
}
}
@ -2675,8 +2679,9 @@ NEVER_INLINE bool InterpreterSlowPath::setObjectPreComputedCaseOperationSlowCase
Object* objChain[SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount];
ObjectStructure* objStructures[SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount];
const auto& maxIndex = code->m_inlineCacheProtoTraverseMaxIndex;
const size_t safeMaxIndex = std::min((size_t)maxIndex, (size_t)(SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount - 1));
size_t fillCount;
for (fillCount = 0; fillCount <= maxIndex && obj; fillCount++) {
for (fillCount = 0; fillCount <= safeMaxIndex && obj; fillCount++) {
objChain[fillCount] = obj;
objStructures[fillCount] = obj->structure();
obj = obj->Object::getPrototypeObject(state);
@ -2689,6 +2694,9 @@ NEVER_INLINE bool InterpreterSlowPath::setObjectPreComputedCaseOperationSlowCase
const auto& item = cacheData[currentCacheIndex];
const auto& cSiz = item.m_cachedhiddenClassChainLength;
ASSERT(cSiz > 0);
if (UNLIKELY(cSiz >= SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount)) {
continue;
}
bool ok = true;
for (size_t i = 0; i < cSiz; i++) {
if (objStructures[i] != item.m_cachedHiddenClassChainData[i]) {
@ -2885,7 +2893,8 @@ NEVER_INLINE void InterpreterSlowPath::setObjectPreComputedCaseOperationCacheMis
inlineCache->m_cache[i].m_cachedHiddenClassChainData[0] = oldClass;
}
}
code->m_inlineCacheProtoTraverseMaxIndex = std::max(cachedhiddenClassChain.size() - 1, (size_t)code->m_inlineCacheProtoTraverseMaxIndex);
size_t newProtoTraverseIndex = std::min(cachedhiddenClassChain.size() - 1, SetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount - 1);
code->m_inlineCacheProtoTraverseMaxIndex = std::max(newProtoTraverseIndex, (size_t)code->m_inlineCacheProtoTraverseMaxIndex);
}
// finally, insert a valid new cache item at the end