[clang] [clang] Fix a use-after-free in expression evaluation (PR #118480)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 22 10:12:32 PDT 2025


AaronBallman wrote:

> @kadircet let's team up tomorrow and poke at what's happening with the smaller reproducer to figure out if this is the right fix?
> 
> @AaronBallman I was initially concerned that it would be incorrect to consider the compound literal expression a full expression even if it fixes the crash. After re-reading the code now, I'm not sure how to properly test that as C++ does not have those (right?) and so I'd probably spend some time poking at GCC and Clang's codegen to see if they exhibit the signs of full expressions.
> 
> If you feel this fix is correct (or at least won't hurt too much), we can definitely land this ASAP. Help with reviewing this or steering it in the right direction is greatly appreciated.

In C:

> A full expression is an expression that is not part of another expression, nor part of a declarator
or abstract declarator. There is also an implicit full expression in which the non-constant size
expressions for a variably modified type are evaluated; within that full expression, the evaluation of
different size expressions are unsequenced with respect to one another. There is a sequence point
between the evaluation of a full expression and the evaluation of the next full expression to be
evaluated.

So a compound literal is definitely not a full expression in C. C++'s rules are similar: https://eel.is/c++draft/intro.execution#5

What's more, in C, it produces an lvalue whose lifetime is that of the block which contains it whereas in C++ it creates a prvalue... most of the time. There are a pile of FIXMEs around here:
```
  // In C, compound literals are l-values for some reason.
  // For GCC compatibility, in C++, file-scope array compound literals with
  // constant initializers are also l-values, and compound literals are
  // otherwise prvalues.
  //
  // (GCC also treats C++ list-initialized file-scope array prvalues with
  // constant initializers as l-values, but that's non-conforming, so we don't
  // follow it there.)
  //
  // FIXME: It would be better to handle the lvalue cases as materializing and
  // lifetime-extending a temporary object, but our materialized temporaries
  // representation only supports lifetime extension from a variable, not "out
  // of thin air".
  // FIXME: For C++, we might want to instead lifetime-extend only if a pointer
  // is bound to the result of applying array-to-pointer decay to the compound
  // literal.
  // FIXME: GCC supports compound literals of reference type, which should
  // obviously have a value kind derived from the kind of reference involved.
```
so the correct fix may very well be elsewhere.

https://github.com/llvm/llvm-project/pull/118480


More information about the cfe-commits mailing list