diff --git a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt index 2904aa87cc..83ec63be30 100644 --- a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt +++ b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt @@ -179,6 +179,7 @@ open class ValueEvaluator( "<" -> handleLess(lhsValue, rhsValue, expr) "<=" -> handleLEq(lhsValue, rhsValue, expr) "==" -> handleEq(lhsValue, rhsValue, expr) + "!=" -> handleNEq(lhsValue, rhsValue, expr) else -> cannotEvaluate(expr as Node, this) } } @@ -298,6 +299,14 @@ open class ValueEvaluator( } } + private fun handleNEq(lhsValue: Any?, rhsValue: Any?, expr: Expression?): Any? { + return if (lhsValue is Number && rhsValue is Number) { + lhsValue.compareTo(rhsValue) != 0 + } else { + cannotEvaluate(expr, this) + } + } + /** * We handle some basic unary operators. These also affect pointers and dereferences for * languages that support them. @@ -361,12 +370,17 @@ open class ValueEvaluator( } protected open fun handleConditionalExpression(expr: ConditionalExpression, depth: Int): Any? { + var condition = expr.condition + // Assume that condition is a binary operator - if (expr.condition is BinaryOperator) { - val lhs = evaluateInternal((expr.condition as? BinaryOperator)?.lhs, depth) - val rhs = evaluateInternal((expr.condition as? BinaryOperator)?.rhs, depth) + if (condition is BinaryOperator) { + val lhs = evaluateInternal(condition.lhs, depth) + val rhs = evaluateInternal(condition.rhs, depth) + + // Compute the effect of the comparison + val comparison = computeBinaryOpEffect(lhs, rhs, condition) - return if (lhs == rhs) { + return if (comparison == true) { evaluateInternal(expr.thenExpression, depth + 1) } else { evaluateInternal(expr.elseExpression, depth + 1) diff --git a/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluatorTest.kt b/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluatorTest.kt index 500144e2ab..1f93f8153a 100644 --- a/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluatorTest.kt +++ b/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluatorTest.kt @@ -177,7 +177,7 @@ class ValueEvaluatorTest { val main = mainClass.functions["main"] assertNotNull(main) - val s = main.refs("s").last() + val s = main.refs("s").lastOrNull() assertNotNull(s) var value = s.evaluate() @@ -186,7 +186,7 @@ class ValueEvaluatorTest { value = s.evaluate(MultiValueEvaluator()) assertEquals(setOf("big!?", "small!?"), value) - val i = main.refs("i").last() + val i = main.refs("i").lastOrNull() assertNotNull(i) value = i.evaluate() @@ -741,15 +741,15 @@ class ValueEvaluatorTest { @Test fun testHandleUnary() { - with(TestHandler(TestLanguageFrontend())) { - val neg = newUnaryOperator("-", false, true) + with(TestLanguageFrontend()) { + val neg = newUnaryOperator("-", postfix = false, prefix = true) neg.input = newLiteral(3, primitiveType("int")) assertEquals(-3, ValueEvaluator().evaluate(neg)) neg.input = newLiteral(3.5, primitiveType("double")) assertEquals(-3.5, ValueEvaluator().evaluate(neg)) - val plusplus = newUnaryOperator("++", true, false) + val plusplus = newUnaryOperator("++", postfix = true, prefix = false) plusplus.input = newLiteral(3, primitiveType("int")) assertEquals(4, ValueEvaluator().evaluate(plusplus)) @@ -759,7 +759,7 @@ class ValueEvaluatorTest { plusplus.input = newLiteral(3.5f, primitiveType("float")) assertEquals(4.5f, ValueEvaluator().evaluate(plusplus)) - val minusminus = newUnaryOperator("--", true, false) + val minusminus = newUnaryOperator("--", postfix = true, prefix = false) minusminus.input = newLiteral(3, primitiveType("int")) assertEquals(2, ValueEvaluator().evaluate(minusminus)) @@ -770,4 +770,36 @@ class ValueEvaluatorTest { assertEquals(2.5f, ValueEvaluator().evaluate(minusminus)) } } + + @Test + fun testHandleConditionalExpression() { + with(TestLanguageFrontend()) { + val a = newVariableDeclaration("a") + a.initializer = newLiteral(1) + + val aRef = newReference("a") + aRef.refersTo = a + aRef.prevDFG = mutableSetOf(a) + + // handle not equals + var comparison = newBinaryOperator("!=") + comparison.lhs = aRef + comparison.rhs = newLiteral(1) + + var cond = newConditionalExpression(comparison, newLiteral(2), aRef) + assertEquals(1, cond.evaluate()) + + // handle equals + comparison = newBinaryOperator("==") + comparison.lhs = aRef + comparison.rhs = newLiteral(1) + + cond = newConditionalExpression(comparison, newLiteral(2), aRef) + assertEquals(2, cond.evaluate()) + + // handle invalid + cond = newConditionalExpression(newProblemExpression(), newLiteral(2), aRef) + assertEquals("{}", cond.evaluate()) + } + } }