ubsan_value.cpp 5.1 KB

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