LibWeb/CSS: Prevent infinite recursion in CSSUnparsedValue::to_string()

As noted in the linked spec issue, it's possible for an author to
construct a CSSUnparsedValue that contains itself, meaning
serialization would be infinitely recursive. So instead, detect that
and then return an empty string, which copies Blink's solution to this
issue.

Stops `css/css-typed-om/cycle-in-unparsed-value-crash.html` from
crashing after we implement converting a CSSUnparsedValue to an
UnresolvedStyleValue, as that relies on serialization.
This commit is contained in:
Sam Atkins 2025-10-03 13:46:29 +01:00 committed by Andreas Kling
commit 9ef523ebb2
Notes: github-actions[bot] 2025-10-09 14:16:59 +00:00
2 changed files with 24 additions and 0 deletions

View file

@ -115,9 +115,31 @@ WebIDL::ExceptionOr<void> CSSUnparsedValue::set_value_of_new_indexed_property(u3
return {};
}
bool CSSUnparsedValue::contains_unparsed_value(CSSUnparsedValue const& needle) const
{
for (auto const& unparsed_segment : m_tokens) {
if (auto const* variable_reference = unparsed_segment.get_pointer<GC::Ref<CSSVariableReferenceValue>>()) {
auto fallback = (*variable_reference)->fallback();
if (!fallback)
continue;
if (fallback.ptr() == &needle)
return true;
if (fallback->contains_unparsed_value(needle))
return true;
}
}
return false;
}
// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssunparsedvalue
WebIDL::ExceptionOr<String> CSSUnparsedValue::to_string() const
{
// AD-HOC: It's possible for one of the m_tokens to contain this in its fallback slot, or a similar situation with
// more levels of nesting. To avoid crashing, do a scan for that first and return the empty string.
// Spec issue: https://github.com/w3c/css-houdini-drafts/issues/1158
if (contains_unparsed_value(*this))
return ""_string;
// To serialize a CSSUnparsedValue this:
// 1. Let s initially be the empty string.
StringBuilder s;