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