godot: Using most System.IO file classes will crash on iOS devices (not in the simulator)

Godot version: 3.2.2 Mono w/ Mono 6.10 stable

OS/device including version: Build w/ OSX Catalina, tested on various iPhones w/ iOS 13

Issue description: App will crash when using most of the System.IO classes, such as File or FileStream. This only happens on real devices. The simulator works fine.

The crash occurs any time the framework needs to call the native Stat method to check if a file exists (and most of the File classes do this on creation to know whether to overwrite, append, or throw depending on modes passed).

SystemNative_Stat2
  at Interop+Sys.Stat (System.ReadOnlySpan`1[T] path, Interop+Sys+FileStatus& output)
  at System.IO.FileSystem.FileExists (System.ReadOnlySpan`1[T] fullPath, System.Int32 fileType, Interop+ErrorInfo& errorInfo)
  at System.IO.FileSystem.DirectoryExists (System.ReadOnlySpan`1[T] fullPath, Interop+ErrorInfo& errorInfo)
  at System.IO.FileSystem.DirectoryExists (System.ReadOnlySpan`1[T] fullPath)
  at System.IO.Directory.Exists (System.String path)
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode)

As with #40633, I am unsure whether this is a problem with the way Godot is using Mono, a symptom of AoT (required for iOS), or a problem with the Mono implementation on iOS. I am starting to think it’s related and that’s its a linking or packaging problem for native methods on iOS.

It’s not clear to me which versions of libmono get packed if your local Mono install doesn’t match the pre-compiled export template (in my case 6.10 vs 6.8). I also tried this matching my local Mono version to the template. The issue still occurred.

Steps to reproduce:

  1. Open a file in OpenCreate modes (other modes should also trigger this). e.g. new FileStream(Path.Combine(".test"), FileMode.OpenOrCreate);

Minimal reproduction project: Test-MonoFileIOS.zip

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 20 (19 by maintainers)

Most upvoted comments

Fixed by #49248.

@Difference That should be the same issue, so it should be fixed in the next release.

This week I was finally able to give this a try (I got an M1 last year but couldn’t get my builds working until now) and I managed to reproduce the issue. I can confirm passing -u to the linker correctly makes it not strip the symbol, fixing the issue. However it has to be done this way:

  • The linker flags are of the form: -Wl,-u,_SystemNative_Stat2
  • These linker flags have to be added to the Other Linker Flags build setting for the TARGET, not the PROJECT.

So in order to fix the issue what I need to do is:

  1. Use cecil or reflection to collect a list of all DllImports in the compiled assemblies to determine which symbols need to be kept.
  2. Modify the exporter to allow specifying linker flags for the target instead of the project.