realm/realm-swift

Realm fails to access property on RealmSwiftObject instance

Closed this issue · 23 comments

Goals

I am fetching custom objects from a REST service. A framework of mine transforms the JSON into Realm instances. The model class is the following:

public class ObservingSite: Object {
    public dynamic var uuid: String = ""
    public dynamic var name: String = ""

    override public static func primaryKey() -> String? {
        return "uuid"
    }    
}

These instances are saved into a realm, and then transferred into the app using the custom framework. However, at that time, I just can't access the properties name or uuid. On the other hand the po command in the debugger shows the correct properties values!

Somehow, I don't have this problem at all when fetching single objects. As far as I can tell, this is similar (or related to) #4005 maybe?

Expected Results

I expect to be able to access the values of these properties.

Actual Results

The runtime result of this is:

-[RealmSwiftObject name]: unrecognized selector sent to instance 0x61000008d8e0

When I set a breakpoint just before accessing the property in my app code, and use the po command, I get the following (the instance is site):

(lldb) po site
ObservingSite {
	uuid = 99b98d50-d831-48c2-89b3-2ff6e4c9f4aa;
	name = Adelaide Observatory;
}

(lldb) po site.name
2017-01-28 10:48:56.220043 iObserve2[16158:347963] -[RealmSwiftObject name]: unrecognized selector sent to instance 0x608000089060
error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..
The process has been returned to the state before expression evaluation.

Steps to Reproduce

I tried the above code in 2 apps and I get the same thing. The custom framework I use is available here: https://github.com/onekiloparsec/arcsecond.swift

Code Sample

And the code to fetch the observing sites is like this:

    _ = ArcsecondService.sharedDefault.observingSites(closure: { (sites, event) in
        if let obsSites = sites {
            Swift.print("\(obsSites)")
            if let site = obsSites.first {
                Swift.print("\(site.name)")
            }
        }
    })

Version of Realm and Tooling

Realm version: 2.4.1

Xcode version: 8.2.1

iOS/OSX version: 10.12.3

Dependency manager + version: Carthage (latest)

My bad, I made a test project and everything worked fine. For some reasons still unclear to me, I deleted entirely the realm files (.realm, .realm.lock and .realm.management) and now it works. As far as I remember, there were no changes in my models, but I could be wrong.

Actually, the problem still persists. But it reappears on the second launch of the app. I'm a bit lost.

Same issue here. Downgrading to 2.3.0, everything is fine.

Thanks a lot @kukushi ! Indeed, v2.3.0 doesn't have this problem.
I must say that I nonetheless wasn't able to reproduce it with v2.4.1 inside a blank new project. ???

I have the same issue. I just upgraded to v2.4.1 and had the same issue. I went back to v2.3.0, restarted the app and everything was working fine again.

Same issue for 2.4.1. Downgraded to 2.4.0 - everything works fine

Thanks everyone for reporting this issue. Would someone be able to provide us with an Xcode project that reproduces this issue consistently so we can have one of the engineers look into it further. Thanks!

jpsim commented

There were no meaningful changes between 2.4.0 and 2.4.1 that could affect this, so reverting to 2.4.0 shouldn't help.

I can confirm: the problem exists with 2.4.0 and 2.4.1 but not with 2.3.0. But so far I couldn't reliably reproduce the problem in a test project.

bdash commented

unrecognized selector sent to instance errors are often the result of messaging a deallocated object. Have you tried reproducing this problem with zombies enabled? (Product -> Scheme -> Edit Scheme…, select the Run action, Diagnostics, and enable Zombie Objects).

Seeing the same issue. Downgrading to 2.3.0 works.

@bdash How the po command in the debugger would work then at that stage, as reported, if the object was already deallocated?

Sending a message to an object represented by a dangling pointer is undefined behavior, and may or may not cause an error in any given instance (depending on e.g. whether the memory the now-deallocated object lives in has been written to or not). The zombie detection tool is explicitly designed to detect this error case by replacing deallocated objects with special 'zombie' objects that detect if anyone attempts to send messages to them.

I know that. But I am surprised the po command systematically find the content of the instance, and that I can inspect the RealmSwiftObject in the debugger.

bdash commented

unrecognized selector sent to instance errors are often the result of an object of the expected type being deallocated, and then an object of a different type being allocated at the same address. Messages like -debugDescription / -description, used by po, are handled by virtually all objects so they would typically continue to work against an object of an unexpected type.

Zombie objects work by not allowing the address to be reused. Instead the deallocated object's class pointer is replaced with one that generates an error whenever any message is sent to the object. Testing with this setting enabled should help determine whether messaging a deallocated object is a factor.

I have been able to reproduce the issue in the following project.

Steps to reproduce

  1. Start the app with Realm v2.3.0
  2. Add a few objects to Realm
  3. Click the Crash or not button to verify that you can access the added objects
  4. Upgrade to Realm v2.4.1
  5. Start the app and click the Crash or not button.
  6. The app crashes
bdash commented

Thanks, @svenbacia! I was able to reproduce by following your instructions.

bdash commented

One thing I've observed is that if you perform a clean build in Xcode between steps 4 and 5, the crash goes away. @svenbacia, can you test whether you see the same result?

bdash commented

It looks to me like Xcode simply isn't rebuilding enough of the app code when updating from Realm Swift 2.3.0 to 2.4.x. Can anyone that's seeing this try doing a clean build of their app (Product -> Clean) and let me know if they still see crashes after doing that?

I can verify that a clean after step 4 fixes the issue. I upgraded realm to the latest version in my application, did a clean build and it is working fine 👍

bdash commented

Thanks for confirming. Since this appears to be an Xcode bug I'd encourage you to file a bug report with Apple with information on how to reproduce. I'll be closing this issue as I don't think there's anything we can do on our side to avoid this problem.

I had exactly the same issue. None of the above solutions worked for me but downgrading realm version to 2.3.0. I tried 2.4.2, 2.4.1 and 2.4.0, at each try I cleaned all targets, removed all build products, removed app from the device - all without success.

bdash commented

Multiple users have confirmed that doing a clean build after updating is sufficient to address the problem. If you're still seeing a crash then either you're not doing a clean-enough build, or you're seeing a similar-but-different problem. I'd suggest updating to 2.4.2, then doing Product -> Clean Build Folder… (hold down Option to see it) to do the cleanest build Xcode can. If you're still seeing a problem, please file a new issue and provide all of the information requested in the new issue template.