tbranyen/diffhtml

`innerHTML` → Maximum call stack size exceeded

CetinSert opened this issue · 1 comments

Large HTML attributes cause excessive backtracking in attribute.exec, and fail due to call stack size exhaustion!

} = attribute.exec(html) || EMPTY.OBJ;

Browsers behave as follows for the reproduction case given below:

Browser Succeeds at Fails at
Chrome 3_355_404 3_355_405
Firefox 1_677_689 1_677_690
Safari 999_972 999_973

Below is a self-contained reproduction.

<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1">
<script type=module>
  import { innerHTML } from '//diffhtml.org/es';
  const getRandomBase64 = (N) => {
    const chunk = (n) => crypto.getRandomValues(new Uint8Array(n));
    const bytes = [].concat(...Array(Math.ceil(N * 0.75 / 65536))
      .fill().map(() => [...chunk(Math.min(65536, N * 0.75))]));
    return btoa(bytes.reduce((s, b) => s + String.fromCharCode(b), '')).slice(0, N);
  };

//                                                                                     4 works ✔️
//                                                                                     ↑
  innerHTML(document.body, `a<img src="data:image/png;base64,${getRandomBase64(3_355_405)}">z`); // ❌ Maximum call stack size exceeded
  console.warn(document.body.innerHTML.length);
</script>

which results in

} = attribute.exec(html) || EMPTY.OBJ;

RangeError: Maximum call stack size exceeded
    at RegExp.exec <anonymous>
    at Object.parse https://diffhtml.org/es/util/parse:303:19
    at Array.parseNewTree https://diffhtml.org/es/tasks/parse-new-tree:17:38
    at Transaction.flow https://diffhtml.org/es/transaction:63:24
    at Transaction.start https://diffhtml.org/es/transaction:176:24
    at innerHTML https://diffhtml.org/es/inner-html:22:51
    at :13:3