-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix allocation of empty array in the frozen heap for collectible types #100444
Fix allocation of empty array in the frozen heap for collectible types #100444
Conversation
My colleague that has been investigating this is also suggesting adding an assert in runtime/src/coreclr/vm/frozenobjectheap.cpp Lines 48 to 49 in 34d13b2
Thoughts? I can add it as part of this PR. |
Sounds good to me. We should also add a test that hits it. |
Let me know if you need help with the test. |
Yes, please, a starting place would be helpful! 😅 |
Yes, runtime/src/coreclr/gc/gcinterface.h Line 974 in d1cc577
|
Thanks! I meant from C# as I'm not familiar how I will be able to make tests only from C++. |
We prefer to test observable behavior like that the program does not crash. You do not need an API that checks if an object is instantiated in a frozen heap for that. |
This will crash with high probability due to this bug: using System.Runtime.Loader;
public class Program
{
static void Main()
{
WeakReference[] wrs = new WeakReference[10];
for (int i = 0; i < wrs.Length; i++)
{
var alc = new MyAssemblyLoadContext();
var a = alc.LoadFromAssemblyPath(typeof(Program).Assembly.Location);
wrs[i] = (WeakReference)a.GetType("Program").GetMethod("Work").Invoke(null, null);
GC.Collect();
}
foreach (var wr in wrs)
{
Console.WriteLine(wr.Target);
}
}
public static WeakReference Work()
{
return new WeakReference(Array.Empty<Program>());
}
}
class MyAssemblyLoadContext : AssemblyLoadContext
{
public MyAssemblyLoadContext()
: base(isCollectible: true)
{
}
} |
Makes sense! Where should I add such a test? In |
As I was writing the test, I have realized that there is an opposite problem too: The frozen object allocated in shared generic static constructor may end up leaking: class MyG<T>
{
// This will be allocated on frozen heap, but it is going to leak if T is collectible
static object s = new object();
} I am not sure what's the best way to fix this leak. We can either detect and reject these problematic patterns as canidates for frozen heap allocation, or we need to pass the containing generic type to the MayBeFrozen allocation helper. cc @EgorBo |
I would add it under src\tests\JIT\Regression\JitBlue. This is a codegen related problem, so the regression test for it belongs under JIT tests. |
Added the test with commit 1189eec but I don't know how to run it. I tried |
Good point! I propose this patch here: - if ((fi.fieldFlags & flagsToCheck) == flagsToCheck)
+ if (((fi.fieldFlags & flagsToCheck) == flagsToCheck) &&
+ ((info.compCompHnd->getClassAttribs(info.compClassHnd) & CORINFO_FLG_SHAREDINST) == 0)) the logic to detect candidates for NonGC allocators is quite trivial here, I have a prototype for a more advanced version, but it's not ready yet. |
Ah, it's a bit too conservative. Basically, with this patch we'll never optimize |
6050688
to
81578a1
Compare
Yes, the conservative fix can be backport candidate. The full fix would be hard to backport. @xoofx Would you like to include it in this PR? (The test for this case can have similar structure - it should use weak handle to verify that the object is gone after the collectible assembly is unloaded.) |
src/tests/JIT/Regression/JitBlue/Runtime_100437/Runtime_100437.cs
Outdated
Show resolved
Hide resolved
src/tests/JIT/Regression/JitBlue/Runtime_100437/Runtime_100437.cs
Outdated
Show resolved
Hide resolved
src/tests/JIT/Regression/JitBlue/Runtime_100437/Runtime_100437.csproj
Outdated
Show resolved
Hide resolved
81578a1
to
a9abd1d
Compare
I have pushed test update that hits all interesting cases. |
I also usually struggle finding the right syntax for issues.props 😐 |
/backport to release/8.0-staging |
Started backporting to release/8.0-staging: https://github.com/dotnet/runtime/actions/runs/8517805878 |
@jkotas backporting to release/8.0-staging failed, the patch most likely resulted in conflicts: $ git am --3way --ignore-whitespace --keep-non-patch changes.patch
Applying: Fix allocation of empty array in the frozen heap for collectible types (#100437)
Using index info to reconstruct a base tree...
M src/coreclr/vm/frozenobjectheap.cpp
M src/coreclr/vm/gchelpers.cpp
Falling back to patching base and 3-way merge...
Auto-merging src/coreclr/vm/gchelpers.cpp
CONFLICT (content): Merge conflict in src/coreclr/vm/gchelpers.cpp
Auto-merging src/coreclr/vm/frozenobjectheap.cpp
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0001 Fix allocation of empty array in the frozen heap for collectible types (#100437)
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128 Please backport manually! |
@jkotas an error occurred while backporting to release/8.0-staging, please check the run log for details! Error: git am failed, most likely due to a merge conflict. |
#100444) * 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: Jan Kotas <[email protected]>
Most of the hard work investigating the crash from our side came from @alexey-zakharov We are super glad that a quick fix was found, as we are heavily relying on collectible ALC and that bug haunted several crashes on our CI. Thanks a lot for helping with it! |
dotnet#100444) * Fix allocation of empty array in the frozen heap for collectible types (dotnet#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: Jan Kotas <[email protected]> (cherry picked from commit 78f7707)
#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]>
dotnet#100444) * Fix allocation of empty array in the frozen heap for collectible types (dotnet#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: Jan Kotas <[email protected]>
Fixes #100437
An empty array should not be allocated on a frozen heap if its type is coming from a collectible assembly.
Might be difficult to bring a proper test (e.g is there an API to check if an object is instantiated in a frozen heap?). If it is required, guidance appreciated.
This fix should be backported to
net8.0
as well.