ObjFW  Diff

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]:


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
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(struct objc_abi_class *rawClass)
registerClass(Class class)
{
	if (classes == NULL)
		classes = objc_hashtable_new(
		    objc_hash_string, objc_equal_string, 2);

	objc_hashtable_set(classes, rawClass->name, rawClass);
	objc_hashtable_set(classes, class->name, class);

	if (emptyDTable == NULL)
		emptyDTable = objc_dtable_new();

	rawClass->DTable = emptyDTable;
	rawClass->metaclass->DTable = emptyDTable;
	class->DTable = emptyDTable;
	class->isa->DTable = emptyDTable;

	if (strcmp(rawClass->name, "Protocol") != 0)
	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
74

75
76


77
78

79
80
81


82
83
84
85
86
87
88
89
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(struct objc_abi_class *rawClass)
registerSelectors(Class class)
{
	struct objc_abi_method_list *methodList;
	struct objc_method_list *iter;
	unsigned int i;

	for (methodList = rawClass->methodList; methodList != NULL;
	for (iter = class->methodList; iter != NULL; iter = iter->next)
	    methodList = methodList->next)
		for (unsigned int i = 0; i < methodList->count; i++)
			objc_register_selector((struct objc_abi_selector *)
		for (i = 0; i < iter->count; i++)
			objc_register_selector(&iter->methods[i].selector);
			    &methodList->methods[i]);
}

Class
objc_classname_to_class(const char *name, bool cache)
{
	Class class;

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
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)
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 +=
		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;
				*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;
		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 = ((struct objc_abi_class *)class)->superclass;
	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
	} else {
		class->isa->isa = class->isa;
		class->isa->superclass = class;

	updateIVarOffsets(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
421

422
423
424
425

426
427
428
429



430
431
432
433
434
435
436
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_abi_symtab *symtab)
objc_register_all_classes(struct objc_symtab *symtab)
{
	for (uint16_t i = 0; i < symtab->classDefsCount; i++) {
		struct objc_abi_class *rawClass =
		    (struct objc_abi_class *)symtab->defs[i];
		Class class = (Class)symtab->defs[i];

		registerClass(rawClass);
		registerSelectors(rawClass);
		registerSelectors(rawClass->metaclass);
		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
496

497
498
499
500
501
502
503
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((struct objc_abi_class *)class);
	registerClass(class);

	if (class->superclass != Nil) {
		addSubclass(class);
		addSubclass(class->isa);
	}

	class->info |= OBJC_CLASS_INFO_SETUP;
757
758
759
760
761
762
763
764
765


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
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);
}

const char *
class_getMethodTypeEncoding(Class class, SEL selector)
Method
class_getInstanceMethod(Class class, SEL selector)
{
	struct objc_method *method;
	Method method;
	Class superclass;

	if (class == Nil)
		return NULL;

	objc_global_mutex_lock();

	if ((method = getMethod(class, selector)) != NULL) {
		const char *ret = method->selector.typeEncoding;
		objc_global_mutex_unlock();
		return ret;
		return method;
	}

	superclass = class->superclass;

	objc_global_mutex_unlock();

	if (class->superclass != Nil)
		return class_getMethodTypeEncoding(class->superclass, selector);
	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
869
870
871
872
873
874
875
876
877
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)
{
	struct objc_abi_class *rawClass = (struct objc_abi_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
906

907
908
909
910
911
912
913
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)
		rawClass->superclass = class->superclass->name;
		class->superclass = (Class)class->superclass->name;

	class->info &= ~OBJC_CLASS_INFO_SETUP;
}

void
objc_unregister_class(Class class)
{