1 | //===-- ubsan_value.h -------------------------------------------*- C++ -*-===// |
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 data which is passed from the compiler-generated calls into |
10 | // the ubsan runtime. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | #ifndef UBSAN_VALUE_H |
14 | #define UBSAN_VALUE_H |
15 | |
16 | #include "sanitizer_common/sanitizer_atomic.h" |
17 | #include "sanitizer_common/sanitizer_common.h" |
18 | |
19 | // FIXME: Move this out to a config header. |
20 | #if __SIZEOF_INT128__ |
21 | __extension__ typedef __int128 s128; |
22 | __extension__ typedef unsigned __int128 u128; |
23 | #define HAVE_INT128_T 1 |
24 | #else |
25 | #define HAVE_INT128_T 0 |
26 | #endif |
27 | |
28 | namespace __ubsan { |
29 | |
30 | /// \brief Largest integer types we support. |
31 | #if HAVE_INT128_T |
32 | typedef s128 SIntMax; |
33 | typedef u128 UIntMax; |
34 | #else |
35 | typedef s64 SIntMax; |
36 | typedef u64 UIntMax; |
37 | #endif |
38 | |
39 | /// \brief Largest floating-point type we support. |
40 | typedef long double FloatMax; |
41 | |
42 | /// \brief A description of a source location. This corresponds to Clang's |
43 | /// \c PresumedLoc type. |
44 | class SourceLocation { |
45 | const char *Filename; |
46 | u32 Line; |
47 | u32 Column; |
48 | |
49 | public: |
50 | SourceLocation() : Filename(), Line(), Column() {} |
51 | SourceLocation(const char *Filename, unsigned Line, unsigned Column) |
52 | : Filename(Filename), Line(Line), Column(Column) {} |
53 | |
54 | /// \brief Determine whether the source location is known. |
55 | bool isInvalid() const { return !Filename; } |
56 | |
57 | /// \brief Atomically acquire a copy, disabling original in-place. |
58 | /// Exactly one call to acquire() returns a copy that isn't disabled. |
59 | SourceLocation acquire() { |
60 | u32 OldColumn = __sanitizer::atomic_exchange( |
61 | a: (__sanitizer::atomic_uint32_t *)&Column, v: ~u32(0), |
62 | mo: __sanitizer::memory_order_relaxed); |
63 | return SourceLocation(Filename, Line, OldColumn); |
64 | } |
65 | |
66 | /// \brief Determine if this Location has been disabled. |
67 | /// Disabled SourceLocations are invalid to use. |
68 | bool isDisabled() { |
69 | return Column == ~u32(0); |
70 | } |
71 | |
72 | /// \brief Get the presumed filename for the source location. |
73 | const char *getFilename() const { return Filename; } |
74 | /// \brief Get the presumed line number. |
75 | unsigned getLine() const { return Line; } |
76 | /// \brief Get the column within the presumed line. |
77 | unsigned getColumn() const { return Column; } |
78 | }; |
79 | |
80 | |
81 | /// \brief A description of a type. |
82 | class TypeDescriptor { |
83 | /// A value from the \c Kind enumeration, specifying what flavor of type we |
84 | /// have. |
85 | u16 TypeKind; |
86 | |
87 | /// A \c Type-specific value providing information which allows us to |
88 | /// interpret the meaning of a ValueHandle of this type. |
89 | u16 TypeInfo; |
90 | |
91 | /// The name of the type follows, in a format suitable for including in |
92 | /// diagnostics. |
93 | char TypeName[1]; |
94 | |
95 | public: |
96 | enum Kind { |
97 | /// An integer type. Lowest bit is 1 for a signed value, 0 for an unsigned |
98 | /// value. Remaining bits are log_2(bit width). The value representation is |
99 | /// the integer itself if it fits into a ValueHandle, and a pointer to the |
100 | /// integer otherwise. |
101 | TK_Integer = 0x0000, |
102 | /// A floating-point type. Low 16 bits are bit width. The value |
103 | /// representation is that of bitcasting the floating-point value to an |
104 | /// integer type. |
105 | TK_Float = 0x0001, |
106 | /// Any other type. The value representation is unspecified. |
107 | TK_Unknown = 0xffff |
108 | }; |
109 | |
110 | const char *getTypeName() const { return TypeName; } |
111 | |
112 | Kind getKind() const { |
113 | return static_cast<Kind>(TypeKind); |
114 | } |
115 | |
116 | bool isIntegerTy() const { return getKind() == TK_Integer; } |
117 | bool isSignedIntegerTy() const { |
118 | return isIntegerTy() && (TypeInfo & 1); |
119 | } |
120 | bool isUnsignedIntegerTy() const { |
121 | return isIntegerTy() && !(TypeInfo & 1); |
122 | } |
123 | unsigned getIntegerBitWidth() const { |
124 | CHECK(isIntegerTy()); |
125 | return 1 << (TypeInfo >> 1); |
126 | } |
127 | |
128 | bool isFloatTy() const { return getKind() == TK_Float; } |
129 | unsigned getFloatBitWidth() const { |
130 | CHECK(isFloatTy()); |
131 | return TypeInfo; |
132 | } |
133 | }; |
134 | |
135 | /// \brief An opaque handle to a value. |
136 | typedef uptr ValueHandle; |
137 | |
138 | /// Returns the class name of the given ObjC object, or null if the name |
139 | /// cannot be found. |
140 | const char *getObjCClassName(ValueHandle Pointer); |
141 | |
142 | /// \brief Representation of an operand value provided by the instrumented code. |
143 | /// |
144 | /// This is a combination of a TypeDescriptor (which is emitted as constant data |
145 | /// as an operand to a handler function) and a ValueHandle (which is passed at |
146 | /// runtime when a check failure occurs). |
147 | class Value { |
148 | /// The type of the value. |
149 | const TypeDescriptor &Type; |
150 | /// The encoded value itself. |
151 | ValueHandle Val; |
152 | |
153 | /// Is \c Val a (zero-extended) integer? |
154 | bool isInlineInt() const { |
155 | CHECK(getType().isIntegerTy()); |
156 | const unsigned InlineBits = sizeof(ValueHandle) * 8; |
157 | const unsigned Bits = getType().getIntegerBitWidth(); |
158 | return Bits <= InlineBits; |
159 | } |
160 | |
161 | /// Is \c Val a (zero-extended) integer representation of a float? |
162 | bool isInlineFloat() const { |
163 | CHECK(getType().isFloatTy()); |
164 | const unsigned InlineBits = sizeof(ValueHandle) * 8; |
165 | const unsigned Bits = getType().getFloatBitWidth(); |
166 | return Bits <= InlineBits; |
167 | } |
168 | |
169 | public: |
170 | Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {} |
171 | |
172 | const TypeDescriptor &getType() const { return Type; } |
173 | |
174 | /// \brief Get this value as a signed integer. |
175 | SIntMax getSIntValue() const; |
176 | |
177 | /// \brief Get this value as an unsigned integer. |
178 | UIntMax getUIntValue() const; |
179 | |
180 | /// \brief Decode this value, which must be a positive or unsigned integer. |
181 | UIntMax getPositiveIntValue() const; |
182 | |
183 | /// Is this an integer with value -1? |
184 | bool isMinusOne() const { |
185 | return getType().isSignedIntegerTy() && getSIntValue() == -1; |
186 | } |
187 | |
188 | /// Is this a negative integer? |
189 | bool isNegative() const { |
190 | return getType().isSignedIntegerTy() && getSIntValue() < 0; |
191 | } |
192 | |
193 | /// \brief Get this value as a floating-point quantity. |
194 | FloatMax getFloatValue() const; |
195 | }; |
196 | |
197 | } // namespace __ubsan |
198 | |
199 | #endif // UBSAN_VALUE_H |
200 | |