[libcxx-commits] [libcxx] [libc++] Fix complexity guarantee in std::clamp (PR #68413)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Oct 26 07:51:46 PDT 2023


================
@@ -37,9 +37,10 @@ struct __fn {
     _LIBCPP_ASSERT_UNCATEGORIZED(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))),
                                  "Bad bounds passed to std::ranges::clamp");
 
-    if (std::invoke(__comp, std::invoke(__proj, __value), std::invoke(__proj, __low)))
+    auto&& __projected = std::invoke(__proj, __value);
----------------
ldionne wrote:

Ok, so you are thinking about the following case?

```
char const* low = "1";
char const* high = "3";
char const* val = "2";
auto projection = [](std::string const& s) -> std::string const& { return s; };
std::ranges::clamp(val, low, high, std::less{}, projection);
```

Here what you're saying is that the `s` argument of the projection is created implicitly when we call `std::invoke(__proj, __something)`, and if we end the full-expression before we are done using that result, we'll be using a dangling ref.

That seems to be correct according to [the lifetime extension docs on cppreference](https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary):

> There are following exceptions to this lifetime rule:
>
> - a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.

I think the "problem" I have with that is that it means we could technically never call any user-provided function (projection or else) and hold on to the result of that, since this case could happen anywhere. Every time we call a user-provided function with some arguments, there could be some implicit conversion happening and then we are vulnerable to this dangling reference issue. Am I right? If so, and if we want to guard against this, then we would in theory write all of our code which is potentially vulnerable to this issue in a single full expression. I'm not sure this is either reasonable or expected. WDYT?

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


More information about the libcxx-commits mailing list