forked from OSchip/llvm-project
[clang][dataflow] Handle null pointers of type std::nullptr_t
Treat `std::nullptr_t` as a regular scalar type to avoid tripping assertions when analyzing code that uses `std::nullptr_t`. Differential Revision: https://reviews.llvm.org/D129097
This commit is contained in:
parent
d1af09ad96
commit
f10d271ae2
|
@ -155,6 +155,7 @@ public:
|
|||
|
||||
/// Returns a pointer value that represents a null pointer. Calls with
|
||||
/// `PointeeType` that are canonically equivalent will return the same result.
|
||||
/// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.
|
||||
PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
|
||||
|
||||
/// Returns a symbolic boolean value that models a boolean literal equal to
|
||||
|
@ -251,6 +252,17 @@ public:
|
|||
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2);
|
||||
|
||||
private:
|
||||
struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> {
|
||||
static QualType getEmptyKey() {
|
||||
// Allow a NULL `QualType` by using a different value as the empty key.
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<Type *>(1));
|
||||
}
|
||||
|
||||
using DenseMapInfo::getHashValue;
|
||||
using DenseMapInfo::getTombstoneKey;
|
||||
using DenseMapInfo::isEqual;
|
||||
};
|
||||
|
||||
/// Adds all constraints of the flow condition identified by `Token` and all
|
||||
/// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
|
||||
/// to track tokens of flow conditions that were already visited by recursive
|
||||
|
@ -311,7 +323,8 @@ private:
|
|||
// required to initialize the `PointeeLoc` field in `PointerValue`. Consider
|
||||
// creating a type-independent `NullPointerValue` without a `PointeeLoc`
|
||||
// field.
|
||||
llvm::DenseMap<QualType, PointerValue *> NullPointerVals;
|
||||
llvm::DenseMap<QualType, PointerValue *, NullableQualTypeDenseMapInfo>
|
||||
NullPointerVals;
|
||||
|
||||
AtomicBoolValue &TrueVal;
|
||||
AtomicBoolValue &FalseVal;
|
||||
|
|
|
@ -24,8 +24,8 @@ namespace dataflow {
|
|||
|
||||
StorageLocation &
|
||||
DataflowAnalysisContext::getStableStorageLocation(QualType Type) {
|
||||
assert(!Type.isNull());
|
||||
if (Type->isStructureOrClassType() || Type->isUnionType()) {
|
||||
if (!Type.isNull() &&
|
||||
(Type->isStructureOrClassType() || Type->isUnionType())) {
|
||||
// FIXME: Explore options to avoid eager initialization of fields as some of
|
||||
// them might not be needed for a particular analysis.
|
||||
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
|
||||
|
@ -57,8 +57,8 @@ DataflowAnalysisContext::getStableStorageLocation(const Expr &E) {
|
|||
|
||||
PointerValue &
|
||||
DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) {
|
||||
assert(!PointeeType.isNull());
|
||||
auto CanonicalPointeeType = PointeeType.getCanonicalType();
|
||||
auto CanonicalPointeeType =
|
||||
PointeeType.isNull() ? PointeeType : PointeeType.getCanonicalType();
|
||||
auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
|
||||
if (Res.second) {
|
||||
auto &PointeeLoc = getStableStorageLocation(CanonicalPointeeType);
|
||||
|
|
|
@ -2213,12 +2213,14 @@ TEST(TransferTest, IntegralToBooleanCastFromBool) {
|
|||
|
||||
TEST(TransferTest, NullToPointerCast) {
|
||||
std::string Code = R"(
|
||||
using my_nullptr_t = decltype(nullptr);
|
||||
struct Baz {};
|
||||
void target() {
|
||||
int *FooX = nullptr;
|
||||
int *FooY = nullptr;
|
||||
bool **Bar = nullptr;
|
||||
Baz *Baz = nullptr;
|
||||
my_nullptr_t Null = 0;
|
||||
// [[p]]
|
||||
}
|
||||
)";
|
||||
|
@ -2242,6 +2244,9 @@ TEST(TransferTest, NullToPointerCast) {
|
|||
const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
|
||||
ASSERT_THAT(BazDecl, NotNull());
|
||||
|
||||
const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null");
|
||||
ASSERT_THAT(NullDecl, NotNull());
|
||||
|
||||
const auto *FooXVal =
|
||||
cast<PointerValue>(Env.getValue(*FooXDecl, SkipPast::None));
|
||||
const auto *FooYVal =
|
||||
|
@ -2250,6 +2255,8 @@ TEST(TransferTest, NullToPointerCast) {
|
|||
cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
|
||||
const auto *BazVal =
|
||||
cast<PointerValue>(Env.getValue(*BazDecl, SkipPast::None));
|
||||
const auto *NullVal =
|
||||
cast<PointerValue>(Env.getValue(*NullDecl, SkipPast::None));
|
||||
|
||||
EXPECT_EQ(FooXVal, FooYVal);
|
||||
EXPECT_NE(FooXVal, BarVal);
|
||||
|
@ -2267,6 +2274,11 @@ TEST(TransferTest, NullToPointerCast) {
|
|||
const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();
|
||||
EXPECT_TRUE(isa<AggregateStorageLocation>(BazPointeeLoc));
|
||||
EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull());
|
||||
|
||||
const StorageLocation &NullPointeeLoc =
|
||||
NullVal->getPointeeLoc();
|
||||
EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));
|
||||
EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue