applejag/Newtonsoft.Json-for-Unity

Bug: null-coalescing operator on deserialized int? causes strange results (only on iOS)

Closed this issue · 5 comments

Expected behavior

Getting results from nullable types via the ?? operator should return the same value on every platform.

Actual behavior

On iOS calling ?? with a default value of 0 causes the program to return a seemingly random number: 1833142448

Steps to reproduce

  • New project
  • Import jillejr.newtonsoft.json-for-unity via UPM
  • Add following script to scene:
private string json = "{'NullableIntJson': null}".Replace("'", "\"");
public int? NullableIntProperty { get; set; }

void Start()
{
    Debug.Log("Deserialize...");
    var dc = JsonConvert.DeserializeObject<SimpleResponse>(json);
    Debug.Log("NullableIntProperty.HasValue: " + NullableIntProperty.HasValue);
    Debug.Log("NullableIntProperty: " + (NullableIntProperty ?? 0));
    Debug.Log("NullableIntJson.HasValue: " + dc.NullableIntJson.HasValue);
    Debug.Log("NullableIntJson: " + (dc.NullableIntJson ?? 0));
}

public class SimpleResponse
{
    public int? NullableIntJson { get; set; }
}
  • Build the game for iOS
  • Run it and observe the Xcode console

Expected Prints:
Deserialize...
NullableIntProperty.HasValue: False
NullableIntProperty: 0
NullableIntJson.HasValue: False
NullableIntJson: 0

Observed Prints:
Deserialize...
NullableIntProperty.HasValue: False
NullableIntProperty: 0
NullableIntJson.HasValue: False
NullableIntJson: 1833142448

You can test in the editor and will see that the results are as expected in comparison to an iOS build.
Changing the default value in line Debug.Log("NullableIntJson: " + (dc.NullableIntJson ?? 0)); from 0 to anything else, will also result in expected outputs. However using 0 always returns a large random number.

As you can see, this only happens if the int? was priorly deserialized by Json-for-Unity, an untouched properties are not affected.

Details

  • Unity build target: iOS
  • Newtonsoft.Json-for-Unity package version: 13.0.102
  • I was using Unity version 2020.3.0f1

Woa! This issue is wild! Extreamly interesting find @Noblauch!

Your other issue (#114) was kind of my go-to response, but this one I have not the slightest of ideas why this is happening. I want to try reproduce this as best I can and investigate further

Only thing I could imagine that could solve this is if you marked int? to be fully preserved.

I will test this myself later, but what happens if you add the following link.xml file? :

<linker>
	<assembly fullname="*">
		<type fullname="System.Nullable`1&lt;System.Int32&gt;" preserve="all" />
	</assembly>
</linker>

Copy that snippet and save that to a file named link.xml inside your Assets directory. Any subdirectory of the Assets directory will also work.

Also the obvious workaround is to make sure you use the .HasValue instead of comparing with null as the ?? op does. But that might get ugly and is not that intuitive.

This issue seems highly related to https://issuetracker.unity3d.com/issues/il2cpp-does-not-compile-null-coalescing-operator-properly-for-bool which is stated to have been fixed since 2020.3.2f1. Could you try updating to the 2020.3.2f1 or beyond?

Thanks for the quick reply! I added the link.xml and it seems like it doesn't have any effect. The outcome is still the same.
I'll try the update!
Yep, we are using: var result = variable.HasValue ? variable.Value : 0; for now.
The issue is, that as the project grows, the workaround pile grows bigger. And adding restrictions that you must know and are hard to debug, like this one are making it hard to write solid code. Especially for new developers in the team.

I understand the pain, been there as well. I'll investigate this and see what I can do about it, even if it is resolved by updating, so it doesn't happen for those who are locked to a certain version.

Updating to 2020.3.4f1 indeed fixed the issue. 😦
Good eye ;) We have no problem updating. I think people having issues will find this post as-well, thank you!