]>
Commit | Line | Data |
---|---|---|
de5a5fa1 MP |
1 | //===-- ubsan_value.h -------------------------------------------*- C++ -*-===// |
2 | // | |
b667dd70 ML |
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 | |
de5a5fa1 MP |
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 | ||
de5a5fa1 MP |
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__ | |
df77f0e4 KS |
21 | __extension__ typedef __int128 s128; |
22 | __extension__ typedef unsigned __int128 u128; | |
de5a5fa1 MP |
23 | #define HAVE_INT128_T 1 |
24 | #else | |
25 | #define HAVE_INT128_T 0 | |
26 | #endif | |
27 | ||
de5a5fa1 MP |
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 | (__sanitizer::atomic_uint32_t *)&Column, ~u32(0), | |
62 | __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 | ||
139 | /// \brief Representation of an operand value provided by the instrumented code. | |
140 | /// | |
141 | /// This is a combination of a TypeDescriptor (which is emitted as constant data | |
142 | /// as an operand to a handler function) and a ValueHandle (which is passed at | |
143 | /// runtime when a check failure occurs). | |
144 | class Value { | |
145 | /// The type of the value. | |
146 | const TypeDescriptor &Type; | |
147 | /// The encoded value itself. | |
148 | ValueHandle Val; | |
149 | ||
150 | /// Is \c Val a (zero-extended) integer? | |
151 | bool isInlineInt() const { | |
152 | CHECK(getType().isIntegerTy()); | |
153 | const unsigned InlineBits = sizeof(ValueHandle) * 8; | |
154 | const unsigned Bits = getType().getIntegerBitWidth(); | |
155 | return Bits <= InlineBits; | |
156 | } | |
157 | ||
158 | /// Is \c Val a (zero-extended) integer representation of a float? | |
159 | bool isInlineFloat() const { | |
160 | CHECK(getType().isFloatTy()); | |
161 | const unsigned InlineBits = sizeof(ValueHandle) * 8; | |
162 | const unsigned Bits = getType().getFloatBitWidth(); | |
163 | return Bits <= InlineBits; | |
164 | } | |
165 | ||
166 | public: | |
167 | Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {} | |
168 | ||
169 | const TypeDescriptor &getType() const { return Type; } | |
170 | ||
171 | /// \brief Get this value as a signed integer. | |
172 | SIntMax getSIntValue() const; | |
173 | ||
174 | /// \brief Get this value as an unsigned integer. | |
175 | UIntMax getUIntValue() const; | |
176 | ||
177 | /// \brief Decode this value, which must be a positive or unsigned integer. | |
178 | UIntMax getPositiveIntValue() const; | |
179 | ||
180 | /// Is this an integer with value -1? | |
181 | bool isMinusOne() const { | |
182 | return getType().isSignedIntegerTy() && getSIntValue() == -1; | |
183 | } | |
184 | ||
185 | /// Is this a negative integer? | |
186 | bool isNegative() const { | |
187 | return getType().isSignedIntegerTy() && getSIntValue() < 0; | |
188 | } | |
189 | ||
190 | /// \brief Get this value as a floating-point quantity. | |
191 | FloatMax getFloatValue() const; | |
192 | }; | |
193 | ||
194 | } // namespace __ubsan | |
195 | ||
196 | #endif // UBSAN_VALUE_H |