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