From 49bd3b8a1d11e4b062b9d43830ba0e7e6d317512 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Mon, 28 Nov 2022 21:01:11 +0100 Subject: [PATCH] JIT: Fix initblk/cpblk and STORE_DYN_BLK size mismatch STORE_DYN_BLK turns into a call to JIT_MemSet/JIT_MemCpy that go quite directly to memset/memcpy, so the size is actually a native uint. This can cause problems since the JIT does not make any normalization guarantees above 32 bits. Fix #78912 --- src/coreclr/jit/gtlist.h | 2 +- src/coreclr/jit/importer.cpp | 11 +++++++++++ src/coreclr/jit/morphblock.cpp | 3 +-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index cde991961ab81..2593bae80f2ff 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -87,7 +87,7 @@ GTNODE(OBJ , GenTreeObj ,0,GTK_UNOP|GTK_EXOP) GTNODE(STORE_OBJ , GenTreeObj ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. GTNODE(BLK , GenTreeBlk ,0,GTK_UNOP|GTK_EXOP) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) GTNODE(STORE_BLK , GenTreeBlk ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) -GTNODE(STORE_DYN_BLK , GenTreeStoreDynBlk ,0,GTK_SPECIAL|GTK_NOVALUE) // Dynamically sized block store +GTNODE(STORE_DYN_BLK , GenTreeStoreDynBlk ,0,GTK_SPECIAL|GTK_NOVALUE) // Dynamically sized block store, with native uint size GTNODE(NULLCHECK , GenTreeIndir ,0,GTK_UNOP|GTK_NOVALUE) // Null checks the source GTNODE(ARR_LENGTH , GenTreeArrLen ,0,GTK_UNOP|GTK_EXOP) // single-dimension (SZ) array length diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index df7834354af19..982c64f467f0b 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -10893,6 +10893,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) op2 = gtNewOperNode(GT_INIT_VAL, TYP_INT, op2); } +#ifdef TARGET_64BIT + // STORE_DYN_BLK takes a native uint size as it turns into call to memset. + op3 = gtNewCastNode(TYP_I_IMPL, op3, /* fromUnsigned */ true, TYP_U_IMPL); +#endif + op1 = new (this, GT_STORE_DYN_BLK) GenTreeStoreDynBlk(op1, op2, op3); size = 0; @@ -10920,6 +10925,12 @@ void Compiler::impImportBlockCode(BasicBlock* block) else { op2 = gtNewOperNode(GT_IND, TYP_STRUCT, op2); + +#ifdef TARGET_64BIT + // STORE_DYN_BLK takes a native uint size as it turns into call to memcpy. + op3 = gtNewCastNode(TYP_I_IMPL, op3, /* fromUnsigned */ true, TYP_U_IMPL); +#endif + op1 = new (this, GT_STORE_DYN_BLK) GenTreeStoreDynBlk(op1, op2, op3); if ((prefixFlags & PREFIX_VOLATILE) != 0) diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 1ff93cf9e4628..5bffde1a74477 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -1571,9 +1571,8 @@ GenTree* Compiler::fgMorphStoreDynBlock(GenTreeStoreDynBlk* tree) if (tree->gtDynamicSize->IsIntegralConst()) { int64_t size = tree->gtDynamicSize->AsIntConCommon()->IntegralValue(); - assert(FitsIn(size)); - if (size != 0) + if ((size != 0) && FitsIn(size)) { GenTree* lhs = gtNewBlockVal(tree->Addr(), static_cast(size)); GenTree* asg = gtNewAssignNode(lhs, tree->Data());