Skip to content

Commit cf42427

Browse files
authored
Merge pull request #7321 from hvitved/csharp/cil/unique-type
C#: Avoid CIL instructions with multiple types
2 parents f7f3890 + 7e99426 commit cf42427

File tree

6 files changed

+45
-9
lines changed

6 files changed

+45
-9
lines changed

csharp/ql/lib/semmle/code/cil/CallableReturns.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ private module Cached {
2525
cached
2626
predicate alwaysThrowsException(Method m, Type t) {
2727
alwaysThrowsMethod(m) and
28-
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExpr().getType())
28+
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExceptionType())
2929
}
3030
}
3131

csharp/ql/lib/semmle/code/cil/ConsistencyChecks.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ class ExprMissingType extends InstructionViolation {
612612
not instruction instanceof Opcodes::Ldvirtftn and
613613
not instruction instanceof Opcodes::Arglist and
614614
not instruction instanceof Opcodes::Refanytype and
615-
instruction.getPushCount() = 1 and
615+
instruction.getPushCount() >= 1 and
616616
count(instruction.getType()) != 1
617617
}
618618

csharp/ql/lib/semmle/code/cil/ControlFlow.qll

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,32 @@ class ControlFlowNode extends @cil_controlflow_node {
5656
)
5757
}
5858

59+
/**
60+
* Gets the type of the `i`th operand. Unlike `getOperand(i).getType()`, this
61+
* predicate takes into account when there are multiple possible operands with
62+
* different types.
63+
*/
64+
Type getOperandType(int i) {
65+
strictcount(this.getOperand(i)) = 1 and
66+
result = this.getOperand(i).getType()
67+
or
68+
strictcount(this.getOperand(i)) = 2 and
69+
exists(ControlFlowNode op1, ControlFlowNode op2, Type t2 |
70+
op1 = this.getOperand(i) and
71+
op2 = this.getOperand(i) and
72+
op1 != op2 and
73+
result = op1.getType() and
74+
t2 = op2.getType()
75+
|
76+
result = t2
77+
or
78+
result.(PrimitiveType).getUnderlyingType().getConversionIndex() >
79+
t2.(PrimitiveType).getUnderlyingType().getConversionIndex()
80+
or
81+
op2 instanceof NullLiteral
82+
)
83+
}
84+
5985
/** Gets an operand of this instruction, if any. */
6086
ControlFlowNode getAnOperand() { result = this.getOperand(_) }
6187

@@ -102,7 +128,12 @@ class ControlFlowNode extends @cil_controlflow_node {
102128
/** Gets the method containing this control flow node. */
103129
MethodImplementation getImplementation() { none() }
104130

105-
/** Gets the type of the item pushed onto the stack, if any. */
131+
/**
132+
* Gets the type of the item pushed onto the stack, if any.
133+
*
134+
* If called via `ControlFlowNode::getOperand(i).getType()`, consider using
135+
* `ControlFlowNode::getOperandType(i)` instead.
136+
*/
106137
cached
107138
Type getType() { none() }
108139

csharp/ql/lib/semmle/code/cil/InstructionGroups.qll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
7373
class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
7474
override Type getType() {
7575
exists(Type t0, Type t1 |
76-
t0 = this.getOperand(0).getType().getUnderlyingType() and
77-
t1 = this.getOperand(1).getType().getUnderlyingType()
76+
t0 = this.getOperandType(0).getUnderlyingType() and
77+
t1 = this.getOperandType(1).getUnderlyingType()
7878
|
7979
t0 = t1 and result = t0
8080
or
@@ -242,6 +242,9 @@ class Return extends Instruction, @cil_ret {
242242
class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
243243
override Expr getExpr() { result = this.getOperand(0) }
244244

245+
/** Gets the type of the exception being thrown. */
246+
Type getExceptionType() { result = this.getOperandType(0) }
247+
245248
override predicate canFlowNext() { none() }
246249
}
247250

csharp/ql/lib/semmle/code/cil/Instructions.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ module Opcodes {
199199
override string getOpcodeName() { result = "neg" }
200200

201201
override NumericType getType() {
202-
result = this.getOperand().getType()
202+
result = this.getOperandType(0)
203203
or
204-
this.getOperand().getType() instanceof Enum and result instanceof IntType
204+
this.getOperandType(0) instanceof Enum and result instanceof IntType
205205
}
206206
}
207207

@@ -260,7 +260,7 @@ module Opcodes {
260260

261261
override int getPushCount() { result = 2 } // This is the only instruction that pushes 2 items
262262

263-
override Type getType() { result = this.getOperand(0).getType() }
263+
override Type getType() { result = this.getOperandType(0) }
264264
}
265265

266266
/** A `ret` instruction. */
@@ -887,7 +887,7 @@ module Opcodes {
887887
class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref {
888888
override string getOpcodeName() { result = "ldelem.ref" }
889889

890-
override Type getType() { result = this.getArray().getType() }
890+
override Type getType() { result = this.getOperandType(1) }
891891
}
892892

893893
/** An `ldelema` instruction. */

csharp/ql/test/library-tests/cil/consistency/consistency.expected

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)