Skip to content

Commit 7ae2d00

Browse files
jkotasxoofx
andauthored
Fix allocation of empty array in the frozen heap for collectible types (#100444) (#100509)
* Fix allocation of empty array in the frozen heap for collectible types (#100437) * Remove Optimize from csproj * Add test for generic with static * Apply suggestions from code review * Better test * Disable tests on Mono --------- Co-authored-by: Alexandre Mutel <[email protected]>
1 parent 7d45915 commit 7ae2d00

File tree

4 files changed

+120
-1
lines changed

4 files changed

+120
-1
lines changed

src/coreclr/jit/importer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9393,7 +9393,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
93939393
CORINFO_FIELD_INFO fi;
93949394
eeGetFieldInfo(&fldToken, CORINFO_ACCESS_SET, &fi);
93959395
unsigned flagsToCheck = CORINFO_FLG_FIELD_STATIC | CORINFO_FLG_FIELD_FINAL;
9396-
if ((fi.fieldFlags & flagsToCheck) == flagsToCheck)
9396+
if (((fi.fieldFlags & flagsToCheck) == flagsToCheck) &&
9397+
((info.compCompHnd->getClassAttribs(info.compClassHnd) & CORINFO_FLG_SHAREDINST) == 0))
93979398
{
93989399
#ifdef FEATURE_READYTORUN
93999400
if (opts.IsReadyToRun())

src/coreclr/vm/frozenobjectheap.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t
4747

4848
_ASSERT(type != nullptr);
4949
_ASSERT(FOH_COMMIT_SIZE >= MIN_OBJECT_SIZE);
50+
_ASSERT(!type->Collectible());
5051

5152
// Currently we don't support frozen objects with special alignment requirements
5253
// TODO: We should also give up on arrays of doubles on 32-bit platforms.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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.Reflection;
6+
using System.Runtime.CompilerServices;
7+
using System.Runtime.Loader;
8+
using Xunit;
9+
10+
public class Runtime_100437
11+
{
12+
[Fact]
13+
[SkipOnMono("PlatformDetection.IsPreciseGcSupported false on mono", TestPlatforms.Any)]
14+
public static void TestNonCollectibleType() => TestCollectibleReadOnlyStatics(nameof(NonCollectibleType));
15+
16+
[Fact]
17+
[SkipOnMono("PlatformDetection.IsPreciseGcSupported false on mono", TestPlatforms.Any)]
18+
public static void TestNonCollectibleTypeInSharedGenericCode() => TestCollectibleReadOnlyStatics(nameof(NonCollectibleTypeInSharedGenericCode));
19+
20+
[Fact]
21+
[SkipOnMono("PlatformDetection.IsPreciseGcSupported false on mono", TestPlatforms.Any)]
22+
public static void TestNonCollectibleArrayTypeInSharedGenericCode() => TestCollectibleReadOnlyStatics(nameof(NonCollectibleArrayTypeInSharedGenericCode));
23+
24+
[Fact]
25+
[SkipOnMono("PlatformDetection.IsPreciseGcSupported false on mono", TestPlatforms.Any)]
26+
public static void TestCollectibleEmptyArray() => TestCollectibleReadOnlyStatics(nameof(CollectibleEmptyArray));
27+
28+
private static void TestCollectibleReadOnlyStatics(string methodName)
29+
{
30+
string assemblyPath = typeof(Runtime_100437).Assembly.Location;
31+
32+
// Skip this test for single file
33+
if (string.IsNullOrEmpty(assemblyPath))
34+
return;
35+
36+
WeakReference wr = CreateReadOnlyStaticWeakReference();
37+
38+
for (int i = 0; i < 10; i++)
39+
{
40+
GC.Collect();
41+
GC.WaitForPendingFinalizers();
42+
43+
if (!IsTargetAlive(wr))
44+
return;
45+
}
46+
47+
throw new Exception("Test failed - readonly static has not been collected.");
48+
49+
[MethodImpl(MethodImplOptions.NoInlining)]
50+
WeakReference CreateReadOnlyStaticWeakReference()
51+
{
52+
AssemblyLoadContext alc = new CollectibleAssemblyLoadContext();
53+
Assembly a = alc.LoadFromAssemblyPath(assemblyPath);
54+
return (WeakReference)a.GetType(nameof(Runtime_100437)).GetMethod(methodName).Invoke(null, new object[] { typeof(Runtime_100437).Assembly });
55+
}
56+
57+
[MethodImpl(MethodImplOptions.NoInlining)]
58+
bool IsTargetAlive(WeakReference wr)
59+
{
60+
return wr.Target != null;
61+
}
62+
}
63+
64+
public static WeakReference NonCollectibleType(Assembly assemblyInDefaultContext)
65+
{
66+
return new WeakReference(Holder.Singleton, trackResurrection: true);
67+
}
68+
69+
public static WeakReference NonCollectibleTypeInSharedGenericCode(Assembly assemblyInDefaultContext)
70+
{
71+
// Create instance of a non-collectible generic type definition over a collectible type
72+
var type = assemblyInDefaultContext.GetType("Runtime_100437+GenericHolder`1", throwOnError: true).MakeGenericType(typeof(Runtime_100437));
73+
var field = type.GetField("Singleton", BindingFlags.Static | BindingFlags.Public);
74+
return new WeakReference(field.GetValue(null), trackResurrection: true);
75+
}
76+
77+
public static WeakReference NonCollectibleArrayTypeInSharedGenericCode(Assembly assemblyInDefaultContext)
78+
{
79+
// Create instance of a non-collectible generic type definition over a collectible type
80+
var type = assemblyInDefaultContext.GetType("Runtime_100437+GenericArrayHolder`1", throwOnError: true).MakeGenericType(typeof(Runtime_100437));
81+
var field = type.GetField("Singleton", BindingFlags.Static | BindingFlags.Public);
82+
return new WeakReference(field.GetValue(null), trackResurrection: true);
83+
}
84+
85+
public static WeakReference CollectibleEmptyArray(Assembly assemblyInDefaultContext)
86+
{
87+
return new WeakReference(Array.Empty<Runtime_100437>(), trackResurrection: true);
88+
}
89+
90+
private class CollectibleAssemblyLoadContext : AssemblyLoadContext
91+
{
92+
public CollectibleAssemblyLoadContext()
93+
: base(isCollectible: true)
94+
{
95+
}
96+
}
97+
98+
private class Holder
99+
{
100+
public static readonly object Singleton = new object();
101+
}
102+
103+
private class GenericHolder<T>
104+
{
105+
public static readonly object Singleton = new object();
106+
}
107+
108+
private class GenericArrayHolder<T>
109+
{
110+
public static readonly int[] Singleton = new int[0];
111+
}
112+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<Compile Include="$(MSBuildProjectName).cs" />
4+
</ItemGroup>
5+
</Project>

0 commit comments

Comments
 (0)