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