Skip to content

Commit 331ddf9

Browse files
authored
[release/9.0-staging] JIT: Fix invalid removal of explicit zeroing in methods without .localsinit (#115568)
If we skip storing a field local because we know it is dead, then assertions about the struct local are no longer valid, so invalidate them in that case. Without this change we could end up using the assertion about the struct local to remove a future store to the particular field, which would leave no zeroing of that field, and would be observable.
1 parent bdcc494 commit 331ddf9

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

src/coreclr/jit/morphblock.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,6 @@ void MorphInitBlockHelper::PropagateBlockAssertions()
250250
//
251251
void MorphInitBlockHelper::PropagateExpansionAssertions()
252252
{
253-
// Consider doing this for FieldByField as well
254-
//
255253
if (m_comp->optLocalAssertionProp && (m_transformationDecision == BlockTransformation::OneStoreBlock))
256254
{
257255
m_comp->fgAssertionGen(m_store);
@@ -408,6 +406,7 @@ void MorphInitBlockHelper::TryInitFieldByField()
408406
if (m_comp->fgGlobalMorph && m_dstLclNode->IsLastUse(i))
409407
{
410408
JITDUMP("Field-by-field init skipping write to dead field V%02u\n", fieldLclNum);
409+
m_comp->fgKillDependentAssertionsSingle(m_dstLclNum DEBUGARG(m_store));
411410
continue;
412411
}
413412

@@ -1236,6 +1235,7 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField()
12361235
{
12371236
INDEBUG(unsigned dstFieldLclNum = m_comp->lvaGetDesc(m_dstLclNum)->lvFieldLclStart + i);
12381237
JITDUMP("Field-by-field copy skipping write to dead field V%02u\n", dstFieldLclNum);
1238+
m_comp->fgKillDependentAssertionsSingle(m_dstLclNum DEBUGARG(m_store));
12391239
continue;
12401240
}
12411241

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using Xunit;
7+
8+
public static class Runtime_113658
9+
{
10+
[Fact]
11+
public static int TestEntryPoint()
12+
{
13+
FillStackWithGarbage();
14+
long? nullable = FaultyDefaultNullable<long?>();
15+
return (int)(100 + nullable.GetValueOrDefault());
16+
}
17+
18+
[MethodImpl(MethodImplOptions.NoInlining)]
19+
private static void FillStackWithGarbage()
20+
{
21+
stackalloc byte[256].Fill(0xcc);
22+
}
23+
24+
[MethodImpl(MethodImplOptions.NoInlining)]
25+
[SkipLocalsInit]
26+
private static T FaultyDefaultNullable<T>()
27+
{
28+
// When T is a Nullable<T> (and only in that case), we support returning null
29+
if (default(T) is null && typeof(T).IsValueType)
30+
return default!;
31+
32+
throw new InvalidOperationException("Not nullable");
33+
}
34+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>True</Optimize>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="$(MSBuildProjectName).cs" />
7+
</ItemGroup>
8+
</Project>

0 commit comments

Comments
 (0)