diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index fe3398417b2c..39e8bfa275d4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7408,7 +7408,16 @@ def __init__(self, descriptor, iterable, methodName): rooted!(in(*cx) let mut call_arg2 = UndefinedValue()); let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)]; rooted!(in(*cx) let mut ignoredReturnVal = UndefinedValue()); - for i in 0..(*this).get_iterable_length() { + + // This has to be a while loop since get_iterable_length() may change during + // the callback, and we need to avoid iterator invalidation. + // + // It is possible for this to loop infinitely, but that matches the spec + // and other browsers. + // + // https://heycam.github.io/webidl/#es-forEach + let mut i = 0; + while i < (*this).get_iterable_length() { (*this).get_value_at_index(i).to_jsval(*cx, call_arg1.handle_mut()); (*this).get_key_at_index(i).to_jsval(*cx, call_arg2.handle_mut()); call_args[0] = call_arg1.handle().get(); @@ -7418,6 +7427,8 @@ def __init__(self, descriptor, iterable, methodName): ignoredReturnVal.handle_mut()) { return false; } + + i += 1; } let result = (); diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 4fdf726fd049..5ee2889461a2 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -308306,6 +308306,12 @@ {} ] ], + "WebIDL/ecmascript-binding/iterator-invalidation-foreach.html": [ + [ + "WebIDL/ecmascript-binding/iterator-invalidation-foreach.html", + {} + ] + ], "WebIDL/ecmascript-binding/iterator-prototype-object.html": [ [ "WebIDL/ecmascript-binding/iterator-prototype-object.html", @@ -466654,6 +466660,10 @@ "03ada7aa0d4d43811652fc679a00a41b9653013d", "testharness" ], + "WebIDL/ecmascript-binding/iterator-invalidation-foreach.html": [ + "d6498c3e388e0c637830fa080cca78b0ab0e5305", + "testharness" + ], "WebIDL/ecmascript-binding/iterator-prototype-object.html": [ "5a935fa20135d88a7268b872b68ab7fe548ab5c7", "testharness" diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/iterator-invalidation-foreach.html b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/iterator-invalidation-foreach.html new file mode 100644 index 000000000000..d6498c3e388e --- /dev/null +++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/iterator-invalidation-foreach.html @@ -0,0 +1,40 @@ + + +Behavior of iterators when modified within foreach + + + + +