AK: Disallow calling ByteString methods that return a view on rvalues

This prevents, for example:

    StringView view = ByteString { "foo" }.view();

This prevents a class of potential UAF.
This commit is contained in:
Timothy Flynn 2024-04-03 22:01:43 -04:00 committed by Andreas Kling
parent de80f544d8
commit c5c5e52c24
Notes: sideshowbarker 2024-07-17 02:35:27 +09:00
2 changed files with 22 additions and 17 deletions

View file

@ -81,14 +81,14 @@ ByteString ByteString::substring(size_t start) const
return { characters() + start, length() - start }; return { characters() + start, length() - start };
} }
StringView ByteString::substring_view(size_t start, size_t length) const StringView ByteString::substring_view(size_t start, size_t length) const&
{ {
VERIFY(!Checked<size_t>::addition_would_overflow(start, length)); VERIFY(!Checked<size_t>::addition_would_overflow(start, length));
VERIFY(start + length <= m_impl->length()); VERIFY(start + length <= m_impl->length());
return { characters() + start, length }; return { characters() + start, length };
} }
StringView ByteString::substring_view(size_t start) const StringView ByteString::substring_view(size_t start) const&
{ {
VERIFY(start <= length()); VERIFY(start <= length());
return { characters() + start, length() - start }; return { characters() + start, length() - start };
@ -123,7 +123,7 @@ Vector<ByteString> ByteString::split_limit(char separator, size_t limit, SplitBe
return v; return v;
} }
Vector<StringView> ByteString::split_view(Function<bool(char)> separator, SplitBehavior split_behavior) const Vector<StringView> ByteString::split_view(Function<bool(char)> separator, SplitBehavior split_behavior) const&
{ {
if (is_empty()) if (is_empty())
return {}; return {};
@ -147,7 +147,7 @@ Vector<StringView> ByteString::split_view(Function<bool(char)> separator, SplitB
return v; return v;
} }
Vector<StringView> ByteString::split_view(char const separator, SplitBehavior split_behavior) const Vector<StringView> ByteString::split_view(char const separator, SplitBehavior split_behavior) const&
{ {
return split_view([separator](char ch) { return ch == separator; }, split_behavior); return split_view([separator](char ch) { return ch == separator; }, split_behavior);
} }

View file

@ -166,8 +166,12 @@ public:
[[nodiscard]] Vector<ByteString> split_limit(char separator, size_t limit, SplitBehavior = SplitBehavior::Nothing) const; [[nodiscard]] Vector<ByteString> split_limit(char separator, size_t limit, SplitBehavior = SplitBehavior::Nothing) const;
[[nodiscard]] Vector<ByteString> split(char separator, SplitBehavior = SplitBehavior::Nothing) const; [[nodiscard]] Vector<ByteString> split(char separator, SplitBehavior = SplitBehavior::Nothing) const;
[[nodiscard]] Vector<StringView> split_view(char separator, SplitBehavior = SplitBehavior::Nothing) const;
[[nodiscard]] Vector<StringView> split_view(Function<bool(char)> separator, SplitBehavior = SplitBehavior::Nothing) const; [[nodiscard]] Vector<StringView> split_view(char separator, SplitBehavior = SplitBehavior::Nothing) const&;
[[nodiscard]] Vector<StringView> split_view(char separator, SplitBehavior = SplitBehavior::Nothing) const&& = delete;
[[nodiscard]] Vector<StringView> split_view(Function<bool(char)> separator, SplitBehavior = SplitBehavior::Nothing) const&;
[[nodiscard]] Vector<StringView> split_view(Function<bool(char)> separator, SplitBehavior = SplitBehavior::Nothing) const&& = delete;
[[nodiscard]] Optional<size_t> find(char needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } [[nodiscard]] Optional<size_t> find(char needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); }
[[nodiscard]] Optional<size_t> find(StringView needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } [[nodiscard]] Optional<size_t> find(StringView needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); }
@ -177,12 +181,17 @@ public:
using SearchDirection = StringUtils::SearchDirection; using SearchDirection = StringUtils::SearchDirection;
[[nodiscard]] Optional<size_t> find_any_of(StringView needles, SearchDirection direction) const { return StringUtils::find_any_of(*this, needles, direction); } [[nodiscard]] Optional<size_t> find_any_of(StringView needles, SearchDirection direction) const { return StringUtils::find_any_of(*this, needles, direction); }
[[nodiscard]] StringView find_last_split_view(char separator) const { return view().find_last_split_view(separator); } [[nodiscard]] StringView find_last_split_view(char separator) const& { return view().find_last_split_view(separator); }
[[nodiscard]] StringView find_last_split_view(char separator) const&& = delete;
[[nodiscard]] ByteString substring(size_t start, size_t length) const; [[nodiscard]] ByteString substring(size_t start, size_t length) const;
[[nodiscard]] ByteString substring(size_t start) const; [[nodiscard]] ByteString substring(size_t start) const;
[[nodiscard]] StringView substring_view(size_t start, size_t length) const;
[[nodiscard]] StringView substring_view(size_t start) const; [[nodiscard]] StringView substring_view(size_t start, size_t length) const&;
[[nodiscard]] StringView substring_view(size_t start, size_t length) const&& = delete;
[[nodiscard]] StringView substring_view(size_t start) const&;
[[nodiscard]] StringView substring_view(size_t start) const&& = delete;
[[nodiscard]] ALWAYS_INLINE bool is_empty() const { return length() == 0; } [[nodiscard]] ALWAYS_INLINE bool is_empty() const { return length() == 0; }
[[nodiscard]] ALWAYS_INLINE size_t length() const { return m_impl->length(); } [[nodiscard]] ALWAYS_INLINE size_t length() const { return m_impl->length(); }
@ -191,10 +200,8 @@ public:
[[nodiscard]] bool copy_characters_to_buffer(char* buffer, size_t buffer_size) const; [[nodiscard]] bool copy_characters_to_buffer(char* buffer, size_t buffer_size) const;
[[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const [[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const& { return m_impl->bytes(); }
{ [[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const&& = delete;
return m_impl->bytes();
}
[[nodiscard]] ALWAYS_INLINE char const& operator[](size_t i) const [[nodiscard]] ALWAYS_INLINE char const& operator[](size_t i) const
{ {
@ -292,10 +299,8 @@ public:
return formatted("{}", value); return formatted("{}", value);
} }
[[nodiscard]] StringView view() const [[nodiscard]] StringView view() const& { return { characters(), length() }; }
{ [[nodiscard]] StringView view() const&& = delete;
return { characters(), length() };
}
[[nodiscard]] ByteString replace(StringView needle, StringView replacement, ReplaceMode replace_mode = ReplaceMode::All) const { return StringUtils::replace(*this, needle, replacement, replace_mode); } [[nodiscard]] ByteString replace(StringView needle, StringView replacement, ReplaceMode replace_mode = ReplaceMode::All) const { return StringUtils::replace(*this, needle, replacement, replace_mode); }
[[nodiscard]] size_t count(StringView needle) const { return StringUtils::count(*this, needle); } [[nodiscard]] size_t count(StringView needle) const { return StringUtils::count(*this, needle); }