[PATCH][Review request] unix.Malloc checker improvement: +handling new/delete, +memory.MismatchedFree, +memory.MismatchedDelete, +improved display names for allocators/deallocators

Anton Yartsev anton.yartsev at gmail.com
Thu Feb 21 18:00:04 PST 2013


>
> On Feb 19, 2013, at 10:18 PM, Anton Yartsev <anton.yartsev at gmail.com 
> <mailto:anton.yartsev at gmail.com>> wrote:
>
>> Hi, Jordan. Thanx for the review!
>>
>> Attached is the new version of the patch with all the comments 
>> addressed. Also added support for directly called operator 
>> new()/new[]() and operator delete()
>>
>> There is currently one problem with handling of operator delete(). 
>> The following test
>>
>> void testDeleteOp1() {
>>  int *p = (int *)malloc(sizeof(int));
>>  operator delete(p); // FIXME: should complain "Argument to operator 
>> delete() was allocated by malloc(), not operator new"
>> }
>>
>> produce no warnings as attached RefState seem to be missing at the 
>> point when checkPostStmt(const CallExpr *CE, CheckerContext &C) 
>> callback is called for operator delete(p).
>> I haven't investigated the problem deeply yet, intend to address it 
>> parallel with the review.
>>
>>> +  if (NE->getNumPlacementArgs())
>>> +    return;
>>> +  // skip placement new operators as they may not allocate memory
>>>
>>> Two comments here:
>>> - Please make sure all comments are complete, capitalized, and 
>>> punctuated sentences. (This has the important one, 
>>> "complete"....just missing capitalization and punctuation.)
>> I'll try. Unfortunately I am not as good in English as I want to be, 
>> so sorry for my grammar, syntax, and punctuation.
>>
>> -- 
>> Anton
>>
>> <MallocChecker_v2.patch>
>

Hi Anna. Thanks for your comments! Attached is the new patch.

> Just adding another kind as extra enumeration values does not seem 
> right. Another option is to make Kind be a pointer to a static array, 
> which contains objects recording all necessary info about each kind 
> (MacOSKeychainAPIChecker uses this approach). This is probably an 
> overkill for now, but is another option.
Not sure that I have got an idea.
The memory and deallocator kind are both set for a RefState. Do you mean 
creating a static array with 'memory kinds' * 'deallocator kind' 
elements for all possible combinations? Also there is no necessary info 
other then the kind itself.
Left for now.

> +  const FunctionDecl *getCalleeDecl() const { return CalleeDecl; }
> Do we only store the name of the allocator declaration here? Do we 
> need to store this in the state? (Growing states implies memory 
> overhead.) Can't this be easily implied from the kind?
Kind can't give us information about the name of an allocator that can 
be malloc(), realloc(), a user function with ownership_takes attribute, etc.
One solution to avoid keeping a CalleeDecl in RefState is to rollback to 
CallExpr::getDirectCallee() from CheckerContext::getCalleeDec() and to 
print "malloc()" in case of indirect calls.
Jordan, what do you think about this?

> +void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
> +                                  CheckerContext &C) const {NE
> +
> +  FunctionDecl *OperatorNew = NE->getOperatorNew();
> +  if (!OperatorNew)
> +    return;
> +
> +  // Skip custom new operators
> +  if (!OperatorNew->isImplicit() &&
> +  !C.getSourceManager().isInSystemHeader(OperatorNew->getLocStart()) &&
> +      !NE->isGlobalNew())
> +    return;
> +
> +  // Skip standard global placement operator new/new[](std::size_t, 
> void * p);
> +  // process all other standard new/new[] operators including placement
> +  // operators new/new[](std::size_t, const std::nothrow_t&)
> +  if (OperatorNew->isReservedGlobalPlacementOperator())
> +    return;
>
> Is there a reason why we first process each operator new in 
> "checkPostStmt(const callExpr" and finish processing in 
> "checkPostStmt(const CXXNewExpr" ? I think the code would be simpler 
> if everything could be done in a single callback.
Code added to "checkPostStmt(const callExpr" is for processing direct 
calls to operator new/delete functions, "checkPostStmt(const CXXNewExpr" 
is for handling new expressions. Either first or second callback is 
called in each particular case but not both of them. Am I right?

>
> +void MallocChecker::PrintExpectedAllocName(raw_ostream &os, 
> CheckerContext &C,
> +                                           const Expr *E) const {
> +  DeallocatorKind dKind = GetDeallocKind(C, E);
> +
> +  switch(dKind) {
> +    case D_free: os << "malloc()"; return;
> +    case D_delete: os << "operator new"; return;
> +    case D_deleteArray: os << "operator new[]"; return;
> +    case D_unknown: os << "unknown means"; return;
>
> This function is used to form user visible warnings. Do we ever expect 
> it to print "unknown means"? Can this be based on the Kind stored 
> inside of RefState, where there is no D_unknown?
Right, changed the case to assert. There is actually implicit D_unknown 
in RefState - case when 2nd and 3rd bits are set to zero.

-- 
Anton

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130222/5bc0d503/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MallocChecker_v3.patch
Type: text/x-diff
Size: 31923 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130222/5bc0d503/attachment.patch>


More information about the cfe-commits mailing list