Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oss-fuzz 69058: TokenError #1787

Closed
nedbat opened this issue May 18, 2024 · 4 comments · Fixed by #1788
Closed

oss-fuzz 69058: TokenError #1787

nedbat opened this issue May 18, 2024 · 4 comments · Fixed by #1788
Labels
bug Something isn't working

Comments

@nedbat
Copy link
Owner

nedbat commented May 18, 2024

This link seems to be private, so copying details here... https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=69058

Project: coveragepy
Fuzzing Engine: libFuzzer
Fuzz Target: fuzz_parse
Job Type: libfuzzer_asan_coveragepy
Platform Id: linux

Crash Type: Uncaught exception
Crash Address: 
Crash State:
  _removeHandlerRef
  _tokenize
  generate_tokens

This is the claimed stack trace:

 	 === Uncaught Python exception: ===
	TokenError: ('EOF in multi-line string', (2, 0))
	Traceback (most recent call last):
	  File "fuzz_parse.py", line 33, in TestOneInput
	  File "coverage/parser.py", line 265, in parse_source
	  File "coverage/parser.py", line 143, in _raw_parse
	  File "coverage/phystokens.py", line 179, in generate_tokens
	  File "tokenize.py", line 461, in _tokenize
	TokenError: ('EOF in multi-line string', (2, 0))

The provided test case is an 8-byte file:

% hexdump -C /dwn/clusterfuzz-testcase-minimized-fuzz_parse-5820066691088384
00000000  ff 8d a7 dc 0a 27 27 a7                           |.....''.|
00000008

I've tried to reproduce this problem, and cannot:

from coverage.parser import PythonParser
parser = PythonParser(text="\xFF\x8D\xA7\xDC\n''\xA7")
parser.parse_source()

produces:

Traceback (most recent call last):
  File "/Users/ned/coverage/trunk/coverage/parser.py", line 265, in parse_source
    self._ast_root = ast_parse(self.text)
                     ^^^^^^^^^^^^^^^^^^^^
  File "/Users/ned/coverage/trunk/coverage/misc.py", line 381, in ast_parse
    return ast.parse(text)
           ^^^^^^^^^^^^^^^
  File "/usr/local/pyenv/pyenv/versions/3.11.9/lib/python3.11/ast.py", line 50, in parse
    return compile(source, filename, mode, flags,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<unknown>", line 1
    ÿ�§Ü
     ^
SyntaxError: invalid non-printable character U+008D

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/ned/coverage/trunk/fuzz.py", line 3, in <module>
    parser.parse_source()
  File "/Users/ned/coverage/trunk/coverage/parser.py", line 268, in parse_source
    raise NotPython(
coverage.exceptions.NotPython: Couldn't parse '<code>' as Python source: 'invalid non-printable character U+008D' at line 1

Somehow they have a TokenError, but coverage.py does not. I don't understand how they are getting their error.

@nedbat nedbat added bug Something isn't working needs triage labels May 18, 2024
@devdanzin
Copy link
Contributor

It's possible to raise an EOF TokenError by decoding the bytes to cp273, but it is caught and results in a NotPython exception. Also, it's about a multi-line statement, while the original error is about a multi-line string. It only works with Python 3.11 or below, 3.12 won't raise a TokenError. Seems to be a coincidence.

from coverage.parser import PythonParser
text = b"\xFF\x8D\xA7\xDC\n''\xA7".decode("cp273")
PythonParser(text).parse_source()
  File "/mnt/c/Users/ddini/PycharmProjects/coveragepy/coverage/parser.py", line 271, in parse_source
    self._raw_parse()
  File "/mnt/c/Users/ddini/PycharmProjects/coveragepy/coverage/parser.py", line 154, in _raw_parse
    tokgen = generate_tokens(self.text)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/ddini/PycharmProjects/coveragepy/coverage/phystokens.py", line 179, in generate_tokens
    return list(tokenize.generate_tokens(readline))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/tokenize.py", line 525, in _tokenize
    raise TokenError("EOF in multi-line statement", (lnum, 0))
tokenize.TokenError: ('EOF in multi-line statement', (2, 0))

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/mnt/c/Users/ddini/PycharmProjects/coveragepy/tok.py", line 22, in <module>
    PythonParser(text).parse_source()
  File "/mnt/c/Users/ddini/PycharmProjects/coveragepy/coverage/parser.py", line 277, in parse_source
    raise NotPython(
coverage.exceptions.NotPython: Couldn't parse '<code>' as Python source: 'EOF in multi-line statement' at line 2

Here's the code I used to try to find matching errors:

from encodings.aliases import aliases
from coverage.parser import PythonParser, NotPython

btext = b"\xFF\x8D\xA7\xDC\n''\xA7"

encs = sorted(set(aliases.values()))
for enc in encs:
    try:
        text = btext.decode(enc)
    except:
        continue
    parser = PythonParser(text)
    try:
        parser.parse_source()
    except NotPython as n:
        print(enc, n)

@nedbat
Copy link
Owner Author

nedbat commented May 20, 2024

@devdanzin said on Mastodon:

Maybe the minimized test case is a seed for the fuzzer, instead of direct input?

"A minimized testcase, which is a fuzzer input that can be used to reproduce the bug."

pigweed.dev/pw_fuzzer/guides/reproducing_oss_fuzz_bugs.html

@nedbat
Copy link
Owner Author

nedbat commented May 20, 2024

This is fixed in commit 364282e

@nedbat
Copy link
Owner Author

nedbat commented May 26, 2024

This is now released as part of coverage 7.5.2.

renovate bot added a commit to allenporter/flux-local that referenced this issue May 26, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [coverage](https://togithub.com/nedbat/coveragepy) | `==7.5.1` ->
`==7.5.2` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/coverage/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/coverage/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/coverage/7.5.1/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/coverage/7.5.1/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>nedbat/coveragepy (coverage)</summary>

###
[`v7.5.2`](https://togithub.com/nedbat/coveragepy/blob/HEAD/CHANGES.rst#Version-752--2024-05-24)

[Compare
Source](https://togithub.com/nedbat/coveragepy/compare/7.5.1...7.5.2)

- Fix: nested matches of exclude patterns could exclude too much code,
as
    reported in `issue 1779`\_.  This is now fixed.

- Changed: previously, coverage.py would consider a module docstring to
be an
executable statement if it appeared after line 1 in the file, but not
executable if it was the first line. Now module docstrings are never
counted
as executable statements. This can change coverage.py's count of the
number
of statements in a file, which can slightly change the coverage
percentage
    reported.

- In the HTML report, the filter term and "hide covered" checkbox
settings are
remembered between viewings, thanks to `Daniel Diniz <pull 1776_>`\_.

-   Python 3.13.0b1 is supported.

- Fix: parsing error handling is improved to ensure bizarre source files
are
handled gracefully, and to unblock oss-fuzz fuzzing, thanks to `Liam
DeVoe <pull 1788_>`*. Closes `issue 1787`*.

.. \_pull
1776:[nedbat/coveragepy#1776
.. \_issue
1779[nedbat/coveragepy#1779
.. \_issue
178[nedbat/coveragepy#1787
.. \_pull
17[nedbat/coveragepy#1788

.. \_changes\_7-5-1:

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/allenporter/flux-local).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zNjguMTAiLCJ1cGRhdGVkSW5WZXIiOiIzNy4zNjguMTAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
renovate bot added a commit to allenporter/pyrainbird that referenced this issue May 27, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [coverage](https://togithub.com/nedbat/coveragepy) | `==7.5.1` ->
`==7.5.2` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/coverage/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/coverage/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/coverage/7.5.1/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/coverage/7.5.1/7.5.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>nedbat/coveragepy (coverage)</summary>

###
[`v7.5.2`](https://togithub.com/nedbat/coveragepy/blob/HEAD/CHANGES.rst#Version-752--2024-05-24)

[Compare
Source](https://togithub.com/nedbat/coveragepy/compare/7.5.1...7.5.2)

- Fix: nested matches of exclude patterns could exclude too much code,
as
    reported in `issue 1779`\_.  This is now fixed.

- Changed: previously, coverage.py would consider a module docstring to
be an
executable statement if it appeared after line 1 in the file, but not
executable if it was the first line. Now module docstrings are never
counted
as executable statements. This can change coverage.py's count of the
number
of statements in a file, which can slightly change the coverage
percentage
    reported.

- In the HTML report, the filter term and "hide covered" checkbox
settings are
remembered between viewings, thanks to `Daniel Diniz <pull 1776_>`\_.

-   Python 3.13.0b1 is supported.

- Fix: parsing error handling is improved to ensure bizarre source files
are
handled gracefully, and to unblock oss-fuzz fuzzing, thanks to `Liam
DeVoe <pull 1788_>`*. Closes `issue 1787`*.

.. \_pull
1776:[nedbat/coveragepy#1776
.. \_issue
1779[nedbat/coveragepy#1779
.. \_issue
178[nedbat/coveragepy#1787
.. \_pull
17[nedbat/coveragepy#1788

.. \_changes\_7-5-1:

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/allenporter/pyrainbird).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zNzcuOCIsInVwZGF0ZWRJblZlciI6IjM3LjM3Ny44IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
github-merge-queue bot pushed a commit to canonical/charmcraft that referenced this issue Jun 10, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [coverage](https://togithub.com/nedbat/coveragepy) | `==7.5.1` ->
`==7.5.3` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/coverage/7.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/coverage/7.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/coverage/7.5.1/7.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/coverage/7.5.1/7.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [cryptography](https://togithub.com/pyca/cryptography)
([changelog](https://cryptography.io/en/latest/changelog/)) | `==42.0.7`
-> `==42.0.8` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/cryptography/42.0.8?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/cryptography/42.0.8?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/cryptography/42.0.7/42.0.8?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/cryptography/42.0.7/42.0.8?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [freezegun](https://togithub.com/spulec/freezegun)
([changelog](https://togithub.com/spulec/freezegun/blob/master/CHANGELOG))
| `==1.5.0` -> `==1.5.1` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/freezegun/1.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/freezegun/1.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/freezegun/1.5.0/1.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/freezegun/1.5.0/1.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [platformdirs](https://togithub.com/platformdirs/platformdirs) |
`==4.2.1` -> `==4.2.2` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/platformdirs/4.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/platformdirs/4.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/platformdirs/4.2.1/4.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/platformdirs/4.2.1/4.2.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>nedbat/coveragepy (coverage)</summary>

###
[`v7.5.3`](https://togithub.com/nedbat/coveragepy/blob/HEAD/CHANGES.rst#Version-753--2024-05-28)

[Compare
Source](https://togithub.com/nedbat/coveragepy/compare/7.5.2...7.5.3)

- Performance improvements for combining data files, especially when
measuring
line coverage. A few different quadratic behaviors were eliminated. In
one
extreme case of combining 700+ data files, the time dropped from more
than
three hours to seven minutes. Thanks for Kraken Tech for funding the
fix.

- Performance improvements for generating HTML reports, with a side
benefit of
reducing memory use, closing `issue 1791`\_. Thanks to Daniel Diniz for
    helping to diagnose the problem.

.. \_issue
1791:[nedbat/coveragepy#1791

.. \_changes\_7-5-2:

###
[`v7.5.2`](https://togithub.com/nedbat/coveragepy/blob/HEAD/CHANGES.rst#Version-752--2024-05-24)

[Compare
Source](https://togithub.com/nedbat/coveragepy/compare/7.5.1...7.5.2)

- Fix: nested matches of exclude patterns could exclude too much code,
as
    reported in `issue 1779`\_.  This is now fixed.

- Changed: previously, coverage.py would consider a module docstring to
be an
executable statement if it appeared after line 1 in the file, but not
executable if it was the first line. Now module docstrings are never
counted
as executable statements. This can change coverage.py's count of the
number
of statements in a file, which can slightly change the coverage
percentage
    reported.

- In the HTML report, the filter term and "hide covered" checkbox
settings are
remembered between viewings, thanks to `Daniel Diniz <pull 1776_>`\_.

-   Python 3.13.0b1 is supported.

- Fix: parsing error handling is improved to ensure bizarre source files
are
handled gracefully, and to unblock oss-fuzz fuzzing, thanks to `Liam
DeVoe <pull 1788_>`*. Closes `issue 1787`*.

.. \_pull
1776:[nedbat/coveragepy#1776
.. \_issue
1779[nedbat/coveragepy#1779
.. \_issue
178[nedbat/coveragepy#1787
.. \_pull
17[nedbat/coveragepy#1788

.. \_changes\_7-5-1:

</details>

<details>
<summary>pyca/cryptography (cryptography)</summary>

###
[`v42.0.8`](https://togithub.com/pyca/cryptography/compare/42.0.7...42.0.8)

[Compare
Source](https://togithub.com/pyca/cryptography/compare/42.0.7...42.0.8)

</details>

<details>
<summary>spulec/freezegun (freezegun)</summary>

###
[`v1.5.1`](https://togithub.com/spulec/freezegun/blob/HEAD/CHANGELOG#151)

[Compare
Source](https://togithub.com/spulec/freezegun/compare/1.5.0...1.5.1)

-   Fix the typing of the `tick()` method, and improve it's behaviour.

</details>

<details>
<summary>platformdirs/platformdirs (platformdirs)</summary>

###
[`v4.2.2`](https://togithub.com/platformdirs/platformdirs/releases/tag/4.2.2)

[Compare
Source](https://togithub.com/platformdirs/platformdirs/compare/4.2.1...4.2.2)

<!-- Release notes generated using configuration in .github/release.yml
at main -->

#### What's Changed

- Fix android detection when python4android is present by
[@&#8203;tmolitor-stud-tu](https://togithub.com/tmolitor-stud-tu) in
[platformdirs/platformdirs#277

#### New Contributors

- [@&#8203;tmolitor-stud-tu](https://togithub.com/tmolitor-stud-tu) made
their first contribution in
[platformdirs/platformdirs#277

**Full Changelog**:
platformdirs/platformdirs@4.2.1...4.2.2

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" in timezone Etc/UTC,
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://togithub.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/canonical/charmcraft).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zOTMuMCIsInVwZGF0ZWRJblZlciI6IjM3LjM5My4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants