Chapter 9 Final application crashes in Release mode

When trying to run the final project from Chapter 9 (EmojiArt) in release mode, the application crashes when scrolling in the gallery.
The crash is present when running on the simulator and when running on a real device (using Xcode 13.2.1).

Here what I can see in Xcode:

@globalActor actor ImageDatabase {
// ...
  func image(_ key: String) async throws -> UIImage {
    if await imageLoader.cache.keys.contains(key) { // Crash here: EXC_BAD_ACCESS
      print("Cached in-memory")
      return try await imageLoader.image(key)
    }
// ...

By running the app with the address sanitizer I can see an error a the same line: “Use of deallocated memory”

My supposition is that the issue comes from the fact that we are accessing the cache property in imageLoader directly from the ImageDatabase.
I am not sure about that, as we are still accessing the property using async.

Following this idea I fixed this issue by making the cache private and adding this method to ImageLoader:

func contains(_ key: String) -> Bool {
  return cache.keys.contains(key)
}

And I then used this method in ImageDatabase where the crash was occurring:

@globalActor actor ImageDatabase {
// ...
  func image(_ key: String) async throws -> UIImage {
    if await imageLoader.contains(key) { // <- The change is here
      print("Cached in-memory")
      return try await imageLoader.image(key)
    }
// ...

With this change there is no longer a crash.
But I am not sure to understand why there was a crash in the first place, can someone explain it to me ?
Is accessing an actor property unsafe ? is it because it came from another thread ?

1 Like

This is a very interesting find — I tried out few things but to me it looks like this might be a bug. Accessing the dictionary keys doesn’t crash, but calling contains(...) on the keys does — I haven’t dug in the contains() code in the stdlib for this issue but I take it there ought to be some optimization that isn’t quite safe. I’ll try to make an isolated sample code and if it’s reproducible will send a bug for it.

For the time being I’ll update the book code to avoid hitting this issue — again, thank you for finding this and taking the time to let us know.

@theipple did you find out anything more about the issue?

Oh, looking at this — this might be about modifying the keys from another thread, but I’m perplexed because the thread sanitizer doesn’t report anything… Will look into this more

I did not looked at it more that I did when writing this post, but as I am still learning the new concurrency features I do not where to search :sweat_smile:.
If I find something I will let you know.

Great! As I wrote, my assumption is Collection.contains(...) is the one causing the issue — it’s on my todo to try to make a reproducible sample :+1:t3:

Here’s the pending change in the code repo: Tsan related changes by icanzilb · Pull Request #18 · raywenderlich/mcon-materials · GitHub