You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
5.5 KiB

  1. //
  2. // FLEXObjcInternal.mm
  3. // FLEX
  4. //
  5. // Created by Tanner Bennett on 11/1/18.
  6. //
  7. /*
  8. * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved.
  9. *
  10. * @APPLE_LICENSE_HEADER_START@
  11. *
  12. * This file contains Original Code and/or Modifications of Original Code
  13. * as defined in and that are subject to the Apple Public Source License
  14. * Version 2.0 (the 'License'). You may not use this file except in
  15. * compliance with the License. Please obtain a copy of the License at
  16. * http://www.opensource.apple.com/apsl/ and read it before using this
  17. * file.
  18. *
  19. * The Original Code and all software distributed under the License are
  20. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  21. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  22. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  24. * Please see the License for the specific language governing rights and
  25. * limitations under the License.
  26. *
  27. * @APPLE_LICENSE_HEADER_END@
  28. */
  29. #import "FLEXObjcInternal.h"
  30. #import <objc/runtime.h>
  31. // For malloc_size
  32. #import <malloc/malloc.h>
  33. // For vm_region_64
  34. #include <mach/mach.h>
  35. #define ALWAYS_INLINE inline __attribute__((always_inline))
  36. #define NEVER_INLINE inline __attribute__((noinline))
  37. // The macros below are copied straight from
  38. // objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with
  39. // as few modifications as possible. Changes are noted in boxed comments.
  40. // https://opensource.apple.com/source/objc4/objc4-723/
  41. // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html
  42. // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html
  43. /////////////////////
  44. // objc-internal.h //
  45. /////////////////////
  46. #if __LP64__
  47. #define OBJC_HAVE_TAGGED_POINTERS 1
  48. #endif
  49. #if OBJC_HAVE_TAGGED_POINTERS
  50. #if TARGET_OS_OSX && __x86_64__
  51. // 64-bit Mac - tag bit is LSB
  52. # define OBJC_MSB_TAGGED_POINTERS 0
  53. #else
  54. // Everything else - tag bit is MSB
  55. # define OBJC_MSB_TAGGED_POINTERS 1
  56. #endif
  57. #if OBJC_MSB_TAGGED_POINTERS
  58. # define _OBJC_TAG_MASK (1UL<<63)
  59. # define _OBJC_TAG_EXT_MASK (0xfUL<<60)
  60. #else
  61. # define _OBJC_TAG_MASK 1UL
  62. # define _OBJC_TAG_EXT_MASK 0xfUL
  63. #endif
  64. //////////////////////////////////////
  65. // originally _objc_isTaggedPointer //
  66. //////////////////////////////////////
  67. static BOOL flex_isTaggedPointer(const void *ptr)
  68. {
  69. return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
  70. }
  71. ///////////////////
  72. // objc-object.h //
  73. ///////////////////
  74. ////////////////////////////////////////////////
  75. // originally objc_object::isExtTaggedPointer //
  76. ////////////////////////////////////////////////
  77. static BOOL flex_isExtTaggedPointer(const void *ptr)
  78. {
  79. return ((uintptr_t)ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;
  80. }
  81. #endif
  82. /////////////////////////////////////
  83. // FLEXObjectInternal //
  84. // No Apple code beyond this point //
  85. /////////////////////////////////////
  86. extern "C" {
  87. static BOOL FLEXPointerIsReadable(const void *inPtr)
  88. {
  89. kern_return_t error = KERN_SUCCESS;
  90. vm_size_t vmsize;
  91. vm_address_t address = (vm_address_t)inPtr;
  92. vm_region_basic_info_data_t info;
  93. mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
  94. memory_object_name_t object;
  95. error = vm_region_64(
  96. mach_task_self(),
  97. &address,
  98. &vmsize,
  99. VM_REGION_BASIC_INFO,
  100. (vm_region_info_t)&info,
  101. &info_count,
  102. &object
  103. );
  104. if (error != KERN_SUCCESS) {
  105. // vm_region/vm_region_64 returned an error
  106. return NO;
  107. } else if (!(BOOL)(info.protection & VM_PROT_READ)) {
  108. return NO;
  109. }
  110. // Read the memory
  111. vm_offset_t readMem = 0;
  112. mach_msg_type_number_t size = 0;
  113. address = (vm_address_t)inPtr;
  114. error = vm_read(mach_task_self(), address, sizeof(uintptr_t), &readMem, &size);
  115. if (error != KERN_SUCCESS) {
  116. // vm_read returned an error
  117. return NO;
  118. }
  119. return YES;
  120. }
  121. /// Accepts addresses that may or may not be readable.
  122. /// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
  123. BOOL FLEXPointerIsValidObjcObject(const void *ptr)
  124. {
  125. uintptr_t pointer = (uintptr_t)ptr;
  126. if (!ptr) {
  127. return NO;
  128. }
  129. #if OBJC_HAVE_TAGGED_POINTERS
  130. // Tagged pointers have 0x1 set, no other valid pointers do
  131. // objc-internal.h -> _objc_isTaggedPointer()
  132. if (flex_isTaggedPointer(ptr) || flex_isExtTaggedPointer(ptr)) {
  133. return YES;
  134. }
  135. #endif
  136. // Check pointer alignment
  137. if ((pointer % sizeof(uintptr_t)) != 0) {
  138. return NO;
  139. }
  140. // From LLDB:
  141. // Pointers in a class_t will only have bits 0 through 46 set,
  142. // so if any pointer has bits 47 through 63 high, we know that this is not a valid isa
  143. // https://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
  144. if ((pointer & 0xFFFF800000000000) != 0) {
  145. return NO;
  146. }
  147. // Make sure dereferencing this address won't crash
  148. if (!FLEXPointerIsReadable(ptr)) {
  149. return NO;
  150. }
  151. // http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
  152. // We check if the returned class is readable because object_getClass
  153. // can return a garbage value when given a non-nil pointer to a non-object
  154. Class cls = object_getClass((__bridge id)ptr);
  155. if (cls && FLEXPointerIsReadable((__bridge void *)cls) && object_isClass(cls)) {
  156. return YES;
  157. }
  158. return NO;
  159. }
  160. }