xref: /llvm-project/compiler-rt/lib/ubsan/ubsan_value.cpp (revision 75cb7de404ee236d6297c551740a2681583d7e5e)
146ba9697SNico Weber //===-- ubsan_value.cpp ---------------------------------------------------===//
246ba9697SNico Weber //
346ba9697SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
446ba9697SNico Weber // See https://llvm.org/LICENSE.txt for license information.
546ba9697SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
646ba9697SNico Weber //
746ba9697SNico Weber //===----------------------------------------------------------------------===//
846ba9697SNico Weber //
946ba9697SNico Weber // Representation of a runtime value, as marshaled from the generated code to
1046ba9697SNico Weber // the ubsan runtime.
1146ba9697SNico Weber //
1246ba9697SNico Weber //===----------------------------------------------------------------------===//
1346ba9697SNico Weber 
1446ba9697SNico Weber #include "ubsan_platform.h"
1546ba9697SNico Weber #if CAN_SANITIZE_UB
1646ba9697SNico Weber #include "ubsan_value.h"
1746ba9697SNico Weber #include "sanitizer_common/sanitizer_common.h"
1846ba9697SNico Weber #include "sanitizer_common/sanitizer_libc.h"
198c4a65b9SVedant Kumar #include "sanitizer_common/sanitizer_mutex.h"
208c4a65b9SVedant Kumar 
2132a425ecSJulian Lettner #if SANITIZER_APPLE
228c4a65b9SVedant Kumar #include <dlfcn.h>
238c4a65b9SVedant Kumar #endif
2446ba9697SNico Weber 
2546ba9697SNico Weber using namespace __ubsan;
2646ba9697SNico Weber 
278c4a65b9SVedant Kumar typedef const char *(*ObjCGetClassNameTy)(void *);
288c4a65b9SVedant Kumar 
298c4a65b9SVedant Kumar const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
3032a425ecSJulian Lettner #if SANITIZER_APPLE
318c4a65b9SVedant Kumar   // We need to query the ObjC runtime for some information, but do not want
328c4a65b9SVedant Kumar   // to introduce a static dependency from the ubsan runtime onto ObjC. Try to
338c4a65b9SVedant Kumar   // grab a handle to the ObjC runtime used by the process.
348c4a65b9SVedant Kumar   static bool AttemptedDlopen = false;
358c4a65b9SVedant Kumar   static void *ObjCHandle = nullptr;
368c4a65b9SVedant Kumar   static void *ObjCObjectGetClassName = nullptr;
378c4a65b9SVedant Kumar 
388c4a65b9SVedant Kumar   // Prevent threads from racing to dlopen().
398c4a65b9SVedant Kumar   static __sanitizer::StaticSpinMutex Lock;
408c4a65b9SVedant Kumar   {
418c4a65b9SVedant Kumar     __sanitizer::SpinMutexLock Guard(&Lock);
428c4a65b9SVedant Kumar 
438c4a65b9SVedant Kumar     if (!AttemptedDlopen) {
448c4a65b9SVedant Kumar       ObjCHandle = dlopen(
458c4a65b9SVedant Kumar           "/usr/lib/libobjc.A.dylib",
468c4a65b9SVedant Kumar           RTLD_LAZY         // Only bind symbols when used.
478c4a65b9SVedant Kumar               | RTLD_LOCAL  // Only make symbols available via the handle.
488c4a65b9SVedant Kumar               | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the
498c4a65b9SVedant Kumar                             // image is already loaded.
508c4a65b9SVedant Kumar               | RTLD_FIRST  // Only search the image pointed-to by the handle.
518c4a65b9SVedant Kumar       );
528c4a65b9SVedant Kumar       AttemptedDlopen = true;
538c4a65b9SVedant Kumar       if (!ObjCHandle)
548c4a65b9SVedant Kumar         return nullptr;
558c4a65b9SVedant Kumar       ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName");
568c4a65b9SVedant Kumar     }
578c4a65b9SVedant Kumar   }
588c4a65b9SVedant Kumar 
598c4a65b9SVedant Kumar   if (!ObjCObjectGetClassName)
608c4a65b9SVedant Kumar     return nullptr;
618c4a65b9SVedant Kumar 
628c4a65b9SVedant Kumar   return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer);
638c4a65b9SVedant Kumar #else
648c4a65b9SVedant Kumar   return nullptr;
658c4a65b9SVedant Kumar #endif
668c4a65b9SVedant Kumar }
678c4a65b9SVedant Kumar 
6846ba9697SNico Weber SIntMax Value::getSIntValue() const {
6946ba9697SNico Weber   CHECK(getType().isSignedIntegerTy());
7046ba9697SNico Weber   // Val was zero-extended to ValueHandle. Sign-extend from original width
7146ba9697SNico Weber   // to SIntMax.
7246ba9697SNico Weber   const unsigned ExtraBits =
73*75cb7de4Searnol       sizeof(SIntMax) * 8 - getType().getIntegerBitCount();
74*75cb7de4Searnol   if (isInlineInt()) {
7516ede095SMartin Liska     return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits;
7646ba9697SNico Weber   }
77*75cb7de4Searnol   if (getType().getIntegerBitWidth() == 64) {
78*75cb7de4Searnol     return SIntMax(UIntMax(*reinterpret_cast<s64 *>(Val)) << ExtraBits) >>
79*75cb7de4Searnol            ExtraBits;
80*75cb7de4Searnol   }
8146ba9697SNico Weber #if HAVE_INT128_T
8246ba9697SNico Weber   if (getType().getIntegerBitWidth() == 128)
83*75cb7de4Searnol     return SIntMax(UIntMax(*reinterpret_cast<s128 *>(Val)) << ExtraBits) >>
84*75cb7de4Searnol            ExtraBits;
8546ba9697SNico Weber #else
8646ba9697SNico Weber   if (getType().getIntegerBitWidth() == 128)
8746ba9697SNico Weber     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
8846ba9697SNico Weber #endif
8946ba9697SNico Weber   UNREACHABLE("unexpected bit width");
9046ba9697SNico Weber }
9146ba9697SNico Weber 
9246ba9697SNico Weber UIntMax Value::getUIntValue() const {
9346ba9697SNico Weber   CHECK(getType().isUnsignedIntegerTy());
9446ba9697SNico Weber   if (isInlineInt())
9546ba9697SNico Weber     return Val;
9646ba9697SNico Weber   if (getType().getIntegerBitWidth() == 64)
9746ba9697SNico Weber     return *reinterpret_cast<u64*>(Val);
9846ba9697SNico Weber #if HAVE_INT128_T
9946ba9697SNico Weber   if (getType().getIntegerBitWidth() == 128)
10046ba9697SNico Weber     return *reinterpret_cast<u128*>(Val);
10146ba9697SNico Weber #else
10246ba9697SNico Weber   if (getType().getIntegerBitWidth() == 128)
10346ba9697SNico Weber     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
10446ba9697SNico Weber #endif
10546ba9697SNico Weber   UNREACHABLE("unexpected bit width");
10646ba9697SNico Weber }
10746ba9697SNico Weber 
10846ba9697SNico Weber UIntMax Value::getPositiveIntValue() const {
10946ba9697SNico Weber   if (getType().isUnsignedIntegerTy())
11046ba9697SNico Weber     return getUIntValue();
11146ba9697SNico Weber   SIntMax Val = getSIntValue();
11246ba9697SNico Weber   CHECK(Val >= 0);
11346ba9697SNico Weber   return Val;
11446ba9697SNico Weber }
11546ba9697SNico Weber 
11646ba9697SNico Weber /// Get the floating-point value of this object, extended to a long double.
11746ba9697SNico Weber /// These are always passed by address (our calling convention doesn't allow
11846ba9697SNico Weber /// them to be passed in floating-point registers, so this has little cost).
11946ba9697SNico Weber FloatMax Value::getFloatValue() const {
12046ba9697SNico Weber   CHECK(getType().isFloatTy());
12146ba9697SNico Weber   if (isInlineFloat()) {
12246ba9697SNico Weber     switch (getType().getFloatBitWidth()) {
12346ba9697SNico Weber #if 0
12446ba9697SNico Weber       // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
12546ba9697SNico Weber       //        from '__fp16' to 'long double'.
12646ba9697SNico Weber       case 16: {
12746ba9697SNico Weber         __fp16 Value;
12846ba9697SNico Weber         internal_memcpy(&Value, &Val, 4);
12946ba9697SNico Weber         return Value;
13046ba9697SNico Weber       }
13146ba9697SNico Weber #endif
13246ba9697SNico Weber       case 32: {
13346ba9697SNico Weber         float Value;
13446ba9697SNico Weber #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
13546ba9697SNico Weber        // For big endian the float value is in the last 4 bytes.
13646ba9697SNico Weber        // On some targets we may only have 4 bytes so we count backwards from
13746ba9697SNico Weber        // the end of Val to account for both the 32-bit and 64-bit cases.
13846ba9697SNico Weber        internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4);
13946ba9697SNico Weber #else
14046ba9697SNico Weber        internal_memcpy(&Value, &Val, 4);
14146ba9697SNico Weber #endif
14246ba9697SNico Weber         return Value;
14346ba9697SNico Weber       }
14446ba9697SNico Weber       case 64: {
14546ba9697SNico Weber         double Value;
14646ba9697SNico Weber         internal_memcpy(&Value, &Val, 8);
14746ba9697SNico Weber         return Value;
14846ba9697SNico Weber       }
14946ba9697SNico Weber     }
15046ba9697SNico Weber   } else {
15146ba9697SNico Weber     switch (getType().getFloatBitWidth()) {
15246ba9697SNico Weber     case 64: return *reinterpret_cast<double*>(Val);
15346ba9697SNico Weber     case 80: return *reinterpret_cast<long double*>(Val);
15446ba9697SNico Weber     case 96: return *reinterpret_cast<long double*>(Val);
15546ba9697SNico Weber     case 128: return *reinterpret_cast<long double*>(Val);
15646ba9697SNico Weber     }
15746ba9697SNico Weber   }
15846ba9697SNico Weber   UNREACHABLE("unexpected floating point bit width");
15946ba9697SNico Weber }
16046ba9697SNico Weber 
16146ba9697SNico Weber #endif  // CAN_SANITIZE_UB
162