gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

__NSCF** classes and libobjc2 dependency on C++ runtime


From: Maxthon Chan
Subject: __NSCF** classes and libobjc2 dependency on C++ runtime
Date: Tue, 04 Jun 2013 06:45:19 +0800

I did some research on how Apple implemented Objective-C exceptions and CoreFoundation on iOS (iOS 6.1.3 on iPhone 4S) and I found something that we can use.

If you want me to test anything, please reply to this Email and I will test it for you. I have three devices to test: iOS 6.1.3 on iPhone 4S (armv7) and iPad 2 (armv7), as well as OS X 10.8.3 on my MacBook Pro (x86-64 and i386 both). I may also be able to borrow an iPad 4 for testing (iOS 6.1.2, armv7s)

1) Apple's libobjc depend on LLVM's libc++abi (in Linux, it should be libsupc++). Not only Apple did that to allow proper Objective-C++, but also something more.
When an Objective-C exception is triggered and not caught in Objective-C code, it will be raised as a C++ exception. This happens no matter if your code have C++ or not. Here is an crash log explaining this: (MobileDeuterium is the app I wrote. It have zero C++ in it.)

Incident Identifier: 3B2E3282-1537-4261-A77A-7931E8898F06
CrashReporter Key:   821361952184b8795bbbd7dd4b9db7b36d3a208a
Hardware Model:      iPhone4,1
Process:         MobileDeuterium [18922]
Path:            /var/mobile/Applications/C9064A00-2DB5-437A-9B0C-AC055C1F70A1/MobileDeuterium.app/MobileDeuterium
Identifier:      MobileDeuterium
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]

Date/Time:       2013-05-26 08:45:19.713 +0800
OS Version:      iOS 6.1.2 (10B146)
Report Version:  104

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Crashed Thread:  4

  --- Lines truncated ---

Thread 4 name:  Dispatch queue: com.apple.root.default-priority
Thread 4 Crashed:
0   libsystem_kernel.dylib        0x39c5e350 __pthread_kill + 8
1   libsystem_c.dylib             0x39bd511e pthread_kill + 54
2   libsystem_c.dylib             0x39c1196e abort + 90
3   libc++abi.dylib               0x391afd4a abort_message + 70
4   libc++abi.dylib               0x391acff4 default_terminate() + 20
5   libobjc.A.dylib               0x39760a74 _objc_terminate() + 144
6   libc++abi.dylib               0x391ad078 safe_handler_caller(void (*)()) + 76
7   libc++abi.dylib               0x391ad110 std::terminate() + 16
8   libc++abi.dylib               0x391ae50e __cxa_throw + 118
9   libobjc.A.dylib               0x397609ba objc_exception_throw + 90
10  CoreFoundation                0x31a46e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166
11  CoreFoundation                0x31a4552c ___forwarding___ + 388
12  CoreFoundation                0x3199cf64 _CF_forwarding_prep_0 + 20
13  MobileDeuterium               0x0009ba36 0x97000 + 18998
14  libdispatch.dylib             0x39b7811c _dispatch_call_block_and_release + 8
15  libdispatch.dylib             0x39b7c95c _dispatch_root_queue_drain + 248
16  libdispatch.dylib             0x39b7cabc _dispatch_worker_thread2 + 80
17  libsystem_c.dylib             0x39baca0e _pthread_wqthread + 358
18  libsystem_c.dylib             0x39bac8a0 start_wqthread + 4

  --- Lines truncated ---

Note: iPhone4,1 is the internal identifier of iPhone 4S.

2) Toll-Free Bridging is a cross-effort of both Foundation and CoreFoundation.
Try compile this code on OS X:

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>

int main(void)
{
    @autoreleasepool
    {
        CFStringRef string = CFSTR("hello, world");
        NSString *string_objc = (__bridge NSStirng *)string;
        NSLog("Class: %@", NSStringFromClass([string_objc class]));
        CFRelease(string);
    }
    return 0;
}

To compile: xcrun clang test.m -o test -framework Foundation -framework CoreFoundation -Wall -fobjc-arc

The output will be: "Class: __NSCFString" and one explanation of that: it is a CoreFoundation object toll-free bridged over into Foundation.

I saw this in my original ohttpd (on OS X) so here is my guess on how that worked:

1) All CoreFoundation objects have a complete Objective-C object structure, and its isa pointer is assigned to its Objective-C companion class. Given that Apple does not put retain counts in the object itself, this structure is only an isa pointer.
2) All CoreFoundation objects have a more or less functional Objective-C companion class.
3) For toll-free bridged objects, this companion class is a subclass of its public class cluster and have at least all important methods overridden with glue code that call into CoreFoundation functions.
4) For non-toll-free bridged objects, this companion class is a subclass of NSObject or NSProxy and implements only memory management methods.
5) CFRetain and CFRelease are stubs that call -[id<NSObject> retain] and -[id<NSObject> release]. CoreFoundation does not manage its memory directly using its own functions. Instead, all clean-ups are done by implementing a -[id<NSObject> dealloc] method in its companion Objective-C class.
6) When a Foundation object is passed into a CoreFoundation function as a parameter and the object is not subject to changes in the procedure, it is converted into its CoreFoundation counterpart, probably using -[id<NSCopying> copy] method.
7) When a Foundation object is passed into a CoreFoundation function as a parameter that will change the object itself, the function will call corresponding Foundation method(s) directly or via other CoreFoundation functions.

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail


reply via email to

[Prev in Thread] Current Thread [Next in Thread]