Skip to content

Commit

Permalink
Diagnose misuse of the cleanup attribute (#80040)
Browse files Browse the repository at this point in the history
This pull request fixes #79443 when the cleanup attribute is intended to
be applied to a variable declaration, passing its address to a specified
function. The problem arises when standard functions like free,
closedir, fclose, etc., are used incorrectly with this attribute,
leading to incorrect behavior.

Fixes #79443
  • Loading branch information
11happy committed Mar 13, 2024
1 parent bb893fa commit ccd1608
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ Improvements to Clang's diagnostics
- Clang now diagnoses lambda function expressions being implicitly cast to boolean values, under ``-Wpointer-bool-conversion``.
Fixes #GH82512.

- Clang now provides improved warnings for the ``cleanup`` attribute to detect misuse scenarios,
such as attempting to call ``free`` on an unallocated object. Fixes
`#79443 <https://github.com/llvm/llvm-project/issues/79443>`_.

Improvements to Clang's time-trace
----------------------------------

Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2152,14 +2152,15 @@ class Sema final {

bool IsLayoutCompatible(QualType T1, QualType T2) const;

bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
const FunctionProtoType *Proto);

private:
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE = nullptr,
bool AllowOnePastEnd = true, bool IndexNegated = false);
void CheckArrayAccess(const Expr *E);

bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
const FunctionProtoType *Proto);
bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
ArrayRef<const Expr *> Args);
bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
Expand Down
24 changes: 24 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3787,6 +3787,30 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< NI.getName() << ParamTy << Ty;
return;
}
VarDecl *VD = cast<VarDecl>(D);
// Create a reference to the variable declaration. This is a fake/dummy
// reference.
DeclRefExpr *VariableReference = DeclRefExpr::Create(
S.Context, NestedNameSpecifierLoc{}, FD->getLocation(), VD, false,
DeclarationNameInfo{VD->getDeclName(), VD->getLocation()}, VD->getType(),
VK_LValue);

// Create a unary operator expression that represents taking the address of
// the variable. This is a fake/dummy expression.
Expr *AddressOfVariable = UnaryOperator::Create(
S.Context, VariableReference, UnaryOperatorKind::UO_AddrOf,
S.Context.getPointerType(VD->getType()), VK_PRValue, OK_Ordinary, Loc,
+false, FPOptionsOverride{});

// Create a function call expression. This is a fake/dummy call expression.
CallExpr *FunctionCallExpression =
CallExpr::Create(S.Context, E, ArrayRef{AddressOfVariable},
S.Context.VoidTy, VK_PRValue, Loc, FPOptionsOverride{});

if (S.CheckFunctionCall(FD, FunctionCallExpression,
FD->getType()->getAs<FunctionProtoType>())) {
return;
}

D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
}
Expand Down
28 changes: 26 additions & 2 deletions clang/test/Sema/attr-cleanup.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
// RUN: %clang_cc1 -Wfree-nonheap-object -fsyntax-only -verify %s

void c1(int *a);

typedef __typeof__(sizeof(0)) size_t;
extern int g1 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute only applies to local variables}}
int g2 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute only applies to local variables}}
static int g3 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute only applies to local variables}}
Expand Down Expand Up @@ -48,3 +48,27 @@ void t6(void) {
}

void t7(__attribute__((cleanup(c4))) int a) {} // expected-warning {{'cleanup' attribute only applies to local variables}}

extern void free(void *);
extern void *malloc(size_t size);
void t8(void) {
void *p
__attribute__((
cleanup(
free // expected-warning{{attempt to call free on non-heap object 'p'}}
)
))
= malloc(10);
}
typedef __attribute__((aligned(2))) int Aligned2Int;
void t9(void){
Aligned2Int __attribute__((cleanup(c1))) xwarn; // expected-warning{{passing 2-byte aligned argument to 4-byte aligned parameter 1 of 'c1' may result in an unaligned pointer access}}
}

__attribute__((enforce_tcb("TCB1"))) void func1(int *x) {
*x = 5;
}
__attribute__((enforce_tcb("TCB2"))) void t10() {
int __attribute__((cleanup(func1))) x = 5; // expected-warning{{calling 'func1' is a violation of trusted computing base 'TCB2'}}
}

0 comments on commit ccd1608

Please sign in to comment.