-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can we make memory management bugs more debuggable? #1038
Comments
Poked at the object represenation a bit today. It looks like the ObjC object header is 8 bytes:
I think the first 9 bits encode the refcount. When the refcount is below 256, it's just stored in the first byte, and the second byte is 0x1D. When it hits 256 or higher, the 0x80 bit of the first two bytes is always on, and the exact count is stored in some way I haven't figured out. Since the ref count works correctly above 2^9, part of it must be stored elsewhere. The latter 6 bytes of the header doesn't change with the refcount, and are specific to the type of the object. I'll call these the type ID. The test object's type ID was different each run, but NSObject's was always the same. Once the object is deleted, the first 2 bytes is zeroed out, and the other bytes are randomized (or possibly some of them are set to a sentinel value, but that value varied between runs). So I think the best I can do to check object validity at the moment is to check the first 2 bytes of the object, and verify they match either If we wanted to be stricter, we could store a table of known type IDs. At runtime, the ffigen'd ObjC bindings would add the type ID of every class it has bindings for to the table. 2 downsides to this approach are:
|
This approach doesn't work for all objects. I tried the same thing with I think a better approach would be to dig through the ObjC runtime to look for functions that might help. |
The main issue with using these internal functions is that they're not well documented. I found the headers on my mac though, so for future reference, the directory is There's some functions in there that should work.
It works for any dereferencable pointer or null, without aborting, including pointers to deleted objects. So then we just have to check whether the class is valid. There's a function that looks like it might be able to verify the class, |
For example, if we try to take a reference to an ObjC object pointer after it has been freed, we get a crash with no stack trace. We can write some native code that will try to detect if an object is valid, then assert it's valid before calling retain. This is definitely possible for blocks (we have tests that do this already), so we just need to investigate if it's possible for objects. There will always be false negatives with a check like this, but an assertion that catches some/most of these mistakes would already be a huge improvement.
Ideally we'd add an assert for this to
objectRetain
,objectRelease
,blockCopy
, andblockRelease
. The assert would check that the object is still alive and has a non-zero ref count.See #1017
The text was updated successfully, but these errors were encountered: