Firefox · Layout
CVE-2026-117941
Logic Error in Layout
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
add_tasklayout/style/test/test_inline_style_cc.html |
modified |
Files Changed
layout/style/nsDOMCSSAttrDeclaration.cpplayout/style/test/mochitest.tomllayout/style/test/test_inline_style_cc.html
Patch
diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp
index dd8b390e3f1..28aa1056bbe 100644
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -47,7 +47,8 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMCSSAttributeDeclaration)
return tmp->HasKnownLiveWrapper() ||
- (tmp->mElement && Element::CanSkipInCC(tmp->mElement));
+ (tmp->mElement && Element::CanSkipInCC(tmp->mElement) &&
+ tmp->HasNothingToTrace(tmp));
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMCSSAttributeDeclaration)
diff --git a/layout/style/test/mochitest.toml b/layout/style/test/mochitest.toml
index 458857fcf66..127d017770b 100644
--- a/layout/style/test/mochitest.toml
+++ b/layout/style/test/mochitest.toml
@@ -506,6 +506,8 @@ skip-if = [
["test_initial_storage.html"]
+["test_inline_style_cc.html"]
+
["test_invalidation_basic.html"]
["test_keyframes_rules.html"]
diff --git a/layout/style/test/test_inline_style_cc.html b/layout/style/test/test_inline_style_cc.html
new file mode 100644
index 00000000000..b48d1c3cc89
--- /dev/null
+++ b/layout/style/test/test_inline_style_cc.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline style declarations trace their gray wrappers</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+function makeAnchor() {
+ const doc = new DOMParser().parseFromString(
+ "<!doctype html><body>",
+ "text/html"
+ );
+ const element = doc.createElement("div");
+ element.appendChild(doc.createElement("span"));
+
+ const victim = doc.createRange();
+ victim.selectNodeContents(element);
+ // Preserve the victim's reflector so it is also a gray JS holder.
+ victim.expando = true;
+ element.style.victim = victim;
+
+ // Retain the carrier only through the native edges of a JS-rooted Range.
+ const anchor = doc.createRange();
+ anchor.selectNodeContents(element);
+ return anchor;
+}
+
+add_task(function() {
+ const anchor = makeAnchor();
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+
+ // Expose the element, but not its style. The first CC has already run the
+ // early forgetSkippable passes, so the style reflector is still gray.
+ const element = anchor.startContainer;
+ SpecialPowers.forceCC();
+
+ // A premature unlink of the still-reachable Range clears its boundaries.
+ is(element.style.victim.collapsed, false, "The style expando must stay alive");
+});
+</script>
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/layout/style/test/mochitest.toml b/layout/style/test/mochitest.toml
index 458857fcf66..127d017770b 100644
--- a/layout/style/test/mochitest.toml
+++ b/layout/style/test/mochitest.toml
@@ -506,6 +506,8 @@ skip-if = [
["test_initial_storage.html"]
+["test_inline_style_cc.html"]
+
["test_invalidation_basic.html"]
["test_keyframes_rules.html"]
diff --git a/layout/style/test/test_inline_style_cc.html b/layout/style/test/test_inline_style_cc.html
new file mode 100644
index 00000000000..b48d1c3cc89
--- /dev/null
+++ b/layout/style/test/test_inline_style_cc.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline style declarations trace their gray wrappers</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+function makeAnchor() {
+ const doc = new DOMParser().parseFromString(
+ "<!doctype html><body>",
+ "text/html"
+ );
+ const element = doc.createElement("div");
+ element.appendChild(doc.createElement("span"));
+
+ const victim = doc.createRange();
+ victim.selectNodeContents(element);
+ // Preserve the victim's reflector so it is also a gray JS holder.
+ victim.expando = true;
+ element.style.victim = victim;
+
+ // Retain the carrier only through the native edges of a JS-rooted Range.
+ const anchor = doc.createRange();
+ anchor.selectNodeContents(element);
+ return anchor;
+}
+
+add_task(function() {
+ const anchor = makeAnchor();
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+
+ // Expose the element, but not its style. The first CC has already run the
+ // early forgetSkippable passes, so the style reflector is still gray.
+ const element = anchor.startContainer;
+ SpecialPowers.forceCC();
+
+ // A premature unlink of the still-reachable Range clears its boundaries.
+ is(element.style.victim.collapsed, false, "The style expando must stay alive");
+});
+</script>
Loading diff…
References
On This Page