Bug 17040 - Null Reference Exception at runtime on iOS using the = operator on Arrays in F#
Summary: Null Reference Exception at runtime on iOS using the = operator on Arrays in F#
Status: RESOLVED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 7.0.6.x
Hardware: Macintosh Mac OS
: --- blocker
Target Milestone: Untriaged
Assignee: Zoltan Varga
URL:
Depends on:
Blocks:
 
Reported: 2014-01-03 12:44 UTC by Dave Thomas
Modified: 2014-01-07 12:51 UTC (History)
1 user (show)

Tags:
Is this bug a regression?: ---
Last known good build:

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 on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Dave Thomas 2014-01-03 12:44:46 UTC
A normal Array comparison in F# looks like this:

let areSame = [|0|] = [|0|]
Assert.IsTrue(areSame)

On a real iOS device this throws a Null Reference Exception

I tried to pull out some of the Generic Equality code out of FSharp.Core to create a small repo sample but I can't get this to behave the same at runtime, I suspect there is a deeper interaction with the AOT code or the GC at runtime.

I have a github repo with this code available as an F# unit test project for iOS:  

https://github.com/7sharp9/GenericEqualityBug
Comment 1 Rolf Bjarne Kvinge [MSFT] 2014-01-06 08:11:47 UTC
Zoltan, this sounds like some sort of AOT problem.
Comment 2 Dave Thomas 2014-01-06 08:25:21 UTC
As far as I can tell, in the context of FSharp.Core  arr1 becomes null at the point I marked below.  

let rec GenericEqualityObj (er:bool) (iec:System.Collections.IEqualityComparer) ((xobj:obj),(yobj:obj)) : bool = 
                (*if objEq xobj yobj then true else  *)
                match xobj,yobj with 
                 | null,null -> true
                 | null,_ -> false
                 | _,null -> false
                 | (:? string as xs),(:? string as ys) -> System.String.Equals(xs,ys)
                 // Permit structural equality on arrays
                 | (:? System.Array as arr1),_ -> 
                     match arr1,yobj with 
                     // Fast path
                     | (:? (obj[]) as arr1),    (:? (obj[]) as arr2)      -> GenericEqualityObjArray er iec arr1 arr2
                     // Fast path
                     | (:? (byte[]) as arr1),    (:? (byte[]) as arr2)     -> GenericEqualityByteArray arr1 arr2
                     | (:? (int32[]) as arr1),   (:? (int32[]) as arr2)   -> GenericEqualityInt32Array arr1 arr2
                     | (:? (int64[]) as arr1),   (:? (int64[]) as arr2)   -> GenericEqualityInt64Array arr1 arr2
                     | (:? (char[]) as arr1),    (:? (char[]) as arr2)     -> GenericEqualityCharArray arr1 arr2
                     | (:? (float32[]) as arr1), (:? (float32[]) as arr2) -> GenericEqualitySingleArray er arr1 arr2
                     | (:? (float[]) as arr1),   (:? (float[]) as arr2)     -> GenericEqualityDoubleArray er arr1 arr2
                     | _                     ,   (:? System.Array as arr2) -> 
                        //** arr1 is null here **
                        GenericEqualityArbArray er iec arr1 arr2
                     | _ -> xobj.Equals(yobj)
                 | (:? IStructuralEquatable as x1),_ -> x1.Equals(yobj,iec)
                 // Ensure ER NaN semantics on recursive calls
                 | (:? float as f1), (:? float as f2) ->
                    if er && (not (# "ceq" f1 f1 : bool #)) && (not (# "ceq" f2 f2 : bool #)) then true // NAN with ER semantics
                    else (# "ceq" f1 f2 : bool #) // PER semantics
                 | (:? float32 as f1), (:? float32 as f2) ->
                    if er && (not (# "ceq" f1 f1 : bool #)) && (not (# "ceq" f2 f2 : bool #)) then true // NAN with ER semantics
                    else (# "ceq" f1 f2 : bool #)  // PER semantics
                 | _ -> xobj.Equals(yobj)

I can't repro this with the code extracted out of FSharp.Core though.
Comment 3 Zoltan Varga 2014-01-07 12:51:27 UTC
Fixed in mono master 208c3ed4129ba705a181e280f71d46b0dfbc2fb5/mt master 762fef64a7baf28d9eaba01f509479dc6aed8424.