8000 gh-132983: [Draft] Run refleak tests against _zstd with tests by emmatyping · Pull Request #133282 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-132983: [Draft] Run refleak tests against _zstd with tests #133282

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

Closed
wants to merge 51 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
9814e3b
Add _zstd module
emmatyping Apr 26, 2025
fda87c8
Add _zstd to modules
emmatyping Apr 26, 2025
887e564
Fix path for compression.zstd module
emmatyping Apr 26, 2025
cdba656
Ignore _zstd module like _io
emmatyping Apr 26, 2025
6b67e9b
Expand module state macros to improve code quality
emmatyping Apr 26, 2025
a99a5d2
Remove backticks suggested in review
emmatyping Apr 27, 2025
02cd17a
Use critical sections to lock object state
emmatyping Apr 27, 2025
54eca74
Remove compress/decompress and mark module as not reliant on the GIL
emmatyping Apr 27, 2025
f605956
Lift critical section to avoid clang warning
emmatyping Apr 27, 2025
2eadc65
Respond to comments by picnixz
emmatyping Apr 27, 2025
8eac354
Call out pyzstd explicitly in license description
emmatyping Apr 27, 2025
26775be
Use a much more robust implementation...
emmatyping Apr 27, 2025
eae460f
Use PyList_GetItemRef for thread safety purposes
emmatyping Apr 27, 2025
2ab5e4a
Use a macro for the minimum supported version
emmatyping Apr 27, 2025
d5bf1c1
remove const from primivite types
emmatyping Apr 27, 2025
9e92b9f
Use PyMem_New in another spot
emmatyping Apr 27, 2025
47f815a
Simplify error handling in _get_frame_size
emmatyping Apr 27, 2025 8000
6a4f7b8
Another simplification of error handling in get_frame_info
emmatyping Apr 27, 2025
d7b3805
Rename _module_state to mod_state
emmatyping Apr 27, 2025
c225ea6
Rewrite comment explaining the context of the code
emmatyping Apr 28, 2025
6e8c61c
Add link to pyzstd
emmatyping Apr 28, 2025
e52ad06
Add TODO about refactoring dict training code
emmatyping Apr 28, 2025
2a1ad8b
Use PyModule_AddObjectRef over PyModule_AddObject
emmatyping Apr 28, 2025
94473b9
Check result of OutputBufferGrow
emmatyping Apr 28, 2025
e2b2515
Simplify return logic in `add_constant_to_type`
emmatyping Apr 29, 2025
cd2f085
Ignore return value of _zstd_clear()
emmatyping Apr 29, 2025
79e174f
Remove redundant comments
emmatyping Apr 29, 2025
ce6f79c
Remove __reduce__ from ZstdDict
emmatyping Apr 29, 2025
e15dd85
Use PyUnicode_FromFormat instead of a buffer
emmatyping Apr 29, 2025
685a3d1
Don't use C constants/types in error messages
emmatyping Apr 29, 2025
1b9f786
Make error messages easier to understand for Python users
emmatyping Apr 29, 2025
40c653c
Lower minimum required version 1.4.0
emmatyping Apr 30, 2025
428677d
Use casts and make slot function signatures correct
emmatyping Apr 30, 2025
0962bbb
Be consistent with CPython on const usage
emmatyping Apr 30, 2025
85efc18
Make else clauses in line with PEP 7
emmatyping Apr 30, 2025
cadf6e4
Fix over-indented blocks in argument clinic
emmatyping Apr 30, 2025
e45c22a
Merge branch 'main' into 3.14-zstd-c-code
emmatyping Apr 30, 2025
b9415be
Merge branch 'main' into 3.14-zstd-c-code
emmatyping Apr 30, 2025
6760545
Add critical section around ZSTD_DCtx_setParameter
emmatyping May 1, 2025
c082d8a
Add a TODO about refactoring critical sections
emmatyping May 1, 2025
e825285
Use Py_UNREACHABLE
emmatyping May 1, 2025
f02ff5a
Move bytes operations out of Py_BEGIN_ALLOW_THREADS
emmatyping May 2, 2025
0d69c8c
Add TODO about ensuring a lock is held
emmatyping May 2, 2025
58b0008
Remove asserts that may not be correct
emmatyping May 2, 2025
c786c3c
Add TODO to make ZstdDict and others GC objects
emmatyping May 2, 2025
d15ced7
Add Python files
emmatyping Apr 30, 2025
dfa7649
Fix byteswarning in test
emmatyping Apr 30, 2025
dedf955
Make objects GC tracked
emmatyping May 2, 2025
9ac9101
Remove unused include
emmatyping May 2, 2025
65542c4
Fix some memory issues
emmatyping May 2, 2025
6328860
Fix refleaks on module and in ZstdDict
emmatyping May 2, 2025
File filter

Filter by extension

Filter by extension

8000
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use critical sections to lock object state
This should avoid races and deadlocks.
  • Loading branch information
emmatyping committed Apr 29, 2025
commit 02cd17a80f62c7df7c65fb7e613032c6311ea80a
15 changes: 0 additions & 15 deletions Modules/_zstd/_zstdmodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ get_zstd_state(PyTypeObject *type) {
return PyModule_GetState(module);
}

/* ------------------
Global macro
------------------ */
#define ACQUIRE_LOCK(obj) PyMutex_Lock(&obj->lock)
#define RELEASE_LOCK(obj) PyMutex_Unlock(&obj->lock)

extern 10000 PyType_Spec zstddict_type_spec;
extern PyType_Spec zstdcompressor_type_spec;
extern PyType_Spec ZstdDecompressor_type_spec;
Expand All @@ -63,9 +57,6 @@ struct _zstd_state {
typedef struct {
PyObject_HEAD

/* Thread lock for generating ZSTD_CDict/ZSTD_DDict */
PyMutex lock;

/* Reusable compress/decompress dictionary, they are created once and
can be shared by multiple threads concurrently, since its usage is
read-only.
Expand All @@ -85,9 +76,6 @@ typedef struct {
typedef struct {
PyObject_HEAD

/* Thread lock for compressing */
PyMutex lock;

/* Compression context */
ZSTD_CCtx *cctx;

Expand All @@ -110,9 +98,6 @@ typedef struct {
typedef struct {
PyObject_HEAD

/* Thread lock for compressing */
PyMutex lock;

/* Decompression context */
ZSTD_DCtx *dctx;

Expand Down
23 changes: 12 additions & 11 deletions Modules/_zstd/compressor.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ _get_CDict(ZstdDict *self, int compressionLevel)
PyObject *capsule;
ZSTD_CDict *cdict;

ACQUIRE_LOCK(self);
Py_BEGIN_CRITICAL_SECTION(self);

/* int level object */
level = PyLong_FromLong(compressionLevel);
Expand Down Expand Up @@ -189,7 +189,7 @@ _get_CDict(ZstdDict *self, int compressionLevel)
cdict = NULL;
success:
Py_XDECREF(level);
RELEASE_LOCK(self);
Py_END_CRITICAL_SECTION();
return cdict;
}

Expand Down Expand Up @@ -250,20 +250,26 @@ _PyZstd_load_c_dict(ZstdCompressor *self, PyObject *dict) {
}
/* Reference a prepared dictionary.
It overrides some compression context's parameters. */
Py_BEGIN_CRITICAL_SECTION(self);
zstd_ret = ZSTD_CCtx_refCDict(self->cctx, c_dict);
Py_END_CRITICAL_SECTION();
} else if (type == DICT_TYPE_UNDIGESTED) {
/* Load a dictionary.
It doesn't override compression context's parameters. */
Py_BEGIN_CRITICAL_SECTION2(self, zd);
zstd_ret = ZSTD_CCtx_loadDictionary(
self->cctx,
PyBytes_AS_STRING(zd->dict_content),
Py_SIZE(zd->dict_content));
Py_END_CRITICAL_SECTION2();
} else if (type == DICT_TYPE_PREFIX) {
/* Load a prefix */
Py_BEGIN_CRITICAL_SECTION2(self, zd);
zstd_ret = ZSTD_CCtx_refPrefix(
self->cctx,
PyBytes_AS_STRING(zd->dict_content),
Py_SIZE(zd->dict_content));
Py_END_CRITICAL_SECTION2();
} else {
/* Impossible code path */
PyErr_SetString(PyExc_SystemError,
Expand Down Expand Up @@ -327,11 +333,6 @@ ZstdCompressor_dealloc(ZstdCompressor *self)
/* Py_XDECREF the dict after free the compression context */
Py_XDECREF(self->dict);

/* Thread lock */
if (PyMutex_IsLocked(&self->lock)) {
PyMutex_Unlock(&self->lock);
}

PyTypeObject *tp = Py_TYPE(self);
tp->tp_free((PyObject*)self);
Py_DECREF(tp);
Expand Down Expand Up @@ -564,7 +565,7 @@ _zstd_ZstdCompressor_compress_impl(ZstdCompressor *self, Py_buffer *data,
}

/* Thread-safe code */
ACQUIRE_LOCK(self);
Py_BEGIN_CRITICAL_SECTION(self);

/* Compress */
if (self->use_multithread && mode == ZSTD_e_continue) {
Expand All @@ -581,7 +582,7 @@ _zstd_ZstdCompressor_compress_impl(ZstdCompressor *self, Py_buffer *data,
/* Resetting cctx's session never fail */
ZSTD_CCtx_reset(self->cctx, ZSTD_reset_session_only);
}
RELEASE_LOCK(self);
Py_END_CRITICAL_SECTION();

return ret;
}
Expand Down Expand Up @@ -616,7 +617,7 @@ _zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode)
}

/* Thread-safe code */
ACQUIRE_LOCK(self);
Py_BEGIN_CRITICAL_SECTION(self);
ret = compress_impl(self, NULL, mode);

if (ret) {
Expand All @@ -627,7 +628,7 @@ _zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode)
/* Resetting cctx's session never fail */
ZSTD_CCtx_reset(self->cctx, ZSTD_reset_session_only);
}
RELEASE_LOCK(self);
Py_END_CRITICAL_SECTION();

return ret;
}
Expand Down
23 changes: 12 additions & 11 deletions Modules/_zstd/decompressor.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ _get_DDict(ZstdDict *self)
return self->d_dict;
}

ACQUIRE_LOCK(self);
Py_BEGIN_CRITICAL_SECTION(self);
if (self->d_dict == NULL) {
/* Create ZSTD_DDict instance from dictionary content */
Py_BEGIN_ALLOW_THREADS
Expand All @@ -58,7 +58,7 @@ _get_DDict(ZstdDict *self)

/* Don't lose any exception */
ret = self->d_dict;
RELEASE_LOCK(self);
Py_END_CRITICAL_SECTION();

return ret;
}
Expand Down Expand Up @@ -175,19 +175,25 @@ _PyZstd_load_d_dict(ZstdDecompressor *self, PyObject *dict)
return -1;
}
/* Reference a prepared dictionary */
Py_BEGIN_CRITICAL_SECTION(self);
zstd_ret = ZSTD_DCtx_refDDict(self->dctx, d_dict);
Py_END_CRITICAL_SECTION();
} else if (type == DICT_TYPE_UNDIGESTED) {
/* Load a dictionary */
Py_BEGIN_CRITICAL_SECTION2(self, zd);
zstd_ret = ZSTD_DCtx_loadDictionary(
self->dctx,
PyBytes_AS_STRING(zd->dict_content),
Py_SIZE(zd->dict_content));
Py_END_CRITICAL_SECTION2();
} else if (type == DICT_TYPE_PREFIX) {
/* Load a prefix */
Py_BEGIN_CRITICAL_SECTION2(self, zd);
zstd_ret = ZSTD_DCtx_refPrefix(
self->dctx,
PyBytes_AS_STRING(zd->dict_content),
Py_SIZE(zd->dict_content));
Py_END_CRITICAL_SECTION2();
} else {
/* Impossible code path */
PyErr_SetString(PyExc_SystemError,
Expand Down Expand Up @@ -397,7 +403,7 @@ stream_decompress(ZstdDecompressor *self, Py_buffer *data, Py_ssize_t max_length
int use_input_buffer;

/* Thread-safe code */
ACQUIRE_LOCK(self);
Py_BEGIN_CRITICAL_SECTION(self);

if (type == TYPE_DECOMPRESSOR) {
/* Check .eof flag */
Expand Down Expand Up @@ -584,7 +590,7 @@ stream_decompress(ZstdDecompressor *self, Py_buffer *data, Py_ssize_t max_length

Py_CLEAR(ret);
success:
RELEASE_LOCK(self);
Py_END_CRITICAL_SECTION();

return ret;
}
Expand Down Expand Up @@ -651,11 +657,6 @@ ZstdDecompressor_dealloc(ZstdDecompressor *self)
/* Free unused data */
Py_XDECREF(self->unused_data);

/* Thread lock */
if (PyMutex_IsLocked(&self->lock)) {
PyMutex_Unlock(&self->lock);
}

PyTypeObject *tp = Py_TYPE(self);
tp->tp_free((PyObject*)self);
Py_DECREF(tp);
Expand Down Expand Up @@ -726,7 +727,7 @@ _zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self)
PyObject *ret;

/* Thread-safe code */
ACQUIRE_LOCK(self);
Py_BEGIN_CRITICAL_SECTION(self);

if (!self->eof) {
_zstd_state* const _module_state = PyType_GetModuleState(Py_TYPE(self));
Expand All @@ -748,7 +749,7 @@ _zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self)
}
}

RELEASE_LOCK(self);
Py_END_CRITICAL_SECTION();

return ret;
}
Expand Down
5 changes: 0 additions & 5 deletions Modules/_zstd/zdict.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ ZstdDict_dealloc(ZstdDict *self)
/* Release dict_content after Free ZSTD_CDict/ZSTD_DDict instances */
Py_XDECREF(self->dict_content);

/* Thread lock */
if (PyMutex_IsLocked(&self->lock)) {
PyMutex_Unlock(&self->lock);
}

PyTypeObject *tp = Py_TYPE(self);
tp->tp_free((PyObject*)self);
Py_DECREF(tp);
Expand Down
0