}
};
+/// Represents a void* field that needs to be casted back to its dynamic type
+/// for a correct note message.
+class NeedsCastLocField final : public FieldNode {
+ QualType CastBackType;
+
+public:
+ NeedsCastLocField(const FieldRegion *FR, const QualType &T)
+ : FieldNode(FR), CastBackType(T) {}
+
+ virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+ Out << "uninitialized pointee ";
+ }
+
+ virtual void printPrefix(llvm::raw_ostream &Out) const override {
+ Out << "static_cast" << '<' << CastBackType.getAsString() << ">(";
+ }
+
+ virtual void printNode(llvm::raw_ostream &Out) const override {
+ Out << getVariableName(getDecl()) << ')';
+ }
+
+ virtual void printSeparator(llvm::raw_ostream &Out) const override {
+ Out << "->";
+ }
+};
+
} // end of anonymous namespace
// Utility function declarations.
QualType DynT = DynTInfo.getType();
+ // If the static type of the field is a void pointer, we need to cast it back
+ // to the dynamic type before dereferencing.
+ bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
+
if (isVoidPointer(DynT)) {
IsAnyFieldInitialized = true;
return false;
const TypedValueRegion *R = RecordV->getRegion();
- if (DynT->getPointeeType()->isStructureOrClassType())
+ if (DynT->getPointeeType()->isStructureOrClassType()) {
+ if (NeedsCastBack)
+ return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
+ }
if (DynT->getPointeeType()->isUnionType()) {
if (isUnionUninit(R)) {
+ if (NeedsCastBack)
+ return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
return addFieldToUninits(LocalChain.add(LocField(FR)));
} else {
IsAnyFieldInitialized = true;
"At this point FR must either have a primitive dynamic type, or it "
"must be a null, undefined, unknown or concrete pointer!");
- if (isPrimitiveUninit(DerefdV))
+ if (isPrimitiveUninit(DerefdV)) {
+ if (NeedsCastBack)
+ return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
return addFieldToUninits(LocalChain.add(LocField(FR)));
+ }
IsAnyFieldInitialized = true;
return false;
}
struct IntDynTypedVoidPointerTest1 {
- void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+ void *vptr; // expected-note{{uninitialized pointee 'static_cast<int *>(this->vptr)'}}
int dontGetFilteredByNonPedanticMode = 0;
IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
struct RecordDynTypedVoidPointerTest {
struct RecordType {
- int x; // expected-note{{uninitialized field 'this->vptr->x'}}
- int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+ int x; // expected-note{{uninitialized field 'static_cast<struct RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}}
+ int y; // expected-note{{uninitialized field 'static_cast<struct RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}}
};
void *vptr;
struct NestedNonVoidDynTypedVoidPointerTest {
struct RecordType {
- int x; // expected-note{{uninitialized field 'this->vptr->x'}}
- int y; // expected-note{{uninitialized field 'this->vptr->y'}}
- void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+ int x; // expected-note{{uninitialized field 'static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}}
+ int y; // expected-note{{uninitialized field 'static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}}
+ void *vptr; // expected-note{{uninitialized pointee 'static_cast<char *>(static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->vptr)'}}
};
void *vptr;