mirror of
https://github.com/github/codeql.git
synced 2025-12-18 09:43:15 +01:00
264 lines
8.2 KiB
Plaintext
264 lines
8.2 KiB
Plaintext
/**
|
|
* Provides classes representing various classes of expression
|
|
* and other instructions.
|
|
*/
|
|
|
|
private import CIL
|
|
private import dotnet
|
|
|
|
/**
|
|
* An instruction that pushes a value onto the stack.
|
|
*/
|
|
class Expr extends DotNet::Expr, Instruction, @cil_expr {
|
|
override int getPushCount() { result = 1 }
|
|
|
|
override Type getType() { result = Instruction.super.getType() }
|
|
|
|
override Method getEnclosingCallable() { result = this.getImplementation().getMethod() }
|
|
|
|
/**
|
|
* The "parent" of a CIL expression is taken to be the instruction
|
|
* that consumes the value pushed by this instruction.
|
|
*/
|
|
override Expr getParent() { this = result.getAnOperand() }
|
|
}
|
|
|
|
/** An instruction that changes control flow. */
|
|
class Branch extends Instruction, @cil_jump {
|
|
/** Gets the instruction that is jumped to. */
|
|
Instruction getTarget() { cil_jump(this, result) }
|
|
|
|
override string getExtra() { result = this.getTarget().getIndex() + ":" }
|
|
}
|
|
|
|
/** An instruction that unconditionally jumps to another instruction. */
|
|
class UnconditionalBranch extends Branch, @cil_unconditional_jump {
|
|
override Instruction getASuccessorType(FlowType t) {
|
|
t instanceof NormalFlow and result = this.getTarget()
|
|
}
|
|
|
|
override predicate canFlowNext() { none() }
|
|
}
|
|
|
|
/** An instruction that jumps to a target based on a condition. */
|
|
class ConditionalBranch extends Branch, @cil_conditional_jump {
|
|
override Instruction getASuccessorType(FlowType t) {
|
|
t instanceof TrueFlow and result = this.getTarget()
|
|
or
|
|
t instanceof FalseFlow and result = this.getImplementation().getInstruction(this.getIndex() + 1)
|
|
}
|
|
|
|
override int getPushCount() { result = 0 }
|
|
}
|
|
|
|
/** An expression with two operands. */
|
|
class BinaryExpr extends Expr, @cil_binary_expr {
|
|
override int getPopCount() { result = 2 }
|
|
}
|
|
|
|
/** An expression with one operand. */
|
|
class UnaryExpr extends Expr, @cil_unary_expr {
|
|
override int getPopCount() { result = 1 }
|
|
|
|
/** Gets the operand of this unary expression. */
|
|
Expr getOperand() { result = this.getOperand(0) }
|
|
}
|
|
|
|
/** A binary expression that compares two values. */
|
|
class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
|
|
override BoolType getType() { exists(result) }
|
|
}
|
|
|
|
/** A binary arithmetic expression. */
|
|
class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
|
|
override Type getType() {
|
|
exists(Type t0, Type t1 |
|
|
t0 = this.getOperandType(0).getUnderlyingType() and
|
|
t1 = this.getOperandType(1).getUnderlyingType()
|
|
|
|
|
t0 = t1 and result = t0
|
|
or
|
|
t0.getConversionIndex() < t1.getConversionIndex() and result = t1
|
|
or
|
|
t0.getConversionIndex() > t1.getConversionIndex() and result = t0
|
|
)
|
|
}
|
|
}
|
|
|
|
/** A binary bitwise expression. */
|
|
class BinaryBitwiseOperation extends BinaryExpr, @cil_binary_bitwise_operation {
|
|
// This is wrong but efficient - should depend on the types of the operands.
|
|
override IntType getType() { exists(result) }
|
|
}
|
|
|
|
/** A unary bitwise expression. */
|
|
class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation {
|
|
// This is wrong but efficient - should depend on the types of the operands.
|
|
override IntType getType() { exists(result) }
|
|
}
|
|
|
|
/** A unary expression that converts a value from one primitive type to another. */
|
|
class Conversion extends UnaryExpr, @cil_conversion_operation {
|
|
/** Gets the expression being converted. */
|
|
Expr getExpr() { result = this.getOperand(0) }
|
|
}
|
|
|
|
/** A branch that leaves the scope of a `Handler`. */
|
|
class Leave extends UnconditionalBranch, @cil_leave_any { }
|
|
|
|
/** An expression that pushes a literal value onto the stack. */
|
|
class Literal extends DotNet::Literal, Expr, @cil_literal {
|
|
/** Gets the pushed value. */
|
|
override string getValue() { cil_value(this, result) }
|
|
|
|
override string getExtra() { result = this.getValue() }
|
|
}
|
|
|
|
/** An integer literal. */
|
|
class IntLiteral extends Literal, @cil_ldc_i {
|
|
override string getExtra() { none() }
|
|
|
|
override IntType getType() { exists(result) }
|
|
}
|
|
|
|
/** An expression that pushes a `float`/`Single`. */
|
|
class FloatLiteral extends Literal, @cil_ldc_r { }
|
|
|
|
/** An expression that pushes a `null` value onto the stack. */
|
|
class NullLiteral extends Literal, @cil_ldnull { }
|
|
|
|
/** An expression that pushes a string onto the stack. */
|
|
class StringLiteral extends Literal, @cil_ldstr { }
|
|
|
|
/** A branch with one operand. */
|
|
class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
|
|
override int getPopCount() { result = 1 }
|
|
|
|
override int getPushCount() { result = 0 }
|
|
}
|
|
|
|
/** A branch with two operands. */
|
|
class BinaryBranch extends ConditionalBranch, @cil_binary_jump {
|
|
override int getPopCount() { result = 2 }
|
|
|
|
override int getPushCount() { result = 0 }
|
|
}
|
|
|
|
/** A call. */
|
|
class Call extends Expr, DotNet::Call, @cil_call_any {
|
|
/** Gets the method that is called. */
|
|
override Method getTarget() { cil_access(this, result) }
|
|
|
|
override Method getARuntimeTarget() { result = this.getTarget().getAnOverrider*() }
|
|
|
|
override string getExtra() { result = this.getTarget().getQualifiedName() }
|
|
|
|
/**
|
|
* Gets the return type of the call. Methods that do not return a value
|
|
* return the `void` type, `System.Void`, although the value of `getPushCount` is
|
|
* 0 in this case.
|
|
*/
|
|
override Type getType() { result = this.getTarget().getReturnType() }
|
|
|
|
// The number of items popped/pushed from the stack
|
|
// depends on the target of the call.
|
|
override int getPopCount() { result = this.getTarget().getCallPopCount() }
|
|
|
|
override int getPushCount() { result = this.getTarget().getCallPushCount() }
|
|
|
|
/**
|
|
* Holds if this is a "tail call", meaning that control does not return to the
|
|
* calling method.
|
|
*/
|
|
predicate isTailCall() {
|
|
this.getImplementation().getInstruction(this.getIndex() - 1) instanceof Opcodes::Tail
|
|
}
|
|
|
|
/** Holds if this call is virtual and could go to an overriding method. */
|
|
predicate isVirtual() { none() }
|
|
|
|
override Expr getRawArgument(int i) { result = this.getOperand(this.getPopCount() - i - 1) }
|
|
|
|
/** Gets the qualifier of this call, if any. */
|
|
Expr getQualifier() { result = this.getRawArgument(0) and not this.getTarget().isStatic() }
|
|
|
|
override Expr getArgument(int i) {
|
|
if this.getTarget().isStatic()
|
|
then result = this.getRawArgument(i)
|
|
else (
|
|
result = this.getRawArgument(i + 1) and i >= 0
|
|
)
|
|
}
|
|
|
|
override Expr getArgumentForParameter(DotNet::Parameter param) {
|
|
exists(int index |
|
|
result = this.getRawArgument(index) and param = this.getTarget().getRawParameter(index)
|
|
)
|
|
}
|
|
}
|
|
|
|
/** A tail call. */
|
|
class TailCall extends Call {
|
|
TailCall() { this.isTailCall() }
|
|
|
|
override predicate canFlowNext() { none() }
|
|
}
|
|
|
|
/** A call to a static target. */
|
|
class StaticCall extends Call {
|
|
StaticCall() { not this.isVirtual() }
|
|
}
|
|
|
|
/** A call to a virtual target. */
|
|
class VirtualCall extends Call {
|
|
VirtualCall() { this.isVirtual() }
|
|
}
|
|
|
|
/** A read of an array element. */
|
|
class ReadArrayElement extends BinaryExpr, @cil_read_array {
|
|
/** Gets the array being read. */
|
|
Expr getArray() { result = this.getOperand(1) }
|
|
|
|
/** Gets the index into the array. */
|
|
Expr getArrayIndex() { result = this.getOperand(0) }
|
|
}
|
|
|
|
/** A write of an array element. */
|
|
class WriteArrayElement extends Instruction, @cil_write_array {
|
|
override int getPushCount() { result = 0 }
|
|
|
|
override int getPopCount() { result = 3 }
|
|
}
|
|
|
|
/** A `return` statement. */
|
|
class Return extends Instruction, @cil_ret {
|
|
/** Gets the expression being returned, if any. */
|
|
Expr getExpr() { result = this.getOperand(0) }
|
|
|
|
override predicate canFlowNext() { none() }
|
|
}
|
|
|
|
/** A `throw` statement. */
|
|
class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
|
|
override Expr getExpr() { result = this.getOperand(0) }
|
|
|
|
/** Gets the type of the exception being thrown. */
|
|
Type getExceptionType() { result = this.getOperandType(0) }
|
|
|
|
override predicate canFlowNext() { none() }
|
|
}
|
|
|
|
/** Stores a value at an address/location. */
|
|
class StoreIndirect extends Instruction, @cil_stind {
|
|
override int getPopCount() { result = 2 }
|
|
|
|
/** Gets the location to store the value at. */
|
|
Expr getAddress() { result = this.getOperand(1) }
|
|
|
|
/** Gets the value to store. */
|
|
Expr getExpr() { result = this.getOperand(0) }
|
|
}
|
|
|
|
/** Loads a value from an address/location. */
|
|
class LoadIndirect extends UnaryExpr, @cil_ldind { }
|