feat(S604): make truthiness unknown in special case

This commit is contained in:
Igor Drokin 2025-10-27 21:21:05 +02:00
parent 96b60c11d9
commit be1c7ab9f3
3 changed files with 26 additions and 7 deletions

View file

@ -22,3 +22,15 @@ foo(shell=lambda: 0)
foo(shell=f"{b''}") foo(shell=f"{b''}")
x = 1 x = 1
foo(shell=f"{x=}") foo(shell=f"{x=}")
print(bool(dict(shell=f"{f""!s}")["shell"]))
# Unknown truthiness
print(bool(dict(shell=f"{"x":.0}")["shell"]))
class C:
def __gt__(self, other):
return ""
print(bool(dict(shell=f"{C() > C()}")["shell"]))

View file

@ -90,4 +90,5 @@ S604 Function call with truthy `shell` parameter identified, security issue
23 | x = 1 23 | x = 1
24 | foo(shell=f"{x=}") 24 | foo(shell=f"{x=}")
| ^^^ | ^^^
25 | print(bool(dict(shell=f"{f""!s}")["shell"]))
| |

View file

@ -1357,7 +1357,9 @@ fn is_non_empty_f_string(expr: &ast::ExprFString) -> bool {
Expr::ListComp(_) => true, Expr::ListComp(_) => true,
Expr::SetComp(_) => true, Expr::SetComp(_) => true,
Expr::DictComp(_) => true, Expr::DictComp(_) => true,
Expr::Compare(_) => true, // Compare can return any value, even empty string
// https://docs.python.org/3/reference/datamodel.html#object.__ge__
Expr::Compare(_) => false,
Expr::NumberLiteral(_) => true, Expr::NumberLiteral(_) => true,
Expr::BooleanLiteral(_) => true, Expr::BooleanLiteral(_) => true,
Expr::NoneLiteral(_) => true, Expr::NoneLiteral(_) => true,
@ -1399,12 +1401,16 @@ fn is_non_empty_f_string(expr: &ast::ExprFString) -> bool {
expr.value.iter().any(|part| match part { expr.value.iter().any(|part| match part {
ast::FStringPart::Literal(string_literal) => !string_literal.is_empty(), ast::FStringPart::Literal(string_literal) => !string_literal.is_empty(),
ast::FStringPart::FString(f_string) => { ast::FStringPart::FString(f_string) => {
f_string.elements.iter().all(|element| match element { !f_string.elements.is_empty()
InterpolatedStringElement::Literal(string_literal) => !string_literal.is_empty(), && f_string.elements.iter().all(|element| match element {
InterpolatedStringElement::Interpolation(f_string) => { InterpolatedStringElement::Literal(string_literal) => {
f_string.debug_text.is_some() || inner(&f_string.expression) !string_literal.is_empty()
} }
}) InterpolatedStringElement::Interpolation(f_string) => {
f_string.format_spec.is_none()
&& (f_string.debug_text.is_some() || inner(&f_string.expression))
}
})
} }
}) })
} }