Skip to content

Commit 9dab2e3

Browse files
authored
[clang][Sema] Warn on return of pointer/reference to compound literal (#83741)
Emit a warning if pointer/reference to compound literal is returned from a function. In C, compound literals in block scope are lvalues that have automatic storage duration. In C++, compound literals in block scope are temporaries. In either case, returning a pointer/reference to a compound literal can cause a use-after-free bug. Fixes #8678
1 parent 0fbe45b commit 9dab2e3

File tree

3 files changed

+15
-3
lines changed

3 files changed

+15
-3
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9901,7 +9901,7 @@ def err_lifetimebound_ctor_dtor : Error<
99019901
// CHECK: returning address/reference of stack memory
99029902
def warn_ret_stack_addr_ref : Warning<
99039903
"%select{address of|reference to}0 stack memory associated with "
9904-
"%select{local variable|parameter}2 %1 returned">,
9904+
"%select{local variable|parameter|compound literal}2 %1 returned">,
99059905
InGroup<ReturnStackAddress>;
99069906
def warn_ret_local_temp_addr_ref : Warning<
99079907
"returning %select{address of|reference to}0 local temporary object">,

clang/lib/Sema/SemaInit.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7734,6 +7734,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
77347734
break;
77357735
}
77367736

7737+
case Stmt::CompoundLiteralExprClass: {
7738+
if (auto *CLE = dyn_cast<CompoundLiteralExpr>(Init)) {
7739+
if (!CLE->isFileScope())
7740+
Visit(Path, Local(CLE), RK);
7741+
}
7742+
break;
7743+
}
7744+
77377745
// FIXME: Visit the left-hand side of an -> or ->*.
77387746

77397747
default:
@@ -8289,6 +8297,10 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
82898297
if (LK == LK_StmtExprResult)
82908298
return false;
82918299
Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange;
8300+
} else if (auto *CLE = dyn_cast<CompoundLiteralExpr>(L)) {
8301+
Diag(DiagLoc, diag::warn_ret_stack_addr_ref)
8302+
<< Entity.getType()->isReferenceType() << CLE->getInitializer() << 2
8303+
<< DiagRange;
82928304
} else {
82938305
Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
82948306
<< Entity.getType()->isReferenceType() << DiagRange;

clang/test/Analysis/stack-addr-ps.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ int* f3(int x, int *y) {
2020

2121
void* compound_literal(int x, int y) {
2222
if (x)
23-
return &(unsigned short){((unsigned short)0x22EF)}; // expected-warning{{Address of stack memory}}
23+
return &(unsigned short){((unsigned short)0x22EF)}; // expected-warning{{Address of stack memory}} expected-warning{{address of stack memory}}
2424

2525
int* array[] = {};
2626
struct s { int z; double y; int w; };
2727

2828
if (y)
29-
return &((struct s){ 2, 0.4, 5 * 8 }); // expected-warning{{Address of stack memory}}
29+
return &((struct s){ 2, 0.4, 5 * 8 }); // expected-warning{{Address of stack memory}} expected-warning{{address of stack memory}}
3030

3131

3232
void* p = &((struct s){ 42, 0.4, x ? 42 : 0 });

0 commit comments

Comments
 (0)