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