2020// Objective-C runtime
2121#include < objc/runtime.h>
2222
23- // For dlsym
24- #include < dlfcn.h>
25-
2623// For malloc_size
2724#include < malloc/malloc.h>
2825
29- // Do not thoroughly check valid memory pointers - it's too computationally intensive and slows down the runtime by 3 to 10 times
30- #define SKIP_CHECK_FOR_KNOWN_CLASS 1
31-
32- #pragma mark - Expose non exported Tagged Pointer functions from objc4-706/runtime/objc-internal.h
26+ #pragma mark - Expose non exported Tagged Pointer functions from objc4-781.2/runtime/objc-internal.h
3327
3428#if TARGET_OS_OSX && __x86_64__
35- // 64-bit Mac - tag bit is LSB
36- #define OBJC_MSB_TAGGED_POINTERS 0
37- #else
38- // Everything else - tag bit is MSB
39- #define OBJC_MSB_TAGGED_POINTERS 1
40- #endif
41-
42- #define _OBJC_TAG_INDEX_MASK 0x7
43- #define _OBJC_TAG_EXT_INDEX_MASK 0xff
44-
45- #if OBJC_MSB_TAGGED_POINTERS
46- #define _OBJC_TAG_MASK (1ULL << 63 )
47- #define _OBJC_TAG_INDEX_SHIFT 60
48- #define _OBJC_TAG_EXT_INDEX_SHIFT 52
29+ // 64-bit Mac - tag bit is LSB
30+ # define _OBJC_TAG_MASK 1UL
4931#else
50- #define _OBJC_TAG_MASK 1
51- #define _OBJC_TAG_INDEX_SHIFT 1
52- #define _OBJC_TAG_EXT_INDEX_SHIFT 4
32+ // Everything else - tag bit is MSB
33+ # define _OBJC_TAG_MASK (1ULL << 63 )
5334#endif
5435
55- #if defined __arm64__ && __arm64__
56- #define ISA_MASK 0x0000000ffffffff8ULL
57- #define ISA_MAGIC_MASK 0x000003f000000001ULL
58- #define ISA_MAGIC_VALUE 0x000001a000000001ULL
59-
60- #elif defined __x86_64__ && __x86_64__
61- #define ISA_MASK 0x00007ffffffffff8ULL
62- #define ISA_MAGIC_MASK 0x001f800000000001ULL
63- #define ISA_MAGIC_VALUE 0x001d800000000001ULL
64-
65- #elif (defined __arm__ && __arm__) || (defined __i386__ && __i386__)
66- #define SKIP_OBJECTIVE_C_CHECKS 1
67- #else
68- // Available bits in isa field are architecture-specific.
69- #error unknown architecture
70- #endif
71-
72- #if !defined SKIP_OBJECTIVE_C_CHECKS || !SKIP_OBJECTIVE_C_CHECKS
73-
74- typedef enum {
75- OBJC_TAG_NSAtom = 0 ,
76- OBJC_TAG_1 = 1 ,
77- OBJC_TAG_NSString = 2 ,
78- OBJC_TAG_NSNumber = 3 ,
79- OBJC_TAG_NSIndexPath = 4 ,
80- OBJC_TAG_NSManagedObjectID = 5 ,
81- OBJC_TAG_NSDate = 6 ,
82- OBJC_TAG_RESERVED_7 = 7 ,
83-
84- OBJC_TAG_First60BitPayload = 0 ,
85- OBJC_TAG_Last60BitPayload = 6 ,
86- OBJC_TAG_First52BitPayload = 8 ,
87- OBJC_TAG_Last52BitPayload = 263 ,
88-
89- OBJC_TAG_RESERVED_264 = 264
90- } objc_tag_index_t ;
91-
92- static inline bool _objc_isTaggedPointer (const void * ptr) {
93- return ((intptr_t )ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
36+ static inline bool _objc_isTaggedPointer (const void * _Nullable ptr) {
37+ return ((uintptr_t )ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
9438}
9539
96- static inline objc_tag_index_t _objc_getTaggedPointerTag (const void * ptr) {
97- uintptr_t basicTag = ((uintptr_t )ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
98- uintptr_t extTag = ((uintptr_t )ptr >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK;
99- if (basicTag == _OBJC_TAG_INDEX_MASK) {
100- return (objc_tag_index_t )(extTag + OBJC_TAG_First52BitPayload);
101- } else {
102- return (objc_tag_index_t )basicTag;
103- }
104- }
105-
106- #pragma mark - Tagged Pointer
107-
108- /* *
109- Returns the registered class for the given tag.
110- Returns nil if the tag is valid but has no registered class.
111-
112- This function searches the exported function: _objc_getClassForTag(objc_tag_index_t tag)
113- declared in https://opensource.apple.com/source/objc4/objc4-706/runtime/objc-internal.h
114- */
115- static Class _objc_getClassForTag (objc_tag_index_t tag) {
116- static bool _objc_getClassForTag_searched = false ;
117- static Class (*_objc_getClassForTag_func)(objc_tag_index_t ) = NULL ;
118- if (!_objc_getClassForTag_searched) {
119- _objc_getClassForTag_func = (Class (*)(objc_tag_index_t ))dlsym (RTLD_DEFAULT, " _objc_getClassForTag" );
120- _objc_getClassForTag_searched = true ;
121- if (_objc_getClassForTag_func == NULL ) {
122- fprintf (stderr, " *** Could not find _objc_getClassForTag()!\n " );
123- }
124- }
125-
126- if (_objc_getClassForTag_func != NULL ) {
127- return _objc_getClassForTag_func (tag);
128- }
129-
130- return NULL ;
131- }
132-
133- /* *
134- Test if a pointer is a tagged pointer
135-
136- @param inPtr is the pointer to check
137- @param outClass returns the registered class for the tagged pointer.
138- @return true if the pointer is a tagged pointer.
139- */
140- bool IsObjcTaggedPointer (const void * inPtr, Class* outClass) {
141- bool isTaggedPointer = _objc_isTaggedPointer (inPtr);
142- if (outClass != NULL ) {
143- if (isTaggedPointer) {
144- objc_tag_index_t tagIndex = _objc_getTaggedPointerTag (inPtr);
145- *outClass = _objc_getClassForTag (tagIndex);
146- } else {
147- *outClass = NULL ;
148- }
149- }
150-
151- return isTaggedPointer;
152- }
153-
154- #endif // !defined SKIP_OBJECTIVE_C_CHECKS || !SKIP_OBJECTIVE_C_CHECKS
155-
15640#pragma mark - Readable and valid memory
15741
15842/* *
15943 Test if the pointer points to readable and valid memory.
160-
16144 @param inPtr is the pointer
16245 @return true if the pointer points to readable and valid memory.
16346 */
@@ -214,14 +97,12 @@ bool IsObjcObject(const void* inPtr) {
21497 return false ;
21598 }
21699
217- #if !defined SKIP_OBJECTIVE_C_CHECKS || !SKIP_OBJECTIVE_C_CHECKS
218100 //
219- // Check for tagged pointers
101+ // Check if the pointer is a tagged objc pointer
220102 //
221- if (IsObjcTaggedPointer (inPtr, NULL )) {
103+ if (_objc_isTaggedPointer (inPtr)) {
222104 return true ;
223105 }
224- #endif
225106
226107 //
227108 // Check if the pointer is aligned
@@ -237,67 +118,13 @@ bool IsObjcObject(const void* inPtr) {
237118 return false ;
238119 }
239120
240- #if !defined SKIP_OBJECTIVE_C_CHECKS || !SKIP_OBJECTIVE_C_CHECKS
241- //
242- // From LLDB:
243- // Objective-C runtime has a rule that pointers in a class_t will only have bits 0 thru 46 set
244- // so if any pointer has bits 47 thru 63 high we know that this is not a valid isa
245- // See http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
246- //
247- if (((uintptr_t )inPtr & 0xFFFF800000000000 ) != 0 ) {
248- return false ;
249- }
250-
251- //
252- // Get the Class from the pointer
253- // From http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html :
254- // If you are writing a debugger-like tool, the Objective-C runtime exports some variables
255- // to help decode isa fields. objc_debug_isa_class_mask describes which bits are the class pointer:
256- // (isa & class_mask) == class pointer.
257- // objc_debug_isa_magic_mask and objc_debug_isa_magic_value describe some bits that help
258- // distinguish valid isa fields from other invalid values:
259- // (isa & magic_mask) == magic_value for isa fields that are not raw class pointers.
260- // These variables may change in the future so do not use them in application code.
261- //
262-
263- uintptr_t isa = (*(uintptr_t *)inPtr);
264121 Class ptrClass = NULL ;
265-
266- if ((isa & ~ISA_MASK) == 0 ) {
267- ptrClass = (Class)isa;
268- } else {
269- if ((isa & ISA_MAGIC_MASK) == ISA_MAGIC_VALUE) {
270- ptrClass = (Class)(isa & ISA_MASK);
271- } else {
272- ptrClass = (Class)isa;
273- }
274- }
122+ ptrClass = object_getClass ((id)inPtr);
275123
276124 if (ptrClass == NULL ) {
277125 return false ;
278126 }
279127
280- #if !defined(SKIP_CHECK_FOR_KNOWN_CLASS) || !SKIP_CHECK_FOR_KNOWN_CLASS
281- //
282- // Verifies that the found Class is a known class.
283- //
284- bool isKnownClass = false ;
285-
286- unsigned int numClasses = 0 ;
287- Class* classesList = objc_copyClassList (&numClasses);
288- for (unsigned i = 0 ; i < numClasses; i++) {
289- if (classesList[i] == ptrClass) {
290- isKnownClass = true ;
291- break ;
292- }
293- }
294- free (classesList);
295-
296- if (!isKnownClass) {
297- return false ;
298- }
299- #endif // !defined(SKIP_CHECK_FOR_KNOWN_CLASS) || !SKIP_CHECK_FOR_KNOWN_CLASS
300-
301128 //
302129 // From Greg Parker
303130 // https://twitter.com/gparker/status/801894068502433792
@@ -307,7 +134,6 @@ bool IsObjcObject(const void* inPtr) {
307134 if (pointerSize > 0 && pointerSize < class_getInstanceSize (ptrClass)) {
308135 return false ;
309136 }
310- #endif // !defined SKIP_OBJECTIVE_C_CHECKS || !SKIP_OBJECTIVE_C_CHECKS
311137
312138 return true ;
313139}
0 commit comments