brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 6e88eba Raw
162 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Representation of a runtime value, as marshaled from the generated code to10// the ubsan runtime.11//12//===----------------------------------------------------------------------===//13 14#include "ubsan_platform.h"15#if CAN_SANITIZE_UB16#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_APPLE22#include <dlfcn.h>23#endif24 25using namespace __ubsan;26 27typedef const char *(*ObjCGetClassNameTy)(void *);28 29const char *__ubsan::getObjCClassName(ValueHandle Pointer) {30#if SANITIZER_APPLE31  // We need to query the ObjC runtime for some information, but do not want32  // to introduce a static dependency from the ubsan runtime onto ObjC. Try to33  // 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 the49                            // 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#else64  return nullptr;65#endif66}67 68SIntMax Value::getSIntValue() const {69  CHECK(getType().isSignedIntegerTy());70  // Val was zero-extended to ValueHandle. Sign-extend from original width71  // 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_T82  if (getType().getIntegerBitWidth() == 128)83    return SIntMax(UIntMax(*reinterpret_cast<s128 *>(Val)) << ExtraBits) >>84           ExtraBits;85#else86  if (getType().getIntegerBitWidth() == 128)87    UNREACHABLE("libclang_rt.ubsan was built without __int128 support");88#endif89  UNREACHABLE("unexpected bit width");90}91 92UIntMax 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_T99  if (getType().getIntegerBitWidth() == 128)100    return *reinterpret_cast<u128*>(Val);101#else102  if (getType().getIntegerBitWidth() == 128)103    UNREACHABLE("libclang_rt.ubsan was built without __int128 support");104#endif105  UNREACHABLE("unexpected bit width");106}107 108UIntMax 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 allow118/// them to be passed in floating-point registers, so this has little cost).119FloatMax Value::getFloatValue() const {120  CHECK(getType().isFloatTy());121  if (isInlineFloat()) {122    switch (getType().getFloatBitWidth()) {123#if 0124      // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion125      //        from '__fp16' to 'long double'.126      case 16: {127        __fp16 Value;128        internal_memcpy(&Value, &Val, 4);129        return Value;130      }131#endif132      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 from137       // 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#else140       internal_memcpy(&Value, &Val, 4);141#endif142        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_UB162