|
1 | | -import semmle.code.csharp.ir.implementation.raw.IR as IR |
| 1 | +private import ValueNumberingImports |
2 | 2 | import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language |
| 3 | +import semmle.code.csharp.ir.implementation.raw.IR |
| 4 | + |
| 5 | +newtype TValueNumber = |
| 6 | + TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) { |
| 7 | + variableAddressValueNumber(_, irFunc, var) |
| 8 | + } or |
| 9 | + TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) { |
| 10 | + initializeParameterValueNumber(_, irFunc, var) |
| 11 | + } or |
| 12 | + TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or |
| 13 | + TConstantValueNumber(IRFunction irFunc, IRType type, string value) { |
| 14 | + constantValueNumber(_, irFunc, type, value) |
| 15 | + } or |
| 16 | + TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { |
| 17 | + stringConstantValueNumber(_, irFunc, type, value) |
| 18 | + } or |
| 19 | + TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) { |
| 20 | + fieldAddressValueNumber(_, irFunc, field, objectAddress) |
| 21 | + } or |
| 22 | + TBinaryValueNumber( |
| 23 | + IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand, |
| 24 | + TValueNumber rightOperand |
| 25 | + ) { |
| 26 | + binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) |
| 27 | + } or |
| 28 | + TPointerArithmeticValueNumber( |
| 29 | + IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand, |
| 30 | + TValueNumber rightOperand |
| 31 | + ) { |
| 32 | + pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) |
| 33 | + } or |
| 34 | + TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) { |
| 35 | + unaryValueNumber(_, irFunc, opcode, type, operand) |
| 36 | + } or |
| 37 | + TInheritanceConversionValueNumber( |
| 38 | + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, |
| 39 | + TValueNumber operand |
| 40 | + ) { |
| 41 | + inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) |
| 42 | + } or |
| 43 | + TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } |
| 44 | + |
| 45 | +/** |
| 46 | + * A `CopyInstruction` whose source operand's value is congruent to the definition of that source |
| 47 | + * operand. |
| 48 | + * For example: |
| 49 | + * ``` |
| 50 | + * Point p = { 1, 2 }; |
| 51 | + * Point q = p; |
| 52 | + * int a = p.x; |
| 53 | + * ``` |
| 54 | + * The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that |
| 55 | + * definition because it accesses the exact same memory. |
| 56 | + * The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not |
| 57 | + * congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`. |
| 58 | + */ |
| 59 | +private class CongruentCopyInstruction extends CopyInstruction { |
| 60 | + CongruentCopyInstruction() { |
| 61 | + this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +/** |
| 66 | + * Holds if this library knows how to assign a value number to the specified instruction, other than |
| 67 | + * a `unique` value number that is never shared by multiple instructions. |
| 68 | + */ |
| 69 | +private predicate numberableInstruction(Instruction instr) { |
| 70 | + instr instanceof VariableAddressInstruction |
| 71 | + or |
| 72 | + instr instanceof InitializeParameterInstruction |
| 73 | + or |
| 74 | + instr instanceof InitializeThisInstruction |
| 75 | + or |
| 76 | + instr instanceof ConstantInstruction |
| 77 | + or |
| 78 | + instr instanceof StringConstantInstruction |
| 79 | + or |
| 80 | + instr instanceof FieldAddressInstruction |
| 81 | + or |
| 82 | + instr instanceof BinaryInstruction |
| 83 | + or |
| 84 | + instr instanceof UnaryInstruction and not instr instanceof CopyInstruction |
| 85 | + or |
| 86 | + instr instanceof PointerArithmeticInstruction |
| 87 | + or |
| 88 | + instr instanceof CongruentCopyInstruction |
| 89 | +} |
| 90 | + |
| 91 | +private predicate variableAddressValueNumber( |
| 92 | + VariableAddressInstruction instr, IRFunction irFunc, IRVariable var |
| 93 | +) { |
| 94 | + instr.getEnclosingIRFunction() = irFunc and |
| 95 | + instr.getIRVariable() = var |
| 96 | +} |
| 97 | + |
| 98 | +private predicate initializeParameterValueNumber( |
| 99 | + InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var |
| 100 | +) { |
| 101 | + instr.getEnclosingIRFunction() = irFunc and |
| 102 | + instr.getIRVariable() = var |
| 103 | +} |
| 104 | + |
| 105 | +private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { |
| 106 | + instr.getEnclosingIRFunction() = irFunc |
| 107 | +} |
| 108 | + |
| 109 | +private predicate constantValueNumber( |
| 110 | + ConstantInstruction instr, IRFunction irFunc, IRType type, string value |
| 111 | +) { |
| 112 | + instr.getEnclosingIRFunction() = irFunc and |
| 113 | + instr.getResultIRType() = type and |
| 114 | + instr.getValue() = value |
| 115 | +} |
| 116 | + |
| 117 | +private predicate stringConstantValueNumber( |
| 118 | + StringConstantInstruction instr, IRFunction irFunc, IRType type, string value |
| 119 | +) { |
| 120 | + instr.getEnclosingIRFunction() = irFunc and |
| 121 | + instr.getResultIRType() = type and |
| 122 | + instr.getValue().getValue() = value |
| 123 | +} |
| 124 | + |
| 125 | +private predicate fieldAddressValueNumber( |
| 126 | + FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, |
| 127 | + TValueNumber objectAddress |
| 128 | +) { |
| 129 | + instr.getEnclosingIRFunction() = irFunc and |
| 130 | + instr.getField() = field and |
| 131 | + tvalueNumber(instr.getObjectAddress()) = objectAddress |
| 132 | +} |
| 133 | + |
| 134 | +private predicate binaryValueNumber( |
| 135 | + BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand, |
| 136 | + TValueNumber rightOperand |
| 137 | +) { |
| 138 | + instr.getEnclosingIRFunction() = irFunc and |
| 139 | + not instr instanceof PointerArithmeticInstruction and |
| 140 | + instr.getOpcode() = opcode and |
| 141 | + instr.getResultIRType() = type and |
| 142 | + tvalueNumber(instr.getLeft()) = leftOperand and |
| 143 | + tvalueNumber(instr.getRight()) = rightOperand |
| 144 | +} |
| 145 | + |
| 146 | +private predicate pointerArithmeticValueNumber( |
| 147 | + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, |
| 148 | + int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
| 149 | +) { |
| 150 | + instr.getEnclosingIRFunction() = irFunc and |
| 151 | + instr.getOpcode() = opcode and |
| 152 | + instr.getResultIRType() = type and |
| 153 | + instr.getElementSize() = elementSize and |
| 154 | + tvalueNumber(instr.getLeft()) = leftOperand and |
| 155 | + tvalueNumber(instr.getRight()) = rightOperand |
| 156 | +} |
| 157 | + |
| 158 | +private predicate unaryValueNumber( |
| 159 | + UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand |
| 160 | +) { |
| 161 | + instr.getEnclosingIRFunction() = irFunc and |
| 162 | + not instr instanceof InheritanceConversionInstruction and |
| 163 | + not instr instanceof CopyInstruction and |
| 164 | + instr.getOpcode() = opcode and |
| 165 | + instr.getResultIRType() = type and |
| 166 | + tvalueNumber(instr.getUnary()) = operand |
| 167 | +} |
| 168 | + |
| 169 | +private predicate inheritanceConversionValueNumber( |
| 170 | + InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, |
| 171 | + Language::Class baseClass, Language::Class derivedClass, TValueNumber operand |
| 172 | +) { |
| 173 | + instr.getEnclosingIRFunction() = irFunc and |
| 174 | + instr.getOpcode() = opcode and |
| 175 | + instr.getBaseClass() = baseClass and |
| 176 | + instr.getDerivedClass() = derivedClass and |
| 177 | + tvalueNumber(instr.getUnary()) = operand |
| 178 | +} |
| 179 | + |
| 180 | +/** |
| 181 | + * Holds if `instr` should be assigned a unique value number because this library does not know how |
| 182 | + * to determine if two instances of that instruction are equivalent. |
| 183 | + */ |
| 184 | +private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { |
| 185 | + instr.getEnclosingIRFunction() = irFunc and |
| 186 | + not instr.getResultIRType() instanceof IRVoidType and |
| 187 | + not numberableInstruction(instr) |
| 188 | +} |
| 189 | + |
| 190 | +/** |
| 191 | + * Gets the value number assigned to `instr`, if any. Returns at most one result. |
| 192 | + */ |
| 193 | +cached |
| 194 | +TValueNumber tvalueNumber(Instruction instr) { |
| 195 | + result = nonUniqueValueNumber(instr) |
| 196 | + or |
| 197 | + exists(IRFunction irFunc | |
| 198 | + uniqueValueNumber(instr, irFunc) and |
| 199 | + result = TUniqueValueNumber(irFunc, instr) |
| 200 | + ) |
| 201 | +} |
| 202 | + |
| 203 | +/** |
| 204 | + * Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique |
| 205 | + * value number. |
| 206 | + */ |
| 207 | +private TValueNumber nonUniqueValueNumber(Instruction instr) { |
| 208 | + exists(IRFunction irFunc | |
| 209 | + irFunc = instr.getEnclosingIRFunction() and |
| 210 | + ( |
| 211 | + exists(IRVariable var | |
| 212 | + variableAddressValueNumber(instr, irFunc, var) and |
| 213 | + result = TVariableAddressValueNumber(irFunc, var) |
| 214 | + ) |
| 215 | + or |
| 216 | + exists(IRVariable var | |
| 217 | + initializeParameterValueNumber(instr, irFunc, var) and |
| 218 | + result = TInitializeParameterValueNumber(irFunc, var) |
| 219 | + ) |
| 220 | + or |
| 221 | + initializeThisValueNumber(instr, irFunc) and |
| 222 | + result = TInitializeThisValueNumber(irFunc) |
| 223 | + or |
| 224 | + exists(IRType type, string value | |
| 225 | + constantValueNumber(instr, irFunc, type, value) and |
| 226 | + result = TConstantValueNumber(irFunc, type, value) |
| 227 | + ) |
| 228 | + or |
| 229 | + exists(IRType type, string value | |
| 230 | + stringConstantValueNumber(instr, irFunc, type, value) and |
| 231 | + result = TStringConstantValueNumber(irFunc, type, value) |
| 232 | + ) |
| 233 | + or |
| 234 | + exists(Language::Field field, TValueNumber objectAddress | |
| 235 | + fieldAddressValueNumber(instr, irFunc, field, objectAddress) and |
| 236 | + result = TFieldAddressValueNumber(irFunc, field, objectAddress) |
| 237 | + ) |
| 238 | + or |
| 239 | + exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand | |
| 240 | + binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and |
| 241 | + result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) |
| 242 | + ) |
| 243 | + or |
| 244 | + exists(Opcode opcode, IRType type, TValueNumber operand | |
| 245 | + unaryValueNumber(instr, irFunc, opcode, type, operand) and |
| 246 | + result = TUnaryValueNumber(irFunc, opcode, type, operand) |
| 247 | + ) |
| 248 | + or |
| 249 | + exists( |
| 250 | + Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand |
| 251 | + | |
| 252 | + inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and |
| 253 | + result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) |
| 254 | + ) |
| 255 | + or |
| 256 | + exists( |
| 257 | + Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand, |
| 258 | + TValueNumber rightOperand |
| 259 | + | |
| 260 | + pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, |
| 261 | + rightOperand) and |
| 262 | + result = |
| 263 | + TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand) |
| 264 | + ) |
| 265 | + or |
| 266 | + // The value number of a copy is just the value number of its source value. |
| 267 | + result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue()) |
| 268 | + ) |
| 269 | + ) |
| 270 | +} |
0 commit comments