xref: /llvm-project/compiler-rt/lib/ubsan/ubsan_value.h (revision b7a6e9da124142a1bd28895eea768a158901a03b)
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                         (__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     /// An _BitInt(N) type. Lowest bit is 1 for a signed value, 0 for an
107     /// unsigned value. Remaining bits are log_2(bit_width). The value
108     /// representation is the integer itself if it fits into a ValueHandle, and
109     /// a pointer to the integer otherwise. TypeName contains the true width
110     /// of the type for the signed _BitInt(N) type stored after zero bit after
111     /// TypeName as 32-bit unsigned integer.
112     TK_BitInt = 0x0002,
113     /// Any other type. The value representation is unspecified.
114     TK_Unknown = 0xffff
115   };
116 
117   const char *getTypeName() const { return TypeName; }
118 
119   Kind getKind() const {
120     return static_cast<Kind>(TypeKind);
121   }
122 
123   bool isIntegerTy() const {
124     return getKind() == TK_Integer || getKind() == TK_BitInt;
125   }
126   bool isBitIntTy() const { return getKind() == TK_BitInt; }
127 
128   bool isSignedIntegerTy() const {
129     return isIntegerTy() && (TypeInfo & 1);
130   }
131   bool isSignedBitIntTy() const { return isBitIntTy() && (TypeInfo & 1); }
132   bool isUnsignedIntegerTy() const {
133     return isIntegerTy() && !(TypeInfo & 1);
134   }
135   unsigned getIntegerBitWidth() const {
136     CHECK(isIntegerTy());
137     return 1 << (TypeInfo >> 1);
138   }
139 
140   const char *getBitIntBitCountPointer() const {
141     DCHECK(isBitIntTy());
142     DCHECK(isSignedBitIntTy());
143     // Scan Name for zero and return the next address
144     const char *p = getTypeName();
145     while (*p != '\0')
146       ++p;
147     // Return the next address
148     return p + 1;
149   }
150 
151   unsigned getIntegerBitCount() const {
152     DCHECK(isIntegerTy());
153     if (isSignedBitIntTy()) {
154       u32 BitCountValue;
155       internal_memcpy(&BitCountValue, getBitIntBitCountPointer(),
156                       sizeof(BitCountValue));
157       return BitCountValue;
158     } else
159       return getIntegerBitWidth();
160   }
161 
162   bool isFloatTy() const { return getKind() == TK_Float; }
163   unsigned getFloatBitWidth() const {
164     CHECK(isFloatTy());
165     return TypeInfo;
166   }
167 };
168 
169 /// \brief An opaque handle to a value.
170 typedef uptr ValueHandle;
171 
172 /// Returns the class name of the given ObjC object, or null if the name
173 /// cannot be found.
174 const char *getObjCClassName(ValueHandle Pointer);
175 
176 /// \brief Representation of an operand value provided by the instrumented code.
177 ///
178 /// This is a combination of a TypeDescriptor (which is emitted as constant data
179 /// as an operand to a handler function) and a ValueHandle (which is passed at
180 /// runtime when a check failure occurs).
181 class Value {
182   /// The type of the value.
183   const TypeDescriptor &Type;
184   /// The encoded value itself.
185   ValueHandle Val;
186 
187   /// Is \c Val a (zero-extended) integer?
188   bool isInlineInt() const {
189     CHECK(getType().isIntegerTy());
190     const unsigned InlineBits = sizeof(ValueHandle) * 8;
191     const unsigned Bits = getType().getIntegerBitWidth();
192     return Bits <= InlineBits;
193   }
194 
195   /// Is \c Val a (zero-extended) integer representation of a float?
196   bool isInlineFloat() const {
197     CHECK(getType().isFloatTy());
198     const unsigned InlineBits = sizeof(ValueHandle) * 8;
199     const unsigned Bits = getType().getFloatBitWidth();
200     return Bits <= InlineBits;
201   }
202 
203 public:
204   Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {}
205 
206   const TypeDescriptor &getType() const { return Type; }
207 
208   /// \brief Get this value as a signed integer.
209   SIntMax getSIntValue() const;
210 
211   /// \brief Get this value as an unsigned integer.
212   UIntMax getUIntValue() const;
213 
214   /// \brief Decode this value, which must be a positive or unsigned integer.
215   UIntMax getPositiveIntValue() const;
216 
217   /// Is this an integer with value -1?
218   bool isMinusOne() const {
219     return getType().isSignedIntegerTy() && getSIntValue() == -1;
220   }
221 
222   /// Is this a negative integer?
223   bool isNegative() const {
224     return getType().isSignedIntegerTy() && getSIntValue() < 0;
225   }
226 
227   /// \brief Get this value as a floating-point quantity.
228   FloatMax getFloatValue() const;
229 };
230 
231 } // namespace __ubsan
232 
233 #endif // UBSAN_VALUE_H
234