swiftMetadataInitializerRealloc.m 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. TEST_CONFIG MEM=mrc
  3. TEST_BUILD
  4. $C{COMPILE} $DIR/swiftMetadataInitializerRealloc-dylib1.m -o libswiftMetadataInitializerRealloc-dylib1.dylib -dynamiclib -Wno-deprecated-objc-pointer-introspection
  5. $C{COMPILE} $DIR/swiftMetadataInitializerRealloc-dylib2.m -o libswiftMetadataInitializerRealloc-dylib2.dylib -dynamiclib -L. -lswiftMetadataInitializerRealloc-dylib1
  6. $C{COMPILE} $DIR/swiftMetadataInitializerRealloc.m -o swiftMetadataInitializerRealloc.exe -L. -lswiftMetadataInitializerRealloc-dylib1 -Wno-deprecated-objc-pointer-introspection
  7. END
  8. */
  9. #include "test.h"
  10. #include "swift-class-def.m"
  11. // _objc_swiftMetadataInitializer hooks for the classes in swift-class-def.m
  12. Class initSuper(Class cls __unused, void *arg __unused)
  13. {
  14. // This test provokes objc's callback out of superclass order.
  15. // SwiftSub's init is first. SwiftSuper's init is never called.
  16. fail("SwiftSuper's init should not have been called");
  17. }
  18. bool isRealized(Class cls)
  19. {
  20. // check the is-realized bits directly
  21. #if __LP64__
  22. # define mask (~(uintptr_t)7)
  23. #else
  24. # define mask (~(uintptr_t)3)
  25. #endif
  26. #define RW_REALIZED (1<<31)
  27. uintptr_t rw = ((uintptr_t *)cls)[4] & mask; // class_t->data
  28. return ((uint32_t *)rw)[0] & RW_REALIZED; // class_rw_t->flags
  29. }
  30. SWIFT_CLASS(SwiftSuper, NSObject, initSuper);
  31. SWIFT_CLASS(RealSwiftSub, SwiftSuper, initSub);
  32. SWIFT_STUB_CLASS(SwiftSub, initSub);
  33. OBJC_EXPORT _Nullable Class
  34. objc_loadClassref(_Nullable Class * _Nonnull clsref);
  35. static int SubInits = 0;
  36. Class initSub(Class cls, void *arg)
  37. {
  38. testprintf("initSub callback\n");
  39. testassert(SubInits == 0);
  40. SubInits++;
  41. testassert(arg == nil);
  42. testassert(cls == RawSwiftSub);
  43. testassert(!isRealized(RawSwiftSuper));
  44. // Copy the class to the heap to ensure they're registered properly.
  45. // Classes in the data segment are automatically "known" even if not
  46. // added as a known class. Swift dynamically allocates classes from
  47. // a statically allocated space in the dylib, then allocates from
  48. // the heap after it runs out of room there. Code that only works
  49. // when the class is in a dylib can fail a long time down the road
  50. // when something finally exceeds the capacity of that space.
  51. // Example: rdar://problem/50707074
  52. Class HeapSwiftSub = (Class)malloc(OBJC_MAX_CLASS_SIZE);
  53. memcpy(HeapSwiftSub, RawRealSwiftSub, OBJC_MAX_CLASS_SIZE);
  54. testprintf("initSub beginning _objc_realizeClassFromSwift\n");
  55. _objc_realizeClassFromSwift(HeapSwiftSub, cls);
  56. testprintf("initSub finished _objc_realizeClassFromSwift\n");
  57. testassert(isRealized(RawSwiftSuper));
  58. testassert(isRealized(HeapSwiftSub));
  59. testprintf("Returning reallocated class %p\n", HeapSwiftSub);
  60. return HeapSwiftSub;
  61. }
  62. @interface SwiftSub (Addition)
  63. - (int)number;
  64. @end
  65. @implementation SwiftSub (Addition)
  66. - (int)number { return 42; }
  67. @end
  68. @interface NSObject (DylibCategories)
  69. - (const char *)dylib1ACategoryInSameDylib;
  70. - (const char *)dylib1BCategoryInSameDylib;
  71. - (const char *)dylib1ACategoryInOtherDylib;
  72. - (const char *)dylib1BCategoryInOtherDylib;
  73. - (const char *)dylib1ACategoryInApp;
  74. - (const char *)dylib1BCategoryInApp;
  75. + (const char *)dylib1ACategoryInAppClassMethod;
  76. + (const char *)dylib1BCategoryInAppClassMethod;
  77. + (void)testFromOtherDylib;
  78. @end
  79. extern int Dylib1AInits;
  80. extern int Dylib1BInits;
  81. SWIFT_STUB_CLASSREF(SwiftDylib1A);
  82. SWIFT_STUB_CLASSREF(SwiftDylib1B);
  83. void Dylib1Test(void);
  84. @interface SwiftDylib1A: NSObject @end
  85. @interface SwiftDylib1B: NSObject @end
  86. @implementation SwiftDylib1A (Category)
  87. - (const char *)dylib1ACategoryInApp { return "dylib1ACategoryInApp"; }
  88. + (const char *)dylib1ACategoryInAppClassMethod { return "dylib1ACategoryInAppClassMethod"; }
  89. @end
  90. @implementation SwiftDylib1B (Category)
  91. - (const char *)dylib1BCategoryInApp { return "dylib1BCategoryInApp"; }
  92. + (const char *)dylib1BCategoryInAppClassMethod { return "dylib1BCategoryInAppClassMethod"; }
  93. @end
  94. int main()
  95. {
  96. #define LOG(fmt, expr) testprintf(#expr " is " #fmt "\n", expr);
  97. LOG(%p, SwiftSubClassref);
  98. Class loadedSwiftSub = objc_loadClassref(&SwiftSubClassref);
  99. LOG(%p, SwiftSubClassref);
  100. LOG(%p, loadedSwiftSub);
  101. LOG(%p, [loadedSwiftSub class]);
  102. LOG(%p, [loadedSwiftSub superclass]);
  103. LOG(%p, [RawSwiftSuper class]);
  104. id obj = [[loadedSwiftSub alloc] init];
  105. LOG(%p, obj);
  106. LOG(%d, [obj number]);
  107. LOG(%p, SwiftDylib1AClassref);
  108. testassert(Dylib1AInits == 0);
  109. testassert((uintptr_t)SwiftDylib1AClassref & 1);
  110. Class SwiftDylib1A = objc_loadClassref(&SwiftDylib1AClassref);
  111. testassert(((uintptr_t)SwiftDylib1AClassref & 1) == 0);
  112. testassert(SwiftDylib1A == [SwiftDylib1A class]);
  113. testassert(SwiftDylib1A == SwiftDylib1AClassref);
  114. testassert(Dylib1AInits == 1);
  115. LOG(%p, SwiftDylib1A);
  116. LOG(%p, SwiftDylib1BClassref);
  117. testassert(Dylib1BInits == 0);
  118. testassert((uintptr_t)SwiftDylib1BClassref & 1);
  119. Class SwiftDylib1B = objc_loadClassref(&SwiftDylib1BClassref);
  120. testassert(((uintptr_t)SwiftDylib1BClassref & 1) == 0);
  121. testassert(SwiftDylib1B == [SwiftDylib1B class]);
  122. testassert(SwiftDylib1B == SwiftDylib1BClassref);
  123. testassert(Dylib1BInits == 1);
  124. LOG(%p, SwiftDylib1B);
  125. Dylib1Test();
  126. testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInSameDylib], "dylib1ACategoryInSameDylib") == 0);
  127. testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInSameDylib], "dylib1BCategoryInSameDylib") == 0);
  128. testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInApp], "dylib1ACategoryInApp") == 0);
  129. testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInApp], "dylib1BCategoryInApp") == 0);
  130. void *handle = dlopen("libswiftMetadataInitializerRealloc-dylib2.dylib", RTLD_LAZY);
  131. testassert(handle);
  132. testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInOtherDylib], "dylib1ACategoryInOtherDylib") == 0);
  133. testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInOtherDylib], "dylib1BCategoryInOtherDylib") == 0);
  134. testassert(strcmp([SwiftDylib1A dylib1ACategoryInAppClassMethod], "dylib1ACategoryInAppClassMethod") == 0);
  135. testassert(strcmp([SwiftDylib1B dylib1BCategoryInAppClassMethod], "dylib1BCategoryInAppClassMethod") == 0);
  136. [SwiftDylib1A testFromOtherDylib];
  137. testassert(objc_getClass("RealSwiftSub"));
  138. testassert(objc_getClass("RealSwiftDylib1A"));
  139. testassert(objc_getClass("RealSwiftDylib1B"));
  140. succeed(__FILE__);
  141. }