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
28namespace __ubsan {
29
30/// \brief Largest integer types we support.
31#if HAVE_INT128_T
32typedef s128 SIntMax;
33typedef u128 UIntMax;
34#else
35typedef s64 SIntMax;
36typedef u64 UIntMax;
37#endif
38
39/// \brief Largest floating-point type we support.
40typedef long double FloatMax;
41
42/// \brief A description of a source location. This corresponds to Clang's
43/// \c PresumedLoc type.
44class SourceLocation {
45  const char *Filename;
46  u32 Line;
47  u32 Column;
48
49public:
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.
82class 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
95public:
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.
136typedef 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).
144class 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
166public:
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
197