Skip to content
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

[NativeAOT] Method overrides with covariant return type don't work in all cases #96175

Closed
AlexDoeringEnvision opened this issue Dec 19, 2023 · 5 comments · Fixed by #106716
Closed
Assignees
Labels
area-NativeAOT-coreclr in-pr There is an active PR which will close this issue when it is merged
Milestone

Comments

@AlexDoeringEnvision
Copy link

Description

when NativeAOT finds an covariant override it will pick that type as new return type and ignore further overrides that don't return the same type
tested with NativeAOT net7/8

Reproduction Steps

var impl = new Impl();
var subImpl = new SubImpl();
Console.WriteLine(impl.FromBase());
Console.WriteLine(impl.FromType());

Console.WriteLine(subImpl.FromBase());
Console.WriteLine(subImpl.FromType());


class Base
{
    public Base FromBase()
    {
        return FromType();
    }

    public virtual Base FromType()
    {
        return new Base();
    }
}

class Impl : Base
{
    public override Impl FromType()
    {
        return new Impl();
    }
}

class SubImpl : Impl
{
    // not called from FromBase()
    public override SubImpl FromType()
    {
        return new SubImpl();
    }
}

Expected behavior

Impl
Impl
SubImpl
SubImpl

Actual behavior

Impl
Impl
Impl
SubImpl

Regression?

No response

Known Workarounds

don't use covariant return type

Configuration

.NET 8, Windows 10, x64, NativeAOT.

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Dec 19, 2023
@ghost
Copy link

ghost commented Dec 19, 2023

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

when NativeAOT finds an covariant override it will pick that type as new return type and ignore further overrides that don't return the same type
tested with NativeAOT net7/8

Reproduction Steps

var impl = new Impl();
var subImpl = new SubImpl();
Console.WriteLine(impl.FromBase());
Console.WriteLine(impl.FromType());

Console.WriteLine(subImpl.FromBase());
Console.WriteLine(subImpl.FromType());


class Base
{
    public Base FromBase()
    {
        return FromType();
    }

    public virtual Base FromType()
    {
        return new Base();
    }
}

class Impl : Base
{
    public override Impl FromType()
    {
        return new Impl();
    }
}

class SubImpl : Impl
{
    // not called from FromBase()
    public override SubImpl FromType()
    {
        return new SubImpl();
    }
}

Expected behavior

Impl
Impl
SubImpl
SubImpl

Actual behavior

Impl
Impl
Impl
SubImpl

Regression?

No response

Known Workarounds

don't use covariant return type

Configuration

.NET 8, Windows 10, x64, NativeAOT.

Other information

No response

Author: AlexDoeringEnvision
Assignees: -
Labels:

area-NativeAOT-coreclr

Milestone: -

@MichalStrehovsky
Copy link
Member

This is an issue in the virtual method resolution algorithm: when asked "what method on SubImpl implements Base::FromType, it answers Impl::FromType". This is because the algorithm fails to consider the fact that Base::FromType was overriden by Impl::FromType and that one is overriden by SubImpl::FromType. It's likely nobody but @davidwrighton is able to make fixes in this codebase. I'd only make this worse if I touch it. We don't run the targeted covariant returns tests for native AOT because the way they were written (mixing valid cases and invalid cases that expect typeloadexceptions) would require us to have a full fidelity typeloadexception emulator that we don't have.

This has been a bug ever since covariant returns got added to the managed type system in #35308 for crossgen2. It would also show up as a bug in crossgen2, but the compiler (neither crossgen2, nor ilc) actually doesn't devirtualize any covariant returns due to this code:

MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl);
MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);
if (slotDefiningMethodImpl != slotDefiningMethodDecl)
{
// If the derived method's slot does not match the vtable slot,
// bail on devirtualization, as the method was installed into
// the vtable slot via an explicit override and even if the
// method is final, the slot may not be.
//
// Note the jit could still safely devirtualize if it had an exact
// class, but such cases are likely rare.
devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_SLOT;
impl = null;
}

That one was also added for crossgen2's sake and I don't actually understand why we do it the way we do it. Fixing it would make this bug also show up in crossgen2.

@agocke agocke added this to the 9.0.0 milestone May 17, 2024
@jeffschwMSFT jeffschwMSFT removed the untriaged New issue has not been triaged by the area owner label May 22, 2024
@filipnavara
Copy link
Member

We just accidentally hit this in our app when implementing handlers in MAUI code.

We have CarouselViewHandler and CarouselViewController classes under both the Microsoft.Maui.Controls.Handlers.Items namespace and the MailClient.Mobile.iOS.Handlers namespace. The latter ones are are derived from the former ones. There's complex hierarchy of generic types that originally defines the CreateController method (MAUI code).

We had the following code:

namespace MailClient.Mobile.iOS.Handlers
{
	class CarouselViewHandler : Microsoft.Maui.Controls.Handlers.Items.CarouselViewHandler
	{
		protected override CarouselViewController CreateController(CarouselView newElement, ItemsViewLayout layout)
		{
			return new CarouselViewController(newElement, layout);
		}
	}
}

The CreateController method was never called. Once we figured out what it happening the workaround is trivial:

@@ -8,7 +8,7 @@ namespace MailClient.Mobile.iOS.Handlers
 {
        class CarouselViewHandler : Microsoft.Maui.Controls.Handlers.Items.CarouselViewHandler
        {
-               protected override CarouselViewController CreateController(CarouselView newElement, ItemsViewLayout layout)
+               protected override Microsoft.Maui.Controls.Handlers.Items.CarouselViewController CreateController(CarouselView newElement, ItemsViewLayout layout)
                {
                        return new CarouselViewController(newElement, layout);
                }

@AndyAyersMS
Copy link
Member

That one was also added for crossgen2's sake and I don't actually understand why we do it the way we do it. Fixing it would make this bug also show up in crossgen2.

For context on that bit of slot-testing code, see the discussion in #10809

@MichalStrehovsky
Copy link
Member

That one was also added for crossgen2's sake and I don't actually understand why we do it the way we do it. Fixing it would make this bug also show up in crossgen2.

For context on that bit of slot-testing code, see the discussion in #10809

If I understand it correctly, the discussion happened when this was an IL-level corner case. These can now be hit with regular C#.

@agocke agocke modified the milestones: 9.0.0, 10.0.0 Aug 14, 2024
davidwrighton added a commit to davidwrighton/runtime that referenced this issue Aug 20, 2024
…in ilc.exe for native aot

- This was causing real C# applications to fail to behave correctly on NativeAOT builds
- Enable testing for covariant byref returns on nativeaot (split testing up so that the tests do not expect TypeLoadException, which NativeAOT doesn't reliably generate)
- Fix implementation of SynthesizedPgoIncompatible project file flag for test script generation
- Put copy of attributetesting.il test into the managed type system unit test suite
- Add regression test of issue noted in dotnet#96175 into managed type system unit test suite
- Update workflow documentation to include a better path to finding details on how to run CoreCLR and Libraries tests for Native AOT

Fixes dotnet#96175
@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Aug 20, 2024
@agocke agocke modified the milestones: 10.0.0, 9.0.0 Aug 30, 2024
github-actions bot pushed a commit that referenced this issue Sep 5, 2024
…in ilc.exe for native aot - This was causing real C# applications to fail to behave correctly on NativeAOT builds - Enable testing for covariant byref returns on nativeaot (split testing up so that the tests do not expect TypeLoadException, which NativeAOT doesn't reliably generate) - Fix implementation of SynthesizedPgoIncompatible project file flag for test script generation - Put copy of attributetesting.il test into the managed type system unit test suite - Add regression test of issue noted in #96175 into managed type system unit test suite - Update workflow documentation to include a better path to finding details on how to run CoreCLR and Libraries tests for Native AOT

Fixes #96175
jeffschwMSFT added a commit that referenced this issue Sep 5, 2024
…d as expected in ilc.exe for native aot (#107409)

* Fix a case in MethodImpl overriding which wasn't handled as expected in ilc.exe for native aot - This was causing real C# applications to fail to behave correctly on NativeAOT builds - Enable testing for covariant byref returns on nativeaot (split testing up so that the tests do not expect TypeLoadException, which NativeAOT doesn't reliably generate) - Fix implementation of SynthesizedPgoIncompatible project file flag for test script generation - Put copy of attributetesting.il test into the managed type system unit test suite - Add regression test of issue noted in #96175 into managed type system unit test suite - Update workflow documentation to include a better path to finding details on how to run CoreCLR and Libraries tests for Native AOT

Fixes #96175

* Fix test with incorrect IL

* Make the remaining TODO comments follow existing practice in this file for todo comments

* Fix test exclusion for mono llvmaot

* Address nits from code review

---------

Co-authored-by: David Wrighton <davidwr@microsoft.com>
Co-authored-by: Jeff Schwartz <jeffschw@microsoft.com>
jtschuster pushed a commit to jtschuster/runtime that referenced this issue Sep 17, 2024
…in ilc.exe for native aot (dotnet#106716)

* Fix a case in MethodImpl overriding which wasn't handled as expected in ilc.exe for native aot
- This was causing real C# applications to fail to behave correctly on NativeAOT builds
- Enable testing for covariant byref returns on nativeaot (split testing up so that the tests do not expect TypeLoadException, which NativeAOT doesn't reliably generate)
- Put copy of attributetesting.il test into the managed type system unit test suite
- Add regression test of issue noted in dotnet#96175 into managed type system unit test suite
- Update workflow documentation to include a better path to finding details on how to run CoreCLR and Libraries tests for Native AOT

Fixes dotnet#96175
sirntar pushed a commit to sirntar/runtime that referenced this issue Sep 30, 2024
…in ilc.exe for native aot (dotnet#106716)

* Fix a case in MethodImpl overriding which wasn't handled as expected in ilc.exe for native aot
- This was causing real C# applications to fail to behave correctly on NativeAOT builds
- Enable testing for covariant byref returns on nativeaot (split testing up so that the tests do not expect TypeLoadException, which NativeAOT doesn't reliably generate)
- Put copy of attributetesting.il test into the managed type system unit test suite
- Add regression test of issue noted in dotnet#96175 into managed type system unit test suite
- Update workflow documentation to include a better path to finding details on how to run CoreCLR and Libraries tests for Native AOT

Fixes dotnet#96175
@github-actions github-actions bot locked and limited conversation to collaborators Oct 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-NativeAOT-coreclr in-pr There is an active PR which will close this issue when it is merged
Projects
Archived in project
7 participants