Author: Gábor Tóthvári Date: 2026-10-16T14:10:11+02:00 New Revision: 72e7990f50005ddbc032ca22d1b77e0f9b1f10ae
URL: https://github.com/llvm/llvm-project/commit/72e7990f50005ddbc032ca22d1b77e0f9b1f10ae DIFF: https://github.com/llvm/llvm-project/commit/72e7990f50005ddbc032ca22d1b77e0f9b1f10ae.diff LOG: [Liveness][analyzer] Fix liveness of binary logical operators and their subexpressions (#231419) Issue #227349 reported a clang static analyzer false negative, where a division by zero error is not found in the following code: ``` int f(bool b) { bool condition = (b && b || b && b); int y = condition ? 0 : 1; return 1 / y; } ``` It turned out, that the expressions `b` were prematurely considered dead and, as a result, their associated values were getting purged from the environment. This caused the path where the denominator `y` is zero to be lost. This patch makes sure that the children of binary logical operators have their liveness properly handled. Added: Modified: clang/lib/Analysis/LiveVariables.cpp clang/test/Analysis/div-zero.cpp clang/test/Analysis/live-stmts.cpp Removed: ################################################################################ diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp index c9e547ac85380..666d33ebecdea 100644 --- a/clang/lib/Analysis/LiveVariables.cpp +++ b/clang/lib/Analysis/LiveVariables.cpp @@ -339,6 +339,15 @@ void TransferFunctions::Visit(Stmt *S) { AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr()); return; } + case Stmt::BinaryOperatorClass: { + auto const *BO = cast<BinaryOperator>(S); + if (BO->isLogicalOp()) { + AddAllConditionalTerms(val.liveExprs, LV.ESetFact, BO->getLHS()); + AddAllConditionalTerms(val.liveExprs, LV.ESetFact, BO->getRHS()); + return; + } + break; + } } // Mark all child expressions live -- "normal" case. diff --git a/clang/test/Analysis/div-zero.cpp b/clang/test/Analysis/div-zero.cpp index 51ea25e828a18..c756f24dec86b 100644 --- a/clang/test/Analysis/div-zero.cpp +++ b/clang/test/Analysis/div-zero.cpp @@ -12,6 +12,44 @@ int fooPR10616 (int qX ) { } +namespace issue227349 { + int f(bool b) { + bool condition = (b && b || b && b); + int y = condition ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} + } + + int f2(bool b1, bool b2, bool b3, bool b4) { + bool condition = (b1 && b2 || b3 && b4); + int y = condition ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} + } + + int f3(bool b) { + bool condition = (b && b || b && b) && (b && b || b && b); + int y = condition ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} + } + + int f4(bool b) { + bool condition = (b && b && b && b); + int y = condition ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} + } + + int f5(bool b) { + bool condition = (b || b || b || b); + int y = condition ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} + } + + int f6(bool b1, bool b2, bool b3, bool b4) { + bool condition = (b1 || b2 && b3 && b4); + int y = condition ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} + } +} + namespace GH148875 { struct A { int x; diff --git a/clang/test/Analysis/live-stmts.cpp b/clang/test/Analysis/live-stmts.cpp index ca2ff6da8b133..136d7b2c23c50 100644 --- a/clang/test/Analysis/live-stmts.cpp +++ b/clang/test/Analysis/live-stmts.cpp @@ -304,3 +304,190 @@ int logicalOpInTernary(bool b) { // CHECK: IntegerLiteral {{.*}} 'int' 0 // CHECK-EMPTY: // CHECK: IntegerLiteral {{.*}} 'int' 1 + +int shortCircuitingBinaryOperator(bool b) { + bool condition = (b && b || b && b); + int y = condition ? 0 : 1; + return 1 / y; +} + +// CHECK: [ B0 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B1 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B2 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue Var {{.*}} 'condition' '_Bool' +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B3 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue Var {{.*}} 'condition' '_Bool' +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B4 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue Var {{.*}} 'condition' '_Bool' +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B5 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B6 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B7 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B8 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK-NEXT: [ B9 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: BinaryOperator {{.*}} '_Bool' '&&' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Bool' <LValueToRValue> +// CHECK-NEXT: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
