Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix obfuscated pointers #470

Merged
merged 17 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@
Identifier = "KSDebug_Tests">
GLinnik21 marked this conversation as resolved.
Show resolved Hide resolved
</Test>
<Test
Identifier = "KSObjC_Tests">
Identifier = "KSObjC_Tests/testArrayDescription">
</Test>
<Test
Identifier = "KSObjC_Tests/testCopyArrayContentsMutable">
</Test>
</SkippedTests>
</TestableReference>
Expand Down
8 changes: 4 additions & 4 deletions KSCrash.podspec
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
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"
s.homepage = "https://github.com/kstenerud/KSCrash"
s.license = { :type => 'KSCrash license agreement', :file => 'LICENSE' }
s.author = { "Karl Stenerud" => "[email protected]" }
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'
Expand Down
8 changes: 4 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
92 changes: 75 additions & 17 deletions Sources/KSCrashRecordingCore/KSObjC.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -364,19 +361,80 @@ static int extractTaggedNSString(const void* const object, char* buffer, int buf
return length;
}

/** 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;
}

/** Get any special class metadata we have about the specified class.
Expand Down
Loading
Loading