Skip to content

[generator] Fix NRE from return type not getting set for abstract methods with generics. #834

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

Merged
merged 4 commits into from
May 13, 2021

Conversation

jpobst
Copy link
Contributor

@jpobst jpobst commented May 11, 2021

Fixes: dotnet/android#5921

For the following generic-laden Java:

public interface MyInterface<R> {
  R Next (int count);
}

public abstract class MyClass<T> implements MyInterface<T> {
  public T Next (int count);
}

We need to generate an explicit method declaration:

Java.Lang.Object Com.Example.IMyInterface.Next (int count)
{
  throw new NotImplementedException ();
}

However when we did the generator refactor this code code path was not tested, and the code short-circuits, bypassing setting the ReturnType and Parameters collection.

Attempting to generate the method results in an NRE:

ReturnType.WriteTypeReference (writer);

   at Xamarin.SourceWriter.MethodWriter.WriteReturnType(CodeWriter writer) in C:\code\xamarin-android-backport\external\Java.Interop\src\Xamarin.SourceWriter\Models\MethodWriter.cs:line 154

This commit ensures the ReturnType and Parameters collection is set before the method returns.

Pre-refactor code: https://github.com/xamarin/java.interop/blob/main/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs#L1175-L1181

@jpobst jpobst marked this pull request as ready for review May 11, 2021 13:58
@jonpryor
Copy link
Member

@jpobst: I'm confused. If I extract the XML within WriteBoundMethodAbstractDeclarationWithGenericReturn(), I'm able to bind it using java.interop/main without any error:

$ mono bin/Debug/generator.exe -o ji-834.main ~/ji-834.xml --codegen-target=XAJavaInterop1
# no error

Additionally, the generated C# source doesn't contain explicitly implemented interface members either; there is no Com.Example.RangeIterator.Next() method:

$ grep -r Com.Example.RangeIterator.Next ji-834.main
# no output

(Why was I bothering in the first place? For the commit message, to attempt to describe why we were explicitly implementing a method in the first place, to help "backfill" historical knowledge. On a related note, the original PR message doesn't quite make sense: the "set-up" mentions MyInterface and MyClass, while the generated code is for RangeIterator (?!). Additionally, RangeIterator is being explicitly implemented, but classes can't be explicitly implemented, that's an interface member feature.)

I thus can't be sure that the fix here is an actual fix, given that the test here doesn't trigger the exception mentioned in dotnet/android#5921.

@jpobst
Copy link
Contributor Author

jpobst commented May 11, 2021

Interesting, if you revert the change to BoundMethodAbstractDeclaration.cs the unit test will fail with the specified exception. However I may have cut down the test case too much that it is no longer self-contained.

Here's the original api.xml that causes the problem on 16.9.

api.xml.fixed.txt

@jpobst
Copy link
Contributor Author

jpobst commented May 11, 2021

It looks like the test fails while real generator does not because we do not use the full pipeline in our tests. Specifically, our tests do not call gen.FixupExplicitImplementation () which eliminates the explicitly implemented method in real generator. Thus real generator never hits the code path that causes the NRE.

@jonpryor
Copy link
Member

@jpobst wrote

Thus real generator never hits the code path that causes the NRE.

This sounds like we don't yet have a repro for the a code path which caused "real generator" to NRE then. :-(

@jpobst
Copy link
Contributor Author

jpobst commented May 11, 2021

The code path that crashes is simply trying to generate any BoundMethodAbstractDeclaration where method.RetVal.IsGeneric && gen != null. How we get to that code path isn't really relevant. I feel like the unit test is sufficient for demonstrating that the crash in that path has been fixed.

jonpryor added 3 commits May 12, 2021 19:23
Context: #834 (comment)
Context: https://gist.github.com/jonpryor/41a0a920d27e5a761f499da4ade791a8

I was operating under the (deluded?) assumption that it should be
possible to use the XML within
`WriteBoundMethodAbstractDeclarationWithGenericReturn()` to reproduce
the `NullReferenceException`, but I was unable to do so.

I thus returned to the [full API declaration][0] to recreate a minimal
test case which *would* result in a `NullReferenceException`, and found
one.

Oddly, the "missing piece" to trigger the NRE was *nested types* (?!):
the original PR #834 had `RangeIterator` as a top-level type, and in
this situation I wasn't able to get an NRE with main.

Once I "reverted" it to a nested `FlowIterator.RangeIterator` type,
it broke.

I don't know if that's the *only* relevant change, as I changed other
pieces as well:

  * Simpler (no parameters) `next()` method
  * Fixed the `//interface/@jni-signature` value for `FlowIterator`

Regardless, this "newer" XML *does* crash, but also only with
`--codegen-target=XAJavaInterop1`.  It doesn't NRE w/o `--codegen-target`:

    $ mono bin/Debug/generator.exe -o yyy ji-834-fixed.xml --codegen-target=XAJavaInterop1
    …
    Unhandled Exception:
    System.NullReferenceException: Object reference not set to an instance of an object
      at Xamarin.SourceWriter.MethodWriter.WriteReturnType (Xamarin.SourceWriter.CodeWriter writer)
      at Xamarin.SourceWriter.MethodWriter.WriteSignature (Xamarin.SourceWriter.CodeWriter writer)
      at Xamarin.SourceWriter.MethodWriter.Write (Xamarin.SourceWriter.CodeWriter writer)

[0]: #834 (comment)
@jonpryor jonpryor merged commit 131c149 into main May 13, 2021
@jonpryor jonpryor deleted the fix-bound-abstract-method branch May 13, 2021 18:32
@jpobst jpobst added this to the 11.4 (16.11 / 8.11) milestone Jun 15, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Apr 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Visual Studio update to 16.9.4 cause binding library build fail
2 participants