LibWeb/HTML: Avoid potential overflow of index for DOMStringList

The included WPT test passes through -1 which ends up modolo'ing
to u32 max at the IDL conversion layer, resulting in an unsigned
overflow when checking bounds.
This commit is contained in:
Shannon Booth 2025-07-05 22:11:47 +12:00 committed by Tim Ledbetter
commit 1b8a77f98c
Notes: github-actions[bot] 2025-07-05 11:29:35 +00:00
3 changed files with 72 additions and 2 deletions

View file

@ -43,7 +43,7 @@ Optional<String> DOMStringList::item(u32 index) const
{
// The item(index) method steps are to return the indexth item in this's associated list, or null if index plus one
// is greater than this's associated list's size.
if (index + 1 > m_list.size())
if (index >= m_list.size())
return {};
return m_list.at(index);
@ -58,7 +58,7 @@ bool DOMStringList::contains(StringView string)
Optional<JS::Value> DOMStringList::item_value(size_t index) const
{
if (index + 1 > m_list.size())
if (index >= m_list.size())
return {};
return JS::PrimitiveString::create(vm(), m_list.at(index));

View file

@ -0,0 +1,9 @@
Harness status: OK
Found 4 tests
4 Pass
Pass DOMStringList: length attribute
Pass DOMStringList: item() method
Pass DOMStringList: indexed getter
Pass DOMStringList: contains() method

View file

@ -0,0 +1,61 @@
<!doctype html>
<title>DOMStringList</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script>
// Returns a promise that resolves to a DOMStringList with
// the requested entries. Relies on Indexed DB.
function createDOMStringList(entries) {
return new Promise((resolve, reject) => {
const dbname = String(self.location + Math.random());
const request = indexedDB.open(dbname);
request.onerror = () => reject(request.error);
request.onupgradeneeded = () => {
const db = request.result;
entries.forEach(entry => db.createObjectStore(entry));
const dsl = db.objectStoreNames;
resolve(dsl);
request.transaction.abort();
}
});
}
function dsl_test(entries, func, description) {
promise_test(t => createDOMStringList(entries).then(dsl => func(t, dsl)),
description);
}
dsl_test(['a', 'b', 'c'], (t, dsl) => {
assert_equals(dsl.length, 3, 'length attribute');
}, 'DOMStringList: length attribute');
dsl_test(['a', 'b', 'c'], (t, dsl) => {
assert_equals(dsl.item(0), 'a', 'item method');
assert_equals(dsl.item(1), 'b', 'item method');
assert_equals(dsl.item(2), 'c', 'item method');
assert_equals(dsl.item(3), null, 'item method out of range');
assert_equals(dsl.item(-1), null, 'item method out of range');
assert_throws_js(TypeError, () => dsl.item(),
'item method should throw if called without enough args');
}, 'DOMStringList: item() method');
dsl_test(['a', 'b', 'c'], (t, dsl) => {
assert_equals(dsl[0], 'a', 'indexed getter');
assert_equals(dsl[1], 'b', 'indexed getter');
assert_equals(dsl[2], 'c', 'indexed getter');
assert_equals(dsl[3], undefined, 'indexed getter out of range');
assert_equals(dsl[-1], undefined, 'indexed getter out of range');
}, 'DOMStringList: indexed getter');
dsl_test(['a', 'b', 'c'], (t, dsl) => {
assert_true(dsl.contains('a'), 'contains method matched');
assert_true(dsl.contains('b'), 'contains method matched');
assert_true(dsl.contains('c'), 'contains method matched');
assert_false(dsl.contains(''), 'contains method unmatched');
assert_false(dsl.contains('d'), 'contains method unmatched');
assert_throws_js(TypeError, () => dsl.contains(),
'contains method should throw if called without enough args');
}, 'DOMStringList: contains() method');
</script>