[PATCH] D28952: [analyzer] Add new Z3 constraint manager backend

Devin Coughlin via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 12 15:19:14 PST 2017


dcoughlin added a comment.

Thanks for updating the tests to be able to run both the z3 and range-constraint managers! I think this will make it much easier to ensure the z3-backed manager continues to work as as expected moving forward. I suggested an alternative approach inline to running the tests under both managers, which you may wish to consider.

In https://reviews.llvm.org/D28952#669963, @ddcc wrote:

> I added support for a callback field in lit's configuration (see https://reviews.llvm.org/D29684), which is used to execute each testcase for each supported constraint solver backends at runtime. I believe this resolves all remaining issues, except for the remaining two testcase failures:
>
> 1. The testcase Analysis/reference.cpp currently fails, because the RangeConstraintManager has an internal optimization that assumes references are known to be non-zero (see RangeConstraintManager.cpp:422). This optimization is probably in the wrong place, and should be moved into the analyzer and out of the constraint solver. Unless anyone objects, I plan to modify this testcase so that this result is fine for the z3 solver backend.


This sounds reasonable to me.

> 1. The testcase Analysis/ptr-arith.c currently fails, because handling of ptrdiff_t is somewhat tricky. This constraint manager interface maps ptrdiff_t to a signed bitvector in Z3, and pointers to unsigned bitvectors in Z3. However, since this testcase compares the pointer values both directly and indirectly via ptrdiff_t, if a < b is true using a signed comparison, the same is not necessarily true using an unsigned comparison. Likewise, unless anyone objects, I plan to whitelist this result for the z3 solver backend.

I think in both cases whitelisting is the right thing to do -- just provide a comment in the test explaining why. If you have a sense of the right way to fix the problem, please add a // FIXME: in the test with a short description.

There are some minor comments inline. Also: It is important to make sure the build still works and the tests still pass even both when Z3 is not present and when it is not enabled.



================
Comment at: CMakeLists.txt:371
 
+option(CLANG_BUILD_Z3
+  "Build the static analyzer with the Z3 constraint manager." OFF)
----------------
I think it would be good to change the name of this setting to have the prefix "CLANG_ANALYZER_...". This will help make it clear in, for example, the ccmake interface, that the option is only relevant to the analyzer.


================
Comment at: lib/StaticAnalyzer/Core/CMakeLists.txt:62
+  ${Z3_LINK_FILES}
   )
----------------
This needs something like:
```
if(CLANG_BUILD_Z3 AND CLANG_HAVE_Z3)
  target_include_directories(clangStaticAnalyzerCore SYSTEM
  PRIVATE
  ${Z3_INCLUDE_DIR}
  )
endif()
```
so that the analyzer core can find the Z3 headers when they are installed outside of the usual system include paths.


================
Comment at: lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp:17
+
+#if defined(CLANG_BUILD_Z3) && defined(CLANG_HAVE_Z3)
+
----------------
Is it possible to expose only one Z3-related definition here? Does the C++ need to understand the distinction between CLANG_HAVE_Z3 and CLANG_BUILD_Z3?

Could the CMake expose one master build setting that is true when other two are both true?


================
Comment at: lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp:21
+
+using namespace clang;
+using namespace ento;
----------------
These 'using' declarations need to be moved outside the #if -- otherwise there is a compile error at the definition of CreateZ3ConstraintManager() when building without Z3.


================
Comment at: test/Analysis/lit.local.cfg:2
+import lit.TestRunner
+
+def callback(test, cmd):
----------------
Here is a suggestion that would avoid needing to block changes to 'lit' itself.

lit allows you to create different a different Test subclass in each test directory. You could create a custom subclass just for analyzer tests (we already do this for unit tests):

```
class AnalyzerTest(lit.formats.ShTest, object):

    def execute(self, test, litConfig):
        result = self.executeWithAnalyzeSubstitution(test, litConfig, '-analyzer-constraints=range')

        if result.code == lit.Test.FAIL:
            return result
      
        if test.config.build_z3 == 'ON' and test.config.have_z3 == '1':
            result = self.executeWithAnalyzeSubstitution(test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3')

        return result

    def executeWithAnalyzeSubstitution(self, test, litConfig, substitution):
        saved_substitutions = list(test.config.substitutions)
        test.config.substitutions.append(('%analyze', substitution))
        result = lit.TestRunner.executeShTest(test, litConfig, self.execute_external)
        test.config.substitutions = saved_substitutions

        return result


config.test_format = AnalyzerTest(config.test_format.execute_external)
```

Saving and mutating the substitutions is kind of janky, but it would avoid blocking this commit on an expanded lit interface.


https://reviews.llvm.org/D28952





More information about the cfe-commits mailing list