Merge bitcoin/bitcoin#36164: util: diagnose dangling views of temporary strings

b57b0dbebd util: annotate `Split` input lifetime (Lőrinc)
34c5dc0583 util: annotate string view input lifetimes (Lőrinc)

Pull request description:

  **Problem:** Several string utilities return or store views into their input.
  A temporary `std::string` can leave these views dangling, although no current caller does this.

  **Fix:** Add `LIFETIMEBOUND` so Clang diagnoses the misuse while preserving immediate use.
  Pass the `Split` span by value so lvalue strings do not trigger false warnings.

ACKs for top commit:
  kevkevinpal:
    crACK b57b0db
  stickies-v:
    ACK b57b0dbebd
  hodlinator:
    ACK b57b0dbebd
  sedited:
    ACK b57b0dbebd

Tree-SHA512: 892b4c386d19dd9d46b36223084751d4be370bc985ad83283f3a2bffdd3a19f95ad107f1bf7ee4a85f90129b29553175b4713eb1308ee5176dbfa64ecff7e435
This commit is contained in:
merge-script
2026-09-06 12:10:04 +02:00

View File

@@ -117,7 +117,7 @@ void ReplaceAll(std::string& in_out, std::string_view search, std::string_view s
* - 3)
*/
template <typename T = std::span<const char>>
std::vector<T> Split(const std::span<const char>& sp, std::string_view separators, bool include_sep = false)
std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, std::string_view separators, bool include_sep = false)
{
std::vector<T> ret;
auto it = sp.begin();
@@ -145,7 +145,7 @@ std::vector<T> Split(const std::span<const char>& sp, std::string_view separator
* "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
*/
template <typename T = std::span<const char>>
std::vector<T> Split(const std::span<const char>& sp, char sep, bool include_sep = false)
std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, char sep, bool include_sep = false)
{
return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
}
@@ -160,7 +160,7 @@ std::vector<T> Split(const std::span<const char>& sp, char sep, bool include_sep
return Split<std::string>(str, separators);
}
[[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
[[nodiscard]] inline std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern = " \f\n\r\t\v")
{
std::string::size_type front = str.find_first_not_of(pattern);
if (front == std::string::npos) {
@@ -175,7 +175,7 @@ std::vector<T> Split(const std::span<const char>& sp, char sep, bool include_sep
return std::string(TrimStringView(str, pattern));
}
[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix)
{
if (str.ends_with(suffix)) {
return str.substr(0, str.size() - suffix.size());
@@ -183,7 +183,7 @@ std::vector<T> Split(const std::span<const char>& sp, char sep, bool include_sep
return str;
}
[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str LIFETIMEBOUND, std::string_view prefix)
{
if (str.starts_with(prefix)) {
return str.substr(prefix.size());
@@ -273,7 +273,7 @@ class LineReader
std::string_view::iterator m_it;
public:
explicit LineReader(std::string_view str, size_t max_line_length);
explicit LineReader(std::string_view str LIFETIMEBOUND, size_t max_line_length);
/**
* Returns a string from current iterator position up to (but not including) next \n