diff options
author | Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com> | 2021-07-01 22:39:04 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-01 22:39:04 +0300 |
commit | b8beed27f441acbad86fca4a37f7e1287fec071f (patch) | |
tree | ced3708f05a23cac790e0e0d475a8cb3d036bfff /src/coreclr/jit | |
parent | 09785ef78f8c758350ec1ded604484bbbed0ce99 (diff) |
Poison address-exposed user variables in debug (#54685)
* Poison address exposed user variables in debug code
Fix #13072
* Run jit-format
* Use named scratch register and kill it in LSRA
* Enable it unconditionally for testing purposes
* Remove unnecessary modified reg on ARM
* Fix OSR and get rid of test code
* Remove a declaration
* Undo modified comment and use modulo instead of and
* Add a test
* Rephrase comment
Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com>
* Disable poisoning test on mono
* Remove outdated line
Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com>
Diffstat (limited to 'src/coreclr/jit')
-rw-r--r-- | src/coreclr/jit/codegen.h | 2 | ||||
-rw-r--r-- | src/coreclr/jit/codegencommon.cpp | 62 | ||||
-rw-r--r-- | src/coreclr/jit/codegenlinear.cpp | 7 | ||||
-rw-r--r-- | src/coreclr/jit/compiler.h | 10 | ||||
-rw-r--r-- | src/coreclr/jit/flowgraph.cpp | 4 | ||||
-rw-r--r-- | src/coreclr/jit/lsrabuild.cpp | 9 |
6 files changed, 92 insertions, 2 deletions
diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index ae862974158..132a763c06b 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -348,6 +348,8 @@ protected: void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn); + void genPoisonFrame(regMaskTP bbRegLiveIn); + #if defined(TARGET_ARM) bool genInstrWithConstant( diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index e99f047c061..cfbdf1e9033 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -12528,3 +12528,65 @@ void CodeGenInterface::VariableLiveKeeper::dumpLvaVariableLiveRanges() const } #endif // DEBUG #endif // USING_VARIABLE_LIVE_RANGE + +//----------------------------------------------------------------------------- +// genPoisonFrame: Generate code that places a recognizable value into address exposed variables. +// +// Remarks: +// This function emits code to poison address exposed non-zero-inited local variables. We expect this function +// to be called when emitting code for the scratch BB that comes right after the prolog. +// The variables are poisoned using 0xcdcdcdcd. +void CodeGen::genPoisonFrame(regMaskTP regLiveIn) +{ + assert(compiler->compShouldPoisonFrame()); + assert((regLiveIn & genRegMask(REG_SCRATCH)) == 0); + + // The first time we need to poison something we will initialize a register to the largest immediate cccccccc that + // we can fit. + bool hasPoisonImm = false; + for (unsigned varNum = 0; varNum < compiler->info.compLocalsCount; varNum++) + { + LclVarDsc* varDsc = compiler->lvaGetDesc(varNum); + if (varDsc->lvIsParam || varDsc->lvMustInit || !varDsc->lvAddrExposed) + { + continue; + } + + assert(varDsc->lvOnFrame); + + if (!hasPoisonImm) + { +#ifdef TARGET_64BIT + genSetRegToIcon(REG_SCRATCH, (ssize_t)0xcdcdcdcdcdcdcdcd, TYP_LONG); +#else + genSetRegToIcon(REG_SCRATCH, (ssize_t)0xcdcdcdcd, TYP_INT); +#endif + hasPoisonImm = true; + } + +// For 64-bit we check if the local is 8-byte aligned. For 32-bit, we assume everything is always 4-byte aligned. +#ifdef TARGET_64BIT + bool fpBased; + int addr = compiler->lvaFrameAddress((int)varNum, &fpBased); +#else + int addr = 0; +#endif + int size = (int)compiler->lvaLclSize(varNum); + int end = addr + size; + for (int offs = addr; offs < end;) + { +#ifdef TARGET_64BIT + if ((offs % 8) == 0 && end - offs >= 8) + { + GetEmitter()->emitIns_S_R(ins_Store(TYP_LONG), EA_8BYTE, REG_SCRATCH, (int)varNum, offs - addr); + offs += 8; + continue; + } +#endif + + assert((offs % 4) == 0 && end - offs >= 4); + GetEmitter()->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, REG_SCRATCH, (int)varNum, offs - addr); + offs += 4; + } + } +} diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 796c128b98e..8bf1f852ffd 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -395,6 +395,13 @@ void CodeGen::genCodeForBBlist() compiler->compCurStmt = nullptr; compiler->compCurLifeTree = nullptr; + // Emit poisoning into scratch BB that comes right after prolog. + // We cannot emit this code in the prolog as it might make the prolog too large. + if (compiler->compShouldPoisonFrame() && compiler->fgBBisScratch(block)) + { + genPoisonFrame(newLiveRegSet); + } + // Traverse the block in linear order, generating code for each node as we // as we encounter it. CLANG_FORMAT_COMMENT_ANCHOR; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 9086613da28..ca8daaf7a96 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9839,6 +9839,16 @@ public: return (info.compUnmanagedCallCountWithGCTransition > 0); } + // Returns true if address-exposed user variables should be poisoned with a recognizable value + bool compShouldPoisonFrame() + { +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (opts.IsOSR()) + return false; +#endif + return !info.compInitMem && opts.compDbgCode; + } + #if defined(DEBUG) void compDispLocalVars(); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index e7a281cdeca..04faed33f50 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -2603,8 +2603,8 @@ void Compiler::fgAddInternal() noway_assert(!compIsForInlining()); // The backend requires a scratch BB into which it can safely insert a P/Invoke method prolog if one is - // required. Create it here. - if (compMethodRequiresPInvokeFrame()) + // required. Similarly, we need a scratch BB for poisoning. Create it here. + if (compMethodRequiresPInvokeFrame() || compShouldPoisonFrame()) { fgEnsureFirstBBisScratch(); fgFirstBB->bbFlags |= BBF_DONT_REMOVE; diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index f4ea6fb3579..cb04ddddf51 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -2333,6 +2333,15 @@ void LinearScan::buildIntervals() // assert(block->isRunRarely()); } + // For frame poisoning we generate code into scratch BB right after prolog since + // otherwise the prolog might become too large. In this case we will put the poison immediate + // into the scratch register, so it will be killed here. + if (compiler->compShouldPoisonFrame() && compiler->fgFirstBBisScratch() && block == compiler->fgFirstBB) + { + addRefsForPhysRegMask(genRegMask(REG_SCRATCH), currentLoc + 1, RefTypeKill, true); + currentLoc += 2; + } + LIR::Range& blockRange = LIR::AsRange(block); for (GenTree* node : blockRange) { |