Skip to content

Commit 10dd123

Browse files
committedFeb 22, 2019
[analyzer] MIGChecker: Fix an FN when the object is released in a destructor.
When a MIG server routine argument is released in an automatic destructor, the Static Analyzer thinks that this happens after the return statement, and so the violation of the MIG convention doesn't happen. Of course, it doesn't quite work that way, so this is a false negative. Add a hack that makes the checker double-check at the end of function that no argument was released when the routine fails with an error. rdar://problem/35380337 Differential Revision: https://reviews.llvm.org/D58392 llvm-svn: 354642
1 parent 7479b3d commit 10dd123

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed
 

‎clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp

+18-3
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,30 @@ using namespace clang;
3232
using namespace ento;
3333

3434
namespace {
35-
class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>> {
35+
class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
36+
check::EndFunction> {
3637
BugType BT{this, "Use-after-free (MIG calling convention violation)",
3738
categories::MemoryError};
3839

3940
CallDescription vm_deallocate { "vm_deallocate", 3 };
4041

42+
void checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const;
43+
4144
public:
4245
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
43-
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
46+
47+
// HACK: We're making two attempts to find the bug: checkEndFunction
48+
// should normally be enough but it fails when the return value is a literal
49+
// that never gets put into the Environment and ends of function with multiple
50+
// returns get agglutinated across returns, preventing us from obtaining
51+
// the return value. The problem is similar to https://reviews.llvm.org/D25326
52+
// but now we step into it in the top-level function.
53+
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const {
54+
checkReturnAux(RS, C);
55+
}
56+
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const {
57+
checkReturnAux(RS, C);
58+
}
4459

4560
class Visitor : public BugReporterVisitor {
4661
public:
@@ -140,7 +155,7 @@ void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
140155
C.addTransition(C.getState()->set<ReleasedParameter>(PVD));
141156
}
142157

143-
void MIGChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const {
158+
void MIGChecker::checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const {
144159
// It is very unlikely that a MIG callback will be called from anywhere
145160
// within the project under analysis and the caller isn't itself a routine
146161
// that follows the MIG calling convention. Therefore we're safe to believe

‎clang/test/Analysis/mig.mm

+25
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,31 @@ kern_return_t release_twice(mach_port_name_t port, vm_address_t addr1, vm_addres
5656
// expected-note@-1{{MIG callback fails with error after deallocating argument value. This is a use-after-free vulnerability because the caller will try to deallocate it again}}
5757
}
5858

59+
// Make sure we find the bug when the object is destroyed within an
60+
// automatic destructor.
61+
MIG_SERVER_ROUTINE
62+
kern_return_t test_vm_deallocate_in_automatic_dtor(mach_port_name_t port, vm_address_t address, vm_size_t size) {
63+
struct WillDeallocate {
64+
mach_port_name_t port;
65+
vm_address_t address;
66+
vm_size_t size;
67+
~WillDeallocate() {
68+
vm_deallocate(port, address, size); // expected-note{{Value passed through parameter 'address' is deallocated}}
69+
}
70+
} will_deallocate{port, address, size};
71+
72+
if (size > 10) {
73+
// expected-note@-1{{Assuming 'size' is > 10}}
74+
// expected-note@-2{{Taking true branch}}
75+
return KERN_ERROR;
76+
// expected-note@-1{{Calling '~WillDeallocate'}}
77+
// expected-note@-2{{Returning from '~WillDeallocate'}}
78+
// expected-warning@-3{{MIG callback fails with error after deallocating argument value. This is a use-after-free vulnerability because the caller will try to deallocate it again}}
79+
// expected-note@-4 {{MIG callback fails with error after deallocating argument value. This is a use-after-free vulnerability because the caller will try to deallocate it again}}
80+
}
81+
return KERN_SUCCESS;
82+
}
83+
5984
// Check that we work on Objective-C messages and blocks.
6085
@interface I
6186
- (kern_return_t)fooAtPort:(mach_port_name_t)port withAddress:(vm_address_t)address ofSize:(vm_size_t)size;

0 commit comments

Comments
 (0)
Please sign in to comment.