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