fix: potential UAF when option's value is programmatically set

This commit is contained in:
Karl Seguin
2026-07-30 13:53:08 +08:00
parent 5aa1f0619c
commit 5ce274cec4
2 changed files with 21 additions and 2 deletions

View File

@@ -23,6 +23,23 @@
testing.expectEqual('changed', $('#opt1').value)
</script>
<script id="value_set_attribute">
{
const option = document.createElement('option')
// short values are stored inline in the String passed to our
// attributeChange hook, long ones are heap-backed
option.setAttribute('value', 'ab')
testing.expectEqual('ab', option.value)
option.setAttribute('value', 'a-long-attribute-value')
testing.expectEqual('a-long-attribute-value', option.value)
option.removeAttribute('value')
testing.expectEqual('', option.value)
}
</script>
<script id="text">
testing.expectEqual('Text 1', $('#opt1').text)
testing.expectEqual('Text 2', $('#opt2').text)

View File

@@ -159,11 +159,13 @@ pub const Build = struct {
self._disabled = element.getAttributeSafe(comptime .wrap("disabled")) != null;
}
pub fn attributeChange(element: *Element, name: String, value: String, _: *Frame) !void {
pub fn attributeChange(element: *Element, name: String, _: String, _: *Frame) !void {
const attribute = std.meta.stringToEnum(enum { value, selected }, name.str()) orelse return;
const self = element.as(Option);
switch (attribute) {
.value => self._value = value.str(),
// `value` is passed by value; for <= 12 bytes, str() points into our
// own parameter copy, so we have to re-read the owned bytes.
.value => self._value = element.getAttributeSafe(comptime .wrap("value")),
.selected => {
self._default_selected = true;
self._selected = true;