2009-02-14 17:08:39 +00:00
|
|
|
//== SimpleConstraintManager.cpp --------------------------------*- C++ -*--==//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2009-02-14 17:08:39 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2017-02-25 04:51:31 +00:00
|
|
|
// This file defines SimpleConstraintManager, a class that provides a
|
|
|
|
// simplified constraint manager interface, compared to ConstraintManager.
|
2009-02-14 17:08:39 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-02-25 04:51:31 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
|
2012-05-08 03:27:16 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
|
2011-02-10 01:03:03 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
2011-08-15 22:09:50 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
|
2023-01-14 11:07:21 -08:00
|
|
|
#include <optional>
|
2009-02-14 17:08:39 +00:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
|
2010-12-23 07:20:52 +00:00
|
|
|
namespace ento {
|
2010-12-22 18:53:20 +00:00
|
|
|
|
2015-10-20 13:23:58 +00:00
|
|
|
SimpleConstraintManager::~SimpleConstraintManager() {}
|
2009-02-14 17:08:39 +00:00
|
|
|
|
2022-05-06 16:20:25 +02:00
|
|
|
ProgramStateRef SimpleConstraintManager::assumeInternal(ProgramStateRef State,
|
|
|
|
DefinedSVal Cond,
|
|
|
|
bool Assumption) {
|
[analyzer] Add support for testing the presence of weak functions.
When casting the address of a FunctionTextRegion to bool, or when adding
constraints to such an address, use a stand-in symbol to represent the
presence or absence of the function if the function is weakly linked.
This is groundwork for possible simple availability testing checks, and
can already catch mistakes involving inverted null checks for
weakly-linked functions.
Currently, the implementation reuses the "extent" symbols, originally created
for tracking the size of a malloc region. Since FunctionTextRegions cannot
be dereferenced, the extent symbol will never be used for anything else.
Still, this probably deserves a refactoring in the future.
This patch does not attempt to support testing the presence of weak
/variables/ (global variables), which would likely require much more of
a change and a generalization of "region structure metadata", like the
current "extents", vs. "region contents metadata", like CStringChecker's
"string length".
Patch by Richard <tarka.t.otter@googlemail.com>!
llvm-svn: 189492
2013-08-28 17:07:04 +00:00
|
|
|
// If we have a Loc value, cast it to a bool NonLoc first.
|
2023-01-14 12:31:01 -08:00
|
|
|
if (std::optional<Loc> LV = Cond.getAs<Loc>()) {
|
2016-12-13 01:40:41 +00:00
|
|
|
SValBuilder &SVB = State->getStateManager().getSValBuilder();
|
[analyzer] Add support for testing the presence of weak functions.
When casting the address of a FunctionTextRegion to bool, or when adding
constraints to such an address, use a stand-in symbol to represent the
presence or absence of the function if the function is weakly linked.
This is groundwork for possible simple availability testing checks, and
can already catch mistakes involving inverted null checks for
weakly-linked functions.
Currently, the implementation reuses the "extent" symbols, originally created
for tracking the size of a malloc region. Since FunctionTextRegions cannot
be dereferenced, the extent symbol will never be used for anything else.
Still, this probably deserves a refactoring in the future.
This patch does not attempt to support testing the presence of weak
/variables/ (global variables), which would likely require much more of
a change and a generalization of "region structure metadata", like the
current "extents", vs. "region contents metadata", like CStringChecker's
"string length".
Patch by Richard <tarka.t.otter@googlemail.com>!
llvm-svn: 189492
2013-08-28 17:07:04 +00:00
|
|
|
QualType T;
|
|
|
|
const MemRegion *MR = LV->getAsRegion();
|
|
|
|
if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
|
|
|
|
T = TR->getLocationType();
|
|
|
|
else
|
|
|
|
T = SVB.getContext().VoidPtrTy;
|
|
|
|
|
|
|
|
Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
|
2009-02-14 17:08:39 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2016-12-13 01:40:41 +00:00
|
|
|
return assume(State, Cond.castAs<NonLoc>(), Assumption);
|
2009-02-14 17:08:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 01:40:41 +00:00
|
|
|
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
|
|
|
|
NonLoc Cond, bool Assumption) {
|
|
|
|
State = assumeAux(State, Cond, Assumption);
|
2022-06-02 15:05:45 +02:00
|
|
|
if (EE)
|
2020-05-26 13:48:20 +02:00
|
|
|
return EE->processAssume(State, Cond, Assumption);
|
2016-12-13 01:40:41 +00:00
|
|
|
return State;
|
2009-02-14 17:08:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 01:40:41 +00:00
|
|
|
ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
|
|
|
|
NonLoc Cond,
|
|
|
|
bool Assumption) {
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2011-12-05 18:58:19 +00:00
|
|
|
// We cannot reason about SymSymExprs, and can only reason about some
|
|
|
|
// SymIntExprs.
|
2009-03-25 05:58:37 +00:00
|
|
|
if (!canReasonAbout(Cond)) {
|
2011-12-05 18:58:19 +00:00
|
|
|
// Just add the constraint to the expression without trying to simplify.
|
2020-07-31 18:57:04 +03:00
|
|
|
SymbolRef Sym = Cond.getAsSymbol();
|
2017-02-25 04:51:31 +00:00
|
|
|
assert(Sym);
|
|
|
|
return assumeSymUnsupported(State, Sym, Assumption);
|
2009-09-09 15:08:12 +00:00
|
|
|
}
|
2009-03-25 05:58:37 +00:00
|
|
|
|
[analyzer][NFC] Rework SVal kind representation (#71039)
The goal of this patch is to refine how the `SVal` base and sub-kinds
are represented by forming one unified enum describing the possible
SVals. This means that the `unsigned SVal::Kind` and the attached
bit-packing semantics would be replaced by a single unified enum. This
is more conventional and leads to a better debugging experience by
default. This eases the need of using debug pretty-printers, or the use
of runtime functions doing the printing for us like we do today by
calling `Val.dump()` whenever we inspect the values.
Previously, the first 2 bits of the `unsigned SVal::Kind` discriminated
the following quartet: `UndefinedVal`, `UnknownVal`, `Loc`, or `NonLoc`.
The rest of the upper bits represented the sub-kind, where the value
represented the index among only the `Loc`s or `NonLoc`s, effectively
attaching 2 meanings of the upper bits depending on the base-kind. We
don't need to pack these bits, as we have plenty even if we would use
just a plan-old `unsigned char`.
Consequently, in this patch, I propose to lay out all the (non-abstract)
`SVal` kinds into a single enum, along with some metadata (`BEGIN_Loc`,
`END_Loc`, `BEGIN_NonLoc`, `END_NonLoc`) artificial enum values, similar
how we do with the `MemRegions`.
Note that in the unified `SVal::Kind` enum, to differentiate
`nonloc::ConcreteInt` from `loc::ConcreteInt`, I had to prefix them with
`Loc` and `NonLoc` to resolve this ambiguity.
This should not surface in general, because I'm replacing the
`nonloc::Kind` enum items with `inline constexpr` global constants to
mimic the original behavior - and offer nicer spelling to these enum
values.
Some `SVal` constructors were not marked explicit, which I now mark as
such to follow best practices, and marked others as `/*implicit*/` to
clarify the intent.
During refactoring, I also found at least one function not marked
`LLVM_ATTRIBUTE_RETURNS_NONNULL`, so I did that.
The `TypeRetrievingVisitor` visitor had some accidental dead code,
namely: `VisitNonLocConcreteInt` and `VisitLocConcreteInt`.
Previously, the `SValVisitor` expected visit handlers of
`VisitNonLocXXXXX(nonloc::XXXXX)` and `VisitLocXXXXX(loc::XXXXX)`, where
I felt that envoding `NonLoc` and `Loc` in the name is not necessary as
the type of the parameter would select the right overload anyways, so I
simplified the naming of those visit functions.
The rest of the diff is a lot of times just formatting, because
`getKind()` by nature, frequently appears in switches, which means that
the whole switch gets automatically reformatted. I could probably undo
the formatting, but I didn't want to deviate from the rule unless
explicitly requested.
2023-11-04 15:26:59 +01:00
|
|
|
switch (Cond.getKind()) {
|
2009-02-14 17:08:39 +00:00
|
|
|
default:
|
2011-09-23 05:06:16 +00:00
|
|
|
llvm_unreachable("'Assume' not implemented for this NonLoc");
|
2009-02-14 17:08:39 +00:00
|
|
|
|
|
|
|
case nonloc::SymbolValKind: {
|
2013-02-20 05:52:05 +00:00
|
|
|
nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
|
2016-12-13 01:40:41 +00:00
|
|
|
SymbolRef Sym = SV.getSymbol();
|
|
|
|
assert(Sym);
|
2017-02-25 04:51:31 +00:00
|
|
|
return assumeSym(State, Sym, Assumption);
|
2009-03-26 03:35:11 +00:00
|
|
|
}
|
2009-02-14 17:08:39 +00:00
|
|
|
|
|
|
|
case nonloc::ConcreteIntKind: {
|
2024-12-19 12:51:40 +01:00
|
|
|
bool b = *Cond.castAs<nonloc::ConcreteInt>().getValue().get() != 0;
|
2009-06-18 22:57:13 +00:00
|
|
|
bool isFeasible = b ? Assumption : !Assumption;
|
2016-12-13 01:40:41 +00:00
|
|
|
return isFeasible ? State : nullptr;
|
2009-02-14 17:08:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 21:27:06 +00:00
|
|
|
case nonloc::PointerToMemberKind: {
|
|
|
|
bool IsNull = !Cond.castAs<nonloc::PointerToMember>().isNullMemberPointer();
|
|
|
|
bool IsFeasible = IsNull ? Assumption : !Assumption;
|
|
|
|
return IsFeasible ? State : nullptr;
|
|
|
|
}
|
|
|
|
|
2009-02-14 17:08:39 +00:00
|
|
|
case nonloc::LocAsIntegerKind:
|
2022-05-06 16:20:25 +02:00
|
|
|
return assumeInternal(State, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
|
|
|
|
Assumption);
|
2009-02-14 17:08:39 +00:00
|
|
|
} // end switch
|
|
|
|
}
|
|
|
|
|
2022-05-19 11:05:24 +02:00
|
|
|
ProgramStateRef SimpleConstraintManager::assumeInclusiveRangeInternal(
|
2015-09-22 20:31:19 +00:00
|
|
|
ProgramStateRef State, NonLoc Value, const llvm::APSInt &From,
|
|
|
|
const llvm::APSInt &To, bool InRange) {
|
|
|
|
|
|
|
|
assert(From.isUnsigned() == To.isUnsigned() &&
|
|
|
|
From.getBitWidth() == To.getBitWidth() &&
|
|
|
|
"Values should have same types!");
|
|
|
|
|
|
|
|
if (!canReasonAbout(Value)) {
|
|
|
|
// Just add the constraint to the expression without trying to simplify.
|
2020-07-31 18:57:04 +03:00
|
|
|
SymbolRef Sym = Value.getAsSymbol();
|
2015-09-22 20:31:19 +00:00
|
|
|
assert(Sym);
|
2017-02-25 04:51:31 +00:00
|
|
|
return assumeSymInclusiveRange(State, Sym, From, To, InRange);
|
2015-09-22 20:31:19 +00:00
|
|
|
}
|
|
|
|
|
[analyzer][NFC] Rework SVal kind representation (#71039)
The goal of this patch is to refine how the `SVal` base and sub-kinds
are represented by forming one unified enum describing the possible
SVals. This means that the `unsigned SVal::Kind` and the attached
bit-packing semantics would be replaced by a single unified enum. This
is more conventional and leads to a better debugging experience by
default. This eases the need of using debug pretty-printers, or the use
of runtime functions doing the printing for us like we do today by
calling `Val.dump()` whenever we inspect the values.
Previously, the first 2 bits of the `unsigned SVal::Kind` discriminated
the following quartet: `UndefinedVal`, `UnknownVal`, `Loc`, or `NonLoc`.
The rest of the upper bits represented the sub-kind, where the value
represented the index among only the `Loc`s or `NonLoc`s, effectively
attaching 2 meanings of the upper bits depending on the base-kind. We
don't need to pack these bits, as we have plenty even if we would use
just a plan-old `unsigned char`.
Consequently, in this patch, I propose to lay out all the (non-abstract)
`SVal` kinds into a single enum, along with some metadata (`BEGIN_Loc`,
`END_Loc`, `BEGIN_NonLoc`, `END_NonLoc`) artificial enum values, similar
how we do with the `MemRegions`.
Note that in the unified `SVal::Kind` enum, to differentiate
`nonloc::ConcreteInt` from `loc::ConcreteInt`, I had to prefix them with
`Loc` and `NonLoc` to resolve this ambiguity.
This should not surface in general, because I'm replacing the
`nonloc::Kind` enum items with `inline constexpr` global constants to
mimic the original behavior - and offer nicer spelling to these enum
values.
Some `SVal` constructors were not marked explicit, which I now mark as
such to follow best practices, and marked others as `/*implicit*/` to
clarify the intent.
During refactoring, I also found at least one function not marked
`LLVM_ATTRIBUTE_RETURNS_NONNULL`, so I did that.
The `TypeRetrievingVisitor` visitor had some accidental dead code,
namely: `VisitNonLocConcreteInt` and `VisitLocConcreteInt`.
Previously, the `SValVisitor` expected visit handlers of
`VisitNonLocXXXXX(nonloc::XXXXX)` and `VisitLocXXXXX(loc::XXXXX)`, where
I felt that envoding `NonLoc` and `Loc` in the name is not necessary as
the type of the parameter would select the right overload anyways, so I
simplified the naming of those visit functions.
The rest of the diff is a lot of times just formatting, because
`getKind()` by nature, frequently appears in switches, which means that
the whole switch gets automatically reformatted. I could probably undo
the formatting, but I didn't want to deviate from the rule unless
explicitly requested.
2023-11-04 15:26:59 +01:00
|
|
|
switch (Value.getKind()) {
|
2015-09-22 20:31:19 +00:00
|
|
|
default:
|
2016-11-15 01:54:41 +00:00
|
|
|
llvm_unreachable("'assumeInclusiveRange' is not implemented"
|
2015-09-22 20:31:19 +00:00
|
|
|
"for this NonLoc");
|
|
|
|
|
|
|
|
case nonloc::LocAsIntegerKind:
|
|
|
|
case nonloc::SymbolValKind: {
|
|
|
|
if (SymbolRef Sym = Value.getAsSymbol())
|
2017-02-25 04:51:31 +00:00
|
|
|
return assumeSymInclusiveRange(State, Sym, From, To, InRange);
|
2015-09-22 20:31:19 +00:00
|
|
|
return State;
|
|
|
|
} // end switch
|
|
|
|
|
|
|
|
case nonloc::ConcreteIntKind: {
|
|
|
|
const llvm::APSInt &IntVal = Value.castAs<nonloc::ConcreteInt>().getValue();
|
|
|
|
bool IsInRange = IntVal >= From && IntVal <= To;
|
|
|
|
bool isFeasible = (IsInRange == InRange);
|
|
|
|
return isFeasible ? State : nullptr;
|
|
|
|
}
|
|
|
|
} // end switch
|
|
|
|
}
|
|
|
|
|
2010-12-23 07:20:52 +00:00
|
|
|
} // end of namespace ento
|
2010-12-22 18:53:20 +00:00
|
|
|
|
|
|
|
} // end of namespace clang
|