From: Apple Date: Fri, 24 Jun 2011 13:59:06 +0000 (+0000) Subject: objc4-437.3.tar.gz X-Git-Tag: mac-os-x-1068^0 X-Git-Url: https://git.saurik.com/apple/objc4.git/commitdiff_plain/ee974f79090efc52c8d37c74dff5abadabf50296?ds=inline objc4-437.3.tar.gz --- diff --git a/libobjc.order b/libobjc.order index d23b201..c7e85ca 100644 --- a/libobjc.order +++ b/libobjc.order @@ -120,7 +120,6 @@ _NXNextHashState _objc_msgSend __class_lookupMethodAndLoadCache __class_getFreedObjectClass -__class_getNonexistentObjectClass __class_isInitialized __class_initialize __class_isMetaClass diff --git a/runtime/objc-cache.m b/runtime/objc-cache.m index 0908c42..0da21a3 100644 --- a/runtime/objc-cache.m +++ b/runtime/objc-cache.m @@ -831,7 +831,7 @@ static int _collecting_in_critical(void) } // Deallocate the thread list - vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number); + vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads[0]) * number); // Return our finding return result; diff --git a/runtime/objc-class-old.m b/runtime/objc-class-old.m index fecccf2..65a85af 100644 --- a/runtime/objc-class-old.m +++ b/runtime/objc-class-old.m @@ -47,20 +47,6 @@ static const struct old_class freedObjectClass = NULL // protocols }; -static const struct old_class nonexistentObjectClass = -{ - Nil, // isa - Nil, // super_class - "NONEXISTENT(id)", // name - 0, // version - 0, // info - 0, // instance_size - NULL, // ivars - NULL, // methodLists - (Cache) &_objc_empty_cache, // cache - NULL // protocols -}; - /*********************************************************************** * _class_getFreedObjectClass. Return a pointer to the dummy freed @@ -74,18 +60,6 @@ static Class _class_getFreedObjectClass(void) } -/*********************************************************************** -* _class_getNonexistentClass. Return a pointer to the dummy nonexistent -* object class. This is used when, for example, mapping the class -* refs for an image, and the class can not be found, so that we can -* catch later uses of the non-existent class. -**********************************************************************/ -__private_extern__ Class _class_getNonexistentObjectClass(void) -{ - return (Class)&nonexistentObjectClass; -} - - /*********************************************************************** * _objc_getFreedObjectClass. Return a pointer to the dummy freed * object class. Freed objects get their isa pointers replaced with @@ -349,15 +323,6 @@ static void _freedHandler(id obj, SEL sel) sel_getName(sel), obj); } -/*********************************************************************** -* _nonexistentHandler. -**********************************************************************/ -static void _nonexistentHandler(id obj, SEL sel) -{ - __objc_error (obj, "message %s sent to non-existent object=%p", - sel_getName(sel), obj); -} - /*********************************************************************** * ABI-specific lookUpMethod helpers. @@ -378,10 +343,6 @@ __private_extern__ IMP prepareForMethodLookup(Class cls, SEL sel, BOOL init) if (cls == _class_getFreedObjectClass()) return (IMP) _freedHandler; - // Check for nonexistent class - if (cls == _class_getNonexistentObjectClass()) - return (IMP) _nonexistentHandler; - if (init && !_class_isInitialized(cls)) { _class_initialize (cls); // If sel == initialize, _class_initialize will send +initialize and diff --git a/runtime/objc-private.h b/runtime/objc-private.h index b147f1a..fd63f76 100644 --- a/runtime/objc-private.h +++ b/runtime/objc-private.h @@ -824,7 +824,6 @@ static inline struct old_class *_class_asOld(Class cls) { return (struct old_cla static inline struct old_category *_category_asOld(Category cat) { return (struct old_category *)cat; } extern void unload_class(struct old_class *cls); -Class _class_getNonexistentObjectClass(void); #endif extern BOOL object_cxxConstruct(id obj); diff --git a/runtime/objc-runtime-new.m b/runtime/objc-runtime-new.m index a1c4d9c..de8d4fc 100644 --- a/runtime/objc-runtime-new.m +++ b/runtime/objc-runtime-new.m @@ -1759,6 +1759,7 @@ static void removeFutureClass(const char *name) /*********************************************************************** * remappedClasses * Returns the oldClass => newClass map for realized future classes. +* Returns the oldClass => NULL map for ignored weak-linked classes. * Locking: runtimeLock must be read- or write-locked by the caller **********************************************************************/ static NXMapTable *remappedClasses(BOOL create) @@ -1797,6 +1798,7 @@ static BOOL noClassesRemapped(void) /*********************************************************************** * addRemappedClass * newcls is a realized future class, replacing oldcls. +* OR newcls is NULL, replacing ignored weak-linked class oldcls. * Locking: runtimeLock must be write-locked by the caller **********************************************************************/ static void addRemappedClass(class_t *oldcls, class_t *newcls) @@ -1818,20 +1820,29 @@ static void addRemappedClass(class_t *oldcls, class_t *newcls) * remapClass * Returns the live class pointer for cls, which may be pointing to * a class struct that has been reallocated. +* Returns NULL if cls is ignored because of weak linking. * Locking: runtimeLock must be read- or write-locked by the caller **********************************************************************/ static class_t *remapClass(class_t *cls) { rwlock_assert_locked(&runtimeLock); - class_t *newcls = NXMapGet(remappedClasses(YES), cls); - return newcls ? newcls : cls; + class_t *c2; + + if (!cls) return NULL; + + if (NXMapMember(remappedClasses(YES), cls, (void**)&c2) == NX_MAPNOTAKEY) { + return cls; + } else { + return c2; + } } /*********************************************************************** * remapClassRef -* Fix up a class ref, in case the class referenced has been reallocated. +* Fix up a class ref, in case the class referenced has been reallocated +* or is an ignored weak-linked class. * Locking: runtimeLock must be read- or write-locked by the caller **********************************************************************/ static void remapClassRef(class_t **clsref) @@ -2234,6 +2245,28 @@ static class_t *getClass(const char *name) } +/*********************************************************************** +* missingWeakSuperclass +* Return YES if some superclass of cls was weak-linked and is missing. +**********************************************************************/ +static BOOL +missingWeakSuperclass(class_t *cls) +{ + assert(!isRealized(cls)); + + if (!cls->superclass) { + // superclass NULL. This is normal for root classes only. + return (!(cls->data->flags & RO_ROOT)); + } else { + // superclass not NULL. Check if a higher superclass is missing. + class_t *supercls = remapClass(cls->superclass); + if (!supercls) return YES; + if (isRealized(supercls)) return NO; + return missingWeakSuperclass(supercls); + } +} + + /*********************************************************************** * realizeAllClassesInImage * Non-lazily realizes all unrealized classes in the given image. @@ -2541,6 +2574,20 @@ __private_extern__ void _read_images(header_info **hList, uint32_t hCount) class_t **classlist = _getObjc2ClassList(hi, &count); for (i = 0; i < count; i++) { const char *name = getName(classlist[i]); + + if (missingWeakSuperclass(classlist[i])) { + // No superclass (probably weak-linked). + // Disavow any knowledge of this subclass. + if (PrintConnecting) { + _objc_inform("CLASS: IGNORING class '%s' with " + "missing weak-linked superclass", name); + } + addRemappedClass(classlist[i], NULL); + classlist[i]->superclass = NULL; + classlist[i] = NULL; + continue; + } + if (NXCountMapTable(future_class_map) > 0) { class_t *newCls = NXMapGet(future_class_map, name); if (newCls) { @@ -2672,6 +2719,18 @@ __private_extern__ void _read_images(header_info **hList, uint32_t hCount) // Do NOT use cat->cls! It may have been remapped. class_t *cls = remapClass(cat->cls); + if (!cls) { + // Category's target class is missing (probably weak-linked). + // Disavow any knowledge of this category. + catlist[i] = NULL; + if (PrintConnecting) { + _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " + "missing weak-linked target class", + cat->name, cat); + } + continue; + } + // Process this category. // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if @@ -2726,12 +2785,13 @@ __private_extern__ void _read_images(header_info **hList, uint32_t hCount) // cls must already be connected. static void schedule_class_load(class_t *cls) { + if (!cls) return; assert(isRealized(cls)); // _read_images should realize if (cls->data->flags & RW_LOADED) return; - class_t *supercls = getSuperclass(cls); - if (supercls) schedule_class_load(supercls); + // Ensure superclass-first ordering + schedule_class_load(getSuperclass(cls)); add_class_to_loadable_list((Class)cls); changeInfo(cls, RW_LOADED, 0); @@ -2746,8 +2806,7 @@ __private_extern__ void prepare_load_methods(header_info *hi) class_t **classlist = _getObjc2NonlazyClassList(hi, &count); for (i = 0; i < count; i++) { - class_t *cls = remapClass(classlist[i]); - schedule_class_load(cls); + schedule_class_load(remapClass(classlist[i])); } category_t **categorylist = _getObjc2NonlazyCategoryList(hi, &count); @@ -2755,6 +2814,7 @@ __private_extern__ void prepare_load_methods(header_info *hi) category_t *cat = categorylist[i]; // Do NOT use cat->cls! It may have been remapped. class_t *cls = remapClass(cat->cls); + if (!cls) continue; // category for ignored weak-linked class realizeClass(cls); assert(isRealized(cls->isa)); add_category_to_loadable_list((Category)cat); @@ -2779,7 +2839,10 @@ __private_extern__ void _unload_image(header_info *hi) category_t **catlist = _getObjc2CategoryList(hi, &count); for (i = 0; i < count; i++) { category_t *cat = catlist[i]; + if (!cat) continue; // category for ignored weak-linked class class_t *cls = remapClass(cat->cls); + assert(cls); // shouldn't have live category for dead class + // fixme for MH_DYLIB cat's class may have been unloaded already // unattached list @@ -2795,9 +2858,12 @@ __private_extern__ void _unload_image(header_info *hi) for (i = 0; i < count; i++) { class_t *cls = classlist[i]; // fixme remapped classes? - remove_class_from_loadable_list((Class)cls); - unload_class(cls->isa, YES); - unload_class(cls, NO); + // fixme ignored weak-linked classes + if (cls) { + remove_class_from_loadable_list((Class)cls); + unload_class(cls->isa, YES); + unload_class(cls, NO); + } } // Clean up protocols. @@ -3728,7 +3794,7 @@ class_copyProtocolList(Class cls_gen, unsigned int *outCount) __private_extern__ const char ** _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount) { - size_t count, i; + size_t count, i, shift; class_t **classlist; const char **names; @@ -3737,9 +3803,16 @@ _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount) classlist = _getObjc2ClassList(hi, &count); names = malloc((count+1) * sizeof(const char *)); + shift = 0; for (i = 0; i < count; i++) { - names[i] = getName(classlist[i]); + class_t *cls = remapClass(classlist[i]); + if (cls) { + names[i-shift] = getName(classlist[i]); + } else { + shift++; // ignored weak-linked class + } } + count -= shift; names[count] = NULL; rwlock_unlock_read(&runtimeLock); diff --git a/runtime/objc-runtime-old.m b/runtime/objc-runtime-old.m index 954bc7a..5374561 100644 --- a/runtime/objc-runtime-old.m +++ b/runtime/objc-runtime-old.m @@ -73,7 +73,7 @@ * (5) is not yet eligible for +load. * * Image mapping is NOT CURRENTLY THREAD-SAFE with respect to just about - * * * anything. Image mapping IS RE-ENTRANT in several places: superclass + * anything. Image mapping IS RE-ENTRANT in several places: superclass * lookup may cause ZeroLink to load another image, and +load calls may * cause dyld to load another image. * @@ -82,7 +82,6 @@ * Read all classes in all new images. * Add them all to unconnected_class_hash. * Note any +load implementations before categories are attached. - * Fix up any pended classrefs referring to them. * Attach any pending categories. * Read all categories in all new images. * Attach categories whose parent class exists (connected or not), @@ -95,6 +94,7 @@ * If the superclass is connected: * connect the class * mark the class eligible for +load, if implemented + * fix up any pended classrefs referring to the class * connect any pended subclasses of the class * Resolve selector refs and class refs in all new images. * Class refs whose classes still do not exist are pended. @@ -131,6 +131,11 @@ * are attached. Otherwise, if a category implements +load and its class * has no class methods, the class's +load scan would find the category's * +load method, which would then be called twice. + * + * Correctness: pended class refs are not fixed up until the class is + * connected. Classes with missing weak superclasses remain unconnected. + * Class refs to classes with missing weak superclasses must be NULL. + * Therefore class refs to unconnected classes must remain un-fixed. * **********************************************************************/ @@ -933,6 +938,9 @@ static void really_connect_class(struct old_class *cls, mutex_unlock(&classLock); + // Fix up pended class refs to this class, if any + resolve_references_to_class(cls); + // Connect newly-connectable subclasses resolve_subclasses_of_class(cls); @@ -1226,9 +1234,6 @@ static void _objc_read_classes_from_image(header_info *hi) mutex_unlock(&classLock); if (!rejected) { - // Fix up pended class refs to this class, if any - resolve_references_to_class(newCls); - // Attach pended categories for this class, if any resolve_categories_for_class(newCls); } @@ -1308,16 +1313,17 @@ static void fix_class_ref(struct old_class **ref, const char *name, BOOL isMeta) struct old_class *cls; // Get pointer to class of this name - // YES unconnected, YES class loader - cls = _class_asOld((Class)look_up_class(name, YES, YES)); + // NO unconnected, YES class loader + // (real class with weak-missing superclass is unconnected now) + cls = _class_asOld((Class)look_up_class(name, NO, YES)); if (cls) { // Referenced class exists. Fix up the reference. *ref = isMeta ? cls->isa : cls; } else { - // Referenced class does not exist yet. Insert a placeholder - // class and fix up the reference later. + // Referenced class does not exist yet. Insert NULL for now + // (weak-linking) and fix up the reference if the class arrives later. pendClassReference (ref, name, isMeta); - *ref = (struct old_class *)_class_getNonexistentObjectClass(); + *ref = NULL; } } @@ -1354,7 +1360,7 @@ static void removePendingReferences(struct old_class **refs, size_t count) if (!pendingClassRefsMap) return; // Search the pending class ref table for class refs in this range. - // The class refs may have already been stomped with nonexistentClass, + // The class refs may have already been stomped with NULL, // so there's no way to recover the original class name. { @@ -2115,7 +2121,7 @@ static void rependClassReferences(struct old_class **refs, size_t count, if ((uintptr_t)(refs[i]) >= start && (uintptr_t)(refs[i]) < end) { pendClassReference(&refs[i], refs[i]->name, (refs[i]->info & CLS_META) ? YES : NO); - refs[i] = (struct old_class *)_class_getNonexistentObjectClass(); + refs[i] = NULL; } } } diff --git a/test/Makefile b/test/Makefile index 3c6e5fd..f2fa04a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -24,7 +24,7 @@ COMPLEX_BUILD_TESTS = cacheflush future unload ivarSlide ivarSlidexx \ # a "complex test" has a dedicated testname run rule below COMPLEX_RUN_TESTS = gcenforcer_noobjc gcenforcer_nogc gcenforcer_supportsgc \ - gcenforcer_requiresgc + gcenforcer_requiresgc weak-missing weak-not-missing # `make fail` just fails FAIL_TESTS = fail @@ -172,6 +172,15 @@ future0.out: future0.m future.h test.h Makefile future2.out: future2.m future.h future0.out test.h Makefile @ $(CC) -dynamiclib future2.m future0.out -o future2.out $(LIBS) +weak.out: weak.m weak2.m weak.h test.h Makefile + @ $(CC) weak2.m -dynamiclib -o libweak.dylib $(LIBS) + @ $(CC) weak2.m -DEMPTY= -dynamiclib -o libweak_empty.dylib $(LIBS) + @ $(CC) weak.m -L. -weak-lweak -o weak.out $(LIBS) + +weak-not-missing: weak.out + @ $(RUN) ./weak.out $(ERR_CHECK) weak-not-missing $(EAT_ERR) +weak-missing: weak.out + @ DYLD_IMAGE_SUFFIX=_empty $(RUN) ./weak.out $(ERR_CHECK) weak-missing $(EAT_ERR) CONCURRENT_IN=cc1 cc2 cc3 cc4 cc5 cc6 cc7 cc8 cc9 cc10 cc11 cc12 cc13 cc14 cc15 CONCURRENT_DYLIBS=$(addsuffix .out,$(CONCURRENT_IN)) diff --git a/test/weak.h b/test/weak.h new file mode 100644 index 0000000..a7bb2e5 --- /dev/null +++ b/test/weak.h @@ -0,0 +1,38 @@ +#include "test.h" +#include + +extern int state; + +@interface MissingRoot { + id isa; +} ++(void) initialize; ++(Class) class; ++(id) alloc; +-(id) init; ++(int) method; +@end + +@interface MissingSuper : MissingRoot { + @public + int ivar; +} +@end + + +@interface NotMissingRoot { + id isa; +} ++(void) initialize; ++(Class) class; ++(id) alloc; +-(id) init; ++(int) method; +@end + +@interface NotMissingSuper : NotMissingRoot { + @public + int unused[100]; + int ivar; +} +@end diff --git a/test/weak.m b/test/weak.m new file mode 100644 index 0000000..379f364 --- /dev/null +++ b/test/weak.m @@ -0,0 +1,294 @@ +#include "test.h" +#include "weak.h" + +// Subclass of superclass that isn't there +@interface MyMissingSuper : MissingSuper ++(int) method; +@end +@implementation MyMissingSuper ++(int) method { return 1+[super method]; } ++(void) load { state++; } +@end + +// Subclass of subclass of superclass that isn't there +@interface MyMissingSub : MyMissingSuper ++(int) method; +@end +@implementation MyMissingSub ++(int) method { return 1+[super method]; } ++(void) load { state++; } +@end + +// Subclass of real superclass +@interface MyNotMissingSuper : NotMissingSuper ++(int) method; +@end +@implementation MyNotMissingSuper ++(int) method { return 1+[super method]; } ++(void) load { state++; } +@end + +// Subclass of subclass of superclass that isn't there +@interface MyNotMissingSub : MyNotMissingSuper ++(int) method; +@end +@implementation MyNotMissingSub ++(int) method { return 1+[super method]; } ++(void) load { state++; } +@end + +// Categories on all of the above +@interface MissingRoot (MissingRootExtras) ++(void)load; ++(int) cat_method; +@end +@implementation MissingRoot (MissingRootExtras) ++(void)load { state++; } ++(int) cat_method { return 40; } +@end + +@interface MissingSuper (MissingSuperExtras) ++(void)load; ++(int) cat_method; +@end +@implementation MissingSuper (MissingSuperExtras) ++(void)load { state++; } ++(int) cat_method { return 1+[super cat_method]; } +@end + +@interface MyMissingSuper (MyMissingSuperExtras) ++(void)load; ++(int) cat_method; +@end +@implementation MyMissingSuper (MyMissingSuperExtras) ++(void)load { state++; } ++(int) cat_method { return 1+[super cat_method]; } +@end + +@interface MyMissingSub (MyMissingSubExtras) ++(void)load; ++(int) cat_method; +@end +@implementation MyMissingSub (MyMissingSubExtras) ++(void)load { state++; } ++(int) cat_method { return 1+[super cat_method]; } +@end + + +@interface NotMissingRoot (NotMissingRootExtras) ++(void)load; ++(int) cat_method; +@end +@implementation NotMissingRoot (NotMissingRootExtras) ++(void)load { state++; } ++(int) cat_method { return 30; } +@end + +@interface NotMissingSuper (NotMissingSuperExtras) ++(void)load; ++(int) cat_method; +@end +@implementation NotMissingSuper (NotMissingSuperExtras) ++(void)load { state++; } ++(int) cat_method { return 1+[super cat_method]; } +@end + +@interface MyNotMissingSuper (MyNotMissingSuperExtras) ++(void)load; ++(int) cat_method; +@end +@implementation MyNotMissingSuper (MyNotMissingSuperExtras) ++(void)load { state++; } ++(int) cat_method { return 1+[super cat_method]; } +@end + +@interface MyNotMissingSub (MyNotMissingSubExtras) ++(void)load; ++(int) cat_method; +@end +@implementation MyNotMissingSub (MyNotMissingSubExtras) ++(void)load { state++; } ++(int) cat_method { return 1+[super cat_method]; } +@end + + +static BOOL classInList(Class *classes, const char *name) +{ + Class *cp; + for (cp = classes; *cp; cp++) { + if (0 == strcmp(class_getName(*cp), name)) return YES; + } + return NO; +} + +static BOOL classInNameList(const char **names, const char *name) +{ + const char **cp; + for (cp = names; *cp; cp++) { + if (0 == strcmp(*cp, name)) return YES; + } + return NO; +} + +int main() +{ + // DYLD_IMAGE_SUFFIX=_empty loads the weak-missing version + BOOL weakMissing = NO; + if (getenv("DYLD_IMAGE_SUFFIX")) weakMissing = YES; + + // class and category +load methods + if (weakMissing) testassert(state == 8); + else testassert(state == 16); + state = 0; + + // classes + testassert([NotMissingRoot class]); + testassert([NotMissingSuper class]); + testassert([MyNotMissingSuper class]); + testassert([MyNotMissingSub class]); + if (weakMissing) { + testassert(! [MissingRoot class]); + testassert(! [MissingSuper class]); + testassert(! [MyMissingSuper class]); + testassert(! [MyMissingSub class]); + } else { + testassert([MissingRoot class]); + testassert([MissingSuper class]); + testassert([MyMissingSuper class]); + testassert([MyMissingSub class]); + } + + // objc_getClass + testassert(objc_getClass("NotMissingRoot")); + testassert(objc_getClass("NotMissingSuper")); + testassert(objc_getClass("MyNotMissingSuper")); + testassert(objc_getClass("MyNotMissingSub")); + if (weakMissing) { + testassert(! objc_getClass("MissingRoot")); + testassert(! objc_getClass("MissingSuper")); + testassert(! objc_getClass("MyMissingSuper")); + testassert(! objc_getClass("MyMissingSub")); + } else { + testassert(objc_getClass("MissingRoot")); + testassert(objc_getClass("MissingSuper")); + testassert(objc_getClass("MyMissingSuper")); + testassert(objc_getClass("MyMissingSub")); + } + + // class list + Class classes[100]; + int count = objc_getClassList(classes, 99); + classes[count] = NULL; + testassert(classInList(classes, "NotMissingRoot")); + testassert(classInList(classes, "NotMissingSuper")); + testassert(classInList(classes, "MyNotMissingSuper")); + testassert(classInList(classes, "MyNotMissingSub")); + if (weakMissing) { + testassert(! classInList(classes, "MissingRoot")); + testassert(! classInList(classes, "MissingSuper")); + testassert(! classInList(classes, "MyMissingSuper")); + testassert(! classInList(classes, "MyMissingSub")); + } else { + testassert(classInList(classes, "MissingRoot")); + testassert(classInList(classes, "MissingSuper")); + testassert(classInList(classes, "MyMissingSuper")); + testassert(classInList(classes, "MyMissingSub")); + } + + // class name list + const char *image = class_getImageName(objc_getClass("NotMissingRoot")); + testassert(image); + const char **names = objc_copyClassNamesForImage(image, NULL); + testassert(names); + testassert(classInNameList(names, "NotMissingRoot")); + testassert(classInNameList(names, "NotMissingSuper")); + if (weakMissing) { + testassert(! classInNameList(names, "MissingRoot")); + testassert(! classInNameList(names, "MissingSuper")); + } else { + testassert(classInNameList(names, "MissingRoot")); + testassert(classInNameList(names, "MissingSuper")); + } + free(names); + + image = class_getImageName(objc_getClass("MyNotMissingSub")); + testassert(image); + names = objc_copyClassNamesForImage(image, NULL); + testassert(names); + testassert(classInNameList(names, "MyNotMissingSuper")); + testassert(classInNameList(names, "MyNotMissingSub")); + if (weakMissing) { + testassert(! classInNameList(names, "MyMissingSuper")); + testassert(! classInNameList(names, "MyMissingSub")); + } else { + testassert(classInNameList(names, "MyMissingSuper")); + testassert(classInNameList(names, "MyMissingSub")); + } + free(names); + + // methods + testassert(20 == [NotMissingRoot method]); + testassert(21 == [NotMissingSuper method]); + testassert(22 == [MyNotMissingSuper method]); + testassert(23 == [MyNotMissingSub method]); + if (weakMissing) { + testassert(0 == [MissingRoot method]); + testassert(0 == [MissingSuper method]); + testassert(0 == [MyMissingSuper method]); + testassert(0 == [MyMissingSub method]); + } else { + testassert(10 == [MissingRoot method]); + testassert(11 == [MissingSuper method]); + testassert(12 == [MyMissingSuper method]); + testassert(13 == [MyMissingSub method]); + } + + // category methods + testassert(30 == [NotMissingRoot cat_method]); + testassert(31 == [NotMissingSuper cat_method]); + testassert(32 == [MyNotMissingSuper cat_method]); + testassert(33 == [MyNotMissingSub cat_method]); + if (weakMissing) { + testassert(0 == [MissingRoot cat_method]); + testassert(0 == [MissingSuper cat_method]); + testassert(0 == [MyMissingSuper cat_method]); + testassert(0 == [MyMissingSub cat_method]); + } else { + testassert(40 == [MissingRoot cat_method]); + testassert(41 == [MissingSuper cat_method]); + testassert(42 == [MyMissingSuper cat_method]); + testassert(43 == [MyMissingSub cat_method]); + } + + // allocations and ivars + id obj; + NotMissingSuper *obj2; + MissingSuper *obj3; + testassert((obj = [[NotMissingRoot alloc] init])); + free(obj); + testassert((obj2 = [[NotMissingSuper alloc] init])); + testassert(obj2->ivar == 200); free(obj2); + testassert((obj2 = [[MyNotMissingSuper alloc] init])); + testassert(obj2->ivar == 200); free(obj2); + testassert((obj2 = [[MyNotMissingSub alloc] init])); + testassert(obj2->ivar == 200); free(obj2); + if (weakMissing) { + testassert(! [[MissingRoot alloc] init]); + testassert(! [[MissingSuper alloc] init]); + testassert(! [[MyMissingSuper alloc] init]); + testassert(! [[MyMissingSub alloc] init]); + } else { + testassert((obj = [[MissingRoot alloc] init])); + free(obj); + testassert((obj3 = [[MissingSuper alloc] init])); + testassert(obj3->ivar == 100); free(obj3); + testassert((obj3 = [[MyMissingSuper alloc] init])); + testassert(obj3->ivar == 100); free(obj3); + testassert((obj3 = [[MyMissingSub alloc] init])); + testassert(obj3->ivar == 100); free(obj3); + } + + if (weakMissing) succeed("weak-missing"); + else succeed("weak-not-missing"); + return 0; +} diff --git a/test/weak2.m b/test/weak2.m new file mode 100644 index 0000000..ab17752 --- /dev/null +++ b/test/weak2.m @@ -0,0 +1,39 @@ +#include "test.h" +#include "weak.h" + +int state = 0; + +#if !defined(EMPTY) + +@implementation MissingRoot ++(void) initialize { } ++(Class) class { return self; } ++(id) alloc { return class_createInstance(self, 0); } +-(id) init { return self; } ++(int) method { return 10; } ++(void) load { state++; } +@end + +@implementation MissingSuper ++(int) method { return 1+[super method]; } +-(id) init { self = [super init]; ivar = 100; return self; } ++(void) load { state++; } +@end + +#endif + +@implementation NotMissingRoot ++(void) initialize { } ++(Class) class { return self; } ++(id) alloc { return class_createInstance(self, 0); } +-(id) init { return self; } ++(int) method { return 20; } ++(void) load { state++; } +@end + +@implementation NotMissingSuper ++(int) method { return 1+[super method]; } +-(id) init { self = [super init]; ivar = 200; return self; } ++(void) load { state++; } +@end +