llvm-project
158 строк · 5.1 Кб
1//===-- ubsan_value.cpp ---------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Representation of a runtime value, as marshaled from the generated code to
10// the ubsan runtime.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ubsan_platform.h"
15#if CAN_SANITIZE_UB
16#include "ubsan_value.h"
17#include "sanitizer_common/sanitizer_common.h"
18#include "sanitizer_common/sanitizer_libc.h"
19#include "sanitizer_common/sanitizer_mutex.h"
20
21#if SANITIZER_APPLE
22#include <dlfcn.h>
23#endif
24
25using namespace __ubsan;
26
27typedef const char *(*ObjCGetClassNameTy)(void *);
28
29const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
30#if SANITIZER_APPLE
31// We need to query the ObjC runtime for some information, but do not want
32// to introduce a static dependency from the ubsan runtime onto ObjC. Try to
33// grab a handle to the ObjC runtime used by the process.
34static bool AttemptedDlopen = false;
35static void *ObjCHandle = nullptr;
36static void *ObjCObjectGetClassName = nullptr;
37
38// Prevent threads from racing to dlopen().
39static __sanitizer::StaticSpinMutex Lock;
40{
41__sanitizer::SpinMutexLock Guard(&Lock);
42
43if (!AttemptedDlopen) {
44ObjCHandle = dlopen(
45"/usr/lib/libobjc.A.dylib",
46RTLD_LAZY // Only bind symbols when used.
47| RTLD_LOCAL // Only make symbols available via the handle.
48| RTLD_NOLOAD // Do not load the dylib, just grab a handle if the
49// image is already loaded.
50| RTLD_FIRST // Only search the image pointed-to by the handle.
51);
52AttemptedDlopen = true;
53if (!ObjCHandle)
54return nullptr;
55ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName");
56}
57}
58
59if (!ObjCObjectGetClassName)
60return nullptr;
61
62return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer);
63#else
64return nullptr;
65#endif
66}
67
68SIntMax Value::getSIntValue() const {
69CHECK(getType().isSignedIntegerTy());
70if (isInlineInt()) {
71// Val was zero-extended to ValueHandle. Sign-extend from original width
72// to SIntMax.
73const unsigned ExtraBits =
74sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
75return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits;
76}
77if (getType().getIntegerBitWidth() == 64)
78return *reinterpret_cast<s64*>(Val);
79#if HAVE_INT128_T
80if (getType().getIntegerBitWidth() == 128)
81return *reinterpret_cast<s128*>(Val);
82#else
83if (getType().getIntegerBitWidth() == 128)
84UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
85#endif
86UNREACHABLE("unexpected bit width");
87}
88
89UIntMax Value::getUIntValue() const {
90CHECK(getType().isUnsignedIntegerTy());
91if (isInlineInt())
92return Val;
93if (getType().getIntegerBitWidth() == 64)
94return *reinterpret_cast<u64*>(Val);
95#if HAVE_INT128_T
96if (getType().getIntegerBitWidth() == 128)
97return *reinterpret_cast<u128*>(Val);
98#else
99if (getType().getIntegerBitWidth() == 128)
100UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
101#endif
102UNREACHABLE("unexpected bit width");
103}
104
105UIntMax Value::getPositiveIntValue() const {
106if (getType().isUnsignedIntegerTy())
107return getUIntValue();
108SIntMax Val = getSIntValue();
109CHECK(Val >= 0);
110return Val;
111}
112
113/// Get the floating-point value of this object, extended to a long double.
114/// These are always passed by address (our calling convention doesn't allow
115/// them to be passed in floating-point registers, so this has little cost).
116FloatMax Value::getFloatValue() const {
117CHECK(getType().isFloatTy());
118if (isInlineFloat()) {
119switch (getType().getFloatBitWidth()) {
120#if 0
121// FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
122// from '__fp16' to 'long double'.
123case 16: {
124__fp16 Value;
125internal_memcpy(&Value, &Val, 4);
126return Value;
127}
128#endif
129case 32: {
130float Value;
131#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
132// For big endian the float value is in the last 4 bytes.
133// On some targets we may only have 4 bytes so we count backwards from
134// the end of Val to account for both the 32-bit and 64-bit cases.
135internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4);
136#else
137internal_memcpy(&Value, &Val, 4);
138#endif
139return Value;
140}
141case 64: {
142double Value;
143internal_memcpy(&Value, &Val, 8);
144return Value;
145}
146}
147} else {
148switch (getType().getFloatBitWidth()) {
149case 64: return *reinterpret_cast<double*>(Val);
150case 80: return *reinterpret_cast<long double*>(Val);
151case 96: return *reinterpret_cast<long double*>(Val);
152case 128: return *reinterpret_cast<long double*>(Val);
153}
154}
155UNREACHABLE("unexpected floating point bit width");
156}
157
158#endif // CAN_SANITIZE_UB
159