Differences From Artifact [132bb904b5]:
- File
src/runtime/class.m
— part of check-in
[3b3729a316]
at
2019-06-25 20:09:55
on branch trunk
— runtime: Don't use static selectors
Static selectors are initialized by a global constructor that might run
too late: If a class has a +[load] that triggers an +[initialize], this
could result in trying to call +[initialize] with the selector in
class.m still being uninitialized. When this happens, it results in a
weird looking crash in an entirely unrelated method. This is because
when uninitialized, the selector name has not been replaced with a
selector UID yet, meaning the pointer to the selector name is treated as
the selector UID. As the dispatch only considers the low 16 bits of the
selector UID for performance reasons, it will just take the low 16 bits
of the pointer to the selector name as the UID without any complaints.
This can then result in calling a random method on that class which then
crashes. (user: js, size: 21746) [annotate] [blame] [check-ins using]
To Artifact [415251c564]:
- File src/runtime/class.m — part of check-in [9e23a50de7] at 2019-12-13 00:00:54 on branch trunk — runtime: Add class_getInstanceMethod() (user: js, size: 21732) [annotate] [blame] [check-ins using] [more...]
︙ | ︙ | |||
30 31 32 33 34 35 36 | static Class *loadQueue = NULL; static size_t loadQueueCount = 0; static struct objc_dtable *emptyDTable = NULL; static unsigned lookupsUntilFastPath = 128; static struct objc_sparsearray *fastPath = NULL; static void | | | | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | static Class *loadQueue = NULL; static size_t loadQueueCount = 0; static struct objc_dtable *emptyDTable = NULL; static unsigned lookupsUntilFastPath = 128; static struct objc_sparsearray *fastPath = NULL; static void registerClass(Class class) { if (classes == NULL) classes = objc_hashtable_new( objc_hash_string, objc_equal_string, 2); objc_hashtable_set(classes, class->name, class); if (emptyDTable == NULL) emptyDTable = objc_dtable_new(); class->DTable = emptyDTable; class->isa->DTable = emptyDTable; if (strcmp(class->name, "Protocol") != 0) classesCount++; } bool class_registerAlias_np(Class class, const char *name) { objc_global_mutex_lock(); |
︙ | ︙ | |||
67 68 69 70 71 72 73 | objc_global_mutex_unlock(); return YES; } static void | | | > | < | | < | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | objc_global_mutex_unlock(); return YES; } static void registerSelectors(Class class) { struct objc_method_list *iter; unsigned int i; for (iter = class->methodList; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) objc_register_selector(&iter->methods[i].selector); } Class objc_classname_to_class(const char *name, bool cache) { Class class; |
︙ | ︙ | |||
253 254 255 256 257 258 259 | OBJC_ERROR("Not enough memory for subclass list of class %s\n", class->superclass->name); class->superclass->subclassList[i] = class; class->superclass->subclassList[i + 1] = Nil; } | < | | | | | | | | | > > > > > > > > > > | > | > | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | OBJC_ERROR("Not enough memory for subclass list of class %s\n", class->superclass->name); class->superclass->subclassList[i] = class; class->superclass->subclassList[i + 1] = Nil; } static void updateIvarOffsets(Class class) { if (!(class->info & OBJC_CLASS_INFO_NEW_ABI)) return; if (class->instanceSize > 0) return; class->instanceSize = -class->instanceSize; if (class->superclass != Nil) { class->instanceSize += class->superclass->instanceSize; if (class->ivars != NULL) { for (unsigned int i = 0; i < class->ivars->count; i++) { class->ivars->ivars[i].offset += class->superclass->instanceSize; *class->ivarOffsets[i] = class->ivars->ivars[i].offset; } } } else for (unsigned int i = 0; i < class->ivars->count; i++) *class->ivarOffsets[i] = class->ivars->ivars[i].offset; } static void setupClass(Class class) { const char *superclassName; if (class->info & OBJC_CLASS_INFO_SETUP) return; superclassName = (const char *)class->superclass; if (superclassName != NULL) { Class super = objc_classname_to_class(superclassName, false); Class rootClass; if (super == Nil) return; setupClass(super); if (!(super->info & OBJC_CLASS_INFO_SETUP)) return; /* * GCC sets class->isa->isa to the name of the root class, * while Clang just sets it to Nil. Therefore always calculate * it. */ for (Class iter = super; iter != NULL; iter = iter->superclass) rootClass = iter; class->superclass = super; class->isa->isa = rootClass->isa; class->isa->superclass = super->isa; addSubclass(class); addSubclass(class->isa); } else { class->isa->isa = class->isa; class->isa->superclass = class; } updateIvarOffsets(class); class->info |= OBJC_CLASS_INFO_SETUP; class->isa->info |= OBJC_CLASS_INFO_SETUP; } static void initializeClass(Class class) |
︙ | ︙ | |||
414 415 416 417 418 419 420 | if (loadQueue == NULL) OBJC_ERROR("Not enough memory for load queue!"); } } } void | | < | | | | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | if (loadQueue == NULL) OBJC_ERROR("Not enough memory for load queue!"); } } } void objc_register_all_classes(struct objc_symtab *symtab) { for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; registerClass(class); registerSelectors(class); registerSelectors(class->isa); } for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; if (hasLoad(class)) { setupClass(class); |
︙ | ︙ | |||
489 490 491 492 493 494 495 | } void objc_registerClassPair(Class class) { objc_global_mutex_lock(); | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | } void objc_registerClassPair(Class class) { objc_global_mutex_lock(); registerClass(class); if (class->superclass != Nil) { addSubclass(class); addSubclass(class->isa); } class->info |= OBJC_CLASS_INFO_SETUP; |
︙ | ︙ | |||
757 758 759 760 761 762 763 | methodList->methods[0].implementation = implementation; class->methodList = methodList; objc_update_dtable(class); } | | | | > < | > > | | | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 | methodList->methods[0].implementation = implementation; class->methodList = methodList; objc_update_dtable(class); } Method class_getInstanceMethod(Class class, SEL selector) { Method method; Class superclass; if (class == Nil) return NULL; objc_global_mutex_lock(); if ((method = getMethod(class, selector)) != NULL) { objc_global_mutex_unlock(); return method; } superclass = class->superclass; objc_global_mutex_unlock(); if (superclass != Nil) return class_getInstanceMethod(superclass, selector); return NULL; } bool class_addMethod(Class class, SEL selector, IMP implementation, const char *typeEncoding) |
︙ | ︙ | |||
862 863 864 865 866 867 868 | { return class_getName(object_getClass(object)); } static void unregisterClass(Class class) { | < < | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | { return class_getName(object_getClass(object)); } static void unregisterClass(Class class) { if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil && class->superclass->subclassList != NULL) { size_t i = SIZE_MAX, count = 0; Class *tmp; for (tmp = class->superclass->subclassList; *tmp != Nil; tmp++) { |
︙ | ︙ | |||
899 900 901 902 903 904 905 | if (class->DTable != NULL && class->DTable != emptyDTable) objc_dtable_free(class->DTable); class->DTable = NULL; if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil) | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | if (class->DTable != NULL && class->DTable != emptyDTable) objc_dtable_free(class->DTable); class->DTable = NULL; if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil) class->superclass = (Class)class->superclass->name; class->info &= ~OBJC_CLASS_INFO_SETUP; } void objc_unregister_class(Class class) { |
︙ | ︙ |