indygreg / indygreg/python-zstandard
`ZstdCompressionWriter()` constructs successfully but leads to `segmentation fault`
Nessuno ha ancora preso questa issue.
- Lingua principale
- C
- Stelle
- 642
- Fork
- 116
- Merge medio
- 1g 14h
- PR unite (30g)
- 5
Descrizione
I've been fuzzing Python C extension modules for a small research project.
I found a sanitizer issue which is a null-pointer dereference in ZstdCompressionWriter_memory_size.
I reproduced it with the binary wheel from a plain pip install zstandard.
The process terminates with SIGSEGV there as well.
I'm not sure whether zero-argument construction of this type is considered supported (calling ZstdCompressionWriter() with no arguments),
but since it currently terminates the interpreter rather than raising a Python exception, I thought it was worth reporting.
Versions
zstandard 0.25.0, cext backend, CPython 3.12, Linux x86_64.
Reproducer
import zstandard
w = zstandard.ZstdCompressionWriter() # succeeds
w.memory_size() # SIGSEGV
Five calls across the two writer types behave the same way, each from a fresh direct construction:
| class | methods that segfault |
|---|---|
ZstdCompressionWriter |
memory_size(), close(), flush() |
ZstdDecompressionWriter |
memory_size(), flush() |
Sanitizer build
Same call, zstandard built with -fsanitize=address,undefined:
c-ext/compressionwriter.c:64:65: runtime error:
member access within null pointer of type 'ZstdCompressor'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior
c-ext/compressionwriter.c:64:65
AddressSanitizer: SEGV on unknown address 0x000000000020
#0 ZstdCompressionWriter_memory_size c-ext/compressionwriter.c:64:65
ZstdDecompressionWriter.memory_size() reports the equivalent at
c-ext/decompressionwriter.c:50:67.
Expected behavior
I think that direct construction should be rejected with a Python exception, as it is by the CFFI backend.
Under PYTHON_ZSTANDARD_IMPORT_POLICY=cffi the same construction is refused outright:
TypeError: ZstdCompressionWriter.__init__() missing 5 required positional
arguments: 'compressor', 'writer', 'source_size', 'write_size',
and 'write_return_read'
Actual behavior
The C extension permits construction with no arguments, leaving internal fields NULL.
Several methods dereference those fields and terminate the process with SIGSEGV.
Although these objects are normally obtained through stream_writer(), I wonder whether the C extension should reject zero-argument construction, as the CFFI backend already does, rather than produce an uninitialized object.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Esegui prima il riproduttore Python, poi ispeziona c-ext/compressionwriter.c:64 e c-ext/decompressionwriter.c:50 insieme ai percorsi di costruzione del writer. Confronta il comportamento dell’estensione C con il backend CFFI per la costruzione senza argomenti. Il lavoro è completato quando la costruzione diretta non lascia più campi interni NULL raggiungibili e solleva un’eccezione Python invece di causare un segfault.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- c, python
- Ambito
- backend
- Tipo di issue
- Bug
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 76/100