ChakraCore icon indicating copy to clipboard operation
ChakraCore copied to clipboard

Crash due to Assertion in `GlobalOpt::CollectMemOpInfo`

Open bin2415 opened this issue 4 years ago • 1 comments

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())));

bin2415 avatar Apr 06 '21 15:04 bin2415

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.

rhuanjl avatar Apr 06 '21 18:04 rhuanjl