summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/codegen.h3
-rw-r--r--src/jit/codegenarmarch.cpp38
-rw-r--r--src/jit/codegencommon.cpp56
-rw-r--r--src/jit/codegenxarch.cpp64
-rw-r--r--src/jit/instr.cpp33
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il67
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj24
7 files changed, 188 insertions, 97 deletions
diff --git a/src/jit/codegen.h b/src/jit/codegen.h
index fcbf4d8ec9..ef1443d0fa 100644
--- a/src/jit/codegen.h
+++ b/src/jit/codegen.h
@@ -1413,9 +1413,6 @@ public:
void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
- void instGen_Store_Imm_Into_Lcl(
- var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
-
#ifdef DEBUG
void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
#endif
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index 87cbd6d1d5..9476e6595d 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -568,6 +568,44 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla
}
//---------------------------------------------------------------------
+// genSetGSSecurityCookie: Set the "GS" security cookie in the prolog.
+//
+// Arguments:
+// initReg - register to use as a scratch register
+// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if
+// this call sets 'initReg' to a non-zero value.
+//
+// Return Value:
+// None
+//
+void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed)
+{
+ assert(compiler->compGeneratingProlog);
+
+ if (!compiler->getNeedsGSSecurityCookie())
+ {
+ return;
+ }
+
+ if (compiler->gsGlobalSecurityCookieAddr == nullptr)
+ {
+ noway_assert(compiler->gsGlobalSecurityCookieVal != 0);
+ // initReg = #GlobalSecurityCookieVal; [frame.GSSecurityCookie] = initReg
+ genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL);
+ getEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0);
+ }
+ else
+ {
+ instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, initReg, (ssize_t)compiler->gsGlobalSecurityCookieAddr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, initReg, initReg, 0);
+ regSet.verifyRegUsed(initReg);
+ getEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0);
+ }
+
+ *pInitRegZeroed = false;
+}
+
+//---------------------------------------------------------------------
// genIntrinsic - generate code for a given intrinsic
//
// Arguments
diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
index 4edcda90b9..bb81361d9b 100644
--- a/src/jit/codegencommon.cpp
+++ b/src/jit/codegencommon.cpp
@@ -6483,62 +6483,6 @@ void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed
#endif // !ARM64 !ARM
}
-/*-----------------------------------------------------------------------------
- *
- * Set the "GS" security cookie in the prolog.
- */
-
-void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed)
-{
- assert(compiler->compGeneratingProlog);
-
- if (!compiler->getNeedsGSSecurityCookie())
- {
- return;
- }
-
- noway_assert(compiler->gsGlobalSecurityCookieAddr || compiler->gsGlobalSecurityCookieVal);
-
- if (compiler->gsGlobalSecurityCookieAddr == nullptr)
- {
-#ifdef _TARGET_AMD64_
- // eax = #GlobalSecurityCookieVal64; [frame.GSSecurityCookie] = eax
- getEmitter()->emitIns_R_I(INS_mov, EA_PTRSIZE, REG_RAX, compiler->gsGlobalSecurityCookieVal);
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_RAX, compiler->lvaGSSecurityCookie, 0);
-#else
- // mov dword ptr [frame.GSSecurityCookie], #GlobalSecurityCookieVal
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, compiler->gsGlobalSecurityCookieVal,
- compiler->lvaGSSecurityCookie, 0, initReg);
-#endif
- }
- else
- {
- regNumber reg;
-#ifdef _TARGET_XARCH_
- // Always use EAX on x86 and x64
- // On x64, if we're not moving into RAX, and the address isn't RIP relative, we can't encode it.
- reg = REG_EAX;
-#else
- // We will just use the initReg since it is an available register
- reg = initReg;
-#endif
-
- *pInitRegZeroed = false;
-
-#if CPU_LOAD_STORE_ARCH
- instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, reg, (ssize_t)compiler->gsGlobalSecurityCookieAddr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, reg, reg, 0);
- regSet.verifyRegUsed(reg);
-#else
- // mov reg, dword ptr [compiler->gsGlobalSecurityCookieAddr]
- // mov dword ptr [frame.GSSecurityCookie], reg
- getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, reg, (ssize_t)compiler->gsGlobalSecurityCookieAddr);
- regSet.verifyRegUsed(reg);
-#endif
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, compiler->lvaGSSecurityCookie, 0);
- }
-}
-
#ifdef PROFILING_SUPPORTED
//-----------------------------------------------------------------------------------
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index 9184c09b39..521aaca407 100644
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -49,6 +49,61 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla
}
}
+//---------------------------------------------------------------------
+// genSetGSSecurityCookie: Set the "GS" security cookie in the prolog.
+//
+// Arguments:
+// initReg - register to use as a scratch register
+// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if
+// this call sets 'initReg' to a non-zero value.
+//
+// Return Value:
+// None
+//
+void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed)
+{
+ assert(compiler->compGeneratingProlog);
+
+ if (!compiler->getNeedsGSSecurityCookie())
+ {
+ return;
+ }
+
+ if (compiler->gsGlobalSecurityCookieAddr == nullptr)
+ {
+ noway_assert(compiler->gsGlobalSecurityCookieVal != 0);
+#ifdef _TARGET_AMD64_
+ if ((int)compiler->gsGlobalSecurityCookieVal != compiler->gsGlobalSecurityCookieVal)
+ {
+ // initReg = #GlobalSecurityCookieVal64; [frame.GSSecurityCookie] = initReg
+ genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL);
+ getEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0);
+ *pInitRegZeroed = false;
+ }
+ else
+#endif
+ {
+ // mov dword ptr [frame.GSSecurityCookie], #GlobalSecurityCookieVal
+ getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaGSSecurityCookie, 0,
+ (int)compiler->gsGlobalSecurityCookieVal);
+ }
+ }
+ else
+ {
+ // Always use EAX on x86 and x64
+ // On x64, if we're not moving into RAX, and the address isn't RIP relative, we can't encode it.
+ // mov eax, dword ptr [compiler->gsGlobalSecurityCookieAddr]
+ // mov dword ptr [frame.GSSecurityCookie], eax
+ getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, REG_EAX, (ssize_t)compiler->gsGlobalSecurityCookieAddr);
+ regSet.verifyRegUsed(REG_EAX);
+ getEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, REG_EAX, compiler->lvaGSSecurityCookie, 0);
+ if (initReg == REG_EAX)
+ {
+ *pInitRegZeroed = false;
+ }
+ }
+}
+
/*****************************************************************************
*
* Generate code to check that the GS cookie wasn't thrashed by a buffer
@@ -325,10 +380,9 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
curNestingSlotOffs = (unsigned)(filterEndOffsetSlotOffs - ((finallyNesting + 1) * TARGET_POINTER_SIZE));
// Zero out the slot for the next nesting level
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaShadowSPslotsVar,
- curNestingSlotOffs - TARGET_POINTER_SIZE);
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, LCL_FINALLY_MARK, compiler->lvaShadowSPslotsVar,
- curNestingSlotOffs);
+ getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaShadowSPslotsVar,
+ curNestingSlotOffs - TARGET_POINTER_SIZE, 0);
+ getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaShadowSPslotsVar, curNestingSlotOffs, LCL_FINALLY_MARK);
// Now push the address where the finally funclet should return to directly.
if (!(block->bbFlags & BBF_RETLESS_CALL))
@@ -1914,7 +1968,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
unsigned curNestingSlotOffs;
curNestingSlotOffs = filterEndOffsetSlotOffs - ((finallyNesting + 1) * TARGET_POINTER_SIZE);
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaShadowSPslotsVar, curNestingSlotOffs);
+ getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaShadowSPslotsVar, curNestingSlotOffs, 0);
break;
#endif // !FEATURE_EH_FUNCLETS
diff --git a/src/jit/instr.cpp b/src/jit/instr.cpp
index 020a783e66..dd3854600d 100644
--- a/src/jit/instr.cpp
+++ b/src/jit/instr.cpp
@@ -2365,39 +2365,6 @@ void CodeGen::instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, in
getEmitter()->emitIns_S_R(ins_Store(dstType), size, srcReg, varNum, offs);
}
-/*****************************************************************************
- *
- * Machine independent way to move an immediate into a stack based local variable
- */
-void CodeGen::instGen_Store_Imm_Into_Lcl(
- var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse)
-{
-#ifdef _TARGET_XARCH_
-#ifdef _TARGET_AMD64_
- if ((EA_SIZE(sizeAttr) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(sizeAttr)))
- {
- assert(!"Invalid immediate for instGen_Store_Imm_Into_Lcl");
- }
- else
-#endif // _TARGET_AMD64_
- {
- getEmitter()->emitIns_S_I(ins_Store(dstType), sizeAttr, varNum, offs, (int)imm);
- }
-#elif defined(_TARGET_ARMARCH_)
- // Load imm into a register
- regNumber immReg = regToUse;
- assert(regToUse != REG_NA);
- instGen_Set_Reg_To_Imm(sizeAttr, immReg, (ssize_t)imm);
- instGen_Store_Reg_Into_Lcl(dstType, immReg, varNum, offs);
- if (EA_IS_RELOC(sizeAttr))
- {
- regSet.verifyRegUsed(immReg);
- }
-#else // _TARGET_*
-#error "Unknown _TARGET_"
-#endif // _TARGET_*
-}
-
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il
new file mode 100644
index 0000000000..e20cc03a79
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.assembly extern System.Runtime { }
+.assembly GitHub_24278 { }
+.module GitHub_24278.exe
+
+// GitHub 24278: a bug is reproduced when
+// 1) a register is used in the prolog for initializing GSSecurityCookie (i.e. the register contains a random non-zero value) and
+// 2) the same register holds a must-init GC variable in the next basic block and
+// 3) the variable is live at the beginning of this basic block.
+// The register was not zeroed at the end of the prolog and this was causing segmentation fault during GC.Collect().
+//
+// This happens in MainMethod at IL_0013:
+// V_0 is not initialized by IL instructions of one of the path to IL_0013 and must be zeroed in the prolog since it is live at IL_0013.
+
+.class private auto ansi beforefieldinit GitHub_24278.Program
+ extends [System.Runtime]System.Object
+{
+ .method private hidebysig static bool True() cil managed noinlining
+ {
+ // Code size 2 (0x2)
+ .maxstack 8
+ IL_0000: ldc.i4.1
+ IL_0001: ret
+ } // end of method Program::True
+
+ .method private hidebysig static void Use(int32 arg0) cil managed noinlining
+ {
+ // Code size 6 (0x6)
+ .maxstack 8
+ IL_0000: call void [System.Runtime]System.GC::Collect()
+ IL_0005: ret
+ } // end of method Program::Use
+
+ .method private hidebysig static void MainMethod() cil managed noinlining
+ {
+ //
+ .maxstack 1
+ .locals init (object V_0)
+ IL_0000: call bool GitHub_24278.Program::True()
+ IL_0005: brtrue.s IL_000d
+
+ IL_0007: newobj instance void [System.Runtime]System.Object::.ctor()
+ IL_000c: stloc.0
+ IL_000d: ldc.i4.s 32
+ IL_000f: conv.u
+ IL_0010: localloc
+ IL_0012: ldind.i4
+ IL_0013: call void GitHub_24278.Program::Use(int32)
+ IL_0018: ldloc.0
+ IL_0019: call void [System.Runtime]System.GC::KeepAlive(object)
+ IL_001e: ret
+ } // end of method Program::MainMethod
+
+ .method private hidebysig static int32
+ Main(string[] args) cil managed
+ {
+ .entrypoint
+ // Code size 8 (0x8)
+ .maxstack 8
+ IL_0000: call void GitHub_24278.Program::MainMethod()
+ IL_0005: ldc.i4.s 100
+ IL_0007: ret
+ } // end of method Program::Main
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj
new file mode 100644
index 0000000000..506f235e2f
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <PropertyGroup>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="GitHub_24278.il" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>