Skip to content

Commit

Permalink
Fix MutationObserver infinite loop bugs (#3173)
Browse files Browse the repository at this point in the history
The code was misindented relative to the spec.

Fixes #3096. Fixes #3172.
  • Loading branch information
TimothyGu committed Apr 9, 2021
1 parent b232f2a commit 2f41466
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 14 deletions.
28 changes: 14 additions & 14 deletions lib/jsdom/living/helpers/mutation-observers.js
Expand Up @@ -152,21 +152,21 @@ function notifyMutationObservers() {
node._registeredObserverList = node._registeredObserverList.filter(registeredObserver => {
return registeredObserver.source !== mo;
});
}

if (records.length) {
try {
const moWrapper = idlUtils.wrapperForImpl(mo);
mo._callback.call(
moWrapper,
records.map(idlUtils.wrapperForImpl),
moWrapper
);
} catch (e) {
const { target } = records[0];
const window = target._ownerDocument._defaultView;

reportException(window, e);
}
if (records.length > 0) {
try {
const moWrapper = idlUtils.wrapperForImpl(mo);
mo._callback.call(
moWrapper,
records.map(idlUtils.wrapperForImpl),
moWrapper
);
} catch (e) {
const { target } = records[0];
const window = target._ownerDocument._defaultView;

reportException(window, e);
}
}
}
Expand Down
@@ -0,0 +1,43 @@
<!doctype html>
<meta charset=utf-8>
<title>Certain actions within the callback does not lead to infinite loop</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body>
<script>
"use strict";

promise_test(() => {
let called = 0;
const div1 = document.createElement("div");
document.body.appendChild(div1);
const m = new MutationObserver(() => {
called++;
const div2 = document.createElement("div");
document.body.appendChild(div2);
m.observe(div2, { attributes: true });
});
m.observe(div1, { attributes: true });
div1.setAttribute("data-test", "test");
return Promise.resolve().then(() => {
assert_equals(called, 1, "times callback called");
});
}, "Calling observe in callback should not lead to more calls");

promise_test(() => {
let called = 0;
const div1 = document.createElement("div");
document.body.appendChild(div1);
const m = new MutationObserver(() => {
called++;
m.disconnect();
m.observe(div1, { attributes: true });
});
m.observe(div1, { attributes: true });
div1.setAttribute("data-test", "test");
return Promise.resolve().then(() => {
assert_equals(called, 1, "times callback called");
});
}, "Disconnect and re-observe in callback should not lead to more calls");
</script>

0 comments on commit 2f41466

Please sign in to comment.