1 //===-- ubsan_value.cpp ---------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Representation of a runtime value, as marshaled from the generated code to
12 //===----------------------------------------------------------------------===//
14 #include "ubsan_platform.h"
16 #include "ubsan_value.h"
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_libc.h"
19 #include "sanitizer_common/sanitizer_mutex.h"
21 // TODO(dliew): Prefer '__APPLE__' here over 'SANITIZER_MAC', as the latter is
22 // unclear. rdar://58124919 tracks using a more obviously portable guard.
23 #if defined(__APPLE__)
27 using namespace __ubsan
;
29 typedef const char *(*ObjCGetClassNameTy
)(void *);
31 const char *__ubsan::getObjCClassName(ValueHandle Pointer
) {
32 #if defined(__APPLE__)
33 // We need to query the ObjC runtime for some information, but do not want
34 // to introduce a static dependency from the ubsan runtime onto ObjC. Try to
35 // grab a handle to the ObjC runtime used by the process.
36 static bool AttemptedDlopen
= false;
37 static void *ObjCHandle
= nullptr;
38 static void *ObjCObjectGetClassName
= nullptr;
40 // Prevent threads from racing to dlopen().
41 static __sanitizer::StaticSpinMutex Lock
;
43 __sanitizer::SpinMutexLock
Guard(&Lock
);
45 if (!AttemptedDlopen
) {
47 "/usr/lib/libobjc.A.dylib",
48 RTLD_LAZY
// Only bind symbols when used.
49 | RTLD_LOCAL
// Only make symbols available via the handle.
50 | RTLD_NOLOAD
// Do not load the dylib, just grab a handle if the
51 // image is already loaded.
52 | RTLD_FIRST
// Only search the image pointed-to by the handle.
54 AttemptedDlopen
= true;
57 ObjCObjectGetClassName
= dlsym(ObjCHandle
, "object_getClassName");
61 if (!ObjCObjectGetClassName
)
64 return ObjCGetClassNameTy(ObjCObjectGetClassName
)((void *)Pointer
);
70 SIntMax
Value::getSIntValue() const {
71 CHECK(getType().isSignedIntegerTy());
73 // Val was zero-extended to ValueHandle. Sign-extend from original width
75 const unsigned ExtraBits
=
76 sizeof(SIntMax
) * 8 - getType().getIntegerBitWidth();
77 return SIntMax(UIntMax(Val
) << ExtraBits
) >> ExtraBits
;
79 if (getType().getIntegerBitWidth() == 64)
80 return *reinterpret_cast<s64
*>(Val
);
82 if (getType().getIntegerBitWidth() == 128)
83 return *reinterpret_cast<s128
*>(Val
);
85 if (getType().getIntegerBitWidth() == 128)
86 UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
88 UNREACHABLE("unexpected bit width");
91 UIntMax
Value::getUIntValue() const {
92 CHECK(getType().isUnsignedIntegerTy());
95 if (getType().getIntegerBitWidth() == 64)
96 return *reinterpret_cast<u64
*>(Val
);
98 if (getType().getIntegerBitWidth() == 128)
99 return *reinterpret_cast<u128
*>(Val
);
101 if (getType().getIntegerBitWidth() == 128)
102 UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
104 UNREACHABLE("unexpected bit width");
107 UIntMax
Value::getPositiveIntValue() const {
108 if (getType().isUnsignedIntegerTy())
109 return getUIntValue();
110 SIntMax Val
= getSIntValue();
115 /// Get the floating-point value of this object, extended to a long double.
116 /// These are always passed by address (our calling convention doesn't allow
117 /// them to be passed in floating-point registers, so this has little cost).
118 FloatMax
Value::getFloatValue() const {
119 CHECK(getType().isFloatTy());
120 if (isInlineFloat()) {
121 switch (getType().getFloatBitWidth()) {
123 // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
124 // from '__fp16' to 'long double'.
127 internal_memcpy(&Value
, &Val
, 4);
133 #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
134 // For big endian the float value is in the last 4 bytes.
135 // On some targets we may only have 4 bytes so we count backwards from
136 // the end of Val to account for both the 32-bit and 64-bit cases.
137 internal_memcpy(&Value
, ((const char*)(&Val
+ 1)) - 4, 4);
139 internal_memcpy(&Value
, &Val
, 4);
145 internal_memcpy(&Value
, &Val
, 8);
150 switch (getType().getFloatBitWidth()) {
151 case 64: return *reinterpret_cast<double*>(Val
);
152 case 80: return *reinterpret_cast<long double*>(Val
);
153 case 96: return *reinterpret_cast<long double*>(Val
);
154 case 128: return *reinterpret_cast<long double*>(Val
);
157 UNREACHABLE("unexpected floating point bit width");
160 #endif // CAN_SANITIZE_UB