godot icon indicating copy to clipboard operation
godot copied to clipboard

Using System.TimeZoneInfo will crash in simulator (as will other native calls)

Open andy-noisyduck opened this issue 3 years ago • 5 comments

Godot version

3.4.2 (Mono)

System information

OSX 10.15 (Catalina), XCode 11.6

Issue description

This is very similar to #40767 - in fact I can trigger it with the same test project. Making any native calls seem to crash with an EntryPointNotFoundException. This seems to be worse than the previous issue which only crashed on device builds, but now crashes on the simulator too.

Any native call seems to trigger this (including the other existing ones from #40757 and #40633).

As an example, you can use can call dateTime.ToUniversalTime(), which will make a call to System.TimeZoneInfo.xamarin_timezone_get_data and crash with the following exception:

System.EntryPointNotFoundException: xamarin_timezone_get_data assembly:<unknown assembly> type:<unknown type> member:(null)
  at (wrapper managed-to-native) System.TimeZoneInfo.xamarin_timezone_get_data(string,uint&)
  at System.TimeZoneInfo.GetMonoTouchData (System.String name, System.Boolean throw_on_error) [0x00002] in <11afb9645ddb4e8fae4163490ca47a50>:0 
  at System.TimeZoneInfo.CreateLocal () [0x00000] in <11afb9645ddb4e8fae4163490ca47a50>:0 
  at System.TimeZoneInfo.get_Local () [0x00009] in <11afb9645ddb4e8fae4163490ca47a50>:0 
  at System.TimeZoneInfo.ConvertTimeToUtc (System.DateTime dateTime, System.TimeZoneInfoOptions flags) [0x00000] in <11afb9645ddb4e8fae4163490ca47a50>:0 
  at System.DateTime.ToUniversalTime () [0x00000] in <11afb9645ddb4e8fae4163490ca47a50>:0

I can fix this with linker flags as suggested in https://github.com/godotengine/godot/issues/40757#issuecomment-841852062, i.e. by passing in -Wl,-u,_xamarin_timezone_get_data,-u,_xamarin_timezone_get_local_name but I was under the impression that was fixed by https://github.com/godotengine/godot/pull/49248. Is this a regression or have I misunderstood the fix?

It's going to be very fiddly if I need to manually test the project and find all the native calls manually.

Steps to reproduce

new DateTime().ToUniversalTime();

Minimal reproduction project

Test-MonoDateIOS.zip

andy-noisyduck avatar Feb 23 '22 01:02 andy-noisyduck

I can fix this with linker flags as suggested in #40757 (comment), i.e. by passing in -Wl,-u,_xamarin_timezone_get_data,-u,_xamarin_timezone_get_local_name but I was under the impression that was fixed by #49248. Is this a regression or have I misunderstood the fix?

That should have been fixed, yes. Godot will create a .cpp file as part of your Xcode project (I think it's called dummy.cpp). Can you upload this file here?

neikeq avatar Feb 23 '22 11:02 neikeq

That should have been fixed, yes. Godot will create a .cpp file as part of your Xcode project (I think it's called dummy.cpp). Can you upload this file here?

dummy.cpp.txt

The Xamarin externs are in there. Some appear to be entered twice (e.g. Stat2), but I'm assuming that's not the issue.

Are they supposed to be wrapped by #if !TARGET_OS_SIMULATOR? I'm not sure what the difference is between now and 3.2 when they ran correctly on the simulator and only stripped for a device build.

andy-noisyduck avatar Feb 23 '22 15:02 andy-noisyduck

Are they supposed to be wrapped by #if !TARGET_OS_SIMULATOR?

Can you reproduce this only in the simulator? Or does the same happen in a device?

neikeq avatar Feb 23 '22 15:02 neikeq

Can you reproduce this only in the simulator? Or does the same happen in a device?

Just tried on a device (via an ad-hoc distribution profile) and it has the same missing entry point exception. If I go and manually specify the linker flags it still doesn't work on the device, though it then works fine in the simulator.

If I remove #if !TARGET_OS_SIMULATOR from dummy.cpp then it works on the simulator without specifying linker flags. This also does not fix it for a real device with an exported archive though.

andy-noisyduck avatar Feb 23 '22 15:02 andy-noisyduck

We're getting a TestFlight-only crash on actual iOS devices using Double.ToString because I think it's invoking System.Globalization.CultureInfo under the hood, even without specifying an IFormatProvider. It uses the current culture by default. Specifying the culture explicitly as CultureInfo.InvariantCulture still crashes, the same as leaving it implicit.

It does not happen when building to an actual iOS device via USB straight from Xcode after exporting from Godot Mono 3.5.1-stable. I believe this issue is the same root cause. The same exact type of crash scenario also occurred using any kind of localized date/time code that invokes System.TimeZoneInfo under the hood.

I can't speak for the simulator, but I don't think this issue is simulator-specific.

Also related to #73110: "This seems to be contained only to the iOS platform when the app is submitted to App Store Connect, aka, not a simulator build."

knightofiam avatar Mar 08 '23 12:03 knightofiam

So the issue is still there. It works flawlessly when the iOS binary is created in XCode, even in the Release build, however archiving the project (i.e. generating the IPA or uploading to the AppStore) performs an additional strip operation that removes libmono-native.xcframework or something else entirely.

Fastest way to avoid the problem is to find the Strip Linked Product option in XCode settings and set it to No:

Screenshot 2023-10-11 at 21 38 44

Another way is to set stripping mode to debug symbols only:

Screenshot 2023-10-11 at 21 41 10

I don't have time and mood to trace why the Mono part is stripped but it is reproducible up to Godot 3.6 beta.

Nomad1 avatar Oct 12 '23 00:10 Nomad1

Note that this issue is also raised with any DateTime string formatting

System.EntryPointNotFoundException: xamarin_timezone_get_data

I'm also seeing a similar issue for currency formatting e.g. where float v.ToString ("C") will cause an exception in iOS

The work-around by @Nomad1 works in both cases

petrsorfa avatar Jun 23 '24 03:06 petrsorfa