Closed Bug 1655658 Opened 4 years ago Closed 4 years ago

Single regex in userContent.css results in 30 seconds of 100% CPU core usage when loading pages

Categories

(Core :: JavaScript Engine, defect)

79 Branch
defect

Tracking

()

RESOLVED DUPLICATE of bug 1391654

People

(Reporter: zerfgog202, Unassigned)

Details

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0

Steps to reproduce:

Crash report (SIGABRT during webpage loading): https://crash-stats.mozilla.org/report/index/1fe44800-c656-4b01-819a-7b2b90200728

  1. Create a fresh Firefox profile.
  2. Place the following line of CSS in /path/to/profile/chrome/userContent.css
  3. In about:config, enable toolkit.legacyUserProfileCustomizations.stylesheets
  4. Relaunch Firefox
  5. Navigate to https://developer.mozilla.org/en-US/

Problematic CSS:

@-moz-document regexp("^https?:\/\/((?!area51)\\w+\.)*?stackexchange\.com.*") {}

Reproduced on:
FF: 79.0b7 (64-bit) Mozilla Firefox Developer Edition for Arch Linux
OS: Arch Linux x86_64, kernel 5.7.8-arch1-1
CPU: AMD Ryzen 7 1700

Also reproduced on:
FF: 79.0b9 (Firefox Developer Edition)
Hardware: MacBook Air 13" Early 2014
Software: macOS Mojave

I tried to follow the Profiling guide but in the profile where I'm reproducing this issue the "Symbolicating call stacks" page hung at 100% CPU usage for 10+ minutes before I gave up, presumably due to this same issue.

Actual results:

The page began to load but did not render fully. CPU usage spiked to 100% and remained there for about 30 seconds. Closing the Firefox window during this time results in a content process lingering at 100% CPU usage for that duration.

On the MacBook Air the CPU usage was at 100% for only around 5-10 seconds.

Expected results:

The page should have loaded normally.

The crash report in the original comment is from before I minimized the CSS that reproduces the issue.

Here's a new crash report using exactly the CSS in the above comment:
https://crash-stats.mozilla.org/report/index/6014c68c-4cf0-4e3a-8a4c-d23ef0200728

Hello,

I’ve attempted to reproduce the issue following the provided STR on the latest Nightly (81.0a1/20200730215452), Beta (80.0b2/20200730152159) and Release (79.0/20200720193547) under Windows 10 Pro 64-bit and Ubuntu 16.04 LTS, however without success.

Indeed, loading the page took longer than normal and not all elements fully rendered immediately, however they did eventually and the page fully loaded and rendered.
Also, CPU usage did spike to ~55% for a couple of seconds but then rapidly returned to normal values once the page loaded, on Windows. On Ubuntu, CPU usage was only at 12% during the page loading and as on Windows it eventually fully rendered.

The specs of my machine:

  • Processor: AMD FX(tm)-8320 Eight-Core Processor (8 CPUs), ~3.5GHz
  • Memory: 16384MB RAM
  • Video card: ATI Radeon 3000 Graphics

Are you using a distro build? Can you doublecheck with an official/mozilla.org-distributed build instead?

Flags: needinfo?(zerfgog202)

The original report was on a distro build (note that I was also able to reproduce this on macOS).
I am able to reproduce this on the following mozilla.org build:

Firefox 79.0 20200720193547
Mozilla/5.0 (X11; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0

Here is the SIGABRT crash dump from this mozilla.org build:
https://crash-stats.mozilla.org/report/index/d9bee2d6-42c4-4d6c-8c32-debbe0200808

Flags: needinfo?(zerfgog202)

Iain or Emilio, any idea why this is so slow? The abort points at regex code, but I'm not sure off-hand if this is because parsing/matching the regex is slow or because we invoke it too often or what.

Reporter: with the official mozilla.org build, can you retry getting a profile? It'll help answer the above question, and I would expect stack symbolicating to work better with the official build...

Component: General → JavaScript Engine
Flags: needinfo?(zerfgog202)
Flags: needinfo?(iireland)
Flags: needinfo?(emilio)
Product: Toolkit → Core

My regex-foo is not great, but it seems like the URL may be a massive data: URI from the crash report, and the regex engine is choking if the regex is too complex. If so:

  • Maybe we should not apply regex() (or @-moz-document really) to data-uri documents in the first place.
  • Probably the domain() function fulfills the purpose better than the more generic regex one?

Anyways we shouldn't be calling into this too often, but depending on what the page does it may end up being a couple dozen times or what not.

This is bug 1391654.

Standalone test case:

r = RegExp("^https?:\/\/((?!area51)\\w+\.)*?stackexchange\.com.*");
r.test("https://" + "a".repeat(100) + ".com");

@-moz-document regexp("^https?:\/\/((?!area51)\\w+\.)*?stackexchange\.com.*") {}

I think the \ need to be double-escaped here, so for example when the regular expression should match a single "." character, the regular expression must use \\. instead of \..

Yeah, what anba says. Without double-escaping the . in ((?!area51)\\w+\.)*?, we backtrack exponentially on long sequences of \w characters, because \w+. can match any length substring, and the outer *? will systematically try every possible partition of the input.

Upstream irregexp is starting to explore the possibility of adding a separate non-backtracking engine to avoid exponential blowup in cases where we don't need backreferences or assertions, but that wouldn't help here, because the regexp contains an assertion.

Double-escaping the . appears to fix the problem.

Flags: needinfo?(iireland)

Thanks anba! I think we should close this as a dupe.

Status: UNCONFIRMED → RESOLVED
Closed: 4 years ago
Flags: needinfo?(emilio)
Resolution: --- → DUPLICATE
Flags: needinfo?(zerfgog202)
You need to log in before you can comment on or make changes to this bug.