Skip to content

Commit 19b47c6

Browse files
committed
[StaticAnalyzer] early return if sym is concrete on assuming
This could deduce some complex syms derived from simple ones whose values could be constrainted to be concrete during execution, thus reducing some overconstrainted states. This commit also fix 'unix.StdCLibraryFunctions' crash due to these overconstrainted states being added to the graph, which is marked as sink node (PosteriorlyOverconstrained). The 'assume' API is used in non-dual style so the checker should protectively test whether these newly added nodes are actually impossible.
1 parent 1bf385f commit 19b47c6

File tree

6 files changed

+78
-5
lines changed

6 files changed

+78
-5
lines changed

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,8 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
13541354
if (BR.isInteresting(ArgSVal))
13551355
OS << Msg;
13561356
}));
1357+
if (NewNode->isSink())
1358+
break;
13571359
}
13581360
}
13591361
}

clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ ConstraintManager::assumeDualImpl(ProgramStateRef &State,
7474
// it might happen that a Checker uncoditionally uses one of them if the
7575
// other is a nullptr. This may also happen with the non-dual and
7676
// adjacent `assume(true)` and `assume(false)` calls. By implementing
77-
// assume in therms of assumeDual, we can keep our API contract there as
77+
// assume in terms of assumeDual, we can keep our API contract there as
7878
// well.
7979
return ProgramStatePair(StInfeasible, StInfeasible);
8080
}

clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ RangedConstraintManager::~RangedConstraintManager() {}
2323
ProgramStateRef RangedConstraintManager::assumeSym(ProgramStateRef State,
2424
SymbolRef Sym,
2525
bool Assumption) {
26-
Sym = simplify(State, Sym);
26+
SVal SimplifiedVal = simplifyToSVal(State, Sym);
27+
if (SimplifiedVal.isConstant()) {
28+
bool Feasible = SimplifiedVal.isZeroConstant() ? !Assumption : Assumption;
29+
return Feasible ? State : nullptr;
30+
}
31+
32+
if (SymbolRef SimplifiedSym = SimplifiedVal.getAsSymbol())
33+
Sym = SimplifiedSym;
2734

2835
// Handle SymbolData.
2936
if (isa<SymbolData>(Sym))
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %clang_analyze_cc1 %s \
2+
// RUN: -analyzer-checker=debug.ExprInspection \
3+
// RUN: -verify
4+
5+
void clang_analyzer_eval(int);
6+
7+
void test_derived_sym_simplification_on_assume(int s0, int s1) {
8+
int elem = s0 + s1 + 1;
9+
if (elem-- == 0) // elem = s0 + s1
10+
return;
11+
12+
if (elem-- == 0) // elem = s0 + s1 - 1
13+
return;
14+
15+
if (s0 < 1) // s0: [1, 2147483647]
16+
return;
17+
if (s1 < 1) // s0: [1, 2147483647]
18+
return;
19+
20+
if (elem-- == 0) // elem = s0 + s1 - 2
21+
return;
22+
23+
if (s0 > 1) // s0: [-2147483648, 0] U [1, 2147483647] => s0 = 0
24+
return;
25+
26+
if (s1 > 1) // s1: [-2147483648, 0] U [1, 2147483647] => s1 = 0
27+
return;
28+
29+
// elem = s0 + s1 - 2 should be 0
30+
clang_analyzer_eval(elem); // expected-warning{{FALSE}}
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_analyze_cc1 %s \
2+
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
3+
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \
4+
// RUN: -analyzer-checker=debug.ExprInspection \
5+
// RUN: -triple x86_64-unknown-linux-gnu \
6+
// RUN: -verify
7+
8+
// expected-no-diagnostics
9+
10+
#include "Inputs/std-c-library-functions-POSIX.h"
11+
12+
void _add_one_to_index_C(int *indices, int *shape) {
13+
int k = 1;
14+
for (; k >= 0; k--)
15+
if (indices[k] < shape[k])
16+
indices[k]++;
17+
else
18+
indices[k] = 0;
19+
}
20+
21+
void PyObject_CopyData_sptr(char *i, char *j, int *indices, int itemsize,
22+
int *shape, struct sockaddr *restrict sa) {
23+
int elements = 1;
24+
for (int k = 0; k < 2; k++)
25+
elements += shape[k];
26+
27+
// no contradiction after 3 iterations when 'elements' could be
28+
// simplified to 0
29+
while (elements--) {
30+
_add_one_to_index_C(indices, shape);
31+
getnameinfo(sa, 10, i, itemsize, i, itemsize, 0);
32+
}
33+
}

clang/test/Analysis/symbol-simplification-fixpoint-two-iterations.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ void test(int a, int b, int c, int d) {
2828
return;
2929
clang_analyzer_printState();
3030
// CHECK: "constraints": [
31-
// CHECK-NEXT: { "symbol": "(reg_$0<int a>) != (reg_$3<int d>)", "range": "{ [0, 0] }" },
31+
// CHECK-NEXT: { "symbol": "((reg_$0<int a>) + (reg_$2<int c>)) != (reg_$3<int d>)", "range": "{ [0, 0] }" },
3232
// CHECK-NEXT: { "symbol": "reg_$1<int b>", "range": "{ [0, 0] }" },
3333
// CHECK-NEXT: { "symbol": "reg_$2<int c>", "range": "{ [0, 0] }" }
3434
// CHECK-NEXT: ],
3535
// CHECK-NEXT: "equivalence_classes": [
36-
// CHECK-NEXT: [ "(reg_$0<int a>) != (reg_$3<int d>)" ],
37-
// CHECK-NEXT: [ "reg_$0<int a>", "reg_$3<int d>" ],
36+
// CHECK-NEXT: [ "((reg_$0<int a>) + (reg_$2<int c>)) != (reg_$3<int d>)" ],
37+
// CHECK-NEXT: [ "(reg_$0<int a>) + (reg_$2<int c>)", "reg_$3<int d>" ],
3838
// CHECK-NEXT: [ "reg_$2<int c>" ]
3939
// CHECK-NEXT: ],
4040
// CHECK-NEXT: "disequality_info": null,

0 commit comments

Comments
 (0)