Packaging: Refactor the cpp libraries

This PR separates the core cpp packs into `codeql/cpp-queries` and
`codeql/cpp-all`.

There are very few lines of code changed. Almost all changes are moving
files around.
This commit is contained in:
Andrew Eisenberg
2021-08-16 17:23:27 -07:00
parent e566fb9c5a
commit 2c5dd2dfa3
421 changed files with 175 additions and 159 deletions

View File

@@ -0,0 +1,469 @@
/**
* Provides classes for modeling accesses including variable accesses, enum
* constant accesses and function accesses.
*/
import semmle.code.cpp.exprs.Expr
import semmle.code.cpp.Variable
import semmle.code.cpp.Enum
private import semmle.code.cpp.dataflow.EscapesTree
/**
* A C/C++ access expression. This refers to a function, variable, or enum constant.
*/
class Access extends Expr, NameQualifiableElement, @access {
// As `@access` is a union type containing `@routineexpr` (which describes function accesses
// that are called), we need to exclude function calls.
Access() { this instanceof @routineexpr implies not iscall(underlyingElement(this), _) }
/** Gets the accessed function, variable, or enum constant. */
Declaration getTarget() { none() } // overridden in subclasses
override predicate mayBeImpure() { none() }
override predicate mayBeGloballyImpure() { none() }
override string toString() { none() }
}
/**
* A C/C++ `enum` constant access expression. For example the access to
* `MYENUMCONST1` in `myFunction` in the following code:
* ```
* enum MyEnum {
* MYENUMCONST1,
* MYENUMCONST2
* };
*
* void myFunction() {
* MyEnum v = MYENUMCONST1;
* };
* ```
*/
class EnumConstantAccess extends Access, @varaccess {
override string getAPrimaryQlClass() { result = "EnumConstantAccess" }
EnumConstantAccess() {
exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
}
/** Gets the accessed `enum` constant. */
override EnumConstant getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
/** Gets a textual representation of this `enum` constant access. */
override string toString() { result = this.getTarget().getName() }
}
/**
* A C/C++ variable access expression. For example the accesses to
* `x` and `y` in `myFunction` in the following code:
* ```
* int x;
*
* void myFunction(int y) {
* x = y;
* };
* ```
*/
class VariableAccess extends Access, @varaccess {
override string getAPrimaryQlClass() { result = "VariableAccess" }
VariableAccess() {
not exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
}
/** Gets the accessed variable. */
override Variable getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
/**
* Holds if this variable access is providing an LValue in a meaningful way.
* For example, this includes accesses on the left-hand side of an assignment.
* It does not include accesses on the right-hand side of an assignment, even if they could appear on the left-hand side of some assignment.
*/
predicate isUsedAsLValue() {
exists(Assignment a | a.getLValue() = this) or
exists(CrementOperation c | c.getOperand() = this) or
exists(AddressOfExpr addof | addof.getOperand() = this) or
exists(ReferenceToExpr rte | this.getConversion() = rte) or
exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
}
/**
* Holds if this variable access is in a position where it is (directly) modified,
* for instance by an assignment or increment/decrement operator.
*/
predicate isModified() {
exists(Assignment a | a.getLValue() = this)
or
exists(CrementOperation c | c.getOperand() = this)
or
exists(FunctionCall c | c.getQualifier() = this and c.getTarget().hasName("operator="))
}
/** Holds if this variable access is an rvalue. */
predicate isRValue() {
not exists(AssignExpr ae | ae.getLValue() = this) and
not exists(AddressOfExpr addof | addof.getOperand() = this) and
not exists(ReferenceToExpr rte | this.getConversion() = rte) and
not exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
}
/**
* Gets the expression generating the variable being accessed.
*
* As a few examples:
* For `ptr->x`, this gives `ptr`.
* For `(*ptr).x`, this gives `(*ptr)`.
* For `smart_ptr->x`, this gives the call to `operator->`.
*
* This applies mostly to FieldAccesses, but also to static member variables accessed
* "through" a pointer. Note that it does NOT apply to static member variables accessed
* through a type name, as in that case the type name is a qualifier on the variable
* rather than a qualifier on the access.
*/
Expr getQualifier() { this.getChild(-1) = result }
/** Gets a textual representation of this variable access. */
override string toString() {
if exists(this.getTarget())
then result = this.getTarget().getName()
else result = "variable access"
}
override predicate mayBeImpure() {
this.getQualifier().mayBeImpure() or
this.getTarget().getType().isVolatile()
}
override predicate mayBeGloballyImpure() {
this.getQualifier().mayBeGloballyImpure() or
this.getTarget().getType().isVolatile()
}
/**
* Holds if this access is used to get the address of the underlying variable
* in such a way that the address might escape. This can be either explicit,
* for example `&x`, or implicit, for example `T& y = x`.
*/
predicate isAddressOfAccess() { variableAddressEscapesTree(this, _) }
/**
* Holds if this access is used to get the address of the underlying variable
* in such a way that the address might escape as a pointer or reference to
* non-const data. This can be either explicit, for example `&x`, or
* implicit, for example `T& y = x`.
*/
predicate isAddressOfAccessNonConst() { variableAddressEscapesTreeNonConst(this, _) }
}
/**
* A C/C++ field access expression. For example the accesses to
* `x` and `y` in `myMethod` in the following code:
* ```
* class MyClass {
* public:
* void myMethod(MyClass &other) {
* x = other.y;
* }
*
* int x, y;
* };
* ```
*/
class FieldAccess extends VariableAccess {
override string getAPrimaryQlClass() { result = "FieldAccess" }
FieldAccess() { exists(Field f | varbind(underlyingElement(this), unresolveElement(f))) }
/** Gets the accessed field. */
override Field getTarget() { result = super.getTarget() }
}
/**
* A field access whose qualifier is a pointer to a class, struct or union.
* These typically take the form `obj->field`. Another case is a field access
* with an implicit `this->` qualifier, which is often a `PointerFieldAccess`
* (but see also `ImplicitThisFieldAccess`).
*
* For example the accesses to `x` and `y` in `myMethod` in the following code
* are each a `PointerFieldAccess`:
* ```
* class MyClass {
* public:
* void myMethod(MyClass *other) {
* other->x = y;
* }
*
* int x, y;
* };
* ```
*/
class PointerFieldAccess extends FieldAccess {
override string getAPrimaryQlClass() { result = "PointerFieldAccess" }
PointerFieldAccess() {
exists(PointerType t |
t = getQualifier().getFullyConverted().getUnspecifiedType() and
t.getBaseType() instanceof Class
)
}
}
/**
* A field access of the form `obj.field`. The type of `obj` is either a
* class/struct/union or a reference to one. `DotFieldAccess` has two
* sub-classes, `ValueFieldAccess` and `ReferenceFieldAccess`, to
* distinguish whether or not the type of `obj` is a reference type.
*/
class DotFieldAccess extends FieldAccess {
override string getAPrimaryQlClass() { result = "DotFieldAccess" }
DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) }
}
/**
* A field access of the form `obj.field`, where the type of `obj` is a
* reference to a class/struct/union. For example the accesses to `y` in
* `myMethod` in the following code:
* ```
* class MyClass {
* public:
* void myMethod(MyClass a, MyClass &b) {
* a.x = b.y;
* }
*
* int x, y;
* };
* ```
*/
class ReferenceFieldAccess extends DotFieldAccess {
override string getAPrimaryQlClass() { result = "ReferenceFieldAccess" }
ReferenceFieldAccess() { exprHasReferenceConversion(this.getQualifier()) }
}
/**
* A field access of the form `obj.field`, where the type of `obj` is a
* class/struct/union (and not a reference). For example the accesses to `x`
* in `myMethod` in the following code:
* ```
* class MyClass {
* public:
* void myMethod(MyClass a, MyClass &b) {
* a.x = b.y;
* }
*
* int x, y;
* };
* ```
*/
class ValueFieldAccess extends DotFieldAccess {
override string getAPrimaryQlClass() { result = "ValueFieldAccess" }
ValueFieldAccess() { not exprHasReferenceConversion(this.getQualifier()) }
}
/**
* Holds if `c` is a conversion from type `T&` to `T` (or from `T&&` to
* `T`).
*/
private predicate referenceConversion(Conversion c) {
c.getType() = c.getExpr().getType().(ReferenceType).getBaseType()
}
/**
* Holds if `e` is a reference expression (that is, it has a type of the
* form `T&`), which is converted to a value. For example:
* ```
* int myfcn(MyStruct &x) {
* return x.field;
* }
* ```
* In this example, the type of `x` is `MyStruct&`, but it gets implicitly
* converted to `MyStruct` in the expression `x.field`.
*/
private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.getConversion+()) }
/**
* A field access of a field of `this` which has no qualifier because
* the use of `this` is implicit. For example, in the following code the
* implicit call to the destructor of `A` has no qualifier because the
* use of `this` is implicit:
* ```
* class A {
* public:
* ~A() {
* // ...
* }
* };
*
* class B {
* public:
* A a;
*
* ~B() {
* // Implicit call to the destructor of `A`.
* }
* };
* ```
* Note: the C++ front-end often automatically desugars `field` to
* `this->field`, so most accesses of `this->field` are instances
* of `PointerFieldAccess` (with `ThisExpr` as the qualifier), not
* `ImplicitThisFieldAccess`.
*/
class ImplicitThisFieldAccess extends FieldAccess {
override string getAPrimaryQlClass() { result = "ImplicitThisFieldAccess" }
ImplicitThisFieldAccess() { not exists(this.getQualifier()) }
}
/**
* A C++ _pointer to non-static data member_ literal. For example, `&C::x` is
* an expression that refers to field `x` of class `C`. If the type of that
* field is `int`, then `&C::x` ought to have type `int C::*`. It is currently
* modeled in QL as having type `int`.
*
* See [dcl.mptr] in the C++17 standard or see
* https://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members.
*/
class PointerToFieldLiteral extends ImplicitThisFieldAccess {
PointerToFieldLiteral() {
// The extractor currently emits a pointer-to-field literal as a field
// access without a qualifier. The only other unqualified field accesses it
// emits are for compiler-generated constructors and destructors. When we
// filter those out, there are only pointer-to-field literals left.
not this.isCompilerGenerated()
}
override predicate isConstant() { any() }
override string getAPrimaryQlClass() { result = "PointerToFieldLiteral" }
}
/**
* A C/C++ function access expression. For example the access to
* `myFunctionTarget` in `myFunction` in the following code:
* ```
* int myFunctionTarget(int);
*
* void myFunction() {
* int (*myFunctionPointer)(int) = &myFunctionTarget;
* }
* ```
*/
class FunctionAccess extends Access, @routineexpr {
FunctionAccess() { not iscall(underlyingElement(this), _) }
override string getAPrimaryQlClass() { result = "FunctionAccess" }
/** Gets the accessed function. */
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
/** Gets a textual representation of this function access. */
override string toString() {
if exists(this.getTarget())
then result = this.getTarget().getName()
else result = "function access"
}
}
/**
* An access to a parameter of a function signature for the purposes of a `decltype`.
*
* For example, given the following code:
* ```
* template <typename L, typename R>
* auto add(L lhs, R rhs) -> decltype(lhs + rhs) {
* return lhs + rhs;
* }
* ```
* The return type of the function is a decltype, the expression of which contains
* an add expression, which in turn has two `ParamAccessForType` children.
*/
class ParamAccessForType extends Expr, @param_ref {
override string toString() { result = "param access" }
}
/**
* An access to a type. This occurs in certain contexts where a built-in
* works on types directly rather than variables, expressions etc. For
* example the reference to `MyClass` in `__is_pod` in the following code:
* ```
* class MyClass {
* ...
* };
*
* void myFunction() {
* if (__is_pod(MyClass))
* {
* ...
* } else {
* ...
* }
* }
* ```
*/
class TypeName extends Expr, @type_operand {
override string getAPrimaryQlClass() { result = "TypeName" }
override string toString() { result = this.getType().getName() }
}
/**
* A C/C++ array access expression. For example, the access to `as` in
* `myFunction` in the following code:
* ```
* int as[10];
*
* void myFunction() {
* as[0]++;
* }
* ```
* For calls to `operator[]`, which look syntactically identical, see
* `OverloadedArrayExpr`.
*/
class ArrayExpr extends Expr, @subscriptexpr {
override string getAPrimaryQlClass() { result = "ArrayExpr" }
/**
* Gets the array or pointer expression being subscripted.
*
* This is `arr` in both `arr[0]` and `0[arr]`.
*/
Expr getArrayBase() { result = this.getChild(0) }
/**
* Gets the expression giving the index into the array.
*
* This is `0` in both `arr[0]` and `0[arr]`.
*/
Expr getArrayOffset() { result = this.getChild(1) }
/**
* Holds if this array access is in a position where it is (directly) modified,
* for instance by an assignment or an increment/decrement operation.
*/
predicate isModified() {
exists(Assignment a | a.getLValue() = this)
or
exists(CrementOperation c | c.getOperand() = this)
or
exists(FunctionCall c | c.getQualifier() = this and c.getTarget().hasName("operator="))
}
override string toString() { result = "access to array" }
override predicate mayBeImpure() {
this.getArrayBase().mayBeImpure() or
this.getArrayOffset().mayBeImpure() or
this.getArrayBase().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile() or
this.getArrayOffset().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile()
}
override predicate mayBeGloballyImpure() {
this.getArrayBase().mayBeGloballyImpure() or
this.getArrayOffset().mayBeGloballyImpure() or
this.getArrayBase().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile() or
this.getArrayOffset().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile()
}
}

View File

@@ -0,0 +1,455 @@
/**
* Provides classes for modeling arithmetic operations such as `+`, `-`, `*`
* and `++`.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C/C++ unary arithmetic operation.
*/
class UnaryArithmeticOperation extends UnaryOperation, @un_arith_op_expr { }
/**
* A C/C++ unary minus expression.
* ```
* b = - a;
* ```
*/
class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "UnaryMinusExpr" }
override int getPrecedence() { result = 16 }
}
/**
* A C/C++ unary plus expression.
* ```
* b = + a;
* ```
*/
class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr {
override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "UnaryPlusExpr" }
override int getPrecedence() { result = 16 }
}
/**
* A C/C++ GNU conjugation expression. It operates on `_Complex` or
* `__complex__ `numbers, and is similar to the C99 `conj`, `conjf` and `conjl`
* functions.
* ```
* _Complex double a = ( 1.0, 2.0 );
* _Complex double b = ~ a; // ( 1.0, - 2.0 )
* ```
*/
class ConjugationExpr extends UnaryArithmeticOperation, @conjugation {
override string getOperator() { result = "~" }
override string getAPrimaryQlClass() { result = "ConjugationExpr" }
}
/**
* A C/C++ `++` or `--` expression (either prefix or postfix).
*
* This is the base QL class for increment and decrement operations.
*
* Note that this does not include calls to user-defined `operator++`
* or `operator--`.
*/
class CrementOperation extends UnaryArithmeticOperation, @crement_expr {
override predicate mayBeImpure() { any() }
override predicate mayBeGloballyImpure() {
not exists(VariableAccess va, StackVariable v |
va = this.getOperand() and
v = va.getTarget() and
not va.getConversion+() instanceof ReferenceDereferenceExpr
)
}
}
/**
* A C/C++ `++` expression (either prefix or postfix).
*
* Note that this does not include calls to user-defined `operator++`.
*/
class IncrementOperation extends CrementOperation, @increment_expr { }
/**
* A C/C++ `--` expression (either prefix or postfix).
*
* Note that this does not include calls to user-defined `operator--`.
*/
class DecrementOperation extends CrementOperation, @decrement_expr { }
/**
* A C/C++ `++` or `--` prefix expression.
*
* Note that this does not include calls to user-defined operators.
*/
class PrefixCrementOperation extends CrementOperation, @prefix_crement_expr { }
/**
* A C/C++ `++` or `--` postfix expression.
*
* Note that this does not include calls to user-defined operators.
*/
class PostfixCrementOperation extends CrementOperation, @postfix_crement_expr { }
/**
* A C/C++ prefix increment expression, as in `++x`.
*
* Note that this does not include calls to user-defined `operator++`.
* ```
* b = ++a;
* ```
*/
class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preincrexpr {
override string getOperator() { result = "++" }
override string getAPrimaryQlClass() { result = "PrefixIncrExpr" }
override int getPrecedence() { result = 16 }
}
/**
* A C/C++ prefix decrement expression, as in `--x`.
*
* Note that this does not include calls to user-defined `operator--`.
* ```
* b = --a;
* ```
*/
class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predecrexpr {
override string getOperator() { result = "--" }
override string getAPrimaryQlClass() { result = "PrefixDecrExpr" }
override int getPrecedence() { result = 16 }
}
/**
* A C/C++ postfix increment expression, as in `x++`.
*
* Note that this does not include calls to user-defined `operator++`.
* ```
* b = a++;
* ```
*/
class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @postincrexpr {
override string getOperator() { result = "++" }
override string getAPrimaryQlClass() { result = "PostfixIncrExpr" }
override int getPrecedence() { result = 17 }
override string toString() { result = "... " + getOperator() }
}
/**
* A C/C++ postfix decrement expression, as in `x--`.
*
* Note that this does not include calls to user-defined `operator--`.
* ```
* b = a--;
* ```
*/
class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @postdecrexpr {
override string getOperator() { result = "--" }
override string getAPrimaryQlClass() { result = "PostfixDecrExpr" }
override int getPrecedence() { result = 17 }
override string toString() { result = "... " + getOperator() }
}
/**
* A C/C++ GNU real part expression. It operates on `_Complex` or
* `__complex__` numbers.
* ```
* _Complex double f = { 2.0, 3.0 };
* double d = __real(f); // 2.0
* ```
*/
class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr {
override string getOperator() { result = "__real" }
override string getAPrimaryQlClass() { result = "RealPartExpr" }
}
/**
* A C/C++ GNU imaginary part expression. It operates on `_Complex` or
* `__complex__` numbers.
* ```
* _Complex double f = { 2.0, 3.0 };
* double d = __imag(f); // 3.0
* ```
*/
class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr {
override string getOperator() { result = "__imag" }
override string getAPrimaryQlClass() { result = "ImaginaryPartExpr" }
}
/**
* A C/C++ binary arithmetic operation.
*
* This is an abstract base QL class for all binary arithmetic operations.
*/
class BinaryArithmeticOperation extends BinaryOperation, @bin_arith_op_expr { }
/**
* A C/C++ add expression.
* ```
* c = a + b;
* ```
*/
class AddExpr extends BinaryArithmeticOperation, @addexpr {
override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "AddExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ subtract expression.
* ```
* c = a - b;
* ```
*/
class SubExpr extends BinaryArithmeticOperation, @subexpr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "SubExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ multiply expression.
* ```
* c = a * b;
* ```
*/
class MulExpr extends BinaryArithmeticOperation, @mulexpr {
override string getOperator() { result = "*" }
override string getAPrimaryQlClass() { result = "MulExpr" }
override int getPrecedence() { result = 14 }
}
/**
* A C/C++ divide expression.
* ```
* c = a / b;
* ```
*/
class DivExpr extends BinaryArithmeticOperation, @divexpr {
override string getOperator() { result = "/" }
override string getAPrimaryQlClass() { result = "DivExpr" }
override int getPrecedence() { result = 14 }
}
/**
* A C/C++ remainder expression.
* ```
* c = a % b;
* ```
*/
class RemExpr extends BinaryArithmeticOperation, @remexpr {
override string getOperator() { result = "%" }
override string getAPrimaryQlClass() { result = "RemExpr" }
override int getPrecedence() { result = 14 }
}
/**
* A C/C++ multiply expression with an imaginary number. This is specific to
* C99 and later.
* ```
* double z;
* _Imaginary double x, y;
* z = x * y;
* ```
*/
class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
override string getOperator() { result = "*" }
override string getAPrimaryQlClass() { result = "ImaginaryMulExpr" }
override int getPrecedence() { result = 14 }
}
/**
* A C/C++ divide expression with an imaginary number. This is specific to
* C99 and later.
* ```
* double z;
* _Imaginary double y;
* z = z / y;
* ```
*/
class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
override string getOperator() { result = "/" }
override string getAPrimaryQlClass() { result = "ImaginaryDivExpr" }
override int getPrecedence() { result = 14 }
}
/**
* A C/C++ add expression with a real term and an imaginary term. This is
* specific to C99 and later.
* ```
* double z;
* _Imaginary double x;
* _Complex double w;
* w = z + x;
* ```
*/
class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "RealImaginaryAddExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ add expression with an imaginary term and a real term. This is
* specific to C99 and later.
* ```
* double z;
* _Imaginary double x;
* _Complex double w;
* w = x + z;
* ```
*/
class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "ImaginaryRealAddExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ subtract expression with a real term and an imaginary term. This is
* specific to C99 and later.
* ```
* double z;
* _Imaginary double x;
* _Complex double w;
* w = z - x;
* ```
*/
class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "RealImaginarySubExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ subtract expression with an imaginary term and a real term. This is
* specific to C99 and later.
* ```
* double z;
* _Imaginary double x;
* _Complex double w;
* w = x - z;
* ```
*/
class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "ImaginaryRealSubExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ GNU min expression.
* ```
* c = a <? b;
* ```
*/
class MinExpr extends BinaryArithmeticOperation, @minexpr {
override string getOperator() { result = "<?" }
override string getAPrimaryQlClass() { result = "MinExpr" }
}
/**
* A C/C++ GNU max expression.
* ```
* c = a >? b;
* ```
*/
class MaxExpr extends BinaryArithmeticOperation, @maxexpr {
override string getOperator() { result = ">?" }
override string getAPrimaryQlClass() { result = "MaxExpr" }
}
/**
* A C/C++ pointer arithmetic operation.
*/
class PointerArithmeticOperation extends BinaryArithmeticOperation, @p_arith_op_expr { }
/**
* A C/C++ pointer add expression.
* ```
* foo *ptr = &f[0];
* ptr = ptr + 2;
* ```
*/
class PointerAddExpr extends PointerArithmeticOperation, @paddexpr {
override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "PointerAddExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ pointer subtract expression.
* ```
* foo *ptr = &f[3];
* ptr = ptr - 2;
* ```
*/
class PointerSubExpr extends PointerArithmeticOperation, @psubexpr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "PointerSubExpr" }
override int getPrecedence() { result = 13 }
}
/**
* A C/C++ pointer difference expression.
* ```
* foo *start = &f[0], *end = &f[4];
* int size = end - size;
* ```
*/
class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "PointerDiffExpr" }
override int getPrecedence() { result = 13 }
}

View File

@@ -0,0 +1,248 @@
import semmle.code.cpp.exprs.Expr
import semmle.code.cpp.exprs.ArithmeticOperation
import semmle.code.cpp.exprs.BitwiseOperation
/**
* A non-overloaded binary assignment operation, including `=`, `+=`, `&=`,
* etc. A C++ overloaded assignment operation looks syntactically identical but is instead
* a `FunctionCall`.
*
* This is a QL base class for all (non-overloaded) assignments.
*/
class Assignment extends Operation, @assign_expr {
/** Gets the _lvalue_ of this assignment. */
Expr getLValue() { this.hasChild(result, 0) }
/** Gets the rvalue of this assignment. */
Expr getRValue() { this.hasChild(result, 1) }
override int getPrecedence() { result = 2 }
override predicate mayBeGloballyImpure() {
this.getRValue().mayBeGloballyImpure()
or
not exists(VariableAccess va, StackVariable v |
va = this.getLValue() and
v = va.getTarget() and
not va.getConversion+() instanceof ReferenceDereferenceExpr
)
}
}
/**
* A non-overloaded assignment operation with the operator `=`.
* ```
* a = b;
* ```
*/
class AssignExpr extends Assignment, @assignexpr {
override string getOperator() { result = "=" }
override string getAPrimaryQlClass() { result = "AssignExpr" }
/** Gets a textual representation of this assignment. */
override string toString() { result = "... = ..." }
}
/**
* A non-overloaded binary assignment operation other than `=`.
*/
class AssignOperation extends Assignment, @assign_op_expr {
override string toString() { result = "... " + this.getOperator() + " ..." }
}
/**
* A non-overloaded arithmetic assignment operation on a non-pointer _lvalue_:
* `+=`, `-=`, `*=`, `/=` and `%=`.
*/
class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { }
/**
* A non-overloaded `+=` assignment expression on a non-pointer _lvalue_.
* ```
* a += b;
* ```
*/
class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr {
override string getAPrimaryQlClass() { result = "AssignAddExpr" }
override string getOperator() { result = "+=" }
}
/**
* A non-overloaded `-=` assignment expression on a non-pointer _lvalue_.
* ```
* a -= b;
* ```
*/
class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr {
override string getAPrimaryQlClass() { result = "AssignSubExpr" }
override string getOperator() { result = "-=" }
}
/**
* A non-overloaded `*=` assignment expression.
* ```
* a *= b;
* ```
*/
class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr {
override string getAPrimaryQlClass() { result = "AssignMulExpr" }
override string getOperator() { result = "*=" }
}
/**
* A non-overloaded `/=` assignment expression.
* ```
* a /= b;
* ```
*/
class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr {
override string getAPrimaryQlClass() { result = "AssignDivExpr" }
override string getOperator() { result = "/=" }
}
/**
* A non-overloaded `%=` assignment expression.
* ```
* a %= b;
* ```
*/
class AssignRemExpr extends AssignArithmeticOperation, @assignremexpr {
override string getAPrimaryQlClass() { result = "AssignRemExpr" }
override string getOperator() { result = "%=" }
}
/**
* A non-overloaded bitwise assignment operation:
* `&=`, `|=`, `^=`, `<<=`, and `>>=`.
*/
class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { }
/**
* A non-overloaded AND (`&=`) assignment expression.
* ```
* a &= b;
* ```
*/
class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr {
override string getAPrimaryQlClass() { result = "AssignAndExpr" }
override string getOperator() { result = "&=" }
}
/**
* A non-overloaded OR (`|=`) assignment expression.
* ```
* a |= b;
* ```
*/
class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr {
override string getAPrimaryQlClass() { result = "AssignOrExpr" }
override string getOperator() { result = "|=" }
}
/**
* A non-overloaded XOR (`^=`) assignment expression.
* ```
* a ^= b;
* ```
*/
class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr {
override string getAPrimaryQlClass() { result = "AssignXorExpr" }
override string getOperator() { result = "^=" }
}
/**
* A non-overloaded `<<=` assignment expression.
* ```
* a <<= b;
* ```
*/
class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr {
override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
override string getOperator() { result = "<<=" }
}
/**
* A non-overloaded `>>=` assignment expression.
* ```
* a >>= b;
* ```
*/
class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr {
override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
override string getOperator() { result = ">>=" }
}
/**
* A non-overloaded `+=` pointer assignment expression.
* ```
* ptr += index;
* ```
*/
class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr {
override string getAPrimaryQlClass() { result = "AssignPointerAddExpr" }
override string getOperator() { result = "+=" }
}
/**
* A non-overloaded `-=` pointer assignment expression.
* ```
* ptr -= index;
* ```
*/
class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr {
override string getAPrimaryQlClass() { result = "AssignPointerSubExpr" }
override string getOperator() { result = "-=" }
}
/**
* A C++ variable declaration inside the conditional expression of a `while`, `if` or
* `for` compound statement. Declaring a variable this way narrows its lifetime and
* scope to be strictly the compound statement itself. For example:
* ```
* extern int x, y;
* if (bool c = x < y) { do_something_with(c); }
* // c is no longer in scope
* while (int d = x - y) { do_something_else_with(d); }
* // d is no longer is scope
* ```
*/
class ConditionDeclExpr extends Expr, @condition_decl {
/**
* DEPRECATED: Use `getVariableAccess()` or `getInitializingExpr()` instead.
*
* Gets the access using the condition for this declaration.
*/
deprecated Expr getExpr() { result = this.getChild(0) }
override string getAPrimaryQlClass() { result = "ConditionDeclExpr" }
/**
* Gets the compiler-generated variable access that conceptually occurs after
* the initialization of the declared variable.
*/
VariableAccess getVariableAccess() { result = this.getChild(0) }
/**
* Gets the expression that initializes the declared variable. This predicate
* always has a result.
*/
Expr getInitializingExpr() { result = this.getVariable().getInitializer().getExpr() }
/** Gets the variable that is declared. */
Variable getVariable() { condition_decl_bind(underlyingElement(this), unresolveElement(result)) }
override string toString() { result = "(condition decl)" }
}

View File

@@ -0,0 +1,100 @@
/**
* Provides classes for modeling bitwise operations such as `~`, `<<`, `&` and
* `|`.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C/C++ unary bitwise operation.
*/
class UnaryBitwiseOperation extends UnaryOperation, @un_bitwise_op_expr { }
/**
* A C/C++ complement expression.
* ```
* unsigned c = ~a;
* ```
*/
class ComplementExpr extends UnaryBitwiseOperation, @complementexpr {
override string getOperator() { result = "~" }
override int getPrecedence() { result = 16 }
override string getAPrimaryQlClass() { result = "ComplementExpr" }
}
/**
* A C/C++ binary bitwise operation.
*/
class BinaryBitwiseOperation extends BinaryOperation, @bin_bitwise_op_expr { }
/**
* A C/C++ left shift expression.
* ```
* unsigned c = a << b;
* ```
*/
class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr {
override string getOperator() { result = "<<" }
override int getPrecedence() { result = 12 }
override string getAPrimaryQlClass() { result = "LShiftExpr" }
}
/**
* A C/C++ right shift expression.
* ```
* unsigned c = a >> b;
* ```
*/
class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr {
override string getOperator() { result = ">>" }
override int getPrecedence() { result = 12 }
override string getAPrimaryQlClass() { result = "RShiftExpr" }
}
/**
* A C/C++ bitwise AND expression.
* ```
* unsigned c = a & b;
* ```
*/
class BitwiseAndExpr extends BinaryBitwiseOperation, @andexpr {
override string getOperator() { result = "&" }
override int getPrecedence() { result = 8 }
override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
}
/**
* A C/C++ bitwise OR expression.
* ```
* unsigned c = a | b;
* ```
*/
class BitwiseOrExpr extends BinaryBitwiseOperation, @orexpr {
override string getOperator() { result = "|" }
override int getPrecedence() { result = 6 }
override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
}
/**
* A C/C++ bitwise XOR expression.
* ```
* unsigned c = a ^ b;
* ```
*/
class BitwiseXorExpr extends BinaryBitwiseOperation, @xorexpr {
override string getOperator() { result = "^" }
override int getPrecedence() { result = 7 }
override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
}

View File

@@ -0,0 +1,990 @@
/**
* Provides classes for modeling built-in operations. Built-in operations are
* typically compiler specific and are used by libraries and generated code.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C/C++ built-in operation. This is the root QL class encompassing
* built-in functionality.
*/
class BuiltInOperation extends Expr, @builtin_op {
override string getAPrimaryQlClass() { result = "BuiltInOperation" }
}
/**
* A C/C++ built-in operation that is used to support functions with variable numbers of arguments.
* This includes `va_start`, `va_end`, `va_copy`, and `va_arg`.
*/
class VarArgsExpr extends BuiltInOperation, @var_args_expr { }
/**
* A C/C++ `__builtin_va_start` built-in operation (used by some
* implementations of `va_start`).
* ```
* __builtin_va_list ap;
* __builtin_va_start(ap, last_named_param);
* ```
*/
class BuiltInVarArgsStart extends VarArgsExpr, @vastartexpr {
override string toString() { result = "__builtin_va_start" }
override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" }
/**
* Gets the `va_list` argument.
*/
final Expr getVAList() { result = getChild(0) }
/**
* Gets the argument that specifies the last named parameter before the ellipsis.
*/
final VariableAccess getLastNamedParameter() { result = getChild(1) }
}
/**
* A C/C++ `__builtin_va_end` built-in operation (used by some implementations
* of `va_end`).
* ```
* __builtin_va_start(ap, last_named_param);
* ap = __builtin_va_arg(ap, long);
* __builtin_va_end(ap);
* ```
*/
class BuiltInVarArgsEnd extends VarArgsExpr, @vaendexpr {
override string toString() { result = "__builtin_va_end" }
override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" }
/**
* Gets the `va_list` argument.
*/
final Expr getVAList() { result = getChild(0) }
}
/**
* A C/C++ `__builtin_va_arg` built-in operation (used by some implementations
* of `va_arg`).
* ```
* ap = __builtin_va_arg(ap, long);
* ```
*/
class BuiltInVarArg extends VarArgsExpr, @vaargexpr {
override string toString() { result = "__builtin_va_arg" }
override string getAPrimaryQlClass() { result = "BuiltInVarArg" }
/**
* Gets the `va_list` argument.
*/
final Expr getVAList() { result = getChild(0) }
}
/**
* A C/C++ `__builtin_va_copy` built-in operation (used by some implementations
* of `va_copy`).
* ```
* va_list ap, aq;
* __builtin_va_start(ap, last_named_param);
* va_copy(aq, ap);
* ```
*/
class BuiltInVarArgCopy extends VarArgsExpr, @vacopyexpr {
override string toString() { result = "__builtin_va_copy" }
override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" }
/**
* Gets the destination `va_list` argument.
*/
final Expr getDestinationVAList() { result = getChild(0) }
/**
* Gets the the source `va_list` argument.
*/
final Expr getSourceVAList() { result = getChild(1) }
}
/**
* A Microsoft C/C++ `__noop` expression, which does nothing.
* ```
* __noop;
* ```
*/
class BuiltInNoOp extends BuiltInOperation, @noopexpr {
override string toString() { result = "__noop" }
override string getAPrimaryQlClass() { result = "BuiltInNoOp" }
}
/**
* DEPRECATED: Use `BuiltInOperationBuiltInOffsetOf` instead.
*/
deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf;
/**
* A C/C++ `__builtin_offsetof` built-in operation (used by some implementations
* of `offsetof`). The operation retains its semantics even in the presence
* of an overloaded `operator &`). This is a GNU/Clang extension.
* ```
* struct S {
* int a, b;
* };
* int d = __builtin_offsetof(struct S, b); // usually 4
* ```
*/
class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr {
override string toString() { result = "__builtin_offsetof" }
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInOffsetOf" }
}
/**
* A C/C++ `__INTADDR__` built-in operation (used by some implementations
* of `offsetof`). The operation retains its semantics even in the presence
* of an overloaded `operator &`). This is an EDG extension.
* ```
* struct S {
* int a, b;
* };
* int d = __INTADDR__(struct S, b); // usually 4
* ```
*/
class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr {
override string toString() { result = "__INTADDR__" }
override string getAPrimaryQlClass() { result = "BuiltInIntAddr" }
}
/**
* A C++ `__has_assign` built-in operation (used by some implementations of
* the `<type_traits>` header).
*
* Returns `true` if the type has a copy assignment operator.
* ```
* bool v = __has_assign(MyType);
* ```
*/
class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr {
override string toString() { result = "__has_assign" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasAssign" }
}
/**
* A C++ `__has_copy` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the type has a copy constructor.
* ```
* std::integral_constant< bool, __has_copy(_Tp)> hc;
* ```
*/
class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr {
override string toString() { result = "__has_copy" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasCopy" }
}
/**
* A C++ `__has_nothrow_assign` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if a copy assignment operator has an empty exception
* specification.
* ```
* std::integral_constant< bool, __has_nothrow_assign(_Tp)> hnta;
* ```
*/
class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign {
override string toString() { result = "__has_nothrow_assign" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowAssign" }
}
/**
* A C++ `__has_nothrow_constructor` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the default constructor has an empty exception
* specification.
* ```
* bool v = __has_nothrow_constructor(MyType);
* ```
*/
class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothrowconstr {
override string toString() { result = "__has_nothrow_constructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowConstructor" }
}
/**
* A C++ `__has_nothrow_copy` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the copy constructor has an empty exception specification.
* ```
* std::integral_constant< bool, __has_nothrow_copy(MyType) >;
* ```
*/
class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy {
override string toString() { result = "__has_nothrow_copy" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowCopy" }
}
/**
* A C++ `__has_trivial_assign` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the type has a trivial assignment
* operator (`operator =`).
* ```
* bool v = __has_trivial_assign(MyType);
* ```
*/
class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassign {
override string toString() { result = "__has_trivial_assign" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialAssign" }
}
/**
* A C++ `__has_trivial_constructor` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type has a trivial constructor.
* ```
* bool v = __has_trivial_constructor(MyType);
* ```
*/
class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivialconstr {
override string toString() { result = "__has_trivial_constructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialConstructor" }
}
/**
* A C++ `__has_trivial_copy` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns true if the type has a trivial copy constructor.
* ```
* std::integral_constant< bool, __has_trivial_copy(MyType) > htc;
* ```
*/
class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy {
override string toString() { result = "__has_trivial_copy" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialCopy" }
}
/**
* A C++ `__has_trivial_destructor` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type has a trivial destructor.
* ```
* bool v = __has_trivial_destructor(MyType);
* ```
*/
class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivialdestructor {
override string toString() { result = "__has_trivial_destructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialDestructor" }
}
/**
* A C++ `__has_user_destructor` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns true if the type has a user-declared destructor.
* ```
* bool v = __has_user_destructor(MyType);
* ```
*/
class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr {
override string toString() { result = "__has_user_destructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasUserDestructor" }
}
/**
* A C++ `__has_virtual_destructor` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type has a virtual destructor.
* ```
* template<typename _Tp>
* struct has_virtual_destructor
* : public integral_constant<bool, __has_virtual_destructor(_Tp)>
* { };
* ```
*/
class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtualdestr {
override string toString() { result = "__has_virtual_destructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasVirtualDestructor" }
}
/**
* A C++ `__is_abstract` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the class has at least one pure virtual function.
* ```
* bool v = __is_abstract(MyType);
* ```
*/
class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr {
override string toString() { result = "__is_abstract" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAbstract" }
}
/**
* A C++ `__is_base_of` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the first type is a base class of the second type, of if both types are the same.
* ```
* bool v = __is_base_of(MyType, OtherType);
* ```
*/
class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr {
override string toString() { result = "__is_base_of" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsBaseOf" }
}
/**
* A C++ `__is_class` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the type is a `class` or a `struct`.
* ```
* bool v = __is_class(MyType);
* ```
*/
class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr {
override string toString() { result = "__is_class" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsClass" }
}
/**
* A C++ `__is_convertible_to` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the first type can be converted to the second type.
* ```
* bool v = __is_convertible_to(MyType, OtherType);
* ```
*/
class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr {
override string toString() { result = "__is_convertible_to" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" }
}
/**
* A C++ `__is_empty` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the type has no instance data members.
* ```
* bool v = __is_empty(MyType);
* ```
*/
class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr {
override string toString() { result = "__is_empty" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsEmpty" }
}
/**
* A C++ `__is_enum` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns true if the type is an `enum`.
* ```
* bool v = __is_enum(MyType);
* ```
*/
class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr {
override string toString() { result = "__is_enum" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsEnum" }
}
/**
* A C++ `__is_pod` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the type is a `class`, `struct` or `union`, WITHOUT
* (1) constructors, (2) private or protected non-static members, (3) base
* classes, or (4) virtual functions.
* ```
* bool v = __is_pod(MyType);
* ```
*/
class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr {
override string toString() { result = "__is_pod" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsPod" }
}
/**
* A C++ `__is_polymorphic` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the type has at least one virtual function.
* ```
* bool v = __is_polymorphic(MyType);
* ```
*/
class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr {
override string toString() { result = "__is_polymorphic" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsPolymorphic" }
}
/**
* A C++ `__is_union` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the type is a `union`.
* ```
* bool v = __is_union(MyType);
* ```
*/
class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr {
override string toString() { result = "__is_union" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" }
}
/**
* DEPRECATED: Use `BuiltInOperationBuiltInTypesCompatibleP` instead.
*/
deprecated class BuiltInOperationBuiltInTypes = BuiltInOperationBuiltInTypesCompatibleP;
/**
* A C++ `__builtin_types_compatible_p` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the two types are the same (modulo qualifiers).
* ```
* template<typename _Tp1, typename _Tp2>
* struct types_compatible
* : public integral_constant<bool, __builtin_types_compatible_p(_Tp1, _Tp2) >
* { };
* ```
*/
class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typescompexpr {
override string toString() { result = "__builtin_types_compatible_p" }
}
/**
* A clang `__builtin_shufflevector` expression.
*
* It outputs a permutation of elements from one or two input vectors.
* Please see
* https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#langext-builtin-shufflevector
* for more information.
* ```
* // Concatenate every other element of 4-element vectors V1 and V2.
* V3 = __builtin_shufflevector(V1, V2, 0, 2, 4, 6);
* ```
*/
class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshufflevector {
override string toString() { result = "__builtin_shufflevector" }
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" }
}
/**
* A clang `__builtin_convertvector` expression.
*
* Allows for conversion of vectors of equal element count and compatible
* element types. Please see
* https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#builtin-convertvector
* for more information.
* ```
* float vf __attribute__((__vector_size__(16)));
* typedef double vector4double __attribute__((__vector_size__(32)));
* // convert from a vector of 4 floats to a vector of 4 doubles.
* vector4double vd = __builtin_convertvector(vf, vector4double);
* ```
*/
class BuiltInOperationBuiltInConvertVector extends BuiltInOperation, @builtinconvertvector {
override string toString() { result = "__builtin_convertvector" }
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInConvertVector" }
}
/**
* A clang `__builtin_addressof` function (can be used to implement C++'s
* `std::addressof`).
*
* This function disregards any overloads created for `operator &`.
* ```
* int a = 1;
* int *b = __builtin_addressof(a);
* ```
*/
class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation, @builtinaddressof {
/** Gets the function or variable whose address is taken. */
Declaration getAddressable() {
result = this.getOperand().(Access).getTarget()
or
// this handles the case where we are taking the address of a reference variable
result = this.getOperand().(ReferenceDereferenceExpr).getChild(0).(Access).getTarget()
}
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInAddressOf" }
override string getOperator() { result = "__builtin_addressof" }
}
/**
* The `__is_trivially_constructible` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type has a trivial default
* constructor, copy constructor or move constructor.
* ```
* template<typename T, typename... Args>
* struct is_trivially_constructible
* : public integral_constant<bool, __is_trivially_constructible(T, Args...) >
* { };
* ```
*/
class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation,
@istriviallyconstructibleexpr {
override string toString() { result = "__is_trivially_constructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" }
}
/**
* The `__is_destructible` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the type's destructor is not `delete`d and is accessible
* in derived `class`es, and whose base `class` and all non-static data members
* are also destructible.
* ```
* bool v = __is_destructible(MyType);
* ```
*/
class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleexpr {
override string toString() { result = "__is_destructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsDestructible" }
}
/**
* The `__is_nothrow_destructible` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type is destructible and whose destructor, and those
* of member data and any super`class`es all have an empty exception
* specification.
* ```
* bool v = __is_nothrow_destructible(MyType);
* ```
*/
class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrowdestructibleexpr {
override string toString() { result = "__is_nothrow_destructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowDestructible" }
}
/**
* The `__is_trivially_destructible` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type is destructible and whose destructor, and those
* of member data and any superclasses are all trivial.
* ```
* bool v = __is_trivially_destructible(MyType);
* ```
*/
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr {
override string toString() { result = "__is_trivially_destructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" }
}
/**
* The `__is_trivially_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the assignment operator `C::operator =(const C& c)` is
* trivial.
* ```
* template<typename T>
* struct is_trivially_assignable
* : public integral_constant<bool, __is_trivially_assignable(T) >
* { };
* ```
*/
class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr {
override string toString() { result = "__is_trivially_assignable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyAssignable" }
}
/**
* The `__is_nothrow_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns true if there exists a `C::operator =(const C& c) nothrow`
* assignment operator (i.e, with an empty exception specification).
* ```
* bool v = __is_nothrow_assignable(MyType);
* ```
*/
class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr {
override string toString() { result = "__is_nothrow_assignable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" }
}
/**
* The `__is_standard_layout` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the type is a primitive type, or a `class`, `struct` or
* `union` WITHOUT (1) virtual functions or base classes, (2) reference member
* variable or (3) multiple occurrences of base `class` objects, among other
* restrictions. Please see
* https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
* for more information.
* ```
* bool v = __is_standard_layout(MyType);
* ```
*/
class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayoutexpr {
override string toString() { result = "__is_standard_layout" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsStandardLayout" }
}
/**
* The `__is_trivially_copyable` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if instances of this type can be copied by trivial
* means. The copying is done in a manner similar to the `memcpy`
* function.
*/
class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr {
override string toString() { result = "__is_trivially_copyable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" }
}
/**
* The `__is_literal_type` built-in operation (used by some implementations of
* the `<type_traits>` header).
*
* Returns `true` if the type is a scalar type, a reference type or an array of
* literal types, among others. Please see
* https://en.cppreference.com/w/cpp/named_req/LiteralType
* for more information.
*
* ```
* template <typename _Tp>
* std::integral_constant< bool, __is_literal_type(_Tp)> ilt;
* ```
*/
class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr {
override string toString() { result = "__is_literal_type" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsLiteralType" }
}
/**
* The `__has_trivial_move_constructor` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns true if the move (`&&`) constructor can be generated by the
* compiler, with semantics of the `memcpy` operation.
* ```
* template <typename _Tp>
* std::integral_constant< bool, __has_trivial_move_constructor(_Tp)> htmc;
* ```
*/
class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
@hastrivialmoveconstructorexpr {
override string toString() { result = "__has_trivial_move_constructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" }
}
/**
* The `__has_trivial_move_assign` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns if the move-assign operator `C::operator =(C &&c)` is trivial.
* ```
* template<typename T>
* struct has_trivial_move_assign
* : public integral_constant<bool, __has_trivial_move_assign(T) >
* { };
* ```
*/
class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivialmoveassignexpr {
override string toString() { result = "__has_trivial_move_assign" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveAssign" }
}
/**
* The `__has_nothrow_move_assign` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type has a `C::operator=(C&& c) nothrow`, that is,
* an assignment operator with an empty exception specification.
* ```
* bool v = __has_nothrow_move_assign(MyType);
* ```
*/
class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrowmoveassignexpr {
override string toString() { result = "__has_nothrow_move_assign" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNothrowMoveAssign" }
}
/**
* The `__is_constructible` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the type can be constructed using specified arguments
* (or none).
* ```
* template<typename T, typename... Args>
* struct is_constructible
* : public integral_constant<bool, __is_constructible(T, Args...) >
* { };
* ```
*/
class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructibleexpr {
override string toString() { result = "__is_constructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConstructible" }
}
/**
* The `__is_nothrow_constructible` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type is constructable and all its constructors have an
* empty exception specification (i.e., are declared with `nothrow`);
* ```
* bool v = __is_nothrow_constructible(MyType);
* ```
*/
class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothrowconstructibleexpr {
override string toString() { result = "__is_nothrow_constructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConstructible" }
}
/**
* The `__has_finalizer` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the type defines a _finalizer_ `C::!C(void)`, to be called
* from either the regular destructor or the garbage collector.
* ```
* bool v = __has_finalizer(MyType);
* ```
*/
class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr {
override string toString() { result = "__has_finalizer" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasFinalizer" }
}
/**
* The `__is_delegate` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the function has been declared as a `delegate`, used in
* message forwarding. Please see
* https://docs.microsoft.com/en-us/cpp/extensions/delegate-cpp-component-extensions
* for more information.
*/
class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr {
override string toString() { result = "__is_delegate" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsDelegate" }
}
/**
* The `__is_interface_class` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the type has been declared as an `interface`. Please see
* https://docs.microsoft.com/en-us/cpp/extensions/interface-class-cpp-component-extensions
* for more information.
*/
class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfaceclassexpr {
override string toString() { result = "__is_interface_class" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsInterfaceClass" }
}
/**
* The `__is_ref_array` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the object passed in is a _platform array_. Please see
* https://docs.microsoft.com/en-us/cpp/extensions/arrays-cpp-component-extensions
* for more information.
* ```
* array<int>^ x = gcnew array<int>(10);
* bool b = __is_ref_array(array<int>);
* ```
*/
class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr {
override string toString() { result = "__is_ref_array" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefArray" }
}
/**
* The `__is_ref_class` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the type is a _reference class_. Please see
* https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions
* for more information.
* ```
* ref class R {};
* bool b = __is_ref_class(R);
* ```
*/
class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr {
override string toString() { result = "__is_ref_class" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefClass" }
}
/**
* The `__is_sealed` built-in operation. This is a Microsoft extension.
*
* Returns `true` if a given class or virtual function is marked as `sealed`,
* meaning that it cannot be extended or overridden. The `sealed` keyword
* is similar to the C++11 `final` keyword.
* ```
* ref class X sealed {
* virtual void f() sealed { }
* };
* ```
*/
class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr {
override string toString() { result = "__is_sealed" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSealed" }
}
/**
* The `__is_simple_value_class` built-in operation. This is a Microsoft extension.
*
* Returns `true` if passed a value type that contains no references to the
* garbage-collected heap.
* ```
* ref class R {}; // __is_simple_value_class(R) == false
* value struct V {}; // __is_simple_value_class(V) == true
* value struct V2 { // __is_simple_value_class(V2) == false
* R ^ r; // not a simple value type
* };
* ```
*/
class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalueclassexpr {
override string toString() { result = "__is_simple_value_class" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSimpleValueClass" }
}
/**
* The `__is_value_class` built-in operation. This is a Microsoft extension.
*
* Returns `true` if passed a value type. Please see
* https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions
* For more information.
* ```
* value struct V {};
* bool v = __is_value_class(V);
* ```
*/
class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr {
override string toString() { result = "__is_value_class" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsValueClass" }
}
/**
* The `__is_final` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the `class` has been marked with the `final` specifier.
* ```
* template<typename T>
* struct is_final
* : public integral_constant<bool, __is_final(T) >
* { };
* ```
*/
class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr {
override string toString() { result = "__is_final" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsFinal" }
}
/**
* The `__builtin_choose_expr` expression. This is a GNU/Clang extension.
*
* The expression functions similarly to the ternary `?:` operator, except
* that it is evaluated at compile-time.
* ```
* int sz = __builtin_choose_expr(__builtin_types_compatible_p(int, long), 4, 8);
* ```
*/
class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr {
override string toString() { result = "__builtin_choose_expr" }
override string getAPrimaryQlClass() { result = "BuiltInChooseExpr" }
}
/**
* Fill operation on a vector. This is a GNU extension.
*
* A single scalar value is used to populate all the elements in a vector.
* In the example below, the scalar value is `25`:
* ```
* typedef int v16i __attribute__((vector_size(16)));
* v16i src, dst;
* dst = src << 25;
* ```
*/
class VectorFillOperation extends UnaryOperation, @vec_fill {
override string getOperator() { result = "(vector fill)" }
override string getAPrimaryQlClass() { result = "VectorFillOperation" }
}
/**
* The GNU `__builtin_complex` operation.
*/
class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex {
override string toString() { result = "__builtin_complex" }
override string getAPrimaryQlClass() { result = "BuiltInComplexOperation" }
/** Gets the operand corresponding to the real part of the complex number. */
Expr getRealOperand() { this.hasChild(result, 0) }
/** Gets the operand corresponding to the imaginary part of the complex number. */
Expr getImaginaryOperand() { this.hasChild(result, 1) }
}

View File

@@ -0,0 +1,665 @@
/**
* Provides classes for modeling call expressions including direct calls to
* functions, constructor and destructor calls, and calls made through function
* pointers.
*/
import semmle.code.cpp.exprs.Expr
import semmle.code.cpp.Function
private import semmle.code.cpp.dataflow.EscapesTree
private class TCall = @funbindexpr or @callexpr;
/**
* A C/C++ call.
*/
class Call extends Expr, NameQualifiableElement, TCall {
// `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes
// `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to
// that function. That's why the charpred for `FunctionCall` requires:
// ```
// iscall(underlyingElement(this), _)
// ```
// So for the charpred for `Call` we include the requirement that if this is an instance of
// `@funbindexpr` it must be a _call_ to the function.
Call() { this instanceof @callexpr or iscall(underlyingElement(this), _) }
/**
* Gets the number of arguments (actual parameters) of this call. The count
* does _not_ include the qualifier of the call, if any.
*/
int getNumberOfArguments() { result = count(this.getAnArgument()) }
/**
* Holds if this call has a qualifier.
*
* For example, `ptr->f()` has a qualifier, whereas plain `f()` does not.
*/
predicate hasQualifier() { exists(Expr e | this.getChild(-1) = e) }
/**
* Gets the expression to the left of the function name or function pointer variable name.
*
* As a few examples:
* For the call to `f` in `ptr->f()`, this gives `ptr`.
* For the call to `f` in `(*ptr).f()`, this gives `(*ptr)`.
*/
Expr getQualifier() { result = this.getChild(-1) }
/**
* Gets an argument for this call. To get the qualifier of this call, if
* any, use `getQualifier()`.
*/
Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 0) }
/**
* Gets the nth argument for this call.
*
* The range of `n` is from `0` to `getNumberOfArguments() - 1`. To get the
* qualifier of this call, if any, use `getQualifier()`.
*/
Expr getArgument(int n) { result = this.getChild(n) and n >= 0 }
/**
* Gets a subexpression of the argument at position `index`. If the
* argument itself contains calls, such calls will be considered
* leaves in the expression tree. The qualifier of the call, if any, is not
* considered to be an argument.
*
* Example: the call `f(2, 3 + 4, g(4 + 5))` has sub expression(s)
* `2` at index 0; `3`, `4`, and `3 + 4` at index 1; and `g(4 + 5)`
* at index 2, respectively.
*/
Expr getAnArgumentSubExpr(int index) {
result = getArgument(index)
or
exists(Expr mid |
mid = getAnArgumentSubExpr(index) and
not mid instanceof Call and
not mid instanceof SizeofOperator and
result = mid.getAChild()
)
}
/**
* Gets the target of the call, as best as makes sense for this kind of call.
* The precise meaning depends on the kind of call it is:
* - For a call to a function, it's the function being called.
* - For a C++ method call, it's the statically resolved method.
* - For an Objective C message expression, it's the statically resolved
* method, and it might not exist.
* - For a variable call, it never exists.
*/
Function getTarget() { none() } // overridden in subclasses
override int getPrecedence() { result = 17 }
override string toString() { none() }
/**
* Holds if this call passes the variable accessed by `va` by
* reference as the `i`th argument. The qualifier of a call to a member
* function is `i = -1`.
*
* A variable is passed by reference if the `i`th parameter of the function
* receives an address that points within the object denoted by `va`. For a
* variable named `x`, passing by reference includes both explicit pointers
* (`&x`) and implicit conversion to a C++ reference (`x`), but it also
* includes deeper expressions such as `&x[0] + length` or `&*&*&x`.
*
* When `Field`s are involved, an argument `i` may pass more than one
* variable by reference simultaneously. For example, the call `f(&x.m1.m2)`
* counts as passing both `x`, `m1` and `m2` to argument 0 of `f`.
*
* This predicate holds for variables passed by reference even if they are
* passed as references to `const` and thus cannot be changed through that
* reference. See `passesByNonConstReference` for a predicate that only holds
* for variables passed by reference to non-const.
*/
predicate passesByReference(int i, VariableAccess va) {
variableAddressEscapesTree(va, this.getArgument(i).getFullyConverted())
or
variableAddressEscapesTree(va, this.getQualifier().getFullyConverted()) and
i = -1
}
/**
* Holds if this call passes the variable accessed by `va` by
* reference to non-const data as the `i`th argument. The qualifier of a
* call to a member function is `i = -1`.
*
* A variable is passed by reference if the `i`th parameter of the function
* receives an address that points within the object denoted by `va`. For a
* variable named `x`, passing by reference includes both explicit pointers
* (`&x`) and implicit conversion to a C++ reference (`x`), but it also
* includes deeper expressions such as `&x[0] + length` or `&*&*&x`.
*
* When `Field`s are involved, an argument `i` may pass more than one
* variable by reference simultaneously. For example, the call `f(&x.m1.m2)`
* counts as passing both `x`, `m1` and `m2` to argument 0 of `f`.
*
* This predicate only holds for variables passed by reference to non-const
* data and thus can be changed through that reference. See
* `passesByReference` for a predicate that also holds for variables passed
* by reference to const.
*/
predicate passesByReferenceNonConst(int i, VariableAccess va) {
variableAddressEscapesTreeNonConst(va, this.getArgument(i).getFullyConverted())
or
variableAddressEscapesTreeNonConst(va, this.getQualifier().getFullyConverted()) and
i = -1
}
}
/**
* A C/C++ function call where the name of the target function is known at compile-time.
*
* This includes various kinds of call:
* 1. Calls such as `f(x)` where `f` is the name of a function.
* 2. Calls such as `ptr->f()` where `f` is the name of a (possibly virtual) member function.
* 3. Constructor calls for stack-allocated objects.
* 4. Implicit and explicit calls to user-defined operators.
* 5. Base class initializers in constructors.
*/
class FunctionCall extends Call, @funbindexpr {
FunctionCall() { iscall(underlyingElement(this), _) }
override string getAPrimaryQlClass() { result = "FunctionCall" }
/** Gets an explicit template argument for this call. */
Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
/** Gets an explicit template argument value for this call. */
Locatable getAnExplicitTemplateArgumentKind() { result = getExplicitTemplateArgumentKind(_) }
/** Gets a template argument for this call. */
Locatable getATemplateArgument() { result = getTarget().getATemplateArgument() }
/** Gets a template argument value for this call. */
Locatable getATemplateArgumentKind() { result = getTarget().getATemplateArgumentKind() }
/** Gets the nth explicit template argument for this call. */
Locatable getExplicitTemplateArgument(int n) {
n < getNumberOfExplicitTemplateArguments() and
result = getTemplateArgument(n)
}
/** Gets the nth explicit template argument value for this call. */
Locatable getExplicitTemplateArgumentKind(int n) {
n < getNumberOfExplicitTemplateArguments() and
result = getTemplateArgumentKind(n)
}
/** Gets the number of explicit template arguments for this call. */
int getNumberOfExplicitTemplateArguments() {
if numtemplatearguments(underlyingElement(this), _)
then numtemplatearguments(underlyingElement(this), result)
else result = 0
}
/** Gets the number of template arguments for this call. */
int getNumberOfTemplateArguments() { result = count(int i | exists(getTemplateArgument(i))) }
/** Gets the nth template argument for this call (indexed from 0). */
Locatable getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
/** Gets the nth template argument value for this call (indexed from 0). */
Locatable getTemplateArgumentKind(int n) { result = getTarget().getTemplateArgumentKind(n) }
/** Holds if any template arguments for this call are implicit / deduced. */
predicate hasImplicitTemplateArguments() {
exists(int i |
exists(getTemplateArgument(i)) and
not exists(getExplicitTemplateArgument(i))
)
}
/** Holds if a template argument list was provided for this call. */
predicate hasTemplateArgumentList() { numtemplatearguments(underlyingElement(this), _) }
/**
* Gets the `RoutineType` of the call target as visible at the call site. For
* constructor calls, this predicate instead gets the `Class` of the constructor
* being called.
*/
Type getTargetType() { result = Call.super.getType().stripType() }
/**
* Gets the expected return type of the function called by this call.
*
* In most cases, the expected return type will be the return type of the function being called.
* It is only different when the function being called is ambiguously declared, at which point
* the expected return type is the return type of the (unambiguous) function declaration that was
* visible at the call site.
*/
Type getExpectedReturnType() {
if getTargetType() instanceof RoutineType
then result = getTargetType().(RoutineType).getReturnType()
else result = getTarget().getType()
}
/**
* Gets the expected type of the nth parameter of the function called by this call.
*
* In most cases, the expected parameter types match the parameter types of the function being called.
* They are only different when the function being called is ambiguously declared, at which point
* the expected parameter types are the parameter types of the (unambiguous) function declaration that
* was visible at the call site.
*/
Type getExpectedParameterType(int n) {
if getTargetType() instanceof RoutineType
then result = getTargetType().(RoutineType).getParameterType(n)
else result = getTarget().getParameter(n).getType()
}
/**
* Gets the function called by this call.
*
* In the case of virtual function calls, the result is the most-specific function in the override tree (as
* determined by the compiler) such that the target at runtime will be one of `result.getAnOverridingFunction*()`.
*/
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
/**
* Gets the type of this expression, that is, the return type of the function being called.
*/
override Type getType() { result = getExpectedReturnType() }
/**
* Holds if this is a call to a virtual function.
*
* Note that this holds even in cases where a sufficiently clever compiler could perform static dispatch.
*/
predicate isVirtual() { iscall(underlyingElement(this), 1) }
/**
* Holds if the target of this function call was found by argument-dependent lookup and wouldn't have been
* found by any other means.
*/
predicate isOnlyFoundByADL() { iscall(underlyingElement(this), 2) }
/** Gets a textual representation of this function call. */
override string toString() {
if exists(getTarget())
then result = "call to " + this.getTarget().getName()
else result = "call to unknown function"
}
override predicate mayBeImpure() {
this.getChild(_).mayBeImpure() or
this.getTarget().mayHaveSideEffects() or
isVirtual() or
getTarget().getAnAttribute().getName() = "weak"
}
override predicate mayBeGloballyImpure() {
this.getChild(_).mayBeGloballyImpure() or
this.getTarget().mayHaveSideEffects() or
isVirtual() or
getTarget().getAnAttribute().getName() = "weak"
}
}
/** A _user-defined_ unary `operator*` function. */
class OverloadedPointerDereferenceFunction extends Function {
OverloadedPointerDereferenceFunction() {
this.hasName("operator*") and
this.getEffectiveNumberOfParameters() = 1
}
}
/**
* An instance of a _user-defined_ unary `operator*` applied to its argument.
* ```
* T1 operator*(const T2 &);
* T1 a; T2 b;
* a = *b;
* ```
*/
class OverloadedPointerDereferenceExpr extends FunctionCall {
OverloadedPointerDereferenceExpr() {
this.getTarget() instanceof OverloadedPointerDereferenceFunction
}
override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" }
/**
* Gets the expression this operator * applies to.
*/
Expr getExpr() {
result = this.getChild(0) or
result = this.getQualifier()
}
override predicate mayBeImpure() {
FunctionCall.super.mayBeImpure() and
(
this.getExpr().mayBeImpure()
or
not exists(Class declaring |
this.getTarget().getDeclaringType().isConstructedFrom*(declaring)
|
declaring.getNamespace() instanceof StdNamespace
)
)
}
override predicate mayBeGloballyImpure() {
FunctionCall.super.mayBeGloballyImpure() and
(
this.getExpr().mayBeGloballyImpure()
or
not exists(Class declaring |
this.getTarget().getDeclaringType().isConstructedFrom*(declaring)
|
declaring.getNamespace() instanceof StdNamespace
)
)
}
}
/**
* An instance of a _user-defined_ binary `operator[]` applied to its arguments.
* ```
* struct T2 { T1 operator[](const T3 &); };
* T1 a; T2 b; T3 c;
* a = b[c];
* ```
*/
class OverloadedArrayExpr extends FunctionCall {
OverloadedArrayExpr() { getTarget().hasName("operator[]") }
override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" }
/**
* Gets the expression being subscripted.
*/
Expr getArrayBase() {
if exists(this.getQualifier()) then result = this.getQualifier() else result = this.getChild(0)
}
/**
* Gets the expression giving the index.
*/
Expr getArrayOffset() {
if exists(this.getQualifier()) then result = this.getChild(0) else result = this.getChild(1)
}
}
/**
* A C/C++ call which is performed through a function pointer.
*
* In the call below, `(*funcptr)` may be simplified to just `funcptr`.
* ```
* extern int (*funcptr)(int a, int b);
* int c = (*funcptr)(1, 2);
* ```
*/
class ExprCall extends Call, @callexpr {
/**
* Gets the expression which yields the function pointer to call.
*/
Expr getExpr() { result = this.getChild(0) }
override string getAPrimaryQlClass() { result = "ExprCall" }
override Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 1) }
override Expr getArgument(int index) {
result = this.getChild(index + 1) and index in [0 .. this.getNumChild() - 2]
}
override string toString() { result = "call to expression" }
override Function getTarget() { none() }
}
/**
* A C/C++ call which is performed through a variable of function pointer type.
* ```
* int call_via_ptr(int (*pfn)(int)) {
* return pfn(5);
* }
* ```
*/
class VariableCall extends ExprCall {
VariableCall() { this.getExpr() instanceof VariableAccess }
override string getAPrimaryQlClass() { result = "VariableCall" }
/**
* Gets the variable which yields the function pointer to call.
*/
Variable getVariable() { this.getExpr().(VariableAccess).getTarget() = result }
}
/**
* A call to a constructor.
* ```
* struct S { S(void) {} };
* S s;
* ```
*/
class ConstructorCall extends FunctionCall {
ConstructorCall() { super.getTarget() instanceof Constructor }
override string getAPrimaryQlClass() { result = "ConstructorCall" }
/** Gets the constructor being called. */
override Constructor getTarget() { result = super.getTarget() }
}
/**
* A call to a destructor.
* ```
* struct S { ~S(void) {} } *s;
* s->~S();
* ```
*/
class DestructorCall extends FunctionCall {
DestructorCall() { super.getTarget() instanceof Destructor }
override string getAPrimaryQlClass() { result = "DestructorCall" }
/** Gets the destructor being called. */
override Destructor getTarget() { result = super.getTarget() }
}
/**
* An expression that looks like a destructor call, but has no effect.
*
* For example, given a plain old data type `pod_t`, the syntax `ptr->~pod_t()` is
* a vacuous destructor call, as `~pod_t` isn't actually a function. This can also
* occur in instantiated templates, as `ptr->~T()` becomes vacuous when `T` is `int`.
* ```
* typedef int pod_t;
* pod_t *s;
* s->~pod_t();
* ```
*/
class VacuousDestructorCall extends Expr, @vacuous_destructor_call {
/**
* Gets the expression for the object whose destructor would be called.
*/
Expr getQualifier() { result = this.getChild(0) }
override string getAPrimaryQlClass() { result = "VacuousDestructorCall" }
override string toString() { result = "(vacuous destructor call)" }
}
/**
* An initialization of a base class or member variable performed as part
* of a constructor's explicit initializer list or implicit actions.
*
* This is a QL root class for reprenting various types of constructor
* initializations.
*/
class ConstructorInit extends Expr, @ctorinit {
override string getAPrimaryQlClass() { result = "ConstructorInit" }
}
/**
* A call to a constructor of a base class as part of a constructor's
* initializer list or compiler-generated actions.
*/
class ConstructorBaseInit extends ConstructorInit, ConstructorCall {
override string getAPrimaryQlClass() { result = "ConstructorBaseInit" }
}
/**
* A call to a constructor of a direct non-virtual base class as part of a
* constructor's initializer list or compiler-generated actions.
* ```
* struct S {
* int a;
* S(int b): a(b) {}
* };
* struct T: S {
* T(): S(33) {} // S(33) is a constructor call
* };
* ```
*/
class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit {
override string getAPrimaryQlClass() { result = "ConstructorDirectInit" }
}
/**
* A call to a constructor of a virtual base class as part of a
* constructor's initializer list or compiler-generated actions.
*
* If the virtual base class has already been initialized, then this
* call won't be performed.
* ```
* struct S {
* int a;
* S(int b): a(b) {}
* };
* struct T: virtual S {
* T(): S(33) {} // S(33) is a call to a virtual base constructor
* };
* ```
*/
class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit {
override string getAPrimaryQlClass() { result = "ConstructorVirtualInit" }
}
/**
* A call to a constructor of the same class as part of a constructor's
* initializer list, which delegates object construction (C++11 only).
* ```
* struct S {
* int a;
* S(int b): a(b) { }
* S(): S(0) { } // delegation to another constructor
* };
* ```
*/
class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit {
override string getAPrimaryQlClass() { result = "ConstructorDelegationInit" }
}
/**
* An initialization of a member variable performed as part of a
* constructor's explicit initializer list or implicit actions.
* In the example below, member variable `b` is being initialized by
* constructor parameter `a`:
* ```
* struct S {
* int b;
* S(int a): b(a) {}
* } s(2);
* ```
*/
class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
/** Gets the field being initialized. */
Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
override string getAPrimaryQlClass() { result = "ConstructorFieldInit" }
/**
* Gets the expression to which the field is initialized.
*
* This is typically either a Literal or a FunctionCall to a
* constructor, but more complex expressions can also occur.
*/
Expr getExpr() { result = this.getChild(0) }
override string toString() { result = "constructor init of field " + getTarget().getName() }
override predicate mayBeImpure() { this.getExpr().mayBeImpure() }
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
}
/**
* A call to a destructor of a base class or field as part of a destructor's
* compiler-generated actions.
*/
class DestructorDestruction extends Expr, @dtordestruct {
override string getAPrimaryQlClass() { result = "DestructorDestruction" }
}
/**
* A call to a destructor of a base class as part of a destructor's
* compiler-generated actions.
*/
class DestructorBaseDestruction extends DestructorCall, DestructorDestruction {
override string getAPrimaryQlClass() { result = "DestructorBaseDestruction" }
}
/**
* A call to a destructor of a direct non-virtual base class as part of a
* destructor's compiler-generated actions.
* ```
* struct S { ~S(void) {} };
* struct T: S {
* ~T(void) {} // will call ~S()
* };
* ```
*/
class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirectdestruct {
override string getAPrimaryQlClass() { result = "DestructorDirectDestruction" }
}
/**
* A call to a destructor of a direct virtual base class as part of a
* destructor's compiler-generated actions.
*
* If the virtual base class wasn't initialized by the ConstructorVirtualInit
* in the corresponding constructor, then this call won't be performed.
* ```
* struct S { ~S(void) {} };
* struct T: virtual S {
* ~T(void) {} // will call ~S()
* };
* ```
*/
class DestructorVirtualDestruction extends DestructorBaseDestruction, @dtorvirtualdestruct {
override string getAPrimaryQlClass() { result = "DestructorVirtualDestruction" }
}
/**
* A destruction of a member variable performed as part of a
* destructor's compiler-generated actions.
* ```
* struct S { ~S(void) {} };
* struct T {
* S s;
* ~T(void) {} // will call s.~S()
* };
* ```
*/
class DestructorFieldDestruction extends DestructorDestruction, @dtorfielddestruct {
/** Gets the field being destructed. */
Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
override string getAPrimaryQlClass() { result = "DestructorFieldDestruction" }
/** Gets the compiler-generated call to the variable's destructor. */
DestructorCall getExpr() { result = this.getChild(0) }
override string toString() {
result = "destructor field destruction of " + this.getTarget().getName()
}
}

View File

@@ -0,0 +1,922 @@
/**
* 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<struct T *>(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<struct S *>(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<std::uintptr_t>(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(getUnspecifiedType()) and
isArithmeticOrEnum(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(getUnspecifiedType()) and
isIntegralOrEnum(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() {
getUnspecifiedType() instanceof FloatingPointType and
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(getUnspecifiedType()) and
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() {
getUnspecifiedType() instanceof FloatingPointType and
isIntegralOrEnum(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(getUnspecifiedType()) and
isPointerOrNullPointer(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 = getExpr().getUnspecifiedType() and
toType = 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(getUnspecifiedType()) and
isPointerOrNullPointer(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(getUnspecifiedType()) and
isIntegralOrEnum(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
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() = getBaseClass() and
result.getDerivedClass() = 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(getExpr()) }
/**
* Holds if this conversion is to a virtual base class.
*/
predicate isVirtual() { getDerivation().isVirtual() or not exists(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(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<struct T *>(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(getTypeOperand())
then result = "__uuidof(" + 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)) }
/**
* DEPRECATED: Use `getResultType()` instead.
*
* Gets the type that is returned by this typeid expression.
*/
deprecated Type getSpecifiedType() { result = this.getResultType() }
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 string toString() { result = "sizeof...(...)" }
override string getAPrimaryQlClass() { result = "SizeofPackOperator" }
override predicate mayBeImpure() { none() }
override predicate mayBeGloballyImpure() { none() }
}
/**
* A C/C++ sizeof expression.
*/
class SizeofOperator extends Expr, @runtime_sizeof {
override int getPrecedence() { result = 16 }
}
/**
* A C/C++ sizeof expression whose operand is an expression.
* ```
* if (sizeof(a) == sizeof(b)) { c = (b)a; }
* ```
*/
class SizeofExprOperator extends SizeofOperator {
SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) }
override string getAPrimaryQlClass() { result = "SizeofExprOperator" }
/** Gets the contained expression. */
Expr getExprOperand() { result = this.getChild(0) }
/**
* DEPRECATED: Use `getExprOperand()` instead
*
* Gets the contained expression.
*/
deprecated Expr getExpr() { result = this.getExprOperand() }
override string toString() { result = "sizeof(<expr>)" }
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" }
/** Gets the contained type. */
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
/**
* DEPRECATED: Use `getTypeOperand()` instead
*
* Gets the contained type.
*/
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
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(Expr e | this.getChild(0) = e) }
/**
* Gets the contained expression.
*/
Expr getExprOperand() { result = this.getChild(0) }
/**
* DEPRECATED: Use `getExprOperand()` instead.
*/
deprecated Expr getExpr() { result = this.getExprOperand() }
override string toString() { result = "alignof(<expr>)" }
}
/**
* A C++11 `alignof` expression whose operand is a type name.
* ```
* bool proper_alignment = (alingof(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)) }
/**
* DEPRECATED: Use `getTypeOperand()` instead.
*/
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" }
}
/**
* 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"
}

View File

@@ -0,0 +1,140 @@
/**
* Provides classes for modeling comparisons such as `==`, `!=` and `<`.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C/C++ comparison operation, that is, either an equality operation or a relational operation.
*
* This is a QL base class for all comparisons.
*/
class ComparisonOperation extends BinaryOperation, @cmp_op_expr { }
/**
* A C/C++ equality operation, that is, either "==" or "!=".
*/
class EqualityOperation extends ComparisonOperation, @eq_op_expr {
override int getPrecedence() { result = 9 }
}
/**
* A C/C++ equal expression.
* ```
* bool c = (a == b);
* ```
*/
class EQExpr extends EqualityOperation, @eqexpr {
override string getAPrimaryQlClass() { result = "EQExpr" }
override string getOperator() { result = "==" }
}
/**
* A C/C++ not equal expression.
* ```
* bool c = (a != b);
* ```
*/
class NEExpr extends EqualityOperation, @neexpr {
override string getAPrimaryQlClass() { result = "NEExpr" }
override string getOperator() { result = "!=" }
}
/**
* A C/C++ relational operation, that is, one of `<=`, `<`, `>`, or `>=`.
*/
class RelationalOperation extends ComparisonOperation, @rel_op_expr {
override int getPrecedence() { result = 10 }
/**
* DEPRECATED: Use `getGreaterOperand()` instead.
*/
deprecated Expr getLarge() { result = getGreaterOperand() }
/**
* DEPRECATED: Use `getLesserOperand()` instead.
*/
deprecated Expr getSmall() { result = getLesserOperand() }
/**
* Gets the operand on the "greater" (or "greater-or-equal") side
* of this relational expression, that is, the side that is larger
* if the overall expression evaluates to `true`; for example on
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
*/
Expr getGreaterOperand() { none() } // overridden in subclasses
/**
* Gets the operand on the "lesser" (or "lesser-or-equal") side
* of this relational expression, that is, the side that is smaller
* if the overall expression evaluates to `true`; for example on
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
*/
Expr getLesserOperand() { none() } // overridden in subclasses
}
/**
* A C/C++ greater than expression.
* ```
* bool c = (a > b);
* ```
*/
class GTExpr extends RelationalOperation, @gtexpr {
override string getAPrimaryQlClass() { result = "GTExpr" }
override string getOperator() { result = ">" }
override Expr getGreaterOperand() { result = getLeftOperand() }
override Expr getLesserOperand() { result = getRightOperand() }
}
/**
* A C/C++ less than expression.
* ```
* bool c = (a < b);
* ```
*/
class LTExpr extends RelationalOperation, @ltexpr {
override string getAPrimaryQlClass() { result = "LTExpr" }
override string getOperator() { result = "<" }
override Expr getGreaterOperand() { result = getRightOperand() }
override Expr getLesserOperand() { result = getLeftOperand() }
}
/**
* A C/C++ greater than or equal expression.
* ```
* bool c = (a >= b);
* ```
*/
class GEExpr extends RelationalOperation, @geexpr {
override string getAPrimaryQlClass() { result = "GEExpr" }
override string getOperator() { result = ">=" }
override Expr getGreaterOperand() { result = getLeftOperand() }
override Expr getLesserOperand() { result = getRightOperand() }
}
/**
* A C/C++ less than or equal expression.
* ```
* bool c = (a <= b);
* ```
*/
class LEExpr extends RelationalOperation, @leexpr {
override string getAPrimaryQlClass() { result = "LEExpr" }
override string getOperator() { result = "<=" }
override Expr getGreaterOperand() { result = getRightOperand() }
override Expr getLesserOperand() { result = getLeftOperand() }
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
/**
* Provides classes for modeling lambda expressions and their captures.
*/
import semmle.code.cpp.exprs.Expr
import semmle.code.cpp.Class
/**
* A C++11 lambda expression, for example the expression initializing `a` in
* the following code:
* ```
* auto a = [x, y](int z) -> int {
* return x + y + z;
* };
* ```
*
* The type given by `getType()` will be an instance of `Closure`.
*/
class LambdaExpression extends Expr, @lambdaexpr {
override string toString() { result = "[...](...){...}" }
override string getAPrimaryQlClass() { result = "LambdaExpression" }
/**
* Gets an implicitly or explicitly captured value of this lambda expression.
*/
LambdaCapture getACapture() { result = getCapture(_) }
/**
* Gets the nth implicitly or explicitly captured value of this lambda expression.
*/
LambdaCapture getCapture(int index) {
lambda_capture(result, underlyingElement(this), index, _, _, _, _)
}
/**
* Gets the default variable capture mode for the lambda expression.
*
* Will be one of:
* - "" if no default was specified, meaning that all captures must be explicit.
* - "&amp;" if capture-by-reference is the default for implicit captures.
* - "=" if capture-by-value is the default for implicit captures.
*/
string getDefaultCaptureMode() { lambdas(underlyingElement(this), result, _) }
/**
* Holds if the return type (of the call operator of the resulting object) was explicitly specified.
*/
predicate returnTypeIsExplicit() { lambdas(underlyingElement(this), _, true) }
/**
* Gets the function which will be invoked when the resulting object is called.
*
* Various components of the lambda expression can be obtained from components of this
* function, such as:
* - The number and type of parameters.
* - Whether the mutable keyword was used (iff this function is not const).
* - The return type.
* - The statements comprising the lambda body.
*/
Operator getLambdaFunction() { result = getType().(Closure).getLambdaFunction() }
/**
* Gets the initializer that initializes the captured variables in the closure, if any.
* A lambda that does not capture any variables will not have an initializer.
*/
ClassAggregateLiteral getInitializer() { result = getChild(0) }
}
/**
* A class written by the compiler to be the type of a C++11 lambda expression.
* For example the variable `a` in the following code has a closure type:
* ```
* auto a = [x, y](int z) -> int {
* return x + y + z;
* };
* ```
*/
class Closure extends Class {
Closure() { exists(LambdaExpression e | this = e.getType()) }
override string getAPrimaryQlClass() { result = "Closure" }
/** Gets the lambda expression of which this is the type. */
LambdaExpression getLambdaExpression() { result.getType() = this }
/** Gets the compiler-generated operator() of this closure type. */
Operator getLambdaFunction() {
result = this.getAMember() and
result.getName() = "operator()"
}
override string getDescription() { result = "decltype([...](...){...})" }
}
/**
* Information about a value captured as part of a lambda expression. For
* example in the following code, information about `x` and `y` is captured:
* ```
* auto a = [x, y](int z) -> int {
* return x + y + z;
* };
* ```
*/
class LambdaCapture extends Locatable, @lambdacapture {
override string toString() { result = getField().getName() }
override string getAPrimaryQlClass() { result = "LambdaCapture" }
/**
* Holds if this capture was made implicitly.
*/
predicate isImplicit() { lambda_capture(this, _, _, _, _, true, _) }
/**
* Holds if the variable was captured by reference.
*
* An identifier is captured by reference if:
* - It is explicitly captured by reference.
* - It is implicitly captured, and the lambda's default capture mode is by-reference.
* - The identifier is "this". [Said behaviour is dictated by the C++11 standard, but it
* is actually "*this" being captured rather than "this".]
*/
predicate isCapturedByReference() { lambda_capture(this, _, _, _, true, _, _) }
/**
* Gets the location of the declaration of this capture.
*
* For explicit captures, this is a location within the "[...]" part of the lambda expression.
*
* For implicit captures, this is the first location within the "{...}" part of the lambda
* expression which accesses the captured variable.
*/
override Location getLocation() { lambda_capture(this, _, _, _, _, _, result) }
/**
* Gets the field of the lambda expression's closure type which is used to store this capture.
*/
MemberVariable getField() { lambda_capture(this, _, _, result, _, _, _) }
/**
* Gets the expression which yields the final captured value.
*
* In many cases, this will be an instance of VariableAccess.
* If a this-pointer is being captured, this will be an instance of ThisExpr.
* For by-value captures of non-primitive types, this will be a call to a copy constructor.
*/
Expr getInitializer() {
exists(LambdaExpression lambda | this = lambda.getCapture(_) |
result = lambda.getInitializer().getFieldExpr(this.getField())
)
}
}

View File

@@ -0,0 +1,346 @@
/**
* Provides classes for modeling literals in the source code such as `0`, `'c'`
* or `"string"`.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C/C++ literal.
*
* The is the QL root class for all literals.
*/
class Literal extends Expr, @literal {
/** Gets a textual representation of this literal. */
override string toString() {
result = this.getValue()
or
not exists(this.getValue()) and
result = "Unknown literal"
}
override string getAPrimaryQlClass() { result = "Literal" }
override predicate mayBeImpure() { none() }
override predicate mayBeGloballyImpure() { none() }
}
/**
* A label literal, that is, a use of the '&&' operator to take the address of a
* label for use in a computed goto statement. This is a non-standard C/C++ extension.
*
* For example:
* ```
* void *label_ptr = &&myLabel; // &&myLabel is a LabelLiteral
* goto *label_ptr; // this is a ComputedGotoStmt
* myLabel: // this is a LabelStmt
* ```
*/
class LabelLiteral extends Literal {
LabelLiteral() { jumpinfo(underlyingElement(this), _, _) }
override string getAPrimaryQlClass() { result = "LabelLiteral" }
/** Gets the corresponding label statement. */
LabelStmt getLabel() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) }
}
/** A character literal or a string literal. */
class TextLiteral extends Literal {
TextLiteral() {
// String Literal
// Note that `AggregateLiteral`s can also have an array type, but they derive from
// @aggregateliteral rather than @literal.
this.getType() instanceof ArrayType
or
// Char literal
this.getValueText().regexpMatch("(?s)\\s*L?'.*")
}
/** Gets a hex escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */
string getAHexEscapeSequence(int occurrence, int offset) {
result = getValueText().regexpFind("(?<!\\\\)\\\\x[0-9a-fA-F]+", occurrence, offset)
}
/** Gets an octal escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */
string getAnOctalEscapeSequence(int occurrence, int offset) {
result = getValueText().regexpFind("(?<!\\\\)\\\\[0-7]{1,3}", occurrence, offset)
}
/**
* Gets a non-standard escape sequence that appears in the character or string literal. This is one that has the
* form of an escape sequence but is not one of the valid types of escape sequence in the C++ Standard.
*/
string getANonStandardEscapeSequence(int occurrence, int offset) {
// Find all single character escape sequences (ignoring the start of octal escape sequences),
// together with anything starting like a hex escape sequence but not followed by a hex digit.
result = getValueText().regexpFind("\\\\[^x0-7\\s]|\\\\x[^0-9a-fA-F]", occurrence, offset) and
// From these, exclude all standard escape sequences.
not result = getAStandardEscapeSequence(_, _)
}
/** Gets a simple escape sequence that appears in the char or string literal (see [lex.ccon] in the C++ Standard). */
string getASimpleEscapeSequence(int occurrence, int offset) {
result = getValueText().regexpFind("\\\\['\"?\\\\abfnrtv]", occurrence, offset)
}
/** Gets a standard escape sequence that appears in the char or string literal (see [lex.ccon] in the C++ Standard). */
string getAStandardEscapeSequence(int occurrence, int offset) {
result = getASimpleEscapeSequence(occurrence, offset) or
result = getAnOctalEscapeSequence(occurrence, offset) or
result = getAHexEscapeSequence(occurrence, offset)
}
/**
* Gets the length of the string literal (including null) before escape sequences added by the extractor.
*/
int getOriginalLength() { result = getValue().length() + 1 }
}
/**
* A character literal. For example:
* ```
* char c1 = 'a';
* wchar_t c2 = L'b';
* ```
*/
class CharLiteral extends TextLiteral {
CharLiteral() { this.getValueText().regexpMatch("(?s)\\s*L?'.*") }
override string getAPrimaryQlClass() { result = "CharLiteral" }
/**
* Gets the character of this literal. For example `L'a'` has character `"a"`.
*/
string getCharacter() { result = this.getValueText().regexpCapture("(?s)\\s*L?'(.*)'", 1) }
}
/**
* A string literal. For example:
* ```
* const char *s1 = "abcdef";
* const wchar_t *s2 = L"123456";
* ```
*/
class StringLiteral extends TextLiteral {
StringLiteral() {
this.getType() instanceof ArrayType
// Note that `AggregateLiteral`s can also have an array type, but they derive from
// @aggregateliteral rather than @literal.
}
override string getAPrimaryQlClass() { result = "StringLiteral" }
}
/**
* An octal literal. For example:
* ```
* char esc = 033;
* ```
* Octal literals must always start with the digit `0`.
*/
class OctalLiteral extends Literal {
OctalLiteral() { super.getValueText().regexpMatch("\\s*0[0-7]+[uUlL]*\\s*") }
override string getAPrimaryQlClass() { result = "OctalLiteral" }
}
/**
* A hexadecimal literal.
* ```
* unsigned int32_t minus2 = 0xfffffffe;
* ```
*/
class HexLiteral extends Literal {
HexLiteral() { super.getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F]+[uUlL]*\\s*") }
override string getAPrimaryQlClass() { result = "HexLiteral" }
}
/**
* A C/C++ aggregate literal.
*/
class AggregateLiteral extends Expr, @aggregateliteral {
override string getAPrimaryQlClass() { result = "AggregateLiteral" }
/**
* DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead.
*
* Gets the expression within the aggregate literal that is used to initialise field `f`,
* if this literal is being used to initialise a class/struct instance.
*/
deprecated Expr getCorrespondingExpr(Field f) {
result = this.(ClassAggregateLiteral).getFieldExpr(f)
}
override predicate mayBeImpure() { this.getAChild().mayBeImpure() }
override predicate mayBeGloballyImpure() { this.getAChild().mayBeGloballyImpure() }
/** Gets a textual representation of this aggregate literal. */
override string toString() { result = "{...}" }
}
/**
* A C/C++ aggregate literal that initializes a `class`, `struct`, or `union`.
* For example:
* ```
* S s = { arg1, arg2, { arg3, arg4 }, arg5 };
* ```
*/
class ClassAggregateLiteral extends AggregateLiteral {
Class classType;
ClassAggregateLiteral() { classType = this.getUnspecifiedType() }
override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" }
/**
* Gets the expression within the aggregate literal that is used to initialize
* field `field`, if present.
*/
Expr getFieldExpr(Field field) {
field = classType.getAField() and
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field))
}
/**
* Holds if the field `field` is initialized by this initializer list, either
* explicitly with an expression, or implicitly value initialized.
*/
pragma[inline]
predicate isInitialized(Field field) {
field = classType.getAField() and
field.isInitializable() and
(
// If the field has an explicit initializer expression, then the field is
// initialized.
exists(getFieldExpr(field))
or
// If the type is not a union, all fields without initializers are value
// initialized.
not classType instanceof Union
or
// If the type is a union, and there are no explicit initializers, then
// the first declared field is value initialized.
not exists(getAChild()) and
field.getInitializationOrder() = 0
)
}
/**
* Holds if the field `field` is value initialized because it is not
* explicitly initialized by this initializer list.
*
* Value initialization (see [dcl.init]/8) recursively initializes all fields
* of an object to `false`, `0`, `nullptr`, or by calling the default
* constructor, as appropriate to the type.
*/
pragma[inline]
predicate isValueInitialized(Field field) {
isInitialized(field) and
not exists(getFieldExpr(field))
}
}
/**
* A C/C++ aggregate literal that initializes an array or a GNU vector type.
*/
class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
ArrayOrVectorAggregateLiteral() {
exists(DerivedType type |
type = this.getUnspecifiedType() and
(
type instanceof ArrayType or
type instanceof GNUVectorType
)
)
}
/**
* Gets the number of elements initialized by this initializer list, either explicitly with an
* expression, or by implicit value initialization.
*/
int getArraySize() { none() }
/**
* Gets the type of the elements in the initializer list.
*/
Type getElementType() { none() }
/**
* Gets the expression within the aggregate literal that is used to initialize
* element `elementIndex`, if present.
*/
Expr getElementExpr(int elementIndex) {
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex)
}
/**
* Holds if the element `elementIndex` is initialized by this initializer
* list, either explicitly with an expression, or implicitly value
* initialized.
*/
bindingset[elementIndex]
predicate isInitialized(int elementIndex) {
elementIndex >= 0 and
elementIndex < getArraySize()
}
/**
* Holds if the element `elementIndex` is value initialized because it is not
* explicitly initialized by this initializer list.
*
* Value initialization (see [dcl.init]/8) recursively initializes all fields
* of an object to `false`, `0`, `nullptr`, or by calling the default
* constructor, as appropriate to the type.
*/
bindingset[elementIndex]
predicate isValueInitialized(int elementIndex) {
isInitialized(elementIndex) and
not exists(getElementExpr(elementIndex))
}
}
/**
* A C/C++ aggregate literal that initializes an array
* ```
* S s[4] = { s_1, s_2, s_3, s_n };
* ```
*/
class ArrayAggregateLiteral extends ArrayOrVectorAggregateLiteral {
ArrayType arrayType;
ArrayAggregateLiteral() { arrayType = this.getUnspecifiedType() }
override string getAPrimaryQlClass() { result = "ArrayAggregateLiteral" }
override int getArraySize() { result = arrayType.getArraySize() }
override Type getElementType() { result = arrayType.getBaseType() }
}
/**
* A C/C++ aggregate literal that initializes a GNU vector type.
*
* Braced initializer lists are used, similarly to what is done
* for arrays.
* ```
* typedef int v4si __attribute__ (( vector_size(4*sizeof(int)) ));
* v4si v = (v4si){ 1, 2, 3, 4 };
* typedef float float4 __attribute__((ext_vector_type(4)));
* float4 vf = {1.0f, 2.0f, 3.0f, 4.0f};
* ```
*/
class VectorAggregateLiteral extends ArrayOrVectorAggregateLiteral {
GNUVectorType vectorType;
VectorAggregateLiteral() { vectorType = this.getUnspecifiedType() }
override string getAPrimaryQlClass() { result = "VectorAggregateLiteral" }
override int getArraySize() { result = vectorType.getNumElements() }
override Type getElementType() { result = vectorType.getBaseType() }
}

View File

@@ -0,0 +1,131 @@
/**
* Provides classes for modeling logical operations such as `!`, `&&`, `||`, and
* the ternary `? :` expression.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C/C++ unary logical operation.
*/
class UnaryLogicalOperation extends UnaryOperation, @un_log_op_expr { }
/**
* A C/C++ logical not expression.
* ```
* c = !a;
* ```
*/
class NotExpr extends UnaryLogicalOperation, @notexpr {
override string getOperator() { result = "!" }
override string getAPrimaryQlClass() { result = "NotExpr" }
override int getPrecedence() { result = 16 }
}
/**
* A C/C++ binary logical operation.
*/
class BinaryLogicalOperation extends BinaryOperation, @bin_log_op_expr {
/**
* Holds if the truth of this binary logical expression having value `wholeIsTrue`
* implies that the truth of the child expression `part` has truth value `partIsTrue`.
*
* For example if the binary operation:
* ```
* x && y
* ```
* is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and
* `impliesValue(y, true, true)` hold.
*/
predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) { none() } // overridden in subclasses
}
/**
* A C/C++ logical AND expression.
* ```
* if (a && b) { }
* ```
*/
class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr {
override string getOperator() { result = "&&" }
override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
override int getPrecedence() { result = 5 }
override predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) {
wholeIsTrue = true and partIsTrue = true and part = this.getAnOperand()
or
wholeIsTrue = true and
this.getAnOperand().(BinaryLogicalOperation).impliesValue(part, partIsTrue, true)
}
}
/**
* A C/C++ logical OR expression.
* ```
* if (a || b) { }
* ```
*/
class LogicalOrExpr extends BinaryLogicalOperation, @orlogicalexpr {
override string getOperator() { result = "||" }
override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
override int getPrecedence() { result = 4 }
override predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) {
wholeIsTrue = false and partIsTrue = false and part = this.getAnOperand()
or
wholeIsTrue = false and
this.getAnOperand().(BinaryLogicalOperation).impliesValue(part, partIsTrue, false)
}
}
/**
* A C/C++ conditional ternary expression.
* ```
* a = (b > c ? d : e);
* ```
*/
class ConditionalExpr extends Operation, @conditionalexpr {
/** Gets the condition of this conditional expression. */
Expr getCondition() { expr_cond_guard(underlyingElement(this), unresolveElement(result)) }
override string getAPrimaryQlClass() { result = "ConditionalExpr" }
/** Gets the 'then' expression of this conditional expression. */
Expr getThen() {
if this.isTwoOperand()
then result = this.getCondition()
else expr_cond_true(underlyingElement(this), unresolveElement(result))
}
/** Gets the 'else' expression of this conditional expression. */
Expr getElse() { expr_cond_false(underlyingElement(this), unresolveElement(result)) }
/**
* Holds if this expression used the two operand form `guard ? : false`.
*/
predicate isTwoOperand() { expr_cond_two_operand(underlyingElement(this)) }
override string getOperator() { result = "?" }
override string toString() { result = "... ? ... : ..." }
override int getPrecedence() { result = 3 }
override predicate mayBeImpure() {
this.getCondition().mayBeImpure() or
this.getThen().mayBeImpure() or
this.getElse().mayBeImpure()
}
override predicate mayBeGloballyImpure() {
this.getCondition().mayBeGloballyImpure() or
this.getThen().mayBeGloballyImpure() or
this.getElse().mayBeGloballyImpure()
}
}

View File

@@ -0,0 +1,297 @@
/**
* DEPRECATED: Objective-C is no longer supported.
*/
import semmle.code.cpp.exprs.Expr
import semmle.code.cpp.Class
import semmle.code.cpp.ObjectiveC
private import semmle.code.cpp.internal.ResolveClass
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C message expression, for example `[myColor changeColorToRed:5.0 green:2.0 blue:6.0]`.
*/
deprecated class MessageExpr extends Expr, Call {
MessageExpr() { none() }
override string toString() { none() }
/**
* Gets the selector of this message expression, for example `-changeColorToRed:green:blue:`.
*/
string getSelector() { none() }
/**
* Gets the function invoked by this message expression, as inferred by the compiler.
*
* If the compiler could infer the type of the receiver, and that type had a method
* whose name matched the selector, then the result of this predicate is said method.
* Otherwise this predicate has no result.
*
* In all cases, actual function dispatch isn't performed until runtime, but the
* lack of a static target is often cause for concern.
*/
MemberFunction getStaticTarget() { none() }
/**
* Provided for compatibility with Call. It is the same as the static target.
*/
override MemberFunction getTarget() { none() }
/**
* Holds if the compiler could infer a function as the target of this message.
*
* In all cases, actual function dispatch isn't performed until runtime, but the
* lack of a static target is often cause for concern.
*/
predicate hasStaticTarget() { none() }
/**
* Gets the number of arguments passed by this message expression.
*
* In most cases, this equals the number of colons in the selector, but this needn't be the
* case for variadic methods like "-initWithFormat:", which can have more than one argument.
*/
override int getNumberOfArguments() { none() }
/**
* Gets an argument passed by this message expression.
*/
override Expr getAnArgument() { none() }
/**
* Gets the nth argument passed by this message expression.
*
* The range of `n` is [`0` .. `getNumberOfArguments()`].
*/
override Expr getArgument(int n) { none() }
override int getPrecedence() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C message expression whose receiver is `super`, for example `[super init]`.
*/
deprecated class SuperMessageExpr extends MessageExpr {
SuperMessageExpr() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C message expression whose receiver is the name of a class, and
* is therefore calling a class method rather than an instance method. This occurs
* most commonly for the "+alloc", "+new", and "+class" selectors.
*/
deprecated class ClassMessageExpr extends MessageExpr {
ClassMessageExpr() { none() }
/**
* Gets the class which is the receiver of this message.
*/
Type getReceiver() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C message expression whose receiver is an expression (which includes the
* common case of the receiver being "self").
*/
deprecated class ExprMessageExpr extends MessageExpr {
ExprMessageExpr() { none() }
/**
* Gets the expression which gives the receiver of this message.
*/
Expr getReceiver() { none() }
/**
* Gets the Objective C class of which the receiving expression is an instance.
*
* If the receiving expression has type `id` or type `id<P>` for some protocol `P`,
* then there will be no result. If the receiving expression has type `C*` or type
* `C<P>*` for some protocol `P`, then the result will be the type `C`.
*/
ObjectiveClass getReceiverClass() { none() }
/**
* Gets the Objective C classes and/or protocols which are statically implemented
* by the receiving expression.
*
* If the receiving expression has type `id`, then there will be no result.
* If the receiving expression has type `id<P>`, then `P` will be the sole result.
* If the receiving expression has type `C*`, then `C` will be the sole result.
* If the receiving expression has type `C<P>*`, then `C` and `P` will both be results.
*/
Class getAReceiverClassOrProtocol() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An access to an Objective C property using dot syntax.
*
* Such accesses are de-sugared into a message expression to the property's getter or setter.
*/
deprecated class PropertyAccess extends ExprMessageExpr {
PropertyAccess() { none() }
/**
* Gets the property being accessed by this expression.
*/
Property getProperty() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C `@selector` expression, for example `@selector(driveForDistance:)`.
*/
deprecated class AtSelectorExpr extends Expr {
AtSelectorExpr() { none() }
override string toString() { none() }
/**
* Gets the selector of this `@selector` expression, for example `driveForDistance:`.
*/
string getSelector() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C `@protocol` expression, for example `@protocol(SomeProtocol)`.
*/
deprecated class AtProtocolExpr extends Expr {
AtProtocolExpr() { none() }
override string toString() { none() }
/**
* Gets the protocol of this `@protocol` expression, for example `SomeProtocol`.
*/
Protocol getProtocol() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C `@encode` expression, for example `@encode(int *)`.
*/
deprecated class AtEncodeExpr extends Expr {
AtEncodeExpr() { none() }
override string toString() { none() }
/**
* Gets the type this `@encode` expression encodes, for example `int *`.
*/
Type getEncodedType() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C throw expression.
*/
deprecated class ObjcThrowExpr extends ThrowExpr {
ObjcThrowExpr() { none() }
override string toString() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C throw expression with no argument (which causes the
* current exception to be re-thrown).
*/
deprecated class ObjcReThrowExpr extends ReThrowExpr, ObjcThrowExpr {
ObjcReThrowExpr() { none() }
override string toString() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C @ expression which boxes a single value, such as @(22).
*/
deprecated class AtExpr extends UnaryOperation {
AtExpr() { none() }
override string toString() { none() }
override string getOperator() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C @[...] literal.
*/
deprecated class ArrayLiteral extends Expr {
ArrayLiteral() { none() }
/** Gets a textual representation of this array literal. */
override string toString() { none() }
/** An element of the array */
Expr getElement(int i) { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C @{...} literal.
*/
deprecated class DictionaryLiteral extends Expr {
DictionaryLiteral() { none() }
/** Gets a textual representation of this dictionary literal. */
override string toString() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C @"..." string literal.
*/
deprecated class ObjCLiteralString extends TextLiteral {
ObjCLiteralString() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C/C++ overloaded subscripting access expression.
*
* Either
* obj[idx]
* or
* obj[idx] = expr
*/
deprecated class SubscriptExpr extends Expr {
SubscriptExpr() { none() }
/**
* Gets the object expression being subscripted.
*/
Expr getSubscriptBase() { none() }
/**
* Gets the expression giving the index into the object.
*/
Expr getSubscriptIndex() { none() }
/**
* Gets the expression being assigned (if this is an assignment).
*/
Expr getAssignedExpr() { none() }
override string toString() { none() }
}
/**
* DEPRECATED: Objective-C is no longer supported.
* An Objective C _cmd expression.
*/
deprecated class CmdExpr extends Expr {
CmdExpr() { none() }
override string toString() { none() }
override predicate mayBeImpure() { none() }
override predicate mayBeGloballyImpure() { none() }
}