[clang] ba92b27 - [analyzer] Improved RangeSet::Negate support of unsigned ranges

2020-05-25 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-05-25T18:52:22+03:00
New Revision: ba92b274225fc78dc15e8dc0076f71e7a8b5d084

URL: 
https://github.com/llvm/llvm-project/commit/ba92b274225fc78dc15e8dc0076f71e7a8b5d084
DIFF: 
https://github.com/llvm/llvm-project/commit/ba92b274225fc78dc15e8dc0076f71e7a8b5d084.diff

LOG: [analyzer] Improved RangeSet::Negate support of unsigned ranges

Summary:
This fixes https://bugs.llvm.org/show_bug.cgi?id=41588
RangeSet Negate function shall handle unsigned ranges as well as signed ones.
RangeSet getRangeForMinusSymbol function shall use wider variety of ranges, not 
only concrete value ranges.
RangeSet Intersect functions shall not produce assertions.

Changes:
Improved safety of RangeSet::Intersect function. Added isEmpty() check to 
prevent an assertion.
Added support of handling unsigned ranges to RangeSet::Negate and 
RangeSet::getRangeForMinusSymbol.
Extended RangeSet::getRangeForMinusSymbol to return not only range sets with 
single value [n,n], but with wide ranges [n,m].
Added unit test for Negate function.
Added regression tests for unsigned values.

Differential Revision: https://reviews.llvm.org/D77802

Added: 
clang/unittests/StaticAnalyzer/RangeSetTest.cpp

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/constraint_manager_negate_difference.c
clang/unittests/StaticAnalyzer/CMakeLists.txt

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 9752a0e22832..137e2cefe5a0 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -155,11 +155,11 @@ bool RangeSet::pin(llvm::APSInt &Lower, llvm::APSInt 
&Upper) const {
 // or, alternatively, /removing/ all integers between Upper and Lower.
 RangeSet RangeSet::Intersect(BasicValueFactory &BV, Factory &F,
  llvm::APSInt Lower, llvm::APSInt Upper) const {
-  if (!pin(Lower, Upper))
-return F.getEmptySet();
-
   PrimRangeSet newRanges = F.getEmptySet();
 
+  if (isEmpty() || !pin(Lower, Upper))
+return newRanges;
+
   PrimRangeSet::iterator i = begin(), e = end();
   if (Lower <= Upper)
 IntersectInRange(BV, F, Lower, Upper, newRanges, i, e);
@@ -190,33 +190,78 @@ RangeSet RangeSet::Intersect(BasicValueFactory &BV, 
Factory &F,
   return newRanges;
 }
 
-// Turn all [A, B] ranges to [-B, -A]. Ranges [MIN, B] are turned to range set
-// [MIN, MIN] U [-B, MAX], when MIN and MAX are the minimal and the maximal
-// signed values of the type.
+// Turn all [A, B] ranges to [-B, -A], when "-" is a C-like unary minus
+// operation under the values of the type.
+//
+// We also handle MIN because applying unary minus to MIN does not change it.
+// Example 1:
+// char x = -128;// -128 is a MIN value in a range of 'char'
+// char y = -x;  // y: -128
+// Example 2:
+// unsigned char x = 0;  // 0 is a MIN value in a range of 'unsigned char'
+// unsigned char y = -x; // y: 0
+//
+// And it makes us to separate the range
+// like [MIN, N] to [MIN, MIN] U [-N,MAX].
+// For instance, whole range is {-128..127} and subrange is [-128,-126],
+// thus [-128,-127,-126,.] negates to [-128,.,126,127].
+//
+// Negate restores disrupted ranges on bounds,
+// e.g. [MIN, B] => [MIN, MIN] U [-B, MAX] => [MIN, B].
 RangeSet RangeSet::Negate(BasicValueFactory &BV, Factory &F) const {
   PrimRangeSet newRanges = F.getEmptySet();
 
-  for (iterator i = begin(), e = end(); i != e; ++i) {
-const llvm::APSInt &from = i->From(), &to = i->To();
-const llvm::APSInt &newTo = (from.isMinSignedValue() ?
- BV.getMaxValue(from) :
- BV.getValue(- from));
-if (to.isMaxSignedValue() && !newRanges.isEmpty() &&
-newRanges.begin()->From().isMinSignedValue()) {
-  assert(newRanges.begin()->To().isMinSignedValue() &&
- "Ranges should not overlap");
-  assert(!from.isMinSignedValue() && "Ranges should not overlap");
-  const llvm::APSInt &newFrom = newRanges.begin()->From();
-  newRanges =
-F.add(F.remove(newRanges, *newRanges.begin()), Range(newFrom, newTo));
-} else if (!to.isMinSignedValue()) {
-  const llvm::APSInt &newFrom = BV.getValue(- to);
-  newRanges = F.add(newRanges, Range(newFrom, newTo));
-}
-if (from.isMinSignedValue()) {
-  newRanges = F.add(newRanges, Range(BV.getMinValue(from),
- BV.getMinValue(from)));
+  if (isEmpty())
+return newRanges;
+
+  const llvm::APSInt sampleValue = getMinValue();
+  const llvm::APSInt &MIN = BV.getMinValue(sampleValue);
+  const llvm::APSInt &MAX = BV.getMaxValue(sampleValue);
+
+  // Handle a special case for MIN value.
+  iterator i = begin();
+  const llvm::APSInt &from = i->From();

[clang] 6bbaa62 - [analyzer] Add support for IE of keyboard and mouse navigation in HTML report

2020-05-26 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-05-27T09:04:30+03:00
New Revision: 6bbaa62d26b6061c93eb62c82048c14014ab7bd7

URL: 
https://github.com/llvm/llvm-project/commit/6bbaa62d26b6061c93eb62c82048c14014ab7bd7
DIFF: 
https://github.com/llvm/llvm-project/commit/6bbaa62d26b6061c93eb62c82048c14014ab7bd7.diff

LOG: [analyzer] Add support for IE of keyboard and mouse navigation in HTML 
report

IE throws errors while using key and mouse navigation through the error path 
tips.
querySelectorAll method returns NodeList. NodeList belongs to browser API. IE 
doesn't have forEach among NodeList's methods. At the same time Array is a 
JavaScript object and can be used instead. The fix is in the converting 
NodeList into Array and keeps using forEach method as before.

Checked in IE11, Chrome and Opera.

Differential Revision: https://reviews.llvm.org/D80444

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp 
b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 184fdcfb3d4b..bc7c41d039c4 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -1070,8 +1070,13 @@ StringRef 
HTMLDiagnostics::generateKeyboardNavigationJavascript() {
 

[clang] e1741e3 - [analyzer] Reasoning about comparison expressions in RangeConstraintManager

2020-06-15 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-06-15T18:35:15+03:00
New Revision: e1741e34e00b27cbf9acc9b2eb85b71d2676e968

URL: 
https://github.com/llvm/llvm-project/commit/e1741e34e00b27cbf9acc9b2eb85b71d2676e968
DIFF: 
https://github.com/llvm/llvm-project/commit/e1741e34e00b27cbf9acc9b2eb85b71d2676e968.diff

LOG: [analyzer] Reasoning about comparison expressions in RangeConstraintManager

Summary:

Implemented RangeConstraintManager::getRangeForComparisonSymbol which handles 
comparison operators.
RangeConstraintManager::getRangeForComparisonSymbol cares about the sanity of 
comparison expressions sequences helps reasonably to branch an exploded graph.
It can significantly reduce the graph and speed up the analysis. For more 
details, please, see the differential revision.

This fixes https://bugs.llvm.org/show_bug.cgi?id=13426

Differential Revision: https://reviews.llvm.org/D78933

Added: 
clang/test/Analysis/constraint_manager_conditions.cpp

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index a14b29c6face..08413c080d41 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -24,6 +24,79 @@
 using namespace clang;
 using namespace ento;
 
+// This class can be extended with other tables which will help to reason
+// about ranges more precisely.
+class OperatorRelationsTable {
+  static_assert(BO_LT < BO_GT && BO_GT < BO_LE && BO_LE < BO_GE &&
+BO_GE < BO_EQ && BO_EQ < BO_NE,
+"This class relies on operators order. Rework it otherwise.");
+
+public:
+  enum TriStateKind {
+False = 0,
+True,
+Unknown,
+  };
+
+private:
+  // CmpOpTable holds states which represent the corresponding range for
+  // branching an exploded graph. We can reason about the branch if there is
+  // a previously known fact of the existence of a comparison expression with
+  // operands used in the current expression.
+  // E.g. assuming (x < y) is true that means (x != y) is surely true.
+  // if (x previous_operation y)  // <| !=  | >
+  //   if (x operation y) // !=   | >   | <
+  // tristate // True | Unknown | False
+  //
+  // CmpOpTable represents next:
+  // __|< |> |<=|>=|==|!=|UnknownX2|
+  // < |1 |0 |* |0 |0 |* |1|
+  // > |0 |1 |0 |* |0 |* |1|
+  // <=|1 |0 |1 |* |1 |* |0|
+  // >=|0 |1 |* |1 |1 |* |0|
+  // ==|0 |0 |* |* |1 |0 |1|
+  // !=|1 |1 |* |* |0 |1 |0|
+  //
+  // Columns stands for a previous operator.
+  // Rows stands for a current operator.
+  // Each row has exactly two `Unknown` cases.
+  // UnknownX2 means that both `Unknown` previous operators are met in code,
+  // and there is a special column for that, for example:
+  // if (x >= y)
+  //   if (x != y)
+  // if (x <= y)
+  //   False only
+  static constexpr size_t CmpOpCount = BO_NE - BO_LT + 1;
+  const TriStateKind CmpOpTable[CmpOpCount][CmpOpCount + 1] = {
+  // <  >  <= >= == !=UnknownX2
+  {True, False, Unknown, False, False, Unknown, True}, // <
+  {False, True, False, Unknown, False, Unknown, True}, // >
+  {True, False, True, Unknown, True, Unknown, False},  // <=
+  {False, True, Unknown, True, True, Unknown, False},  // >=
+  {False, False, Unknown, Unknown, True, False, True}, // ==
+  {True, True, Unknown, Unknown, False, True, False},  // !=
+  };
+
+  static size_t getIndexFromOp(BinaryOperatorKind OP) {
+return static_cast(OP - BO_LT);
+  }
+
+public:
+  constexpr size_t getCmpOpCount() const { return CmpOpCount; }
+
+  static BinaryOperatorKind getOpFromIndex(size_t Index) {
+return static_cast(Index + BO_LT);
+  }
+
+  TriStateKind getCmpOpState(BinaryOperatorKind CurrentOP,
+ BinaryOperatorKind QueriedOP) const {
+return CmpOpTable[getIndexFromOp(CurrentOP)][getIndexFromOp(QueriedOP)];
+  }
+
+  TriStateKind getCmpOpStateForUnknownX2(BinaryOperatorKind CurrentOP) const {
+return CmpOpTable[getIndexFromOp(CurrentOP)][CmpOpCount];
+  }
+};
 
//===--===//
 //   RangeSet implementation
 
//===--===//
@@ -390,6 +463,13 @@ class SymbolicRangeInferrer
 if (RangeAssociatedWithNegatedSym)
   return RangeAssociatedWithNegatedSym->Negate(ValueFactory, RangeFactory);
 
+// If Sym is a comparison expression (except <=>),
+// find any other comparisons with the same operands.
+// See function description.
+const RangeSet CmpRangeSet = getRangeForComparisonSymbol(State, Sym);
+if (!CmpRangeSet.isEmpty())
+ 

[clang] 01f9388 - [analyzer] Handle `\l` symbol in string literals in exploded-graph-rewriter

2020-06-22 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-06-22T13:44:27+03:00
New Revision: 01f9388d95aca2cc86ed6b2794e199ef55d16e91

URL: 
https://github.com/llvm/llvm-project/commit/01f9388d95aca2cc86ed6b2794e199ef55d16e91
DIFF: 
https://github.com/llvm/llvm-project/commit/01f9388d95aca2cc86ed6b2794e199ef55d16e91.diff

LOG: [analyzer] Handle `\l` symbol in string literals in exploded-graph-rewriter

Summary:
Handle `\l` separately because a string literal can be in code like 
"string\\literal" with the `\l` inside. Also on Windows macros __FILE__ 
produces specific delimiters `\` and a directory or file may starts with the 
letter `l`.

Fix:
Use regex for replacing all `\l` (like `,\l`, `}\l`, `[\l`) except `\\l`, 
because a literal as a rule contains multiple `\` before `\l`.

Differential Revision: https://reviews.llvm.org/D82092

Added: 
clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp

Modified: 
clang/utils/analyzer/exploded-graph-rewriter.py

Removed: 




diff  --git 
a/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp 
b/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp
new file mode 100644
index ..b84c49974530
--- /dev/null
+++ b/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp
@@ -0,0 +1,28 @@
+// CAUTION: The name of this file should start with `l` for proper tests.
+// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
+// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
+// RUN: -analyzer-checker=core \
+// RUN: -analyzer-dump-egraph=%t.dot %s
+// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
+// REQUIRES: asserts
+
+void test1() {
+  // Here __FILE__ macros produces a string with `\` delimiters on Windows
+  // and the name of the file starts with `l`.
+  char text[] = __FILE__;
+}
+
+void test2() {
+  // Here `\l` is in the middle of the literal.
+  char text[] = "string\\literal";
+}
+
+void test() {
+  test1();
+  test2();
+}
+
+// This test is passed if exploded_graph_rewriter handles dot file without 
errors.
+// CHECK: digraph "ExplodedGraph"
+// CHECK: 
clang\\test\\Analysis\\exploded-graph-rewriter\\l_name_starts_with_l.cpp";
+// CHECK: char text[] = "string\\literal";

diff  --git a/clang/utils/analyzer/exploded-graph-rewriter.py 
b/clang/utils/analyzer/exploded-graph-rewriter.py
index bae863cb6d04..54d87addd3da 100755
--- a/clang/utils/analyzer/exploded-graph-rewriter.py
+++ b/clang/utils/analyzer/exploded-graph-rewriter.py
@@ -368,8 +368,7 @@ def add_raw_line(self, raw_line):
 self.root_id = node_id
 # Note: when writing tests you don't need to escape everything,
 # even though in a valid dot file everything is escaped.
-node_label = result.group(2).replace('\\l', '') \
-.replace(' ', '') \
+node_label = result.group(2).replace(' ', '') \
 .replace('\\"', '"') \
 .replace('\\{', '{') \
 .replace('\\}', '}') \
@@ -378,6 +377,13 @@ def add_raw_line(self, raw_line):
 .replace('\\<', '<') \
 .replace('\\>', '>') \
 .rstrip(',')
+# Handle `\l` separately because a string literal can be in code
+# like "string\\literal" with the `\l` inside.
+# Also on Windows macros __FILE__ produces specific delimiters `\`
+# and a directory or file may starts with the letter `l`.
+# Find all `\l` (like `,\l`, `}\l`, `[\l`) except `\\l`,
+# because the literal as a rule containes multiple `\` before `\l`.
+node_label = re.sub(r'(?', '>') \
- .replace('\\l', '') \
  .replace('|', '\\|')
+s = re.sub(r'(?', s)
 if self._gray_mode:
 s = re.sub(r'', '', s)
 s = re.sub(r'', '', s)



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 632088c - [analyzer] Handle `\l` symbol in string literals in exploded-graph-rewriter

2020-06-22 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-06-22T14:19:13+03:00
New Revision: 632088c7e84a7ff625c8c67cdc392849b1358f5d

URL: 
https://github.com/llvm/llvm-project/commit/632088c7e84a7ff625c8c67cdc392849b1358f5d
DIFF: 
https://github.com/llvm/llvm-project/commit/632088c7e84a7ff625c8c67cdc392849b1358f5d.diff

LOG: [analyzer] Handle `\l` symbol in string literals in exploded-graph-rewriter

Fix for test due to build-bot complains.

Added: 


Modified: 
clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp

Removed: 




diff  --git 
a/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp 
b/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp
index b84c49974530..a5d2443ea0b4 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp
+++ b/clang/test/Analysis/exploded-graph-rewriter/l_name_starts_with_l.cpp
@@ -24,5 +24,5 @@ void test() {
 
 // This test is passed if exploded_graph_rewriter handles dot file without 
errors.
 // CHECK: digraph "ExplodedGraph"
-// CHECK: 
clang\\test\\Analysis\\exploded-graph-rewriter\\l_name_starts_with_l.cpp";
+// CHECK: shape=record,label=<
 // CHECK: char text[] = "string\\literal";



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] be9c581 - [analyzer] Remove forbidden characters from a filename for a graph dump on Windows

2020-06-22 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-06-22T17:27:20+03:00
New Revision: be9c5818351bf99a193edbc82e4dc25ab5206a44

URL: 
https://github.com/llvm/llvm-project/commit/be9c5818351bf99a193edbc82e4dc25ab5206a44
DIFF: 
https://github.com/llvm/llvm-project/commit/be9c5818351bf99a193edbc82e4dc25ab5206a44.diff

LOG: [analyzer] Remove forbidden characters from a filename for a graph dump on 
Windows

Summary:
Windows forbidden file path characters are used in a field `file`, while 
creating a dump `dot` file using an argument -analyzer-dump-egraph. It 
specifically relates to angle brackets when using ``, 
``, `` values in filenames. It causes that script 
exploded-graph-rewriter.py incorrectly parses the dump.

Fix:
Remove forbidden characters from filename for Windows platform, when creating 
graph dump file.

Differential Revision: https://reviews.llvm.org/D82103

Added: 
clang/test/Analysis/exploded-graph-rewriter/win_path_forbidden_chars.cpp

Modified: 
clang/include/clang/Basic/JsonSupport.h

Removed: 




diff  --git a/clang/include/clang/Basic/JsonSupport.h 
b/clang/include/clang/Basic/JsonSupport.h
index 1b118b45a049..8b02e440df44 100644
--- a/clang/include/clang/Basic/JsonSupport.h
+++ b/clang/include/clang/Basic/JsonSupport.h
@@ -13,7 +13,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/raw_ostream.h"
-
+#include 
 
 namespace clang {
 
@@ -98,7 +98,16 @@ inline void printSourceLocationAsJson(raw_ostream &Out, 
SourceLocation Loc,
 if (AddBraces)
   Out << "{ ";
 std::string filename(PLoc.getFilename());
-#ifdef _WIN32 // Handle windows-specific path delimiters.
+#ifdef _WIN32
+// Remove forbidden Windows path characters
+auto RemoveIt =
+std::remove_if(filename.begin(), filename.end(), [](auto Char) {
+  static const char ForbiddenChars[] = "<>*?\"|";
+  return std::find(std::begin(ForbiddenChars), 
std::end(ForbiddenChars),
+   Char) != std::end(ForbiddenChars);
+});
+filename.erase(RemoveIt, filename.end());
+// Handle windows-specific path delimiters.
 std::replace(filename.begin(), filename.end(), '\\', '/');
 #endif
 Out << "\"line\": " << PLoc.getLine()

diff  --git 
a/clang/test/Analysis/exploded-graph-rewriter/win_path_forbidden_chars.cpp 
b/clang/test/Analysis/exploded-graph-rewriter/win_path_forbidden_chars.cpp
new file mode 100644
index ..4eac964a4f44
--- /dev/null
+++ b/clang/test/Analysis/exploded-graph-rewriter/win_path_forbidden_chars.cpp
@@ -0,0 +1,20 @@
+// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
+// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
+// RUN: -analyzer-checker=core \
+// RUN: -analyzer-dump-egraph=%t.dot %s
+// RUN: %exploded_graph_rewriter --verbose %t.dot 2>&1 | FileCheck %s
+// REQUIRES: asserts
+// UNSUPPORTED: !windows
+
+// Angle brackets shall not be presented in the field `file`,
+// because exploded_graph_rewriter handles it as a file path
+// and such symbols are forbidden on Windows platform.
+
+void test() {
+  // This produces angle brackets.
+  char text[] = __FILE__;
+}
+
+// This test is passed if exploded_graph_rewriter handles dot file without 
errors.
+// CHECK: DEBUG:root:Line: digraph "Exploded Graph"
+// CHECK: \"file\": \"scratch space\"



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 86e1b73 - [analyzer] Simplify function SVal::getAsSymbolicExpression and similar ones

2020-08-03 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-08-03T15:03:35+03:00
New Revision: 86e1b73507f3738f10eefb580d7c5e9adf17c6c0

URL: 
https://github.com/llvm/llvm-project/commit/86e1b73507f3738f10eefb580d7c5e9adf17c6c0
DIFF: 
https://github.com/llvm/llvm-project/commit/86e1b73507f3738f10eefb580d7c5e9adf17c6c0.diff

LOG: [analyzer] Simplify function SVal::getAsSymbolicExpression and similar ones

Summary: Simplify functions SVal::getAsSymbolicExpression SVal::getAsSymExpr 
and SVal::getAsSymbol. After revision I concluded that 
`getAsSymbolicExpression` and `getAsSymExpr` repeat functionality of 
`getAsSymbol`, thus them can be removed.

Fix: Remove functions SVal::getAsSymbolicExpression and SVal::getAsSymExpr.

Differential Revision: https://reviews.llvm.org/D85034

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
clang/lib/StaticAnalyzer/Checkers/Taint.cpp
clang/lib/StaticAnalyzer/Core/ProgramState.cpp
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/lib/StaticAnalyzer/Core/SVals.cpp
clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 1abe29782088..a640d815a5ce 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -182,12 +182,6 @@ class SVal {
   /// should continue to the base regions if the region is not symbolic.
   SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
 
-  /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
-  ///  return that expression.  Otherwise return NULL.
-  const SymExpr *getAsSymbolicExpression() const;
-
-  const SymExpr *getAsSymExpr() const;
-
   const MemRegion *getAsRegion() const;
 
   /// printJson - Pretty-prints in JSON format.

diff  --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp 
b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 13836f08a61e..78b3c209ad6b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -406,7 +406,7 @@ ProgramStateRef 
ObjCDeallocChecker::evalAssume(ProgramStateRef State, SVal Cond,
   if (State->get().isEmpty())
 return State;
 
-  auto *CondBSE = dyn_cast_or_null(Cond.getAsSymExpr());
+  auto *CondBSE = dyn_cast_or_null(Cond.getAsSymbol());
   if (!CondBSE)
 return State;
 

diff  --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 87477e96d2d1..a157ee2da5df 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -509,7 +509,7 @@ ProgramStateRef 
MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State,
   if (AMap.isEmpty())
 return State;
 
-  auto *CondBSE = dyn_cast_or_null(Cond.getAsSymExpr());
+  auto *CondBSE = dyn_cast_or_null(Cond.getAsSymbol());
   if (!CondBSE)
 return State;
   BinaryOperator::Opcode OpCode = CondBSE->getOpcode();

diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 1d8ed90f7590..854646a8779d 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -177,7 +177,7 @@ static Optional 
findArgIdxOfSymbol(ProgramStateRef CurrSt,
   for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
 if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
   if (const auto *TR = dyn_cast(MR))
-if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym)
+if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym)
   return Idx;
 
   return None;

diff  --git a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp 
b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
index 5b46ffb656cf..71b2ab834a07 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
@@ -148,7 +148,7 @@ bool taint::isTainted(ProgramStateRef State, const Stmt *S,
 }
 
 bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) {
-  if (const SymExpr *Sym = V.getAsSymExpr())
+  if (SymbolRef Sym = V.getAsSymbol())
 return isTainted(State, Sym, Kind);
   if (const MemRegion *Reg = V.getAsRegion())
 return isTainted(State, Reg, 

[clang] 21fa82d - [analyzer] Introduce minor refactoring of SVal::getSubKind function

2020-08-03 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-08-03T15:05:08+03:00
New Revision: 21fa82d5c63c30c745d5181889329084ac6d2767

URL: 
https://github.com/llvm/llvm-project/commit/21fa82d5c63c30c745d5181889329084ac6d2767
DIFF: 
https://github.com/llvm/llvm-project/commit/21fa82d5c63c30c745d5181889329084ac6d2767.diff

LOG: [analyzer] Introduce minor refactoring of SVal::getSubKind function

Summary: `BaseMask` occupies the lowest bits. Effect of applying the mask is 
neutralized by right shift operation, thus making it useless.

Fix: Remove a redundant bitwise operation.

Differential Revision: https://reviews.llvm.org/D85026

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index a640d815a5ce..a561ac67bf78 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -80,7 +80,7 @@ class SVal {
 #define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
   };
-  enum { BaseBits = 2, BaseMask = 0x3 };
+  enum { BaseBits = 2, BaseMask = 0b11 };
 
 protected:
   const void *Data = nullptr;
@@ -116,7 +116,7 @@ class SVal {
 
   unsigned getRawKind() const { return Kind; }
   BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
-  unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
+  unsigned getSubKind() const { return Kind >> BaseBits; }
 
   // This method is required for using SVal in a FoldingSetNode.  It
   // extracts a unique signature for this SVal object.



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] f01ac8c - A test commit as a new contributor to verify commit access is OK.

2020-05-04 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-05-04T21:36:18+03:00
New Revision: f01ac8c6574344e9bc30fdf9aa357a51bb607961

URL: 
https://github.com/llvm/llvm-project/commit/f01ac8c6574344e9bc30fdf9aa357a51bb607961
DIFF: 
https://github.com/llvm/llvm-project/commit/f01ac8c6574344e9bc30fdf9aa357a51bb607961.diff

LOG: A test commit as a new contributor to verify commit access is OK.

Added: 


Modified: 
clang/test/Analysis/a_flaky_crash.cpp

Removed: 




diff  --git a/clang/test/Analysis/a_flaky_crash.cpp 
b/clang/test/Analysis/a_flaky_crash.cpp
index 04bd57883fce..f350c1e1280c 100644
--- a/clang/test/Analysis/a_flaky_crash.cpp
+++ b/clang/test/Analysis/a_flaky_crash.cpp
@@ -1,6 +1,6 @@
 // This code used to crash but unpredictably and rarely.
-// Even with the current set of run-lines, if a buildbot tells you that
-// you broke this test there's a chance that someone else broke it
+// Even with the current set of run-lines, if a buildbot tells you
+// that you broke this test there's a chance that someone else broke it
 // a few commits ago.
 
 struct S {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] ba8cda9 - [analyzer] Stability improvement for IteratorModeling

2020-05-06 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-05-06T14:16:39+03:00
New Revision: ba8cda989cf884d53596099dc38a0e5a2c351074

URL: 
https://github.com/llvm/llvm-project/commit/ba8cda989cf884d53596099dc38a0e5a2c351074
DIFF: 
https://github.com/llvm/llvm-project/commit/ba8cda989cf884d53596099dc38a0e5a2c351074.diff

LOG: [analyzer] Stability improvement for IteratorModeling

Summary:
Some function path may lead to crash.
Fixed using local variable outside the scope  through a pointer.
Fixed minor misspellings.
Added regression test.

This patch covers a bug https://bugs.llvm.org/show_bug.cgi?id=41485

Reviewed By: baloghadamsoftware

Differential Revision: https://reviews.llvm.org/D78289

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
clang/test/Analysis/iterator-range.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp 
b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index 2850c6d39322..e35918edbf89 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -402,7 +402,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, 
const Expr *CE,
   if (!Cont)
 return;
 
-  // At least one of the iterators have recorded positions. If one of them has
+  // At least one of the iterators has recorded positions. If one of them does
   // not then create a new symbol for the offset.
   SymbolRef Sym;
   if (!LPos || !RPos) {
@@ -422,7 +422,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, 
const Expr *CE,
 RPos = getIteratorPosition(State, RVal);
   }
 
-  // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol
+  // We cannot make assumptions on `UnknownVal`. Let us conjure a symbol
   // instead.
   if (RetVal.isUnknown()) {
 auto &SymMgr = C.getSymbolManager();
@@ -532,8 +532,9 @@ void 
IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C,
 return;
 
   const auto *value = &RHS;
+  SVal val;
   if (auto loc = RHS.getAs()) {
-const auto val = State->getRawSVal(*loc);
+val = State->getRawSVal(*loc);
 value = &val;
   }
 

diff  --git a/clang/test/Analysis/iterator-range.cpp 
b/clang/test/Analysis/iterator-range.cpp
index bdfb04ba3a8c..ad8ce92ecfb8 100644
--- a/clang/test/Analysis/iterator-range.cpp
+++ b/clang/test/Analysis/iterator-range.cpp
@@ -810,6 +810,19 @@ void prev_0_end(const std::vector &V) {
   auto j = std::prev(i, 0); // no-warning
 }
 
+// std::prev() with int* for checking Loc value argument
+namespace std {
+template 
+T prev(T, int *);
+}
+
+void prev_loc_value(const std::vector &V, int o) {
+
+  auto i = return_any_iterator(V.begin());
+  int *offset = &o;
+  auto j = std::prev(i, offset); // no-warning
+}
+
 //
 // Structure member dereference operators
 //



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 7e2b995 - [analyzer] [NFC] Add more test cases for equality tracking

2022-08-10 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2022-08-10T19:52:55+03:00
New Revision: 7e2b995e0cced8a292c3de9e4ec6a503223de38a

URL: 
https://github.com/llvm/llvm-project/commit/7e2b995e0cced8a292c3de9e4ec6a503223de38a
DIFF: 
https://github.com/llvm/llvm-project/commit/7e2b995e0cced8a292c3de9e4ec6a503223de38a.diff

LOG: [analyzer] [NFC] Add more test cases for equality tracking

Summary: Cover `ConstraintAssignor::assign(EquivalenceClass, RangeSet)` 
function with more regression tests.

Differential Revision: https://reviews.llvm.org/D131514

Added: 


Modified: 
clang/test/Analysis/equality_tracking.c

Removed: 




diff  --git a/clang/test/Analysis/equality_tracking.c 
b/clang/test/Analysis/equality_tracking.c
index 681453b1fe29b..e33b95700d002 100644
--- a/clang/test/Analysis/equality_tracking.c
+++ b/clang/test/Analysis/equality_tracking.c
@@ -8,6 +8,7 @@
 #define CHAR_MAX (char)(UCHAR_MAX & (UCHAR_MAX >> 1))
 #define CHAR_MIN (char)(UCHAR_MAX & ~(UCHAR_MAX >> 1))
 
+void clang_analyzer_value(int);
 void clang_analyzer_eval(int);
 void clang_analyzer_warnIfReached(void);
 
@@ -233,3 +234,139 @@ void implyDisequalityFromLT(int a, int b) {
 clang_analyzer_eval(a != b); // expected-warning{{TRUE}}
   }
 }
+
+void deletePointBefore(int x, int tmp) {
+  if(tmp == 0)
+if(x != tmp)
+ clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, -1], 
[1, 2147483647] }}}
+}
+
+void deletePointAfter(int x, int tmp) {
+  if(x != tmp)
+if(tmp == 2147483647)
+  clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 
2147483646] }}}
+}
+
+void deleteTwoPoints(int x, int tmp1, int tmp2) {
+  if(x != tmp1) {
+if (tmp1 == 42 && tmp2 == 87) {
+  clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 41], 
[43, 2147483647] }}}
+  if(x != tmp2)
+clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 
41], [43, 86], [88, 2147483647] }}}
+}
+  }
+}
+
+void deleteAllPoints(unsigned char x, unsigned char *arr) {
+
+#define cond(n) \
+arr[n##0] == n##0 && \
+arr[n##1] == n##1 && \
+arr[n##2] == n##2 && \
+arr[n##3] == n##3 && \
+arr[n##4] == n##4 && \
+arr[n##5] == n##5 && \
+arr[n##6] == n##6 && \
+arr[n##7] == n##7 && \
+arr[n##8] == n##8 && \
+arr[n##9] == n##9 && \
+
+#define condX(n) \
+arr[n##0] != x && \
+arr[n##1] != x && \
+arr[n##2] != x && \
+arr[n##3] != x && \
+arr[n##4] != x && \
+arr[n##5] != x && \
+arr[n##6] != x && \
+arr[n##7] != x && \
+arr[n##8] != x && \
+arr[n##9] != x && \
+
+  clang_analyzer_value(x); // expected-warning {{{ [0, 255] }}}
+  if (
+cond()  // 0  .. 9
+cond(1) // 10 .. 19
+cond(2) // 20 .. 29
+cond(3) // 30 .. 39
+cond(4) // 40 .. 49
+cond(5) // 50 .. 59
+cond(6) // 60 .. 69
+cond(7) // 70 .. 79
+cond(8) // 80 .. 89
+cond(9) // 90 .. 99
+cond(10) // 100 .. 209
+cond(11) // 110 .. 219
+cond(12) // 120 .. 229
+cond(13) // 130 .. 239
+cond(14) // 140 .. 249
+cond(15) // 150 .. 259
+cond(16) // 160 .. 269
+cond(17) // 170 .. 279
+cond(18) // 180 .. 289
+cond(19) // 190 .. 199
+cond(20) // 200 .. 209
+cond(21) // 210 .. 219
+cond(22) // 220 .. 229
+cond(23) // 230 .. 239
+cond(24) // 240 .. 249
+arr[250] == 250 &&
+arr[251] == 251 &&
+arr[252] == 252 &&
+arr[253] == 253 &&
+arr[254] == 254 &&
+arr[255] == 255
+) {
+if (
+  condX()  // 0  .. 9
+  condX(1) // 10 .. 19
+  condX(2) // 20 .. 29
+  condX(3) // 30 .. 39
+  condX(4) // 40 .. 49
+  condX(5) // 50 .. 59
+  condX(6) // 60 .. 69
+  condX(7) // 70 .. 79
+  condX(8) // 80 .. 89
+  condX(9) // 90 .. 99
+  condX(10) // 100 .. 209
+  condX(11) // 110 .. 219
+  condX(12) // 120 .. 229
+  condX(13) // 130 .. 239
+  condX(14) // 140 .. 249
+  condX(15) // 150 .. 259
+  condX(16) // 160 .. 269
+  condX(17) // 170 .. 279
+  condX(18) // 180 .. 289
+  condX(19) // 190 .. 199
+  condX(20) // 200 .. 209
+  condX(21) // 210 .. 219
+  condX(22) // 220 .. 229
+  condX(23) // 230 .. 239
+  arr[240] != x &&
+  arr[241] != x &&
+  arr[242] != x &&
+  arr[243] != x &&
+  arr[244] != x &&
+  arr[245] != x &&
+  arr[246] != x &&
+  arr[247] != x &&
+  arr[248] != x &&
+  arr[249] != x
+  ) {
+  clang_analyzer_value(x); // expected-warning {{{ [250, 255] }}}
+  if (
+  arr[250] != x &&
+  arr[251] != x &&
+  //skip arr[252]
+  arr[253] != x &&
+  arr[254] != x &&
+  arr[255] != x
+  ) {
+clang_analyzer_value(x); // expected-warning {{32s:252}}
+if (arr[252] != x) {
+  clang_analyzer_warnIfReached(); // unreachable
+}
+  }
+}
+  }
+}



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.o

[clang] e37726b - [analyzer] Implemented RangeSet::Factory::castTo function to perform promotions, truncations and conversions.

2022-04-19 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2022-04-19T22:34:03+03:00
New Revision: e37726beb22a8e3865e1f6fcdbb5cd4262786903

URL: 
https://github.com/llvm/llvm-project/commit/e37726beb22a8e3865e1f6fcdbb5cd4262786903
DIFF: 
https://github.com/llvm/llvm-project/commit/e37726beb22a8e3865e1f6fcdbb5cd4262786903.diff

LOG: [analyzer] Implemented RangeSet::Factory::castTo function to perform 
promotions, truncations and conversions.

Summary: Handle casts for ranges working similarly to APSIntType::apply 
function but for the whole range set. Support promotions, truncations and 
conversions.
Example:
promotion: char [0, 42] -> short [0, 42] -> int [0, 42] -> llong [0, 42]
truncation: llong [4295033088, 4295033130] -> int [65792, 65834] -> short [256, 
298] -> char [0, 42]
conversion: char [-42, 42] -> uint [0, 42]U[4294967254, 4294967295] -> 
short[-42, 42]

Differential Revision: https://reviews.llvm.org/D103094

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/unittests/StaticAnalyzer/RangeSetTest.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index 4b7d6054cd877..f1c50e721937b 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -21,8 +21,8 @@ class APSIntType {
   bool IsUnsigned;
 
 public:
-  APSIntType(uint32_t Width, bool Unsigned)
-: BitWidth(Width), IsUnsigned(Unsigned) {}
+  constexpr APSIntType(uint32_t Width, bool Unsigned)
+  : BitWidth(Width), IsUnsigned(Unsigned) {}
 
   /* implicit */ APSIntType(const llvm::APSInt &Value)
 : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {}

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index 6c487697bc551..49ea006e27aa5 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -237,6 +237,29 @@ class RangeSet {
 /// Complexity: O(N)
 /// where N = size(What)
 RangeSet negate(RangeSet What);
+/// Performs promotions, truncations and conversions of the given set.
+///
+/// This function is optimized for each of the six cast cases:
+/// - noop
+/// - conversion
+/// - truncation
+/// - truncation-conversion
+/// - promotion
+/// - promotion-conversion
+///
+/// NOTE: This function is NOT self-inverse for truncations, because of
+///   the higher bits loss:
+/// - castTo(castTo(OrigRangeOfInt, char), int) != OrigRangeOfInt.
+/// - castTo(castTo(OrigRangeOfChar, int), char) == OrigRangeOfChar.
+///   But it is self-inverse for all the rest casts.
+///
+/// Complexity:
+/// - Noop   O(1);
+/// - Truncation O(N^2);
+/// - Another case   O(N);
+/// where N = size(What)
+RangeSet castTo(RangeSet What, APSIntType Ty);
+RangeSet castTo(RangeSet What, QualType T);
 
 /// Return associated value factory.
 BasicValueFactory &getValueFactory() const { return ValueFactory; }
@@ -252,6 +275,22 @@ class RangeSet {
 /// containers are persistent (created via BasicValueFactory::getValue).
 ContainerType unite(const ContainerType &LHS, const ContainerType &RHS);
 
+/// This is a helper function for `castTo` method. Implies not to be used
+/// separately.
+/// Performs a truncation case of a cast operation.
+ContainerType truncateTo(RangeSet What, APSIntType Ty);
+
+/// This is a helper function for `castTo` method. Implies not to be used
+/// separately.
+/// Performs a conversion case and a promotion-conversion case for signeds
+/// of a cast operation.
+ContainerType convertTo(RangeSet What, APSIntType Ty);
+
+/// This is a helper function for `castTo` method. Implies not to be used
+/// separately.
+/// Performs a promotion for unsigneds only.
+ContainerType promoteTo(RangeSet What, APSIntType Ty);
+
 // Many operations include producing new APSInt values and that's why
 // we need this factory.
 BasicValueFactory &ValueFactory;
@@ -303,6 +342,10 @@ class RangeSet {
   /// Complexity: O(1)
   const llvm::APSInt &getMaxValue() const;
 
+  bool isUnsigned() const;
+  uint32_t getBitWidth() const;
+  APSIntType getAPSIntType() const;
+
   /// Test whether the given point is contained by any of the ranges.
   ///
   ///

[clang] 82f76c0 - [analyzer][NFC] Tidy up handler-functions in SymbolicRangeInferrer

2022-07-15 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2022-07-15T19:24:57+03:00
New Revision: 82f76c04774fbeb2313b84932afac478f010c8d0

URL: 
https://github.com/llvm/llvm-project/commit/82f76c04774fbeb2313b84932afac478f010c8d0
DIFF: 
https://github.com/llvm/llvm-project/commit/82f76c04774fbeb2313b84932afac478f010c8d0.diff

LOG: [analyzer][NFC] Tidy up handler-functions in SymbolicRangeInferrer

Summary: Sorted some handler-functions into more appropriate visitor functions 
of the SymbolicRangeInferrer.
- Spread `getRangeForNegatedSub` body over several visitor functions: 
`VisitSymExpr`, `VisitSymIntExpr`, `VisitSymSymExpr`.
- Moved `getRangeForComparisonSymbol` from `infer` to `VisitSymSymExpr`.

Differential Revision: https://reviews.llvm.org/D129678

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index e788a7a608302..8f1e3aa039759 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1213,13 +1213,21 @@ class SymbolicRangeInferrer
   }
 
   RangeSet VisitSymExpr(SymbolRef Sym) {
-// If we got to this function, the actual type of the symbolic
+if (Optional RS = getRangeForNegatedSym(Sym))
+  return *RS;
+// If we've reached this line, the actual type of the symbolic
 // expression is not supported for advanced inference.
 // In this case, we simply backoff to the default "let's simply
 // infer the range from the expression's type".
 return infer(Sym->getType());
   }
 
+  RangeSet VisitUnarySymExpr(const UnarySymExpr *USE) {
+if (Optional RS = getRangeForNegatedUnarySym(USE))
+  return *RS;
+return infer(USE->getType());
+  }
+
   RangeSet VisitSymIntExpr(const SymIntExpr *Sym) {
 return VisitBinaryOperator(Sym);
   }
@@ -1228,14 +1236,25 @@ class SymbolicRangeInferrer
 return VisitBinaryOperator(Sym);
   }
 
-  RangeSet VisitSymSymExpr(const SymSymExpr *Sym) {
+  RangeSet VisitSymSymExpr(const SymSymExpr *SSE) {
 return intersect(
 RangeFactory,
+// If Sym is a 
diff erence of symbols A - B, then maybe we have range
+// set stored for B - A.
+//
+// If we have range set stored for both A - B and B - A then
+// calculate the effective range set by intersecting the range set
+// for A - B and the negated range set of B - A.
+getRangeForNegatedSymSym(SSE),
+// If Sym is a comparison expression (except <=>),
+// find any other comparisons with the same operands.
+// See function description.
+getRangeForComparisonSymbol(SSE),
 // If Sym is (dis)equality, we might have some information
 // on that in our equality classes data structure.
-getRangeForEqualities(Sym),
+getRangeForEqualities(SSE),
 // And we should always check what we can get from the operands.
-VisitBinaryOperator(Sym));
+VisitBinaryOperator(SSE));
   }
 
 private:
@@ -1264,25 +1283,13 @@ class SymbolicRangeInferrer
   }
 
   RangeSet infer(SymbolRef Sym) {
-return intersect(
-RangeFactory,
-// Of course, we should take the constraint directly associated with
-// this symbol into consideration.
-getConstraint(State, Sym),
-// If Sym is a 
diff erence of symbols A - B, then maybe we have range
-// set stored for B - A.
-//
-// If we have range set stored for both A - B and B - A then
-// calculate the effective range set by intersecting the range set
-// for A - B and the negated range set of B - A.
-getRangeForNegatedSub(Sym),
-// If Sym is a comparison expression (except <=>),
-// find any other comparisons with the same operands.
-// See function description.
-getRangeForComparisonSymbol(Sym),
-// Apart from the Sym itself, we can infer quite a lot if we look
-// into subexpressions of Sym.
-Visit(Sym));
+return intersect(RangeFactory,
+ // Of course, we should take the constraint directly
+ // associated with this symbol into consideration.
+ getConstraint(State, Sym),
+ // Apart from the Sym itself, we can infer quite a lot if
+ // we look into subexpressions of Sym.
+ Visit(Sym));
   }
 
   RangeSet infer(EquivalenceClass Class) {
@@ -1443,38 +1450,53 @@ class SymbolicRangeInferrer
 return RangeFactory.deletePoint(Domain, IntType.getZeroValue());
   }
 
-  Optional getRangeForNegatedSub(SymbolRef Sym) {
+  template 
+  Optional getRangeForNegatedExpr(ProduceNegatedSymFunc F,
+QualType T) {
 // Do

[clang] bc08c3c - [analyzer] Add new function `clang_analyzer_value` to ExprInspectionChecker

2022-07-15 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2022-07-15T20:07:04+03:00
New Revision: bc08c3cb7f8e797fee14e96eedd3dc358608ada3

URL: 
https://github.com/llvm/llvm-project/commit/bc08c3cb7f8e797fee14e96eedd3dc358608ada3
DIFF: 
https://github.com/llvm/llvm-project/commit/bc08c3cb7f8e797fee14e96eedd3dc358608ada3.diff

LOG: [analyzer] Add new function `clang_analyzer_value` to ExprInspectionChecker

Summary: Introduce a new function 'clang_analyzer_value'. It emits a report 
that in turn prints a RangeSet or APSInt associated with SVal. If there is no 
associated value, prints "n/a".

Added: 
clang/test/Analysis/print-ranges.cpp

Modified: 
clang/docs/analyzer/developer-docs/DebugChecks.rst
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/SVals.cpp

Removed: 




diff  --git a/clang/docs/analyzer/developer-docs/DebugChecks.rst 
b/clang/docs/analyzer/developer-docs/DebugChecks.rst
index 7a837659576d9..d038cb5d7ccac 100644
--- a/clang/docs/analyzer/developer-docs/DebugChecks.rst
+++ b/clang/docs/analyzer/developer-docs/DebugChecks.rst
@@ -309,6 +309,33 @@ ExprInspection checks
   clang_analyzer_dumpExtent(a);   // expected-warning {{8 S64b}}
   clang_analyzer_dumpElementCount(a); // expected-warning {{2 S64b}}
 }
+
+- ``clang_analyzer_value(a single argument of integer or pointer type)``
+
+  Prints an associated value for the given argument.
+  Supported argument types are integers, enums and pointers.
+  The value can be represented either as a range set or as a concrete integer.
+  For the rest of the types function prints ``n/a`` (aka not available).
+  
+  **Note:** This function will print nothing for clang built with Z3 
constraint manager.
+  This may cause crashes of your tests. To manage this use one of the test 
constraining
+  techniques:
+  
+  * llvm-lit commands ``REQUIRES no-z3`` or ``UNSUPPORTED z3`` `See for 
details. `_
+  
+  * a preprocessor directive ``#ifndef ANALYZER_CM_Z3``
+  
+  * a clang command argument ``-analyzer-constraints=range``
+
+  Example usage::
+
+void print(char c, unsigned u) {
+  clang_analyzer_value(c); // expected-warning {{8s:{ [-128, 127] }}}
+  if(u != 42)
+ clang_analyzer_value(u); // expected-warning {{32u:{ [0, 41], [43, 
4294967295] }}}
+  else
+ clang_analyzer_value(u); // expected-warning {{32u:42}}
+}
 
 Statistics
 ==

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 22b405919bc17..ca6d7849d6210 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -119,6 +119,9 @@ class ConstraintManager {
  const char *NL, unsigned int Space,
  bool IsDot) const = 0;
 
+  virtual void printValue(raw_ostream &Out, ProgramStateRef State,
+  SymbolRef Sym) {}
+
   /// Convenience method to query the state to see if a symbol is null or
   /// not null, or if neither assumption can be made.
   ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {

diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 69f19f7d85655..c9c21fcf230ef 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -169,6 +169,11 @@ class SVal {
   /// should continue to the base regions if the region is not symbolic.
   SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
 
+  /// If this SVal is loc::ConcreteInt or nonloc::ConcreteInt,
+  /// return a pointer to APSInt which is held in it.
+  /// Otherwise, return nullptr.
+  const llvm::APSInt *getAsInteger() const;
+
   const MemRegion *getAsRegion() const;
 
   /// printJson - Pretty-prints in JSON format.

diff  --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 1c33648b2b321..ec1b0a70d7d3b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -40,6 +40,7 @@ class ExprInspectionChecker
   void analyzerNumTimesReached(const CallExpr *CE, CheckerContext &C) const;
   void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
   void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const;
+  void analyzerVal

[clang] a364987 - [analyzer][NFC] Use `SValVisitor` instead of explicit helper functions

2022-07-19 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2022-07-19T23:10:00+03:00
New Revision: a364987368a1c586088c62eb7cffcdef0f4ee852

URL: 
https://github.com/llvm/llvm-project/commit/a364987368a1c586088c62eb7cffcdef0f4ee852
DIFF: 
https://github.com/llvm/llvm-project/commit/a364987368a1c586088c62eb7cffcdef0f4ee852.diff

LOG: [analyzer][NFC] Use `SValVisitor` instead of explicit helper functions

Summary: Get rid of explicit function splitting in favor of specifically 
designed Visitor. Move logic from a family of `evalCastKind` and 
`evalCastSubKind` helper functions to `SValVisitor`.

Differential Revision: https://reviews.llvm.org/D130029

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 3d247e7887d70..1b9526324086d 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -75,39 +75,6 @@ class SValBuilder {
   /// The width of the scalar type used for array indices.
   const unsigned ArrayIndexWidth;
 
-  SVal evalCastKind(UndefinedVal V, QualType CastTy, QualType OriginalTy);
-  SVal evalCastKind(UnknownVal V, QualType CastTy, QualType OriginalTy);
-  SVal evalCastKind(Loc V, QualType CastTy, QualType OriginalTy);
-  SVal evalCastKind(NonLoc V, QualType CastTy, QualType OriginalTy);
-  SVal evalCastSubKind(loc::ConcreteInt V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(loc::GotoLabel V, QualType CastTy, QualType OriginalTy);
-  SVal evalCastSubKind(loc::MemRegionVal V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(nonloc::CompoundVal V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(nonloc::ConcreteInt V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(nonloc::LazyCompoundVal V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(nonloc::LocAsInteger V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(nonloc::SymbolVal V, QualType CastTy,
-   QualType OriginalTy);
-  SVal evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
-   QualType OriginalTy);
-  /// Reduce cast expression by removing redundant intermediate casts.
-  /// E.g.
-  /// - (char)(short)(int x) -> (char)(int x)
-  /// - (int)(int x) -> int x
-  ///
-  /// \param V -- SymbolVal, which pressumably contains SymbolCast or any 
symbol
-  /// that is applicable for cast operation.
-  /// \param CastTy -- QualType, which `V` shall be cast to.
-  /// \return SVal with simplified cast expression.
-  /// \note: Currently only support integral casts.
-  nonloc::SymbolVal simplifySymbolCast(nonloc::SymbolVal V, QualType CastTy);
-
 public:
   SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
   ProgramStateManager &stateMgr);

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index cf3d13ffb7ba7..d90e869196eb7 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -19,15 +19,16 @@
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/Type.h"
-#include "clang/Basic/LLVM.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/Basic/LLVM.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
@@ -617,517 +618,478 @@ SVal SValBuilder::evalIntegralCast(ProgramStateRef 
state, SVal val,
 }
 
 
//===--===//
-// Cast methods.
-// `evalCast` is the main method
-// `evalCastKind` and `evalCastSubKind` are helpers
+// Cast method.
+// `evalCast` and its helper `EvalCastVisitor`
 
//===--===//
 
-/// Cast a given SV

[clang] e674051 - [analyzer] [NFC] Introduce refactoring of PthreadLockChecker

2020-09-08 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-09-08T16:04:19+03:00
New Revision: e67405141836fcd88183863758eeb42f32e847a6

URL: 
https://github.com/llvm/llvm-project/commit/e67405141836fcd88183863758eeb42f32e847a6
DIFF: 
https://github.com/llvm/llvm-project/commit/e67405141836fcd88183863758eeb42f32e847a6.diff

LOG: [analyzer] [NFC] Introduce refactoring of PthreadLockChecker

Change capitalization of some names due to LLVM naming rules.
Change names of some variables to make them more speaking.
Rework similar bug reports into one common function.

Prepare code for the next patches to reduce unrelated changes.

Differential Revision: https://reviews.llvm.org/D87138

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 285d2da104f1..88e80c481a5a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -83,7 +83,7 @@ class PthreadLockChecker : public Checker PThreadCallbacks = {
   // Init.
   {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock},
@@ -167,46 +167,49 @@ class PthreadLockChecker : public 
Checker BT[],
+ const Expr *MtxExpr, CheckerKind CheckKind,
+ StringRef Desc) const;
 
   // Init.
   void InitAnyLock(const CallEvent &Call, CheckerContext &C,
-   CheckerKind checkkind) const;
-  void InitLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo,
-   SVal Lock, CheckerKind checkkind) const;
+   CheckerKind CheckKind) const;
+  void InitLockAux(const CallEvent &Call, CheckerContext &C,
+   const Expr *MtxExpr, SVal MtxVal,
+   CheckerKind CheckKind) const;
 
   // Lock, Try-lock.
   void AcquirePthreadLock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
   void AcquireXNULock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
   void TryPthreadLock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
   void TryXNULock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
   void TryFuchsiaLock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
   void TryC11Lock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
-  void AcquireLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo,
-  SVal lock, bool isTryLock, LockingSemantics semantics,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
+  void AcquireLockAux(const CallEvent &Call, CheckerContext &C,
+  const Expr *MtxExpr, SVal MtxVal, bool IsTryLock,
+  LockingSemantics Semantics, CheckerKind CheckKind) const;
 
   // Release.
   void ReleaseAnyLock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
-  void ReleaseLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo,
-  SVal lock, CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
+  void ReleaseLockAux(const CallEvent &Call, CheckerContext &C,
+  const Expr *MtxExpr, SVal MtxVal,
+  CheckerKind CheckKind) const;
 
   // Destroy.
   void DestroyPthreadLock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
   void DestroyXNULock(const CallEvent &Call, CheckerContext &C,
-  CheckerKind checkkind) const;
-  void DestroyLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo,
-  SVal Lock, LockingSemantics semantics,
-  CheckerKind checkkind) const;
+  CheckerKind CheckKind) const;
+  void DestroyLockAux(const CallEvent &Call, CheckerContext &C,
+  const Expr *MtxExpr, SVal MtxVal,
+  LockingSemantics Semantics, CheckerKind CheckKind) const;
 
 public:
   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
@@ -226,18 +229,18 @@ class PthreadLockChecker : public 
Checker BT_initlock[CK_NumCheckKinds];
   mutable std::unique_ptr BT_lor[CK_NumCheckKinds];
 
-  void initBugType(CheckerKind checkKind) const {
-  

[clang] 32efb81 - [analyzer] [NFC] Simplify SVal::getAsLocSymbol function using existing functions

2020-10-26 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2020-10-26T17:00:29+02:00
New Revision: 32efb81ea60a9e99571923bf9308598f6cd341f2

URL: 
https://github.com/llvm/llvm-project/commit/32efb81ea60a9e99571923bf9308598f6cd341f2
DIFF: 
https://github.com/llvm/llvm-project/commit/32efb81ea60a9e99571923bf9308598f6cd341f2.diff

LOG: [analyzer] [NFC] Simplify SVal::getAsLocSymbol function using existing 
functions

Summary: Method of obtaining MemRegion from LocAsInteger/MemRegionVal already 
exists in SVal::getAsRegion function. Replace repetitive conditions in 
SVal::getAsLocSymbol with SVal::getAsRegion function.

Differential Revision: https://reviews.llvm.org/D89982

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/SVals.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp 
b/clang/lib/StaticAnalyzer/Core/SVals.cpp
index c4d5377f3bae..252596887e4f 100644
--- a/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -84,16 +84,12 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
 /// the first symbolic parent region is returned.
 SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
-  if (Optional X = getAs())
-return X->getLoc().getAsLocSymbol(IncludeBaseRegions);
-
-  if (Optional X = getAs()) {
-const MemRegion *R = X->getRegion();
-if (const SymbolicRegion *SymR = IncludeBaseRegions ?
-  R->getSymbolicBase() :
-  
dyn_cast(R->StripCasts()))
+  if (const MemRegion *R = getAsRegion())
+if (const SymbolicRegion *SymR =
+IncludeBaseRegions ? R->getSymbolicBase()
+   : dyn_cast(R->StripCasts()))
   return SymR->getSymbol();
-  }
+
   return nullptr;
 }
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] fae3534 - [analyzer] Use Optional as a return type of StoreManager::castRegion

2021-05-29 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-05-29T15:16:56+03:00
New Revision: fae3534b3056bb96d26a6d1b6e7d6a2ccaf4fab1

URL: 
https://github.com/llvm/llvm-project/commit/fae3534b3056bb96d26a6d1b6e7d6a2ccaf4fab1
DIFF: 
https://github.com/llvm/llvm-project/commit/fae3534b3056bb96d26a6d1b6e7d6a2ccaf4fab1.diff

LOG: [analyzer]  Use Optional as a return type of StoreManager::castRegion

Summary: Make StoreManager::castRegion function usage safier. Replace `const 
MemRegion *` with `Optional`. Simplified one of related test 
cases due to suggestions in D101635.

Differential Revision: https://reviews.llvm.org/D103319

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/lib/StaticAnalyzer/Core/Store.cpp
clang/test/Analysis/casts.c

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 947913ae4eee9..d2461705d1282 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -181,7 +181,8 @@ class StoreManager {
   /// castRegion - Used by ExprEngine::VisitCast to handle casts from
   ///  a MemRegion* to a specific location type.  'R' is the region being
   ///  casted and 'CastToTy' the result type of the cast.
-  const MemRegion *castRegion(const MemRegion *region, QualType CastToTy);
+  Optional castRegion(const MemRegion *region,
+ QualType CastToTy);
 
   virtual StoreRef removeDeadBindings(Store store, const StackFrameContext 
*LCtx,
   SymbolReaper &SymReaper) = 0;

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 0003c27513994..39787886cd7a5 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -753,16 +753,16 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, 
QualType CastTy,
 if (const auto *SR = dyn_cast(R)) {
   QualType SRTy = SR->getSymbol()->getType();
   if (!hasSameUnqualifiedPointeeType(SRTy, CastTy)) {
-R = StateMgr.getStoreManager().castRegion(SR, CastTy);
-return loc::MemRegionVal(R);
+if (auto OptR = StateMgr.getStoreManager().castRegion(SR, CastTy))
+  return loc::MemRegionVal(*OptR);
   }
 }
   }
   // Next fixes pointer dereference using type 
diff erent from its initial
   // one. See PR37503 and PR49007 for details.
   if (const auto *ER = dyn_cast(R)) {
-if ((R = StateMgr.getStoreManager().castRegion(ER, CastTy)))
-  return loc::MemRegionVal(R);
+if (auto OptR = StateMgr.getStoreManager().castRegion(ER, CastTy))
+  return loc::MemRegionVal(*OptR);
   }
 
   return V;
@@ -807,8 +807,8 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, 
QualType CastTy,
 
 // Get the result of casting a region to a 
diff erent type.
 const MemRegion *R = V.getRegion();
-if ((R = StateMgr.getStoreManager().castRegion(R, CastTy)))
-  return loc::MemRegionVal(R);
+if (auto OptR = StateMgr.getStoreManager().castRegion(R, CastTy))
+  return loc::MemRegionVal(*OptR);
   }
 
   // Pointer to whatever else.
@@ -873,8 +873,8 @@ SVal SValBuilder::evalCastSubKind(nonloc::LocAsInteger V, 
QualType CastTy,
   if (!IsUnknownOriginalType && Loc::isLocType(CastTy) &&
   OriginalTy->isIntegralOrEnumerationType()) {
 if (const MemRegion *R = L.getAsRegion())
-  if ((R = StateMgr.getStoreManager().castRegion(R, CastTy)))
-return loc::MemRegionVal(R);
+  if (auto OptR = StateMgr.getStoreManager().castRegion(R, CastTy))
+return loc::MemRegionVal(*OptR);
 return L;
   }
 
@@ -890,8 +890,8 @@ SVal SValBuilder::evalCastSubKind(nonloc::LocAsInteger V, 
QualType CastTy,
   // Delegate to store manager to get the result of casting a region to a
   // 
diff erent type. If the MemRegion* returned is NULL, this expression
   // Evaluates to UnknownVal.
-  if ((R = StateMgr.getStoreManager().castRegion(R, CastTy)))
-return loc::MemRegionVal(R);
+  if (auto OptR = StateMgr.getStoreManager().castRegion(R, CastTy))
+return loc::MemRegionVal(*OptR);
 }
   } else {
 if (Loc::isLocType(CastTy)) {

diff  --git a/clang/lib/StaticAnalyzer/Core/Store.cpp 
b/clang/lib/StaticAnalyzer/Core/Store.cpp
index c563b44efc13e..b867b0746f90f 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -71,7 +71,8 @@ const ElementRegion *StoreManager::GetElementZeroRegion(const 
SubRegion *R,
   return MRMgr.getElementRegion(T, idx, R, Ctx);
 }
 
-const MemRegion *StoreManager::castRegion(const MemR

[clang] 98a95d4 - [analyzer] Retrieve a value from list initialization of constant array declaration in a global scope.

2021-09-24 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-09-24T12:37:58+03:00
New Revision: 98a95d4844caf8edfabd9352393a5546049b54e8

URL: 
https://github.com/llvm/llvm-project/commit/98a95d4844caf8edfabd9352393a5546049b54e8
DIFF: 
https://github.com/llvm/llvm-project/commit/98a95d4844caf8edfabd9352393a5546049b54e8.diff

LOG: [analyzer] Retrieve a value from list initialization of constant array 
declaration in a global scope.

Summary: Fix the point that we didn't take into account array's dimension. 
Retrieve a value of global constant array by iterating through its initializer 
list.

Differential Revision: https://reviews.llvm.org/D104285

Fixes: https://bugs.llvm.org/show_bug.cgi?id=50604

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.c
clang/test/Analysis/initialization.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4ffa1aacb41fa..a82749f30e027 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1668,23 +1668,50 @@ SVal 
RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
 if (const auto *InitList = dyn_cast(Init)) {
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
-int64_t i = CI->getValue().getSExtValue();
-// If it is known that the index is out of bounds, we can return
-// an undefined value.
-if (i < 0)
+// If it is not an array, return Undef.
+QualType T = VD->getType();
+const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T);
+if (!CAT)
   return UndefinedVal();
 
-if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
-  if (CAT->getSize().sle(i))
+// Support one-dimensional array.
+// C++20 [expr.add] 7.6.6.4 (excerpt):
+//   If P points to an array element i of an array object x with n
+//   elements, where i < 0 or i > n, the behavior is undefined.
+//   Dereferencing is not allowed on the "one past the last
+//   element", when i == n.
+// Example:
+//   const int arr[4] = {1, 2};
+//   const int *ptr = arr;
+//   int x0 = ptr[0]; // 1
+//   int x1 = ptr[1]; // 2
+//   int x2 = ptr[2]; // 0
+//   int x3 = ptr[3]; // 0
+//   int x4 = ptr[4]; // UB
+// TODO: Support multidimensional array.
+if (!isa(CAT->getElementType())) {
+  // One-dimensional array.
+  const llvm::APSInt &Idx = CI->getValue();
+  const auto I = static_cast(Idx.getExtValue());
+  // Use `getZExtValue` because array extent can not be negative.
+  const uint64_t Extent = CAT->getSize().getZExtValue();
+  // Check for `Idx < 0`, NOT for `I < 0`, because `Idx` CAN be
+  // negative, but `I` can NOT.
+  if (Idx < 0 || I >= Extent)
 return UndefinedVal();
 
-// If there is a list, but no init, it must be zero.
-if (i >= InitList->getNumInits())
-  return svalBuilder.makeZeroVal(R->getElementType());
+  // C++20 [expr.add] 9.4.17.5 (excerpt):
+  //   i-th array element is value-initialized for each k < i ≤ n,
+  //   where k is an expression-list size and n is an array extent.
+  if (I >= InitList->getNumInits())
+return svalBuilder.makeZeroVal(R->getElementType());
 
-if (const Expr *ElemInit = InitList->getInit(i))
-  if (Optional V = svalBuilder.getConstantVal(ElemInit))
+  // Return a constant value, if it is presented.
+  // FIXME: Support other SVals.
+  const Expr *E = InitList->getInit(I);
+  if (Optional V = svalBuilder.getConstantVal(E))
 return *V;
+}
   }
 }
   }

diff  --git a/clang/test/Analysis/initialization.c 
b/clang/test/Analysis/initialization.c
index c1d6361f1245b..a0899e678699b 100644
--- a/clang/test/Analysis/initialization.c
+++ b/clang/test/Analysis/initialization.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze 
-analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-config 
eagerly-assume=false  
-analyzer-checker=core.uninitialized.Assign,debug.ExprInspection -verify %s
 
 void clang_analyzer_eval(int);
 
@@ -26,3 +26,74 @@ void multinit() {
   clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
   clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
 }
+
+const int glob_arr1[6] = {[2] = 3

[clang] 13f4448 - [analyzer] Rework SValBuilder::evalCast function into maintainable and clear way

2021-02-16 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-02-16T14:30:51+02:00
New Revision: 13f4448ae7db1a477ec2d48776e46415a3401314

URL: 
https://github.com/llvm/llvm-project/commit/13f4448ae7db1a477ec2d48776e46415a3401314
DIFF: 
https://github.com/llvm/llvm-project/commit/13f4448ae7db1a477ec2d48776e46415a3401314.diff

LOG: [analyzer] Rework SValBuilder::evalCast function into maintainable and 
clear way

Summary: Refactor SValBuilder::evalCast function. Make the function clear and 
get rid of redundant and repetitive code. Unite SValBuilder::evalCast, 
SimpleSValBuilder::dispatchCast, SimpleSValBuilder::evalCastFromNonLoc and 
SimpleSValBuilder::evalCastFromLoc functions into single SValBuilder::evalCast.
This patch shall not change any previous behavior.

Differential Revision: https://reviews.llvm.org/D90157

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 4ea85f9730bb..2358d2d66b30 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -75,6 +75,28 @@ class SValBuilder {
   virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
   virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
 
+  SVal evalCastKind(UndefinedVal V, QualType CastTy, QualType OriginalTy);
+  SVal evalCastKind(UnknownVal V, QualType CastTy, QualType OriginalTy);
+  SVal evalCastKind(Loc V, QualType CastTy, QualType OriginalTy);
+  SVal evalCastKind(NonLoc V, QualType CastTy, QualType OriginalTy);
+  SVal evalCastSubKind(loc::ConcreteInt V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(loc::GotoLabel V, QualType CastTy, QualType OriginalTy);
+  SVal evalCastSubKind(loc::MemRegionVal V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(nonloc::CompoundVal V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(nonloc::ConcreteInt V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(nonloc::LazyCompoundVal V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(nonloc::LocAsInteger V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(nonloc::SymbolVal V, QualType CastTy,
+   QualType OriginalTy);
+  SVal evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
+   QualType OriginalTy);
+
 public:
   // FIXME: Make these protected again once RegionStoreManager correctly
   // handles loads from 
diff erent bound value types.
@@ -102,7 +124,7 @@ class SValBuilder {
  Ty2->isIntegralOrEnumerationType()));
   }
 
-  SVal evalCast(SVal val, QualType castTy, QualType originalType);
+  SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy);
 
   // Handles casts of type CK_IntegralCast.
   SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 72b8ada1dfab..4b146d83c194 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -530,108 +530,197 @@ SVal SValBuilder::evalIntegralCast(ProgramStateRef 
state, SVal val,
   return evalCast(val, castTy, originalTy);
 }
 
-// FIXME: should rewrite according to the cast kind.
-SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
-  castTy = Context.getCanonicalType(castTy);
-  originalTy = Context.getCanonicalType(originalTy);
-  if (val.isUnknownOrUndef() || castTy == originalTy)
-return val;
+//===--===//
+// Cast methods.
+// `evalCast` is the main method
+// `evalCastKind` and `evalCastSubKind` are helpers
+//===--===//
 
-  if (castTy->isBooleanType()) {
-if (val.isUnknownOrUndef())
-  return val;
-if (val.isConstant())
-  return makeTruthVal(!val.isZeroConstant(), castTy);
-if (!Loc::isLocType(originalTy) &&
-!originalTy->isIntegralOrEnumerationType() &&
-!originalTy->isMemberPointerType())
-  return UnknownVal();
-if (SymbolRef Sym = val.getAsSymbol(true)) {
-  BasicValueFactory &BVF = getBasicValueFactory();
-  // FIXME: If we had a state here, we could see if the symbol is known to
-  // be zero, but we don't.
-  return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy);
-}
-// Loc values are not always true, they could be weakly linked functio

[clang] d3a6181 - [analyzer] [NFC] Implement a wrapper SValBuilder::getCastedMemRegionVal for similar functionality on region cast

2021-06-08 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-06-08T10:43:43+03:00
New Revision: d3a6181e82ca8d1c49c1bc049c07233bd8c38550

URL: 
https://github.com/llvm/llvm-project/commit/d3a6181e82ca8d1c49c1bc049c07233bd8c38550
DIFF: 
https://github.com/llvm/llvm-project/commit/d3a6181e82ca8d1c49c1bc049c07233bd8c38550.diff

LOG: [analyzer]  [NFC] Implement a wrapper SValBuilder::getCastedMemRegionVal 
for similar functionality on region cast

Summary: Replaced code on region cast with a function-wrapper 
SValBuilder::getCastedMemRegionVal. This is a next step of code refining due to 
suggestions in D103319.

Differential Revision: https://reviews.llvm.org/D103803

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 99277e91ed067..64c61a3514be8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -380,6 +380,10 @@ class SValBuilder {
 return loc::ConcreteInt(BasicVals.getValue(integer));
   }
 
+  /// Return MemRegionVal on success cast, otherwise return None.
+  Optional getCastedMemRegionVal(const MemRegion *region,
+QualType type);
+
   /// Make an SVal that represents the given symbol. This follows the 
convention
   /// of representing Loc-type symbols (symbolic pointers and references)
   /// as Loc values wrapping the symbol rather than as plain symbol values.

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 39787886cd7a5..b7ca8e8ca9cd4 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -268,6 +268,13 @@ DefinedSVal SValBuilder::getBlockPointer(const BlockDecl 
*block,
   return loc::MemRegionVal(BD);
 }
 
+Optional
+SValBuilder::getCastedMemRegionVal(const MemRegion *R, QualType Ty) {
+  if (auto OptR = StateMgr.getStoreManager().castRegion(R, Ty))
+return loc::MemRegionVal(*OptR);
+  return None;
+}
+
 /// Return a memory region for the 'this' object reference.
 loc::MemRegionVal SValBuilder::getCXXThis(const CXXMethodDecl *D,
   const StackFrameContext *SFC) {
@@ -753,16 +760,16 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, 
QualType CastTy,
 if (const auto *SR = dyn_cast(R)) {
   QualType SRTy = SR->getSymbol()->getType();
   if (!hasSameUnqualifiedPointeeType(SRTy, CastTy)) {
-if (auto OptR = StateMgr.getStoreManager().castRegion(SR, CastTy))
-  return loc::MemRegionVal(*OptR);
+if (auto OptMemRegV = getCastedMemRegionVal(SR, CastTy))
+  return *OptMemRegV;
   }
 }
   }
   // Next fixes pointer dereference using type 
diff erent from its initial
   // one. See PR37503 and PR49007 for details.
   if (const auto *ER = dyn_cast(R)) {
-if (auto OptR = StateMgr.getStoreManager().castRegion(ER, CastTy))
-  return loc::MemRegionVal(*OptR);
+if (auto OptMemRegV = getCastedMemRegionVal(ER, CastTy))
+  return *OptMemRegV;
   }
 
   return V;
@@ -807,8 +814,8 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, 
QualType CastTy,
 
 // Get the result of casting a region to a 
diff erent type.
 const MemRegion *R = V.getRegion();
-if (auto OptR = StateMgr.getStoreManager().castRegion(R, CastTy))
-  return loc::MemRegionVal(*OptR);
+if (auto OptMemRegV = getCastedMemRegionVal(R, CastTy))
+  return *OptMemRegV;
   }
 
   // Pointer to whatever else.
@@ -873,8 +880,8 @@ SVal SValBuilder::evalCastSubKind(nonloc::LocAsInteger V, 
QualType CastTy,
   if (!IsUnknownOriginalType && Loc::isLocType(CastTy) &&
   OriginalTy->isIntegralOrEnumerationType()) {
 if (const MemRegion *R = L.getAsRegion())
-  if (auto OptR = StateMgr.getStoreManager().castRegion(R, CastTy))
-return loc::MemRegionVal(*OptR);
+  if (auto OptMemRegV = getCastedMemRegionVal(R, CastTy))
+return *OptMemRegV;
 return L;
   }
 
@@ -890,8 +897,8 @@ SVal SValBuilder::evalCastSubKind(nonloc::LocAsInteger V, 
QualType CastTy,
   // Delegate to store manager to get the result of casting a region to a
   // 
diff erent type. If the MemRegion* returned is NULL, this expression
   // Evaluates to UnknownVal.
-  if (auto OptR = StateMgr.getStoreManager().castRegion(R, CastTy))
-return loc::MemRegionVal(*OptR);
+  if (auto OptMemRegV = getCastedMemRegionVal(R, CastTy))
+return *OptMemRegV;
 }
   } else {
 if (Loc::isLocType(CastTy)) {



_

[clang] e76c008 - [analyzer] Added a test case for PR46264

2021-06-24 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-06-24T12:24:26+03:00
New Revision: e76c008c906af3dc093dd5c3ceaea577359b5432

URL: 
https://github.com/llvm/llvm-project/commit/e76c008c906af3dc093dd5c3ceaea577359b5432
DIFF: 
https://github.com/llvm/llvm-project/commit/e76c008c906af3dc093dd5c3ceaea577359b5432.diff

LOG: [analyzer] Added a test case for PR46264

Summary: It's not able to reproduce the issue 
(https://bugs.llvm.org/show_bug.cgi?id=46264) for the latest sources. Add a 
reported test case to try to catch the problem if occur es.

Differential Revision: https://reviews.llvm.org/D104381

Prevent: https://bugs.llvm.org/show_bug.cgi?id=46264

Added: 
clang/test/Analysis/diagnostics/PR46264.cpp

Modified: 


Removed: 




diff  --git a/clang/test/Analysis/diagnostics/PR46264.cpp 
b/clang/test/Analysis/diagnostics/PR46264.cpp
new file mode 100644
index 0..466dada694be9
--- /dev/null
+++ b/clang/test/Analysis/diagnostics/PR46264.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text 
-verify %s
+
+// PR46264
+// This case shall not crash with an assertion failure about void* 
dereferening.
+// The crash has been last seen on commit
+// `3ed8ebc2f6b8172bed48cc5986d3b7af4cfca1bc` from 24.05.2020.
+namespace ns1 {
+namespace a {
+class b {
+public:
+  typedef int b::*c;
+  operator c() { return d ? &b::d : 0; }
+  // expected-note@-1{{'?' condition is true}}
+  // expected-note@-2{{Assuming field 'd' is not equal to 0}}
+  // expected-note@-3{{Returning value, which participates in a condition 
later}}
+  int d;
+};
+} // namespace a
+using a::b;
+class e {
+  void f();
+  void g();
+  b h;
+};
+void e::f() {
+  e *i;
+  // expected-note@-1{{'i' declared without an initial value}}
+  if (h)
+// expected-note@-1{{Taking true branch}}
+// expected-note@-2{{'b::operator int ns1::a::b::*'}}
+// expected-note@-3{{Returning from 'b::operator int ns1::a::b::*'}}
+i->g();
+  // expected-note@-1{{Called C++ object pointer is uninitialized}}
+  // expected-warning@-2{{Called C++ object pointer is uninitialized}}
+}
+} // namespace ns1



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 497b57a - revert test commit

2021-08-10 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-08-10T19:19:27+03:00
New Revision: 497b57ad0b9ee34aeb8c56e9f47332912b50d58c

URL: 
https://github.com/llvm/llvm-project/commit/497b57ad0b9ee34aeb8c56e9f47332912b50d58c
DIFF: 
https://github.com/llvm/llvm-project/commit/497b57ad0b9ee34aeb8c56e9f47332912b50d58c.diff

LOG: revert test commit

Added: 


Modified: 
clang/test/Analysis/PR47511.cpp

Removed: 




diff  --git a/clang/test/Analysis/PR47511.cpp b/clang/test/Analysis/PR47511.cpp
index a9f2d592b6f59..d42799f4fbde5 100644
--- a/clang/test/Analysis/PR47511.cpp
+++ b/clang/test/Analysis/PR47511.cpp
@@ -14,6 +14,6 @@ constexpr strong_ordering strong_ordering::less = {-1};
 } // namespace std
 
 void test() {
-  // No crash 
+  // no crash
   (void)(0 <=> 0);
 }



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 9dabacd - [analyzer] Adjust JS code of analyzer's HTML report for IE support.

2021-08-17 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-08-17T19:32:34+03:00
New Revision: 9dabacd09fdd52b5995546794290651c477d3885

URL: 
https://github.com/llvm/llvm-project/commit/9dabacd09fdd52b5995546794290651c477d3885
DIFF: 
https://github.com/llvm/llvm-project/commit/9dabacd09fdd52b5995546794290651c477d3885.diff

LOG: [analyzer] Adjust JS code of analyzer's HTML report for IE support.

Summary: Change and replace some functions which IE does not support. This 
patch is made as a continuation of D92928 revision. Also improve hot keys 
behavior.

Differential Revision: https://reviews.llvm.org/D107366

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp 
b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 3ee12c0bdf65..c90046ffb413 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -1289,15 +1289,32 @@ var findNum = function() {
 return out;
 };
 
+var classListAdd = function(el, theClass) {
+  if(!el.className.baseVal)
+el.className += " " + theClass;
+  else
+el.className.baseVal += " " + theClass;
+};
+
+var classListRemove = function(el, theClass) {
+  var className = (!el.className.baseVal) ?
+  el.className : el.className.baseVal;
+className = className.replace(" " + theClass, "");
+  if(!el.className.baseVal)
+el.className = className;
+  else
+el.className.baseVal = className;
+};
+
 var scrollTo = function(el) {
 querySelectorAllArray(".selected").forEach(function(s) {
-s.classList.remove("selected");
+  classListRemove(s, "selected");
 });
-el.classList.add("selected");
+classListAdd(el, "selected");
 window.scrollBy(0, el.getBoundingClientRect().top -
 (window.innerHeight / 2));
 highlightArrowsForSelectedEvent();
-}
+};
 
 var move = function(num, up, numItems) {
   if (num == 1 && up || num == numItems - 1 && !up) {
@@ -1332,9 +1349,11 @@ window.addEventListener("keydown", function (event) {
   if (event.defaultPrevented) {
 return;
   }
-  if (event.key == "j") {
+  // key 'j'
+  if (event.keyCode == 74) {
 navigateTo(/*up=*/false);
-  } else if (event.key == "k") {
+  // key 'k'
+  } else if (event.keyCode == 75) {
 navigateTo(/*up=*/true);
   } else {
 return;
@@ -1350,8 +1369,11 @@ StringRef 
HTMLDiagnostics::generateArrowDrawingJavascript() {
 

[clang] 1deccd0 - [analyzer] Retrieve a character from StringLiteral as an initializer for constant arrays.

2021-10-29 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-10-29T19:44:37+03:00
New Revision: 1deccd05ba8a326e57a513002f482ed0924b1fd8

URL: 
https://github.com/llvm/llvm-project/commit/1deccd05ba8a326e57a513002f482ed0924b1fd8
DIFF: 
https://github.com/llvm/llvm-project/commit/1deccd05ba8a326e57a513002f482ed0924b1fd8.diff

LOG: [analyzer] Retrieve a character from StringLiteral as an initializer for 
constant arrays.

Summary: Assuming that values of constant arrays never change, we can retrieve 
values for specific position(index) right from the initializer, if presented. 
Retrieve a character code by index from StringLiteral which is an initializer 
of constant arrays in global scope.

This patch has a known issue of getting access to characters past the end of 
the literal. The declaration, in which the literal is used, is an implicit cast 
of kind `array-to-pointer`. The offset should be in literal length's bounds. 
This should be distinguished from the states in the Standard C++20 
[dcl.init.string] 9.4.2.3. Example:
  const char arr[42] = "123";
  char c = arr[41]; // OK
  const char * const str = "123";
  char c = str[41]; // NOK

Differential Revision: https://reviews.llvm.org/D107339

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 5565e9cfd08cf..79d2fc76a42f1 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -441,6 +441,8 @@ class RegionStoreManager : public StoreManager {
   RegionBindingsConstRef B, const VarRegion *VR, const ElementRegion *R);
   Optional getSValFromInitListExpr(const InitListExpr *ILE,
  uint64_t Offset, QualType ElemT);
+  SVal getSValFromStringLiteral(const StringLiteral *SL, uint64_t Offset,
+QualType ElemT);
 
 public: // Part of public interface to class.
 
@@ -1701,10 +1703,16 @@ Optional 
RegionStoreManager::getConstantValFromConstArrayInitializer(
   // From here `Offset` is in the bounds.
 
   // Handle InitListExpr.
+  // Example:
+  //   const char arr[] = { 1, 2, 3 };
   if (const auto *ILE = dyn_cast(Init))
 return getSValFromInitListExpr(ILE, Offset, R->getElementType());
 
-  // FIXME: Handle StringLiteral.
+  // Handle StringLiteral.
+  // Example:
+  //   const char arr[] = "abc";
+  if (const auto *SL = dyn_cast(Init))
+return getSValFromStringLiteral(SL, Offset, R->getElementType());
 
   // FIXME: Handle CompoundLiteralExpr.
 
@@ -1716,6 +1724,15 @@ RegionStoreManager::getSValFromInitListExpr(const 
InitListExpr *ILE,
 uint64_t Offset, QualType ElemT) {
   assert(ILE && "InitListExpr should not be null");
 
+  // C++20 [dcl.init.string] 9.4.2.1:
+  //   An array of ordinary character type [...] can be initialized by [...]
+  //   an appropriately-typed string-literal enclosed in braces.
+  // Example:
+  //   const char arr[] = { "abc" };
+  if (ILE->isStringLiteralInit())
+if (const auto *SL = dyn_cast(ILE->getInit(0)))
+  return getSValFromStringLiteral(SL, Offset, ElemT);
+
   // C++20 [expr.add] 9.4.17.5 (excerpt):
   //   i-th array element is value-initialized for each k < i ≤ n,
   //   where k is an expression-list size and n is an array extent.
@@ -1728,6 +1745,42 @@ RegionStoreManager::getSValFromInitListExpr(const 
InitListExpr *ILE,
   return svalBuilder.getConstantVal(E);
 }
 
+/// Returns an SVal, if possible, for the specified position in a string
+/// literal.
+///
+/// \param SL The given string literal.
+/// \param Offset The unsigned offset. E.g. for the expression
+///   `char x = str[42];` an offset should be 42.
+///   E.g. for the string "abc" offset:
+///   - 1 returns SVal{b}, because it's the second position in the string.
+///   - 42 returns SVal{0}, because there's no explicit value at this
+/// position in the string.
+/// \param ElemT The type of the result SVal expression.
+///
+/// NOTE: We return `0` for every offset >= the literal length for array
+/// declarations, like:
+///   const char str[42] = "123"; // Literal length is 4.
+///   char c = str[41];   // Offset is 41.
+/// FIXME: Nevertheless, we can't do the same for pointer declaraions, like:
+///   const char * const str = "123"; // Literal length is 4.
+///   char c = str[41];   // Offset is 41. Returns `0`, but Undef
+///   // expected.
+/// It should be properly handled before reaching this point.
+/// The main problem is that we can't distinguish between these declarations,
+/// because in case of array we can get the Decl from VarRegion, but in case
+/// of pointer the region is a StringRegion, which doesn't contain a Decl.
+/// Possible solution could be 

[clang] a12bfac - [analyzer] Retrieve a value from list initialization of multi-dimensional array declaration.

2021-11-08 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-11-08T16:17:55+02:00
New Revision: a12bfac292db2195d3461dce51467d350de865dc

URL: 
https://github.com/llvm/llvm-project/commit/a12bfac292db2195d3461dce51467d350de865dc
DIFF: 
https://github.com/llvm/llvm-project/commit/a12bfac292db2195d3461dce51467d350de865dc.diff

LOG: [analyzer] Retrieve a value from list initialization of multi-dimensional 
array declaration.

Summary: Add support of multi-dimensional arrays in 
`RegionStoreManager::getBindingForElement`. Handle nested ElementRegion's 
getting offsets and checking for being in bounds. Get values from the nested 
initialization lists using obtained offsets.

Differential Revision: https://reviews.llvm.org/D111654

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.c
clang/test/Analysis/initialization.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 79d2fc76a42f..135130b35ba7 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -437,10 +437,13 @@ class RegionStoreManager : public StoreManager {
 
   RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B,
 const SubRegion *R);
-  Optional getConstantValFromConstArrayInitializer(
-  RegionBindingsConstRef B, const VarRegion *VR, const ElementRegion *R);
-  Optional getSValFromInitListExpr(const InitListExpr *ILE,
- uint64_t Offset, QualType ElemT);
+  Optional
+  getConstantValFromConstArrayInitializer(RegionBindingsConstRef B,
+  const ElementRegion *R);
+  Optional
+  getSValFromInitListExpr(const InitListExpr *ILE,
+  const SmallVector &ConcreteOffsets,
+  QualType ElemT);
   SVal getSValFromStringLiteral(const StringLiteral *SL, uint64_t Offset,
 QualType ElemT);
 
@@ -1631,9 +1634,127 @@ 
RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
   return Result;
 }
 
+/// This is a helper function for `getConstantValFromConstArrayInitializer`.
+///
+/// Return an array of extents of the declared array type.
+///
+/// E.g. for `int x[1][2][3];` returns { 1, 2, 3 }.
+static SmallVector
+getConstantArrayExtents(const ConstantArrayType *CAT) {
+  assert(CAT && "ConstantArrayType should not be null");
+  CAT = cast(CAT->getCanonicalTypeInternal());
+  SmallVector Extents;
+  do {
+Extents.push_back(CAT->getSize().getZExtValue());
+  } while ((CAT = dyn_cast(CAT->getElementType(;
+  return Extents;
+}
+
+/// This is a helper function for `getConstantValFromConstArrayInitializer`.
+///
+/// Return an array of offsets from nested ElementRegions and a root base
+/// region. The array is never empty and a base region is never null.
+///
+/// E.g. for `Element{Element{Element{VarRegion},1},2},3}` returns { 3, 2, 1 }.
+/// This represents an access through indirection: `arr[1][2][3];`
+///
+/// \param ER The given (possibly nested) ElementRegion.
+///
+/// \note The result array is in the reverse order of indirection expression:
+/// arr[1][2][3] -> { 3, 2, 1 }. This helps to provide complexity O(n), where n
+/// is a number of indirections. It may not affect performance in real-life
+/// code, though.
+static std::pair, const MemRegion *>
+getElementRegionOffsetsWithBase(const ElementRegion *ER) {
+  assert(ER && "ConstantArrayType should not be null");
+  const MemRegion *Base;
+  SmallVector SValOffsets;
+  do {
+SValOffsets.push_back(ER->getIndex());
+Base = ER->getSuperRegion();
+ER = dyn_cast(Base);
+  } while (ER);
+  return {SValOffsets, Base};
+}
+
+/// This is a helper function for `getConstantValFromConstArrayInitializer`.
+///
+/// Convert array of offsets from `SVal` to `uint64_t` in consideration of
+/// respective array extents.
+/// \param SrcOffsets [in]   The array of offsets of type `SVal` in reversed
+///   order (expectedly received from `getElementRegionOffsetsWithBase`).
+/// \param ArrayExtents [in] The array of extents.
+/// \param DstOffsets [out]  The array of offsets of type `uint64_t`.
+/// \returns:
+/// - `None` for successful convertion.
+/// - `UndefinedVal` or `UnknownVal` otherwise. It's expected that this SVal
+///   will be returned as a suitable value of the access operation.
+///   which should be returned as a correct
+///
+/// \example:
+///   const int arr[10][20][30] = {}; // ArrayExtents { 10, 20, 30 }
+///   int x1 = arr[4][5][6]; // SrcOffsets { NonLoc(6), NonLoc(5), NonLoc(4) }
+///  // DstOffsets { 4, 5, 6 }
+///  // returns None
+///   int x2 = arr[42][5][-6]; // returns UndefinedVal
+///   int x3 = arr[4][5][x2];  // returns UnknownVal
+static Optional
+

[clang] f0bc7d2 - [analyzer] Fix region cast between the same types with different qualifiers.

2021-11-15 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-11-15T19:23:00+02:00
New Revision: f0bc7d24882ab84f6398a1ea614dd0bf6e2a1085

URL: 
https://github.com/llvm/llvm-project/commit/f0bc7d24882ab84f6398a1ea614dd0bf6e2a1085
DIFF: 
https://github.com/llvm/llvm-project/commit/f0bc7d24882ab84f6398a1ea614dd0bf6e2a1085.diff

LOG: [analyzer] Fix region cast between the same types with different 
qualifiers.

Summary: Specifically, this fixes the case when we get an access to array 
element through the pointer to element. This covers several FIXME's. in 
https://reviews.llvm.org/D111654.
Example:
  const int arr[4][2];
  const int *ptr = arr[1]; // Fixes this.
The issue is that `arr[1]` is `int*` (&Element{Element{glob_arr5,1 
S64b,int[2]},0 S64b,int}), and `ptr` is `const int*`. We don't take qualifiers 
into account. Consequently, we doesn't match the types as the same ones.

Differential Revision: https://reviews.llvm.org/D113480

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/Store.cpp
clang/test/Analysis/initialization.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/Store.cpp 
b/clang/lib/StaticAnalyzer/Core/Store.cpp
index 97b8b9d3d07a7..3cc0cd224d7a4 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -96,18 +96,24 @@ Optional StoreManager::castRegion(const 
MemRegion *R,
   // already be handled.
   QualType PointeeTy = CastToTy->getPointeeType();
   QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
+  CanonPointeeTy = CanonPointeeTy.getLocalUnqualifiedType();
 
   // Handle casts to void*.  We just pass the region through.
-  if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy)
+  if (CanonPointeeTy == Ctx.VoidTy)
 return R;
 
-  // Handle casts from compatible types.
-  if (R->isBoundable())
+  const auto IsSameRegionType = [&Ctx](const MemRegion *R, QualType OtherTy) {
 if (const auto *TR = dyn_cast(R)) {
   QualType ObjTy = Ctx.getCanonicalType(TR->getValueType());
-  if (CanonPointeeTy == ObjTy)
-return R;
+  if (OtherTy == ObjTy.getLocalUnqualifiedType())
+return true;
 }
+return false;
+  };
+
+  // Handle casts from compatible types.
+  if (R->isBoundable() && IsSameRegionType(R, CanonPointeeTy))
+return R;
 
   // Process region cast according to the kind of the region being cast.
   switch (R->getKind()) {
@@ -174,16 +180,11 @@ Optional 
StoreManager::castRegion(const MemRegion *R,
   CharUnits off = rawOff.getOffset();
 
   if (off.isZero()) {
-// Edge case: we are at 0 bytes off the beginning of baseR.  We
-// check to see if type we are casting to is the same as the base
-// region.  If so, just return the base region.
-if (const auto *TR = dyn_cast(baseR)) {
-  QualType ObjTy = Ctx.getCanonicalType(TR->getValueType());
-  QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
-  if (CanonPointeeTy == ObjTy)
-return baseR;
-}
-
+// Edge case: we are at 0 bytes off the beginning of baseR. We check to
+// see if the type we are casting to is the same as the type of the 
base
+// region. If so, just return the base region.
+if (IsSameRegionType(baseR, CanonPointeeTy))
+  return baseR;
 // Otherwise, create a new ElementRegion at offset 0.
 return MakeElementRegion(cast(baseR), PointeeTy);
   }

diff  --git a/clang/test/Analysis/initialization.cpp 
b/clang/test/Analysis/initialization.cpp
index 0883678c8e908..e5b94ea7d0a2b 100644
--- a/clang/test/Analysis/initialization.cpp
+++ b/clang/test/Analysis/initialization.cpp
@@ -68,8 +68,7 @@ void glob_invalid_index3() {
 void glob_invalid_index4() {
   const int *ptr = glob_arr4[1];
   int idx = -42;
-  // FIXME: Should warn {{garbage or undefined}}.
-  auto x = ptr[idx]; // no-warning
+  auto x = ptr[idx]; // expected-warning{{garbage or undefined}}
 }
 
 int const glob_arr5[4][2] = {{1}, 3, 4, 5};
@@ -86,16 +85,11 @@ void glob_array_index3() {
 
 void glob_ptr_index2() {
   int const *ptr = glob_arr5[1];
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(ptr[0] == 3); // expected-warning{{UNKNOWN}}
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(ptr[1] == 4); // expected-warning{{UNKNOWN}}
-  // FIXME: Should be UNDEFINED.
-  clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNKNOWN}}
-  // FIXME: Should be UNDEFINED.
-  clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNKNOWN}}
-  // FIXME: Should be UNDEFINED.
-  clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(ptr[0] == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr[1] == 4); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNDEFINED}}
+  clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNDEFINED}}
+  clang_analyzer_eval(ptr[4] == 0); // expe

[clang] adcd4b1 - [analyzer] [NFC] Fix comments into more regular form.

2022-08-11 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2022-08-11T21:28:23+03:00
New Revision: adcd4b1c0bd43c89e579bf07daff7ffb02848012

URL: 
https://github.com/llvm/llvm-project/commit/adcd4b1c0bd43c89e579bf07daff7ffb02848012
DIFF: 
https://github.com/llvm/llvm-project/commit/adcd4b1c0bd43c89e579bf07daff7ffb02848012.diff

LOG: [analyzer] [NFC] Fix comments into more regular form.

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp 
b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 81c11099e93f0..bb64cbc4b71c4 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1286,8 +1286,8 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
   return isa(getMemorySpace());
 }
 
-// getBaseRegion strips away all elements and fields, and get the base region
-// of them.
+// Strips away all elements and fields.
+// Returns the base region of them.
 const MemRegion *MemRegion::getBaseRegion() const {
   const MemRegion *R = this;
   while (true) {
@@ -1307,8 +1307,7 @@ const MemRegion *MemRegion::getBaseRegion() const {
   return R;
 }
 
-// getgetMostDerivedObjectRegion gets the region of the root class of a C++
-// class hierarchy.
+// Returns the region of the root class of a C++ class hierarchy.
 const MemRegion *MemRegion::getMostDerivedObjectRegion() const {
   const MemRegion *R = this;
   while (const auto *BR = dyn_cast(R))



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] b30521c - [analyzer] Wrong type cast occurs during pointer dereferencing after type punning

2021-04-28 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-04-29T01:03:38+03:00
New Revision: b30521c28a4dc1b94d793385e4144ede5822b2c1

URL: 
https://github.com/llvm/llvm-project/commit/b30521c28a4dc1b94d793385e4144ede5822b2c1
DIFF: 
https://github.com/llvm/llvm-project/commit/b30521c28a4dc1b94d793385e4144ede5822b2c1.diff

LOG: [analyzer] Wrong type cast occurs during pointer dereferencing after type 
punning

Summary: During pointer dereferencing CastRetrievedVal uses wrong type from the 
Store after type punning. Namely, the pointer casts to another type and then 
assigns with a value of one more another type. It produces NonLoc value when 
Loc is expected.

Differential Revision: https://reviews.llvm.org/D89055

Fixes:
https://bugs.llvm.org/show_bug.cgi?id=37503
https://bugs.llvm.org/show_bug.cgi?id=49007

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/test/Analysis/casts.c
clang/test/Analysis/string.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index a49099384d2a..f376922754bf 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -748,8 +748,8 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, 
QualType CastTy,
   // pointers as well.
   // FIXME: We really need a single good function to perform casts for us
   // correctly every time we need it.
+  const MemRegion *R = V.getRegion();
   if (CastTy->isPointerType() && !CastTy->isVoidPointerType()) {
-const MemRegion *R = V.getRegion();
 if (const auto *SR = dyn_cast(R)) {
   QualType SRTy = SR->getSymbol()->getType();
   if (!hasSameUnqualifiedPointeeType(SRTy, CastTy)) {
@@ -758,6 +758,13 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, 
QualType CastTy,
   }
 }
   }
+  // Next fixes pointer dereference using type 
diff erent from its initial
+  // one. See PR37503 and PR49007 for details.
+  if (const auto *ER = dyn_cast(R)) {
+R = StateMgr.getStoreManager().castRegion(ER, CastTy);
+return loc::MemRegionVal(R);
+  }
+
   return V;
 }
 

diff  --git a/clang/test/Analysis/casts.c b/clang/test/Analysis/casts.c
index ae7b84641b13..702e53a82f2e 100644
--- a/clang/test/Analysis/casts.c
+++ b/clang/test/Analysis/casts.c
@@ -245,3 +245,8 @@ double no_crash_reinterpret_double_as_sym_ptr(double a, 
void * b) {
   return a * a;
 }
 
+void no_crash_reinterpret_char_as_uchar(char ***a, int *b) {
+  *(unsigned char **)a = (unsigned char *)b;
+  if (**a == 0) // no-crash
+;
+}

diff  --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index debcea481adb..2bf34ca757e7 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -363,6 +363,20 @@ void strcpy_no_overflow(char *y) {
 strcpy(x, y); // no-warning
 }
 
+// PR37503
+void *get_void_ptr();
+char ***type_punned_ptr;
+void strcpy_no_assertion(char c) {
+  *(unsigned char **)type_punned_ptr = (unsigned char *)(get_void_ptr());
+  strcpy(**type_punned_ptr, &c); // no-crash
+}
+
+// PR49007
+char f(char ***c, int *i) {
+  *(void **)c = i + 1;
+  return (**c)[0]; // no-crash
+}
+
 //===--===
 // stpcpy()
 //===--===



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 6a399bf - [analyzer] Implemented RangeSet::Factory::unite function to handle intersections and adjacency

2021-12-10 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-12-10T18:48:02+02:00
New Revision: 6a399bf4b3aa32a87fb04dd1deb05f0066810a05

URL: 
https://github.com/llvm/llvm-project/commit/6a399bf4b3aa32a87fb04dd1deb05f0066810a05
DIFF: 
https://github.com/llvm/llvm-project/commit/6a399bf4b3aa32a87fb04dd1deb05f0066810a05.diff

LOG: [analyzer] Implemented RangeSet::Factory::unite function to handle 
intersections and adjacency

Summary: Handle intersected and adjacent ranges uniting them into a single one.
Example:
intersection [0, 10] U [5, 20] = [0, 20]
adjacency [0, 10] U [11, 20] = [0, 20]

Differential Revision: https://reviews.llvm.org/D99797

Added: 


Modified: 

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/unittests/StaticAnalyzer/RangeSetTest.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index a80484610131b..3a0bec9d04e57 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -140,6 +140,30 @@ class RangeSet {
 /// Complexity: O(N)
 /// where N = size(Original)
 RangeSet add(RangeSet Original, const llvm::APSInt &Point);
+/// Create a new set which is a union of two given ranges.
+/// Possible intersections are not checked here.
+///
+/// Complexity: O(N + M)
+/// where N = size(LHS), M = size(RHS)
+RangeSet unite(RangeSet LHS, RangeSet RHS);
+/// Create a new set by uniting given range set with the given range.
+/// All intersections and adjacent ranges are handled here.
+///
+/// Complexity: O(N)
+/// where N = size(Original)
+RangeSet unite(RangeSet Original, Range Element);
+/// Create a new set by uniting given range set with the given point.
+/// All intersections and adjacent ranges are handled here.
+///
+/// Complexity: O(N)
+/// where N = size(Original)
+RangeSet unite(RangeSet Original, llvm::APSInt Point);
+/// Create a new set by uniting given range set with the given range
+/// between points. All intersections and adjacent ranges are handled here.
+///
+/// Complexity: O(N)
+/// where N = size(Original)
+RangeSet unite(RangeSet Original, llvm::APSInt From, llvm::APSInt To);
 
 RangeSet getEmptySet() { return &EmptySet; }
 
@@ -224,6 +248,9 @@ class RangeSet {
 ContainerType *construct(ContainerType &&From);
 
 RangeSet intersect(const ContainerType &LHS, const ContainerType &RHS);
+/// NOTE: This function relies on the fact that all values in the
+/// containers are persistent (created via BasicValueFactory::getValue).
+ContainerType unite(const ContainerType &LHS, const ContainerType &RHS);
 
 // Many operations include producing new APSInt values and that's why
 // we need this factory.

diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 74403a160b8e0..4b0d4942e5287 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -110,6 +110,14 @@ class OperatorRelationsTable {
 
 RangeSet::ContainerType RangeSet::Factory::EmptySet{};
 
+RangeSet RangeSet::Factory::add(RangeSet LHS, RangeSet RHS) {
+  ContainerType Result;
+  Result.reserve(LHS.size() + RHS.size());
+  std::merge(LHS.begin(), LHS.end(), RHS.begin(), RHS.end(),
+ std::back_inserter(Result));
+  return makePersistent(std::move(Result));
+}
+
 RangeSet RangeSet::Factory::add(RangeSet Original, Range Element) {
   ContainerType Result;
   Result.reserve(Original.size() + 1);
@@ -126,6 +134,186 @@ RangeSet RangeSet::Factory::add(RangeSet Original, const 
llvm::APSInt &Point) {
   return add(Original, Range(Point));
 }
 
+RangeSet RangeSet::Factory::unite(RangeSet LHS, RangeSet RHS) {
+  ContainerType Result = unite(*LHS.Impl, *RHS.Impl);
+  return makePersistent(std::move(Result));
+}
+
+RangeSet RangeSet::Factory::unite(RangeSet Original, Range R) {
+  ContainerType Result;
+  Result.push_back(R);
+  Result = unite(*Original.Impl, Result);
+  return makePersistent(std::move(Result));
+}
+
+RangeSet RangeSet::Factory::unite(RangeSet Original, llvm::APSInt Point) {
+  return unite(Original, Range(ValueFactory.getValue(Point)));
+}
+
+RangeSet RangeSet::Factory::unite(RangeSet Original, llvm::APSInt From,
+  llvm::APSInt To) {
+  return unite(Original,
+   Range(ValueFactory.getValue(From), ValueFactory.getValue(To)));
+}
+
+template 
+void swapIterators(T &First, T &FirstEnd

[clang] da8bd97 - [analyzer][NFC] Change return value of StoreManager::attemptDownCast function from SVal to Optional

2021-12-17 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-12-17T13:03:47+02:00
New Revision: da8bd972a33ad642d6237b5b95b31a2a20f46a35

URL: 
https://github.com/llvm/llvm-project/commit/da8bd972a33ad642d6237b5b95b31a2a20f46a35
DIFF: 
https://github.com/llvm/llvm-project/commit/da8bd972a33ad642d6237b5b95b31a2a20f46a35.diff

LOG: [analyzer][NFC] Change return value of StoreManager::attemptDownCast 
function from SVal to Optional

Summary: Refactor return value of `StoreManager::attemptDownCast` function by 
removing the last parameter `bool &Failed` and replace the return value `SVal` 
with `Optional`.  Make the function consistent with the family of 
`evalDerivedToBase` by renaming it to `evalBaseToDerived`. Aligned the code on 
the call side with these changes.

Differential Revision: https://reviews.llvm.org/

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
clang/lib/StaticAnalyzer/Core/CallEvent.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
clang/lib/StaticAnalyzer/Core/Store.cpp

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index d2461705d128..bdf9662d5d99 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -172,9 +172,9 @@ class StoreManager {
   ///dynamic_cast.
   ///  - We don't know (base is a symbolic region and we don't have
   ///enough info to determine if the cast will succeed at run time).
-  /// The function returns an SVal representing the derived class; it's
-  /// valid only if Failed flag is set to false.
-  SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed);
+  /// The function returns an optional with SVal representing the derived class
+  /// in case of a successful cast and `None` otherwise.
+  Optional evalBaseToDerived(SVal Base, QualType DerivedPtrType);
 
   const ElementRegion *GetElementZeroRegion(const SubRegion *R, QualType T);
 

diff  --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp 
b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 764dad3e7ab4..ae46709340d3 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -762,9 +762,9 @@ void CXXInstanceCall::getInitialStackFrameContents(
   QualType Ty = Ctx.getPointerType(Ctx.getRecordType(Class));
 
   // FIXME: CallEvent maybe shouldn't be directly accessing StoreManager.
-  bool Failed;
-  ThisVal = StateMgr.getStoreManager().attemptDownCast(ThisVal, Ty, 
Failed);
-  if (Failed) {
+  Optional V =
+  StateMgr.getStoreManager().evalBaseToDerived(ThisVal, Ty);
+  if (!V.hasValue()) {
 // We might have suffered some sort of placement new earlier, so
 // we're constructing in a completely unexpected storage.
 // Fall back to a generic pointer cast for this-value.
@@ -772,7 +772,8 @@ void CXXInstanceCall::getInitialStackFrameContents(
 const CXXRecordDecl *StaticClass = StaticMD->getParent();
 QualType StaticTy = Ctx.getPointerType(Ctx.getRecordType(StaticClass));
 ThisVal = SVB.evalCast(ThisVal, Ty, StaticTy);
-  }
+  } else
+ThisVal = *V;
 }
 
 if (!ThisVal.isUnknown())

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 69d67cf9b465..637e4edfd778 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -439,14 +439,15 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
 if (CastE->isGLValue())
   resultType = getContext().getPointerType(resultType);
 
-bool Failed = false;
-
-// Check if the value being cast evaluates to 0.
-if (val.isZeroConstant())
-  Failed = true;
-// Else, evaluate the cast.
-else
-  val = getStoreManager().attemptDownCast(val, T, Failed);
+bool Failed = true;
+
+// Check if the value being cast does not evaluates to 0.
+if (!val.isZeroConstant())
+  if (Optional V =
+  StateMgr.getStoreManager().evalBaseToDerived(val, T)) {
+val = *V;
+Failed = false;
+  }
 
 if (Failed) {
   if (T->isReferenceType()) {
@@ -478,14 +479,13 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
 if (CastE->isGLValue())
   resultType = getContext().getPointerType(resultType);
 
-bool Failed = false;
-
 if (!val.isConstant()) {
-  val = getStoreManager().attemptDownCast(val, T, Failed);
+  Optional V = getStoreManager().evalBaseToDerived(val, T);
+  val = V ? *V : UnknownVal();
 }
 
 // Failed to cast or the result is unknown, fall ba

[clang] 7736b08 - [analyzer] Replace StoreManager::CastRetrievedVal with SValBuilder::evalCast

2021-04-13 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-04-13T18:10:06+03:00
New Revision: 7736b08c287274361f2cdf13512015708af4d335

URL: 
https://github.com/llvm/llvm-project/commit/7736b08c287274361f2cdf13512015708af4d335
DIFF: 
https://github.com/llvm/llvm-project/commit/7736b08c287274361f2cdf13512015708af4d335.diff

LOG: [analyzer] Replace StoreManager::CastRetrievedVal with 
SValBuilder::evalCast

Summary: Move logic from CastRetrievedVal to evalCast and replace 
CastRetrievedVal with evalCast. Also move guts from 
SimpleSValBuilder::dispatchCast inside evalCast.
evalCast intends to substitute dispatchCast, evalCastFromNonLoc and 
evalCastFromLoc in the future. OriginalTy provides additional information for 
casting, which is useful for some cases and useless for others.  If 
`OriginalTy.isNull()` is true, then cast performs based on CastTy only. Now 
evalCast operates in two ways. It retains all previous behavior and take over 
dispatchCast behavior. dispatchCast, evalCastFromNonLoc and evalCastFromLoc is 
considered as buggy since it doesn't take into account OriginalTy of the SVal 
and should be improved.

>From this patch use evalCast instead of dispatchCast, evalCastFromNonLoc and 
>evalCastFromLoc functions. dispatchCast redirects to evalCast.

This patch shall not change any behavior.

Differential Revision: https://reviews.llvm.org/D96090

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
clang/lib/StaticAnalyzer/Core/Store.cpp

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index c3b590e4784e4..947913ae4eee9 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -280,12 +280,6 @@ class StoreManager {
  QualType pointeeTy,
  uint64_t index = 0);
 
-  /// CastRetrievedVal - Used by subclasses of StoreManager to implement
-  ///  implicit casts that arise from loads from regions that are reinterpreted
-  ///  as another region.
-  SVal CastRetrievedVal(SVal val, const TypedValueRegion *region,
-QualType castTy);
-
 private:
   SVal getLValueFieldOrIvar(const Decl *decl, SVal base);
 };

diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 5acc51674e9a6..4ffa1aacb41fa 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1478,7 +1478,7 @@ SVal 
RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
 return UnknownVal();
 
   if (const FieldRegion* FR = dyn_cast(R))
-return CastRetrievedVal(getBindingForField(B, FR), FR, T);
+return svalBuilder.evalCast(getBindingForField(B, FR), T, QualType{});
 
   if (const ElementRegion* ER = dyn_cast(R)) {
 // FIXME: Here we actually perform an implicit conversion from the loaded
@@ -1486,7 +1486,7 @@ SVal 
RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
 // more intelligently.  For example, an 'element' can encompass multiple
 // bound regions (e.g., several bound bytes), or could be a subset of
 // a larger value.
-return CastRetrievedVal(getBindingForElement(B, ER), ER, T);
+return svalBuilder.evalCast(getBindingForElement(B, ER), T, QualType{});
   }
 
   if (const ObjCIvarRegion *IVR = dyn_cast(R)) {
@@ -1496,7 +1496,7 @@ SVal 
RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
 // reinterpretted, it is possible we stored a 
diff erent value that could
 // fit within the ivar.  Either we need to cast these when storing them
 // or reinterpret them lazily (as we do here).
-return CastRetrievedVal(getBindingForObjCIvar(B, IVR), IVR, T);
+return svalBuilder.evalCast(getBindingForObjCIvar(B, IVR), T, QualType{});
   }
 
   if (const VarRegion *VR = dyn_cast(R)) {
@@ -1506,7 +1506,7 @@ SVal 
RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
 // variable is reinterpretted, it is possible we stored a 
diff erent value
 // that could fit within the variable.  Either we need to cast these when
 // storing them or reinterpret them lazily (as we do here).
-return CastRetrievedVal(getBindingForVar(B, VR), VR, T);
+return svalBuilder.evalCast(getBindingForVar(B, VR), T, QualType{});
   }
 
   const SVal *V = B.lookup(R, BindingKey::Direct);

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 9942b7e1423cf..9a9edb25f2d77 100644
--- a/clang/lib/StaticAnalyzer

[clang] 01ddfa9 - [analyzer] [NFC] Eliminate dispatchCast, evalCastFromNonLoc and evalCastFromLoc functions from SValBuilder

2021-04-13 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-04-13T18:56:04+03:00
New Revision: 01ddfa95bd14b35c5706cc5d69fe64b4b60526e3

URL: 
https://github.com/llvm/llvm-project/commit/01ddfa95bd14b35c5706cc5d69fe64b4b60526e3
DIFF: 
https://github.com/llvm/llvm-project/commit/01ddfa95bd14b35c5706cc5d69fe64b4b60526e3.diff

LOG: [analyzer] [NFC] Eliminate dispatchCast, evalCastFromNonLoc and 
evalCastFromLoc functions from SValBuilder

Summary: Remove dispatchCast, evalCastFromNonLoc and evalCastFromLoc functions 
since their functionality has been moved to common evalCast function. Use 
evalCast instead.

Post-clean up patch for https://reviews.llvm.org/D96090 patch. The patch shall 
not change any behavior.

Differential Revision: https://reviews.llvm.org/D97277

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 2358d2d66b30..99277e91ed06 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -72,9 +72,6 @@ class SValBuilder {
   /// The width of the scalar type used for array indices.
   const unsigned ArrayIndexWidth;
 
-  virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
-  virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
-
   SVal evalCastKind(UndefinedVal V, QualType CastTy, QualType OriginalTy);
   SVal evalCastKind(UnknownVal V, QualType CastTy, QualType OriginalTy);
   SVal evalCastKind(Loc V, QualType CastTy, QualType OriginalTy);
@@ -97,11 +94,6 @@ class SValBuilder {
   SVal evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
QualType OriginalTy);
 
-public:
-  // FIXME: Make these protected again once RegionStoreManager correctly
-  // handles loads from 
diff erent bound value types.
-  virtual SVal dispatchCast(SVal val, QualType castTy) = 0;
-
 public:
   SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
   ProgramStateManager &stateMgr)

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 9a9edb25f2d7..a49099384d2a 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -107,7 +107,7 @@ SVal SValBuilder::convertToArrayIndex(SVal val) {
   return val;
   }
 
-  return evalCastFromNonLoc(val.castAs(), ArrayIndexTy);
+  return evalCast(val, ArrayIndexTy, QualType{});
 }
 
 nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr 
*boolean){

diff  --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 7fe2374c9914..e57d92fbcebb 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -22,11 +22,6 @@ using namespace ento;
 
 namespace {
 class SimpleSValBuilder : public SValBuilder {
-protected:
-  SVal dispatchCast(SVal val, QualType castTy) override;
-  SVal evalCastFromNonLoc(NonLoc val, QualType castTy) override;
-  SVal evalCastFromLoc(Loc val, QualType castTy) override;
-
 public:
   SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
 ProgramStateManager &stateMgr)
@@ -61,134 +56,6 @@ SValBuilder 
*ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
   return new SimpleSValBuilder(alloc, context, stateMgr);
 }
 
-//===--===//
-// Transfer function for Casts.
-//===--===//
-
-// FIXME: This function should be eliminated and replaced with `evalCast`
-SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) {
-  return evalCast(Val, CastTy, QualType{});
-}
-
-// FIXME: This function should be eliminated and replaced with `evalCast`
-SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
-  bool isLocType = Loc::isLocType(castTy);
-  if (val.getAs())
-return val;
-
-  if (Optional LI = val.getAs()) {
-if (isLocType)
-  return LI->getLoc();
-// FIXME: Correctly support promotions/truncations.
-unsigned castSize = Context.getIntWidth(castTy);
-if (castSize == LI->getNumBits())
-  return val;
-return makeLocAsInteger(LI->getLoc(), castSize);
-  }
-
-  if (SymbolRef se = val.getAsSymbol()) {
-QualType T = Context.getCanonicalType(se->getType());
-// If types are the same or both are integers, ignore the cast.
-// FIXME: Remove this hack when we support symbolic truncation/extension.
-// HACK: If both castTy and 

[clang] 44e803e - [analyzer][NFCI] Move a block from `getBindingForElement` to separate functions

2021-10-25 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-10-25T15:14:10+03:00
New Revision: 44e803ef6d41770adf309960e37bcc6a75dbbe2c

URL: 
https://github.com/llvm/llvm-project/commit/44e803ef6d41770adf309960e37bcc6a75dbbe2c
DIFF: 
https://github.com/llvm/llvm-project/commit/44e803ef6d41770adf309960e37bcc6a75dbbe2c.diff

LOG: [analyzer][NFCI] Move a block from `getBindingForElement` to separate 
functions

Summary:
1. Improve readability by moving deeply nested block of code from 
RegionStoreManager::getBindingForElement to new separate functions:
- getConstantValFromConstArrayInitializer;
- getSValFromInitListExpr.
2. Handle the case when index is a symbolic value. Write specific test cases.
3. Add test cases when there is no initialization expression presented.
This patch implies to make next patches clearer and easier for review process.

Differential Revision: https://reviews.llvm.org/D106681

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.c
clang/test/Analysis/initialization.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 5e7352cc8756b..e0e6bca1e7cc3 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -437,6 +437,10 @@ class RegionStoreManager : public StoreManager {
 
   RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B,
 const SubRegion *R);
+  Optional getConstantValFromConstArrayInitializer(
+  RegionBindingsConstRef B, const VarRegion *VR, const ElementRegion *R);
+  Optional getSValFromInitListExpr(const InitListExpr *ILE,
+ uint64_t Offset, QualType ElemT);
 
 public: // Part of public interface to class.
 
@@ -1625,6 +1629,95 @@ 
RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
   return Result;
 }
 
+Optional RegionStoreManager::getConstantValFromConstArrayInitializer(
+RegionBindingsConstRef B, const VarRegion *VR, const ElementRegion *R) {
+  assert(R && VR && "Regions should not be null");
+
+  // Check if the containing array has an initialized value that we can trust.
+  // We can trust a const value or a value of a global initializer in main().
+  const VarDecl *VD = VR->getDecl();
+  if (!VD->getType().isConstQualified() &&
+  !R->getElementType().isConstQualified() &&
+  (!B.isMainAnalysis() || !VD->hasGlobalStorage()))
+return None;
+
+  // Array's declaration should have an initializer.
+  const Expr *Init = VD->getAnyInitializer();
+  if (!Init)
+return None;
+
+  // Array's declaration should have ConstantArrayType type, because only this
+  // type contains an array extent.
+  const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(VD->getType());
+  if (!CAT)
+return None;
+
+  // Array should be one-dimensional.
+  // TODO: Support multidimensional array.
+  if (isa(CAT->getElementType())) // is multidimensional
+return None;
+
+  // Array's offset should be a concrete value.
+  // Return Unknown value if symbolic index presented.
+  // FIXME: We also need to take ElementRegions with symbolic
+  // indexes into account.
+  const auto OffsetVal = R->getIndex().getAs();
+  if (!OffsetVal.hasValue())
+return UnknownVal();
+
+  // Check offset for being out of bounds.
+  // C++20 [expr.add] 7.6.6.4 (excerpt):
+  //   If P points to an array element i of an array object x with n
+  //   elements, where i < 0 or i > n, the behavior is undefined.
+  //   Dereferencing is not allowed on the "one past the last
+  //   element", when i == n.
+  // Example:
+  //   const int arr[4] = {1, 2};
+  //   const int *ptr = arr;
+  //   int x0 = ptr[0];  // 1
+  //   int x1 = ptr[1];  // 2
+  //   int x2 = ptr[2];  // 0
+  //   int x3 = ptr[3];  // 0
+  //   int x4 = ptr[4];  // UB
+  //   int x5 = ptr[-1]; // UB
+  const llvm::APSInt &OffsetInt = OffsetVal->getValue();
+  const auto Offset = static_cast(OffsetInt.getExtValue());
+  // Use `getZExtValue` because array extent can not be negative.
+  const uint64_t Extent = CAT->getSize().getZExtValue();
+  // Check for `OffsetInt < 0` but NOT for `Offset < 0`, because `OffsetInt`
+  // CAN be negative, but `Offset` can NOT, because `Offset` is an uint64_t.
+  if (OffsetInt < 0 || Offset >= Extent)
+return UndefinedVal();
+  // From here `Offset` is in the bounds.
+
+  // Handle InitListExpr.
+  if (const auto *ILE = dyn_cast(Init))
+return getSValFromInitListExpr(ILE, Offset, R->getElementType());
+
+  // FIXME: Handle StringLiteral.
+
+  // FIXME: Handle CompoundLiteralExpr.
+
+  return None;
+}
+
+Optional
+RegionStoreManager::getSValFromInitListExpr(const InitListExpr *ILE,
+uint64_t Offset, QualType ElemT) {
+  assert(ILE && "InitListExpr should not be null");
+
+  // C

[clang] 3b1165b - [analyzer] Retrieve incomplete array extent from its redeclaration.

2021-10-25 Thread Denys Petrov via cfe-commits

Author: Denys Petrov
Date: 2021-10-25T15:14:10+03:00
New Revision: 3b1165ba3d15de83699be3ff4be3b6adf4d6e977

URL: 
https://github.com/llvm/llvm-project/commit/3b1165ba3d15de83699be3ff4be3b6adf4d6e977
DIFF: 
https://github.com/llvm/llvm-project/commit/3b1165ba3d15de83699be3ff4be3b6adf4d6e977.diff

LOG: [analyzer] Retrieve incomplete array extent from its redeclaration.

Summary: Fix a case when the extent can not be retrieved correctly from 
incomplete array declaration. Use redeclaration to get the array extent.

Differential Revision: https://reviews.llvm.org/D111542

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index e0e6bca1e7cc..5565e9cfd08c 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1641,8 +1641,18 @@ Optional 
RegionStoreManager::getConstantValFromConstArrayInitializer(
   (!B.isMainAnalysis() || !VD->hasGlobalStorage()))
 return None;
 
-  // Array's declaration should have an initializer.
-  const Expr *Init = VD->getAnyInitializer();
+  // Array's declaration should have `ConstantArrayType` type, because only 
this
+  // type contains an array extent. It may happen that array type can be of
+  // `IncompleteArrayType` type. To get the declaration of `ConstantArrayType`
+  // type, we should find the declaration in the redeclarations chain that has
+  // the initialization expression.
+  // NOTE: `getAnyInitializer` has an out-parameter, which returns a new `VD`
+  // from which an initializer is obtained. We replace current `VD` with the 
new
+  // `VD`. If the return value of the function is null than `VD` won't be
+  // replaced.
+  const Expr *Init = VD->getAnyInitializer(VD);
+  // NOTE: If `Init` is non-null, then a new `VD` is non-null for sure. So 
check
+  // `Init` for null only and don't worry about the replaced `VD`.
   if (!Init)
 return None;
 

diff  --git a/clang/test/Analysis/initialization.c 
b/clang/test/Analysis/initialization.c
index 7981465394ea..9015113f8640 100644
--- a/clang/test/Analysis/initialization.c
+++ b/clang/test/Analysis/initialization.c
@@ -103,3 +103,42 @@ void glob_arr_index4() {
   // FIXME: Should warn {{FALSE}}, since the array has a static storage.
   clang_analyzer_eval(glob_arr_no_init[2]); // expected-warning{{UNKNOWN}}
 }
+
+const int glob_arr3[];  // IncompleteArrayType
+const int glob_arr3[4] = {1, 2, 3}; // ConstantArrayType
+void glob_arr_index5() {
+  clang_analyzer_eval(glob_arr3[0] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr3[1] == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr3[2] == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr3[3] == 0); // expected-warning{{TRUE}}
+}
+
+void glob_invalid_index5() {
+  int x = 42;
+  int res = glob_arr3[x]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_invalid_index6() {
+  int x = -42;
+  int res = glob_arr3[x]; // expected-warning{{garbage or undefined}}
+}
+
+const int glob_arr4[];  // IncompleteArrayType
+const int glob_arr4[4] = {1, 2, 3}; // ConstantArrayType
+const int glob_arr4[];  // ConstantArrayType (according to AST)
+void glob_arr_index6() {
+  clang_analyzer_eval(glob_arr4[0] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr4[1] == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr4[2] == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr4[3] == 0); // expected-warning{{TRUE}}
+}
+
+void glob_invalid_index7() {
+  int x = 42;
+  int res = glob_arr4[x]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_invalid_index8() {
+  int x = -42;
+  int res = glob_arr4[x]; // expected-warning{{garbage or undefined}}
+}



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits