/** * Provides classes for modeling C/C++ casts and conversions, as well as some * type-related operators such as `sizeof` and `alignof`. */ import semmle.code.cpp.exprs.Expr private import semmle.code.cpp.internal.ResolveClass /** * A C/C++ cast expression or similar unary expression that doesn't affect the logical value of its operand. * * Instances of this class are not present in the main AST which is navigated by parent/child links. Instead, * instances of this class are attached to nodes in the main AST via special conversion links. */ class Conversion extends Expr, @conversion { /** Gets the expression being converted. */ Expr getExpr() { result.getConversion() = this } /** Holds if this conversion is an implicit conversion. */ predicate isImplicit() { this.isCompilerGenerated() } override predicate mayBeImpure() { this.getExpr().mayBeImpure() } override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() } } /** * A C/C++ cast expression. * * To get the type which the expression is being cast to, use `Cast::getType()`. * * There are two groups of subtypes of `Cast`. The first group differentiates * between the different cast syntax forms, e.g. `CStyleCast`, `StaticCast`, * etc. The second group differentiates between the semantic operation being * performed by the cast, e.g. `IntegralConversion`, `PointerBaseClassConversion`, * etc. * The two groups are largely orthogonal to one another. For example, a * cast that is syntactically as `CStyleCast` may also be an `IntegralConversion`, * a `PointerBaseClassConversion`, or some other semantic conversion. Similarly, * a `PointerDerivedClassConversion` may also be a `CStyleCast` or a `StaticCast`. * * This is a root QL class representing the different casts. For * specific examples, consult the documentation for any of QL classes mentioned above. */ class Cast extends Conversion, @cast { /** * Gets a string describing the semantic conversion operation being performed by * this cast. */ string getSemanticConversionString() { result = "unknown conversion" } } /** * INTERNAL: Do not use. * Query predicates used to check invariants that should hold for all `Cast` * nodes. To run all consistency queries for the ASTs, including the ones below, * run "semmle/code/cpp/ASTConsistency.ql". */ module CastConsistency { /** * Holds if the cast has more than one result for `Cast.getSemanticConversionString()`. */ query predicate multipleSemanticConversionStrings(Cast cast, Type fromType, string kind) { // Every cast should have exactly one semantic conversion kind count(cast.getSemanticConversionString()) > 1 and kind = cast.getSemanticConversionString() and fromType = cast.getExpr().getUnspecifiedType() } /** * Holds if the cast has no result for `Cast.getSemanticConversionString()`. */ query predicate missingSemanticConversionString(Cast cast, Type fromType) { // Every cast should have exactly one semantic conversion kind not exists(cast.getSemanticConversionString()) and fromType = cast.getExpr().getUnspecifiedType() } /** * Holds if the cast has a result for `Cast.getSemanticConversionString()` that indicates that the * kind of its semantic conversion is not known. */ query predicate unknownSemanticConversionString(Cast cast, Type fromType) { // Every cast should have a known semantic conversion kind cast.getSemanticConversionString() = "unknown conversion" and fromType = cast.getExpr().getUnspecifiedType() } } /** * A cast expression in C, or a C-style cast expression in C++. * ``` * float f = 3.0f; * int i = (int)f; * ``` */ class CStyleCast extends Cast, @c_style_cast { override string toString() { result = "(" + this.getType().getName() + ")..." } override string getAPrimaryQlClass() { result = "CStyleCast" } override int getPrecedence() { result = 16 } } /** * A C++ `static_cast` expression. * * Please see https://en.cppreference.com/w/cpp/language/static_cast for * more information. * ``` * struct T: S {}; * struct S *s = get_S(); * struct T *t = static_cast(s); // downcast * ``` */ class StaticCast extends Cast, @static_cast { override string toString() { result = "static_cast<" + this.getType().getName() + ">..." } override string getAPrimaryQlClass() { result = "StaticCast" } override int getPrecedence() { result = 17 } } /** * A C++ `const_cast` expression. * * Please see https://en.cppreference.com/w/cpp/language/const_cast for * more information. * ``` * const struct S *s = get_S(); * struct S *t = const_cast(s); * ``` */ class ConstCast extends Cast, @const_cast { override string toString() { result = "const_cast<" + this.getType().getName() + ">..." } override string getAPrimaryQlClass() { result = "ConstCast" } override int getPrecedence() { result = 17 } } /** * A C++ `reinterpret_cast` expression. * * Please see https://en.cppreference.com/w/cpp/language/reinterpret_cast for * more information. * ``` * struct S *s = get_S(); * std::uintptr_t p = reinterpret_cast(s); * ``` */ class ReinterpretCast extends Cast, @reinterpret_cast { override string toString() { result = "reinterpret_cast<" + this.getType().getName() + ">..." } override string getAPrimaryQlClass() { result = "ReinterpretCast" } override int getPrecedence() { result = 17 } } private predicate isArithmeticOrEnum(Type type) { type instanceof ArithmeticType or type instanceof Enum } private predicate isIntegralOrEnum(Type type) { type instanceof IntegralType or type instanceof Enum } private predicate isPointerOrNullPointer(Type type) { type instanceof PointerType or type instanceof FunctionPointerType or type instanceof NullPointerType } private predicate isPointerToMemberOrNullPointer(Type type) { type instanceof PointerToMemberType or type instanceof NullPointerType } /** * A conversion from one arithmetic or `enum` type to another. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class ArithmeticConversion extends Cast { ArithmeticConversion() { conversionkinds(underlyingElement(this), 0) and isArithmeticOrEnum(this.getUnspecifiedType()) and isArithmeticOrEnum(this.getExpr().getUnspecifiedType()) } override string getSemanticConversionString() { result = "arithmetic conversion" } } /** * A conversion from one integral or enum type to another. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class IntegralConversion extends ArithmeticConversion { IntegralConversion() { isIntegralOrEnum(this.getUnspecifiedType()) and isIntegralOrEnum(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralConversion" } override string getSemanticConversionString() { result = "integral conversion" } } /** * A conversion from one floating point type. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class FloatingPointConversion extends ArithmeticConversion { FloatingPointConversion() { this.getUnspecifiedType() instanceof FloatingPointType and this.getExpr().getUnspecifiedType() instanceof FloatingPointType } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointConversion" } override string getSemanticConversionString() { result = "floating point conversion" } } /** * A conversion from a floating point type to an integral or enum type. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class FloatingPointToIntegralConversion extends ArithmeticConversion { FloatingPointToIntegralConversion() { isIntegralOrEnum(this.getUnspecifiedType()) and this.getExpr().getUnspecifiedType() instanceof FloatingPointType } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointToIntegralConversion" } override string getSemanticConversionString() { result = "floating point to integral conversion" } } /** * A conversion from an integral or enum type to a floating point type. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class IntegralToFloatingPointConversion extends ArithmeticConversion { IntegralToFloatingPointConversion() { this.getUnspecifiedType() instanceof FloatingPointType and isIntegralOrEnum(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToFloatingPointConversion" } override string getSemanticConversionString() { result = "integral to floating point conversion" } } /** * A conversion from one pointer type to another. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. * * The conversion does * not modify the value of the pointer. For pointer conversions involving * casts between base and derived classes, please see see `BaseClassConversion` or * `DerivedClassConversion`. */ class PointerConversion extends Cast { PointerConversion() { conversionkinds(underlyingElement(this), 0) and isPointerOrNullPointer(this.getUnspecifiedType()) and isPointerOrNullPointer(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" } override string getSemanticConversionString() { result = "pointer conversion" } } /** * A conversion from one pointer-to-member type to another. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. * * The conversion does not modify the value of the pointer-to-member. * For pointer-to-member conversions involving casts between base and * derived classes, please see `PointerToMemberBaseClassConversion` * or `PointerToMemberDerivedClassConversion`. */ class PointerToMemberConversion extends Cast { PointerToMemberConversion() { conversionkinds(underlyingElement(this), 0) and exists(Type fromType, Type toType | fromType = this.getExpr().getUnspecifiedType() and toType = this.getUnspecifiedType() and isPointerToMemberOrNullPointer(fromType) and isPointerToMemberOrNullPointer(toType) and // A conversion from nullptr to nullptr is a `PointerConversion`, not a // `PointerToMemberConversion`. not ( fromType instanceof NullPointerType and toType instanceof NullPointerType ) ) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberConversion" } override string getSemanticConversionString() { result = "pointer-to-member conversion" } } /** * A conversion from a pointer type to an integral or enum type. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class PointerToIntegralConversion extends Cast { PointerToIntegralConversion() { conversionkinds(underlyingElement(this), 0) and isIntegralOrEnum(this.getUnspecifiedType()) and isPointerOrNullPointer(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToIntegralConversion" } override string getSemanticConversionString() { result = "pointer to integral conversion" } } /** * A conversion from an integral or enum type to a pointer type. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class IntegralToPointerConversion extends Cast { IntegralToPointerConversion() { conversionkinds(underlyingElement(this), 0) and isPointerOrNullPointer(this.getUnspecifiedType()) and isIntegralOrEnum(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToPointerConversion" } override string getSemanticConversionString() { result = "integral to pointer conversion" } } /** * A conversion to `bool`. Returns `false` if the source value is zero, * `false`, or `nullptr`. Returns `true` otherwise. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class BoolConversion extends Cast { BoolConversion() { conversionkinds(underlyingElement(this), 1) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BoolConversion" } override string getSemanticConversionString() { result = "conversion to bool" } } /** * A conversion to `void`. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class VoidConversion extends Cast { VoidConversion() { conversionkinds(underlyingElement(this), 0) and this.getUnspecifiedType() instanceof VoidType } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" } override string getSemanticConversionString() { result = "conversion to void" } } /** * A conversion between two pointers or _glvalue_s related by inheritance. * * The base class will always be either a direct base class of the derived class, * or a virtual base class of the derived class. A conversion to an indirect * non-virtual base class will be represented as a sequence of conversions to * direct base classes. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class InheritanceConversion extends Cast { InheritanceConversion() { conversionkinds(underlyingElement(this), 2) or conversionkinds(underlyingElement(this), 3) } /** * Gets the `ClassDerivation` for the inheritance relationship between * the base and derived classes. This predicate does not hold if the * conversion is to an indirect virtual base class. */ final ClassDerivation getDerivation() { result.getBaseClass() = this.getBaseClass() and result.getDerivedClass() = this.getDerivedClass() } /** * Gets the base class of the conversion. This will be either a direct * base class of the derived class, or a virtual base class of the * derived class. */ Class getBaseClass() { none() // Overridden by subclasses } /** * Gets the derived class of the conversion. */ Class getDerivedClass() { none() // Overridden by subclasses } } /** * Given the source operand or result of an `InheritanceConversion`, returns the * class being converted from or to. If the type of the expression is a pointer, * this returns the pointed-to class. Otherwise, the type of the expression must * be a class, in which case the result is that class. */ private Class getConversionClass(Expr expr) { exists(Type operandType | operandType = expr.getUnspecifiedType() and ( result = operandType or result = operandType.(PointerType).getBaseType() ) ) } /** * A conversion from a pointer or _glvalue_ of a derived class to a pointer or * _glvalue_ of a direct or virtual base class. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class BaseClassConversion extends InheritanceConversion { BaseClassConversion() { conversionkinds(underlyingElement(this), 2) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BaseClassConversion" } override string getSemanticConversionString() { result = "base class conversion" } override Class getBaseClass() { result = getConversionClass(this) } override Class getDerivedClass() { result = getConversionClass(this.getExpr()) } /** * Holds if this conversion is to a virtual base class. */ predicate isVirtual() { this.getDerivation().isVirtual() or not exists(this.getDerivation()) } } /** * A conversion from a pointer or _glvalue_ to a base class to a pointer or _glvalue_ * to a direct derived class. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class DerivedClassConversion extends InheritanceConversion { DerivedClassConversion() { conversionkinds(underlyingElement(this), 3) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "DerivedClassConversion" } override string getSemanticConversionString() { result = "derived class conversion" } override Class getBaseClass() { result = getConversionClass(this.getExpr()) } override Class getDerivedClass() { result = getConversionClass(this) } } /** * A conversion from a pointer-to-member of a derived class to a pointer-to-member * of an immediate base class. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class PointerToMemberBaseClassConversion extends Cast { PointerToMemberBaseClassConversion() { conversionkinds(underlyingElement(this), 4) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberBaseClassConversion" } override string getSemanticConversionString() { result = "pointer-to-member base class conversion" } } /** * A conversion from a pointer-to-member of a base class to a pointer-to-member * of an immediate derived class. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class PointerToMemberDerivedClassConversion extends Cast { PointerToMemberDerivedClassConversion() { conversionkinds(underlyingElement(this), 5) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberDerivedClassConversion" } override string getSemanticConversionString() { result = "pointer-to-member derived class conversion" } } /** * A conversion of a _glvalue_ from one type to another. The conversion does not * modify the address of the _glvalue_. For _glvalue_ conversions involving base and * derived classes, see `BaseClassConversion` and `DerivedClassConversion`. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class GlvalueConversion extends Cast { GlvalueConversion() { conversionkinds(underlyingElement(this), 6) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" } override string getSemanticConversionString() { result = "glvalue conversion" } } /** * The adjustment of the type of a class _prvalue_. Most commonly seen in code * similar to: * ``` * class String { ... }; * String func(); * void caller() { * const String& r = func(); * } * ``` * In the above example, the result of the call to `func` is a _prvalue_ of type * `String`, which will be adjusted to type `const String` before being bound * to the reference. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class PrvalueAdjustmentConversion extends Cast { PrvalueAdjustmentConversion() { conversionkinds(underlyingElement(this), 7) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PrvalueAdjustmentConversion" } override string getSemanticConversionString() { result = "prvalue adjustment conversion" } } /** * A C++ `dynamic_cast` expression. * * Please see https://en.cppreference.com/w/cpp/language/dynamic_cast for * more information. * ``` * struct T: S {}; * struct S *s = get_S(); * struct T *t = dynamic_cast(s); // downcast * ``` */ class DynamicCast extends Cast, @dynamic_cast { override string toString() { result = "dynamic_cast<" + this.getType().getName() + ">..." } override int getPrecedence() { result = 17 } override string getAPrimaryQlClass() { result = "DynamicCast" } override string getSemanticConversionString() { result = "dynamic_cast" } } /** * A Microsoft C/C++ `__uuidof` expression that returns the UUID of a type, as * specified by the `__declspec(uuid)` attribute. * ``` * struct UUID { char a[16]; }; * struct __declspec(uuid("{01234567-89ab-cdef-0123-456789ABCDEF}")) S {}; * UUID uuid = __uuidof(S); * ``` */ class UuidofOperator extends Expr, @uuidof { override string toString() { if exists(this.getTypeOperand()) then result = "__uuidof(" + this.getTypeOperand().getName() + ")" else result = "__uuidof(0)" } override int getPrecedence() { result = 16 } /** Gets the contained type. */ Type getTypeOperand() { uuidof_bind(underlyingElement(this), unresolveElement(result)) } } /** * A C++ `typeid` expression which provides run-time type information (RTTI) * about its argument. * * Please see https://en.cppreference.com/w/cpp/language/typeid for more * information. * ``` * Base *ptr = new Derived; * const std::type_info &info1 = typeid(ptr); * printf("the type of ptr is: %s\n", typeid(ptr).name()); * ``` */ class TypeidOperator extends Expr, @type_id { /** * Gets the type that is returned by this typeid expression. */ Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) } override string getAPrimaryQlClass() { result = "TypeidOperator" } /** * Gets the contained expression, if any (if this typeid contains * a type rather than an expression, there is no result). */ Expr getExpr() { result = this.getChild(0) } override string toString() { result = "typeid ..." } override int getPrecedence() { result = 17 } override predicate mayBeImpure() { this.getExpr().mayBeImpure() } override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() } } /** * A C++11 `sizeof...` expression which determines the size of a template * parameter pack. * * This expression only appears in templates themselves - in any actual * instantiations, "sizeof...(x)" will be replaced by its integer value. * ``` * template < typename... T > * int count ( T &&... t ) { return sizeof... ( t ); } * ``` */ class SizeofPackOperator extends Expr, @sizeof_pack { override predicate mayBeImpure() { none() } override predicate mayBeGloballyImpure() { none() } } /** * A C++11 `sizeof...` expression which determines the size of a template * parameter pack and whose operand is an expression. * * This expression only appears in templates themselves - in any actual * instantiations, "sizeof...(x)" will be replaced by its integer value. * ``` * template < typename... T > * int count ( T &&... t ) { return sizeof... ( t ); } * ``` */ class SizeofPackExprOperator extends SizeofPackOperator { SizeofPackExprOperator() { exists(this.getChild(0)) } override string getAPrimaryQlClass() { result = "SizeofPackExprOperator" } /** Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } override string toString() { result = "sizeof...()" } } /** * A C++11 `sizeof...` expression which determines the size of a template * parameter pack and whose operand is an type name or a template template * parameter. * * This expression only appears in templates themselves - in any actual * instantiations, "sizeof...(x)" will be replaced by its integer value. * ``` * template < typename... T > * int count ( T &&... t ) { return sizeof... ( T ); } * ``` */ class SizeofPackTypeOperator extends SizeofPackOperator { SizeofPackTypeOperator() { sizeof_bind(underlyingElement(this), _) } override string getAPrimaryQlClass() { result = "SizeofPackTypeOperator" } /** Gets the contained type. */ Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } override string toString() { result = "sizeof...(" + this.getTypeOperand().getName() + ")" } } /** * A C/C++ sizeof expression. */ class SizeofOperator extends Expr, @runtime_sizeof { override int getPrecedence() { result = 16 } /** * Gets the contained type of this `sizeof`. For example, * the result is `int` in both cases below: * ``` * sizeof(int); * sizeof(42); * ``` */ Type getTypeOperand() { none() } // overridden in subclasses } /** * A C/C++ sizeof expression whose operand is an expression. * ``` * if (sizeof(a) == sizeof(b)) { c = (b)a; } * ``` */ class SizeofExprOperator extends SizeofOperator { SizeofExprOperator() { exists(this.getChild(0)) } override string getAPrimaryQlClass() { result = "SizeofExprOperator" } /** Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } override Type getTypeOperand() { result = this.getExprOperand().getType() } override string toString() { result = "sizeof()" } override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() } override predicate mayBeGloballyImpure() { this.getExprOperand().mayBeGloballyImpure() } } /** * A C/C++ sizeof expression whose operand is a type name. * ``` * int szlong = sizeof(int) == sizeof(long)? 4 : 8; * ``` */ class SizeofTypeOperator extends SizeofOperator { SizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) } override string getAPrimaryQlClass() { result = "SizeofTypeOperator" } override Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" } override predicate mayBeImpure() { none() } override predicate mayBeGloballyImpure() { none() } } /** * A C++11 `alignof` expression. */ class AlignofOperator extends Expr, @runtime_alignof { override int getPrecedence() { result = 16 } } /** * A C++11 `alignof` expression whose operand is an expression. * ``` * int addrMask = ~(alignof(expr) - 1); * ``` */ class AlignofExprOperator extends AlignofOperator { AlignofExprOperator() { exists(this.getChild(0)) } /** * Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } override string toString() { result = "alignof()" } } /** * A C++11 `alignof` expression whose operand is a type name. * ``` * bool proper_alignment = (alignof(T) == alignof(T[0]); * ``` */ class AlignofTypeOperator extends AlignofOperator { AlignofTypeOperator() { sizeof_bind(underlyingElement(this), _) } /** Gets the contained type. */ Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" } } /** * A C++ `__datasizeof` expression (used by some implementations * of the `` header). * * The `__datasizeof` expression behaves identically to `sizeof` except * that the result ignores tail padding. */ class DatasizeofOperator extends Expr, @datasizeof { override int getPrecedence() { result = 16 } /** * Gets the contained type of this `__datasizeof`. For example, * the result is `int` in both cases below: * ``` * __datasizeof(int); * __datasizeof(42); * ``` */ Type getTypeOperand() { none() } } /** * A C++ `__datasizeof` expression whose operand is an expression. */ class DatasizeofExprOperator extends DatasizeofOperator { DatasizeofExprOperator() { exists(this.getChild(0)) } override string getAPrimaryQlClass() { result = "DatasizeofExprOperator" } /** Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } override Type getTypeOperand() { result = this.getExprOperand().getType() } override string toString() { result = "__datasizeof()" } override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() } override predicate mayBeGloballyImpure() { this.getExprOperand().mayBeGloballyImpure() } } /** * A C++ `__datasizeof` expression whose operand is a type name. */ class DatasizeofTypeOperator extends DatasizeofOperator { DatasizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) } override string getAPrimaryQlClass() { result = "DatasizeofTypeOperator" } override Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } override string toString() { result = "__datasizeof(" + this.getTypeOperand().getName() + ")" } override predicate mayBeImpure() { none() } override predicate mayBeGloballyImpure() { none() } } /** * A C/C++ array to pointer conversion. * * The conversion is either implicit or underlies a particular cast. * Please see `CStyleCast`, `StaticCast`, `ConstCast` * or `ReinterpretCast` for more information. */ class ArrayToPointerConversion extends Conversion, @array_to_pointer { /** Gets a textual representation of this conversion. */ override string toString() { result = "array to pointer conversion" } override string getAPrimaryQlClass() { result = "ArrayToPointerConversion" } override predicate mayBeImpure() { none() } override predicate mayBeGloballyImpure() { none() } } /** * A node representing a temporary object created as part of an expression. * * This is most commonly seen in the following cases: * ```c++ * // when binding a reference to a prvalue * const std::string& r = std::string("text"); * * // when performing member access on a class prvalue * strlen(std::string("text").c_str()); * * // when a prvalue of a type with a destructor is discarded * s.substr(0, 5); // Return value is discarded but requires destruction * ``` */ class TemporaryObjectExpr extends Conversion, @temp_init { /** Gets a textual representation of this conversion. */ override string toString() { result = "temporary object" } override string getAPrimaryQlClass() { result = "TemporaryObjectExpr" } } /** * A node representing the Cast sub-class of entity `cast`. */ string qlCast(Cast cast) { // NB: Take care and include only leaf QL classes cast instanceof CStyleCast and result = "CStyleCast" or cast instanceof StaticCast and result = "StaticCast" or cast instanceof DynamicCast and result = "DynamicCast" or cast instanceof ConstCast and result = "ConstCast" or cast instanceof ReinterpretCast and result = "ReinterpretCast" } /** * A node representing the Conversion sub-class of entity `cast`. */ string qlConversion(Cast cast) { // NB: Take care and include only leaf QL classes cast instanceof IntegralConversion and result = "IntegralConversion" or cast instanceof FloatingPointConversion and result = "FloatingPointConversion" or cast instanceof FloatingPointToIntegralConversion and result = "FloatingPointToIntegralConversion" or cast instanceof IntegralToFloatingPointConversion and result = "IntegralToFloatingPointConversion" or cast instanceof PointerConversion and result = "PointerConversion" or cast instanceof PointerToMemberConversion and result = "PointerToMemberConversion" or cast instanceof PointerToIntegralConversion and result = "PointerToIntegralConversion" or cast instanceof IntegralToPointerConversion and result = "IntegralToPointerConversion" or cast instanceof BoolConversion and result = "BoolConversion" or cast instanceof VoidConversion and result = "VoidConversion" or cast instanceof BaseClassConversion and result = "BaseClassConversion" or cast instanceof DerivedClassConversion and result = "DerivedClassConversion" or cast instanceof PointerToMemberBaseClassConversion and result = "PointerToMemberBaseClassConversion" or cast instanceof PointerToMemberDerivedClassConversion and result = "PointerToMemberDerivedClassConversion" or cast instanceof GlvalueConversion and result = "GlvalueConversion" or cast instanceof PrvalueAdjustmentConversion and result = "PrvalueAdjustmentConversion" or // treat dynamic_cast<...>(...) as a conversion cast instanceof DynamicCast and result = "DynamicCast" }