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 // Val was zero-extended to ValueHandle. Sign-extend from original width 71 // to SIntMax. 72 const unsigned ExtraBits = 73 sizeof(SIntMax) * 8 - getType().getIntegerBitCount(); 74 if (isInlineInt()) { 75 return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits; 76 } 77 if (getType().getIntegerBitWidth() == 64) { 78 return SIntMax(UIntMax(*reinterpret_cast<s64 *>(Val)) << ExtraBits) >> 79 ExtraBits; 80 } 81 #if HAVE_INT128_T 82 if (getType().getIntegerBitWidth() == 128) 83 return SIntMax(UIntMax(*reinterpret_cast<s128 *>(Val)) << ExtraBits) >> 84 ExtraBits; 85 #else 86 if (getType().getIntegerBitWidth() == 128) 87 UNREACHABLE("libclang_rt.ubsan was built without __int128 support"); 88 #endif 89 UNREACHABLE("unexpected bit width"); 90 } 91 92 UIntMax Value::getUIntValue() const { 93 CHECK(getType().isUnsignedIntegerTy()); 94 if (isInlineInt()) 95 return Val; 96 if (getType().getIntegerBitWidth() == 64) 97 return *reinterpret_cast<u64*>(Val); 98 #if HAVE_INT128_T 99 if (getType().getIntegerBitWidth() == 128) 100 return *reinterpret_cast<u128*>(Val); 101 #else 102 if (getType().getIntegerBitWidth() == 128) 103 UNREACHABLE("libclang_rt.ubsan was built without __int128 support"); 104 #endif 105 UNREACHABLE("unexpected bit width"); 106 } 107 108 UIntMax Value::getPositiveIntValue() const { 109 if (getType().isUnsignedIntegerTy()) 110 return getUIntValue(); 111 SIntMax Val = getSIntValue(); 112 CHECK(Val >= 0); 113 return Val; 114 } 115 116 /// Get the floating-point value of this object, extended to a long double. 117 /// These are always passed by address (our calling convention doesn't allow 118 /// them to be passed in floating-point registers, so this has little cost). 119 FloatMax Value::getFloatValue() const { 120 CHECK(getType().isFloatTy()); 121 if (isInlineFloat()) { 122 switch (getType().getFloatBitWidth()) { 123 #if 0 124 // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion 125 // from '__fp16' to 'long double'. 126 case 16: { 127 __fp16 Value; 128 internal_memcpy(&Value, &Val, 4); 129 return Value; 130 } 131 #endif 132 case 32: { 133 float Value; 134 #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 135 // For big endian the float value is in the last 4 bytes. 136 // On some targets we may only have 4 bytes so we count backwards from 137 // the end of Val to account for both the 32-bit and 64-bit cases. 138 internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4); 139 #else 140 internal_memcpy(&Value, &Val, 4); 141 #endif 142 return Value; 143 } 144 case 64: { 145 double Value; 146 internal_memcpy(&Value, &Val, 8); 147 return Value; 148 } 149 } 150 } else { 151 switch (getType().getFloatBitWidth()) { 152 case 64: return *reinterpret_cast<double*>(Val); 153 case 80: return *reinterpret_cast<long double*>(Val); 154 case 96: return *reinterpret_cast<long double*>(Val); 155 case 128: return *reinterpret_cast<long double*>(Val); 156 } 157 } 158 UNREACHABLE("unexpected floating point bit width"); 159 } 160 161 #endif // CAN_SANITIZE_UB 162