xref: /freebsd/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_value.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
168d75effSDimitry Andric //===-- ubsan_value.cpp ---------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Representation of a runtime value, as marshaled from the generated code to
1068d75effSDimitry Andric // the ubsan runtime.
1168d75effSDimitry Andric //
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "ubsan_platform.h"
1568d75effSDimitry Andric #if CAN_SANITIZE_UB
1668d75effSDimitry Andric #include "ubsan_value.h"
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
19*5ffd83dbSDimitry Andric #include "sanitizer_common/sanitizer_mutex.h"
20*5ffd83dbSDimitry Andric 
21*5ffd83dbSDimitry Andric // TODO(dliew): Prefer '__APPLE__' here over 'SANITIZER_MAC', as the latter is
22*5ffd83dbSDimitry Andric // unclear. rdar://58124919 tracks using a more obviously portable guard.
23*5ffd83dbSDimitry Andric #if defined(__APPLE__)
24*5ffd83dbSDimitry Andric #include <dlfcn.h>
25*5ffd83dbSDimitry Andric #endif
2668d75effSDimitry Andric 
2768d75effSDimitry Andric using namespace __ubsan;
2868d75effSDimitry Andric 
29*5ffd83dbSDimitry Andric typedef const char *(*ObjCGetClassNameTy)(void *);
30*5ffd83dbSDimitry Andric 
31*5ffd83dbSDimitry Andric const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
32*5ffd83dbSDimitry Andric #if defined(__APPLE__)
33*5ffd83dbSDimitry Andric   // We need to query the ObjC runtime for some information, but do not want
34*5ffd83dbSDimitry Andric   // to introduce a static dependency from the ubsan runtime onto ObjC. Try to
35*5ffd83dbSDimitry Andric   // grab a handle to the ObjC runtime used by the process.
36*5ffd83dbSDimitry Andric   static bool AttemptedDlopen = false;
37*5ffd83dbSDimitry Andric   static void *ObjCHandle = nullptr;
38*5ffd83dbSDimitry Andric   static void *ObjCObjectGetClassName = nullptr;
39*5ffd83dbSDimitry Andric 
40*5ffd83dbSDimitry Andric   // Prevent threads from racing to dlopen().
41*5ffd83dbSDimitry Andric   static __sanitizer::StaticSpinMutex Lock;
42*5ffd83dbSDimitry Andric   {
43*5ffd83dbSDimitry Andric     __sanitizer::SpinMutexLock Guard(&Lock);
44*5ffd83dbSDimitry Andric 
45*5ffd83dbSDimitry Andric     if (!AttemptedDlopen) {
46*5ffd83dbSDimitry Andric       ObjCHandle = dlopen(
47*5ffd83dbSDimitry Andric           "/usr/lib/libobjc.A.dylib",
48*5ffd83dbSDimitry Andric           RTLD_LAZY         // Only bind symbols when used.
49*5ffd83dbSDimitry Andric               | RTLD_LOCAL  // Only make symbols available via the handle.
50*5ffd83dbSDimitry Andric               | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the
51*5ffd83dbSDimitry Andric                             // image is already loaded.
52*5ffd83dbSDimitry Andric               | RTLD_FIRST  // Only search the image pointed-to by the handle.
53*5ffd83dbSDimitry Andric       );
54*5ffd83dbSDimitry Andric       AttemptedDlopen = true;
55*5ffd83dbSDimitry Andric       if (!ObjCHandle)
56*5ffd83dbSDimitry Andric         return nullptr;
57*5ffd83dbSDimitry Andric       ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName");
58*5ffd83dbSDimitry Andric     }
59*5ffd83dbSDimitry Andric   }
60*5ffd83dbSDimitry Andric 
61*5ffd83dbSDimitry Andric   if (!ObjCObjectGetClassName)
62*5ffd83dbSDimitry Andric     return nullptr;
63*5ffd83dbSDimitry Andric 
64*5ffd83dbSDimitry Andric   return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer);
65*5ffd83dbSDimitry Andric #else
66*5ffd83dbSDimitry Andric   return nullptr;
67*5ffd83dbSDimitry Andric #endif
68*5ffd83dbSDimitry Andric }
69*5ffd83dbSDimitry Andric 
7068d75effSDimitry Andric SIntMax Value::getSIntValue() const {
7168d75effSDimitry Andric   CHECK(getType().isSignedIntegerTy());
7268d75effSDimitry Andric   if (isInlineInt()) {
7368d75effSDimitry Andric     // Val was zero-extended to ValueHandle. Sign-extend from original width
7468d75effSDimitry Andric     // to SIntMax.
7568d75effSDimitry Andric     const unsigned ExtraBits =
7668d75effSDimitry Andric       sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
7768d75effSDimitry Andric     return SIntMax(Val) << ExtraBits >> ExtraBits;
7868d75effSDimitry Andric   }
7968d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 64)
8068d75effSDimitry Andric     return *reinterpret_cast<s64*>(Val);
8168d75effSDimitry Andric #if HAVE_INT128_T
8268d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
8368d75effSDimitry Andric     return *reinterpret_cast<s128*>(Val);
8468d75effSDimitry Andric #else
8568d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
8668d75effSDimitry Andric     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
8768d75effSDimitry Andric #endif
8868d75effSDimitry Andric   UNREACHABLE("unexpected bit width");
8968d75effSDimitry Andric }
9068d75effSDimitry Andric 
9168d75effSDimitry Andric UIntMax Value::getUIntValue() const {
9268d75effSDimitry Andric   CHECK(getType().isUnsignedIntegerTy());
9368d75effSDimitry Andric   if (isInlineInt())
9468d75effSDimitry Andric     return Val;
9568d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 64)
9668d75effSDimitry Andric     return *reinterpret_cast<u64*>(Val);
9768d75effSDimitry Andric #if HAVE_INT128_T
9868d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
9968d75effSDimitry Andric     return *reinterpret_cast<u128*>(Val);
10068d75effSDimitry Andric #else
10168d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
10268d75effSDimitry Andric     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
10368d75effSDimitry Andric #endif
10468d75effSDimitry Andric   UNREACHABLE("unexpected bit width");
10568d75effSDimitry Andric }
10668d75effSDimitry Andric 
10768d75effSDimitry Andric UIntMax Value::getPositiveIntValue() const {
10868d75effSDimitry Andric   if (getType().isUnsignedIntegerTy())
10968d75effSDimitry Andric     return getUIntValue();
11068d75effSDimitry Andric   SIntMax Val = getSIntValue();
11168d75effSDimitry Andric   CHECK(Val >= 0);
11268d75effSDimitry Andric   return Val;
11368d75effSDimitry Andric }
11468d75effSDimitry Andric 
11568d75effSDimitry Andric /// Get the floating-point value of this object, extended to a long double.
11668d75effSDimitry Andric /// These are always passed by address (our calling convention doesn't allow
11768d75effSDimitry Andric /// them to be passed in floating-point registers, so this has little cost).
11868d75effSDimitry Andric FloatMax Value::getFloatValue() const {
11968d75effSDimitry Andric   CHECK(getType().isFloatTy());
12068d75effSDimitry Andric   if (isInlineFloat()) {
12168d75effSDimitry Andric     switch (getType().getFloatBitWidth()) {
12268d75effSDimitry Andric #if 0
12368d75effSDimitry Andric       // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
12468d75effSDimitry Andric       //        from '__fp16' to 'long double'.
12568d75effSDimitry Andric       case 16: {
12668d75effSDimitry Andric         __fp16 Value;
12768d75effSDimitry Andric         internal_memcpy(&Value, &Val, 4);
12868d75effSDimitry Andric         return Value;
12968d75effSDimitry Andric       }
13068d75effSDimitry Andric #endif
13168d75effSDimitry Andric       case 32: {
13268d75effSDimitry Andric         float Value;
13368d75effSDimitry Andric #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
13468d75effSDimitry Andric        // For big endian the float value is in the last 4 bytes.
13568d75effSDimitry Andric        // On some targets we may only have 4 bytes so we count backwards from
13668d75effSDimitry Andric        // the end of Val to account for both the 32-bit and 64-bit cases.
13768d75effSDimitry Andric        internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4);
13868d75effSDimitry Andric #else
13968d75effSDimitry Andric        internal_memcpy(&Value, &Val, 4);
14068d75effSDimitry Andric #endif
14168d75effSDimitry Andric         return Value;
14268d75effSDimitry Andric       }
14368d75effSDimitry Andric       case 64: {
14468d75effSDimitry Andric         double Value;
14568d75effSDimitry Andric         internal_memcpy(&Value, &Val, 8);
14668d75effSDimitry Andric         return Value;
14768d75effSDimitry Andric       }
14868d75effSDimitry Andric     }
14968d75effSDimitry Andric   } else {
15068d75effSDimitry Andric     switch (getType().getFloatBitWidth()) {
15168d75effSDimitry Andric     case 64: return *reinterpret_cast<double*>(Val);
15268d75effSDimitry Andric     case 80: return *reinterpret_cast<long double*>(Val);
15368d75effSDimitry Andric     case 96: return *reinterpret_cast<long double*>(Val);
15468d75effSDimitry Andric     case 128: return *reinterpret_cast<long double*>(Val);
15568d75effSDimitry Andric     }
15668d75effSDimitry Andric   }
15768d75effSDimitry Andric   UNREACHABLE("unexpected floating point bit width");
15868d75effSDimitry Andric }
15968d75effSDimitry Andric 
16068d75effSDimitry Andric #endif  // CAN_SANITIZE_UB
161