10b57cec5SDimitry Andric //===-- ubsan_value.h -------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Representation of data which is passed from the compiler-generated calls into 100b57cec5SDimitry Andric // the ubsan runtime. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric #ifndef UBSAN_VALUE_H 140b57cec5SDimitry Andric #define UBSAN_VALUE_H 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_atomic.h" 170b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric // FIXME: Move this out to a config header. 200b57cec5SDimitry Andric #if __SIZEOF_INT128__ 210b57cec5SDimitry Andric __extension__ typedef __int128 s128; 220b57cec5SDimitry Andric __extension__ typedef unsigned __int128 u128; 230b57cec5SDimitry Andric #define HAVE_INT128_T 1 240b57cec5SDimitry Andric #else 250b57cec5SDimitry Andric #define HAVE_INT128_T 0 260b57cec5SDimitry Andric #endif 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace __ubsan { 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric /// \brief Largest integer types we support. 310b57cec5SDimitry Andric #if HAVE_INT128_T 320b57cec5SDimitry Andric typedef s128 SIntMax; 330b57cec5SDimitry Andric typedef u128 UIntMax; 340b57cec5SDimitry Andric #else 350b57cec5SDimitry Andric typedef s64 SIntMax; 360b57cec5SDimitry Andric typedef u64 UIntMax; 370b57cec5SDimitry Andric #endif 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric /// \brief Largest floating-point type we support. 400b57cec5SDimitry Andric typedef long double FloatMax; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric /// \brief A description of a source location. This corresponds to Clang's 430b57cec5SDimitry Andric /// \c PresumedLoc type. 440b57cec5SDimitry Andric class SourceLocation { 450b57cec5SDimitry Andric const char *Filename; 460b57cec5SDimitry Andric u32 Line; 470b57cec5SDimitry Andric u32 Column; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric public: SourceLocation()500b57cec5SDimitry Andric SourceLocation() : Filename(), Line(), Column() {} SourceLocation(const char * Filename,unsigned Line,unsigned Column)510b57cec5SDimitry Andric SourceLocation(const char *Filename, unsigned Line, unsigned Column) 520b57cec5SDimitry Andric : Filename(Filename), Line(Line), Column(Column) {} 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric /// \brief Determine whether the source location is known. isInvalid()550b57cec5SDimitry Andric bool isInvalid() const { return !Filename; } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric /// \brief Atomically acquire a copy, disabling original in-place. 580b57cec5SDimitry Andric /// Exactly one call to acquire() returns a copy that isn't disabled. acquire()590b57cec5SDimitry Andric SourceLocation acquire() { 600b57cec5SDimitry Andric u32 OldColumn = __sanitizer::atomic_exchange( 610b57cec5SDimitry Andric (__sanitizer::atomic_uint32_t *)&Column, ~u32(0), 620b57cec5SDimitry Andric __sanitizer::memory_order_relaxed); 630b57cec5SDimitry Andric return SourceLocation(Filename, Line, OldColumn); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric /// \brief Determine if this Location has been disabled. 670b57cec5SDimitry Andric /// Disabled SourceLocations are invalid to use. isDisabled()680b57cec5SDimitry Andric bool isDisabled() { 690b57cec5SDimitry Andric return Column == ~u32(0); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric /// \brief Get the presumed filename for the source location. getFilename()730b57cec5SDimitry Andric const char *getFilename() const { return Filename; } 740b57cec5SDimitry Andric /// \brief Get the presumed line number. getLine()750b57cec5SDimitry Andric unsigned getLine() const { return Line; } 760b57cec5SDimitry Andric /// \brief Get the column within the presumed line. getColumn()770b57cec5SDimitry Andric unsigned getColumn() const { return Column; } 780b57cec5SDimitry Andric }; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric /// \brief A description of a type. 820b57cec5SDimitry Andric class TypeDescriptor { 830b57cec5SDimitry Andric /// A value from the \c Kind enumeration, specifying what flavor of type we 840b57cec5SDimitry Andric /// have. 850b57cec5SDimitry Andric u16 TypeKind; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric /// A \c Type-specific value providing information which allows us to 880b57cec5SDimitry Andric /// interpret the meaning of a ValueHandle of this type. 890b57cec5SDimitry Andric u16 TypeInfo; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric /// The name of the type follows, in a format suitable for including in 920b57cec5SDimitry Andric /// diagnostics. 930b57cec5SDimitry Andric char TypeName[1]; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric public: 960b57cec5SDimitry Andric enum Kind { 970b57cec5SDimitry Andric /// An integer type. Lowest bit is 1 for a signed value, 0 for an unsigned 980b57cec5SDimitry Andric /// value. Remaining bits are log_2(bit width). The value representation is 990b57cec5SDimitry Andric /// the integer itself if it fits into a ValueHandle, and a pointer to the 1000b57cec5SDimitry Andric /// integer otherwise. 1010b57cec5SDimitry Andric TK_Integer = 0x0000, 1020b57cec5SDimitry Andric /// A floating-point type. Low 16 bits are bit width. The value 1030b57cec5SDimitry Andric /// representation is that of bitcasting the floating-point value to an 1040b57cec5SDimitry Andric /// integer type. 1050b57cec5SDimitry Andric TK_Float = 0x0001, 1060b57cec5SDimitry Andric /// Any other type. The value representation is unspecified. 1070b57cec5SDimitry Andric TK_Unknown = 0xffff 1080b57cec5SDimitry Andric }; 1090b57cec5SDimitry Andric getTypeName()1100b57cec5SDimitry Andric const char *getTypeName() const { return TypeName; } 1110b57cec5SDimitry Andric getKind()1120b57cec5SDimitry Andric Kind getKind() const { 1130b57cec5SDimitry Andric return static_cast<Kind>(TypeKind); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric isIntegerTy()1160b57cec5SDimitry Andric bool isIntegerTy() const { return getKind() == TK_Integer; } isSignedIntegerTy()1170b57cec5SDimitry Andric bool isSignedIntegerTy() const { 1180b57cec5SDimitry Andric return isIntegerTy() && (TypeInfo & 1); 1190b57cec5SDimitry Andric } isUnsignedIntegerTy()1200b57cec5SDimitry Andric bool isUnsignedIntegerTy() const { 1210b57cec5SDimitry Andric return isIntegerTy() && !(TypeInfo & 1); 1220b57cec5SDimitry Andric } getIntegerBitWidth()1230b57cec5SDimitry Andric unsigned getIntegerBitWidth() const { 1240b57cec5SDimitry Andric CHECK(isIntegerTy()); 1250b57cec5SDimitry Andric return 1 << (TypeInfo >> 1); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric isFloatTy()1280b57cec5SDimitry Andric bool isFloatTy() const { return getKind() == TK_Float; } getFloatBitWidth()1290b57cec5SDimitry Andric unsigned getFloatBitWidth() const { 1300b57cec5SDimitry Andric CHECK(isFloatTy()); 1310b57cec5SDimitry Andric return TypeInfo; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric }; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric /// \brief An opaque handle to a value. 1360b57cec5SDimitry Andric typedef uptr ValueHandle; 1370b57cec5SDimitry Andric 138*5ffd83dbSDimitry Andric /// Returns the class name of the given ObjC object, or null if the name 139*5ffd83dbSDimitry Andric /// cannot be found. 140*5ffd83dbSDimitry Andric const char *getObjCClassName(ValueHandle Pointer); 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric /// \brief Representation of an operand value provided by the instrumented code. 1430b57cec5SDimitry Andric /// 1440b57cec5SDimitry Andric /// This is a combination of a TypeDescriptor (which is emitted as constant data 1450b57cec5SDimitry Andric /// as an operand to a handler function) and a ValueHandle (which is passed at 1460b57cec5SDimitry Andric /// runtime when a check failure occurs). 1470b57cec5SDimitry Andric class Value { 1480b57cec5SDimitry Andric /// The type of the value. 1490b57cec5SDimitry Andric const TypeDescriptor &Type; 1500b57cec5SDimitry Andric /// The encoded value itself. 1510b57cec5SDimitry Andric ValueHandle Val; 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric /// Is \c Val a (zero-extended) integer? isInlineInt()1540b57cec5SDimitry Andric bool isInlineInt() const { 1550b57cec5SDimitry Andric CHECK(getType().isIntegerTy()); 1560b57cec5SDimitry Andric const unsigned InlineBits = sizeof(ValueHandle) * 8; 1570b57cec5SDimitry Andric const unsigned Bits = getType().getIntegerBitWidth(); 1580b57cec5SDimitry Andric return Bits <= InlineBits; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric /// Is \c Val a (zero-extended) integer representation of a float? isInlineFloat()1620b57cec5SDimitry Andric bool isInlineFloat() const { 1630b57cec5SDimitry Andric CHECK(getType().isFloatTy()); 1640b57cec5SDimitry Andric const unsigned InlineBits = sizeof(ValueHandle) * 8; 1650b57cec5SDimitry Andric const unsigned Bits = getType().getFloatBitWidth(); 1660b57cec5SDimitry Andric return Bits <= InlineBits; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric public: Value(const TypeDescriptor & Type,ValueHandle Val)1700b57cec5SDimitry Andric Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {} 1710b57cec5SDimitry Andric getType()1720b57cec5SDimitry Andric const TypeDescriptor &getType() const { return Type; } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric /// \brief Get this value as a signed integer. 1750b57cec5SDimitry Andric SIntMax getSIntValue() const; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric /// \brief Get this value as an unsigned integer. 1780b57cec5SDimitry Andric UIntMax getUIntValue() const; 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric /// \brief Decode this value, which must be a positive or unsigned integer. 1810b57cec5SDimitry Andric UIntMax getPositiveIntValue() const; 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric /// Is this an integer with value -1? isMinusOne()1840b57cec5SDimitry Andric bool isMinusOne() const { 1850b57cec5SDimitry Andric return getType().isSignedIntegerTy() && getSIntValue() == -1; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric /// Is this a negative integer? isNegative()1890b57cec5SDimitry Andric bool isNegative() const { 1900b57cec5SDimitry Andric return getType().isSignedIntegerTy() && getSIntValue() < 0; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric /// \brief Get this value as a floating-point quantity. 1940b57cec5SDimitry Andric FloatMax getFloatValue() const; 1950b57cec5SDimitry Andric }; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric } // namespace __ubsan 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric #endif // UBSAN_VALUE_H 200