1 | //===-- ubsan_value.cpp ---------------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Representation of a runtime value, as marshaled from the generated code to |
10 | // the ubsan runtime. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "ubsan_platform.h" |
15 | #if CAN_SANITIZE_UB |
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" |
20 | |
21 | #if SANITIZER_APPLE |
22 | #include <dlfcn.h> |
23 | #endif |
24 | |
25 | using namespace __ubsan; |
26 | |
27 | typedef const char *(*ObjCGetClassNameTy)(void *); |
28 | |
29 | const char *__ubsan::getObjCClassName(ValueHandle Pointer) { |
30 | #if SANITIZER_APPLE |
31 | // We need to query the ObjC runtime for some information, but do not want |
32 | // to introduce a static dependency from the ubsan runtime onto ObjC. Try to |
33 | // grab a handle to the ObjC runtime used by the process. |
34 | static bool AttemptedDlopen = false; |
35 | static void *ObjCHandle = nullptr; |
36 | static void *ObjCObjectGetClassName = nullptr; |
37 | |
38 | // Prevent threads from racing to dlopen(). |
39 | static __sanitizer::StaticSpinMutex Lock; |
40 | { |
41 | __sanitizer::SpinMutexLock Guard(&Lock); |
42 | |
43 | if (!AttemptedDlopen) { |
44 | ObjCHandle = dlopen( |
45 | "/usr/lib/libobjc.A.dylib" , |
46 | RTLD_LAZY // Only bind symbols when used. |
47 | | RTLD_LOCAL // Only make symbols available via the handle. |
48 | | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the |
49 | // image is already loaded. |
50 | | RTLD_FIRST // Only search the image pointed-to by the handle. |
51 | ); |
52 | AttemptedDlopen = true; |
53 | if (!ObjCHandle) |
54 | return nullptr; |
55 | ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName" ); |
56 | } |
57 | } |
58 | |
59 | if (!ObjCObjectGetClassName) |
60 | return nullptr; |
61 | |
62 | return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer); |
63 | #else |
64 | return nullptr; |
65 | #endif |
66 | } |
67 | |
68 | SIntMax Value::getSIntValue() const { |
69 | CHECK(getType().isSignedIntegerTy()); |
70 | if (isInlineInt()) { |
71 | // Val was zero-extended to ValueHandle. Sign-extend from original width |
72 | // to SIntMax. |
73 | const unsigned = |
74 | sizeof(SIntMax) * 8 - getType().getIntegerBitWidth(); |
75 | return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits; |
76 | } |
77 | if (getType().getIntegerBitWidth() == 64) |
78 | return *reinterpret_cast<s64*>(Val); |
79 | #if HAVE_INT128_T |
80 | if (getType().getIntegerBitWidth() == 128) |
81 | return *reinterpret_cast<s128*>(Val); |
82 | #else |
83 | if (getType().getIntegerBitWidth() == 128) |
84 | UNREACHABLE("libclang_rt.ubsan was built without __int128 support" ); |
85 | #endif |
86 | UNREACHABLE("unexpected bit width" ); |
87 | } |
88 | |
89 | UIntMax Value::getUIntValue() const { |
90 | CHECK(getType().isUnsignedIntegerTy()); |
91 | if (isInlineInt()) |
92 | return Val; |
93 | if (getType().getIntegerBitWidth() == 64) |
94 | return *reinterpret_cast<u64*>(Val); |
95 | #if HAVE_INT128_T |
96 | if (getType().getIntegerBitWidth() == 128) |
97 | return *reinterpret_cast<u128*>(Val); |
98 | #else |
99 | if (getType().getIntegerBitWidth() == 128) |
100 | UNREACHABLE("libclang_rt.ubsan was built without __int128 support" ); |
101 | #endif |
102 | UNREACHABLE("unexpected bit width" ); |
103 | } |
104 | |
105 | UIntMax Value::getPositiveIntValue() const { |
106 | if (getType().isUnsignedIntegerTy()) |
107 | return getUIntValue(); |
108 | SIntMax Val = getSIntValue(); |
109 | CHECK(Val >= 0); |
110 | return Val; |
111 | } |
112 | |
113 | /// Get the floating-point value of this object, extended to a long double. |
114 | /// These are always passed by address (our calling convention doesn't allow |
115 | /// them to be passed in floating-point registers, so this has little cost). |
116 | FloatMax Value::getFloatValue() const { |
117 | CHECK(getType().isFloatTy()); |
118 | if (isInlineFloat()) { |
119 | switch (getType().getFloatBitWidth()) { |
120 | #if 0 |
121 | // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion |
122 | // from '__fp16' to 'long double'. |
123 | case 16: { |
124 | __fp16 Value; |
125 | internal_memcpy(&Value, &Val, 4); |
126 | return Value; |
127 | } |
128 | #endif |
129 | case 32: { |
130 | float Value; |
131 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
132 | // For big endian the float value is in the last 4 bytes. |
133 | // On some targets we may only have 4 bytes so we count backwards from |
134 | // the end of Val to account for both the 32-bit and 64-bit cases. |
135 | internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4); |
136 | #else |
137 | internal_memcpy(dest: &Value, src: &Val, n: 4); |
138 | #endif |
139 | return Value; |
140 | } |
141 | case 64: { |
142 | double Value; |
143 | internal_memcpy(dest: &Value, src: &Val, n: 8); |
144 | return Value; |
145 | } |
146 | } |
147 | } else { |
148 | switch (getType().getFloatBitWidth()) { |
149 | case 64: return *reinterpret_cast<double*>(Val); |
150 | case 80: return *reinterpret_cast<long double*>(Val); |
151 | case 96: return *reinterpret_cast<long double*>(Val); |
152 | case 128: return *reinterpret_cast<long double*>(Val); |
153 | } |
154 | } |
155 | UNREACHABLE("unexpected floating point bit width" ); |
156 | } |
157 | |
158 | #endif // CAN_SANITIZE_UB |
159 | |