Skip to content

Commit 1888094

Browse files
committed
[clang][Interp] Check pointers for live-ness when returning them
We might be trying to return a pointer or reference to a local variable, which doesn't work. Differential Revision: https://reviews.llvm.org/D154795
1 parent f606a43 commit 1888094

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

clang/lib/AST/Interp/Interp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
181181
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
182182
const T &Ret = S.Stk.pop<T>();
183183

184+
// Make sure returned pointers are live. We might be trying to return a
185+
// pointer or reference to a local variable.
186+
// Just return false, since a diagnostic has already been emitted in Sema.
187+
if constexpr (std::is_same_v<T, Pointer>) {
188+
// FIXME: We could be calling isLive() here, but the emitted diagnostics
189+
// seem a little weird, at least if the returned expression is of
190+
// pointer type.
191+
if (!Ret.isLive())
192+
return false;
193+
}
194+
184195
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
185196
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
186197
S.Current->popArgs();

clang/test/AST/Interp/functions.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,29 @@ namespace CallWithArgs {
265265
g(0);
266266
}
267267
}
268+
269+
namespace ReturnLocalPtr {
270+
constexpr int *p() {
271+
int a = 12;
272+
return &a; // ref-warning {{address of stack memory}} \
273+
// expected-warning {{address of stack memory}}
274+
}
275+
276+
/// GCC rejects the expression below, just like the new interpreter. The current interpreter
277+
/// however accepts it and only warns about the function above returning an address to stack
278+
/// memory. If we change the condition to 'p() != nullptr', it even succeeds.
279+
static_assert(p() == nullptr, ""); // ref-error {{static assertion failed}} \
280+
// expected-error {{not an integral constant expression}}
281+
282+
/// FIXME: The current interpreter emits diagnostics in the reference case below, but the
283+
/// new one does not.
284+
constexpr const int &p2() {
285+
int a = 12; // ref-note {{declared here}}
286+
return a; // ref-warning {{reference to stack memory associated with local variable}} \
287+
// expected-warning {{reference to stack memory associated with local variable}}
288+
}
289+
290+
static_assert(p2() == 12, ""); // ref-error {{not an integral constant expression}} \
291+
// ref-note {{read of variable whose lifetime has ended}} \
292+
// expected-error {{not an integral constant expression}}
293+
}

0 commit comments

Comments
 (0)