[PATCH] D74094: Reapply: [IRGen] Emit lifetime intrinsics around temporary aggregate argument allocas

John McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 11 10:54:33 PDT 2023


rjmccall added a comment.

Under [expr.call]p6 (https://eel.is/c++draft/expr.call#6), it is implementation-defined whether the lifetime of a parameter ends at the end of the containing full expression or at the end of the function.  If the implementation chooses the latter, a reference to the parameter will dangle after the return.  In your example, on your chosen target (probably x64-64?), we are actually forced by the psABI to end those lifetimes at the end of the function, because the contents of the parameters are passed in registers (rather than by implicit reference) and reconstituted in the stack frame of the callee.  Therefore your `min` function has undefined behavior, and not just in a formal sense but actually in a very directly dangerous sense.  That should not be surprising; intuitively, you should think of this as returning a reference to a local variable, which is highly suspect even if it is sometimes — only on certain targets and for certain types — formally allowed.

> That makes me think we should probably do this lifetime annotation in the caller of CodeGenFunction::EmitCallArg since it will have information about the return type of the caller. If a function returns a reference to a type, we probably don't want to emit the lifetime markers for any parameter of that type. I wonder if strict aliasing needs to be considered, too?

This is definitely barking up the wrong tree.  The language specifies the lifetime of an object, and any access to the object during its lifetime is valid.  If the parameter's lifetime *was* guaranteed to be the full expression here, we would be obliged to keep it alive for that full duration.

In particular, we cannot do anything with reasoning like "the return value cannot be a reference to the parameter". The right way to understand that is as an effort to invoke the as-if rule, arguing that it is impossible to reference the parameter after the call if it is not part of the return value, and therefore we can be more aggressive than the language would formally allow. But it is not true that the only way to reference a parameter after a call is if it is part of the return value.  For example, the function could store a pointer to the parameter into a global variable, and as long as all accesses through that global happen before the parameter's lifetime ends, that's totally fine — it's obviously a very confusing and error-prone way to write code, but it's legal.  (Also, even if the address of the parameter *could* only escape into the return value, the type analysis would have to be much more complicated than just whether it's a reference to the type of a parameter.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74094/new/

https://reviews.llvm.org/D74094



More information about the cfe-commits mailing list