Bug 61086 - Can't override method that has struct as parameter if it is declared in native protocol
Summary: Can't override method that has struct as parameter if it is declared in nativ...
Alias: None
Product: iOS
Classification: Xamarin
Component: General ()
Version: XI 11.6 (xcode9.2)
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Future Cycle (TBD)
Assignee: Rolf Bjarne Kvinge [MSFT]
Depends on:
Reported: 2017-12-13 10:30 UTC by andrii
Modified: 2018-01-11 18:31 UTC (History)
4 users (show)

Is this bug a regression?: No
Last known good build:

Crash in overriden method from native protocol that has a struct as parameter (117.86 KB, application/zip)
2017-12-13 10:30 UTC, andrii
Build log. (12.67 KB, text/plain)
2017-12-14 13:01 UTC, Manuel de la Peña [MSFT]

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report for Bug 61086 on Developer Community or GitHub if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: Developer Community HTML or GitHub Markdown
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:

Description andrii 2017-12-13 10:30:18 UTC
Created attachment 25990 [details]
Crash in overriden method from native protocol that has a struct as parameter

I have a protocol and a class that implements the protocol.
Native class implements method with structure as parameter. The method is declared in the protocol.

I have bundings for protocol and methods.
If I create subclass on Xamarin side with override of that method it produces a crash when method is called.

If I do the same without protocols in hierarchy it works without crashing.

I've attached project that reproduces the crash
Comment 1 Manuel de la Peña [MSFT] 2017-12-14 13:00:41 UTC
Confirming the bug with the following env:

=== Visual Studio Community 2017 for Mac ===

Version Preview - Internal Dogfood (7.3.2 build 10)
Installation UUID: 8d12e55e-3489-463f-ac52-8cb4573c5a81
	Mono (2017-10/99db2351979) (64-bit)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 508000039

=== NuGet ===


=== .NET Core ===

Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
SDK: /usr/local/share/dotnet/sdk/2.0.0/Sdks
SDK Versions:
MSBuild SDKs: /Library/Frameworks/Mono.framework/Versions/5.8.0/lib/mono/msbuild/15.0/bin/Sdks

=== Xamarin.Profiler ===

Version: 1.6.0
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

=== Xamarin.Android ===

Version: (Visual Studio Community)
Android SDK: /Users/mandel/Library/Developer/Xamarin/android-sdk-macosx
	Supported Android versions:
		4.0.3 (API level 15)
		4.3   (API level 18)
		4.4   (API level 19)
		5.0   (API level 21)
		6.0   (API level 23)
		7.0   (API level 24)
		7.1   (API level 25)

SDK Tools Version: 25.2.5
SDK Platform Tools Version: 25.0.4
SDK Build Tools Version: 25.0.1

Java SDK: /usr
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)

Android Designer EPL code available here:

=== Xamarin Inspector ===

Version: 1.3.2
Hash: 461f09a
Branch: 1.3-release
Build date: Tue, 03 Oct 2017 18:26:57 GMT
Client compatibility: 1

=== Apple Developer Tools ===

Xcode 9.2 (13772)
Build 9C40b

=== Xamarin.iOS ===

Version: (Visual Studio Community)
Hash: 6857dfcc
Branch: xcode9.2
Build date: 2017-12-04 21:20:41-0500

=== Xamarin.Mac ===

Version: (Visual Studio Community)

=== Build Information ===

Release ID: 703020010
Git revision: d203af94011a0bfba0685a67e73281a53c25e393
Build date: 2017-12-07 11:00:27-05
Xamarin addins: 1981a9e7c28d5c3839bb5dc2a0dcaf56fe640906
Build lane: monodevelop-lion-dogfood-vNext

=== Operating System ===

Mac OS X 10.13.1
Darwin 17.2.0 Darwin Kernel Version 17.2.0
    Fri Sep 29 18:27:05 PDT 2017
    root:xnu-4570.20.62~3/RELEASE_X86_64 x86_64

=== Enabled user installed addins ===

Internet of Things (IoT) development (Preview) 7.1
Comment 2 Manuel de la Peña [MSFT] 2017-12-14 13:01:35 UTC
Created attachment 26004 [details]
Build log.
Comment 3 Rolf Bjarne Kvinge [MSFT] 2018-01-11 18:30:18 UTC
The problem is:

* Xamarin.iOS needs to know the size of each argument when the method is called (to properly marshal structs to managed code)
* In this process, we ask the object instance for its method signature like this:

    [self methodSignatureForSelector: sel];

* and unfortunately we get back something that doesn't have enough information about the argument:

    <NSMethodSignature: 0x614000269e40>
    argument 2: -------- -------- -------- --------
        type encoding ({) '{?}'

Note the "{?}" part, basically NSMethodSignature just gave up.

Looking into Apple's code, the information is available, the methodSignatureForSelector: implementation finds the method in the protocol, and the signature there (for the entire method) is "v32@0:8{?=i(?=csiqfd^v*^s^i^q^f^d)}16", which parsed gives "{?=i(?=csiqfd^v*^s^i^q^f^d)}16" as the type encoding for the argument we need (and it has enough information to the get the argument size).

Trying that as input to NSMethodSignature, reveals that NSMethodSignature doesn't understand it:

    (lldb) p (char *) [[NSMethodSignature signatureWithObjCTypes: "v32@0:8{?=i(?=csiqfd^v*^s^i^q^f^d)}16"] getArgumentTypeAtIndex: 2]
    (char *) $23 = 0x0000614000093b75 "{?}" 

So the fix would be to re-implement [NSObject methodSignatureForSelector:] and [NSMethodSignature signatureWithObjCTypes:] in our runtime, preserving all the information we need instead of dropping it (while I don't expect it to be particularly complex, it's nevertheless full of corner cases, and in a very sensitive location).

Fortunately there's a trivial workaround: add "--registrar:static" to the additional mtouch arguments in the project's iOS Build options (this is only needed for the simulator; the static registrar is already the default for device builds).