ChakraCore
ChakraCore copied to clipboard
Crash due to Assertion in `GlobalOpt::CollectMemOpInfo`
poc:
function main() {
for (let v3 = -2; v3 < 1337; v3 = v3 + 0) {
const v4 = v3++;
}
}
main();
backtrace is:
(gdb) bt
#0 0x000055cd2ac3320a in GlobOpt::CollectMemOpInfo (this=0x7fb322aeefd0, instrBegin=<optimized out>, instr=<optimized out>, src1Val=0x7fb324fbd270, src2Val=<optimized out>) at /src/chakracore/lib/Backend/GlobOpt.cpp:2360
#1 0x000055cd2abf1ea0 in GlobOpt::OptInstr (this=0x7fb322aeefd0, instr=<optimized out>, isInstrRemoved=0x7fb322aedd20) at /src/chakracore/lib/Backend/GlobOpt.cpp:2739
#2 0x000055cd2abe17a7 in GlobOpt::OptBlock (this=<optimized out>, block=0x7fb324fb3508) at /src/chakracore/lib/Backend/GlobOpt.cpp:520
#3 0x000055cd2abdbcd7 in GlobOpt::ForwardPass (this=0x7fb322aeefd0) at /src/chakracore/lib/Backend/GlobOpt.cpp:401
#4 0x000055cd2abd8637 in GlobOpt::Optimize (this=<optimized out>) at /src/chakracore/lib/Backend/GlobOpt.cpp:211
#5 0x000055cd2ab831c7 in Func::TryCodegen (this=<optimized out>) at /src/chakracore/lib/Backend/Func.cpp:457
#6 0x000055cd2ab819f8 in Func::Codegen (alloc=0x7fb322af04a0, workItem=0x7fb324fa1030, threadContextInfo=0x623000000198, scriptContextInfo=0x622000000158, outputData=0x7fb322af0740, epInfo=0x7fb325165180, runtimeInfo=<optimized out>,
polymorphicInlineCacheInfo=<optimized out>, codeGenAllocators=<optimized out>, codeGenProfiler=<optimized out>, isBackgroundJIT=<optimized out>) at /src/chakracore/lib/Backend/Func.cpp:325
#7 0x000055cd2a62990f in NativeCodeGenerator::CodeGen (this=<optimized out>, pageAllocator=<optimized out>, workItemData=0x612000000540, jitWriteData=..., foreground=false, epInfo=0x7fb325165180) at /src/chakracore/lib/Backend/NativeCodeGenerator.cpp:890
#8 0x000055cd2a62eaf8 in NativeCodeGenerator::CodeGen (this=0x6130000005d8, pageAllocator=<optimized out>, workItem=<optimized out>, foreground=64) at /src/chakracore/lib/Backend/NativeCodeGenerator.cpp:1007
#9 0x000055cd2a637e80 in NativeCodeGenerator::Process (this=<optimized out>, job=<optimized out>, threadData=0x615000002658) at /src/chakracore/lib/Backend/NativeCodeGenerator.cpp:1907
#10 0x000055cd2a77bad4 in JsUtil::BackgroundJobProcessor::Process (this=<optimized out>, job=<optimized out>, threadData=0x615000002658) at /src/chakracore/lib/Common/Common/Jobs.cpp:1037
#11 0x000055cd2a77c2ad in JsUtil::BackgroundJobProcessor::Run (this=0x612000000098, threadData=<optimized out>) at /src/chakracore/lib/Common/Common/Jobs.cpp:1135
#12 0x000055cd2a7740d0 in JsUtil::BackgroundJobProcessor::StaticThreadProc (lpParam=<optimized out>) at /src/chakracore/lib/Common/Common/Jobs.cpp:1319
#13 0x000055cd26fc3adb in CorUnix::CPalThread::ThreadEntry (pvParam=0x61c000001880) at /src/chakracore/pal/src/thread/pal_thread.cpp:1605
#14 0x000055cd26e2df3f in __asan::AsanThread::ThreadStart(unsigned long, __sanitizer::atomic_uintptr_t*) ()
#15 0x00007fb32a3986db in start_thread (arg=0x7fb322af1700) at pthread_create.c:463
#16 0x00007fb32990771f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
The source code of the assertion is:
// If an instr where the dst is an induction variable (and thus is being written to) is not caught by a case in the above
// switch statement (which implies that this instr does not contributes to a inductionVariableChangeInfo) and in the default
// case does not set doMemOp to false (which implies that this instr does not invalidate this MemOp), then FailFast as we
// should not be performing a MemOp under these conditions.
AssertOrFailFast(!instr->GetDst() || instr->m_opcode == Js::OpCode::IncrLoopBodyCount || !loop->memOpInfo ||
// Refer to "Case #2" described above in this function. For the following IR:
// Line #1: s4(s2) = Add_I4 s3(s1) 1
// Line #2: s3(s1) = Ld_A s4(s2)
// do not consider line #2 as a violating instr
(instr->m_opcode == Js::OpCode::Ld_I4 &&
prevInstr && (prevInstr->m_opcode == Js::OpCode::Add_I4 || prevInstr->m_opcode == Js::OpCode::Sub_I4) &&
instr->GetSrc1()->IsRegOpnd() &&
instr->GetDst()->IsRegOpnd() &&
prevInstr->GetDst()->IsRegOpnd() &&
instr->GetDst()->GetStackSym() == prevInstr->GetSrc1()->GetStackSym() &&
instr->GetSrc1()->GetStackSym() == prevInstr->GetDst()->GetStackSym()) ||
!loop->memOpInfo->inductionVariableChangeInfoMap->ContainsKey(GetVarSymID(instr->GetDst()->GetStackSym())));
This is a very strange bug - an AssertOrFailFast should catch abort in a release build BUT this doesn't.
It only hits in a Debug build - this is an incorrect path being followed in Debug builds only. In a release build we follow a different path and never get to this line.
So, going to have to look at what's different between Release and Debug builds when running this snippet.