jaraco / jaraco/cssutils

CSS file of 320 bytes takes 10+ seconds to parse

Offen
#18 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
help wanted
Vorherrschende Sprache
Python
Sterne
92
Forks
30
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

I've encountered CSS file which `cssutils` library takes lots of seconds to parse (in fact, almost infinite).
After some investigation I've minified problematic sample (as possible) and prepared reproducible code example.
On my laptop (core i7-8550U) it takes **14 seconds** to parse file with just one line and 320 bytes of text.

Original file has 20kBytes of text and parser does not finish it in several hours.

Code:
https://gist.github.com/vdmit/ef9007170fa1c616cf5aba1fcebfce87
I'm using:
- latest stable `cssutils` release 2.3.0 from pypi repo
- python 3.8.10
- Ubuntu 20.04 linux distribution.

Notes:
- original CSS file was malformed and even contained non-printable characters. My minified example is still not valid CSS file, but it is a plain ANSI file.
- Adding line break in any place fixes problem;
- Removing of last style expression (`.s11...` reduces execution time from 14 seconds to 3 seconds).
- Adding of one more style expression increases execution time from 14 seconds to 50, 2 more styles yields ~260 seconds.

So, there is a **exponential** complexity somewhere, which is strange.

Traceback of interrupted script is following:

```python3 cssutils_infinite_loop_bug_example.py
Traceback (most recent call last):
File "cssutils_infinite_loop_bug_example.py", line 10, in
sheet = css_parser.parseString(cssText=css_text)
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/parse.py", line 147, in parseString
sheet._setCssTextWithEncodingOverride(
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/css/cssstylesheet.py", line 408, in _setCssTextWithEncodingOverride
self.cssText = cssText
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/css/cssstylesheet.py", line 331, in _setCssText
wellformed, expected = self._parse(
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/util.py", line 484, in _parse
expected = p(expected, seq, token, tokenizer)
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/css/cssstylesheet.py", line 313, in ruleset
rule.cssText = self._tokensupto2(tokenizer, token)
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/util.py", line 343, in _tokensupto2
for token in tokenizer:
File "/home/vdmit/.local/lib/python3.8/site-packages/cssutils/tokenize2.py", line 172, in tokenize
match = matcher(text, pos) # if no match try next production
KeyboardInterrupt
```

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Beginne mit dem verknüpften reproduzierbaren Beispiel und verfolge den gemeldeten Pfad durch cssutils/parse.py, cssutils/css/cssstylesheet.py, util.py und tokenize2.py. Führe Benchmarks für das Beispiel durch, während du Zeilenumbrüche und Stilausdrücke variierst, und füge einen Regressionstest hinzu, der zeigt, dass die Eingabe keine exponentielle Parsing-Zeit mehr hat.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
performance
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
42/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.