Skip to content

Commit

Permalink
[clang][Interp] Check pointers for live-ness when returning them
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tbaederr committed Jul 26, 2023
1 parent fca4a9d commit c725138
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
11 changes: 11 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,17 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
const T &Ret = S.Stk.pop<T>();

// Make sure returned pointers are live. We might be trying to return a
// pointer or reference to a local variable.
// Just return false, since a diagnostic has already been emitted in Sema.
if constexpr (std::is_same_v<T, Pointer>) {
// FIXME: We could be calling isLive() here, but the emitted diagnostics
// seem a little weird, at least if the returned expression is of
// pointer type.
if (!Ret.isLive())
return false;
}

assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
S.Current->popArgs();
Expand Down
26 changes: 26 additions & 0 deletions clang/test/AST/Interp/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,29 @@ namespace CallWithArgs {
g(0);
}
}

namespace ReturnLocalPtr {
constexpr int *p() {
int a = 12;
return &a; // ref-warning {{address of stack memory}} \
// expected-warning {{address of stack memory}}
}

/// GCC rejects the expression below, just like the new interpreter. The current interpreter
/// however accepts it and only warns about the function above returning an address to stack
/// memory. If we change the condition to 'p() != nullptr', it even succeeds.
static_assert(p() == nullptr, ""); // ref-error {{static assertion failed}} \
// expected-error {{not an integral constant expression}}

/// FIXME: The current interpreter emits diagnostics in the reference case below, but the
/// new one does not.
constexpr const int &p2() {
int a = 12; // ref-note {{declared here}}
return a; // ref-warning {{reference to stack memory associated with local variable}} \
// expected-warning {{reference to stack memory associated with local variable}}
}

static_assert(p2() == 12, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{read of variable whose lifetime has ended}} \
// expected-error {{not an integral constant expression}}
}

0 comments on commit c725138

Please sign in to comment.