Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>2021-07-01 22:39:04 +0300
committerGitHub <noreply@github.com>2021-07-01 22:39:04 +0300
commitb8beed27f441acbad86fca4a37f7e1287fec071f (patch)
treeced3708f05a23cac790e0e0d475a8cb3d036bfff /src/coreclr/jit
parent09785ef78f8c758350ec1ded604484bbbed0ce99 (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.h2
-rw-r--r--src/coreclr/jit/codegencommon.cpp62
-rw-r--r--src/coreclr/jit/codegenlinear.cpp7
-rw-r--r--src/coreclr/jit/compiler.h10
-rw-r--r--src/coreclr/jit/flowgraph.cpp4
-rw-r--r--src/coreclr/jit/lsrabuild.cpp9
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)
{