diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h @@ -146,7 +146,7 @@ Solver->addConstraint(NotExp); Optional isNotSat = Solver->check(); - if (!isSat.hasValue() || isNotSat.getValue()) + if (!isNotSat.hasValue() || isNotSat.getValue()) return nullptr; // This is the only solution, store it diff --git a/clang/test/Analysis/z3/D83660.c b/clang/test/Analysis/z3/D83660.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/z3/D83660.c @@ -0,0 +1,23 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %host_cxx -shared -fPIC %S/Inputs/MockZ3_solver_check.c -o %t/MockZ3_solver_check.so +// +// RUN: LD_PRELOAD="%t/MockZ3_solver_check.so" \ +// RUN: %clang_cc1 -analyze -analyzer-constraints=z3 -setup-static-analyzer \ +// RUN: -analyzer-checker=core,debug.ExprInspection %s -verify 2>&1 | FileCheck %s +// +// REQUIRES: z3, asserts, shell, system-linux +// +// Works only with the z3 constraint manager. +// expected-no-diagnostics + +// CHECK: Z3_solver_check returns the real value: TRUE +// CHECK-NEXT: Z3_solver_check returns the real value: TRUE +// CHECK-NEXT: Z3_solver_check returns the real value: TRUE +// CHECK-NEXT: Z3_solver_check returns the real value: TRUE +// CHECK-NEXT: Z3_solver_check returns a mocked value: UNDEF + +void D83660(int b) { + if (b) { + } + (void)b; // no-crash +} diff --git a/clang/test/Analysis/z3/Inputs/MockZ3_solver_check.c b/clang/test/Analysis/z3/Inputs/MockZ3_solver_check.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/z3/Inputs/MockZ3_solver_check.c @@ -0,0 +1,28 @@ +#include +#include + +#include + +// Mock implementation: return UNDEF for the 5th invocation, otherwise it just +// returns the result of the real invocation. +Z3_lbool Z3_API Z3_solver_check(Z3_context c, Z3_solver s) { + static Z3_lbool (*OriginalFN)(Z3_context, Z3_solver); + if (!OriginalFN) { + OriginalFN = (Z3_lbool(*)(Z3_context, Z3_solver))dlsym(RTLD_NEXT, + "Z3_solver_check"); + } + + // Invoke the actual solver. + Z3_lbool Result = OriginalFN(c, s); + + // Mock the 5th invocation to return UNDEF. + static unsigned int Counter = 0; + if (++Counter == 5) { + fprintf(stderr, "Z3_solver_check returns a mocked value: UNDEF\n"); + return Z3_L_UNDEF; + } + fprintf(stderr, "Z3_solver_check returns the real value: %s\n", + (Result == Z3_L_UNDEF ? "UNDEF" + : ((Result == Z3_L_TRUE ? "TRUE" : "FALSE")))); + return Result; +}