diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 9829388ef177..7828f5a36744 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -62,12 +62,20 @@ private predicate ignoreConstantValue(Operation op) { op instanceof BitwiseXorExpr } +/** Holds if `expr` contains an address-of expression that EDG may have constant-folded. */ +private predicate containsAddressOf(Expr expr) { + expr instanceof AddressOfExpr + or + containsAddressOf(expr.getAChild()) +} + /** * Holds if `expr` is a constant of a type that can be replaced directly with * its value in the IR. This does not include address constants as we have no * means to express those as QL values. */ predicate isIRConstant(Expr expr) { + not containsAddressOf(expr) and exists(expr.getValue()) and // We avoid constant folding certain operations since it's often useful to // mark one of those as a source in dataflow, and if the operation is diff --git a/cpp/ql/test/library-tests/ir/address_constant_folding/test.c b/cpp/ql/test/library-tests/ir/address_constant_folding/test.c new file mode 100644 index 000000000000..3055b0ae32dc --- /dev/null +++ b/cpp/ql/test/library-tests/ir/address_constant_folding/test.c @@ -0,0 +1,22 @@ +#define NULL ((void*)0) + +int global_var; + +void test_address_null_comparison(int param_var) { + int local_var; + + if (&global_var == NULL) {} // $ VariableAddress=global_var + if (&global_var != NULL) {} // $ VariableAddress=global_var + if (&global_var) {} // $ VariableAddress=global_var + if (!&global_var) {} // $ VariableAddress=global_var + + if (&local_var == NULL) {} // $ VariableAddress=local_var + if (&local_var != NULL) {} // $ VariableAddress=local_var + if (&local_var) {} // $ VariableAddress=local_var + if (!&local_var) {} // $ VariableAddress=local_var + + if (¶m_var == NULL) {} // $ VariableAddress=param_var + if (¶m_var != NULL) {} // $ VariableAddress=param_var + if (¶m_var) {} // $ VariableAddress=param_var + if (!¶m_var) {} // $ VariableAddress=param_var +} diff --git a/cpp/ql/test/library-tests/ir/address_constant_folding/variable_addresses.expected b/cpp/ql/test/library-tests/ir/address_constant_folding/variable_addresses.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cpp/ql/test/library-tests/ir/address_constant_folding/variable_addresses.ql b/cpp/ql/test/library-tests/ir/address_constant_folding/variable_addresses.ql new file mode 100644 index 000000000000..6f4458475e97 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/address_constant_folding/variable_addresses.ql @@ -0,0 +1,20 @@ +import cpp +private import utils.test.InlineExpectationsTest +private import semmle.code.cpp.ir.IR + +module VariableAddressTest implements TestSig { + string getARelevantTag() { result = "VariableAddress" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(VariableAddressInstruction vai | + not vai.getAst() instanceof DeclarationEntry and + not vai.getAst() instanceof Parameter and + tag = "VariableAddress" and + value = vai.getAstVariable().getName() and + element = vai.toString() and + location = vai.getLocation() + ) + } +} + +import MakeTest