diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
index 4ca2f233a..42930a35b 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
@@ -135,7 +135,10 @@
Identifier = "KSDebug_Tests">
+ Identifier = "KSObjC_Tests/testArrayDescription">
+
+
diff --git a/KSCrash.podspec b/KSCrash.podspec
index d2a332a07..283b97840 100644
--- a/KSCrash.podspec
+++ b/KSCrash.podspec
@@ -1,5 +1,5 @@
Pod::Spec.new do |s|
- IOS_DEPLOYMENT_TARGET = '11.0' unless defined? IOS_DEPLOYMENT_TARGET
+ IOS_DEPLOYMENT_TARGET = '12.0' unless defined? IOS_DEPLOYMENT_TARGET
s.name = "KSCrash"
s.version = "1.17.1"
s.summary = "The Ultimate iOS Crash Reporter"
@@ -7,9 +7,9 @@ Pod::Spec.new do |s|
s.license = { :type => 'KSCrash license agreement', :file => 'LICENSE' }
s.author = { "Karl Stenerud" => "kstenerud@gmail.com" }
s.ios.deployment_target = IOS_DEPLOYMENT_TARGET
- s.osx.deployment_target = '10.13'
- s.tvos.deployment_target = '11.0'
- s.watchos.deployment_target = '4.0'
+ s.osx.deployment_target = '10.14'
+ s.tvos.deployment_target = '12.0'
+ s.watchos.deployment_target = '5.0'
s.visionos.deployment_target = '1.0'
s.source = { :git => "https://github.com/kstenerud/KSCrash.git", :tag=>s.version.to_s }
s.frameworks = 'Foundation'
diff --git a/Package.swift b/Package.swift
index f9030099d..75610d128 100644
--- a/Package.swift
+++ b/Package.swift
@@ -5,10 +5,10 @@ import PackageDescription
let package = Package(
name: "KSCrash",
platforms: [
- .iOS(.v11),
- .tvOS(.v11),
- .watchOS(.v4),
- .macOS(.v10_13),
+ .iOS(.v12),
+ .tvOS(.v12),
+ .watchOS(.v5),
+ .macOS(.v10_14),
],
products: [
.library(
diff --git a/Sources/KSCrashRecordingCore/KSObjC.c b/Sources/KSCrashRecordingCore/KSObjC.c
index cf3cf7025..349620c64 100644
--- a/Sources/KSCrashRecordingCore/KSObjC.c
+++ b/Sources/KSCrashRecordingCore/KSObjC.c
@@ -156,14 +156,16 @@ static const char* g_blockBaseClassName = "NSBlock";
#pragma mark - Utility -
//======================================================================
-#if SUPPORT_TAGGED_POINTERS
-static bool isTaggedPointer(const void* pointer) {return (((uintptr_t)pointer) & TAG_MASK) != 0; }
-static int getTaggedSlot(const void* pointer) { return (int)((((uintptr_t)pointer) >> TAG_SLOT_SHIFT) & TAG_SLOT_MASK); }
-static uintptr_t getTaggedPayload(const void* pointer) { return (((uintptr_t)pointer) << TAG_PAYLOAD_LSHIFT) >> TAG_PAYLOAD_RSHIFT; }
+#if OBJC_HAVE_TAGGED_POINTERS
+static bool isTaggedPointer(const void* pointer) { return _objc_isTaggedPointer(pointer); }
+static int getTaggedSlot(const void* pointer) { return (int)_objc_getTaggedPointerTag(pointer); }
+static uintptr_t getTaggedPayload(const void* pointer) { return _objc_getTaggedPointerValue(pointer); }
+static intptr_t getTaggedSignedPayload(const void* pointer) { return _objc_getTaggedPointerSignedValue(pointer); }
#else
static bool isTaggedPointer(__unused const void* pointer) { return false; }
static int getTaggedSlot(__unused const void* pointer) { return 0; }
static uintptr_t getTaggedPayload(const void* pointer) { return (uintptr_t)pointer; }
+static intptr_t getTaggedSignedPayload(const void* pointer) { return (intptr_t)pointer; }
#endif
/** Get class data for a tagged pointer.
@@ -306,13 +308,8 @@ static bool isTaggedPointerNSDate(const void* const object)
*/
static int64_t extractTaggedNSNumber(const void* const object)
{
- intptr_t signedPointer = (intptr_t)object;
-#if SUPPORT_TAGGED_POINTERS
- intptr_t value = (signedPointer << TAG_PAYLOAD_LSHIFT) >> TAG_PAYLOAD_RSHIFT;
-#else
- intptr_t value = signedPointer & 0;
-#endif
-
+ intptr_t value = getTaggedSignedPayload(object);
+
// The lower 4 bits encode type information so shift them out.
return (int64_t)(value >> 4);
}
@@ -363,22 +360,83 @@ static int extractTaggedNSString(const void* const object, char* buffer, int buf
return length;
}
+#if OBJC_HAVE_TAGGED_POINTERS
+/** Decodes the exponent of a tagged NSDate pointer.
+ *
+ * @param exp The 7-bit exponent value from the tagged NSDate pointer.
+ * @return The decoded exponent value as a 64-bit unsigned integer.
+ *
+ * @note This function is based on the LLVM code in the Cocoa.cpp file: https://github.com/apple/llvm-project/blob/5dc9d563e5a6cd2cdd44117697dead98955ccddf/lldb/source/Plugins/Language/ObjC/Cocoa.cpp#L934
+ */
+static uint64_t decodeExponent(uint64_t exp)
+{
+ // Bias value for tagged pointer exponents.
+ // Recommended values:
+ // 0x3e3: encodes all dates between distantPast and distantFuture
+ // except for the range within about 1e-28 second of the reference date.
+ // 0x3ef: encodes all dates for a few million years beyond distantPast and
+ // distantFuture, except within about 1e-25 second of the reference date.
+ static const int taggedDateExponentBias = 0x3ef;
+
+ // Sign-extend the 7-bit exponent to 64 bits
+ const uint64_t signBit = 1ULL << 6;
+ const uint64_t extendMask = ~((1ULL << 7) - 1);
+ exp = (exp ^ signBit) - signBit;
+ exp &= (1ULL << 7) - 1;
+ exp |= extendMask & -((exp & signBit) != 0);
+
+ // Add the bias to the sign-extended exponent
+ return exp + taggedDateExponentBias;
+}
/** Extract a tagged NSDate's time value as an absolute time.
*
* @param object The NSDate object (must be a tagged pointer).
* @return The date's absolute time.
+ *
+ * @note This function is based on the LLVM code in the Cocoa.cpp file: https://github.com/apple/llvm-project/blob/5dc9d563e5a6cd2cdd44117697dead98955ccddf/lldb/source/Plugins/Language/ObjC/Cocoa.cpp#L913-L958
*/
static CFAbsoluteTime extractTaggedNSDate(const void* const object)
{
- uintptr_t payload = getTaggedPayload(object);
- // Payload is a 60-bit float. Fortunately we can just cast across from
- // an integer pointer after shifting out the upper 4 bits.
- payload <<= 4;
- CFAbsoluteTime value = *((CFAbsoluteTime*)&payload);
- return value;
-}
+ #pragma pack(4)
+ union {
+ uintptr_t raw;
+ struct {
+ uint64_t fraction : 52;
+ uint64_t exponent : 7;
+ uint64_t sign : 1;
+ uint64_t unused : 4;
+ } bits;
+ } encodedBits = { .raw = getTaggedPayload(object) };
+
+ if (encodedBits.raw == 0)
+ {
+ return 0.0;
+ }
+ if (encodedBits.raw == UINT64_MAX)
+ {
+ return -0.0;
+ }
+
+ #pragma pack(4)
+ union {
+ CFAbsoluteTime value;
+ struct {
+ uint64_t fraction : 52;
+ uint64_t exponent : 11;
+ uint64_t sign : 1;
+ } bits;
+ } decodedBits = {
+ .bits = {
+ .fraction = encodedBits.bits.fraction,
+ .exponent = decodeExponent(encodedBits.bits.exponent),
+ .sign = encodedBits.bits.sign
+ }
+ };
+ return decodedBits.value;
+}
+#endif
/** Get any special class metadata we have about the specified class.
* It will return a generic metadata object if the type is not recognized.
*
@@ -856,6 +914,7 @@ bool ksobjc_ivarNamed(const void* const classPtr, const char* name, KSObjCIvar*
bool ksobjc_ivarValue(const void* const objectPtr, int ivarIndex, void* dst)
{
+#if OBJC_HAVE_TAGGED_POINTERS
if(isTaggedPointer(objectPtr))
{
// Naively assume they want "value".
@@ -874,7 +933,7 @@ bool ksobjc_ivarValue(const void* const objectPtr, int ivarIndex, void* dst)
}
return false;
}
-
+#endif
const void* const classPtr = getIsaPointer(objectPtr);
const struct ivar_list_t* ivars = getClassRO(classPtr)->ivars;
if(ivarIndex >= (int)ivars->count)
@@ -1291,10 +1350,12 @@ static bool dateIsValid(const void* const datePtr)
CFAbsoluteTime ksobjc_dateContents(const void* const datePtr)
{
+#if OBJC_HAVE_TAGGED_POINTERS
if(isValidTaggedPointer(datePtr))
{
return extractTaggedNSDate(datePtr);
}
+#endif
const struct __CFDate* date = datePtr;
return date->_time;
}
@@ -1318,6 +1379,7 @@ static bool taggedDateIsValid(const void* const datePtr)
static int taggedDateDescription(const void* object, char* buffer, int bufferLength)
{
+#if OBJC_HAVE_TAGGED_POINTERS
char* pBuffer = buffer;
char* pEnd = buffer + bufferLength;
@@ -1326,6 +1388,9 @@ static int taggedDateDescription(const void* object, char* buffer, int bufferLen
pBuffer += stringPrintf(pBuffer, (int)(pEnd - pBuffer), ": %f", time);
return (int)(pBuffer - buffer);
+#else
+ return 0;
+#endif
}
diff --git a/Sources/KSCrashRecordingCore/include/KSObjCApple.h b/Sources/KSCrashRecordingCore/include/KSObjCApple.h
index 5a92c2328..a4ce0a6aa 100644
--- a/Sources/KSCrashRecordingCore/include/KSObjCApple.h
+++ b/Sources/KSCrashRecordingCore/include/KSObjCApple.h
@@ -57,71 +57,40 @@ NAME { \
# define ISA_MASK ~1UL
#endif
-
// ======================================================================
-#pragma mark - objc4-680/runtime/objc-config.h -
+#pragma mark - objc4-912.3/runtime/objc-config.h -
// ======================================================================
-// Define SUPPORT_TAGGED_POINTERS=1 to enable tagged pointer objects
-// Be sure to edit tagged pointer SPI in objc-internal.h as well.
-#if !(__LP64__)
-# define SUPPORT_TAGGED_POINTERS 0
-#else
-# define SUPPORT_TAGGED_POINTERS 1
-#endif
-
-// Define SUPPORT_MSB_TAGGED_POINTERS to use the MSB
-// as the tagged pointer marker instead of the LSB.
-// Be sure to edit tagged pointer SPI in objc-internal.h as well.
-#if !SUPPORT_TAGGED_POINTERS || !TARGET_OS_IPHONE
-# define SUPPORT_MSB_TAGGED_POINTERS 0
+#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
+# define SUPPORT_INDEXED_ISA 1
#else
-# define SUPPORT_MSB_TAGGED_POINTERS 1
+# define SUPPORT_INDEXED_ISA 0
#endif
-
// ======================================================================
-#pragma mark - objc4-680/runtime/objc-object.h -
+#pragma mark - objc4-912.3/runtime/objc-internal.h -
+// With removed nullability to suppress warning
// ======================================================================
-
-#if SUPPORT_TAGGED_POINTERS
-
-// KS: The original values wouldn't have worked. The slot shift and mask
-// were incorrect.
-#define TAG_COUNT 8
-//#define TAG_SLOT_MASK 0xf
-#define TAG_SLOT_MASK 0x07
-
-#if SUPPORT_MSB_TAGGED_POINTERS
-# define TAG_MASK (1ULL<<63)
-# define TAG_SLOT_SHIFT 60
-# define TAG_PAYLOAD_LSHIFT 4
-# define TAG_PAYLOAD_RSHIFT 4
-#else
-# define TAG_MASK 1
-//# define TAG_SLOT_SHIFT 0
-# define TAG_SLOT_SHIFT 1
-# define TAG_PAYLOAD_LSHIFT 0
-# define TAG_PAYLOAD_RSHIFT 4
-#endif
+#if __LP64__
+#define OBJC_HAVE_TAGGED_POINTERS 1
#endif
-// ======================================================================
-#pragma mark - objc4-781/runtime/objc-internal.h -
-// ======================================================================
-#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
-# define SUPPORT_INDEXED_ISA 1
-#else
-# define SUPPORT_INDEXED_ISA 0
-#endif
+// Tagged pointer layout and usage is subject to change on different OS versions.
-// ======================================================================
-#pragma mark - objc4-680/runtime/objc-internal.h -
-// ======================================================================
+// Tag indexes 0..<7 have a 60-bit payload.
+// Tag index 7 is reserved.
+// Tag indexes 8..<264 have a 52-bit payload.
+// Tag index 264 is reserved.
+#if __has_feature(objc_fixed_enum) || __cplusplus >= 201103L
+enum objc_tag_index_t : uint16_t
+#else
+typedef uint16_t objc_tag_index_t;
enum
+#endif
{
+ // 60-bit payloads
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2,
@@ -129,10 +98,377 @@ enum
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
- OBJC_TAG_7 = 7
+
+ // 60-bit reserved
+ OBJC_TAG_RESERVED_7 = 7,
+
+ // 52-bit payloads
+ OBJC_TAG_Photos_1 = 8,
+ OBJC_TAG_Photos_2 = 9,
+ OBJC_TAG_Photos_3 = 10,
+ OBJC_TAG_Photos_4 = 11,
+ OBJC_TAG_XPC_1 = 12,
+ OBJC_TAG_XPC_2 = 13,
+ OBJC_TAG_XPC_3 = 14,
+ OBJC_TAG_XPC_4 = 15,
+ OBJC_TAG_NSColor = 16,
+ OBJC_TAG_UIColor = 17,
+ OBJC_TAG_CGColor = 18,
+ OBJC_TAG_NSIndexSet = 19,
+ OBJC_TAG_NSMethodSignature = 20,
+ OBJC_TAG_UTTypeRecord = 21,
+ OBJC_TAG_Foundation_1 = 22,
+ OBJC_TAG_Foundation_2 = 23,
+ OBJC_TAG_Foundation_3 = 24,
+ OBJC_TAG_Foundation_4 = 25,
+ OBJC_TAG_CGRegion = 26,
+
+ // When using the split tagged pointer representation
+ // (OBJC_SPLIT_TAGGED_POINTERS), this is the first tag where
+ // the tag and payload are unobfuscated. All tags from here to
+ // OBJC_TAG_Last52BitPayload are unobfuscated. The shared cache
+ // builder is able to construct these as long as the low bit is
+ // not set (i.e. even-numbered tags).
+ OBJC_TAG_FirstUnobfuscatedSplitTag = 136, // 128 + 8, first ext tag with high bit set
+
+ OBJC_TAG_Constant_CFString = 136,
+
+ OBJC_TAG_First60BitPayload = 0,
+ OBJC_TAG_Last60BitPayload = 6,
+ OBJC_TAG_First52BitPayload = 8,
+ OBJC_TAG_Last52BitPayload = 263,
+
+ OBJC_TAG_RESERVED_264 = 264
};
+#if __has_feature(objc_fixed_enum) && !defined(__cplusplus)
+typedef enum objc_tag_index_t objc_tag_index_t;
+#endif
+
+#if OBJC_HAVE_TAGGED_POINTERS // (KSCrash) This line is moved here to make `objc_tag_index_t` enum visible for i386.
+
+// Returns true if tagged pointers are enabled.
+// The other functions below must not be called if tagged pointers are disabled.
+static inline bool
+_objc_taggedPointersEnabled(void);
+
+// Create a tagged pointer object with the given tag and payload.
+// Assumes the tag is valid.
+// Assumes tagged pointers are enabled.
+// The payload will be silently truncated to fit.
+static inline void *
+_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload);
+
+// Return true if ptr is a tagged pointer object.
+// Does not check the validity of ptr's class.
+static inline bool
+_objc_isTaggedPointer(const void *ptr);
+
+// Extract the tag value from the given tagged pointer object.
+// Assumes ptr is a valid tagged pointer object.
+// Does not check the validity of ptr's tag.
+static inline objc_tag_index_t
+_objc_getTaggedPointerTag(const void *ptr);
+
+// Extract the payload from the given tagged pointer object.
+// Assumes ptr is a valid tagged pointer object.
+// The payload value is zero-extended.
+static inline uintptr_t
+_objc_getTaggedPointerValue(const void *ptr);
+
+// Extract the payload from the given tagged pointer object.
+// Assumes ptr is a valid tagged pointer object.
+// The payload value is sign-extended.
+static inline intptr_t
+_objc_getTaggedPointerSignedValue(const void *ptr);
+
+// Don't use the values below. Use the declarations above.
+
+#if __arm64__
+// ARM64 uses a new tagged pointer scheme where normal tags are in
+// the low bits, extended tags are in the high bits, and half of the
+// extended tag space is reserved for unobfuscated payloads.
+# define OBJC_SPLIT_TAGGED_POINTERS 1
+#else
+# define OBJC_SPLIT_TAGGED_POINTERS 0
+#endif
+#if (TARGET_OS_OSX || TARGET_OS_MACCATALYST) && __x86_64__
+// 64-bit Mac - tag bit is LSB
+# define OBJC_MSB_TAGGED_POINTERS 0
+#else
+// Everything else - tag bit is MSB
+# define OBJC_MSB_TAGGED_POINTERS 1
+#endif
+
+#define _OBJC_TAG_INDEX_MASK 0x7UL
+
+#if OBJC_SPLIT_TAGGED_POINTERS
+#define _OBJC_TAG_SLOT_COUNT 8
+#define _OBJC_TAG_SLOT_MASK 0x7UL
+#else
+// array slot includes the tag bit itself
+#define _OBJC_TAG_SLOT_COUNT 16
+#define _OBJC_TAG_SLOT_MASK 0xfUL
+#endif
+
+#define _OBJC_TAG_EXT_INDEX_MASK 0xff
+// array slot has no extra bits
+#define _OBJC_TAG_EXT_SLOT_COUNT 256
+#define _OBJC_TAG_EXT_SLOT_MASK 0xff
+
+#if OBJC_SPLIT_TAGGED_POINTERS
+# define _OBJC_TAG_MASK (1UL<<63)
+# define _OBJC_TAG_INDEX_SHIFT 0
+# define _OBJC_TAG_SLOT_SHIFT 0
+# define _OBJC_TAG_PAYLOAD_LSHIFT 1
+# define _OBJC_TAG_PAYLOAD_RSHIFT 4
+# define _OBJC_TAG_EXT_MASK (_OBJC_TAG_MASK | 0x7UL)
+# define _OBJC_TAG_NO_OBFUSCATION_MASK ((1UL<<62) | _OBJC_TAG_EXT_MASK)
+# define _OBJC_TAG_CONSTANT_POINTER_MASK \
+~(_OBJC_TAG_EXT_MASK | ((uintptr_t)_OBJC_TAG_EXT_SLOT_MASK << _OBJC_TAG_EXT_SLOT_SHIFT))
+# define _OBJC_TAG_EXT_INDEX_SHIFT 55
+# define _OBJC_TAG_EXT_SLOT_SHIFT 55
+# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 9
+# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
+#elif OBJC_MSB_TAGGED_POINTERS
+# define _OBJC_TAG_MASK (1UL<<63)
+# define _OBJC_TAG_INDEX_SHIFT 60
+# define _OBJC_TAG_SLOT_SHIFT 60
+# define _OBJC_TAG_PAYLOAD_LSHIFT 4
+# define _OBJC_TAG_PAYLOAD_RSHIFT 4
+# define _OBJC_TAG_EXT_MASK (0xfUL<<60)
+# define _OBJC_TAG_EXT_INDEX_SHIFT 52
+# define _OBJC_TAG_EXT_SLOT_SHIFT 52
+# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
+# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
+#else
+# define _OBJC_TAG_MASK 1UL
+# define _OBJC_TAG_INDEX_SHIFT 1
+# define _OBJC_TAG_SLOT_SHIFT 0
+# define _OBJC_TAG_PAYLOAD_LSHIFT 0
+# define _OBJC_TAG_PAYLOAD_RSHIFT 4
+# define _OBJC_TAG_EXT_MASK 0xfUL
+# define _OBJC_TAG_EXT_INDEX_SHIFT 4
+# define _OBJC_TAG_EXT_SLOT_SHIFT 4
+# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
+# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
+#endif
+
+// Map of tags to obfuscated tags.
+extern uintptr_t objc_debug_taggedpointer_obfuscator;
+
+#if OBJC_SPLIT_TAGGED_POINTERS
+extern uint8_t objc_debug_tag60_permutations[8];
+
+static inline uintptr_t _objc_basicTagToObfuscatedTag(uintptr_t tag) {
+ return objc_debug_tag60_permutations[tag];
+}
+
+static inline uintptr_t _objc_obfuscatedTagToBasicTag(uintptr_t tag) {
+ for (unsigned i = 0; i < 7; i++)
+ if (objc_debug_tag60_permutations[i] == tag)
+ return i;
+ return 7;
+}
+#endif
+
+static inline void *
+_objc_encodeTaggedPointer_withObfuscator(uintptr_t ptr, uintptr_t obfuscator)
+{
+ uintptr_t value = (obfuscator ^ ptr);
+#if OBJC_SPLIT_TAGGED_POINTERS
+ if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
+ return (void *)ptr;
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ uintptr_t permutedTag = _objc_basicTagToObfuscatedTag(basicTag);
+ value &= ~(_OBJC_TAG_INDEX_MASK << _OBJC_TAG_INDEX_SHIFT);
+ value |= permutedTag << _OBJC_TAG_INDEX_SHIFT;
+#endif
+ return (void *)value;
+}
+
+static inline uintptr_t
+_objc_decodeTaggedPointer_noPermute_withObfuscator(const void *ptr,
+ uintptr_t obfuscator)
+{
+ uintptr_t value = (uintptr_t)ptr;
+#if OBJC_SPLIT_TAGGED_POINTERS
+ if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
+ return value;
+#endif
+ return value ^ obfuscator;
+}
+static inline uintptr_t
+_objc_decodeTaggedPointer_withObfuscator(const void *ptr,
+ uintptr_t obfuscator)
+{
+ uintptr_t value
+ = _objc_decodeTaggedPointer_noPermute_withObfuscator(ptr, obfuscator);
+#if OBJC_SPLIT_TAGGED_POINTERS
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+
+ value &= ~(_OBJC_TAG_INDEX_MASK << _OBJC_TAG_INDEX_SHIFT);
+ value |= _objc_obfuscatedTagToBasicTag(basicTag) << _OBJC_TAG_INDEX_SHIFT;
+#endif
+ return value;
+}
+
+static inline void *
+_objc_encodeTaggedPointer(uintptr_t ptr)
+{
+ return _objc_encodeTaggedPointer_withObfuscator(ptr, objc_debug_taggedpointer_obfuscator);
+}
+
+static inline uintptr_t
+_objc_decodeTaggedPointer_noPermute(const void *ptr)
+{
+ return _objc_decodeTaggedPointer_noPermute_withObfuscator(ptr, objc_debug_taggedpointer_obfuscator);
+}
+
+static inline uintptr_t
+_objc_decodeTaggedPointer(const void *ptr)
+{
+ return _objc_decodeTaggedPointer_withObfuscator(ptr, objc_debug_taggedpointer_obfuscator);
+}
+
+static inline bool
+_objc_taggedPointersEnabled(void)
+{
+ extern uintptr_t objc_debug_taggedpointer_mask;
+ return (objc_debug_taggedpointer_mask != 0);
+}
+
+__attribute__((no_sanitize("unsigned-shift-base")))
+static inline void *
+_objc_makeTaggedPointer_withObfuscator(objc_tag_index_t tag, uintptr_t value,
+ uintptr_t obfuscator)
+{
+ // PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts.
+ // They are reversed here for payload insertion.
+
+ // ASSERT(_objc_taggedPointersEnabled());
+ if (tag <= OBJC_TAG_Last60BitPayload) {
+ // ASSERT(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value);
+ uintptr_t result =
+ (_OBJC_TAG_MASK |
+ ((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) |
+ ((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));
+ return _objc_encodeTaggedPointer_withObfuscator(result, obfuscator);
+ } else {
+ // ASSERT(tag >= OBJC_TAG_First52BitPayload);
+ // ASSERT(tag <= OBJC_TAG_Last52BitPayload);
+ // ASSERT(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);
+ uintptr_t result =
+ (_OBJC_TAG_EXT_MASK |
+ ((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) |
+ ((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT));
+ return _objc_encodeTaggedPointer_withObfuscator(result, obfuscator);
+ }
+}
+
+static inline void *
+_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
+{
+ return _objc_makeTaggedPointer_withObfuscator(tag, value, objc_debug_taggedpointer_obfuscator);
+}
+
+static inline bool
+_objc_isTaggedPointer(const void *ptr)
+{
+ return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
+}
+
+static inline bool
+_objc_isTaggedPointerOrNil(const void *ptr)
+{
+ // this function is here so that clang can turn this into
+ // a comparison with NULL when this is appropriate
+ // it turns out it's not able to in many cases without this
+ return !ptr || ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
+}
+
+static inline objc_tag_index_t
+_objc_getTaggedPointerTag_withObfuscator(const void *ptr,
+ uintptr_t obfuscator)
+{
+ // ASSERT(_objc_isTaggedPointer(ptr));
+ uintptr_t value = _objc_decodeTaggedPointer_withObfuscator(ptr, obfuscator);
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ uintptr_t extTag = (value >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK;
+ if (basicTag == _OBJC_TAG_INDEX_MASK) {
+ return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload);
+ } else {
+ return (objc_tag_index_t)basicTag;
+ }
+}
+
+__attribute__((no_sanitize("unsigned-shift-base")))
+static inline uintptr_t
+_objc_getTaggedPointerValue_withObfuscator(const void *ptr,
+ uintptr_t obfuscator)
+{
+ // ASSERT(_objc_isTaggedPointer(ptr));
+ uintptr_t value = _objc_decodeTaggedPointer_noPermute_withObfuscator(ptr, obfuscator);
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ if (basicTag == _OBJC_TAG_INDEX_MASK) {
+ return (value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
+ } else {
+ return (value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
+ }
+}
+
+__attribute__((no_sanitize("unsigned-shift-base")))
+static inline intptr_t
+_objc_getTaggedPointerSignedValue_withObfuscator(const void *ptr,
+ uintptr_t obfuscator)
+{
+ // ASSERT(_objc_isTaggedPointer(ptr));
+ uintptr_t value = _objc_decodeTaggedPointer_noPermute_withObfuscator(ptr, obfuscator);
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ if (basicTag == _OBJC_TAG_INDEX_MASK) {
+ return ((intptr_t)value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
+ } else {
+ return ((intptr_t)value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
+ }
+}
+
+static inline objc_tag_index_t
+_objc_getTaggedPointerTag(const void *ptr)
+{
+ return _objc_getTaggedPointerTag_withObfuscator(ptr, objc_debug_taggedpointer_obfuscator);
+}
+
+static inline uintptr_t
+_objc_getTaggedPointerValue(const void *ptr)
+{
+ return _objc_getTaggedPointerValue_withObfuscator(ptr, objc_debug_taggedpointer_obfuscator);
+}
+
+static inline intptr_t
+_objc_getTaggedPointerSignedValue(const void *ptr)
+{
+ return _objc_getTaggedPointerSignedValue_withObfuscator(ptr, objc_debug_taggedpointer_obfuscator);
+}
+
+# if OBJC_SPLIT_TAGGED_POINTERS
+static inline void *
+_objc_getTaggedPointerRawPointerValue(const void *ptr) {
+ return (void *)((uintptr_t)ptr & _OBJC_TAG_CONSTANT_POINTER_MASK);
+}
+# endif
+
+#else
+
+// Just check for nil when we don't support tagged pointers.
+static inline bool
+_objc_isTaggedPointerOrNil(const void *ptr)
+{
+ return !ptr;
+}
+
+// OBJC_HAVE_TAGGED_POINTERS
+#endif
// ======================================================================
#pragma mark - objc4-680/runtime/objc-os.h -
diff --git a/Tests/KSCrashRecordingCoreTests/KSObjC_Tests.m b/Tests/KSCrashRecordingCoreTests/KSObjC_Tests.m
index 4a03018ab..e81ee44b6 100644
--- a/Tests/KSCrashRecordingCoreTests/KSObjC_Tests.m
+++ b/Tests/KSCrashRecordingCoreTests/KSObjC_Tests.m
@@ -735,7 +735,6 @@ - (void) testArrayDescriptionEmpty
- (void) testArrayDescription
{
-#if 0
NSArray* array = [NSArray arrayWithObjects:@"test", nil];
void* arrayPtr = (__bridge void*)array;
NSString* expectedClassName = [NSString stringWithCString:class_getName([array class]) encoding:NSUTF8StringEncoding];
@@ -758,7 +757,6 @@ - (void) testArrayDescription
expectedClassName = [NSString stringWithCString:class_getName([expectedTheRest class]) encoding:NSUTF8StringEncoding];
XCTAssertEqualObjects(className, expectedClassName, @"");
XCTAssertEqualObjects(theRest, expectedTheRest, @"");
-#endif
}
- (void) testCopyArrayContentsImmutable