xref: /freebsd/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_value.cpp (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
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"
195ffd83dbSDimitry Andric #include "sanitizer_common/sanitizer_mutex.h"
205ffd83dbSDimitry Andric 
21*fcaf7f86SDimitry Andric #if SANITIZER_APPLE
225ffd83dbSDimitry Andric #include <dlfcn.h>
235ffd83dbSDimitry Andric #endif
2468d75effSDimitry Andric 
2568d75effSDimitry Andric using namespace __ubsan;
2668d75effSDimitry Andric 
275ffd83dbSDimitry Andric typedef const char *(*ObjCGetClassNameTy)(void *);
285ffd83dbSDimitry Andric 
getObjCClassName(ValueHandle Pointer)295ffd83dbSDimitry Andric const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
30*fcaf7f86SDimitry Andric #if SANITIZER_APPLE
315ffd83dbSDimitry Andric   // We need to query the ObjC runtime for some information, but do not want
325ffd83dbSDimitry Andric   // to introduce a static dependency from the ubsan runtime onto ObjC. Try to
335ffd83dbSDimitry Andric   // grab a handle to the ObjC runtime used by the process.
345ffd83dbSDimitry Andric   static bool AttemptedDlopen = false;
355ffd83dbSDimitry Andric   static void *ObjCHandle = nullptr;
365ffd83dbSDimitry Andric   static void *ObjCObjectGetClassName = nullptr;
375ffd83dbSDimitry Andric 
385ffd83dbSDimitry Andric   // Prevent threads from racing to dlopen().
395ffd83dbSDimitry Andric   static __sanitizer::StaticSpinMutex Lock;
405ffd83dbSDimitry Andric   {
415ffd83dbSDimitry Andric     __sanitizer::SpinMutexLock Guard(&Lock);
425ffd83dbSDimitry Andric 
435ffd83dbSDimitry Andric     if (!AttemptedDlopen) {
445ffd83dbSDimitry Andric       ObjCHandle = dlopen(
455ffd83dbSDimitry Andric           "/usr/lib/libobjc.A.dylib",
465ffd83dbSDimitry Andric           RTLD_LAZY         // Only bind symbols when used.
475ffd83dbSDimitry Andric               | RTLD_LOCAL  // Only make symbols available via the handle.
485ffd83dbSDimitry Andric               | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the
495ffd83dbSDimitry Andric                             // image is already loaded.
505ffd83dbSDimitry Andric               | RTLD_FIRST  // Only search the image pointed-to by the handle.
515ffd83dbSDimitry Andric       );
525ffd83dbSDimitry Andric       AttemptedDlopen = true;
535ffd83dbSDimitry Andric       if (!ObjCHandle)
545ffd83dbSDimitry Andric         return nullptr;
555ffd83dbSDimitry Andric       ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName");
565ffd83dbSDimitry Andric     }
575ffd83dbSDimitry Andric   }
585ffd83dbSDimitry Andric 
595ffd83dbSDimitry Andric   if (!ObjCObjectGetClassName)
605ffd83dbSDimitry Andric     return nullptr;
615ffd83dbSDimitry Andric 
625ffd83dbSDimitry Andric   return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer);
635ffd83dbSDimitry Andric #else
645ffd83dbSDimitry Andric   return nullptr;
655ffd83dbSDimitry Andric #endif
665ffd83dbSDimitry Andric }
675ffd83dbSDimitry Andric 
getSIntValue() const6868d75effSDimitry Andric SIntMax Value::getSIntValue() const {
6968d75effSDimitry Andric   CHECK(getType().isSignedIntegerTy());
7068d75effSDimitry Andric   if (isInlineInt()) {
7168d75effSDimitry Andric     // Val was zero-extended to ValueHandle. Sign-extend from original width
7268d75effSDimitry Andric     // to SIntMax.
7368d75effSDimitry Andric     const unsigned ExtraBits =
7468d75effSDimitry Andric       sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
75fe6060f1SDimitry Andric     return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits;
7668d75effSDimitry Andric   }
7768d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 64)
7868d75effSDimitry Andric     return *reinterpret_cast<s64*>(Val);
7968d75effSDimitry Andric #if HAVE_INT128_T
8068d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
8168d75effSDimitry Andric     return *reinterpret_cast<s128*>(Val);
8268d75effSDimitry Andric #else
8368d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
8468d75effSDimitry Andric     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
8568d75effSDimitry Andric #endif
8668d75effSDimitry Andric   UNREACHABLE("unexpected bit width");
8768d75effSDimitry Andric }
8868d75effSDimitry Andric 
getUIntValue() const8968d75effSDimitry Andric UIntMax Value::getUIntValue() const {
9068d75effSDimitry Andric   CHECK(getType().isUnsignedIntegerTy());
9168d75effSDimitry Andric   if (isInlineInt())
9268d75effSDimitry Andric     return Val;
9368d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 64)
9468d75effSDimitry Andric     return *reinterpret_cast<u64*>(Val);
9568d75effSDimitry Andric #if HAVE_INT128_T
9668d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
9768d75effSDimitry Andric     return *reinterpret_cast<u128*>(Val);
9868d75effSDimitry Andric #else
9968d75effSDimitry Andric   if (getType().getIntegerBitWidth() == 128)
10068d75effSDimitry Andric     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
10168d75effSDimitry Andric #endif
10268d75effSDimitry Andric   UNREACHABLE("unexpected bit width");
10368d75effSDimitry Andric }
10468d75effSDimitry Andric 
getPositiveIntValue() const10568d75effSDimitry Andric UIntMax Value::getPositiveIntValue() const {
10668d75effSDimitry Andric   if (getType().isUnsignedIntegerTy())
10768d75effSDimitry Andric     return getUIntValue();
10868d75effSDimitry Andric   SIntMax Val = getSIntValue();
10968d75effSDimitry Andric   CHECK(Val >= 0);
11068d75effSDimitry Andric   return Val;
11168d75effSDimitry Andric }
11268d75effSDimitry Andric 
11368d75effSDimitry Andric /// Get the floating-point value of this object, extended to a long double.
11468d75effSDimitry Andric /// These are always passed by address (our calling convention doesn't allow
11568d75effSDimitry Andric /// them to be passed in floating-point registers, so this has little cost).
getFloatValue() const11668d75effSDimitry Andric FloatMax Value::getFloatValue() const {
11768d75effSDimitry Andric   CHECK(getType().isFloatTy());
11868d75effSDimitry Andric   if (isInlineFloat()) {
11968d75effSDimitry Andric     switch (getType().getFloatBitWidth()) {
12068d75effSDimitry Andric #if 0
12168d75effSDimitry Andric       // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
12268d75effSDimitry Andric       //        from '__fp16' to 'long double'.
12368d75effSDimitry Andric       case 16: {
12468d75effSDimitry Andric         __fp16 Value;
12568d75effSDimitry Andric         internal_memcpy(&Value, &Val, 4);
12668d75effSDimitry Andric         return Value;
12768d75effSDimitry Andric       }
12868d75effSDimitry Andric #endif
12968d75effSDimitry Andric       case 32: {
13068d75effSDimitry Andric         float Value;
13168d75effSDimitry Andric #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
13268d75effSDimitry Andric        // For big endian the float value is in the last 4 bytes.
13368d75effSDimitry Andric        // On some targets we may only have 4 bytes so we count backwards from
13468d75effSDimitry Andric        // the end of Val to account for both the 32-bit and 64-bit cases.
13568d75effSDimitry Andric        internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4);
13668d75effSDimitry Andric #else
13768d75effSDimitry Andric        internal_memcpy(&Value, &Val, 4);
13868d75effSDimitry Andric #endif
13968d75effSDimitry Andric         return Value;
14068d75effSDimitry Andric       }
14168d75effSDimitry Andric       case 64: {
14268d75effSDimitry Andric         double Value;
14368d75effSDimitry Andric         internal_memcpy(&Value, &Val, 8);
14468d75effSDimitry Andric         return Value;
14568d75effSDimitry Andric       }
14668d75effSDimitry Andric     }
14768d75effSDimitry Andric   } else {
14868d75effSDimitry Andric     switch (getType().getFloatBitWidth()) {
14968d75effSDimitry Andric     case 64: return *reinterpret_cast<double*>(Val);
15068d75effSDimitry Andric     case 80: return *reinterpret_cast<long double*>(Val);
15168d75effSDimitry Andric     case 96: return *reinterpret_cast<long double*>(Val);
15268d75effSDimitry Andric     case 128: return *reinterpret_cast<long double*>(Val);
15368d75effSDimitry Andric     }
15468d75effSDimitry Andric   }
15568d75effSDimitry Andric   UNREACHABLE("unexpected floating point bit width");
15668d75effSDimitry Andric }
15768d75effSDimitry Andric 
15868d75effSDimitry Andric #endif  // CAN_SANITIZE_UB
159