Skip to content

Commit 0d98b77

Browse files
committed
[Obj-C] Fix undefined behaviour(s) in the new NSTaggedDate formatter.
Type punning through a union -> no good. double to uint64 to double again -> no good either. The nice side effect, other than silencing the sanitizer bot is that it fixes the formatting of some dates, e.g. Jan 1st 1970. <rdar://problem/47617983> llvm-svn: 353191
1 parent 78dc38e commit 0d98b77

File tree

1 file changed

+24
-28
lines changed

1 file changed

+24
-28
lines changed

lldb/source/Plugins/Language/ObjC/Cocoa.cpp

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "lldb/Utility/Stream.h"
2828

2929
#include "llvm/ADT/APInt.h"
30+
#include "llvm/ADT/bit.h"
3031

3132
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
3233

@@ -749,49 +750,43 @@ bool lldb_private::formatters::NSURLSummaryProvider(
749750
/// distantFuture, except within about 1e-25 second of the reference date.
750751
const int TAGGED_DATE_EXPONENT_BIAS = 0x3ef;
751752

752-
typedef union {
753-
struct {
754-
uint64_t fraction:52; // unsigned
755-
uint64_t exponent:11; // signed
756-
uint64_t sign:1;
757-
} repr;
758-
uint64_t i;
759-
double d;
760-
} DoubleBits;
761-
typedef union {
762-
struct {
763-
uint64_t fraction:52; // unsigned
764-
uint64_t exponent:7; // signed
765-
uint64_t sign:1;
766-
uint64_t unused:4; // placeholder for pointer tag bits
767-
} repr;
768-
uint64_t i;
769-
} TaggedDoubleBits;
753+
struct DoubleBits {
754+
uint64_t fraction : 52; // unsigned
755+
uint64_t exponent : 11; // signed
756+
uint64_t sign : 1;
757+
};
758+
759+
struct TaggedDoubleBits {
760+
uint64_t fraction : 52; // unsigned
761+
uint64_t exponent : 7; // signed
762+
uint64_t sign : 1;
763+
uint64_t unused : 4; // placeholder for pointer tag bits
764+
};
770765

771766
static uint64_t decodeExponent(uint64_t exp) {
772767
// Tagged exponent field is 7-bit signed. Sign-extend the value to 64 bits
773768
// before performing arithmetic.
774769
return llvm::SignExtend64<7>(exp) + TAGGED_DATE_EXPONENT_BIAS;
775770
}
776771

777-
static uint64_t decodeTaggedTimeInterval(uint64_t encodedTimeInterval) {
772+
static double decodeTaggedTimeInterval(uint64_t encodedTimeInterval) {
778773
if (encodedTimeInterval == 0)
779774
return 0.0;
780775
if (encodedTimeInterval == std::numeric_limits<uint64_t>::max())
781776
return (uint64_t)-0.0;
782777

783-
TaggedDoubleBits encodedBits = {};
784-
encodedBits.i = encodedTimeInterval;
785-
DoubleBits decodedBits;
778+
TaggedDoubleBits encodedBits =
779+
llvm::bit_cast<TaggedDoubleBits>(encodedTimeInterval);
780+
assert(encodedBits.unused == 0);
786781

787782
// Sign and fraction are represented exactly.
788783
// Exponent is encoded.
789-
assert(encodedBits.repr.unused == 0);
790-
decodedBits.repr.sign = encodedBits.repr.sign;
791-
decodedBits.repr.fraction = encodedBits.repr.fraction;
792-
decodedBits.repr.exponent = decodeExponent(encodedBits.repr.exponent);
784+
DoubleBits decodedBits;
785+
decodedBits.sign = encodedBits.sign;
786+
decodedBits.fraction = encodedBits.fraction;
787+
decodedBits.exponent = decodeExponent(encodedBits.exponent);
793788

794-
return decodedBits.d;
789+
return llvm::bit_cast<double>(decodedBits);
795790
}
796791

797792
bool lldb_private::formatters::NSDateSummaryProvider(
@@ -868,7 +863,8 @@ bool lldb_private::formatters::NSDateSummaryProvider(
868863

869864
// Accomodate for the __NSTaggedDate format introduced in Foundation 1600.
870865
if (class_name == g___NSTaggedDate) {
871-
auto *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
866+
auto *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
867+
process_sp->GetObjCLanguageRuntime());
872868
if (runtime && runtime->GetFoundationVersion() >= 1600)
873869
date_value = decodeTaggedTimeInterval(value_bits << 4);
874870
}

0 commit comments

Comments
 (0)