xref: /freebsd/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_value.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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 
215ffd83dbSDimitry Andric // TODO(dliew): Prefer '__APPLE__' here over 'SANITIZER_MAC', as the latter is
225ffd83dbSDimitry Andric // unclear. rdar://58124919 tracks using a more obviously portable guard.
235ffd83dbSDimitry Andric #if defined(__APPLE__)
245ffd83dbSDimitry Andric #include <dlfcn.h>
255ffd83dbSDimitry Andric #endif
2668d75effSDimitry Andric 
2768d75effSDimitry Andric using namespace __ubsan;
2868d75effSDimitry Andric 
295ffd83dbSDimitry Andric typedef const char *(*ObjCGetClassNameTy)(void *);
305ffd83dbSDimitry Andric 
315ffd83dbSDimitry Andric const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
325ffd83dbSDimitry Andric #if defined(__APPLE__)
335ffd83dbSDimitry Andric   // We need to query the ObjC runtime for some information, but do not want
345ffd83dbSDimitry Andric   // to introduce a static dependency from the ubsan runtime onto ObjC. Try to
355ffd83dbSDimitry Andric   // grab a handle to the ObjC runtime used by the process.
365ffd83dbSDimitry Andric   static bool AttemptedDlopen = false;
375ffd83dbSDimitry Andric   static void *ObjCHandle = nullptr;
385ffd83dbSDimitry Andric   static void *ObjCObjectGetClassName = nullptr;
395ffd83dbSDimitry Andric 
405ffd83dbSDimitry Andric   // Prevent threads from racing to dlopen().
415ffd83dbSDimitry Andric   static __sanitizer::StaticSpinMutex Lock;
425ffd83dbSDimitry Andric   {
435ffd83dbSDimitry Andric     __sanitizer::SpinMutexLock Guard(&Lock);
445ffd83dbSDimitry Andric 
455ffd83dbSDimitry Andric     if (!AttemptedDlopen) {
465ffd83dbSDimitry Andric       ObjCHandle = dlopen(
475ffd83dbSDimitry Andric           "/usr/lib/libobjc.A.dylib",
485ffd83dbSDimitry Andric           RTLD_LAZY         // Only bind symbols when used.
495ffd83dbSDimitry Andric               | RTLD_LOCAL  // Only make symbols available via the handle.
505ffd83dbSDimitry Andric               | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the
515ffd83dbSDimitry Andric                             // image is already loaded.
525ffd83dbSDimitry Andric               | RTLD_FIRST  // Only search the image pointed-to by the handle.
535ffd83dbSDimitry Andric       );
545ffd83dbSDimitry Andric       AttemptedDlopen = true;
555ffd83dbSDimitry Andric       if (!ObjCHandle)
565ffd83dbSDimitry Andric         return nullptr;
575ffd83dbSDimitry Andric       ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName");
585ffd83dbSDimitry Andric     }
595ffd83dbSDimitry Andric   }
605ffd83dbSDimitry Andric 
615ffd83dbSDimitry Andric   if (!ObjCObjectGetClassName)
625ffd83dbSDimitry Andric     return nullptr;
635ffd83dbSDimitry Andric 
645ffd83dbSDimitry Andric   return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer);
655ffd83dbSDimitry Andric #else
665ffd83dbSDimitry Andric   return nullptr;
675ffd83dbSDimitry Andric #endif
685ffd83dbSDimitry Andric }
695ffd83dbSDimitry 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();
77*fe6060f1SDimitry Andric     return SIntMax(UIntMax(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