Bug report
Bug description:
find_frozen in Python/import.c converts the module name to a C string using PyUnicode_AsUTF8, which returns a \0-terminated pointer into the Unicode object's internal buffer. When the name contains an embedded null byte -- for example "codecs\x00junk" -- the C string passed to look_up_frozen is silently truncated to "codecs", so the frozen table lookup succeeds.
The module is then created and registered in sys.modules under the full key "codecs\x00junk" rather than "codecs", producing a second, independent frozen codecs module that is not the cached one. Every subsequent call with such a name bypasses the cache and allocates a fresh copy of all the module's functions/etc.
The following reproducer shows the inconsistency:
import sys before = set(sys.modules.keys()) m = __import__('codecs\x00junk') new_keys = set(sys.modules.keys()) - before print("Added to sys.modules.keys:", new_keys) print("Name of the newly added module:", m.__name__) print("Modules are the same?", m is sys.modules.get('codecs'))
... which shows:
Added to sys.modules.keys: {'codecs\x00junk'}
Name of the newly added module: codecsjunk
Modules are the same? False
This bug was discovered by fuzzing pickle.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-150633: properly handle imports with null bytes in names #150634
- [3.15] gh-150633: Properly handle null characters in the name when importing frozen modules (GH-150634) #151100
- [3.14] gh-150633: Properly handle null characters in the name when importing frozen modules (GH-150634) #151101
- [3.13] gh-150633: Properly handle null characters in the name when importing frozen modules (GH-150634) #151102
- gh-150633: Minor improvement of a newly added test #151103
- [3.15] gh-150633: Minor improvement of a newly added test (GH-151103) #151106