]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-23224: Fix segfaults and multiple leaks in the lzma and bz2 modules (GH-7822)
authorZackery Spytz <zspytz@gmail.com>
Thu, 23 Feb 2023 14:00:58 +0000 (06:00 -0800)
committerGitHub <noreply@github.com>
Thu, 23 Feb 2023 14:00:58 +0000 (06:00 -0800)
lzma.LZMADecompressor and bz2.BZ2Decompressor objects caused
segfaults when their `__init__()` methods were not called.

lzma.LZMADecompressor, lzma.LZMACompressor, bz2.BZ2Compressor,
and bz2.BZ2Decompressor objects would leak locks and internal buffers
when their `__init__()` methods were called multiple times.

https://bugs.python.org/issue23224

Lib/test/test_bz2.py
Lib/test/test_lzma.py
Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst [new file with mode: 0644]
Modules/_bz2module.c
Modules/_lzmamodule.c
Modules/clinic/_bz2module.c.h
Modules/clinic/_lzmamodule.c.h

index c97ed1cea0d113bf2842f3c50a7950ebbf9549ee..e4dd7fc2100b6277c8707a8f6b7c92b988382dfe 100644 (file)
@@ -844,6 +844,10 @@ class BZ2DecompressorTest(BaseTest):
             bzd.__init__()
         self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
 
+    def test_uninitialized_BZ2Decompressor_crash(self):
+        self.assertEqual(BZ2Decompressor.__new__(BZ2Decompressor).
+                         decompress(bytes()), b'')
+
 
 class CompressDecompressTest(BaseTest):
     def testCompress(self):
index 18f474ba2a8bdc4f409ec9390becdf83793fe30c..ac53bdda2f174742e787aedcbf59cf01daad9d39 100644 (file)
@@ -380,6 +380,10 @@ class CompressorDecompressorTestCase(unittest.TestCase):
             lzd.__init__()
         self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
 
+    def test_uninitialized_LZMADecompressor_crash(self):
+        self.assertEqual(LZMADecompressor.__new__(LZMADecompressor).
+                         decompress(bytes()), b'')
+
 
 class CompressDecompressFunctionTestCase(unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst b/Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst
new file mode 100644 (file)
index 0000000..8909753
--- /dev/null
@@ -0,0 +1,6 @@
+Fix segfaults when creating :class:`lzma.LZMADecompressor` and
+:class:`bz2.BZ2Decompressor` objects without calling ``__init__()``, and fix
+leakage of locks and internal buffers when calling the ``__init__()``
+methods of :class:`lzma.LZMADecompressor`, :class:`lzma.LZMACompressor`,
+:class:`bz2.BZ2Compressor`, and :class:`bz2.BZ2Decompressor` objects
+multiple times.
index 9304c13fbed5fca3b3a7d9874fb3a19d82095546..8e7b8e8078af4e7abc6fd62f8bc93de479b10f91 100644 (file)
     #error "The maximum block size accepted by libbzip2 is UINT32_MAX."
 #endif
 
+typedef struct {
+    PyTypeObject *bz2_compressor_type;
+    PyTypeObject *bz2_decompressor_type;
+} _bz2_state;
+
+static inline _bz2_state *
+get_module_state(PyObject *module)
+{
+    void *state = PyModule_GetState(module);
+    assert(state != NULL);
+    return (_bz2_state *)state;
+}
+
+static struct PyModuleDef _bz2module;
+
+static inline _bz2_state *
+find_module_state_by_def(PyTypeObject *type)
+{
+    PyObject *module = PyType_GetModuleByDef(type, &_bz2module);
+    assert(module != NULL);
+    return get_module_state(module);
+}
+
 /* On success, return value >= 0
    On failure, return -1 */
 static inline Py_ssize_t
@@ -214,12 +237,14 @@ error:
 
 /*[clinic input]
 module _bz2
-class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type"
-class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type"
+class _bz2.BZ2Compressor "BZ2Compressor *" "clinic_state()->bz2_compressor_type"
+class _bz2.BZ2Decompressor "BZ2Decompressor *" "clinic_state()->bz2_decompressor_type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dc7d7992a79f9cb7]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92348121632b94c4]*/
 
+#define clinic_state() (find_module_state_by_def(type))
 #include "clinic/_bz2module.c.h"
+#undef clinic_state
 
 /*[clinic input]
 _bz2.BZ2Compressor.compress
@@ -295,24 +320,43 @@ BZ2_Free(void* ctx, void *ptr)
     PyMem_RawFree(ptr);
 }
 
+/*[clinic input]
+@classmethod
+_bz2.BZ2Compressor.__new__
+
+    compresslevel: int = 9
+        Compression level, as a number between 1 and 9.
+    /
 
-/* Argument Clinic is not used since the Argument Clinic always want to
-   check the type which would be wrong here */
-static int
-_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
+Create a compressor object for compressing data incrementally.
+
+For one-shot compression, use the compress() function instead.
+[clinic start generated code]*/
+
+static PyObject *
+_bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel)
+/*[clinic end generated code: output=83346c96beaacad7 input=d4500d2a52c8b263]*/
 {
     int bzerror;
+    BZ2Compressor *self;
 
     if (!(1 <= compresslevel && compresslevel <= 9)) {
         PyErr_SetString(PyExc_ValueError,
                         "compresslevel must be between 1 and 9");
-        return -1;
+        return NULL;
+    }
+
+    assert(type != NULL && type->tp_alloc != NULL);
+    self = (BZ2Compressor *)type->tp_alloc(type, 0);
+    if (self == NULL) {
+        return NULL;
     }
 
     self->lock = PyThread_allocate_lock();
     if (self->lock == NULL) {
+        Py_DECREF(self);
         PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
-        return -1;
+        return NULL;
     }
 
     self->bzs.opaque = NULL;
@@ -322,49 +366,11 @@ _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
     if (catch_bz2_error(bzerror))
         goto error;
 
-    return 0;
+    return (PyObject *)self;
 
 error:
-    PyThread_free_lock(self->lock);
-    self->lock = NULL;
-    return -1;
-}
-
-PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__,
-"BZ2Compressor(compresslevel=9, /)\n"
-"--\n"
-"\n"
-"Create a compressor object for compressing data incrementally.\n"
-"\n"
-"  compresslevel\n"
-"    Compression level, as a number between 1 and 9.\n"
-"\n"
-"For one-shot compression, use the compress() function instead.");
-
-static int
-_bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    int return_value = -1;
-    int compresslevel = 9;
-
-    if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) {
-        goto exit;
-    }
-    if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) {
-        goto exit;
-    }
-    if (PyTuple_GET_SIZE(args) < 1) {
-        goto skip_optional;
-    }
-    compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0));
-    if (compresslevel == -1 && PyErr_Occurred()) {
-        goto exit;
-    }
-skip_optional:
-    return_value = _bz2_BZ2Compressor___init___impl((BZ2Compressor *)self, compresslevel);
-
-exit:
-    return return_value;
+    Py_DECREF(self);
+    return NULL;
 }
 
 static void
@@ -395,9 +401,8 @@ static PyMethodDef BZ2Compressor_methods[] = {
 static PyType_Slot bz2_compressor_type_slots[] = {
     {Py_tp_dealloc, BZ2Compressor_dealloc},
     {Py_tp_methods, BZ2Compressor_methods},
-    {Py_tp_init, _bz2_BZ2Compressor___init__},
-    {Py_tp_new, PyType_GenericNew},
-    {Py_tp_doc, (char *)_bz2_BZ2Compressor___init____doc__},
+    {Py_tp_new, _bz2_BZ2Compressor},
+    {Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__},
     {Py_tp_traverse, BZ2Compressor_traverse},
     {0, 0}
 };
@@ -624,28 +629,40 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data,
     return result;
 }
 
-/* Argument Clinic is not used since the Argument Clinic always want to
-   check the type which would be wrong here */
-static int
-_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
+/*[clinic input]
+@classmethod
+_bz2.BZ2Decompressor.__new__
+
+Create a decompressor object for decompressing data incrementally.
+
+For one-shot decompression, use the decompress() function instead.
+[clinic start generated code]*/
+
+static PyObject *
+_bz2_BZ2Decompressor_impl(PyTypeObject *type)
+/*[clinic end generated code: output=5150d51ccaab220e input=b87413ce51853528]*/
 {
+    BZ2Decompressor *self;
     int bzerror;
 
-    PyThread_type_lock lock = PyThread_allocate_lock();
-    if (lock == NULL) {
-        PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
-        return -1;
+    assert(type != NULL && type->tp_alloc != NULL);
+    self = (BZ2Decompressor *)type->tp_alloc(type, 0);
+    if (self == NULL) {
+        return NULL;
     }
-    if (self->lock != NULL) {
-        PyThread_free_lock(self->lock);
+
+    self->lock = PyThread_allocate_lock();
+    if (self->lock == NULL) {
+        Py_DECREF(self);
+        PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
+        return NULL;
     }
-    self->lock = lock;
 
     self->needs_input = 1;
     self->bzs_avail_in_real = 0;
     self->input_buffer = NULL;
     self->input_buffer_size = 0;
-    Py_XSETREF(self->unused_data, PyBytes_FromStringAndSize(NULL, 0));
+    self->unused_data = PyBytes_FromStringAndSize(NULL, 0);
     if (self->unused_data == NULL)
         goto error;
 
@@ -653,40 +670,13 @@ _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
     if (catch_bz2_error(bzerror))
         goto error;
 
-    return 0;
+    return (PyObject *)self;
 
 error:
-    Py_CLEAR(self->unused_data);
-    PyThread_free_lock(self->lock);
-    self->lock = NULL;
-    return -1;
-}
-
-static int
-_bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    int return_value = -1;
-
-    if (!_PyArg_NoPositional("BZ2Decompressor", args)) {
-        goto exit;
-    }
-    if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) {
-        goto exit;
-    }
-    return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self);
-
-exit:
-    return return_value;
+    Py_DECREF(self);
+    return NULL;
 }
 
-PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__,
-"BZ2Decompressor()\n"
-"--\n"
-"\n"
-"Create a decompressor object for decompressing data incrementally.\n"
-"\n"
-"For one-shot decompression, use the decompress() function instead.");
-
 static void
 BZ2Decompressor_dealloc(BZ2Decompressor *self)
 {
@@ -738,10 +728,9 @@ static PyMemberDef BZ2Decompressor_members[] = {
 static PyType_Slot bz2_decompressor_type_slots[] = {
     {Py_tp_dealloc, BZ2Decompressor_dealloc},
     {Py_tp_methods, BZ2Decompressor_methods},
-    {Py_tp_init, _bz2_BZ2Decompressor___init__},
-    {Py_tp_doc, (char *)_bz2_BZ2Decompressor___init____doc__},
+    {Py_tp_doc, (char *)_bz2_BZ2Decompressor__doc__},
     {Py_tp_members, BZ2Decompressor_members},
-    {Py_tp_new, PyType_GenericNew},
+    {Py_tp_new, _bz2_BZ2Decompressor},
     {Py_tp_traverse, BZ2Decompressor_traverse},
     {0, 0}
 };
@@ -762,31 +751,52 @@ static PyType_Spec bz2_decompressor_type_spec = {
 static int
 _bz2_exec(PyObject *module)
 {
-    PyTypeObject *bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
+    _bz2_state *state = get_module_state(module);
+    state->bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
                                                             &bz2_compressor_type_spec, NULL);
-    if (bz2_compressor_type == NULL) {
+    if (state->bz2_compressor_type == NULL) {
         return -1;
     }
-    int rc = PyModule_AddType(module, bz2_compressor_type);
-    Py_DECREF(bz2_compressor_type);
-    if (rc < 0) {
+    if (PyModule_AddType(module, state->bz2_compressor_type) < 0) {
         return -1;
     }
 
-    PyTypeObject *bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
+    state->bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
                                                          &bz2_decompressor_type_spec, NULL);
-    if (bz2_decompressor_type == NULL) {
+    if (state->bz2_decompressor_type == NULL) {
         return -1;
     }
-    rc = PyModule_AddType(module, bz2_decompressor_type);
-    Py_DECREF(bz2_decompressor_type);
-    if (rc < 0) {
+    if (PyModule_AddType(module, state->bz2_decompressor_type) < 0) {
         return -1;
     }
 
     return 0;
 }
 
+static int
+_bz2_traverse(PyObject *module, visitproc visit, void *arg)
+{
+    _bz2_state *state = get_module_state(module);
+    Py_VISIT(state->bz2_compressor_type);
+    Py_VISIT(state->bz2_decompressor_type);
+    return 0;
+}
+
+static int
+_bz2_clear(PyObject *module)
+{
+    _bz2_state *state = get_module_state(module);
+    Py_CLEAR(state->bz2_compressor_type);
+    Py_CLEAR(state->bz2_decompressor_type);
+    return 0;
+}
+
+static void
+_bz2_free(void *module)
+{
+    (void)_bz2_clear((PyObject *)module);
+}
+
 static struct PyModuleDef_Slot _bz2_slots[] = {
     {Py_mod_exec, _bz2_exec},
     {0, NULL}
@@ -795,6 +805,10 @@ static struct PyModuleDef_Slot _bz2_slots[] = {
 static struct PyModuleDef _bz2module = {
     .m_base = PyModuleDef_HEAD_INIT,
     .m_name = "_bz2",
+    .m_size = sizeof(_bz2_state),
+    .m_traverse = _bz2_traverse,
+    .m_clear = _bz2_clear,
+    .m_free = _bz2_free,
     .m_slots = _bz2_slots,
 };
 
index b572d8cd909fd14b83e1e9f16702d76c5551a04f..bccab8639159e7bbf1bcd578fc4bd379290ec345 100644 (file)
@@ -734,7 +734,8 @@ Compressor_init_raw(_lzma_state *state, lzma_stream *lzs, PyObject *filterspecs)
 }
 
 /*[-clinic input]
-_lzma.LZMACompressor.__init__
+@classmethod
+_lzma.LZMACompressor.__new__
 
     format: int(c_default="FORMAT_XZ") = FORMAT_XZ
         The container format to use for the output.  This can
@@ -765,8 +766,8 @@ the raw compressor does not support preset compression levels.
 
 For one-shot compression, use the compress() function instead.
 [-clinic start generated code]*/
-static int
-Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
+static PyObject *
+Compressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     static char *arg_names[] = {"format", "check", "preset", "filters", NULL};
     int format = FORMAT_XZ;
@@ -774,31 +775,37 @@ Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
     uint32_t preset = LZMA_PRESET_DEFAULT;
     PyObject *preset_obj = Py_None;
     PyObject *filterspecs = Py_None;
-    _lzma_state *state = PyType_GetModuleState(Py_TYPE(self));
+    Compressor *self;
+
+    _lzma_state *state = PyType_GetModuleState(type);
     assert(state != NULL);
     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                      "|iiOO:LZMACompressor", arg_names,
                                      &format, &check, &preset_obj,
                                      &filterspecs)) {
-        return -1;
+        return NULL;
     }
 
     if (format != FORMAT_XZ && check != -1 && check != LZMA_CHECK_NONE) {
         PyErr_SetString(PyExc_ValueError,
                         "Integrity checks are only supported by FORMAT_XZ");
-        return -1;
+        return NULL;
     }
 
     if (preset_obj != Py_None && filterspecs != Py_None) {
         PyErr_SetString(PyExc_ValueError,
                         "Cannot specify both preset and filter chain");
-        return -1;
+        return NULL;
     }
 
-    if (preset_obj != Py_None) {
-        if (!uint32_converter(preset_obj, &preset)) {
-            return -1;
-        }
+    if (preset_obj != Py_None && !uint32_converter(preset_obj, &preset)) {
+        return NULL;
+    }
+
+    assert(type != NULL && type->tp_alloc != NULL);
+    self = (Compressor *)type->tp_alloc(type, 0);
+    if (self == NULL) {
+        return NULL;
     }
 
     self->alloc.opaque = NULL;
@@ -808,8 +815,9 @@ Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
 
     self->lock = PyThread_allocate_lock();
     if (self->lock == NULL) {
+        Py_DECREF(self);
         PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
-        return -1;
+        return NULL;
     }
 
     self->flushed = 0;
@@ -819,31 +827,33 @@ Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
                 check = LZMA_CHECK_CRC64;
             }
             if (Compressor_init_xz(state, &self->lzs, check, preset, filterspecs) != 0) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         case FORMAT_ALONE:
             if (Compressor_init_alone(state, &self->lzs, preset, filterspecs) != 0) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         case FORMAT_RAW:
             if (Compressor_init_raw(state, &self->lzs, filterspecs) != 0) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         default:
             PyErr_Format(PyExc_ValueError,
                          "Invalid container format: %d", format);
-            break;
+            goto error;
     }
 
-    PyThread_free_lock(self->lock);
-    self->lock = NULL;
-    return -1;
+    return (PyObject *)self;
+
+error:
+    Py_DECREF(self);
+    return NULL;
 }
 
 static void
@@ -902,8 +912,7 @@ PyDoc_STRVAR(Compressor_doc,
 static PyType_Slot lzma_compressor_type_slots[] = {
     {Py_tp_dealloc, Compressor_dealloc},
     {Py_tp_methods, Compressor_methods},
-    {Py_tp_init, Compressor_init},
-    {Py_tp_new, PyType_GenericNew},
+    {Py_tp_new, Compressor_new},
     {Py_tp_doc, (char *)Compressor_doc},
     {Py_tp_traverse, Compressor_traverse},
     {0, 0}
@@ -1165,7 +1174,8 @@ Decompressor_init_raw(_lzma_state *state, lzma_stream *lzs, PyObject *filterspec
 }
 
 /*[clinic input]
-_lzma.LZMADecompressor.__init__
+@classmethod
+_lzma.LZMADecompressor.__new__
 
     format: int(c_default="FORMAT_AUTO") = FORMAT_AUTO
         Specifies the container format of the input stream.  If this is
@@ -1189,54 +1199,57 @@ Create a decompressor object for decompressing data incrementally.
 For one-shot decompression, use the decompress() function instead.
 [clinic start generated code]*/
 
-static int
-_lzma_LZMADecompressor___init___impl(Decompressor *self, int format,
-                                     PyObject *memlimit, PyObject *filters)
-/*[clinic end generated code: output=3e1821f8aa36564c input=81fe684a6c2f8a27]*/
+static PyObject *
+_lzma_LZMADecompressor_impl(PyTypeObject *type, int format,
+                            PyObject *memlimit, PyObject *filters)
+/*[clinic end generated code: output=2d46d5e70f10bc7f input=ca40cd1cb1202b0d]*/
 {
+    Decompressor *self;
     const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK;
     uint64_t memlimit_ = UINT64_MAX;
     lzma_ret lzret;
-    _lzma_state *state = PyType_GetModuleState(Py_TYPE(self));
+    _lzma_state *state = PyType_GetModuleState(type);
     assert(state != NULL);
 
     if (memlimit != Py_None) {
         if (format == FORMAT_RAW) {
             PyErr_SetString(PyExc_ValueError,
                             "Cannot specify memory limit with FORMAT_RAW");
-            return -1;
+            return NULL;
         }
         memlimit_ = PyLong_AsUnsignedLongLong(memlimit);
         if (PyErr_Occurred()) {
-            return -1;
+            return NULL;
         }
     }
 
     if (format == FORMAT_RAW && filters == Py_None) {
         PyErr_SetString(PyExc_ValueError,
                         "Must specify filters for FORMAT_RAW");
-        return -1;
+        return NULL;
     } else if (format != FORMAT_RAW && filters != Py_None) {
         PyErr_SetString(PyExc_ValueError,
                         "Cannot specify filters except with FORMAT_RAW");
-        return -1;
+        return NULL;
     }
 
+    assert(type != NULL && type->tp_alloc != NULL);
+    self = (Decompressor *)type->tp_alloc(type, 0);
+    if (self == NULL) {
+        return NULL;
+    }
     self->alloc.opaque = NULL;
     self->alloc.alloc = PyLzma_Malloc;
     self->alloc.free = PyLzma_Free;
     self->lzs.allocator = &self->alloc;
     self->lzs.next_in = NULL;
 
-    PyThread_type_lock lock = PyThread_allocate_lock();
-    if (lock == NULL) {
+    self->lock = PyThread_allocate_lock();
+    if (self->lock == NULL) {
+        Py_DECREF(self);
         PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
-        return -1;
-    }
-    if (self->lock != NULL) {
-        PyThread_free_lock(self->lock);
+        return NULL;
     }
-    self->lock = lock;
 
     self->check = LZMA_CHECK_UNKNOWN;
     self->needs_input = 1;
@@ -1251,43 +1264,43 @@ _lzma_LZMADecompressor___init___impl(Decompressor *self, int format,
         case FORMAT_AUTO:
             lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags);
             if (catch_lzma_error(state, lzret)) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         case FORMAT_XZ:
             lzret = lzma_stream_decoder(&self->lzs, memlimit_, decoder_flags);
             if (catch_lzma_error(state, lzret)) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         case FORMAT_ALONE:
             self->check = LZMA_CHECK_NONE;
             lzret = lzma_alone_decoder(&self->lzs, memlimit_);
             if (catch_lzma_error(state, lzret)) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         case FORMAT_RAW:
             self->check = LZMA_CHECK_NONE;
             if (Decompressor_init_raw(state, &self->lzs, filters) == -1) {
-                break;
+                goto error;
             }
-            return 0;
+            break;
 
         default:
             PyErr_Format(PyExc_ValueError,
                          "Invalid container format: %d", format);
-            break;
+            goto error;
     }
 
+    return (PyObject *)self;
+
 error:
-    Py_CLEAR(self->unused_data);
-    PyThread_free_lock(self->lock);
-    self->lock = NULL;
-    return -1;
+    Py_DECREF(self);
+    return NULL;
 }
 
 static void
@@ -1345,9 +1358,8 @@ static PyMemberDef Decompressor_members[] = {
 static PyType_Slot lzma_decompressor_type_slots[] = {
     {Py_tp_dealloc, Decompressor_dealloc},
     {Py_tp_methods, Decompressor_methods},
-    {Py_tp_init, _lzma_LZMADecompressor___init__},
-    {Py_tp_new, PyType_GenericNew},
-    {Py_tp_doc, (char *)_lzma_LZMADecompressor___init____doc__},
+    {Py_tp_new, _lzma_LZMADecompressor},
+    {Py_tp_doc, (char *)_lzma_LZMADecompressor__doc__},
     {Py_tp_traverse, Decompressor_traverse},
     {Py_tp_members, Decompressor_members},
     {0, 0}
index 50a48b0bf2b8250ac455351c5b579e203431bece..d7797d639ae32e29c2c2c115a710b07c6d237b32 100644 (file)
@@ -71,6 +71,48 @@ _bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored))
     return _bz2_BZ2Compressor_flush_impl(self);
 }
 
+PyDoc_STRVAR(_bz2_BZ2Compressor__doc__,
+"BZ2Compressor(compresslevel=9, /)\n"
+"--\n"
+"\n"
+"Create a compressor object for compressing data incrementally.\n"
+"\n"
+"  compresslevel\n"
+"    Compression level, as a number between 1 and 9.\n"
+"\n"
+"For one-shot compression, use the compress() function instead.");
+
+static PyObject *
+_bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel);
+
+static PyObject *
+_bz2_BZ2Compressor(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    PyObject *return_value = NULL;
+    PyTypeObject *base_tp = clinic_state()->bz2_compressor_type;
+    int compresslevel = 9;
+
+    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+        !_PyArg_NoKeywords("BZ2Compressor", kwargs)) {
+        goto exit;
+    }
+    if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) {
+        goto exit;
+    }
+    if (PyTuple_GET_SIZE(args) < 1) {
+        goto skip_optional;
+    }
+    compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0));
+    if (compresslevel == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+skip_optional:
+    return_value = _bz2_BZ2Compressor_impl(type, compresslevel);
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__,
 "decompress($self, /, data, max_length=-1)\n"
 "--\n"
@@ -168,4 +210,35 @@ exit:
 
     return return_value;
 }
-/*[clinic end generated code: output=829bed4097cf2e63 input=a9049054013a1b77]*/
+
+PyDoc_STRVAR(_bz2_BZ2Decompressor__doc__,
+"BZ2Decompressor()\n"
+"--\n"
+"\n"
+"Create a decompressor object for decompressing data incrementally.\n"
+"\n"
+"For one-shot decompression, use the decompress() function instead.");
+
+static PyObject *
+_bz2_BZ2Decompressor_impl(PyTypeObject *type);
+
+static PyObject *
+_bz2_BZ2Decompressor(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    PyObject *return_value = NULL;
+    PyTypeObject *base_tp = clinic_state()->bz2_decompressor_type;
+
+    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+        !_PyArg_NoPositional("BZ2Decompressor", args)) {
+        goto exit;
+    }
+    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+        !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) {
+        goto exit;
+    }
+    return_value = _bz2_BZ2Decompressor_impl(type);
+
+exit:
+    return return_value;
+}
+/*[clinic end generated code: output=805400e4805098ec input=a9049054013a1b77]*/
index 286d2b0070659f9a57eaaa0e3530bf8ff1a1fe67..9b396a566839217888c1a42675b2756470eb142c 100644 (file)
@@ -169,7 +169,7 @@ exit:
     return return_value;
 }
 
-PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__,
+PyDoc_STRVAR(_lzma_LZMADecompressor__doc__,
 "LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n"
 "--\n"
 "\n"
@@ -192,14 +192,14 @@ PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__,
 "\n"
 "For one-shot decompression, use the decompress() function instead.");
 
-static int
-_lzma_LZMADecompressor___init___impl(Decompressor *self, int format,
-                                     PyObject *memlimit, PyObject *filters);
+static PyObject *
+_lzma_LZMADecompressor_impl(PyTypeObject *type, int format,
+                            PyObject *memlimit, PyObject *filters);
 
-static int
-_lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs)
+static PyObject *
+_lzma_LZMADecompressor(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
-    int return_value = -1;
+    PyObject *return_value = NULL;
     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
 
     #define NUM_KEYWORDS 3
@@ -257,7 +257,7 @@ _lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs
     }
     filters = fastargs[2];
 skip_optional_pos:
-    return_value = _lzma_LZMADecompressor___init___impl((Decompressor *)self, format, memlimit, filters);
+    return_value = _lzma_LZMADecompressor_impl(type, format, memlimit, filters);
 
 exit:
     return return_value;
@@ -338,4 +338,4 @@ exit:
 
     return return_value;
 }
-/*[clinic end generated code: output=da3e83ba97244044 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=96c1fbdada1ef232 input=a9049054013a1b77]*/