python: handle guards compared to boolean literals

This commit is contained in:
yoff
2026-02-08 09:35:13 +01:00
parent 8488039fb9
commit 7351e82c92
3 changed files with 45 additions and 9 deletions

View File

@@ -595,7 +595,8 @@ ControlFlowNode guardNode(ConditionBlock conditionBlock, boolean flipped) {
result = conditionBlock.getLastNode() and
flipped = false
or
// Recursive case: if a guard node is a `not`-expression,
// Recursive cases:
// if a guard node is a `not`-expression,
// the operand is also a guard node, but with inverted polarity.
exists(UnaryExprNode notNode |
result = notNode.getOperand() and
@@ -603,6 +604,33 @@ ControlFlowNode guardNode(ConditionBlock conditionBlock, boolean flipped) {
|
notNode = guardNode(conditionBlock, flipped.booleanNot())
)
or
// if a guard node is compared to a boolean literal,
// the other operand is also a guard node,
// but with polarity depending on the literal (and on the comparison).
exists(CompareNode cmpNode, Cmpop op, ControlFlowNode b, boolean bool |
(
cmpNode.operands(result, op, b) or
cmpNode.operands(b, op, result)
) and
not result.getNode() instanceof BooleanLiteral and
(
// comparing to the boolean
(op instanceof Eq or op instanceof Is) and
// `bool` is the value being compared against, here the value of `b`
b.getNode().(BooleanLiteral).booleanValue() = bool
or
// comparing to the negation of the boolean
(op instanceof NotEq or op instanceof IsNot) and
// again, `bool` is the value being compared against, but here it is the value of `not b`
b.getNode().(BooleanLiteral).booleanValue() = bool.booleanNot()
)
|
// if `bool` is true, we should preserve `flipped`, otherwise we should flip it
// `flipped xor (not bool)` achieves that.
flipped in [true, false] and
cmpNode = guardNode(conditionBlock, flipped.booleanXor(bool.booleanNot()))
)
}
/**

View File

@@ -22,4 +22,12 @@ isSanitizer
| test_logical.py:176:24:176:24 | ControlFlowNode for s |
| test_logical.py:185:24:185:24 | ControlFlowNode for s |
| test_logical.py:193:24:193:24 | ControlFlowNode for s |
| test_logical.py:199:28:199:28 | ControlFlowNode for s |
| test_logical.py:206:28:206:28 | ControlFlowNode for s |
| test_logical.py:211:28:211:28 | ControlFlowNode for s |
| test_logical.py:214:28:214:28 | ControlFlowNode for s |
| test_logical.py:219:28:219:28 | ControlFlowNode for s |
| test_logical.py:226:28:226:28 | ControlFlowNode for s |
| test_logical.py:231:28:231:28 | ControlFlowNode for s |
| test_logical.py:234:28:234:28 | ControlFlowNode for s |
| test_reference.py:31:28:31:28 | ControlFlowNode for s |

View File

@@ -196,42 +196,42 @@ def test_comparison_with_bool():
s = TAINTED_STRING
if is_safe(s) == True:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
else:
ensure_tainted(s) # $ tainted
if is_safe(s) == False:
ensure_tainted(s) # $ tainted
else:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
if is_safe(s) != True:
ensure_tainted(s) # $ tainted
else:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
if is_safe(s) != False:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
else:
ensure_tainted(s) # $ tainted
if is_safe(s) is True:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
else:
ensure_tainted(s) # $ tainted
if is_safe(s) is False:
ensure_tainted(s) # $ tainted
else:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
if is_safe(s) is not True:
ensure_tainted(s) # $ tainted
else:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
if is_safe(s) is not False:
ensure_not_tainted(s) # $ SPURIOUS: tainted
ensure_not_tainted(s)
else:
ensure_tainted(s) # $ tainted