ubsan_value.cpp 5.2 KB

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