commit 9a5b8ffe1c099fe3f11c950ae470bfc6aa26b794
parent d8541bfd5737659a445ea490de305ddb93f834d3
Author: Peter Van der Beken <peterv@propagandism.org>
Date: Thu, 16 Oct 2025 20:01:35 +0000
Bug 1941002 - Testcase. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D235873
Diffstat:
5 files changed, 186 insertions(+), 0 deletions(-)
diff --git a/dom/xslt/crashtests/1941002-1.html b/dom/xslt/crashtests/1941002-1.html
@@ -0,0 +1,49 @@
+<html class="reftest-wait">
+<body>
+<script>
+ function checkEvents(test, callback) {
+ const detailsElement = document.getElementById("detailsElement");
+ detailsElement.addEventListener("toggle", callback, { once: true });
+ detailsElement.setAttribute("open", "");
+
+ test();
+
+ detailsElement.removeAttribute("open");
+ }
+
+ function destroyElement(doc) {
+ doc.removeChild(doc.documentElement);
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+ }
+
+ const xmlString = `<foo><bar/></foo>`;
+ const xsltString = `
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:include href="1941002.sjs"/>
+ <xsl:template match="/">
+ <xsl:copy-of select="foo|(document('1941002.sjs')/xsl:stylesheet)"/>
+ </xsl:template>
+ </xsl:stylesheet>
+ `;
+
+ const parser = new DOMParser();
+ const xmlDoc = parser.parseFromString(xmlString, "application/xml");
+ const xsltDoc = parser.parseFromString(xsltString, "application/xml");
+ const xsltProcessor = new XSLTProcessor();
+
+ addEventListener("load", () => {
+ checkEvents(() => {
+ xsltProcessor.importStylesheet(xsltDoc);
+ }, () => { destroyElement(xsltDoc); });
+
+ checkEvents(() => {
+ xsltProcessor.transformToFragment(xmlDoc, document);
+ }, () => { destroyElement(xmlDoc); });
+
+ document.documentElement.classList.remove("reftest-wait");
+ });
+</script>
+<details id="detailsElement"></details>
+</body>
+</html>
diff --git a/dom/xslt/crashtests/1941002-2.html b/dom/xslt/crashtests/1941002-2.html
@@ -0,0 +1,58 @@
+<html class="reftest-wait">
+<body>
+<script>
+ function checkEvents(test, callback) {
+ const detailsElement = document.getElementById("detailsElement");
+ detailsElement.addEventListener("toggle", callback, { once: true });
+ detailsElement.setAttribute("open", "");
+
+ test();
+
+ detailsElement.removeAttribute("open");
+ }
+
+ const xmlString = `<foo><bar/></foo>`;
+ const xsltString = `
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:param name="p" />
+ <xsl:template match="/">
+ <xsl:for-each select="$p/bar">
+ <xsl:copy-of select="." />
+ <xsl:copy-of select="document('1941002.sjs')/xsl:stylesheet"/>
+ </xsl:for-each>
+ </xsl:template>
+ </xsl:stylesheet>
+ `;
+ const paramString = `
+ <foo>
+ <bar>p1</bar>
+ <bar>p2</bar>
+ <bar>p3</bar>
+ <bar>p4</bar>
+ </foo>
+ `;
+
+ const parser = new DOMParser();
+ const xmlDoc = parser.parseFromString(xmlString, "application/xml");
+ const xsltDoc = parser.parseFromString(xsltString, "application/xml");
+ const xsltProcessor = new XSLTProcessor();
+
+ xsltProcessor.setParameter(null, "p", parser.parseFromString(paramString, "application/xml").documentElement);
+
+ addEventListener("load", () => {
+ xsltProcessor.importStylesheet(xsltDoc);
+
+ checkEvents(() => {
+ xsltProcessor.transformToFragment(xmlDoc, document);
+ }, () => {
+ xsltProcessor.clearParameters();
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+ });
+
+ document.documentElement.classList.remove("reftest-wait");
+ });
+</script>
+<details id="detailsElement"></details>
+</body>
+</html>
diff --git a/dom/xslt/crashtests/1941002-3.html b/dom/xslt/crashtests/1941002-3.html
@@ -0,0 +1,56 @@
+<html class="reftest-wait">
+<body>
+<script>
+ function checkEvents(test, callback) {
+ const detailsElement = document.getElementById("detailsElement");
+ detailsElement.addEventListener("toggle", callback, { once: true });
+ detailsElement.setAttribute("open", "");
+
+ test();
+
+ detailsElement.removeAttribute("open");
+ }
+
+const xsltString1 = `
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:include href="1941002.sjs"/>
+ <xsl:template match="/">
+ </xsl:template>
+ </xsl:stylesheet>
+ `;
+ const xsltString2 = `
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:template match="/">
+ </xsl:template>
+ </xsl:stylesheet>
+ `;
+
+ const parser = new DOMParser();
+ let xsltDoc1 = parser.parseFromString(xsltString1, "application/xml");
+ let xsltDoc2 = parser.parseFromString(xsltString2, "application/xml");
+
+ addEventListener("load", () => {
+ let xsltProcessor = new XSLTProcessor();
+ checkEvents(() => {
+ xsltProcessor.importStylesheet(xsltDoc1);
+ }, () => {
+ xsltProcessor.importStylesheet(xsltDoc2);
+ });
+
+ delete xsltProcessor;
+
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+
+ delete xsltDoc1;
+ delete xsltDoc2;
+
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+
+ document.documentElement.classList.remove("reftest-wait");
+ });
+</script>
+<details id="detailsElement"></details>
+</body>
+</html>
diff --git a/dom/xslt/crashtests/1941002.sjs b/dom/xslt/crashtests/1941002.sjs
@@ -0,0 +1,20 @@
+let { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+function handleRequest(request, response) {
+ response.processAsync();
+
+ response.setHeader(
+ "Cache-Control",
+ "no-cache, no-store, must-revalidate",
+ false
+ );
+ response.setHeader("Pragma", "no-cache", false);
+ response.setHeader("Expires", "0", false);
+ setTimeout(() => {
+ response.write(`<?xml version="1.0" encoding="UTF-8"?>
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />`);
+ response.finish();
+ }, 1000);
+}
diff --git a/dom/xslt/crashtests/crashtests.list b/dom/xslt/crashtests/crashtests.list
@@ -29,3 +29,6 @@ load 1527277.html
load 1589930.xml
load 1936613.html
HTTP load 1430818.sjs
+HTTP load 1941002-1.html
+HTTP load 1941002-2.html
+HTTP load 1941002-3.html