Skip to content

Commit cac8808

Browse files
weirdsmileyGabor Marton
authored and
Gabor Marton
committed
[analyzer][solver] Introduce reasoning for not equal to operator
Prior to this, the solver was only able to verify whether two symbols are equal/unequal, only when constants were involved. This patch allows the solver to work over ranges as well. Reviewed By: steakhal, martong Differential Revision: https://reviews.llvm.org/D106102 Patch by: @manas (Manas Gupta)
1 parent 74c6895 commit cac8808

File tree

2 files changed

+88
-13
lines changed

2 files changed

+88
-13
lines changed

clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

+42-13
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
#include "llvm/ADT/FoldingSet.h"
2121
#include "llvm/ADT/ImmutableSet.h"
2222
#include "llvm/ADT/STLExtras.h"
23-
#include "llvm/ADT/StringExtras.h"
2423
#include "llvm/ADT/SmallSet.h"
24+
#include "llvm/ADT/StringExtras.h"
2525
#include "llvm/Support/Compiler.h"
2626
#include "llvm/Support/raw_ostream.h"
2727
#include <algorithm>
@@ -955,18 +955,7 @@ class SymbolicRangeInferrer
955955
}
956956

957957
RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
958-
RangeSet RHS, QualType T) {
959-
switch (Op) {
960-
case BO_Or:
961-
return VisitBinaryOperator<BO_Or>(LHS, RHS, T);
962-
case BO_And:
963-
return VisitBinaryOperator<BO_And>(LHS, RHS, T);
964-
case BO_Rem:
965-
return VisitBinaryOperator<BO_Rem>(LHS, RHS, T);
966-
default:
967-
return infer(T);
968-
}
969-
}
958+
RangeSet RHS, QualType T);
970959

971960
//===----------------------------------------------------------------------===//
972961
// Ranges and operators
@@ -1231,6 +1220,29 @@ class SymbolicRangeInferrer
12311220
// Range-based reasoning about symbolic operations
12321221
//===----------------------------------------------------------------------===//
12331222

1223+
template <>
1224+
RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_NE>(RangeSet LHS,
1225+
RangeSet RHS,
1226+
QualType T) {
1227+
// When both the RangeSets are non-overlapping then all possible pairs of
1228+
// (x, y) in LHS, RHS respectively, will satisfy expression (x != y).
1229+
if ((LHS.getMaxValue() < RHS.getMinValue()) ||
1230+
(LHS.getMinValue() > RHS.getMaxValue())) {
1231+
return getTrueRange(T);
1232+
}
1233+
1234+
// If both RangeSets contain only one Point which is equal then the
1235+
// expression will always return true.
1236+
if ((LHS.getMinValue() == RHS.getMaxValue()) &&
1237+
(LHS.getMaxValue() == RHS.getMaxValue()) &&
1238+
(LHS.getMinValue() == RHS.getMinValue())) {
1239+
return getFalseRange(T);
1240+
}
1241+
1242+
// In all other cases, the resulting range cannot be deduced.
1243+
return infer(T);
1244+
}
1245+
12341246
template <>
12351247
RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Or>(Range LHS, Range RHS,
12361248
QualType T) {
@@ -1391,6 +1403,23 @@ RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Rem>(Range LHS,
13911403
return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
13921404
}
13931405

1406+
RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
1407+
BinaryOperator::Opcode Op,
1408+
RangeSet RHS, QualType T) {
1409+
switch (Op) {
1410+
case BO_NE:
1411+
return VisitBinaryOperator<BO_NE>(LHS, RHS, T);
1412+
case BO_Or:
1413+
return VisitBinaryOperator<BO_Or>(LHS, RHS, T);
1414+
case BO_And:
1415+
return VisitBinaryOperator<BO_And>(LHS, RHS, T);
1416+
case BO_Rem:
1417+
return VisitBinaryOperator<BO_Rem>(LHS, RHS, T);
1418+
default:
1419+
return infer(T);
1420+
}
1421+
}
1422+
13941423
//===----------------------------------------------------------------------===//
13951424
// Constraint manager implementation details
13961425
//===----------------------------------------------------------------------===//

clang/test/Analysis/constant-folding.c

+46
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,49 @@ void testRemainderRules(unsigned int a, unsigned int b, int c, int d) {
281281
clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
282282
}
283283
}
284+
285+
void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) {
286+
// Checks when ranges are not overlapping
287+
if (u1 <= 10 && u2 >= 20) {
288+
// u1: [0,10], u2: [20,UINT_MAX]
289+
clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}}
290+
}
291+
292+
if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
293+
// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
294+
clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}}
295+
}
296+
297+
// Checks when ranges are completely overlapping and have more than one point
298+
if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
299+
// u1: [20,50], u2: [20,50]
300+
clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
301+
}
302+
303+
if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
304+
// s1: [-20,20], s2: [-20,20]
305+
clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}}
306+
}
307+
308+
// Checks when ranges are partially overlapping
309+
if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
310+
// u1: [100,200], u2: [150,300]
311+
clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
312+
}
313+
314+
if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
315+
// s1: [-80,-50], s2: [-100,-75]
316+
clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
317+
}
318+
319+
// Checks for ranges which are subset of one-another
320+
if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
321+
// u1: [500,1000], u2: [750,1000]
322+
clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}}
323+
}
324+
325+
if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
326+
// s1: [-1000,-500], s2: [-500,-750]
327+
clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
328+
}
329+
}

0 commit comments

Comments
 (0)