From 0592b48e55116fb083eb9c3d194462ab7edcbab7 Mon Sep 17 00:00:00 2001 From: Richard Frith-MacDonald Date: Sun, 13 Feb 2011 06:31:05 +0000 Subject: [PATCH] Raise when attempting to use unimplemented classes. Check for null pointers in more runtime functions (probably still many cases where we crash if null pointers are passed to the API and Apple behave more tolrantly). git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@32124 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 13 ++++ .../GNUstepBase/NSObject+GNUstepBase.h | 7 ++ Source/Additions/NSObject+GNUstepBase.m | 36 +++++++--- Source/NSCalendar.m | 8 +++ Source/NSLocale.m | 8 +++ Source/ObjectiveC2/runtime.c | 69 ++++++++++++++----- 6 files changed, 114 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index c572ca7be..bf8a97133 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2011-02-13 Richard Frith-Macdonald + + * Headers/Additions/GNUstepBase/NSObject+GNUstepBase.h: + * Source/Additions/NSObject+GNUstepBase.m: + Add -notImplemented:reason: to raise an exception when someone used + a class/method which depends on another library not present at + configure time. + * Source/NSCalendar.m: + * Source/NSLocale.m: + Raise exception if used when not implmented because of no UCU + * Source/ObjectiveC2/runtime.c: Fix some cases of dereferencing null + pointers. + 2011-02-12 Richard Frith-Macdonald * Source/NSObject.m: Obtain NSZombie class pointer using diff --git a/Headers/Additions/GNUstepBase/NSObject+GNUstepBase.h b/Headers/Additions/GNUstepBase/NSObject+GNUstepBase.h index 6859ec78d..84a95aa2c 100644 --- a/Headers/Additions/GNUstepBase/NSObject+GNUstepBase.h +++ b/Headers/Additions/GNUstepBase/NSObject+GNUstepBase.h @@ -76,6 +76,13 @@ extern "C" { */ - (id) notImplemented: (SEL)aSel GS_NORETURN_METHOD; +/** + * Message sent when an implementation wants to explicitly exclude a method + * (but cannot due to compiler constraint), and wants to make sure it is not + * called by mistake. Default implementation raises an exception at runtime. + */ +- (id) notImplemented: (SEL)aSel reason: (NSString*)reason GS_NORETURN_METHOD; + /** * Message sent when an implementation wants to explicitly require a subclass * to implement a method (but cannot at compile time since there is no diff --git a/Source/Additions/NSObject+GNUstepBase.m b/Source/Additions/NSObject+GNUstepBase.m index 46da2321a..0bf0325c2 100644 --- a/Source/Additions/NSObject+GNUstepBase.m +++ b/Source/Additions/NSObject+GNUstepBase.m @@ -90,32 +90,48 @@ - (id) notImplemented: (SEL)aSel { + char c = (class_isMetaClass(object_getClass(self)) ? '+' : '-'); + [NSException raise: NSGenericException - format: @"method %@ not implemented in %@(%s)", + format: @"[%@%c%@] not implemented", + NSStringFromClass([self class]), c, + aSel ? (id)NSStringFromSelector(aSel) : (id)@"(null)"]; + return nil; +} + +- (id) notImplemented: (SEL)aSel reason: (NSString*)reason +{ + char c = (class_isMetaClass(object_getClass(self)) ? '+' : '-'); + + [NSException + raise: NSGenericException + format: @"[%@%c%@] not implemented ... %@", + NSStringFromClass([self class]), c, aSel ? (id)NSStringFromSelector(aSel) : (id)@"(null)", - NSStringFromClass([self class]), - GSObjCIsInstance(self) ? "instance" : "class"]; + reason]; return nil; } - (id) shouldNotImplement: (SEL)aSel { + char c = (class_isMetaClass(object_getClass(self)) ? '+' : '-'); + [NSException raise: NSGenericException - format: @"%@(%s) should not implement %@", - NSStringFromClass([self class]), - GSObjCIsInstance(self) ? "instance" : "class", + format: @"[%@%c%@] should not be implemented", + NSStringFromClass([self class]), c, aSel ? (id)NSStringFromSelector(aSel) : (id)@"(null)"]; return nil; } - (id) subclassResponsibility: (SEL)aSel { - [NSException raise: NSInvalidArgumentException - format: @"subclass %@(%s) should override %@", - NSStringFromClass([self class]), - GSObjCIsInstance(self) ? "instance" : "class", + char c = (class_isMetaClass(object_getClass(self)) ? '+' : '-'); + + [NSException raise: NSGenericException + format: @"[%@%c%@] should be overridden by subclass", + NSStringFromClass([self class]), c, aSel ? (id)NSStringFromSelector(aSel) : (id)@"(null)"]; return nil; } diff --git a/Source/NSCalendar.m b/Source/NSCalendar.m index d3cdd522d..ec77a0876 100644 --- a/Source/NSCalendar.m +++ b/Source/NSCalendar.m @@ -155,6 +155,14 @@ static UCalendarDateFields _NSCalendarUnitToDateField (NSCalendarUnit unit) static NSCalendar *autoupdatingCalendar = nil; static NSRecursiveLock *classLock = nil; +#if GS_USE_ICU == 0 ++ (id) allocWithZone: (NSZone*)z +{ + [self notImplemented: _cmd + reason: @"missing ICU support at configure time."]; +} +#endif + + (void) initialize { if (self == [NSLocale class]) diff --git a/Source/NSLocale.m b/Source/NSLocale.m index 32d01e674..12873feed 100644 --- a/Source/NSLocale.m +++ b/Source/NSLocale.m @@ -179,6 +179,14 @@ static NSMutableDictionary *allLocales = nil; static NSDictionary *canonicalLocales = nil; static NSRecursiveLock *classLock = nil; +#if GS_USE_ICU == 0 ++ (id) allocWithZone: (NSZone*)z +{ + [self notImplemented: _cmd + reason: @"missing ICU support at configure time."]; +} +#endif + + (void) initialize { if (self == [NSLocale class]) diff --git a/Source/ObjectiveC2/runtime.c b/Source/ObjectiveC2/runtime.c index e800b15f6..5309f6fe5 100644 --- a/Source/ObjectiveC2/runtime.c +++ b/Source/ObjectiveC2/runtime.c @@ -102,21 +102,24 @@ skip_argspec(const char *types) static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector) { - struct objc_method_list *methods; - - for (methods = aClass->methods; - methods != NULL; methods = methods->method_next) + if (Nil != aClass) { - int i; + struct objc_method_list *methods; - for (i = 0; i < methods->method_count; i++) + for (methods = aClass->methods; + methods != NULL; methods = methods->method_next) { - Method_t method = &methods->method_list[i]; + int i; - if (method->method_name->sel_id == aSelector->sel_id) - { - return method; - } + for (i = 0; i < methods->method_count; i++) + { + Method_t method = &methods->method_list[i]; + + if (method->method_name->sel_id == aSelector->sel_id) + { + return method; + } + } } } return NULL; @@ -148,7 +151,7 @@ class_addIvar(Class cls, const char *name, unsigned off; Ivar ivar; - if (CLS_ISRESOLV(cls) || CLS_ISMETA(cls)) + if (Nil == cls || CLS_ISRESOLV(cls) || CLS_ISMETA(cls)) { return NO; } @@ -380,6 +383,10 @@ class_getInstanceMethod(Class aClass, SEL aSelector) Method class_getClassMethod(Class aClass, SEL aSelector) { + if (Nil == aClass) + { + return NULL; + } return class_getInstanceMethod(aClass->class_pointer, aSelector); } @@ -393,13 +400,17 @@ class_getClassVariable(Class cls, const char *name) size_t class_getInstanceSize(Class cls) { + if (Nil == cls) + { + return 0; + } return cls->instance_size; } Ivar class_getInstanceVariable(Class cls, const char *name) { - if (name != NULL) + if (Nil != cls && NULL != name) { while (cls != Nil) { @@ -430,6 +441,10 @@ class_getInstanceVariable(Class cls, const char *name) const char * class_getIvarLayout(Class cls) { + if (Nil == cls) + { + return 0; + } return (char *) cls->ivars; } @@ -444,18 +459,26 @@ class_getIvarLayout(Class cls) IMP class_getMethodImplementation(Class cls, SEL name) { + if (Nil == cls || 0 == name) + { + return 0; + } return (IMP) get_imp(cls, name); } IMP class_getMethodImplementation_stret(Class cls, SEL name) { + if (Nil == cls || 0 == name) + { + return 0; + } return (IMP) get_imp(cls, name); } const char * class_getName(Class cls) { - if (cls == Nil) + if (Nil == cls) { return "nil"; // This is what OSX does. } @@ -471,6 +494,10 @@ void __objc_resolve_class_links(void); Class class_getSuperclass(Class cls) { + if (Nil == cls) + { + return 0; + } if (!CLS_ISRESOLV(cls)) { /* This class is not yet resolved ... so lookup superclass by name. @@ -485,9 +512,13 @@ class_getSuperclass(Class cls) } int -class_getVersion(Class theClass) +class_getVersion(Class cls) { - return class_get_version(theClass); + if (Nil == cls) + { + return 0; + } + return class_get_version(cls); } const char * @@ -500,7 +531,11 @@ class_getWeakIvarLayout(Class cls) BOOL class_isMetaClass(Class cls) { - return CLS_ISMETA(cls); + if (Nil == cls || !CLS_ISMETA(cls)) + { + return NO; + } + return YES; } IMP