[PATCH][Review request] unix.Malloc checker improvement: +handling new/delete, +memory.MismatchedFree, +memory.MismatchedDelete, +improved display names for allocators/deallocators
Jordan Rose
jordan_rose at apple.com
Thu Feb 28 17:55:23 PST 2013
>>> Memory allocated by malloc() should be deallocated by free(), not operator delete[].
>> I'm really not sure whether it's better to mention the deallocator's expected allocator, or the allocated region's expected deallocator. Which mistake do you think people are more likely to make?
>>
>> (Also, I came up with that phrasing in ten seconds; it could totally change.)
> The second one of course. I definitely prefer to print the allocated region's expected deallocator.
> The single downside I see is that this breaks the uniformity of reports and complicate ReportBadFree(). (other reports about, for example, freeing addresses of labels, could not be printed in the new fashion)
Hm. I think we should still go with the second one.
One last major comment: in talking offline to Ted (Kremenek) about this, he pointed out that it has the potential to be a very noisy new warning. In the same way that we have unix.Malloc and alpha.unix.MallocWithAnnotations, it might be good to separate out cplusplus.NewDelete and...we don't have a good category for MismatchedFree, but maybe unix.MismatchedFree. That way we can control these checks individually; look for "MallocOptimistic" to see how it's currently being used.
Comments comments comments:
+// Used to check correspondence between allocators and deallocators.
+enum AllocationFamilies {
+ AF_None,
+ AF_Malloc,
+ AF_CXXNew,
+ AF_CXXNewArray
+};
Not sure if I introduced this or you, but we generally name enums in the singular (AllocationFamily rather than AllocationFamilies).
- static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
+ static RefState getReleased(const Stmt *s) {
+ return RefState(Released, s, AF_None);
+ }
static RefState getRelinquished(const Stmt *s) {
- return RefState(Relinquished, s);
+ return RefState(Relinquished, s, AF_None);
}
I'm wondering if you might as well preserve the families here. We're not using them now, but at the very least it could be nice for debugging.
+ if (FD->getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return false;
+
+ OverloadedOperatorKind Kind = FD->getOverloadedOperator();
+ if (Kind != OO_New && Kind != OO_Array_New &&
+ Kind != OO_Delete && Kind != OO_Array_Delete)
+ return false;
The second check takes care of the first here.
+ OverloadedOperatorKind K = FD->getDeclName().getCXXOverloadedOperator();
Can be shortened to FD->getOverloadedOperator() again.
+ SmallString<100> TempBuf;
+ llvm::raw_svector_ostream TempOs(TempBuf);
+
+ if (printAllocDeallocName(TempOs, C, AllocExpr))
+ os << " was allocated by " << TempOs.str() << ", not ";
+ else
+ os << " was not allocated by ";
Ah, I see why you were avoiding this. Nevertheless, I think this is a better experience for the user, and if we go with the new output this will get restructured a bit anyway. (As a tiny comment, you can probably shrink the SmallString to use less stack space, since most functions have much shorter names.)
Jordan
More information about the cfe-commits
mailing list