Skip to content

Commit 9b1dbaf

Browse files
committed
fix-missing-lifetimeends-for-params
1 parent d44d329 commit 9b1dbaf

File tree

5 files changed

+106
-9
lines changed

5 files changed

+106
-9
lines changed

clang/lib/Analysis/CFG.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,12 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
16661666
assert(Succ == &cfg->getExit());
16671667
Block = nullptr; // the EXIT block is empty. Create all other blocks lazily.
16681668

1669+
// Add parameters to the initial scope to handle their dtos and lifetime ends.
1670+
LocalScope *paramScope = nullptr;
1671+
if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
1672+
for (ParmVarDecl *PD : FD->parameters())
1673+
paramScope = addLocalScopeForVarDecl(PD, paramScope);
1674+
16691675
if (BuildOpts.AddImplicitDtors)
16701676
if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
16711677
addImplicitDtorsForDestructor(DD);
@@ -2246,6 +2252,9 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
22462252
if (!VD->hasLocalStorage())
22472253
return Scope;
22482254

2255+
if (isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType())
2256+
return Scope;
2257+
22492258
if (!BuildOpts.AddLifetime && !BuildOpts.AddScopes &&
22502259
!needsAutomaticDestruction(VD)) {
22512260
assert(BuildOpts.AddImplicitDtors);
@@ -5616,8 +5625,14 @@ class StmtPrinterHelper : public PrinterHelper {
56165625
bool handleDecl(const Decl *D, raw_ostream &OS) {
56175626
DeclMapTy::iterator I = DeclMap.find(D);
56185627

5619-
if (I == DeclMap.end())
5628+
if (I == DeclMap.end()) {
5629+
// CFG does not have the decls for ParmVarDecl.
5630+
if (auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
5631+
OS << "[Parm: " << PVD->getNameAsString() << "]";
5632+
return true;
5633+
}
56205634
return false;
5635+
}
56215636

56225637
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
56235638
&& I->second.second == currStmt) {

clang/test/Analysis/lifetime-cfg-output.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,3 +935,31 @@ int backpatched_goto() {
935935
goto label;
936936
i++;
937937
}
938+
939+
// CHECK: [B2 (ENTRY)]
940+
// CHECK-NEXT: Succs (1): B1
941+
// CHECK: [B1]
942+
// CHECK-NEXT: 1: a
943+
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
944+
// CHECK-NEXT: 3: b
945+
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, LValueToRValue, int)
946+
// CHECK-NEXT: 5: [B1.2] + [B1.4]
947+
// CHECK-NEXT: 6: c
948+
// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, LValueToRValue, int)
949+
// CHECK-NEXT: 8: [B1.5] + [B1.7]
950+
// CHECK-NEXT: 9: int res = a + b + c;
951+
// CHECK-NEXT: 10: res
952+
// CHECK-NEXT: 11: [B1.10] (ImplicitCastExpr, LValueToRValue, int)
953+
// CHECK-NEXT: 12: return [B1.11];
954+
// CHECK-NEXT: 13: [B1.9] (Lifetime ends)
955+
// CHECK-NEXT: 14: [Parm: c] (Lifetime ends)
956+
// CHECK-NEXT: 15: [Parm: b] (Lifetime ends)
957+
// CHECK-NEXT: 16: [Parm: a] (Lifetime ends)
958+
// CHECK-NEXT: Preds (1): B2
959+
// CHECK-NEXT: Succs (1): B0
960+
// CHECK: [B0 (EXIT)]
961+
// CHECK-NEXT: Preds (1): B1
962+
int test_param_scope_end_order(int a, int b, int c) {
963+
int res = a + b + c;
964+
return res;
965+
}

clang/test/Analysis/scopes-cfg-output.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,12 +1437,14 @@ void test_cleanup_functions() {
14371437
// CHECK-NEXT: 4: return;
14381438
// CHECK-NEXT: 5: CleanupFunction (cleanup_int)
14391439
// CHECK-NEXT: 6: CFGScopeEnd(i)
1440+
// CHECK-NEXT: 7: CFGScopeEnd(m)
14401441
// CHECK-NEXT: Preds (1): B3
14411442
// CHECK-NEXT: Succs (1): B0
14421443
// CHECK: [B2]
14431444
// CHECK-NEXT: 1: return;
14441445
// CHECK-NEXT: 2: CleanupFunction (cleanup_int)
14451446
// CHECK-NEXT: 3: CFGScopeEnd(i)
1447+
// CHECK-NEXT: 4: CFGScopeEnd(m)
14461448
// CHECK-NEXT: Preds (1): B3
14471449
// CHECK-NEXT: Succs (1): B0
14481450
// CHECK: [B3]

clang/test/Sema/warn-lifetime-safety.cpp

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -529,14 +529,14 @@ TriviallyDestructedClass* trivial_class_uar () {
529529
return ptr; // expected-note {{returned here}}
530530
}
531531

532-
// FIXME: No lifetime warning for this as no expire facts are generated for parameters
533532
const int& return_parameter(int a) {
534-
return a;
533+
return a; // expected-warning {{address of stack memory is returned later}}
534+
// expected-note@-1 {{returned here}}
535535
}
536536

537-
// FIXME: No lifetime warning for this as no expire facts are generated for parameters
538537
int* return_pointer_to_parameter(int a) {
539-
return &a;
538+
return &a; // expected-warning {{address of stack memory is returned later}}
539+
// expected-note@-1 {{returned here}}
540540
}
541541

542542
const int& return_reference_to_parameter(int a)
@@ -788,9 +788,52 @@ const MyObj& lifetimebound_return_ref_to_local() {
788788
// expected-note@-1 {{returned here}}
789789
}
790790

791-
// FIXME: Fails to diagnose UAR when a reference to a by-value param escapes via the return value.
792-
View lifetimebound_return_of_by_value_param(MyObj stack_param) {
793-
return Identity(stack_param);
791+
View lifetimebound_return_by_value_param(MyObj stack_param) {
792+
return Identity(stack_param); // expected-warning {{address of stack memory is returned later}}
793+
// expected-note@-1 {{returned here}}
794+
}
795+
796+
View lifetimebound_return_by_value_multiple_param(int cond, MyObj a, MyObj b, MyObj c) {
797+
if (cond == 1)
798+
return Identity(a); // expected-warning {{address of stack memory is returned later}}
799+
// expected-note@-1 {{returned here}}
800+
if (cond == 2)
801+
return Identity(b); // expected-warning {{address of stack memory is returned later}}
802+
// expected-note@-1 {{returned here}}
803+
return Identity(c); // expected-warning {{address of stack memory is returned later}}
804+
// expected-note@-1 {{returned here}}
805+
}
806+
807+
template<class T>
808+
View lifetimebound_return_by_value_param_template(T t) {
809+
return Identity(t); // expected-warning {{address of stack memory is returned later}}
810+
// expected-note@-1 {{returned here}}
811+
}
812+
void use_lifetimebound_return_by_value_param_template() {
813+
lifetimebound_return_by_value_param_template(MyObj{}); // expected-note {{in instantiation of}}
814+
}
815+
816+
void lambda_uar_param() {
817+
auto lambda = [](MyObj stack_param) {
818+
return Identity(stack_param); // expected-warning {{address of stack memory is returned later}}
819+
// expected-note@-1 {{returned here}}
820+
};
821+
lambda(MyObj{});
822+
}
823+
824+
// FIXME: This should be detected. We see correct destructors but origin flow breaks somewhere.
825+
namespace VariadicTemplatedParamsUAR{
826+
827+
template<typename... Args>
828+
View Max(Args... args [[clang::lifetimebound]]);
829+
830+
template<typename... Args>
831+
View lifetimebound_return_of_variadic_param(Args... args) {
832+
return Max(args...);
833+
}
834+
void test_variadic() {
835+
lifetimebound_return_of_variadic_param(MyObj{1}, MyObj{2}, MyObj{3});
836+
}
794837
}
795838

796839
// FIXME: Fails to diagnose UAF when a reference to a by-value param escapes via an out-param.

clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,18 @@ recordState(Elements=8, Branches=2, Joins=1)
149149
enterElement(return b ? p : q;)
150150
transfer()
151151
recordState(Elements=9, Branches=2, Joins=1)
152+
enterElement([Parm: q] (Lifetime ends))
153+
transfer()
154+
recordState(Elements=10, Branches=2, Joins=1)
155+
enterElement([Parm: p] (Lifetime ends))
156+
transfer()
157+
recordState(Elements=11, Branches=2, Joins=1)
158+
enterElement([Parm: b] (Lifetime ends))
159+
transfer()
160+
recordState(Elements=12, Branches=2, Joins=1)
152161
153162
enterBlock(0, false)
154-
recordState(Elements=9, Branches=2, Joins=1)
163+
recordState(Elements=12, Branches=2, Joins=1)
155164
156165
endAnalysis()
157166
)");

0 commit comments

Comments
 (0)