aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/Setup3
-rw-r--r--Modules/Setup.stdlib.in5
-rw-r--r--Modules/_collectionsmodule.c5
-rw-r--r--Modules/_complex.h54
-rw-r--r--Modules/_csv.c73
-rw-r--r--Modules/_ctypes/_ctypes.c179
-rw-r--r--Modules/_ctypes/_ctypes_test.c6
-rw-r--r--Modules/_ctypes/callbacks.c9
-rw-r--r--Modules/_ctypes/callproc.c23
-rw-r--r--Modules/_ctypes/cfield.c47
-rw-r--r--Modules/_ctypes/clinic/_ctypes.c.h44
-rw-r--r--Modules/_ctypes/ctypes.h25
-rw-r--r--Modules/_curses_panel.c369
-rw-r--r--Modules/_cursesmodule.c1165
-rw-r--r--Modules/_datetimemodule.c18
-rw-r--r--Modules/_dbmmodule.c76
-rw-r--r--Modules/_elementtree.c45
-rw-r--r--Modules/_functoolsmodule.c38
-rw-r--r--Modules/_gdbmmodule.c93
-rw-r--r--Modules/_hacl/Hacl_Hash_Blake2b.c52
-rw-r--r--Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c52
-rw-r--r--Modules/_hacl/Hacl_Hash_Blake2s.c52
-rw-r--r--Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c52
-rw-r--r--Modules/_hacl/Hacl_Hash_MD5.c523
-rw-r--r--Modules/_hacl/Hacl_Hash_SHA1.c12
-rw-r--r--Modules/_hacl/Hacl_Hash_SHA2.c42
-rw-r--r--Modules/_hacl/Hacl_Hash_SHA3.c22
-rw-r--r--Modules/_hacl/Hacl_Streaming_HMAC.c127
-rw-r--r--Modules/_hacl/Lib_Memzero0.c20
-rw-r--r--Modules/_hacl/include/krml/FStar_UInt128_Verified.h45
-rw-r--r--Modules/_hacl/python_hacl_namespaces.h237
-rwxr-xr-xModules/_hacl/refresh.sh2
-rw-r--r--Modules/_hashopenssl.c1023
-rw-r--r--Modules/_heapqmodule.c177
-rw-r--r--Modules/_interpchannelsmodule.c222
-rw-r--r--Modules/_interpqueuesmodule.c209
-rw-r--r--Modules/_interpreters_common.h58
-rw-r--r--Modules/_interpretersmodule.c751
-rw-r--r--Modules/_io/bufferedio.c16
-rw-r--r--Modules/_io/bytesio.c284
-rw-r--r--Modules/_io/clinic/bytesio.c.h66
-rw-r--r--Modules/_io/clinic/stringio.c.h12
-rw-r--r--Modules/_io/fileio.c8
-rw-r--r--Modules/_io/iobase.c4
-rw-r--r--Modules/_io/stringio.c29
-rw-r--r--Modules/_io/textio.c22
-rw-r--r--Modules/_io/winconsoleio.c4
-rw-r--r--Modules/_json.c43
-rw-r--r--Modules/_localemodule.c12
-rw-r--r--Modules/_lsprof.c30
-rw-r--r--Modules/_lzmamodule.c25
-rw-r--r--Modules/_opcode.c2
-rw-r--r--Modules/_pickle.c15
-rw-r--r--Modules/_queuemodule.c5
-rw-r--r--Modules/_randommodule.c20
-rw-r--r--Modules/_remote_debugging_module.c3139
-rw-r--r--Modules/_sqlite/blob.c5
-rw-r--r--Modules/_sqlite/clinic/_sqlite3.connect.c.h14
-rw-r--r--Modules/_sqlite/clinic/connection.c.h279
-rw-r--r--Modules/_sqlite/connection.c27
-rw-r--r--Modules/_sqlite/cursor.c5
-rw-r--r--Modules/_sqlite/module.c61
-rw-r--r--Modules/_sre/sre.c6
-rw-r--r--Modules/_ssl.c10
-rw-r--r--Modules/_ssl/debughelpers.c2
-rw-r--r--Modules/_stat.c4
-rw-r--r--Modules/_struct.c9
-rw-r--r--Modules/_testcapi/long.c2
-rw-r--r--Modules/_testcapi/object.c8
-rw-r--r--Modules/_testcapi/unicode.c29
-rw-r--r--Modules/_testcapimodule.c51
-rw-r--r--Modules/_testclinic.c118
-rw-r--r--Modules/_testexternalinspection.c1543
-rw-r--r--Modules/_testinternalcapi.c276
-rw-r--r--Modules/_testinternalcapi/test_lock.c5
-rw-r--r--Modules/_testlimitedcapi/import.c9
-rw-r--r--Modules/_testlimitedcapi/sys.c73
-rw-r--r--Modules/_threadmodule.c113
-rw-r--r--Modules/_tkinter.c5
-rw-r--r--Modules/_uuidmodule.c40
-rw-r--r--Modules/_winapi.c28
-rw-r--r--Modules/_zoneinfo.c5
-rw-r--r--Modules/_zstd/_zstdmodule.c767
-rw-r--r--Modules/_zstd/_zstdmodule.h61
-rw-r--r--Modules/_zstd/buffer.h108
-rw-r--r--Modules/_zstd/clinic/_zstdmodule.c.h429
-rw-r--r--Modules/_zstd/clinic/compressor.c.h294
-rw-r--r--Modules/_zstd/clinic/decompressor.c.h223
-rw-r--r--Modules/_zstd/clinic/zstddict.c.h225
-rw-r--r--Modules/_zstd/compressor.c797
-rw-r--r--Modules/_zstd/decompressor.c717
-rw-r--r--Modules/_zstd/zstddict.c273
-rw-r--r--Modules/_zstd/zstddict.h29
-rw-r--r--Modules/arraymodule.c5
-rw-r--r--Modules/blake2module.c874
-rw-r--r--Modules/clinic/_curses_panel.c.h159
-rw-r--r--Modules/clinic/_cursesmodule.c.h88
-rw-r--r--Modules/clinic/_dbmmodule.c.h37
-rw-r--r--Modules/clinic/_gdbmmodule.c.h70
-rw-r--r--Modules/clinic/_hashopenssl.c.h549
-rw-r--r--Modules/clinic/_heapqmodule.c.h145
-rw-r--r--Modules/clinic/_lsprof.c.h35
-rw-r--r--Modules/clinic/_randommodule.c.h10
-rw-r--r--Modules/clinic/_remote_debugging_module.c.h276
-rw-r--r--Modules/clinic/_testclinic_depr.c.h304
-rw-r--r--Modules/clinic/_threadmodule.c.h50
-rw-r--r--Modules/clinic/_winapi.c.h28
-rw-r--r--Modules/clinic/blake2module.c.h110
-rw-r--r--Modules/clinic/mathmodule.c.h108
-rw-r--r--Modules/clinic/md5module.c.h34
-rw-r--r--Modules/clinic/posixmodule.c.h18
-rw-r--r--Modules/clinic/sha1module.c.h34
-rw-r--r--Modules/clinic/sha2module.c.h130
-rw-r--r--Modules/clinic/sha3module.c.h168
-rw-r--r--Modules/clinic/socketmodule.c.h173
-rw-r--r--Modules/clinic/zlibmodule.c.h120
-rw-r--r--Modules/faulthandler.c34
-rw-r--r--Modules/fcntlmodule.c126
-rw-r--r--Modules/hashlib.h137
-rw-r--r--Modules/hmacmodule.c347
-rw-r--r--Modules/itertoolsmodule.c65
-rw-r--r--Modules/main.c35
-rw-r--r--Modules/mathmodule.c83
-rw-r--r--Modules/md5module.c110
-rw-r--r--Modules/mmapmodule.c30
-rw-r--r--Modules/posixmodule.c162
-rw-r--r--Modules/pwdmodule.c25
-rw-r--r--Modules/sha1module.c90
-rw-r--r--Modules/sha2module.c215
-rw-r--r--Modules/sha3module.c219
-rw-r--r--Modules/socketmodule.c196
-rw-r--r--Modules/socketmodule.h2
-rw-r--r--Modules/syslogmodule.c3
-rw-r--r--Modules/timemodule.c2
-rw-r--r--Modules/xxlimited.c11
-rw-r--r--Modules/zlibmodule.c88
136 files changed, 15019 insertions, 6827 deletions
diff --git a/Modules/Setup b/Modules/Setup
index 65c22d48ba0..a066982df1a 100644
--- a/Modules/Setup
+++ b/Modules/Setup
@@ -201,6 +201,7 @@ PYTHONPATH=$(COREPYTHONPATH)
#_gdbm _gdbmmodule.c -lgdbm
#_lzma _lzmamodule.c -llzma
#_uuid _uuidmodule.c -luuid
+#_zstd _zstd/_zstdmodule.c -lzstd -I$(srcdir)/Modules/_zstd
#zlib zlibmodule.c -lz
# The readline module also supports libeditline (-leditline).
@@ -283,10 +284,10 @@ PYTHONPATH=$(COREPYTHONPATH)
#*shared*
#_ctypes_test _ctypes/_ctypes_test.c
+#_remote_debugging _remote_debugging_module.c
#_testcapi _testcapimodule.c
#_testimportmultiple _testimportmultiple.c
#_testmultiphase _testmultiphase.c
-#_testexternalinspection _testexternalinspection.c
#_testsinglephase _testsinglephase.c
# ---
diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in
index 33e60f37d19..3a38a60a152 100644
--- a/Modules/Setup.stdlib.in
+++ b/Modules/Setup.stdlib.in
@@ -41,6 +41,7 @@
@MODULE__PICKLE_TRUE@_pickle _pickle.c
@MODULE__QUEUE_TRUE@_queue _queuemodule.c
@MODULE__RANDOM_TRUE@_random _randommodule.c
+@MODULE__REMOTE_DEBUGGING_TRUE@_remote_debugging _remote_debugging_module.c
@MODULE__STRUCT_TRUE@_struct _struct.c
# build supports subinterpreters
@@ -64,10 +65,11 @@
@MODULE__DECIMAL_TRUE@_decimal _decimal/_decimal.c
# compression libs and binascii (optional CRC32 from zlib)
-# bindings need -lbz2, -lz, or -llzma, respectively
+# bindings need -lbz2, -llzma, -lzstd, or -lz, respectively
@MODULE_BINASCII_TRUE@binascii binascii.c
@MODULE__BZ2_TRUE@_bz2 _bz2module.c
@MODULE__LZMA_TRUE@_lzma _lzmamodule.c
+@MODULE__ZSTD_TRUE@_zstd _zstd/_zstdmodule.c _zstd/zstddict.c _zstd/compressor.c _zstd/decompressor.c
@MODULE_ZLIB_TRUE@zlib zlibmodule.c
# dbm/gdbm
@@ -186,7 +188,6 @@
@MODULE__TESTIMPORTMULTIPLE_TRUE@_testimportmultiple _testimportmultiple.c
@MODULE__TESTMULTIPHASE_TRUE@_testmultiphase _testmultiphase.c
@MODULE__TESTSINGLEPHASE_TRUE@_testsinglephase _testsinglephase.c
-@MODULE__TESTEXTERNALINSPECTION_TRUE@_testexternalinspection _testexternalinspection.c
@MODULE__CTYPES_TEST_TRUE@_ctypes_test _ctypes/_ctypes_test.c
# Limited API template modules; must be built as shared modules.
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index ad670293ec5..3ba48d5d9d3 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -5,6 +5,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_typeobject.h" // _PyType_GetModuleState()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h>
@@ -1532,9 +1533,7 @@ deque_dealloc(PyObject *self)
Py_ssize_t i;
PyObject_GC_UnTrack(deque);
- if (deque->weakreflist != NULL) {
- PyObject_ClearWeakRefs(self);
- }
+ FT_CLEAR_WEAKREFS(self, deque->weakreflist);
if (deque->leftblock != NULL) {
(void)deque_clear(self);
assert(deque->leftblock != NULL);
diff --git a/Modules/_complex.h b/Modules/_complex.h
deleted file mode 100644
index 28d4a32794b..00000000000
--- a/Modules/_complex.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Workarounds for buggy complex number arithmetic implementations. */
-
-#ifndef Py_HAVE_C_COMPLEX
-# error "this header file should only be included if Py_HAVE_C_COMPLEX is defined"
-#endif
-
-#include <complex.h>
-
-/* Other compilers (than clang), that claims to
- implement C11 *and* define __STDC_IEC_559_COMPLEX__ - don't have
- issue with CMPLX(). This is specific to glibc & clang combination:
- https://sourceware.org/bugzilla/show_bug.cgi?id=26287
-
- Here we fallback to using __builtin_complex(), available in clang
- v12+. Else CMPLX implemented following C11 6.2.5p13: "Each complex type
- has the same representation and alignment requirements as an array
- type containing exactly two elements of the corresponding real type;
- the first element is equal to the real part, and the second element
- to the imaginary part, of the complex number.
- */
-#if !defined(CMPLX)
-# if defined(__clang__) && __has_builtin(__builtin_complex)
-# define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
-# define CMPLXF(x, y) __builtin_complex ((float) (x), (float) (y))
-# define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
-# else
-static inline double complex
-CMPLX(double real, double imag)
-{
- double complex z;
- ((double *)(&z))[0] = real;
- ((double *)(&z))[1] = imag;
- return z;
-}
-
-static inline float complex
-CMPLXF(float real, float imag)
-{
- float complex z;
- ((float *)(&z))[0] = real;
- ((float *)(&z))[1] = imag;
- return z;
-}
-
-static inline long double complex
-CMPLXL(long double real, long double imag)
-{
- long double complex z;
- ((long double *)(&z))[0] = real;
- ((long double *)(&z))[1] = imag;
- return z;
-}
-# endif
-#endif
diff --git a/Modules/_csv.c b/Modules/_csv.c
index e5ae853590b..2e04136e0ac 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -237,7 +237,7 @@ _set_int(const char *name, int *target, PyObject *src, int dflt)
int value;
if (!PyLong_CheckExact(src)) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be an integer", name);
+ "\"%s\" must be an integer, not %T", name, src);
return -1;
}
value = PyLong_AsInt(src);
@@ -255,27 +255,29 @@ _set_char_or_none(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt
if (src == NULL) {
*target = dflt;
}
- else {
+ else if (src == Py_None) {
*target = NOT_SET;
- if (src != Py_None) {
- if (!PyUnicode_Check(src)) {
- PyErr_Format(PyExc_TypeError,
- "\"%s\" must be string or None, not %.200s", name,
- Py_TYPE(src)->tp_name);
- return -1;
- }
- Py_ssize_t len = PyUnicode_GetLength(src);
- if (len < 0) {
- return -1;
- }
- if (len != 1) {
- PyErr_Format(PyExc_TypeError,
- "\"%s\" must be a 1-character string",
- name);
- return -1;
- }
- *target = PyUnicode_READ_CHAR(src, 0);
+ }
+ else {
+ // similar to PyArg_Parse("C?")
+ if (!PyUnicode_Check(src)) {
+ PyErr_Format(PyExc_TypeError,
+ "\"%s\" must be a unicode character or None, not %T",
+ name, src);
+ return -1;
+ }
+ Py_ssize_t len = PyUnicode_GetLength(src);
+ if (len < 0) {
+ return -1;
}
+ if (len != 1) {
+ PyErr_Format(PyExc_TypeError,
+ "\"%s\" must be a unicode character or None, "
+ "not a string of length %zd",
+ name, len);
+ return -1;
+ }
+ *target = PyUnicode_READ_CHAR(src, 0);
}
return 0;
}
@@ -287,11 +289,12 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
*target = dflt;
}
else {
+ // similar to PyArg_Parse("C")
if (!PyUnicode_Check(src)) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be string, not %.200s", name,
- Py_TYPE(src)->tp_name);
- return -1;
+ "\"%s\" must be a unicode character, not %T",
+ name, src);
+ return -1;
}
Py_ssize_t len = PyUnicode_GetLength(src);
if (len < 0) {
@@ -299,8 +302,9 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
}
if (len != 1) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be a 1-character string",
- name);
+ "\"%s\" must be a unicode character, "
+ "not a string of length %zd",
+ name, len);
return -1;
}
*target = PyUnicode_READ_CHAR(src, 0);
@@ -314,16 +318,12 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
if (src == NULL)
*target = PyUnicode_DecodeASCII(dflt, strlen(dflt), NULL);
else {
- if (src == Py_None)
- *target = NULL;
- else if (!PyUnicode_Check(src)) {
+ if (!PyUnicode_Check(src)) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be a string", name);
+ "\"%s\" must be a string, not %T", name, src);
return -1;
}
- else {
- Py_XSETREF(*target, Py_NewRef(src));
- }
+ Py_XSETREF(*target, Py_NewRef(src));
}
return 0;
}
@@ -533,11 +533,6 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
/* validate options */
if (dialect_check_quoting(self->quoting))
goto err;
- if (self->delimiter == NOT_SET) {
- PyErr_SetString(PyExc_TypeError,
- "\"delimiter\" must be a 1-character string");
- goto err;
- }
if (quotechar == Py_None && quoting == NULL)
self->quoting = QUOTE_NONE;
if (self->quoting != QUOTE_NONE && self->quotechar == NOT_SET) {
@@ -545,10 +540,6 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
"quotechar must be set if quoting enabled");
goto err;
}
- if (self->lineterminator == NULL) {
- PyErr_SetString(PyExc_TypeError, "lineterminator must be set");
- goto err;
- }
if (dialect_check_char("delimiter", self->delimiter, self, true) ||
dialect_check_char("escapechar", self->escapechar, self,
!self->skipinitialspace) ||
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 1bb65e0a649..7e8a133caa7 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -576,8 +576,15 @@ _ctypes_CType_Type___sizeof___impl(PyObject *self, PyTypeObject *cls)
return PyLong_FromSsize_t(size);
}
+/*[clinic input]
+@getter
+_ctypes.CType_Type.__pointer_type__
+
+[clinic start generated code]*/
+
static PyObject *
-ctype_get_pointer_type(PyObject *self, void *Py_UNUSED(ignored))
+_ctypes_CType_Type___pointer_type___get_impl(PyObject *self)
+/*[clinic end generated code: output=718c9ff10b2b0012 input=ad12dc835943ceb8]*/
{
ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *info;
@@ -588,9 +595,12 @@ ctype_get_pointer_type(PyObject *self, void *Py_UNUSED(ignored))
PyErr_Format(PyExc_TypeError, "%R must have storage info", self);
return NULL;
}
-
- if (info->pointer_type) {
- return Py_NewRef(info->pointer_type);
+ PyObject *pointer_type;
+ STGINFO_LOCK(info);
+ pointer_type = Py_XNewRef(info->pointer_type);
+ STGINFO_UNLOCK();
+ if (pointer_type) {
+ return pointer_type;
}
PyErr_Format(PyExc_AttributeError,
@@ -599,8 +609,15 @@ ctype_get_pointer_type(PyObject *self, void *Py_UNUSED(ignored))
return NULL;
}
+/*[clinic input]
+@setter
+_ctypes.CType_Type.__pointer_type__
+
+[clinic start generated code]*/
+
static int
-ctype_set_pointer_type(PyObject *self, PyObject *tp, void *Py_UNUSED(ignored))
+_ctypes_CType_Type___pointer_type___set_impl(PyObject *self, PyObject *value)
+/*[clinic end generated code: output=6259be8ea21693fa input=a05055fc7f4714b6]*/
{
ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *info;
@@ -611,8 +628,9 @@ ctype_set_pointer_type(PyObject *self, PyObject *tp, void *Py_UNUSED(ignored))
PyErr_Format(PyExc_TypeError, "%R must have storage info", self);
return -1;
}
-
- Py_XSETREF(info->pointer_type, Py_XNewRef(tp));
+ STGINFO_LOCK(info);
+ Py_XSETREF(info->pointer_type, Py_XNewRef(value));
+ STGINFO_UNLOCK();
return 0;
}
@@ -626,8 +644,7 @@ static PyMethodDef ctype_methods[] = {
};
static PyGetSetDef ctype_getsets[] = {
- { "__pointer_type__", ctype_get_pointer_type, ctype_set_pointer_type,
- "pointer type", NULL },
+ _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF
{ NULL, NULL }
};
@@ -1254,9 +1271,11 @@ PyCPointerType_SetProto(ctypes_state *st, PyObject *self, StgInfo *stginfo, PyOb
return -1;
}
Py_XSETREF(stginfo->proto, Py_NewRef(proto));
+ STGINFO_LOCK(info);
if (info->pointer_type == NULL) {
Py_XSETREF(info->pointer_type, Py_NewRef(self));
}
+ STGINFO_UNLOCK();
return 0;
}
@@ -3591,6 +3610,45 @@ generic_pycdata_new(ctypes_state *st,
PyCFuncPtr_Type
*/
+static inline void
+atomic_xsetref(PyObject **field, PyObject *value)
+{
+#ifdef Py_GIL_DISABLED
+ PyObject *old = *field;
+ _Py_atomic_store_ptr(field, value);
+ Py_XDECREF(old);
+#else
+ Py_XSETREF(*field, value);
+#endif
+}
+/*
+ This function atomically loads the reference from *field, and
+ tries to get a new reference to it. If the incref fails,
+ it acquires critical section of obj and returns a new reference to the *field.
+ In the general case, this avoids contention on acquiring the critical section.
+*/
+static inline PyObject *
+atomic_xgetref(PyObject *obj, PyObject **field)
+{
+#ifdef Py_GIL_DISABLED
+ PyObject *value = _Py_atomic_load_ptr(field);
+ if (value == NULL) {
+ return NULL;
+ }
+ if (_Py_TryIncrefCompare(field, value)) {
+ return value;
+ }
+ Py_BEGIN_CRITICAL_SECTION(obj);
+ value = Py_XNewRef(*field);
+ Py_END_CRITICAL_SECTION();
+ return value;
+#else
+ return Py_XNewRef(*field);
+#endif
+}
+
+
+
/*[clinic input]
@critical_section
@setter
@@ -3607,7 +3665,7 @@ _ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value)
return -1;
}
Py_XINCREF(value);
- Py_XSETREF(self->errcheck, value);
+ atomic_xsetref(&self->errcheck, value);
return 0;
}
@@ -3639,12 +3697,10 @@ static int
_ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value)
/*[clinic end generated code: output=0be0a086abbabf18 input=683c3bef4562ccc6]*/
{
- PyObject *checker, *oldchecker;
+ PyObject *checker;
if (value == NULL) {
- oldchecker = self->checker;
- self->checker = NULL;
- Py_CLEAR(self->restype);
- Py_XDECREF(oldchecker);
+ atomic_xsetref(&self->restype, NULL);
+ atomic_xsetref(&self->checker, NULL);
return 0;
}
ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
@@ -3660,11 +3716,9 @@ _ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value)
if (PyObject_GetOptionalAttr(value, &_Py_ID(_check_retval_), &checker) < 0) {
return -1;
}
- oldchecker = self->checker;
- self->checker = checker;
Py_INCREF(value);
- Py_XSETREF(self->restype, value);
- Py_XDECREF(oldchecker);
+ atomic_xsetref(&self->checker, checker);
+ atomic_xsetref(&self->restype, value);
return 0;
}
@@ -3709,16 +3763,16 @@ _ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
PyObject *converters;
if (value == NULL || value == Py_None) {
- Py_CLEAR(self->converters);
- Py_CLEAR(self->argtypes);
+ atomic_xsetref(&self->argtypes, NULL);
+ atomic_xsetref(&self->converters, NULL);
} else {
ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
converters = converters_from_argtypes(st, value);
if (!converters)
return -1;
- Py_XSETREF(self->converters, converters);
+ atomic_xsetref(&self->converters, converters);
Py_INCREF(value);
- Py_XSETREF(self->argtypes, value);
+ atomic_xsetref(&self->argtypes, value);
}
return 0;
}
@@ -4514,16 +4568,11 @@ _build_result(PyObject *result, PyObject *callargs,
}
static PyObject *
-PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
+PyCFuncPtr_call(PyObject *op, PyObject *inargs, PyObject *kwds)
{
- _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
- PyObject *restype;
- PyObject *converters;
- PyObject *checker;
- PyObject *argtypes;
- PyObject *result;
- PyObject *callargs;
- PyObject *errcheck;
+ PyObject *result = NULL;
+ PyObject *callargs = NULL;
+ PyObject *ret = NULL;
#ifdef MS_WIN32
IUnknown *piunk = NULL;
#endif
@@ -4541,13 +4590,24 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
}
assert(info); /* Cannot be NULL for PyCFuncPtrObject instances */
- restype = self->restype ? self->restype : info->restype;
- converters = self->converters ? self->converters : info->converters;
- checker = self->checker ? self->checker : info->checker;
- argtypes = self->argtypes ? self->argtypes : info->argtypes;
-/* later, we probably want to have an errcheck field in stginfo */
- errcheck = self->errcheck /* ? self->errcheck : info->errcheck */;
-
+ PyObject *restype = atomic_xgetref(op, &self->restype);
+ if (restype == NULL) {
+ restype = Py_XNewRef(info->restype);
+ }
+ PyObject *converters = atomic_xgetref(op, &self->converters);
+ if (converters == NULL) {
+ converters = Py_XNewRef(info->converters);
+ }
+ PyObject *checker = atomic_xgetref(op, &self->checker);
+ if (checker == NULL) {
+ checker = Py_XNewRef(info->checker);
+ }
+ PyObject *argtypes = atomic_xgetref(op, &self->argtypes);
+ if (argtypes == NULL) {
+ argtypes = Py_XNewRef(info->argtypes);
+ }
+ /* later, we probably want to have an errcheck field in stginfo */
+ PyObject *errcheck = atomic_xgetref(op, &self->errcheck);
pProc = *(void **)self->b_ptr;
#ifdef MS_WIN32
@@ -4558,25 +4618,25 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
if (!this) {
PyErr_SetString(PyExc_ValueError,
"native com method call without 'this' parameter");
- return NULL;
+ goto finally;
}
if (!CDataObject_Check(st, this)) {
PyErr_SetString(PyExc_TypeError,
"Expected a COM this pointer as first argument");
- return NULL;
+ goto finally;
}
/* there should be more checks? No, in Python */
/* First arg is a pointer to an interface instance */
if (!this->b_ptr || *(void **)this->b_ptr == NULL) {
PyErr_SetString(PyExc_ValueError,
"NULL COM pointer access");
- return NULL;
+ goto finally;
}
piunk = *(IUnknown **)this->b_ptr;
if (NULL == piunk->lpVtbl) {
PyErr_SetString(PyExc_ValueError,
"COM method call without VTable");
- return NULL;
+ goto finally;
}
pProc = ((void **)piunk->lpVtbl)[self->index - 0x1000];
}
@@ -4584,8 +4644,9 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
callargs = _build_callargs(st, self, argtypes,
inargs, kwds,
&outmask, &inoutmask, &numretvals);
- if (callargs == NULL)
- return NULL;
+ if (callargs == NULL) {
+ goto finally;
+ }
if (converters) {
int required = Py_SAFE_DOWNCAST(PyTuple_GET_SIZE(converters),
@@ -4604,7 +4665,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
required,
required == 1 ? "" : "s",
actual);
- return NULL;
+ goto finally;
}
} else if (required != actual) {
Py_DECREF(callargs);
@@ -4613,7 +4674,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
required,
required == 1 ? "" : "s",
actual);
- return NULL;
+ goto finally;
}
}
@@ -4644,23 +4705,19 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
if (v == NULL || v != callargs) {
Py_DECREF(result);
Py_DECREF(callargs);
- return v;
+ ret = v;
+ goto finally;
}
Py_DECREF(v);
}
-
- return _build_result(result, callargs,
- outmask, inoutmask, numretvals);
-}
-
-static PyObject *
-PyCFuncPtr_call(PyObject *op, PyObject *inargs, PyObject *kwds)
-{
- PyObject *result;
- Py_BEGIN_CRITICAL_SECTION(op);
- result = PyCFuncPtr_call_lock_held(op, inargs, kwds);
- Py_END_CRITICAL_SECTION();
- return result;
+ ret = _build_result(result, callargs, outmask, inoutmask, numretvals);
+finally:
+ Py_XDECREF(restype);
+ Py_XDECREF(converters);
+ Py_XDECREF(checker);
+ Py_XDECREF(argtypes);
+ Py_XDECREF(errcheck);
+ return ret;
}
static int
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c
index 2268072545f..66338805007 100644
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -23,8 +23,8 @@
# define _Py_thread_local __thread
#endif
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-# include "../_complex.h" // csqrt()
+#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
+# include <complex.h> // csqrt()
# undef I // for _ctypes_test_generated.c.h
#endif
#include <stdio.h> // printf()
@@ -457,7 +457,7 @@ EXPORT(double) my_sqrt(double a)
return sqrt(a);
}
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
+#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
EXPORT(double complex) my_csqrt(double complex a)
{
return csqrt(a);
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c
index ec113e41d16..fd508ae61f2 100644
--- a/Modules/_ctypes/callbacks.c
+++ b/Modules/_ctypes/callbacks.c
@@ -11,18 +11,9 @@
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_runtime.h" // _Py_ID()
-#ifdef MS_WIN32
-# include <malloc.h>
-#endif
-
#include <ffi.h>
#include "ctypes.h"
-#ifdef HAVE_ALLOCA_H
-/* AIX needs alloca.h for alloca() */
-#include <alloca.h>
-#endif
-
/**************************************************************/
static int
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index fc7265cb63e..65a0f14e2b0 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -77,22 +77,14 @@ module _ctypes
#include <mach-o/dyld.h>
#endif
-#ifdef MS_WIN32
-#include <malloc.h>
-#endif
-
#include <ffi.h>
#include "ctypes.h"
-#ifdef HAVE_ALLOCA_H
-/* AIX needs alloca.h for alloca() */
-#include <alloca.h>
-#endif
#ifdef _Py_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#endif
-#if defined(_DEBUG) || defined(__MINGW32__)
+#if defined(Py_DEBUG) || defined(__MINGW32__)
/* Don't use structured exception handling on Windows if this is defined.
MingW, AFAIK, doesn't support it.
*/
@@ -103,9 +95,6 @@ module _ctypes
#include "pycore_global_objects.h"// _Py_ID()
#include "pycore_traceback.h" // _PyTraceback_Add()
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-#include "../_complex.h" // complex
-#endif
#define clinic_state() (get_module_state(module))
#include "clinic/callproc.c.h"
#undef clinic_state
@@ -652,11 +641,9 @@ union result {
double d;
float f;
void *p;
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
- double complex D;
- float complex F;
- long double complex G;
-#endif
+ double D[2];
+ float F[2];
+ long double G[2];
};
struct argument {
@@ -1394,7 +1381,7 @@ static PyObject *format_error(PyObject *self, PyObject *args)
code = GetLastError();
lpMsgBuf = FormatError(code);
if (lpMsgBuf) {
- result = PyUnicode_FromWideChar(lpMsgBuf, wcslen(lpMsgBuf));
+ result = PyUnicode_FromWideChar(lpMsgBuf, -1);
LocalFree(lpMsgBuf);
} else {
result = PyUnicode_FromString("<no description>");
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 580ea18af2a..547e2471a1c 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -14,10 +14,6 @@
#include <ffi.h>
#include "ctypes.h"
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-# include "../_complex.h" // complex
-#endif
-
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
/*[clinic input]
@@ -763,18 +759,25 @@ d_get(void *ptr, Py_ssize_t size)
return PyFloat_FromDouble(val);
}
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
+#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
+
+/* We don't use _Complex types here, using arrays instead, as the C11+
+ standard says: "Each complex type has the same representation and alignment
+ requirements as an array type containing exactly two elements of the
+ corresponding real type; the first element is equal to the real part, and
+ the second element to the imaginary part, of the complex number." */
+
/* D: double complex */
static PyObject *
D_set(void *ptr, PyObject *value, Py_ssize_t size)
{
- assert(NUM_BITS(size) || (size == sizeof(double complex)));
+ assert(NUM_BITS(size) || (size == 2*sizeof(double)));
Py_complex c = PyComplex_AsCComplex(value);
if (c.real == -1 && PyErr_Occurred()) {
return NULL;
}
- double complex x = CMPLX(c.real, c.imag);
+ double x[2] = {c.real, c.imag};
memcpy(ptr, &x, sizeof(x));
_RET(value);
}
@@ -782,24 +785,24 @@ D_set(void *ptr, PyObject *value, Py_ssize_t size)
static PyObject *
D_get(void *ptr, Py_ssize_t size)
{
- assert(NUM_BITS(size) || (size == sizeof(double complex)));
- double complex x;
+ assert(NUM_BITS(size) || (size == 2*sizeof(double)));
+ double x[2];
memcpy(&x, ptr, sizeof(x));
- return PyComplex_FromDoubles(creal(x), cimag(x));
+ return PyComplex_FromDoubles(x[0], x[1]);
}
/* F: float complex */
static PyObject *
F_set(void *ptr, PyObject *value, Py_ssize_t size)
{
- assert(NUM_BITS(size) || (size == sizeof(float complex)));
+ assert(NUM_BITS(size) || (size == 2*sizeof(float)));
Py_complex c = PyComplex_AsCComplex(value);
if (c.real == -1 && PyErr_Occurred()) {
return NULL;
}
- float complex x = CMPLXF((float)c.real, (float)c.imag);
+ float x[2] = {(float)c.real, (float)c.imag};
memcpy(ptr, &x, sizeof(x));
_RET(value);
}
@@ -807,24 +810,24 @@ F_set(void *ptr, PyObject *value, Py_ssize_t size)
static PyObject *
F_get(void *ptr, Py_ssize_t size)
{
- assert(NUM_BITS(size) || (size == sizeof(float complex)));
- float complex x;
+ assert(NUM_BITS(size) || (size == 2*sizeof(float)));
+ float x[2];
memcpy(&x, ptr, sizeof(x));
- return PyComplex_FromDoubles(crealf(x), cimagf(x));
+ return PyComplex_FromDoubles(x[0], x[1]);
}
/* G: long double complex */
static PyObject *
G_set(void *ptr, PyObject *value, Py_ssize_t size)
{
- assert(NUM_BITS(size) || (size == sizeof(long double complex)));
+ assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
Py_complex c = PyComplex_AsCComplex(value);
if (c.real == -1 && PyErr_Occurred()) {
return NULL;
}
- long double complex x = CMPLXL(c.real, c.imag);
+ long double x[2] = {c.real, c.imag};
memcpy(ptr, &x, sizeof(x));
_RET(value);
}
@@ -832,11 +835,11 @@ G_set(void *ptr, PyObject *value, Py_ssize_t size)
static PyObject *
G_get(void *ptr, Py_ssize_t size)
{
- assert(NUM_BITS(size) || (size == sizeof(long double complex)));
- long double complex x;
+ assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
+ long double x[2];
memcpy(&x, ptr, sizeof(x));
- return PyComplex_FromDoubles((double)creall(x), (double)cimagl(x));
+ return PyComplex_FromDoubles((double)x[0], (double)x[1]);
}
#endif
@@ -1250,7 +1253,7 @@ Z_get(void *ptr, Py_ssize_t size)
wchar_t *p;
p = *(wchar_t **)ptr;
if (p) {
- return PyUnicode_FromWideChar(p, wcslen(p));
+ return PyUnicode_FromWideChar(p, -1);
} else {
Py_RETURN_NONE;
}
@@ -1596,7 +1599,7 @@ for base_code, base_c_type in [
///////////////////////////////////////////////////////////////////////////
TABLE_ENTRY_SW(d, &ffi_type_double);
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
+#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
if (Py_FFI_COMPLEX_AVAILABLE) {
TABLE_ENTRY(D, &ffi_type_complex_double);
TABLE_ENTRY(F, &ffi_type_complex_float);
diff --git a/Modules/_ctypes/clinic/_ctypes.c.h b/Modules/_ctypes/clinic/_ctypes.c.h
index 92dfb8f83b7..cf2e3fa2107 100644
--- a/Modules/_ctypes/clinic/_ctypes.c.h
+++ b/Modules/_ctypes/clinic/_ctypes.c.h
@@ -31,6 +31,48 @@ _ctypes_CType_Type___sizeof__(PyObject *self, PyTypeObject *cls, PyObject *const
return _ctypes_CType_Type___sizeof___impl(self, cls);
}
+#if !defined(_ctypes_CType_Type___pointer_type___DOCSTR)
+# define _ctypes_CType_Type___pointer_type___DOCSTR NULL
+#endif
+#if defined(_CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF)
+# undef _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF
+# define _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF {"__pointer_type__", (getter)_ctypes_CType_Type___pointer_type___get, (setter)_ctypes_CType_Type___pointer_type___set, _ctypes_CType_Type___pointer_type___DOCSTR},
+#else
+# define _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF {"__pointer_type__", (getter)_ctypes_CType_Type___pointer_type___get, NULL, _ctypes_CType_Type___pointer_type___DOCSTR},
+#endif
+
+static PyObject *
+_ctypes_CType_Type___pointer_type___get_impl(PyObject *self);
+
+static PyObject *
+_ctypes_CType_Type___pointer_type___get(PyObject *self, void *Py_UNUSED(context))
+{
+ return _ctypes_CType_Type___pointer_type___get_impl(self);
+}
+
+#if !defined(_ctypes_CType_Type___pointer_type___DOCSTR)
+# define _ctypes_CType_Type___pointer_type___DOCSTR NULL
+#endif
+#if defined(_CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF)
+# undef _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF
+# define _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF {"__pointer_type__", (getter)_ctypes_CType_Type___pointer_type___get, (setter)_ctypes_CType_Type___pointer_type___set, _ctypes_CType_Type___pointer_type___DOCSTR},
+#else
+# define _CTYPES_CTYPE_TYPE___POINTER_TYPE___GETSETDEF {"__pointer_type__", NULL, (setter)_ctypes_CType_Type___pointer_type___set, NULL},
+#endif
+
+static int
+_ctypes_CType_Type___pointer_type___set_impl(PyObject *self, PyObject *value);
+
+static int
+_ctypes_CType_Type___pointer_type___set(PyObject *self, PyObject *value, void *Py_UNUSED(context))
+{
+ int return_value;
+
+ return_value = _ctypes_CType_Type___pointer_type___set_impl(self, value);
+
+ return return_value;
+}
+
PyDoc_STRVAR(CDataType_from_address__doc__,
"from_address($self, value, /)\n"
"--\n"
@@ -1000,4 +1042,4 @@ Simple_from_outparm(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py
}
return Simple_from_outparm_impl(self, cls);
}
-/*[clinic end generated code: output=9fb75bf7e9a17df2 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=536c9bcf4e05913e input=a9049054013a1b77]*/
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 9aceeceb88a..5b4f97d43b8 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -1,5 +1,17 @@
-#if defined (__SVR4) && defined (__sun)
+/* Get a definition of alloca(). */
+#if (defined (__SVR4) && defined (__sun)) || defined(HAVE_ALLOCA_H)
# include <alloca.h>
+#elif defined(MS_WIN32)
+# include <malloc.h>
+#endif
+
+/* If the system does not define alloca(), we have to hope for a compiler builtin. */
+#ifndef alloca
+# if defined __GNUC__ || (__clang_major__ >= 4)
+# define alloca __builtin_alloca
+# else
+# error "Could not define alloca() on your platform."
+# endif
#endif
#include <stdbool.h>
@@ -11,8 +23,7 @@
// Do we support C99 complex types in ffi?
// For Apple's libffi, this must be determined at runtime (see gh-128156).
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-# include "../_complex.h" // complex
+#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
# if USING_APPLE_OS_LIBFFI && defined(__has_builtin)
# if __has_builtin(__builtin_available)
# define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *)
@@ -494,11 +505,9 @@ struct tagPyCArgObject {
double d;
float f;
void *p;
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
- double complex D;
- float complex F;
- long double complex G;
-#endif
+ double D[2];
+ float F[2];
+ long double G[2];
} value;
PyObject *obj;
Py_ssize_t size; /* for the 'V' tag */
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c
index eecf7a1c8a1..d7acfc6a06a 100644
--- a/Modules/_curses_panel.c
+++ b/Modules/_curses_panel.c
@@ -17,6 +17,7 @@ static const char PyCursesVersion[] = "2.1";
#include "Python.h"
+#define CURSES_PANEL_MODULE
#include "py_curses.h"
#if defined(HAVE_NCURSESW_PANEL_H)
@@ -28,10 +29,12 @@ static const char PyCursesVersion[] = "2.1";
#endif
typedef struct {
- PyObject *PyCursesError;
+ PyObject *error;
PyTypeObject *PyCursesPanel_Type;
} _curses_panel_state;
+typedef struct PyCursesPanelObject PyCursesPanelObject;
+
static inline _curses_panel_state *
get_curses_panel_state(PyObject *module)
{
@@ -40,11 +43,30 @@ get_curses_panel_state(PyObject *module)
return (_curses_panel_state *)state;
}
+static inline _curses_panel_state *
+get_curses_panel_state_by_panel(PyCursesPanelObject *panel)
+{
+ /*
+ * Note: 'state' may be NULL if Py_TYPE(panel) is not a heap
+ * type associated with this module, but the compiler would
+ * have likely already complained with an "invalid pointer
+ * type" at compile-time.
+ *
+ * To make it more robust, all functions recovering a module's
+ * state from an object should expect to return NULL with an
+ * exception set (in contrast to functions recovering a module's
+ * state from a module itself).
+ */
+ void *state = PyType_GetModuleState(Py_TYPE(panel));
+ assert(state != NULL);
+ return (_curses_panel_state *)state;
+}
+
static int
_curses_panel_clear(PyObject *mod)
{
_curses_panel_state *state = get_curses_panel_state(mod);
- Py_CLEAR(state->PyCursesError);
+ Py_CLEAR(state->error);
Py_CLEAR(state->PyCursesPanel_Type);
return 0;
}
@@ -54,7 +76,7 @@ _curses_panel_traverse(PyObject *mod, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(mod));
_curses_panel_state *state = get_curses_panel_state(mod);
- Py_VISIT(state->PyCursesError);
+ Py_VISIT(state->error);
Py_VISIT(state->PyCursesPanel_Type);
return 0;
}
@@ -65,28 +87,149 @@ _curses_panel_free(void *mod)
(void)_curses_panel_clear((PyObject *)mod);
}
+/* Utility Error Procedures
+ *
+ * The naming and implementations are identical to those in _cursesmodule.c.
+ * Functions that are not yet needed (for instance, reporting an ERR value
+ * from a module-wide function, namely curses_panel_set_error()) are
+ * omitted and should only be added if needed.
+ */
+
+static void
+_curses_panel_format_error(_curses_panel_state *state,
+ const char *curses_funcname,
+ const char *python_funcname,
+ const char *return_value,
+ const char *default_message)
+{
+ assert(!PyErr_Occurred());
+ if (python_funcname == NULL && curses_funcname == NULL) {
+ PyErr_SetString(state->error, default_message);
+ }
+ else if (python_funcname == NULL) {
+ (void)PyErr_Format(state->error, CURSES_ERROR_FORMAT,
+ curses_funcname, return_value);
+ }
+ else {
+ assert(python_funcname != NULL);
+ (void)PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT,
+ curses_funcname, python_funcname, return_value);
+ }
+}
+
+/*
+ * Format a curses error for a function that returned ERR.
+ *
+ * Specify a non-NULL 'python_funcname' when the latter differs from
+ * 'curses_funcname'. If both names are NULL, uses the 'catchall_ERR'
+ * message instead.
+ */
+static void
+_curses_panel_set_error(_curses_panel_state *state,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_panel_format_error(state, curses_funcname, python_funcname,
+ "ERR", catchall_ERR);
+}
+
+/*
+ * Format a curses error for a function that returned NULL.
+ *
+ * Specify a non-NULL 'python_funcname' when the latter differs from
+ * 'curses_funcname'. If both names are NULL, uses the 'catchall_NULL'
+ * message instead.
+ */
+static void
+_curses_panel_set_null_error(_curses_panel_state *state,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_panel_format_error(state, curses_funcname, python_funcname,
+ "NULL", catchall_NULL);
+}
+
+/* Same as _curses_panel_set_null_error() for a module object. */
+static void
+curses_panel_set_null_error(PyObject *module,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_panel_state *state = get_curses_panel_state(module);
+ _curses_panel_set_null_error(state, curses_funcname, python_funcname);
+}
+
+/* Same as _curses_panel_set_error() for a panel object. */
+static void
+curses_panel_panel_set_error(PyCursesPanelObject *panel,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_panel_state *state = get_curses_panel_state_by_panel(panel);
+ _curses_panel_set_error(state, curses_funcname, python_funcname);
+}
+
+/* Same as _curses_panel_set_null_error() for a panel object. */
+static void
+curses_panel_panel_set_null_error(PyCursesPanelObject *panel,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_panel_state *state = get_curses_panel_state_by_panel(panel);
+ _curses_panel_set_null_error(state, curses_funcname, python_funcname);
+}
+
+/*
+ * Indicate that a panel object couldn't be found.
+ *
+ * Use it for the following constructions:
+ *
+ * PROC caller_funcname:
+ * pan = called_funcname()
+ * find_po(panel)
+ *
+ * PROC caller_funcname:
+ * find_po(self->pan)
+*/
+static void
+curses_panel_notfound_error(const char *called_funcname,
+ const char *caller_funcname)
+{
+ assert(!(called_funcname == NULL && caller_funcname == NULL));
+ if (caller_funcname == NULL) {
+ (void)PyErr_Format(PyExc_RuntimeError,
+ "%s(): cannot find panel object",
+ called_funcname);
+ }
+ else {
+ (void)PyErr_Format(PyExc_RuntimeError,
+ "%s() (called by %s()): cannot find panel object",
+ called_funcname, caller_funcname);
+ }
+}
+
/* Utility Functions */
/*
- * Check the return code from a curses function and return None
- * or raise an exception as appropriate.
+ * Check the return code from a curses function, returning None
+ * on success and setting an exception on error.
*/
+/*
+ * Return None if 'code' is different from ERR (implementation-defined).
+ * Otherwise, set an exception using curses_panel_panel_set_error() and
+ * the remaining arguments, and return NULL.
+ */
static PyObject *
-PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname)
+curses_panel_panel_check_err(PyCursesPanelObject *panel, int code,
+ const char *curses_funcname,
+ const char *python_funcname)
{
if (code != ERR) {
Py_RETURN_NONE;
}
- else {
- if (fname == NULL) {
- PyErr_SetString(state->PyCursesError, catchall_ERR);
- }
- else {
- PyErr_Format(state->PyCursesError, "%s() returned ERR", fname);
- }
- return NULL;
- }
+ curses_panel_panel_set_error(panel, curses_funcname, python_funcname);
+ return NULL;
}
/*****************************************************************************
@@ -95,7 +238,7 @@ PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname)
/* Definition of the panel object and panel type */
-typedef struct {
+typedef struct PyCursesPanelObject {
PyObject_HEAD
PANEL *pan;
PyCursesWindowObject *wo; /* for reference counts */
@@ -144,8 +287,11 @@ insert_lop(PyCursesPanelObject *po)
return 0;
}
-/* Remove the panel object from lop */
-static void
+/* Remove the panel object from lop.
+ *
+ * Return -1 on error but do NOT set an exception; otherwise return 0.
+ */
+static int
remove_lop(PyCursesPanelObject *po)
{
list_of_panels *temp, *n;
@@ -154,25 +300,23 @@ remove_lop(PyCursesPanelObject *po)
if (temp->po == po) {
lop = temp->next;
PyMem_Free(temp);
- return;
+ return 0;
}
while (temp->next == NULL || temp->next->po != po) {
if (temp->next == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "remove_lop: can't find Panel Object");
- return;
+ return -1;
}
temp = temp->next;
}
n = temp->next->next;
PyMem_Free(temp->next);
temp->next = n;
- return;
+ return 0;
}
/* Return the panel object that corresponds to pan */
static PyCursesPanelObject *
-find_po(PANEL *pan)
+find_po_impl(PANEL *pan)
{
list_of_panels *temp;
for (temp = lop; temp->po->pan != pan; temp = temp->next)
@@ -180,6 +324,17 @@ find_po(PANEL *pan)
return temp->po;
}
+/* Same as find_po_impl() but with caller context information. */
+static PyCursesPanelObject *
+find_po(PANEL *pan, const char *called_funcname, const char *caller_funcname)
+{
+ PyCursesPanelObject *res = find_po_impl(pan);
+ if (res == NULL) {
+ curses_panel_notfound_error(called_funcname, caller_funcname);
+ }
+ return res;
+}
+
/*[clinic input]
module _curses_panel
class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
@@ -193,67 +348,59 @@ class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
/*[clinic input]
_curses_panel.panel.bottom
- cls: defining_class
-
Push the panel to the bottom of the stack.
[clinic start generated code]*/
static PyObject *
-_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=8ec7fbbc08554021 input=6b7d2c0578b5a1c4]*/
+_curses_panel_panel_bottom_impl(PyCursesPanelObject *self)
+/*[clinic end generated code: output=7aa7d14d7e1d1ce6 input=b6c920c071b61e2e]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
- return PyCursesCheckERR(state, bottom_panel(self->pan), "bottom");
+ int rtn = bottom_panel(self->pan);
+ return curses_panel_panel_check_err(self, rtn, "bottom_panel", "bottom");
}
/*[clinic input]
_curses_panel.panel.hide
- cls: defining_class
-
Hide the panel.
This does not delete the object, it just makes the window on screen invisible.
[clinic start generated code]*/
static PyObject *
-_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=cc6ab7203cdc1450 input=1bfc741f473e6055]*/
+_curses_panel_panel_hide_impl(PyCursesPanelObject *self)
+/*[clinic end generated code: output=a7bbbd523e1eab49 input=f6ab884e99386118]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
- return PyCursesCheckERR(state, hide_panel(self->pan), "hide");
+ int rtn = hide_panel(self->pan);
+ return curses_panel_panel_check_err(self, rtn, "hide_panel", "hide");
}
/*[clinic input]
_curses_panel.panel.show
- cls: defining_class
-
Display the panel (which might have been hidden).
[clinic start generated code]*/
static PyObject *
-_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=dc3421de375f0409 input=8122e80151cb4379]*/
+_curses_panel_panel_show_impl(PyCursesPanelObject *self)
+/*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
- return PyCursesCheckERR(state, show_panel(self->pan), "show");
+ int rtn = show_panel(self->pan);
+ return curses_panel_panel_check_err(self, rtn, "show_panel", "show");
}
/*[clinic input]
_curses_panel.panel.top
- cls: defining_class
-
Push panel to the top of the stack.
[clinic start generated code]*/
static PyObject *
-_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=10a072e511e873f7 input=1f372d597dda3379]*/
+_curses_panel_panel_top_impl(PyCursesPanelObject *self)
+/*[clinic end generated code: output=0f5f2f8cdd2d1777 input=be33975ec3ca0e9a]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
- return PyCursesCheckERR(state, top_panel(self->pan), "top");
+ int rtn = top_panel(self->pan);
+ return curses_panel_panel_check_err(self, rtn, "top_panel", "top");
}
/* Allocation and deallocation of Panel Objects */
@@ -287,13 +434,22 @@ PyCursesPanel_Dealloc(PyObject *self)
tp = (PyObject *) Py_TYPE(po);
obj = (PyObject *) panel_userptr(po->pan);
if (obj) {
- (void)set_panel_userptr(po->pan, NULL);
Py_DECREF(obj);
+ if (set_panel_userptr(po->pan, NULL) == ERR) {
+ curses_panel_panel_set_error(po, "set_panel_userptr", "__del__");
+ PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()");
+ }
+ }
+ if (del_panel(po->pan) == ERR && !PyErr_Occurred()) {
+ curses_panel_panel_set_error(po, "del_panel", "__del__");
+ PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()");
}
- (void)del_panel(po->pan);
if (po->wo != NULL) {
Py_DECREF(po->wo);
- remove_lop(po);
+ if (remove_lop(po) < 0) {
+ PyErr_SetString(PyExc_RuntimeError, "__del__: no panel object to delete");
+ PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()");
+ }
}
PyObject_Free(po);
Py_DECREF(tp);
@@ -315,18 +471,11 @@ _curses_panel_panel_above_impl(PyCursesPanelObject *self)
PyCursesPanelObject *po;
pan = panel_above(self->pan);
-
- if (pan == NULL) { /* valid output, it means the calling panel
- is on top of the stack */
+ if (pan == NULL) { /* valid output: it means no panel exists yet */
Py_RETURN_NONE;
}
- po = find_po(pan);
- if (po == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "panel_above: can't find Panel Object");
- return NULL;
- }
- return Py_NewRef(po);
+ po = find_po(pan, "panel_above", "above");
+ return Py_XNewRef(po);
}
/* panel_below(NULL) returns the top panel in the stack. To get
@@ -345,18 +494,11 @@ _curses_panel_panel_below_impl(PyCursesPanelObject *self)
PyCursesPanelObject *po;
pan = panel_below(self->pan);
-
- if (pan == NULL) { /* valid output, it means the calling panel
- is on the bottom of the stack */
+ if (pan == NULL) { /* valid output: it means no panel exists yet */
Py_RETURN_NONE;
}
- po = find_po(pan);
- if (po == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "panel_below: can't find Panel Object");
- return NULL;
- }
- return Py_NewRef(po);
+ po = find_po(pan, "panel_below", "below");
+ return Py_XNewRef(po);
}
/*[clinic input]
@@ -378,7 +520,6 @@ _curses_panel_panel_hidden_impl(PyCursesPanelObject *self)
/*[clinic input]
_curses_panel.panel.move
- cls: defining_class
y: int
x: int
/
@@ -387,12 +528,11 @@ Move the panel to the screen coordinates (y, x).
[clinic start generated code]*/
static PyObject *
-_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls,
- int y, int x)
-/*[clinic end generated code: output=ce546c93e56867da input=60a0e7912ff99849]*/
+_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x)
+/*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
- return PyCursesCheckERR(state, move_panel(self->pan, y, x), "move_panel");
+ int rtn = move_panel(self->pan, y, x);
+ return curses_panel_panel_check_err(self, rtn, "move_panel", "move");
}
/*[clinic input]
@@ -411,7 +551,6 @@ _curses_panel_panel_window_impl(PyCursesPanelObject *self)
/*[clinic input]
_curses_panel.panel.replace
- cls: defining_class
win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
/
@@ -420,22 +559,17 @@ Change the window associated with the panel to the window win.
static PyObject *
_curses_panel_panel_replace_impl(PyCursesPanelObject *self,
- PyTypeObject *cls,
PyCursesWindowObject *win)
-/*[clinic end generated code: output=c71f95c212d58ae7 input=dbec7180ece41ff5]*/
+/*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
-
- PyCursesPanelObject *po = find_po(self->pan);
+ PyCursesPanelObject *po = find_po(self->pan, "replace", NULL);
if (po == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "replace_panel: can't find Panel Object");
return NULL;
}
int rtn = replace_panel(self->pan, win->win);
if (rtn == ERR) {
- PyErr_SetString(state->PyCursesError, "replace_panel() returned ERR");
+ curses_panel_panel_set_error(self, "replace_panel", "replace");
return NULL;
}
Py_SETREF(po->wo, (PyCursesWindowObject*)Py_NewRef(win));
@@ -445,7 +579,6 @@ _curses_panel_panel_replace_impl(PyCursesPanelObject *self,
/*[clinic input]
_curses_panel.panel.set_userptr
- cls: defining_class
obj: object
/
@@ -454,8 +587,8 @@ Set the panel's user pointer to obj.
static PyObject *
_curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
- PyTypeObject *cls, PyObject *obj)
-/*[clinic end generated code: output=db74f3db07b28080 input=e3fee2ff7b1b8e48]*/
+ PyObject *obj)
+/*[clinic end generated code: output=7fa1fd23f69db71e input=d2c6a9dbefabbf39]*/
{
PyCursesInitialised;
Py_INCREF(obj);
@@ -464,34 +597,27 @@ _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
if (rc == ERR) {
/* In case of an ncurses error, decref the new object again */
Py_DECREF(obj);
+ curses_panel_panel_set_error(self, "set_panel_userptr", "set_userptr");
+ return NULL;
}
- else {
- Py_XDECREF(oldobj);
- }
-
- _curses_panel_state *state = PyType_GetModuleState(cls);
- return PyCursesCheckERR(state, rc, "set_panel_userptr");
+ Py_XDECREF(oldobj);
+ Py_RETURN_NONE;
}
/*[clinic input]
_curses_panel.panel.userptr
- cls: defining_class
-
Return the user pointer for the panel.
[clinic start generated code]*/
static PyObject *
-_curses_panel_panel_userptr_impl(PyCursesPanelObject *self,
- PyTypeObject *cls)
-/*[clinic end generated code: output=eea6e6f39ffc0179 input=f22ca4f115e30a80]*/
+_curses_panel_panel_userptr_impl(PyCursesPanelObject *self)
+/*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/
{
- _curses_panel_state *state = PyType_GetModuleState(cls);
-
PyCursesInitialised;
PyObject *obj = (PyObject *) panel_userptr(self->pan);
if (obj == NULL) {
- PyErr_SetString(state->PyCursesError, "no userptr set");
+ curses_panel_panel_set_null_error(self, "panel_userptr", "userptr");
return NULL;
}
@@ -552,18 +678,11 @@ _curses_panel_bottom_panel_impl(PyObject *module)
PyCursesInitialised;
pan = panel_above(NULL);
-
- if (pan == NULL) { /* valid output, it means
- there's no panel at all */
+ if (pan == NULL) { /* valid output: it means no panel exists yet */
Py_RETURN_NONE;
}
- po = find_po(pan);
- if (po == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "panel_above: can't find Panel Object");
- return NULL;
- }
- return Py_NewRef(po);
+ po = find_po(pan, "panel_above", "bottom_panel");
+ return Py_XNewRef(po);
}
/*[clinic input]
@@ -579,14 +698,13 @@ static PyObject *
_curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win)
/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/
{
- _curses_panel_state *state = get_curses_panel_state(module);
-
PANEL *pan = new_panel(win->win);
if (pan == NULL) {
- PyErr_SetString(state->PyCursesError, catchall_NULL);
+ curses_panel_set_null_error(module, "new_panel", NULL);
return NULL;
}
- return (PyObject *)PyCursesPanel_New(state, pan, win);
+ _curses_panel_state *state = get_curses_panel_state(module);
+ return PyCursesPanel_New(state, pan, win);
}
@@ -610,18 +728,11 @@ _curses_panel_top_panel_impl(PyObject *module)
PyCursesInitialised;
pan = panel_below(NULL);
-
- if (pan == NULL) { /* valid output, it means
- there's no panel at all */
+ if (pan == NULL) { /* valid output: it means no panel exists yet */
Py_RETURN_NONE;
}
- po = find_po(pan);
- if (po == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "panel_below: can't find Panel Object");
- return NULL;
- }
- return Py_NewRef(po);
+ po = find_po(pan, "panel_below", "top_panel");
+ return Py_XNewRef(po);
}
/*[clinic input]
@@ -673,10 +784,10 @@ _curses_panel_exec(PyObject *mod)
}
/* For exception _curses_panel.error */
- state->PyCursesError = PyErr_NewException(
+ state->error = PyErr_NewException(
"_curses_panel.error", NULL, NULL);
- if (PyModule_AddObjectRef(mod, "error", state->PyCursesError) < 0) {
+ if (PyModule_AddObjectRef(mod, "error", state->error) < 0) {
return -1;
}
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index bf18cb51605..d7788ef7a58 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -108,7 +108,6 @@ static const char PyCursesVersion[] = "2.2";
#include "pycore_capsule.h" // _PyCapsule_SetTraverse()
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_structseq.h" // _PyStructSequence_NewType()
-#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString()
#include "pycore_fileutils.h" // _Py_set_inheritable
#ifdef __hpux
@@ -211,18 +210,116 @@ static int curses_start_color_called = FALSE;
static const char *curses_screen_encoding = NULL;
+/* Utility Error Procedures */
+
+static void
+_curses_format_error(cursesmodule_state *state,
+ const char *curses_funcname,
+ const char *python_funcname,
+ const char *return_value,
+ const char *default_message)
+{
+ assert(!PyErr_Occurred());
+ if (python_funcname == NULL && curses_funcname == NULL) {
+ PyErr_SetString(state->error, default_message);
+ }
+ else if (python_funcname == NULL) {
+ (void)PyErr_Format(state->error, CURSES_ERROR_FORMAT,
+ curses_funcname, return_value);
+ }
+ else {
+ assert(python_funcname != NULL);
+ (void)PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT,
+ curses_funcname, python_funcname, return_value);
+ }
+}
+
+/*
+ * Format a curses error for a function that returned ERR.
+ *
+ * Specify a non-NULL 'python_funcname' when the latter differs from
+ * 'curses_funcname'. If both names are NULL, uses the 'catchall_ERR'
+ * message instead.
+ */
+static void
+_curses_set_error(cursesmodule_state *state,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_format_error(state, curses_funcname, python_funcname,
+ "ERR", catchall_ERR);
+}
+
+/*
+ * Format a curses error for a function that returned NULL.
+ *
+ * Specify a non-NULL 'python_funcname' when the latter differs from
+ * 'curses_funcname'. If both names are NULL, uses the 'catchall_NULL'
+ * message instead.
+ */
+static inline void
+_curses_set_null_error(cursesmodule_state *state,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ _curses_format_error(state, curses_funcname, python_funcname,
+ "NULL", catchall_NULL);
+}
+
+/* Same as _curses_set_error() for a module object. */
+static void
+curses_set_error(PyObject *module,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ cursesmodule_state *state = get_cursesmodule_state(module);
+ _curses_set_error(state, curses_funcname, python_funcname);
+}
+
+/* Same as _curses_set_null_error() for a module object. */
+static void
+curses_set_null_error(PyObject *module,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ cursesmodule_state *state = get_cursesmodule_state(module);
+ _curses_set_null_error(state, curses_funcname, python_funcname);
+}
+
+/* Same as _curses_set_error() for a Window object. */
+static void
+curses_window_set_error(PyCursesWindowObject *win,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ cursesmodule_state *state = get_cursesmodule_state_by_win(win);
+ _curses_set_error(state, curses_funcname, python_funcname);
+}
+
+/* Same as _curses_set_null_error() for a Window object. */
+static void
+curses_window_set_null_error(PyCursesWindowObject *win,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ cursesmodule_state *state = get_cursesmodule_state_by_win(win);
+ _curses_set_null_error(state, curses_funcname, python_funcname);
+}
+
/* Utility Checking Procedures */
/*
* Function to check that 'funcname' has been called by testing
- * the 'called' boolean. If an error occurs, a PyCursesError is
+ * the 'called' boolean. If an error occurs, an exception is
* set and this returns 0. Otherwise, this returns 1.
*
* Since this function can be called in functions that do not
* have a direct access to the module's state, '_curses.error'
* is imported on demand.
+ *
+ * Use _PyCursesStatefulCheckFunction() if the module is given.
*/
-static inline int
+static int
_PyCursesCheckFunction(int called, const char *funcname)
{
if (called == TRUE) {
@@ -230,7 +327,7 @@ _PyCursesCheckFunction(int called, const char *funcname)
}
PyObject *exc = PyImport_ImportModuleAttrString("_curses", "error");
if (exc != NULL) {
- PyErr_Format(exc, "must call %s() first", funcname);
+ PyErr_Format(exc, CURSES_ERROR_MUST_CALL_FORMAT, funcname);
Py_DECREF(exc);
}
assert(PyErr_Occurred());
@@ -244,14 +341,15 @@ _PyCursesCheckFunction(int called, const char *funcname)
*
* The exception type is obtained from the 'module' state.
*/
-static inline int
-_PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcname)
+static int
+_PyCursesStatefulCheckFunction(PyObject *module,
+ int called, const char *funcname)
{
if (called == TRUE) {
return 1;
}
cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_Format(state->error, "must call %s() first", funcname);
+ PyErr_Format(state->error, CURSES_ERROR_MUST_CALL_FORMAT, funcname);
return 0;
}
@@ -287,44 +385,39 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam
/* Utility Functions */
-static inline void
-_PyCursesSetError(cursesmodule_state *state, const char *funcname)
-{
- if (funcname == NULL) {
- PyErr_SetString(state->error, catchall_ERR);
- }
- else {
- PyErr_Format(state->error, "%s() returned ERR", funcname);
- }
-}
-
/*
- * Check the return code from a curses function and return None
- * or raise an exception as appropriate.
+ * Check the return code from a curses function, returning None
+ * on success and setting an exception on error.
*/
+/*
+ * Return None if 'code' is different from ERR (implementation-defined).
+ * Otherwise, set an exception using curses_set_error() and the remaining
+ * arguments, and return NULL.
+ */
static PyObject *
-PyCursesCheckERR(PyObject *module, int code, const char *fname)
+curses_check_err(PyObject *module, int code,
+ const char *curses_funcname,
+ const char *python_funcname)
{
if (code != ERR) {
Py_RETURN_NONE;
- } else {
- cursesmodule_state *state = get_cursesmodule_state(module);
- _PyCursesSetError(state, fname);
- return NULL;
}
+ curses_set_error(module, curses_funcname, python_funcname);
+ return NULL;
}
+/* Same as curses_check_err() for a Window object. */
static PyObject *
-PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, const char *fname)
+curses_window_check_err(PyCursesWindowObject *win, int code,
+ const char *curses_funcname,
+ const char *python_funcname)
{
if (code != ERR) {
Py_RETURN_NONE;
- } else {
- cursesmodule_state *state = get_cursesmodule_state_by_win(win);
- _PyCursesSetError(state, fname);
- return NULL;
}
+ curses_window_set_error(win, curses_funcname, python_funcname);
+ return NULL;
}
/* Convert an object to a byte (an integer of type chtype):
@@ -650,13 +743,16 @@ class component_converter(CConverter):
The Window Object
******************************************************************************/
-/* Function prototype macros for Window object
-
- X - function name
- TYPE - parameter Type
- ERGSTR - format string for construction of the return value
- PARSESTR - format string for argument parsing
-*/
+/*
+ * Macros for creating a PyCursesWindowObject object's method.
+ *
+ * Parameters
+ *
+ * X The name of the curses C function or macro to invoke.
+ * TYPE The function parameter(s) type.
+ * ERGSTR The format string for construction of the return value.
+ * PARSESTR The format string for argument parsing.
+ */
#define Window_NoArgNoReturnFunction(X) \
static PyObject *PyCursesWindow_ ## X \
@@ -664,7 +760,7 @@ class component_converter(CConverter):
{ \
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \
int code = X(self->win); \
- return PyCursesCheckERR_ForWin(self, code, # X); \
+ return curses_window_check_err(self, code, # X, NULL); \
}
#define Window_NoArgTrueFalseFunction(X) \
@@ -717,7 +813,7 @@ class component_converter(CConverter):
} \
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \
int code = X(self->win, arg1); \
- return PyCursesCheckERR_ForWin(self, code, # X); \
+ return curses_window_check_err(self, code, # X, NULL); \
}
#define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \
@@ -730,7 +826,7 @@ class component_converter(CConverter):
} \
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \
int code = X(self->win, arg1, arg2); \
- return PyCursesCheckERR_ForWin(self, code, # X); \
+ return curses_window_check_err(self, code, # X, NULL); \
}
/* ------------- WINDOW routines --------------- */
@@ -787,7 +883,8 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
static PyObject *
PyCursesWindow_New(cursesmodule_state *state,
- WINDOW *win, const char *encoding)
+ WINDOW *win, const char *encoding,
+ PyCursesWindowObject *orig)
{
if (encoding == NULL) {
#if defined(MS_WINDOWS)
@@ -821,6 +918,8 @@ PyCursesWindow_New(cursesmodule_state *state,
PyErr_NoMemory();
return NULL;
}
+ wo->orig = orig;
+ Py_XINCREF(orig);
PyObject_GC_Track((PyObject *)wo);
return (PyObject *)wo;
}
@@ -832,12 +931,15 @@ PyCursesWindow_dealloc(PyObject *self)
PyObject_GC_UnTrack(self);
PyCursesWindowObject *wo = (PyCursesWindowObject *)self;
if (wo->win != stdscr && wo->win != NULL) {
- // silently ignore errors in delwin(3)
- (void)delwin(wo->win);
+ if (delwin(wo->win) == ERR) {
+ curses_window_set_error(wo, "delwin", "__del__");
+ PyErr_FormatUnraisable("Exception ignored in delwin()");
+ }
}
if (wo->encoding != NULL) {
PyMem_Free(wo->encoding);
}
+ Py_XDECREF(wo->orig);
window_type->tp_free(self);
Py_DECREF(window_type);
}
@@ -846,6 +948,8 @@ static int
PyCursesWindow_traverse(PyObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
+ PyCursesWindowObject *wo = (PyCursesWindowObject *)self;
+ Py_VISIT(wo->orig);
return 0;
}
@@ -897,13 +1001,19 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1,
#ifdef HAVE_NCURSESW
type = PyCurses_ConvertToCchar_t(self, ch, &cch, wstr);
if (type == 2) {
- funcname = "add_wch";
wstr[1] = L'\0';
- setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL);
- if (coordinates_group)
+ rtn = setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL);
+ if (rtn == ERR) {
+ curses_window_set_error(self, "setcchar", "addch");
+ return NULL;
+ }
+ if (coordinates_group) {
rtn = mvwadd_wch(self->win,y,x, &wcval);
+ funcname = "mvwadd_wch";
+ }
else {
rtn = wadd_wch(self->win, &wcval);
+ funcname = "wadd_wch";
}
}
else
@@ -911,17 +1021,40 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1,
type = PyCurses_ConvertToCchar_t(self, ch, &cch);
#endif
if (type == 1) {
- funcname = "addch";
- if (coordinates_group)
+ if (coordinates_group) {
rtn = mvwaddch(self->win,y,x, cch | (attr_t) attr);
+ funcname = "mvwaddch";
+ }
else {
rtn = waddch(self->win, cch | (attr_t) attr);
+ funcname = "waddch";
}
}
else {
return NULL;
}
- return PyCursesCheckERR_ForWin(self, rtn, funcname);
+ return curses_window_check_err(self, rtn, funcname, "addch");
+}
+
+#ifdef HAVE_NCURSESW
+#define curses_release_wstr(STRTYPE, WSTR) \
+ do { \
+ if ((STRTYPE) == 2) { \
+ PyMem_Free((WSTR)); \
+ } \
+ } while (0)
+#else
+#define curses_release_wstr(_STRTYPE, _WSTR)
+#endif
+
+static int
+curses_wattrset(PyCursesWindowObject *self, long attr, const char *funcname)
+{
+ if (wattrset(self->win, attr) == ERR) {
+ curses_window_set_error(self, "wattrset", funcname);
+ return -1;
+ }
+ return 0;
}
/*[clinic input]
@@ -977,31 +1110,46 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1,
}
if (use_attr) {
attr_old = getattrs(self->win);
- (void)wattrset(self->win,attr);
+ if (curses_wattrset(self, attr, "addstr") < 0) {
+ curses_release_wstr(strtype, wstr);
+ return NULL;
+ }
}
#ifdef HAVE_NCURSESW
if (strtype == 2) {
- funcname = "addwstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwaddwstr(self->win,y,x,wstr);
- else
+ funcname = "mvwaddwstr";
+ }
+ else {
rtn = waddwstr(self->win,wstr);
+ funcname = "waddwstr";
+ }
PyMem_Free(wstr);
}
else
#endif
{
const char *str = PyBytes_AS_STRING(bytesobj);
- funcname = "addstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwaddstr(self->win,y,x,str);
- else
+ funcname = "mvwaddstr";
+ }
+ else {
rtn = waddstr(self->win,str);
+ funcname = "waddstr";
+ }
Py_DECREF(bytesobj);
}
- if (use_attr)
- (void)wattrset(self->win,attr_old);
- return PyCursesCheckERR_ForWin(self, rtn, funcname);
+ if (rtn == ERR) {
+ curses_window_set_error(self, funcname, "addstr");
+ return NULL;
+ }
+ if (use_attr) {
+ rtn = wattrset(self->win, attr_old);
+ return curses_window_check_err(self, rtn, "wattrset", "addstr");
+ }
+ Py_RETURN_NONE;
}
/*[clinic input]
@@ -1060,31 +1208,46 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1,
if (use_attr) {
attr_old = getattrs(self->win);
- (void)wattrset(self->win,attr);
+ if (curses_wattrset(self, attr, "addnstr") < 0) {
+ curses_release_wstr(strtype, wstr);
+ return NULL;
+ }
}
#ifdef HAVE_NCURSESW
if (strtype == 2) {
- funcname = "addnwstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwaddnwstr(self->win,y,x,wstr,n);
- else
+ funcname = "mvwaddnwstr";
+ }
+ else {
rtn = waddnwstr(self->win,wstr,n);
+ funcname = "waddnwstr";
+ }
PyMem_Free(wstr);
}
else
#endif
{
const char *str = PyBytes_AS_STRING(bytesobj);
- funcname = "addnstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwaddnstr(self->win,y,x,str,n);
- else
+ funcname = "mvwaddnstr";
+ }
+ else {
rtn = waddnstr(self->win,str,n);
+ funcname = "waddnstr";
+ }
Py_DECREF(bytesobj);
}
- if (use_attr)
- (void)wattrset(self->win,attr_old);
- return PyCursesCheckERR_ForWin(self, rtn, funcname);
+ if (rtn == ERR) {
+ curses_window_set_error(self, funcname, "addnstr");
+ return NULL;
+ }
+ if (use_attr) {
+ rtn = wattrset(self->win, attr_old);
+ return curses_window_check_err(self, rtn, "wattrset", "addnstr");
+ }
+ Py_RETURN_NONE;
}
/*[clinic input]
@@ -1108,7 +1271,8 @@ _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr)
if (!PyCurses_ConvertToChtype(self, ch, &bkgd))
return NULL;
- return PyCursesCheckERR_ForWin(self, wbkgd(self->win, bkgd | attr), "bkgd");
+ int rtn = wbkgd(self->win, bkgd | attr);
+ return curses_window_check_err(self, rtn, "wbkgd", "bkgd");
}
/*[clinic input]
@@ -1124,7 +1288,8 @@ static PyObject *
_curses_window_attroff_impl(PyCursesWindowObject *self, long attr)
/*[clinic end generated code: output=8a2fcd4df682fc64 input=786beedf06a7befe]*/
{
- return PyCursesCheckERR_ForWin(self, wattroff(self->win, (attr_t)attr), "attroff");
+ int rtn = wattroff(self->win, (attr_t)attr);
+ return curses_window_check_err(self, rtn, "wattroff", "attroff");
}
/*[clinic input]
@@ -1140,7 +1305,8 @@ static PyObject *
_curses_window_attron_impl(PyCursesWindowObject *self, long attr)
/*[clinic end generated code: output=7afea43b237fa870 input=5a88fba7b1524f32]*/
{
- return PyCursesCheckERR_ForWin(self, wattron(self->win, (attr_t)attr), "attron");
+ int rtn = wattron(self->win, (attr_t)attr);
+ return curses_window_check_err(self, rtn, "wattron", "attron");
}
/*[clinic input]
@@ -1156,7 +1322,8 @@ static PyObject *
_curses_window_attrset_impl(PyCursesWindowObject *self, long attr)
/*[clinic end generated code: output=84e379bff20c0433 input=42e400c0d0154ab5]*/
{
- return PyCursesCheckERR_ForWin(self, wattrset(self->win, (attr_t)attr), "attrset");
+ int rtn = wattrset(self->win, (attr_t)attr);
+ return curses_window_check_err(self, rtn, "wattrset", "attrset");
}
/*[clinic input]
@@ -1182,7 +1349,7 @@ _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch,
return NULL;
wbkgdset(self->win, bkgd | attr);
- return PyCursesCheckERR_ForWin(self, 0, "bkgdset");
+ Py_RETURN_NONE;
}
/*[clinic input]
@@ -1222,7 +1389,7 @@ _curses_window_border_impl(PyCursesWindowObject *self, PyObject *ls,
/*[clinic end generated code: output=670ef38d3d7c2aa3 input=e015f735d67a240b]*/
{
chtype ch[8];
- int i;
+ int i, rtn;
/* Clear the array of parameters */
for(i=0; i<8; i++)
@@ -1243,10 +1410,10 @@ _curses_window_border_impl(PyCursesWindowObject *self, PyObject *ls,
#undef CONVERTTOCHTYPE
- wborder(self->win,
- ch[0], ch[1], ch[2], ch[3],
- ch[4], ch[5], ch[6], ch[7]);
- Py_RETURN_NONE;
+ rtn = wborder(self->win,
+ ch[0], ch[1], ch[2], ch[3],
+ ch[4], ch[5], ch[6], ch[7]);
+ return curses_window_check_err(self, rtn, "wborder", "border");
}
/*[clinic input]
@@ -1280,8 +1447,7 @@ _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1,
return NULL;
}
}
- box(self->win,ch1,ch2);
- Py_RETURN_NONE;
+ return curses_window_check_err(self, box(self->win, ch1, ch2), "box", NULL);
}
#if defined(HAVE_NCURSES_H) || defined(MVWDELCH_IS_EXPRESSION)
@@ -1306,38 +1472,34 @@ int py_mvwdelch(WINDOW *w, int y, int x)
/* chgat, added by Fabian Kreutz <fabian.kreutz at gmx.net> */
#ifdef HAVE_CURSES_WCHGAT
-/*[-clinic input]
-_curses.window.chgat
- [
- y: int
- Y-coordinate.
- x: int
- X-coordinate.
- ]
-
- n: int = -1
- Number of characters.
-
- attr: long
- Attributes for characters.
- /
+PyDoc_STRVAR(_curses_window_chgat__doc__,
+"chgat([y, x,] [n=-1,] attr)\n"
+"Set the attributes of characters.\n"
+"\n"
+" y\n"
+" Y-coordinate.\n"
+" x\n"
+" X-coordinate.\n"
+" n\n"
+" Number of characters.\n"
+" attr\n"
+" Attributes for characters.\n"
+"\n"
+"Set the attributes of num characters at the current cursor position, or at\n"
+"position (y, x) if supplied. If no value of num is given or num = -1, the\n"
+"attribute will be set on all the characters to the end of the line. This\n"
+"function does not move the cursor. The changed line will be touched using\n"
+"the touchline() method so that the contents will be redisplayed by the next\n"
+"window refresh.");
-Set the attributes of characters.
-
-Set the attributes of num characters at the current cursor position, or at
-position (y, x) if supplied. If no value of num is given or num = -1, the
-attribute will be set on all the characters to the end of the line. This
-function does not move the cursor. The changed line will be touched using
-the touchline() method so that the contents will be redisplayed by the next
-window refresh.
-[-clinic start generated code]*/
static PyObject *
PyCursesWindow_ChgAt(PyObject *op, PyObject *args)
{
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
int rtn;
+ const char *funcname;
int x, y;
int num = -1;
short color;
@@ -1357,19 +1519,20 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args)
attr = lattr;
break;
case 3:
- if (!PyArg_ParseTuple(args,"iil;int,int,attr", &y, &x, &lattr))
+ if (!PyArg_ParseTuple(args,"iil;y,x,attr", &y, &x, &lattr))
return NULL;
attr = lattr;
use_xy = TRUE;
break;
case 4:
- if (!PyArg_ParseTuple(args,"iiil;int,int,n,attr", &y, &x, &num, &lattr))
+ if (!PyArg_ParseTuple(args,"iiil;y,x,n,attr", &y, &x, &num, &lattr))
return NULL;
attr = lattr;
use_xy = TRUE;
break;
default:
- PyErr_SetString(PyExc_TypeError, "chgat requires 1 to 4 arguments");
+ PyErr_SetString(PyExc_TypeError,
+ "_curses.window.chgat requires 1 to 4 arguments");
return NULL;
}
@@ -1378,13 +1541,18 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args)
if (use_xy) {
rtn = mvwchgat(self->win,y,x,num,attr,color,NULL);
- touchline(self->win,y,1);
+ funcname = "mvwchgat";
} else {
getyx(self->win,y,x);
rtn = wchgat(self->win,num,attr,color,NULL);
- touchline(self->win,y,1);
+ funcname = "wchgat";
}
- return PyCursesCheckERR_ForWin(self, rtn, "chgat");
+ if (rtn == ERR) {
+ curses_window_set_error(self, funcname, "chgat");
+ return NULL;
+ }
+ rtn = touchline(self->win,y,1);
+ return curses_window_check_err(self, rtn, "touchline", "chgat");
}
#endif
@@ -1407,12 +1575,17 @@ _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1,
int y, int x)
/*[clinic end generated code: output=22e77bb9fa11b461 input=d2f79e630a4fc6d0]*/
{
+ int rtn;
+ const char *funcname;
if (!group_right_1) {
- return PyCursesCheckERR_ForWin(self, wdelch(self->win), "wdelch");
+ rtn = wdelch(self->win);
+ funcname = "wdelch";
}
else {
- return PyCursesCheckERR_ForWin(self, py_mvwdelch(self->win, y, x), "mvwdelch");
+ rtn = py_mvwdelch(self->win, y, x);
+ funcname = "mvwdelch";
}
+ return curses_window_check_err(self, rtn, funcname, "delch");
}
/*[clinic input]
@@ -1447,13 +1620,12 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
win = derwin(self->win,nlines,ncols,begin_y,begin_x);
if (win == NULL) {
- cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- PyErr_SetString(state->error, catchall_NULL);
+ curses_window_set_null_error(self, "derwin", NULL);
return NULL;
}
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- return PyCursesWindow_New(state, win, NULL);
+ return PyCursesWindow_New(state, win, NULL, self);
}
/*[clinic input]
@@ -1479,17 +1651,20 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch,
if (!PyCurses_ConvertToChtype(self, ch, &ch_))
return NULL;
+ int rtn;
+ const char *funcname;
#ifdef py_is_pad
if (py_is_pad(self->win)) {
- return PyCursesCheckERR_ForWin(self,
- pechochar(self->win, ch_ | (attr_t)attr),
- "echochar");
+ rtn = pechochar(self->win, ch_ | (attr_t)attr);
+ funcname = "pechochar";
}
else
#endif
- return PyCursesCheckERR_ForWin(self,
- wechochar(self->win, ch_ | (attr_t)attr),
- "echochar");
+ {
+ rtn = wechochar(self->win, ch_ | (attr_t)attr);
+ funcname = "wechochar";
+ }
+ return curses_window_check_err(self, rtn, funcname, "echochar");
}
#ifdef NCURSES_MOUSE_VERSION
@@ -1514,20 +1689,40 @@ _curses_window_enclose_impl(PyCursesWindowObject *self, int y, int x)
#endif
/*[clinic input]
-_curses.window.getbkgd -> long
+_curses.window.getbkgd
Return the window's current background character/attribute pair.
[clinic start generated code]*/
-static long
+static PyObject *
_curses_window_getbkgd_impl(PyCursesWindowObject *self)
-/*[clinic end generated code: output=c52b25dc16b215c3 input=a69db882fa35426c]*/
+/*[clinic end generated code: output=3ff953412b0e6028 input=7cf1f59a31f89df4]*/
{
- return (long) getbkgd(self->win);
+ chtype rtn = getbkgd(self->win);
+ if (rtn == (chtype)ERR) {
+ curses_window_set_error(self, "getbkgd", NULL);
+ return NULL;
+ }
+ return PyLong_FromLong(rtn);
+}
+
+static PyObject *
+curses_check_signals_on_input_error(PyCursesWindowObject *self,
+ const char *curses_funcname,
+ const char *python_funcname)
+{
+ assert(!PyErr_Occurred());
+ if (PyErr_CheckSignals()) {
+ return NULL;
+ }
+ cursesmodule_state *state = get_cursesmodule_state_by_win(self);
+ PyErr_Format(state->error, "%s() (called by %s()): no input",
+ curses_funcname, python_funcname);
+ return NULL;
}
/*[clinic input]
-_curses.window.getch -> int
+_curses.window.getch
[
y: int
@@ -1544,10 +1739,10 @@ keypad keys and so on return numbers higher than 256. In no-delay mode, -1
is returned if there is no input, else getch() waits until a key is pressed.
[clinic start generated code]*/
-static int
+static PyObject *
_curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1,
int y, int x)
-/*[clinic end generated code: output=980aa6af0c0ca387 input=bb24ebfb379f991f]*/
+/*[clinic end generated code: output=e1639e87d545e676 input=73f350336b1ee8c8]*/
{
int rtn;
@@ -1560,7 +1755,17 @@ _curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1,
}
Py_END_ALLOW_THREADS
- return rtn;
+ if (rtn == ERR) {
+ // We suppress ERR returned by wgetch() in nodelay mode
+ // after we handled possible interruption signals.
+ if (PyErr_CheckSignals()) {
+ return NULL;
+ }
+ // ERR is an implementation detail, so to be on the safe side,
+ // we forcibly set the return value to -1 as documented above.
+ rtn = -1;
+ }
+ return PyLong_FromLong(rtn);
}
/*[clinic input]
@@ -1598,13 +1803,9 @@ _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1,
Py_END_ALLOW_THREADS
if (rtn == ERR) {
- /* getch() returns ERR in nodelay mode */
- PyErr_CheckSignals();
- if (!PyErr_Occurred()) {
- cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- PyErr_SetString(state->error, "no input");
- }
- return NULL;
+ /* wgetch() returns ERR in nodelay mode */
+ const char *funcname = group_right_1 ? "mvwgetch" : "wgetch";
+ return curses_check_signals_on_input_error(self, funcname, "getkey");
} else if (rtn <= 255) {
#ifdef NCURSES_VERSION_MAJOR
#if NCURSES_VERSION_MAJOR*100+NCURSES_VERSION_MINOR <= 507
@@ -1657,13 +1858,9 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1,
Py_END_ALLOW_THREADS
if (ct == ERR) {
- if (PyErr_CheckSignals())
- return NULL;
-
- /* get_wch() returns ERR in nodelay mode */
- cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- PyErr_SetString(state->error, "no input");
- return NULL;
+ /* wget_wch() returns ERR in nodelay mode */
+ const char *funcname = group_right_1 ? "mvwget_wch" : "wget_wch";
+ return curses_check_signals_on_input_error(self, funcname, "get_wch");
}
if (ct == KEY_CODE_YES)
return PyLong_FromLong(rtn);
@@ -1672,84 +1869,102 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1,
}
#endif
-/*[-clinic input]
-_curses.window.getstr
-
- [
- y: int
- Y-coordinate.
- x: int
- X-coordinate.
- ]
- n: int = 1023
- Maximal number of characters.
- /
+/*
+ * Helper function for parsing parameters from getstr() and instr().
+ * This function is necessary because Argument Clinic does not know
+ * how to handle nested optional groups with default values inside.
+ *
+ * Return 1 on success and 0 on failure, similar to PyArg_ParseTuple().
+ */
+static int
+curses_clinic_parse_optional_xy_n(PyObject *args,
+ int *y, int *x, unsigned int *n, int *use_xy,
+ const char *qualname)
+{
+ switch (PyTuple_GET_SIZE(args)) {
+ case 0: {
+ *use_xy = 0;
+ return 1;
+ }
+ case 1: {
+ *use_xy = 0;
+ return PyArg_ParseTuple(args, "O&;n",
+ _PyLong_UnsignedInt_Converter, n);
+ }
+ case 2: {
+ *use_xy = 1;
+ return PyArg_ParseTuple(args, "ii;y,x", y, x);
+ }
+ case 3: {
+ *use_xy = 1;
+ return PyArg_ParseTuple(args, "iiO&;y,x,n", y, x,
+ _PyLong_UnsignedInt_Converter, n);
+ }
+ default: {
+ *use_xy = 0;
+ PyErr_Format(PyExc_TypeError, "%s requires 0 to 3 arguments",
+ qualname);
+ return 0;
+ }
+ }
+}
-Read a string from the user, with primitive line editing capacity.
-[-clinic start generated code]*/
+PyDoc_STRVAR(_curses_window_getstr__doc__,
+"getstr([[y, x,] n=2047])\n"
+"Read a string from the user, with primitive line editing capacity.\n"
+"\n"
+" y\n"
+" Y-coordinate.\n"
+" x\n"
+" X-coordinate.\n"
+" n\n"
+" Maximal number of characters.");
static PyObject *
-PyCursesWindow_GetStr(PyObject *op, PyObject *args)
+PyCursesWindow_getstr(PyObject *op, PyObject *args)
{
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
+ int rtn, use_xy = 0, y = 0, x = 0;
+ unsigned int max_buf_size = 2048;
+ unsigned int n = max_buf_size - 1;
+ PyObject *res;
- int x, y, n;
- char rtn[1024]; /* This should be big enough.. I hope */
- int rtn2;
+ if (!curses_clinic_parse_optional_xy_n(args, &y, &x, &n, &use_xy,
+ "_curses.window.instr"))
+ {
+ return NULL;
+ }
- switch (PyTuple_Size(args)) {
- case 0:
- Py_BEGIN_ALLOW_THREADS
- rtn2 = wgetnstr(self->win,rtn, 1023);
- Py_END_ALLOW_THREADS
- break;
- case 1:
- if (!PyArg_ParseTuple(args,"i;n", &n))
- return NULL;
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
- return NULL;
- }
- Py_BEGIN_ALLOW_THREADS
- rtn2 = wgetnstr(self->win, rtn, Py_MIN(n, 1023));
- Py_END_ALLOW_THREADS
- break;
- case 2:
- if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
- return NULL;
+ n = Py_MIN(n, max_buf_size - 1);
+ res = PyBytes_FromStringAndSize(NULL, n + 1);
+ if (res == NULL) {
+ return NULL;
+ }
+ char *buf = PyBytes_AS_STRING(res);
+
+ if (use_xy) {
Py_BEGIN_ALLOW_THREADS
#ifdef STRICT_SYSV_CURSES
- rtn2 = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, 1023);
+ rtn = wmove(self->win, y, x) == ERR
+ ? ERR
+ : wgetnstr(self->win, buf, n);
#else
- rtn2 = mvwgetnstr(self->win,y,x,rtn, 1023);
+ rtn = mvwgetnstr(self->win, y, x, buf, n);
#endif
Py_END_ALLOW_THREADS
- break;
- case 3:
- if (!PyArg_ParseTuple(args,"iii;y,x,n", &y, &x, &n))
- return NULL;
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
- return NULL;
- }
-#ifdef STRICT_SYSV_CURSES
- Py_BEGIN_ALLOW_THREADS
- rtn2 = wmove(self->win,y,x)==ERR ? ERR :
- wgetnstr(self->win, rtn, Py_MIN(n, 1023));
- Py_END_ALLOW_THREADS
-#else
+ }
+ else {
Py_BEGIN_ALLOW_THREADS
- rtn2 = mvwgetnstr(self->win, y, x, rtn, Py_MIN(n, 1023));
+ rtn = wgetnstr(self->win, buf, n);
Py_END_ALLOW_THREADS
-#endif
- break;
- default:
- PyErr_SetString(PyExc_TypeError, "getstr requires 0 to 3 arguments");
- return NULL;
}
- if (rtn2 == ERR)
- rtn[0] = 0;
- return PyBytes_FromString(rtn);
+
+ if (rtn == ERR) {
+ Py_DECREF(res);
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+ _PyBytes_Resize(&res, strlen(buf)); // 'res' is set to NULL on failure
+ return res;
}
/*[clinic input]
@@ -1788,10 +2003,12 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1,
return NULL;
if (group_left_1) {
if (wmove(self->win, y, x) == ERR) {
- return PyCursesCheckERR_ForWin(self, ERR, "wmove");
+ curses_window_set_error(self, "wmove", "hline");
+ return NULL;
}
}
- return PyCursesCheckERR_ForWin(self, whline(self->win, ch_ | (attr_t)attr, n), "hline");
+ int rtn = whline(self->win, ch_ | (attr_t)attr, n);
+ return curses_window_check_err(self, rtn, "whline", "hline");
}
/*[clinic input]
@@ -1831,18 +2048,21 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1,
if (!PyCurses_ConvertToChtype(self, ch, &ch_))
return NULL;
+ const char *funcname;
if (!group_left_1) {
rtn = winsch(self->win, ch_ | (attr_t)attr);
+ funcname = "winsch";
}
else {
rtn = mvwinsch(self->win, y, x, ch_ | (attr_t)attr);
+ funcname = "mvwwinsch";
}
- return PyCursesCheckERR_ForWin(self, rtn, "insch");
+ return curses_window_check_err(self, rtn, funcname, "insch");
}
/*[clinic input]
-_curses.window.inch -> unsigned_long
+_curses.window.inch
[
y: int
@@ -1857,86 +2077,80 @@ Return the character at the given position in the window.
The bottom 8 bits are the character proper, and upper bits are the attributes.
[clinic start generated code]*/
-static unsigned long
+static PyObject *
_curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1,
int y, int x)
-/*[clinic end generated code: output=6c4719fe978fe86a input=fac23ee11e3b3a66]*/
+/*[clinic end generated code: output=97ca8581baaafd06 input=4b4fb43d85b177c3]*/
{
- unsigned long rtn;
+ chtype rtn;
+ const char *funcname;
if (!group_right_1) {
rtn = winch(self->win);
+ funcname = "winch";
}
else {
rtn = mvwinch(self->win, y, x);
+ funcname = "mvwinch";
}
-
- return rtn;
+ if (rtn == (chtype)ERR) {
+ curses_window_set_error(self, funcname, "inch");
+ return NULL;
+ }
+ return PyLong_FromUnsignedLong(rtn);
}
-/*[-clinic input]
-_curses.window.instr
+PyDoc_STRVAR(_curses_window_instr__doc__,
+"instr([y, x,] n=2047)\n"
+"Return a string of characters, extracted from the window.\n"
+"\n"
+" y\n"
+" Y-coordinate.\n"
+" x\n"
+" X-coordinate.\n"
+" n\n"
+" Maximal number of characters.\n"
+"\n"
+"Return a string of characters, extracted from the window starting at the\n"
+"current cursor position, or at y, x if specified. Attributes are stripped\n"
+"from the characters. If n is specified, instr() returns a string at most\n"
+"n characters long (exclusive of the trailing NUL).");
- [
- y: int
- Y-coordinate.
- x: int
- X-coordinate.
- ]
- n: int = 1023
- Maximal number of characters.
- /
-
-Return a string of characters, extracted from the window.
-
-Return a string of characters, extracted from the window starting at the
-current cursor position, or at y, x if specified. Attributes are stripped
-from the characters. If n is specified, instr() returns a string at most
-n characters long (exclusive of the trailing NUL).
-[-clinic start generated code]*/
static PyObject *
-PyCursesWindow_InStr(PyObject *op, PyObject *args)
+PyCursesWindow_instr(PyObject *op, PyObject *args)
{
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
+ int rtn, use_xy = 0, y = 0, x = 0;
+ unsigned int max_buf_size = 2048;
+ unsigned int n = max_buf_size - 1;
+ PyObject *res;
- int x, y, n;
- char rtn[1024]; /* This should be big enough.. I hope */
- int rtn2;
+ if (!curses_clinic_parse_optional_xy_n(args, &y, &x, &n, &use_xy,
+ "_curses.window.instr"))
+ {
+ return NULL;
+ }
- switch (PyTuple_Size(args)) {
- case 0:
- rtn2 = winnstr(self->win,rtn, 1023);
- break;
- case 1:
- if (!PyArg_ParseTuple(args,"i;n", &n))
- return NULL;
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
- return NULL;
- }
- rtn2 = winnstr(self->win, rtn, Py_MIN(n, 1023));
- break;
- case 2:
- if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
- return NULL;
- rtn2 = mvwinnstr(self->win,y,x,rtn,1023);
- break;
- case 3:
- if (!PyArg_ParseTuple(args, "iii;y,x,n", &y, &x, &n))
- return NULL;
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
- return NULL;
- }
- rtn2 = mvwinnstr(self->win, y, x, rtn, Py_MIN(n,1023));
- break;
- default:
- PyErr_SetString(PyExc_TypeError, "instr requires 0 or 3 arguments");
+ n = Py_MIN(n, max_buf_size - 1);
+ res = PyBytes_FromStringAndSize(NULL, n + 1);
+ if (res == NULL) {
return NULL;
}
- if (rtn2 == ERR)
- rtn[0] = 0;
- return PyBytes_FromString(rtn);
+ char *buf = PyBytes_AS_STRING(res);
+
+ if (use_xy) {
+ rtn = mvwinnstr(self->win, y, x, buf, n);
+ }
+ else {
+ rtn = winnstr(self->win, buf, n);
+ }
+
+ if (rtn == ERR) {
+ Py_DECREF(res);
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+ _PyBytes_Resize(&res, strlen(buf)); // 'res' is set to NULL on failure
+ return res;
}
/*[clinic input]
@@ -1993,31 +2207,46 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1,
if (use_attr) {
attr_old = getattrs(self->win);
- (void)wattrset(self->win, (attr_t)attr);
+ if (curses_wattrset(self, attr, "insstr") < 0) {
+ curses_release_wstr(strtype, wstr);
+ return NULL;
+ }
}
#ifdef HAVE_NCURSESW
if (strtype == 2) {
- funcname = "inswstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwins_wstr(self->win,y,x,wstr);
- else
+ funcname = "mvwins_wstr";
+ }
+ else {
rtn = wins_wstr(self->win,wstr);
+ funcname = "wins_wstr";
+ }
PyMem_Free(wstr);
}
else
#endif
{
const char *str = PyBytes_AS_STRING(bytesobj);
- funcname = "insstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwinsstr(self->win,y,x,str);
- else
+ funcname = "mvwinsstr";
+ }
+ else {
rtn = winsstr(self->win,str);
+ funcname = "winsstr";
+ }
Py_DECREF(bytesobj);
}
- if (use_attr)
- (void)wattrset(self->win,attr_old);
- return PyCursesCheckERR_ForWin(self, rtn, funcname);
+ if (rtn == ERR) {
+ curses_window_set_error(self, funcname, "insstr");
+ return NULL;
+ }
+ if (use_attr) {
+ rtn = wattrset(self->win, attr_old);
+ return curses_window_check_err(self, rtn, "wattrset", "insstr");
+ }
+ Py_RETURN_NONE;
}
/*[clinic input]
@@ -2078,31 +2307,46 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1,
if (use_attr) {
attr_old = getattrs(self->win);
- (void)wattrset(self->win, (attr_t)attr);
+ if (curses_wattrset(self, attr, "insnstr") < 0) {
+ curses_release_wstr(strtype, wstr);
+ return NULL;
+ }
}
#ifdef HAVE_NCURSESW
if (strtype == 2) {
- funcname = "insn_wstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwins_nwstr(self->win,y,x,wstr,n);
- else
+ funcname = "mvwins_nwstr";
+ }
+ else {
rtn = wins_nwstr(self->win,wstr,n);
+ funcname = "wins_nwstr";
+ }
PyMem_Free(wstr);
}
else
#endif
{
const char *str = PyBytes_AS_STRING(bytesobj);
- funcname = "insnstr";
- if (use_xy)
+ if (use_xy) {
rtn = mvwinsnstr(self->win,y,x,str,n);
- else
+ funcname = "mvwinsnstr";
+ }
+ else {
rtn = winsnstr(self->win,str,n);
+ funcname = "winsnstr";
+ }
Py_DECREF(bytesobj);
}
- if (use_attr)
- (void)wattrset(self->win,attr_old);
- return PyCursesCheckERR_ForWin(self, rtn, funcname);
+ if (rtn == ERR) {
+ curses_window_set_error(self, funcname, "insnstr");
+ return NULL;
+ }
+ if (use_attr) {
+ rtn = wattrset(self->win, attr_old);
+ return curses_window_check_err(self, rtn, "wattrset", "insnstr");
+ }
+ Py_RETURN_NONE;
}
/*[clinic input]
@@ -2124,8 +2368,7 @@ _curses_window_is_linetouched_impl(PyCursesWindowObject *self, int line)
int erg;
erg = is_linetouched(self->win, line);
if (erg == ERR) {
- PyErr_SetString(PyExc_TypeError,
- "is_linetouched: line number outside of boundaries");
+ curses_window_set_error(self, "is_linetouched", NULL);
return NULL;
}
return PyBool_FromLong(erg);
@@ -2179,8 +2422,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self)
#ifdef py_is_pad
if (py_is_pad(self->win)) {
if (!group_right_1) {
- cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- PyErr_SetString(state->error,
+ PyErr_SetString(PyExc_TypeError,
"noutrefresh() called for a pad "
"requires 6 arguments");
return NULL;
@@ -2189,7 +2431,8 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self)
rtn = pnoutrefresh(self->win, pminrow, pmincol,
sminrow, smincol, smaxrow, smaxcol);
Py_END_ALLOW_THREADS
- return PyCursesCheckERR_ForWin(self, rtn, "pnoutrefresh");
+ return curses_window_check_err(self, rtn,
+ "pnoutrefresh", "noutrefresh");
}
if (group_right_1) {
PyErr_SetString(PyExc_TypeError,
@@ -2200,7 +2443,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self)
Py_BEGIN_ALLOW_THREADS
rtn = wnoutrefresh(self->win);
Py_END_ALLOW_THREADS
- return PyCursesCheckERR_ForWin(self, rtn, "wnoutrefresh");
+ return curses_window_check_err(self, rtn, "wnoutrefresh", "noutrefresh");
}
/*[clinic input]
@@ -2242,11 +2485,11 @@ _curses_window_overlay_impl(PyCursesWindowObject *self,
if (group_right_1) {
rtn = copywin(self->win, destwin->win, sminrow, smincol,
dminrow, dmincol, dmaxrow, dmaxcol, TRUE);
- return PyCursesCheckERR_ForWin(self, rtn, "copywin");
+ return curses_window_check_err(self, rtn, "copywin", "overlay");
}
else {
rtn = overlay(self->win, destwin->win);
- return PyCursesCheckERR_ForWin(self, rtn, "overlay");
+ return curses_window_check_err(self, rtn, "overlay", NULL);
}
}
@@ -2290,11 +2533,11 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self,
if (group_right_1) {
rtn = copywin(self->win, destwin->win, sminrow, smincol,
dminrow, dmincol, dmaxrow, dmaxcol, FALSE);
- return PyCursesCheckERR_ForWin(self, rtn, "copywin");
+ return curses_window_check_err(self, rtn, "copywin", "overwrite");
}
else {
rtn = overwrite(self->win, destwin->win);
- return PyCursesCheckERR_ForWin(self, rtn, "overwrite");
+ return curses_window_check_err(self, rtn, "overwrite", NULL);
}
}
@@ -2323,7 +2566,7 @@ _curses_window_putwin_impl(PyCursesWindowObject *self, PyObject *file)
return PyErr_SetFromErrno(PyExc_OSError);
if (_Py_set_inheritable(fileno(fp), 0, NULL) < 0)
goto exit;
- res = PyCursesCheckERR_ForWin(self, putwin(self->win, fp), "putwin");
+ res = curses_window_check_err(self, putwin(self->win, fp), "putwin", NULL);
if (res == NULL)
goto exit;
fseek(fp, 0, 0);
@@ -2362,7 +2605,8 @@ static PyObject *
_curses_window_redrawln_impl(PyCursesWindowObject *self, int beg, int num)
/*[clinic end generated code: output=ea216e334f9ce1b4 input=152155e258a77a7a]*/
{
- return PyCursesCheckERR_ForWin(self, wredrawln(self->win,beg,num), "redrawln");
+ int rtn = wredrawln(self->win,beg, num);
+ return curses_window_check_err(self, rtn, "wredrawln", "redrawln");
}
/*[clinic input]
@@ -2404,8 +2648,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1,
#ifdef py_is_pad
if (py_is_pad(self->win)) {
if (!group_right_1) {
- cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- PyErr_SetString(state->error,
+ PyErr_SetString(PyExc_TypeError,
"refresh() for a pad requires 6 arguments");
return NULL;
}
@@ -2413,7 +2656,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1,
rtn = prefresh(self->win, pminrow, pmincol,
sminrow, smincol, smaxrow, smaxcol);
Py_END_ALLOW_THREADS
- return PyCursesCheckERR_ForWin(self, rtn, "prefresh");
+ return curses_window_check_err(self, rtn, "prefresh", "refresh");
}
#endif
if (group_right_1) {
@@ -2424,7 +2667,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1,
Py_BEGIN_ALLOW_THREADS
rtn = wrefresh(self->win);
Py_END_ALLOW_THREADS
- return PyCursesCheckERR_ForWin(self, rtn, "prefresh");
+ return curses_window_check_err(self, rtn, "wrefresh", "refresh");
}
/*[clinic input]
@@ -2446,7 +2689,8 @@ _curses_window_setscrreg_impl(PyCursesWindowObject *self, int top,
int bottom)
/*[clinic end generated code: output=486ab5db218d2b1a input=1b517b986838bf0e]*/
{
- return PyCursesCheckERR_ForWin(self, wsetscrreg(self->win, top, bottom), "wsetscrreg");
+ int rtn = wsetscrreg(self->win, top, bottom);
+ return curses_window_check_err(self, rtn, "wsetscrreg", "setscrreg");
}
/*[clinic input]
@@ -2476,24 +2720,28 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1,
/*[clinic end generated code: output=93e898afc348f59a input=2129fa47fd57721c]*/
{
WINDOW *win;
+ const char *funcname;
/* printf("Subwin: %i %i %i %i \n", nlines, ncols, begin_y, begin_x); */
#ifdef py_is_pad
if (py_is_pad(self->win)) {
win = subpad(self->win, nlines, ncols, begin_y, begin_x);
+ funcname = "subpad";
}
else
#endif
+ {
win = subwin(self->win, nlines, ncols, begin_y, begin_x);
+ funcname = "subwin";
+ }
if (win == NULL) {
- cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- PyErr_SetString(state->error, catchall_NULL);
+ curses_window_set_null_error(self, funcname, "subwin");
return NULL;
}
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
- return PyCursesWindow_New(state, win, self->encoding);
+ return PyCursesWindow_New(state, win, self->encoding, self);
}
/*[clinic input]
@@ -2515,12 +2763,17 @@ _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1,
int lines)
/*[clinic end generated code: output=4541a8a11852d360 input=c969ca0cfabbdbec]*/
{
+ int rtn;
+ const char *funcname;
if (!group_right_1) {
- return PyCursesCheckERR_ForWin(self, scroll(self->win), "scroll");
+ rtn = scroll(self->win);
+ funcname = "scroll";
}
else {
- return PyCursesCheckERR_ForWin(self, wscrl(self->win, lines), "scroll");
+ rtn = wscrl(self->win, lines);
+ funcname = "wscrl";
}
+ return curses_window_check_err(self, rtn, funcname, "scroll");
}
/*[clinic input]
@@ -2544,12 +2797,17 @@ _curses_window_touchline_impl(PyCursesWindowObject *self, int start,
int count, int group_right_1, int changed)
/*[clinic end generated code: output=65d05b3f7438c61d input=a98aa4f79b6be845]*/
{
+ int rtn;
+ const char *funcname;
if (!group_right_1) {
- return PyCursesCheckERR_ForWin(self, touchline(self->win, start, count), "touchline");
+ rtn = touchline(self->win, start, count);
+ funcname = "touchline";
}
else {
- return PyCursesCheckERR_ForWin(self, wtouchln(self->win, start, count, changed), "touchline");
+ rtn = wtouchln(self->win, start, count, changed);
+ funcname = "wtouchln";
}
+ return curses_window_check_err(self, rtn, funcname, "touchline");
}
/*[clinic input]
@@ -2587,10 +2845,13 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1,
if (!PyCurses_ConvertToChtype(self, ch, &ch_))
return NULL;
if (group_left_1) {
- if (wmove(self->win, y, x) == ERR)
- return PyCursesCheckERR_ForWin(self, ERR, "wmove");
+ if (wmove(self->win, y, x) == ERR) {
+ curses_window_set_error(self, "wmove", "vline");
+ return NULL;
+ }
}
- return PyCursesCheckERR_ForWin(self, wvline(self->win, ch_ | (attr_t)attr, n), "vline");
+ int rtn = wvline(self->win, ch_ | (attr_t)attr, n);
+ return curses_window_check_err(self, rtn, "wvline", "vline");
}
static PyObject *
@@ -2647,7 +2908,10 @@ static PyMethodDef PyCursesWindow_methods[] = {
_CURSES_WINDOW_ATTRSET_METHODDEF
_CURSES_WINDOW_BKGD_METHODDEF
#ifdef HAVE_CURSES_WCHGAT
- {"chgat", PyCursesWindow_ChgAt, METH_VARARGS},
+ {
+ "chgat", PyCursesWindow_ChgAt, METH_VARARGS,
+ _curses_window_chgat__doc__
+ },
#endif
_CURSES_WINDOW_BKGDSET_METHODDEF
_CURSES_WINDOW_BORDER_METHODDEF
@@ -2670,7 +2934,10 @@ static PyMethodDef PyCursesWindow_methods[] = {
_CURSES_WINDOW_GET_WCH_METHODDEF
{"getmaxyx", PyCursesWindow_getmaxyx, METH_NOARGS},
{"getparyx", PyCursesWindow_getparyx, METH_NOARGS},
- {"getstr", PyCursesWindow_GetStr, METH_VARARGS},
+ {
+ "getstr", PyCursesWindow_getstr, METH_VARARGS,
+ _curses_window_getstr__doc__
+ },
{"getyx", PyCursesWindow_getyx, METH_NOARGS},
_CURSES_WINDOW_HLINE_METHODDEF
{"idcok", PyCursesWindow_idcok, METH_VARARGS},
@@ -2684,7 +2951,10 @@ static PyMethodDef PyCursesWindow_methods[] = {
{"insertln", PyCursesWindow_winsertln, METH_NOARGS},
_CURSES_WINDOW_INSNSTR_METHODDEF
_CURSES_WINDOW_INSSTR_METHODDEF
- {"instr", PyCursesWindow_InStr, METH_VARARGS},
+ {
+ "instr", PyCursesWindow_instr, METH_VARARGS,
+ _curses_window_instr__doc__
+ },
_CURSES_WINDOW_IS_LINETOUCHED_METHODDEF
{"is_wintouched", PyCursesWindow_is_wintouched, METH_NOARGS},
{"keypad", PyCursesWindow_keypad, METH_VARARGS},
@@ -2755,49 +3025,78 @@ static PyType_Spec PyCursesWindow_Type_spec = {
/* -------------------------------------------------------*/
-/* Function Body Macros - They are ugly but very, very useful. ;-)
-
- X - function name
- TYPE - parameter Type
- ERGSTR - format string for construction of the return value
- PARSESTR - format string for argument parsing
- */
-
-#define NoArgNoReturnFunctionBody(X) \
-{ \
- PyCursesStatefulInitialised(module); \
- return PyCursesCheckERR(module, X(), # X); }
+/*
+ * Macros for implementing simple module's methods.
+ *
+ * Parameters
+ *
+ * X The name of the curses C function or macro to invoke.
+ * FLAG When false, prefixes the function name with 'no' at runtime,
+ * This parameter is present in the signature and auto-generated
+ * by Argument Clinic.
+ *
+ * These macros should only be used for generating the body of
+ * the module's methods since they need a module reference.
+ *
+ * The Python function name must be the same as the curses function name (X).
+ */
-#define NoArgOrFlagNoReturnFunctionBody(X, flag) \
-{ \
- PyCursesStatefulInitialised(module); \
- if (flag) \
- return PyCursesCheckERR(module, X(), # X); \
- else \
- return PyCursesCheckERR(module, no ## X(), # X); \
+#define NoArgNoReturnFunctionBody(X) \
+{ \
+ PyCursesStatefulInitialised(module); \
+ return curses_check_err(module, X(), # X, NULL); \
}
-#define NoArgReturnIntFunctionBody(X) \
-{ \
- PyCursesStatefulInitialised(module); \
- return PyLong_FromLong((long) X()); }
+#define NoArgOrFlagNoReturnFunctionBody(X, FLAG) \
+{ \
+ PyCursesStatefulInitialised(module); \
+ int rtn; \
+ const char *funcname; \
+ if (FLAG) { \
+ rtn = X(); \
+ funcname = # X; \
+ } \
+ else { \
+ rtn = no ## X(); \
+ funcname = "no" # X; \
+ } \
+ return curses_check_err(module, rtn, funcname, # X); \
+}
+#define NoArgReturnIntFunctionBody(X) \
+{ \
+ PyCursesStatefulInitialised(module); \
+ int rtn = X(); \
+ if (rtn == ERR) { \
+ curses_set_error(module, # X, NULL); \
+ return NULL; \
+ } \
+ return PyLong_FromLong(rtn); \
+}
-#define NoArgReturnStringFunctionBody(X) \
-{ \
- PyCursesStatefulInitialised(module); \
- return PyBytes_FromString(X()); }
+#define NoArgReturnStringFunctionBody(X) \
+{ \
+ PyCursesStatefulInitialised(module); \
+ const char *res = X(); \
+ if (res == NULL) { \
+ curses_set_null_error(module, # X, NULL); \
+ return NULL; \
+ } \
+ return PyBytes_FromString(res); \
+}
-#define NoArgTrueFalseFunctionBody(X) \
-{ \
- PyCursesStatefulInitialised(module); \
- return PyBool_FromLong(X()); }
+#define NoArgTrueFalseFunctionBody(X) \
+{ \
+ PyCursesStatefulInitialised(module); \
+ return PyBool_FromLong(X()); \
+}
-#define NoArgNoReturnVoidFunctionBody(X) \
-{ \
- PyCursesStatefulInitialised(module); \
- X(); \
- Py_RETURN_NONE; }
+#define NoArgNoReturnVoidFunctionBody(X) \
+{ \
+ PyCursesStatefulInitialised(module); \
+ X(); \
+ Py_RETURN_NONE; \
+}
/*********************************************************************
Global Functions
@@ -2897,9 +3196,8 @@ _curses_color_content_impl(PyObject *module, int color_number)
PyCursesStatefulInitialisedColor(module);
if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_Format(state->error, "%s() returned ERR",
- Py_STRINGIFY(_COLOR_CONTENT_FUNC));
+ const char *funcname = Py_STRINGIFY(_COLOR_CONTENT_FUNC);
+ curses_set_error(module, funcname, "color_content");
return NULL;
}
@@ -2953,7 +3251,10 @@ _curses_curs_set_impl(PyObject *module, int visibility)
PyCursesStatefulInitialised(module);
erg = curs_set(visibility);
- if (erg == ERR) return PyCursesCheckERR(module, erg, "curs_set");
+ if (erg == ERR) {
+ curses_set_error(module, "curs_set", NULL);
+ return NULL;
+ }
return PyLong_FromLong((long) erg);
}
@@ -3004,7 +3305,7 @@ _curses_delay_output_impl(PyObject *module, int ms)
{
PyCursesStatefulInitialised(module);
- return PyCursesCheckERR(module, delay_output(ms), "delay_output");
+ return curses_check_err(module, delay_output(ms), "delay_output", NULL);
}
/*[clinic input]
@@ -3137,8 +3438,7 @@ _curses_getmouse_impl(PyObject *module)
rtn = getmouse( &event );
if (rtn == ERR) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, "getmouse() returned ERR");
+ curses_set_error(module, "getmouse", NULL);
return NULL;
}
return Py_BuildValue("(hiiik)",
@@ -3176,7 +3476,7 @@ _curses_ungetmouse_impl(PyObject *module, short id, int x, int y, int z,
event.y = y;
event.z = z;
event.bstate = bstate;
- return PyCursesCheckERR(module, ungetmouse(&event), "ungetmouse");
+ return curses_check_err(module, ungetmouse(&event), "ungetmouse", NULL);
}
#endif
@@ -3232,12 +3532,11 @@ _curses_getwin(PyObject *module, PyObject *file)
fseek(fp, 0, 0);
win = getwin(fp);
if (win == NULL) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, catchall_NULL);
+ curses_set_null_error(module, "getwin", NULL);
goto error;
}
cursesmodule_state *state = get_cursesmodule_state(module);
- res = PyCursesWindow_New(state, win, NULL);
+ res = PyCursesWindow_New(state, win, NULL, NULL);
error:
fclose(fp);
@@ -3262,7 +3561,7 @@ _curses_halfdelay_impl(PyObject *module, unsigned char tenths)
{
PyCursesStatefulInitialised(module);
- return PyCursesCheckERR(module, halfdelay(tenths), "halfdelay");
+ return curses_check_err(module, halfdelay(tenths), "halfdelay", NULL);
}
/*[clinic input]
@@ -3347,9 +3646,10 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g,
PyCursesStatefulInitialised(module);
PyCursesStatefulInitialisedColor(module);
- return PyCursesCheckERR(module,
+ return curses_check_err(module,
_CURSES_INIT_COLOR_FUNC(color_number, r, g, b),
- Py_STRINGIFY(_CURSES_INIT_COLOR_FUNC));
+ Py_STRINGIFY(_CURSES_INIT_COLOR_FUNC),
+ NULL);
}
/*[clinic input]
@@ -3383,9 +3683,8 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg)
COLOR_PAIRS - 1);
}
else {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_Format(state->error, "%s() returned ERR",
- Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC));
+ const char *funcname = Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC);
+ curses_set_error(module, funcname, "init_pair");
}
return NULL;
}
@@ -3408,16 +3707,19 @@ _curses_initscr_impl(PyObject *module)
WINDOW *win;
if (curses_initscr_called) {
- wrefresh(stdscr);
cursesmodule_state *state = get_cursesmodule_state(module);
- return PyCursesWindow_New(state, stdscr, NULL);
+ int code = wrefresh(stdscr);
+ if (code == ERR) {
+ _curses_set_null_error(state, "wrefresh", "initscr");
+ return NULL;
+ }
+ return PyCursesWindow_New(state, stdscr, NULL, NULL);
}
win = initscr();
if (win == NULL) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, catchall_NULL);
+ curses_set_null_error(module, "initscr", NULL);
return NULL;
}
@@ -3514,7 +3816,7 @@ _curses_initscr_impl(PyObject *module)
#undef SetDictInt
cursesmodule_state *state = get_cursesmodule_state(module);
- PyObject *winobj = PyCursesWindow_New(state, win, NULL);
+ PyObject *winobj = PyCursesWindow_New(state, win, NULL, NULL);
if (winobj == NULL) {
return NULL;
}
@@ -3544,7 +3846,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd)
if (fd == -1) {
PyObject* sys_stdout;
- if (_PySys_GetOptionalAttrString("stdout", &sys_stdout) < 0) {
+ if (PySys_GetOptionalAttrString("stdout", &sys_stdout) < 0) {
return NULL;
}
@@ -3622,7 +3924,7 @@ _curses_set_escdelay_impl(PyObject *module, int ms)
return NULL;
}
- return PyCursesCheckERR(module, set_escdelay(ms), "set_escdelay");
+ return curses_check_err(module, set_escdelay(ms), "set_escdelay", NULL);
}
/*[clinic input]
@@ -3661,7 +3963,7 @@ _curses_set_tabsize_impl(PyObject *module, int size)
return NULL;
}
- return PyCursesCheckERR(module, set_tabsize(size), "set_tabsize");
+ return curses_check_err(module, set_tabsize(size), "set_tabsize", NULL);
}
#endif
@@ -3679,7 +3981,7 @@ _curses_intrflush_impl(PyObject *module, int flag)
{
PyCursesStatefulInitialised(module);
- return PyCursesCheckERR(module, intrflush(NULL, flag), "intrflush");
+ return curses_check_err(module, intrflush(NULL, flag), "intrflush", NULL);
}
/*[clinic input]
@@ -3792,7 +4094,7 @@ _curses_meta_impl(PyObject *module, int yes)
{
PyCursesStatefulInitialised(module);
- return PyCursesCheckERR(module, meta(stdscr, yes), "meta");
+ return curses_check_err(module, meta(stdscr, yes), "meta", NULL);
}
#ifdef NCURSES_MOUSE_VERSION
@@ -3815,8 +4117,12 @@ _curses_mouseinterval_impl(PyObject *module, int interval)
/*[clinic end generated code: output=c4f5ff04354634c5 input=75aaa3f0db10ac4e]*/
{
PyCursesStatefulInitialised(module);
-
- return PyCursesCheckERR(module, mouseinterval(interval), "mouseinterval");
+ int value = mouseinterval(interval);
+ if (value == ERR) {
+ curses_set_error(module, "mouseinterval", NULL);
+ return NULL;
+ }
+ return PyLong_FromLong(value);
}
/*[clinic input]
@@ -3892,13 +4198,12 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols)
win = newpad(nlines, ncols);
if (win == NULL) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, catchall_NULL);
+ curses_set_null_error(module, "newpad", NULL);
return NULL;
}
cursesmodule_state *state = get_cursesmodule_state(module);
- return PyCursesWindow_New(state, win, NULL);
+ return PyCursesWindow_New(state, win, NULL, NULL);
}
/*[clinic input]
@@ -3933,13 +4238,12 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols,
win = newwin(nlines,ncols,begin_y,begin_x);
if (win == NULL) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, catchall_NULL);
+ curses_set_null_error(module, "newwin", NULL);
return NULL;
}
cursesmodule_state *state = get_cursesmodule_state(module);
- return PyCursesWindow_New(state, win, NULL);
+ return PyCursesWindow_New(state, win, NULL, NULL);
}
/*[clinic input]
@@ -4053,9 +4357,8 @@ _curses_pair_content_impl(PyObject *module, int pair_number)
COLOR_PAIRS - 1);
}
else {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_Format(state->error, "%s() returned ERR",
- Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC));
+ const char *funcname = Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC);
+ curses_set_error(module, funcname, "pair_content");
}
return NULL;
}
@@ -4099,7 +4402,7 @@ static PyObject *
_curses_putp_impl(PyObject *module, const char *string)
/*[clinic end generated code: output=e98081d1b8eb5816 input=1601faa828b44cb3]*/
{
- return PyCursesCheckERR(module, putp(string), "putp");
+ return curses_check_err(module, putp(string), "putp", NULL);
}
/*[clinic input]
@@ -4273,10 +4576,12 @@ _curses_resizeterm_impl(PyObject *module, short nlines, short ncols)
/*[clinic end generated code: output=4de3abab50c67f02 input=414e92a63e3e9899]*/
{
PyObject *result;
+ int code;
PyCursesStatefulInitialised(module);
- result = PyCursesCheckERR(module, resizeterm(nlines, ncols), "resizeterm");
+ code = resizeterm(nlines, ncols);
+ result = curses_check_err(module, code, "resizeterm", NULL);
if (!result)
return NULL;
if (!update_lines_cols(module)) {
@@ -4312,10 +4617,12 @@ _curses_resize_term_impl(PyObject *module, short nlines, short ncols)
/*[clinic end generated code: output=46c6d749fa291dbd input=276afa43d8ea7091]*/
{
PyObject *result;
+ int code;
PyCursesStatefulInitialised(module);
- result = PyCursesCheckERR(module, resize_term(nlines, ncols), "resize_term");
+ code = resize_term(nlines, ncols);
+ result = curses_check_err(module, code, "resize_term", NULL);
if (!result)
return NULL;
if (!update_lines_cols(module)) {
@@ -4384,8 +4691,7 @@ _curses_start_color_impl(PyObject *module)
PyCursesStatefulInitialised(module);
if (start_color() == ERR) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, "start_color() returned ERR");
+ curses_set_error(module, "start_color", NULL);
return NULL;
}
@@ -4537,8 +4843,7 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3,
result = tparm((char *)str,i1,i2,i3,i4,i5,i6,i7,i8,i9);
if (!result) {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, "tparm() returned NULL");
+ curses_set_null_error(module, "tparm", NULL);
return NULL;
}
@@ -4564,7 +4869,7 @@ _curses_typeahead_impl(PyObject *module, int fd)
{
PyCursesStatefulInitialised(module);
- return PyCursesCheckERR(module, typeahead( fd ), "typeahead");
+ return curses_check_err(module, typeahead(fd), "typeahead", NULL);
}
#endif
@@ -4591,7 +4896,12 @@ _curses_unctrl(PyObject *module, PyObject *ch)
if (!PyCurses_ConvertToChtype(NULL, ch, &ch_))
return NULL;
- return PyBytes_FromString(unctrl(ch_));
+ const char *res = unctrl(ch_);
+ if (res == NULL) {
+ curses_set_null_error(module, "unctrl", NULL);
+ return NULL;
+ }
+ return PyBytes_FromString(res);
}
/*[clinic input]
@@ -4614,7 +4924,7 @@ _curses_ungetch(PyObject *module, PyObject *ch)
if (!PyCurses_ConvertToChtype(NULL, ch, &ch_))
return NULL;
- return PyCursesCheckERR(module, ungetch(ch_), "ungetch");
+ return curses_check_err(module, ungetch(ch_), "ungetch", NULL);
}
#ifdef HAVE_NCURSESW
@@ -4684,7 +4994,7 @@ _curses_unget_wch(PyObject *module, PyObject *ch)
if (!PyCurses_ConvertToWchar_t(ch, &wch))
return NULL;
- return PyCursesCheckERR(module, unget_wch(wch), "unget_wch");
+ return curses_check_err(module, unget_wch(wch), "unget_wch", NULL);
}
#endif
@@ -4720,15 +5030,12 @@ _curses_use_env_impl(PyObject *module, int flag)
/*[clinic input]
_curses.use_default_colors
-Allow use of default values for colors on terminals supporting this feature.
-
-Use this to support transparency in your application. The default color
-is assigned to the color number -1.
+Equivalent to assume_default_colors(-1, -1).
[clinic start generated code]*/
static PyObject *
_curses_use_default_colors_impl(PyObject *module)
-/*[clinic end generated code: output=a3b81ff71dd901be input=656844367470e8fc]*/
+/*[clinic end generated code: output=a3b81ff71dd901be input=99ff0b7c69834d1f]*/
{
int code;
@@ -4736,13 +5043,34 @@ _curses_use_default_colors_impl(PyObject *module)
PyCursesStatefulInitialisedColor(module);
code = use_default_colors();
- if (code != ERR) {
- Py_RETURN_NONE;
- } else {
- cursesmodule_state *state = get_cursesmodule_state(module);
- PyErr_SetString(state->error, "use_default_colors() returned ERR");
- return NULL;
- }
+ return curses_check_err(module, code, "use_default_colors", NULL);
+}
+
+/*[clinic input]
+_curses.assume_default_colors
+ fg: int
+ bg: int
+ /
+
+Allow use of default values for colors on terminals supporting this feature.
+
+Assign terminal default foreground/background colors to color number -1.
+Change the definition of the color-pair 0 to (fg, bg).
+
+Use this to support transparency in your application.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_assume_default_colors_impl(PyObject *module, int fg, int bg)
+/*[clinic end generated code: output=54985397a7d2b3a5 input=7fe301712ef3e9fb]*/
+{
+ int code;
+
+ PyCursesStatefulInitialised(module);
+ PyCursesStatefulInitialisedColor(module);
+
+ code = assume_default_colors(fg, bg);
+ return curses_check_err(module, code, "assume_default_colors", NULL);
}
#endif /* STRICT_SYSV_CURSES */
@@ -4902,6 +5230,7 @@ static PyMethodDef cursesmodule_methods[] = {
_CURSES_UNGET_WCH_METHODDEF
_CURSES_USE_ENV_METHODDEF
_CURSES_USE_DEFAULT_COLORS_METHODDEF
+ _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index 9bba0e3354b..eb90be81c8d 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -1088,6 +1088,7 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
// -3: Failed to parse time component
// -4: Failed to parse time separator
// -5: Malformed timezone string
+ // -6: Timezone fields are not in range
const char *p = dtstr;
const char *p_end = dtstr + dtlen;
@@ -1134,6 +1135,11 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end, &tzhour, &tzminute, &tzsecond,
tzmicrosecond);
+ // Check if timezone fields are in range
+ if (check_time_args(tzhour, tzminute, tzsecond, *tzmicrosecond, 0) < 0) {
+ return -6;
+ }
+
*tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond);
*tzmicrosecond *= tzsign;
@@ -5039,6 +5045,9 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
&tzoffset, &tzimicrosecond);
if (rv < 0) {
+ if (rv == -6) {
+ goto error;
+ }
goto invalid_string_error;
}
@@ -5075,6 +5084,9 @@ invalid_iso_midnight:
invalid_string_error:
PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", tstr);
return NULL;
+
+error:
+ return NULL;
}
@@ -5539,8 +5551,9 @@ datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
time_t secs;
int us;
- if (_PyTime_AsTimevalTime_t(ts, &secs, &us, _PyTime_ROUND_FLOOR) < 0)
+ if (_PyTime_AsTimevalTime_t(ts, &secs, &us, _PyTime_ROUND_HALF_EVEN) < 0) {
return NULL;
+ }
assert(0 <= us && us <= 999999);
return datetime_from_timet_and_us(cls, f, secs, us, tzinfo);
@@ -5927,6 +5940,9 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr)
len -= (p - dt_ptr);
rv = parse_isoformat_time(p, len, &hour, &minute, &second,
&microsecond, &tzoffset, &tzusec);
+ if (rv == -6) {
+ goto error;
+ }
}
if (rv < 0) {
goto invalid_string_error;
diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c
index cc65cbd98d7..0cd0f043de4 100644
--- a/Modules/_dbmmodule.c
+++ b/Modules/_dbmmodule.c
@@ -69,6 +69,7 @@ typedef struct {
#include "clinic/_dbmmodule.c.h"
#define check_dbmobject_open(v, err) \
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED((v)) \
if ((v)->di_dbm == NULL) { \
PyErr_SetString(err, "DBM object has already been closed"); \
return NULL; \
@@ -116,7 +117,7 @@ dbm_dealloc(PyObject *self)
}
static Py_ssize_t
-dbm_length(PyObject *self)
+dbm_length_lock_held(PyObject *self)
{
dbmobject *dp = dbmobject_CAST(self);
_dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
@@ -138,8 +139,18 @@ dbm_length(PyObject *self)
return dp->di_size;
}
+static Py_ssize_t
+dbm_length(PyObject *self)
+{
+ Py_ssize_t result;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ result = dbm_length_lock_held(self);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
static int
-dbm_bool(PyObject *self)
+dbm_bool_lock_held(PyObject *self)
{
dbmobject *dp = dbmobject_CAST(self);
_dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
@@ -170,8 +181,18 @@ dbm_bool(PyObject *self)
return 1;
}
+static int
+dbm_bool(PyObject *self)
+{
+ int result;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ result = dbm_bool_lock_held(self);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
static PyObject *
-dbm_subscript(PyObject *self, PyObject *key)
+dbm_subscript_lock_held(PyObject *self, PyObject *key)
{
datum drec, krec;
Py_ssize_t tmp_size;
@@ -197,8 +218,18 @@ dbm_subscript(PyObject *self, PyObject *key)
return PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
}
+static PyObject *
+dbm_subscript(PyObject *self, PyObject *key)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ result = dbm_subscript_lock_held(self, key);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
static int
-dbm_ass_sub(PyObject *self, PyObject *v, PyObject *w)
+dbm_ass_sub_lock_held(PyObject *self, PyObject *v, PyObject *w)
{
datum krec, drec;
Py_ssize_t tmp_size;
@@ -252,7 +283,18 @@ dbm_ass_sub(PyObject *self, PyObject *v, PyObject *w)
return 0;
}
+static int
+dbm_ass_sub(PyObject *self, PyObject *v, PyObject *w)
+{
+ int result;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ result = dbm_ass_sub_lock_held(self, v, w);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
+@critical_section
_dbm.dbm.close
Close the database.
@@ -260,7 +302,7 @@ Close the database.
static PyObject *
_dbm_dbm_close_impl(dbmobject *self)
-/*[clinic end generated code: output=c8dc5b6709600b86 input=046db72377d51be8]*/
+/*[clinic end generated code: output=c8dc5b6709600b86 input=4a94f79facbc28ca]*/
{
if (self->di_dbm) {
dbm_close(self->di_dbm);
@@ -270,6 +312,7 @@ _dbm_dbm_close_impl(dbmobject *self)
}
/*[clinic input]
+@critical_section
_dbm.dbm.keys
cls: defining_class
@@ -279,7 +322,7 @@ Return a list of all keys in the database.
static PyObject *
_dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=f2a593b3038e5996 input=d3706a28fc051097]*/
+/*[clinic end generated code: output=f2a593b3038e5996 input=6ddefeadf2a80156]*/
{
PyObject *v, *item;
datum key;
@@ -310,7 +353,7 @@ _dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls)
}
static int
-dbm_contains(PyObject *self, PyObject *arg)
+dbm_contains_lock_held(PyObject *self, PyObject *arg)
{
dbmobject *dp = dbmobject_CAST(self);
datum key, val;
@@ -343,7 +386,18 @@ dbm_contains(PyObject *self, PyObject *arg)
return val.dptr != NULL;
}
+static int
+dbm_contains(PyObject *self, PyObject *arg)
+{
+ int result;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ result = dbm_contains_lock_held(self, arg);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
+@critical_section
_dbm.dbm.get
cls: defining_class
key: str(accept={str, robuffer}, zeroes=True)
@@ -356,7 +410,7 @@ Return the value for key if present, otherwise default.
static PyObject *
_dbm_dbm_get_impl(dbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_t key_length, PyObject *default_value)
-/*[clinic end generated code: output=b4e55f8b6d482bc4 input=66b993b8349fa8c1]*/
+/*[clinic end generated code: output=b4e55f8b6d482bc4 input=1d88a22bb5e55202]*/
{
datum dbm_key, val;
_dbm_state *state = PyType_GetModuleState(cls);
@@ -373,6 +427,7 @@ _dbm_dbm_get_impl(dbmobject *self, PyTypeObject *cls, const char *key,
}
/*[clinic input]
+@critical_section
_dbm.dbm.setdefault
cls: defining_class
key: str(accept={str, robuffer}, zeroes=True)
@@ -387,7 +442,7 @@ If key is not in the database, it is inserted with default as the value.
static PyObject *
_dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_t key_length, PyObject *default_value)
-/*[clinic end generated code: output=9c2f6ea6d0fb576c input=126a3ff15c5f8232]*/
+/*[clinic end generated code: output=9c2f6ea6d0fb576c input=c01510ef7571e13b]*/
{
datum dbm_key, val;
Py_ssize_t tmp_size;
@@ -427,6 +482,7 @@ _dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key,
}
/*[clinic input]
+@critical_section
_dbm.dbm.clear
cls: defining_class
/
@@ -436,7 +492,7 @@ Remove all items from the database.
static PyObject *
_dbm_dbm_clear_impl(dbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=8d126b9e1d01a434 input=43aa6ca1acb7f5f5]*/
+/*[clinic end generated code: output=8d126b9e1d01a434 input=a1aa5d99adfb9656]*/
{
_dbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index 8c3efa36353..b9e12ab2026 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -17,6 +17,7 @@
#include "Python.h"
#include "pycore_pyhash.h" // _Py_HashSecret
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "expat.h"
@@ -690,8 +691,7 @@ element_dealloc(PyObject *op)
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
/* element_gc_clear clears all references and deallocates extra
*/
@@ -811,6 +811,8 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
PyTypeObject *tp = Py_TYPE(self);
elementtreestate *st = get_elementtree_state_by_type(tp);
+ // The deepcopy() helper takes care of incrementing the refcount
+ // of the object to copy so to avoid use-after-frees.
tag = deepcopy(st, self->tag, memo);
if (!tag)
return NULL;
@@ -845,11 +847,13 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
assert(!element->extra || !element->extra->length);
if (self->extra) {
- if (element_resize(element, self->extra->length) < 0)
+ Py_ssize_t expected_count = self->extra->length;
+ if (element_resize(element, expected_count) < 0) {
+ assert(!element->extra->length);
goto error;
+ }
- // TODO(picnixz): check for an evil child's __deepcopy__ on 'self'
- for (i = 0; i < self->extra->length; i++) {
+ for (i = 0; self->extra && i < self->extra->length; i++) {
PyObject* child = deepcopy(st, self->extra->children[i], memo);
if (!child || !Element_Check(st, child)) {
if (child) {
@@ -859,11 +863,24 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
element->extra->length = i;
goto error;
}
+ if (self->extra && expected_count != self->extra->length) {
+ // 'self->extra' got mutated and 'element' may not have
+ // sufficient space to hold the next iteration's item.
+ expected_count = self->extra->length;
+ if (element_resize(element, expected_count) < 0) {
+ Py_DECREF(child);
+ element->extra->length = i;
+ goto error;
+ }
+ }
element->extra->children[i] = child;
}
assert(!element->extra->length);
- element->extra->length = self->extra->length;
+ // The original 'self->extra' may be gone at this point if deepcopy()
+ // has side-effects. However, 'i' is the number of copied items that
+ // we were able to successfully copy.
+ element->extra->length = i;
}
/* add object to memo dictionary (so deepcopy won't visit it again) */
@@ -906,13 +923,20 @@ deepcopy(elementtreestate *st, PyObject *object, PyObject *memo)
break;
}
}
- if (simple)
+ if (simple) {
return PyDict_Copy(object);
+ }
/* Fall through to general case */
}
else if (Element_CheckExact(st, object)) {
- return _elementtree_Element___deepcopy___impl(
+ // The __deepcopy__() call may call arbitrary code even if the
+ // object to copy is a built-in XML element (one of its children
+ // any of its parents in its own __deepcopy__() implementation).
+ Py_INCREF(object);
+ PyObject *res = _elementtree_Element___deepcopy___impl(
(ElementObject *)object, memo);
+ Py_DECREF(object);
+ return res;
}
}
@@ -923,8 +947,11 @@ deepcopy(elementtreestate *st, PyObject *object, PyObject *memo)
return NULL;
}
+ Py_INCREF(object);
PyObject *args[2] = {object, memo};
- return PyObject_Vectorcall(st->deepcopy_obj, args, 2, NULL);
+ PyObject *res = PyObject_Vectorcall(st->deepcopy_obj, args, 2, NULL);
+ Py_DECREF(object);
+ return res;
}
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index e6c454faf4b..d3dabd58b89 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -7,6 +7,7 @@
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/_functoolsmodule.c.h"
@@ -196,6 +197,19 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
return NULL;
}
+ /* keyword Placeholder prohibition */
+ if (kw != NULL) {
+ PyObject *key, *val;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(kw, &pos, &key, &val)) {
+ if (val == phold) {
+ PyErr_SetString(PyExc_TypeError,
+ "Placeholder cannot be passed as a keyword argument");
+ return NULL;
+ }
+ }
+ }
+
/* check wrapped function / object */
pto_args = pto_kw = NULL;
int res = PyObject_TypeCheck(func, state->partial_type);
@@ -338,9 +352,7 @@ partial_dealloc(PyObject *self)
PyTypeObject *tp = Py_TYPE(self);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
- if (partialobject_CAST(self)->weakreflist != NULL) {
- PyObject_ClearWeakRefs(self);
- }
+ FT_CLEAR_WEAKREFS(self, partialobject_CAST(self)->weakreflist);
(void)partial_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
@@ -1370,8 +1382,8 @@ bounded_lru_cache_update_lock_held(lru_cache_object *self,
this same key, then this setitem call will update the cache dict
with this new link, leaving the old link as an orphan (i.e. not
having a cache dict entry that refers to it). */
- if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
- hash) < 0) {
+ if (_PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)self->cache, key,
+ (PyObject *)link, hash) < 0) {
Py_DECREF(link);
return NULL;
}
@@ -1440,8 +1452,8 @@ bounded_lru_cache_update_lock_held(lru_cache_object *self,
for successful insertion in the cache dict before adding the
link to the linked list. Otherwise, the potentially reentrant
__eq__ call could cause the then orphan link to be visited. */
- if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
- hash) < 0) {
+ if (_PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)self->cache, key,
+ (PyObject *)link, hash) < 0) {
/* Somehow the cache dict update failed. We no longer can
restore the old link. Let the error propagate upward and
leave the cache short one link. */
@@ -1608,9 +1620,7 @@ lru_cache_dealloc(PyObject *op)
PyTypeObject *tp = Py_TYPE(obj);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(obj);
- if (obj->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, obj->weakreflist);
(void)lru_cache_tp_clear(op);
tp->tp_free(obj);
@@ -1676,7 +1686,13 @@ _functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
lru_list_elem *list = lru_cache_unlink_list(_self);
FT_ATOMIC_STORE_SSIZE_RELAXED(_self->hits, 0);
FT_ATOMIC_STORE_SSIZE_RELAXED(_self->misses, 0);
- PyDict_Clear(_self->cache);
+ if (_self->wrapper == bounded_lru_cache_wrapper) {
+ /* The critical section on the lru cache itself protects the dictionary
+ for bounded_lru_cache instances. */
+ _PyDict_Clear_LockHeld(_self->cache);
+ } else {
+ PyDict_Clear(_self->cache);
+ }
lru_cache_clear_list(list);
Py_RETURN_NONE;
}
diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c
index ab2ebdba924..6a4939512b2 100644
--- a/Modules/_gdbmmodule.c
+++ b/Modules/_gdbmmodule.c
@@ -81,6 +81,7 @@ typedef struct {
#include "clinic/_gdbmmodule.c.h"
#define check_gdbmobject_open(v, err) \
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED((v)) \
if ((v)->di_dbm == NULL) { \
PyErr_SetString(err, "GDBM object has already been closed"); \
return NULL; \
@@ -142,7 +143,7 @@ gdbm_dealloc(PyObject *op)
}
static Py_ssize_t
-gdbm_length(PyObject *op)
+gdbm_length_lock_held(PyObject *op)
{
gdbmobject *dp = _gdbmobject_CAST(op);
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
@@ -188,8 +189,18 @@ gdbm_length(PyObject *op)
return dp->di_size;
}
+static Py_ssize_t
+gdbm_length(PyObject *op)
+{
+ Py_ssize_t result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = gdbm_length_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
static int
-gdbm_bool(PyObject *op)
+gdbm_bool_lock_held(PyObject *op)
{
gdbmobject *dp = _gdbmobject_CAST(op);
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
@@ -218,6 +229,16 @@ gdbm_bool(PyObject *op)
return 1;
}
+static int
+gdbm_bool(PyObject *op)
+{
+ int result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = gdbm_bool_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
// Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
// This function is needed to support PY_SSIZE_T_CLEAN.
// Return 1 on success, same to PyArg_Parse().
@@ -240,7 +261,7 @@ parse_datum(PyObject *o, datum *d, const char *failmsg)
}
static PyObject *
-gdbm_subscript(PyObject *op, PyObject *key)
+gdbm_subscript_lock_held(PyObject *op, PyObject *key)
{
PyObject *v;
datum drec, krec;
@@ -265,6 +286,16 @@ gdbm_subscript(PyObject *op, PyObject *key)
return v;
}
+static PyObject *
+gdbm_subscript(PyObject *op, PyObject *key)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = gdbm_subscript_lock_held(op, key);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
_gdbm.gdbm.get
@@ -290,7 +321,7 @@ _gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
}
static int
-gdbm_ass_sub(PyObject *op, PyObject *v, PyObject *w)
+gdbm_ass_sub_lock_held(PyObject *op, PyObject *v, PyObject *w)
{
datum krec, drec;
const char *failmsg = "gdbm mappings have bytes or string indices only";
@@ -335,7 +366,18 @@ gdbm_ass_sub(PyObject *op, PyObject *v, PyObject *w)
return 0;
}
+static int
+gdbm_ass_sub(PyObject *op, PyObject *v, PyObject *w)
+{
+ int result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = gdbm_ass_sub_lock_held(op, v, w);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
+@critical_section
_gdbm.gdbm.setdefault
key: object
@@ -348,7 +390,7 @@ Get value for key, or set it to default and return default if not present.
static PyObject *
_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
PyObject *default_value)
-/*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
+/*[clinic end generated code: output=f3246e880509f142 input=854374cd81ab51b6]*/
{
PyObject *res;
@@ -363,6 +405,7 @@ _gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
}
/*[clinic input]
+@critical_section
_gdbm.gdbm.close
Close the database.
@@ -370,7 +413,7 @@ Close the database.
static PyObject *
_gdbm_gdbm_close_impl(gdbmobject *self)
-/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
+/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=56b604f4e77f533d]*/
{
if (self->di_dbm) {
gdbm_close(self->di_dbm);
@@ -381,6 +424,7 @@ _gdbm_gdbm_close_impl(gdbmobject *self)
/* XXX Should return a set or a set view */
/*[clinic input]
+@critical_section
_gdbm.gdbm.keys
cls: defining_class
@@ -390,7 +434,7 @@ Get a list of all keys in the database.
static PyObject *
_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
+/*[clinic end generated code: output=c24b824e81404755 input=785988b1ea8f77e0]*/
{
PyObject *v, *item;
datum key, nextkey;
@@ -432,7 +476,7 @@ _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
}
static int
-gdbm_contains(PyObject *self, PyObject *arg)
+gdbm_contains_lock_held(PyObject *self, PyObject *arg)
{
gdbmobject *dp = (gdbmobject *)self;
datum key;
@@ -463,7 +507,18 @@ gdbm_contains(PyObject *self, PyObject *arg)
return gdbm_exists(dp->di_dbm, key);
}
+static int
+gdbm_contains(PyObject *self, PyObject *arg)
+{
+ int result;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ result = gdbm_contains_lock_held(self, arg);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
+@critical_section
_gdbm.gdbm.firstkey
cls: defining_class
@@ -477,7 +532,7 @@ hash values, and won't be sorted by the key values.
static PyObject *
_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
+/*[clinic end generated code: output=139275e9c8b60827 input=aad5a7c886c542f5]*/
{
PyObject *v;
datum key;
@@ -497,6 +552,7 @@ _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
}
/*[clinic input]
+@critical_section
_gdbm.gdbm.nextkey
cls: defining_class
@@ -517,7 +573,7 @@ to create a list in memory that contains them all:
static PyObject *
_gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_t key_length)
-/*[clinic end generated code: output=c81a69300ef41766 input=365e297bc0b3db48]*/
+/*[clinic end generated code: output=c81a69300ef41766 input=181f1130d5bfeb1e]*/
{
PyObject *v;
datum dbm_key, nextkey;
@@ -539,6 +595,7 @@ _gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
}
/*[clinic input]
+@critical_section
_gdbm.gdbm.reorganize
cls: defining_class
@@ -554,7 +611,7 @@ kept and reused as new (key,value) pairs are added.
static PyObject *
_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
+/*[clinic end generated code: output=d77c69e8e3dd644a input=3e3ca0d2ea787861]*/
{
_gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
@@ -573,6 +630,7 @@ _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
}
/*[clinic input]
+@critical_section
_gdbm.gdbm.sync
cls: defining_class
@@ -585,7 +643,7 @@ any unwritten data to be written to the disk.
static PyObject *
_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
+/*[clinic end generated code: output=bb680a2035c3f592 input=6054385b071d238a]*/
{
_gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
@@ -595,6 +653,7 @@ _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
}
/*[clinic input]
+@critical_section
_gdbm.gdbm.clear
cls: defining_class
/
@@ -604,7 +663,7 @@ Remove all items from the database.
static PyObject *
_gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls)
-/*[clinic end generated code: output=673577c573318661 input=34136d52fcdd4210]*/
+/*[clinic end generated code: output=673577c573318661 input=b17467adfe62f23d]*/
{
_gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
@@ -755,6 +814,11 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
iflags |= GDBM_NOLOCK;
break;
#endif
+#ifdef GDBM_NOMMAP
+ case 'm':
+ iflags |= GDBM_NOMMAP;
+ break;
+#endif
default:
PyErr_Format(state->gdbm_error,
"Flag '%c' is not supported.", (unsigned char)*flags);
@@ -788,6 +852,9 @@ static const char gdbmmodule_open_flags[] = "rwcn"
#ifdef GDBM_NOLOCK
"u"
#endif
+#ifdef GDBM_NOMMAP
+ "m"
+#endif
;
static PyMethodDef _gdbm_module_methods[] = {
diff --git a/Modules/_hacl/Hacl_Hash_Blake2b.c b/Modules/_hacl/Hacl_Hash_Blake2b.c
index 21ab2b88c79..a5b75d61798 100644
--- a/Modules/_hacl/Hacl_Hash_Blake2b.c
+++ b/Modules/_hacl/Hacl_Hash_Blake2b.c
@@ -544,11 +544,9 @@ void Hacl_Hash_Blake2b_init(uint64_t *hash, uint32_t kk, uint32_t nn)
uint64_t x = r;
os[i] = x;);
tmp[0U] =
- (uint64_t)nn1
- ^
- ((uint64_t)kk1
- << 8U
- ^ ((uint64_t)p.fanout << 16U ^ ((uint64_t)p.depth << 24U ^ (uint64_t)p.leaf_length << 32U)));
+ (uint64_t)nn1 ^
+ ((uint64_t)kk1 << 8U ^
+ ((uint64_t)p.fanout << 16U ^ ((uint64_t)p.depth << 24U ^ (uint64_t)p.leaf_length << 32U)));
tmp[1U] = p.node_offset;
tmp[2U] = (uint64_t)p.node_depth ^ (uint64_t)p.inner_length << 8U;
tmp[3U] = 0ULL;
@@ -860,14 +858,10 @@ static Hacl_Hash_Blake2b_state_t
uint64_t x = r4;
os[i0] = x;);
tmp[0U] =
- (uint64_t)nn1
- ^
- ((uint64_t)kk2
- << 8U
- ^
- ((uint64_t)pv.fanout
- << 16U
- ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
+ (uint64_t)nn1 ^
+ ((uint64_t)kk2 << 8U ^
+ ((uint64_t)pv.fanout << 16U ^
+ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
tmp[1U] = pv.node_offset;
tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U;
tmp[3U] = 0ULL;
@@ -1059,11 +1053,9 @@ static void reset_raw(Hacl_Hash_Blake2b_state_t *state, Hacl_Hash_Blake2b_params
uint64_t x = r;
os[i0] = x;);
tmp[0U] =
- (uint64_t)nn1
- ^
- ((uint64_t)kk2
- << 8U
- ^ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
+ (uint64_t)nn1 ^
+ ((uint64_t)kk2 << 8U ^
+ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
tmp[1U] = pv.node_offset;
tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U;
tmp[3U] = 0ULL;
@@ -1200,8 +1192,7 @@ Hacl_Hash_Blake2b_update(Hacl_Hash_Blake2b_state_t *state, uint8_t *chunk, uint3
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_state_t){
.block_state = block_state1,
@@ -1265,8 +1256,7 @@ Hacl_Hash_Blake2b_update(Hacl_Hash_Blake2b_state_t *state, uint8_t *chunk, uint3
nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_state_t){
.block_state = block_state1,
@@ -1296,8 +1286,7 @@ Hacl_Hash_Blake2b_update(Hacl_Hash_Blake2b_state_t *state, uint8_t *chunk, uint3
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_state_t){
.block_state = block_state10,
@@ -1359,8 +1348,7 @@ Hacl_Hash_Blake2b_update(Hacl_Hash_Blake2b_state_t *state, uint8_t *chunk, uint3
nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_state_t){
.block_state = block_state1,
@@ -1690,14 +1678,10 @@ Hacl_Hash_Blake2b_hash_with_key_and_params(
uint64_t x = r;
os[i] = x;);
tmp[0U] =
- (uint64_t)nn
- ^
- ((uint64_t)kk
- << 8U
- ^
- ((uint64_t)params.fanout
- << 16U
- ^ ((uint64_t)params.depth << 24U ^ (uint64_t)params.leaf_length << 32U)));
+ (uint64_t)nn ^
+ ((uint64_t)kk << 8U ^
+ ((uint64_t)params.fanout << 16U ^
+ ((uint64_t)params.depth << 24U ^ (uint64_t)params.leaf_length << 32U)));
tmp[1U] = params.node_offset;
tmp[2U] = (uint64_t)params.node_depth ^ (uint64_t)params.inner_length << 8U;
tmp[3U] = 0ULL;
diff --git a/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c b/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c
index c4d9b4a689d..f955f1c6115 100644
--- a/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c
+++ b/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c
@@ -274,11 +274,9 @@ Hacl_Hash_Blake2b_Simd256_init(Lib_IntVector_Intrinsics_vec256 *hash, uint32_t k
uint64_t x = r;
os[i] = x;);
tmp[0U] =
- (uint64_t)nn1
- ^
- ((uint64_t)kk1
- << 8U
- ^ ((uint64_t)p.fanout << 16U ^ ((uint64_t)p.depth << 24U ^ (uint64_t)p.leaf_length << 32U)));
+ (uint64_t)nn1 ^
+ ((uint64_t)kk1 << 8U ^
+ ((uint64_t)p.fanout << 16U ^ ((uint64_t)p.depth << 24U ^ (uint64_t)p.leaf_length << 32U)));
tmp[1U] = p.node_offset;
tmp[2U] = (uint64_t)p.node_depth ^ (uint64_t)p.inner_length << 8U;
tmp[3U] = 0ULL;
@@ -746,14 +744,10 @@ static Hacl_Hash_Blake2b_Simd256_state_t
uint64_t x = r4;
os[i0] = x;);
tmp[0U] =
- (uint64_t)nn1
- ^
- ((uint64_t)kk2
- << 8U
- ^
- ((uint64_t)pv.fanout
- << 16U
- ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
+ (uint64_t)nn1 ^
+ ((uint64_t)kk2 << 8U ^
+ ((uint64_t)pv.fanout << 16U ^
+ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
tmp[1U] = pv.node_offset;
tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U;
tmp[3U] = 0ULL;
@@ -936,11 +930,9 @@ reset_raw(Hacl_Hash_Blake2b_Simd256_state_t *state, Hacl_Hash_Blake2b_params_and
uint64_t x = r;
os[i0] = x;);
tmp[0U] =
- (uint64_t)nn1
- ^
- ((uint64_t)kk2
- << 8U
- ^ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
+ (uint64_t)nn1 ^
+ ((uint64_t)kk2 << 8U ^
+ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U)));
tmp[1U] = pv.node_offset;
tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U;
tmp[3U] = 0ULL;
@@ -1075,8 +1067,7 @@ Hacl_Hash_Blake2b_Simd256_update(
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_Simd256_state_t){
.block_state = block_state1,
@@ -1140,8 +1131,7 @@ Hacl_Hash_Blake2b_Simd256_update(
nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_Simd256_state_t){
.block_state = block_state1,
@@ -1171,8 +1161,7 @@ Hacl_Hash_Blake2b_Simd256_update(
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_Simd256_state_t){
.block_state = block_state10,
@@ -1234,8 +1223,7 @@ Hacl_Hash_Blake2b_Simd256_update(
nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2b_Simd256_state_t){
.block_state = block_state1,
@@ -1578,14 +1566,10 @@ Hacl_Hash_Blake2b_Simd256_hash_with_key_and_params(
uint64_t x = r;
os[i] = x;);
tmp[0U] =
- (uint64_t)nn
- ^
- ((uint64_t)kk
- << 8U
- ^
- ((uint64_t)params.fanout
- << 16U
- ^ ((uint64_t)params.depth << 24U ^ (uint64_t)params.leaf_length << 32U)));
+ (uint64_t)nn ^
+ ((uint64_t)kk << 8U ^
+ ((uint64_t)params.fanout << 16U ^
+ ((uint64_t)params.depth << 24U ^ (uint64_t)params.leaf_length << 32U)));
tmp[1U] = params.node_offset;
tmp[2U] = (uint64_t)params.node_depth ^ (uint64_t)params.inner_length << 8U;
tmp[3U] = 0ULL;
diff --git a/Modules/_hacl/Hacl_Hash_Blake2s.c b/Modules/_hacl/Hacl_Hash_Blake2s.c
index 730ba135afb..0d4fcc7f395 100644
--- a/Modules/_hacl/Hacl_Hash_Blake2s.c
+++ b/Modules/_hacl/Hacl_Hash_Blake2s.c
@@ -543,13 +543,13 @@ void Hacl_Hash_Blake2s_init(uint32_t *hash, uint32_t kk, uint32_t nn)
uint32_t x = r;
os[i] = x;);
tmp[0U] =
- (uint32_t)(uint8_t)nn
- ^ ((uint32_t)(uint8_t)kk << 8U ^ ((uint32_t)p.fanout << 16U ^ (uint32_t)p.depth << 24U));
+ (uint32_t)(uint8_t)nn ^
+ ((uint32_t)(uint8_t)kk << 8U ^ ((uint32_t)p.fanout << 16U ^ (uint32_t)p.depth << 24U));
tmp[1U] = p.leaf_length;
tmp[2U] = (uint32_t)p.node_offset;
tmp[3U] =
- (uint32_t)(p.node_offset >> 32U)
- ^ ((uint32_t)p.node_depth << 16U ^ (uint32_t)p.inner_length << 24U);
+ (uint32_t)(p.node_offset >> 32U) ^
+ ((uint32_t)p.node_depth << 16U ^ (uint32_t)p.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
@@ -846,16 +846,14 @@ static Hacl_Hash_Blake2s_state_t
uint32_t x = r4;
os[i0] = x;);
tmp[0U] =
- (uint32_t)pv.digest_length
- ^
- ((uint32_t)pv.key_length
- << 8U
- ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
+ (uint32_t)pv.digest_length ^
+ ((uint32_t)pv.key_length << 8U ^
+ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
tmp[1U] = pv.leaf_length;
tmp[2U] = (uint32_t)pv.node_offset;
tmp[3U] =
- (uint32_t)(pv.node_offset >> 32U)
- ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
+ (uint32_t)(pv.node_offset >> 32U) ^
+ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
@@ -1042,13 +1040,13 @@ static void reset_raw(Hacl_Hash_Blake2s_state_t *state, Hacl_Hash_Blake2b_params
uint32_t x = r;
os[i0] = x;);
tmp[0U] =
- (uint32_t)pv.digest_length
- ^ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
+ (uint32_t)pv.digest_length ^
+ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
tmp[1U] = pv.leaf_length;
tmp[2U] = (uint32_t)pv.node_offset;
tmp[3U] =
- (uint32_t)(pv.node_offset >> 32U)
- ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
+ (uint32_t)(pv.node_offset >> 32U) ^
+ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
@@ -1182,8 +1180,7 @@ Hacl_Hash_Blake2s_update(Hacl_Hash_Blake2s_state_t *state, uint8_t *chunk, uint3
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_state_t){
.block_state = block_state1,
@@ -1237,8 +1234,7 @@ Hacl_Hash_Blake2s_update(Hacl_Hash_Blake2s_state_t *state, uint8_t *chunk, uint3
Hacl_Hash_Blake2s_update_multi(data1_len, wv, hash, total_len1, data1, nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_state_t){
.block_state = block_state1,
@@ -1268,8 +1264,7 @@ Hacl_Hash_Blake2s_update(Hacl_Hash_Blake2s_state_t *state, uint8_t *chunk, uint3
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_state_t){
.block_state = block_state10,
@@ -1321,8 +1316,7 @@ Hacl_Hash_Blake2s_update(Hacl_Hash_Blake2s_state_t *state, uint8_t *chunk, uint3
Hacl_Hash_Blake2s_update_multi(data1_len, wv, hash, total_len1, data1, nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_state_t){
.block_state = block_state1,
@@ -1639,16 +1633,14 @@ Hacl_Hash_Blake2s_hash_with_key_and_params(
uint32_t x = r;
os[i] = x;);
tmp[0U] =
- (uint32_t)params.digest_length
- ^
- ((uint32_t)params.key_length
- << 8U
- ^ ((uint32_t)params.fanout << 16U ^ (uint32_t)params.depth << 24U));
+ (uint32_t)params.digest_length ^
+ ((uint32_t)params.key_length << 8U ^
+ ((uint32_t)params.fanout << 16U ^ (uint32_t)params.depth << 24U));
tmp[1U] = params.leaf_length;
tmp[2U] = (uint32_t)params.node_offset;
tmp[3U] =
- (uint32_t)(params.node_offset >> 32U)
- ^ ((uint32_t)params.node_depth << 16U ^ (uint32_t)params.inner_length << 24U);
+ (uint32_t)(params.node_offset >> 32U) ^
+ ((uint32_t)params.node_depth << 16U ^ (uint32_t)params.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
diff --git a/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c b/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c
index 7e9cd79544f..fa46be045f3 100644
--- a/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c
+++ b/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c
@@ -271,13 +271,13 @@ Hacl_Hash_Blake2s_Simd128_init(Lib_IntVector_Intrinsics_vec128 *hash, uint32_t k
uint32_t x = r;
os[i] = x;);
tmp[0U] =
- (uint32_t)(uint8_t)nn
- ^ ((uint32_t)(uint8_t)kk << 8U ^ ((uint32_t)p.fanout << 16U ^ (uint32_t)p.depth << 24U));
+ (uint32_t)(uint8_t)nn ^
+ ((uint32_t)(uint8_t)kk << 8U ^ ((uint32_t)p.fanout << 16U ^ (uint32_t)p.depth << 24U));
tmp[1U] = p.leaf_length;
tmp[2U] = (uint32_t)p.node_offset;
tmp[3U] =
- (uint32_t)(p.node_offset >> 32U)
- ^ ((uint32_t)p.node_depth << 16U ^ (uint32_t)p.inner_length << 24U);
+ (uint32_t)(p.node_offset >> 32U) ^
+ ((uint32_t)p.node_depth << 16U ^ (uint32_t)p.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
@@ -736,16 +736,14 @@ static Hacl_Hash_Blake2s_Simd128_state_t
uint32_t x = r4;
os[i0] = x;);
tmp[0U] =
- (uint32_t)pv.digest_length
- ^
- ((uint32_t)pv.key_length
- << 8U
- ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
+ (uint32_t)pv.digest_length ^
+ ((uint32_t)pv.key_length << 8U ^
+ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
tmp[1U] = pv.leaf_length;
tmp[2U] = (uint32_t)pv.node_offset;
tmp[3U] =
- (uint32_t)(pv.node_offset >> 32U)
- ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
+ (uint32_t)(pv.node_offset >> 32U) ^
+ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
@@ -923,13 +921,13 @@ reset_raw(Hacl_Hash_Blake2s_Simd128_state_t *state, Hacl_Hash_Blake2b_params_and
uint32_t x = r;
os[i0] = x;);
tmp[0U] =
- (uint32_t)pv.digest_length
- ^ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
+ (uint32_t)pv.digest_length ^
+ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U));
tmp[1U] = pv.leaf_length;
tmp[2U] = (uint32_t)pv.node_offset;
tmp[3U] =
- (uint32_t)(pv.node_offset >> 32U)
- ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
+ (uint32_t)(pv.node_offset >> 32U) ^
+ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
@@ -1061,8 +1059,7 @@ Hacl_Hash_Blake2s_Simd128_update(
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_Simd128_state_t){
.block_state = block_state1,
@@ -1116,8 +1113,7 @@ Hacl_Hash_Blake2s_Simd128_update(
Hacl_Hash_Blake2s_Simd128_update_multi(data1_len, wv, hash, total_len1, data1, nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_Simd128_state_t){
.block_state = block_state1,
@@ -1147,8 +1143,7 @@ Hacl_Hash_Blake2s_Simd128_update(
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_Simd128_state_t){
.block_state = block_state10,
@@ -1200,8 +1195,7 @@ Hacl_Hash_Blake2s_Simd128_update(
Hacl_Hash_Blake2s_Simd128_update_multi(data1_len, wv, hash, total_len1, data1, nb);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_Blake2s_Simd128_state_t){
.block_state = block_state1,
@@ -1531,16 +1525,14 @@ Hacl_Hash_Blake2s_Simd128_hash_with_key_and_params(
uint32_t x = r;
os[i] = x;);
tmp[0U] =
- (uint32_t)params.digest_length
- ^
- ((uint32_t)params.key_length
- << 8U
- ^ ((uint32_t)params.fanout << 16U ^ (uint32_t)params.depth << 24U));
+ (uint32_t)params.digest_length ^
+ ((uint32_t)params.key_length << 8U ^
+ ((uint32_t)params.fanout << 16U ^ (uint32_t)params.depth << 24U));
tmp[1U] = params.leaf_length;
tmp[2U] = (uint32_t)params.node_offset;
tmp[3U] =
- (uint32_t)(params.node_offset >> 32U)
- ^ ((uint32_t)params.node_depth << 16U ^ (uint32_t)params.inner_length << 24U);
+ (uint32_t)(params.node_offset >> 32U) ^
+ ((uint32_t)params.node_depth << 16U ^ (uint32_t)params.inner_length << 24U);
uint32_t tmp0 = tmp[0U];
uint32_t tmp1 = tmp[1U];
uint32_t tmp2 = tmp[2U];
diff --git a/Modules/_hacl/Hacl_Hash_MD5.c b/Modules/_hacl/Hacl_Hash_MD5.c
index 75ce8d2926e..305c75483c0 100644
--- a/Modules/_hacl/Hacl_Hash_MD5.c
+++ b/Modules/_hacl/Hacl_Hash_MD5.c
@@ -66,11 +66,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti0 = _t[0U];
uint32_t
v =
- vb0
- +
- ((va + ((vb0 & vc0) | (~vb0 & vd0)) + xk + ti0)
- << 7U
- | (va + ((vb0 & vc0) | (~vb0 & vd0)) + xk + ti0) >> 25U);
+ vb0 +
+ ((va + ((vb0 & vc0) | (~vb0 & vd0)) + xk + ti0) << 7U |
+ (va + ((vb0 & vc0) | (~vb0 & vd0)) + xk + ti0) >> 25U);
abcd[0U] = v;
uint32_t va0 = abcd[3U];
uint32_t vb1 = abcd[0U];
@@ -82,11 +80,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti1 = _t[1U];
uint32_t
v0 =
- vb1
- +
- ((va0 + ((vb1 & vc1) | (~vb1 & vd1)) + xk0 + ti1)
- << 12U
- | (va0 + ((vb1 & vc1) | (~vb1 & vd1)) + xk0 + ti1) >> 20U);
+ vb1 +
+ ((va0 + ((vb1 & vc1) | (~vb1 & vd1)) + xk0 + ti1) << 12U |
+ (va0 + ((vb1 & vc1) | (~vb1 & vd1)) + xk0 + ti1) >> 20U);
abcd[3U] = v0;
uint32_t va1 = abcd[2U];
uint32_t vb2 = abcd[3U];
@@ -98,11 +94,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti2 = _t[2U];
uint32_t
v1 =
- vb2
- +
- ((va1 + ((vb2 & vc2) | (~vb2 & vd2)) + xk1 + ti2)
- << 17U
- | (va1 + ((vb2 & vc2) | (~vb2 & vd2)) + xk1 + ti2) >> 15U);
+ vb2 +
+ ((va1 + ((vb2 & vc2) | (~vb2 & vd2)) + xk1 + ti2) << 17U |
+ (va1 + ((vb2 & vc2) | (~vb2 & vd2)) + xk1 + ti2) >> 15U);
abcd[2U] = v1;
uint32_t va2 = abcd[1U];
uint32_t vb3 = abcd[2U];
@@ -114,11 +108,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti3 = _t[3U];
uint32_t
v2 =
- vb3
- +
- ((va2 + ((vb3 & vc3) | (~vb3 & vd3)) + xk2 + ti3)
- << 22U
- | (va2 + ((vb3 & vc3) | (~vb3 & vd3)) + xk2 + ti3) >> 10U);
+ vb3 +
+ ((va2 + ((vb3 & vc3) | (~vb3 & vd3)) + xk2 + ti3) << 22U |
+ (va2 + ((vb3 & vc3) | (~vb3 & vd3)) + xk2 + ti3) >> 10U);
abcd[1U] = v2;
uint32_t va3 = abcd[0U];
uint32_t vb4 = abcd[1U];
@@ -130,11 +122,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti4 = _t[4U];
uint32_t
v3 =
- vb4
- +
- ((va3 + ((vb4 & vc4) | (~vb4 & vd4)) + xk3 + ti4)
- << 7U
- | (va3 + ((vb4 & vc4) | (~vb4 & vd4)) + xk3 + ti4) >> 25U);
+ vb4 +
+ ((va3 + ((vb4 & vc4) | (~vb4 & vd4)) + xk3 + ti4) << 7U |
+ (va3 + ((vb4 & vc4) | (~vb4 & vd4)) + xk3 + ti4) >> 25U);
abcd[0U] = v3;
uint32_t va4 = abcd[3U];
uint32_t vb5 = abcd[0U];
@@ -146,11 +136,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti5 = _t[5U];
uint32_t
v4 =
- vb5
- +
- ((va4 + ((vb5 & vc5) | (~vb5 & vd5)) + xk4 + ti5)
- << 12U
- | (va4 + ((vb5 & vc5) | (~vb5 & vd5)) + xk4 + ti5) >> 20U);
+ vb5 +
+ ((va4 + ((vb5 & vc5) | (~vb5 & vd5)) + xk4 + ti5) << 12U |
+ (va4 + ((vb5 & vc5) | (~vb5 & vd5)) + xk4 + ti5) >> 20U);
abcd[3U] = v4;
uint32_t va5 = abcd[2U];
uint32_t vb6 = abcd[3U];
@@ -162,11 +150,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti6 = _t[6U];
uint32_t
v5 =
- vb6
- +
- ((va5 + ((vb6 & vc6) | (~vb6 & vd6)) + xk5 + ti6)
- << 17U
- | (va5 + ((vb6 & vc6) | (~vb6 & vd6)) + xk5 + ti6) >> 15U);
+ vb6 +
+ ((va5 + ((vb6 & vc6) | (~vb6 & vd6)) + xk5 + ti6) << 17U |
+ (va5 + ((vb6 & vc6) | (~vb6 & vd6)) + xk5 + ti6) >> 15U);
abcd[2U] = v5;
uint32_t va6 = abcd[1U];
uint32_t vb7 = abcd[2U];
@@ -178,11 +164,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti7 = _t[7U];
uint32_t
v6 =
- vb7
- +
- ((va6 + ((vb7 & vc7) | (~vb7 & vd7)) + xk6 + ti7)
- << 22U
- | (va6 + ((vb7 & vc7) | (~vb7 & vd7)) + xk6 + ti7) >> 10U);
+ vb7 +
+ ((va6 + ((vb7 & vc7) | (~vb7 & vd7)) + xk6 + ti7) << 22U |
+ (va6 + ((vb7 & vc7) | (~vb7 & vd7)) + xk6 + ti7) >> 10U);
abcd[1U] = v6;
uint32_t va7 = abcd[0U];
uint32_t vb8 = abcd[1U];
@@ -194,11 +178,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti8 = _t[8U];
uint32_t
v7 =
- vb8
- +
- ((va7 + ((vb8 & vc8) | (~vb8 & vd8)) + xk7 + ti8)
- << 7U
- | (va7 + ((vb8 & vc8) | (~vb8 & vd8)) + xk7 + ti8) >> 25U);
+ vb8 +
+ ((va7 + ((vb8 & vc8) | (~vb8 & vd8)) + xk7 + ti8) << 7U |
+ (va7 + ((vb8 & vc8) | (~vb8 & vd8)) + xk7 + ti8) >> 25U);
abcd[0U] = v7;
uint32_t va8 = abcd[3U];
uint32_t vb9 = abcd[0U];
@@ -210,11 +192,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti9 = _t[9U];
uint32_t
v8 =
- vb9
- +
- ((va8 + ((vb9 & vc9) | (~vb9 & vd9)) + xk8 + ti9)
- << 12U
- | (va8 + ((vb9 & vc9) | (~vb9 & vd9)) + xk8 + ti9) >> 20U);
+ vb9 +
+ ((va8 + ((vb9 & vc9) | (~vb9 & vd9)) + xk8 + ti9) << 12U |
+ (va8 + ((vb9 & vc9) | (~vb9 & vd9)) + xk8 + ti9) >> 20U);
abcd[3U] = v8;
uint32_t va9 = abcd[2U];
uint32_t vb10 = abcd[3U];
@@ -226,11 +206,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti10 = _t[10U];
uint32_t
v9 =
- vb10
- +
- ((va9 + ((vb10 & vc10) | (~vb10 & vd10)) + xk9 + ti10)
- << 17U
- | (va9 + ((vb10 & vc10) | (~vb10 & vd10)) + xk9 + ti10) >> 15U);
+ vb10 +
+ ((va9 + ((vb10 & vc10) | (~vb10 & vd10)) + xk9 + ti10) << 17U |
+ (va9 + ((vb10 & vc10) | (~vb10 & vd10)) + xk9 + ti10) >> 15U);
abcd[2U] = v9;
uint32_t va10 = abcd[1U];
uint32_t vb11 = abcd[2U];
@@ -242,11 +220,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti11 = _t[11U];
uint32_t
v10 =
- vb11
- +
- ((va10 + ((vb11 & vc11) | (~vb11 & vd11)) + xk10 + ti11)
- << 22U
- | (va10 + ((vb11 & vc11) | (~vb11 & vd11)) + xk10 + ti11) >> 10U);
+ vb11 +
+ ((va10 + ((vb11 & vc11) | (~vb11 & vd11)) + xk10 + ti11) << 22U |
+ (va10 + ((vb11 & vc11) | (~vb11 & vd11)) + xk10 + ti11) >> 10U);
abcd[1U] = v10;
uint32_t va11 = abcd[0U];
uint32_t vb12 = abcd[1U];
@@ -258,11 +234,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti12 = _t[12U];
uint32_t
v11 =
- vb12
- +
- ((va11 + ((vb12 & vc12) | (~vb12 & vd12)) + xk11 + ti12)
- << 7U
- | (va11 + ((vb12 & vc12) | (~vb12 & vd12)) + xk11 + ti12) >> 25U);
+ vb12 +
+ ((va11 + ((vb12 & vc12) | (~vb12 & vd12)) + xk11 + ti12) << 7U |
+ (va11 + ((vb12 & vc12) | (~vb12 & vd12)) + xk11 + ti12) >> 25U);
abcd[0U] = v11;
uint32_t va12 = abcd[3U];
uint32_t vb13 = abcd[0U];
@@ -274,11 +248,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti13 = _t[13U];
uint32_t
v12 =
- vb13
- +
- ((va12 + ((vb13 & vc13) | (~vb13 & vd13)) + xk12 + ti13)
- << 12U
- | (va12 + ((vb13 & vc13) | (~vb13 & vd13)) + xk12 + ti13) >> 20U);
+ vb13 +
+ ((va12 + ((vb13 & vc13) | (~vb13 & vd13)) + xk12 + ti13) << 12U |
+ (va12 + ((vb13 & vc13) | (~vb13 & vd13)) + xk12 + ti13) >> 20U);
abcd[3U] = v12;
uint32_t va13 = abcd[2U];
uint32_t vb14 = abcd[3U];
@@ -290,11 +262,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti14 = _t[14U];
uint32_t
v13 =
- vb14
- +
- ((va13 + ((vb14 & vc14) | (~vb14 & vd14)) + xk13 + ti14)
- << 17U
- | (va13 + ((vb14 & vc14) | (~vb14 & vd14)) + xk13 + ti14) >> 15U);
+ vb14 +
+ ((va13 + ((vb14 & vc14) | (~vb14 & vd14)) + xk13 + ti14) << 17U |
+ (va13 + ((vb14 & vc14) | (~vb14 & vd14)) + xk13 + ti14) >> 15U);
abcd[2U] = v13;
uint32_t va14 = abcd[1U];
uint32_t vb15 = abcd[2U];
@@ -306,11 +276,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti15 = _t[15U];
uint32_t
v14 =
- vb15
- +
- ((va14 + ((vb15 & vc15) | (~vb15 & vd15)) + xk14 + ti15)
- << 22U
- | (va14 + ((vb15 & vc15) | (~vb15 & vd15)) + xk14 + ti15) >> 10U);
+ vb15 +
+ ((va14 + ((vb15 & vc15) | (~vb15 & vd15)) + xk14 + ti15) << 22U |
+ (va14 + ((vb15 & vc15) | (~vb15 & vd15)) + xk14 + ti15) >> 10U);
abcd[1U] = v14;
uint32_t va15 = abcd[0U];
uint32_t vb16 = abcd[1U];
@@ -322,11 +290,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti16 = _t[16U];
uint32_t
v15 =
- vb16
- +
- ((va15 + ((vb16 & vd16) | (vc16 & ~vd16)) + xk15 + ti16)
- << 5U
- | (va15 + ((vb16 & vd16) | (vc16 & ~vd16)) + xk15 + ti16) >> 27U);
+ vb16 +
+ ((va15 + ((vb16 & vd16) | (vc16 & ~vd16)) + xk15 + ti16) << 5U |
+ (va15 + ((vb16 & vd16) | (vc16 & ~vd16)) + xk15 + ti16) >> 27U);
abcd[0U] = v15;
uint32_t va16 = abcd[3U];
uint32_t vb17 = abcd[0U];
@@ -338,11 +304,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti17 = _t[17U];
uint32_t
v16 =
- vb17
- +
- ((va16 + ((vb17 & vd17) | (vc17 & ~vd17)) + xk16 + ti17)
- << 9U
- | (va16 + ((vb17 & vd17) | (vc17 & ~vd17)) + xk16 + ti17) >> 23U);
+ vb17 +
+ ((va16 + ((vb17 & vd17) | (vc17 & ~vd17)) + xk16 + ti17) << 9U |
+ (va16 + ((vb17 & vd17) | (vc17 & ~vd17)) + xk16 + ti17) >> 23U);
abcd[3U] = v16;
uint32_t va17 = abcd[2U];
uint32_t vb18 = abcd[3U];
@@ -354,11 +318,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti18 = _t[18U];
uint32_t
v17 =
- vb18
- +
- ((va17 + ((vb18 & vd18) | (vc18 & ~vd18)) + xk17 + ti18)
- << 14U
- | (va17 + ((vb18 & vd18) | (vc18 & ~vd18)) + xk17 + ti18) >> 18U);
+ vb18 +
+ ((va17 + ((vb18 & vd18) | (vc18 & ~vd18)) + xk17 + ti18) << 14U |
+ (va17 + ((vb18 & vd18) | (vc18 & ~vd18)) + xk17 + ti18) >> 18U);
abcd[2U] = v17;
uint32_t va18 = abcd[1U];
uint32_t vb19 = abcd[2U];
@@ -370,11 +332,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti19 = _t[19U];
uint32_t
v18 =
- vb19
- +
- ((va18 + ((vb19 & vd19) | (vc19 & ~vd19)) + xk18 + ti19)
- << 20U
- | (va18 + ((vb19 & vd19) | (vc19 & ~vd19)) + xk18 + ti19) >> 12U);
+ vb19 +
+ ((va18 + ((vb19 & vd19) | (vc19 & ~vd19)) + xk18 + ti19) << 20U |
+ (va18 + ((vb19 & vd19) | (vc19 & ~vd19)) + xk18 + ti19) >> 12U);
abcd[1U] = v18;
uint32_t va19 = abcd[0U];
uint32_t vb20 = abcd[1U];
@@ -386,11 +346,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti20 = _t[20U];
uint32_t
v19 =
- vb20
- +
- ((va19 + ((vb20 & vd20) | (vc20 & ~vd20)) + xk19 + ti20)
- << 5U
- | (va19 + ((vb20 & vd20) | (vc20 & ~vd20)) + xk19 + ti20) >> 27U);
+ vb20 +
+ ((va19 + ((vb20 & vd20) | (vc20 & ~vd20)) + xk19 + ti20) << 5U |
+ (va19 + ((vb20 & vd20) | (vc20 & ~vd20)) + xk19 + ti20) >> 27U);
abcd[0U] = v19;
uint32_t va20 = abcd[3U];
uint32_t vb21 = abcd[0U];
@@ -402,11 +360,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti21 = _t[21U];
uint32_t
v20 =
- vb21
- +
- ((va20 + ((vb21 & vd21) | (vc21 & ~vd21)) + xk20 + ti21)
- << 9U
- | (va20 + ((vb21 & vd21) | (vc21 & ~vd21)) + xk20 + ti21) >> 23U);
+ vb21 +
+ ((va20 + ((vb21 & vd21) | (vc21 & ~vd21)) + xk20 + ti21) << 9U |
+ (va20 + ((vb21 & vd21) | (vc21 & ~vd21)) + xk20 + ti21) >> 23U);
abcd[3U] = v20;
uint32_t va21 = abcd[2U];
uint32_t vb22 = abcd[3U];
@@ -418,11 +374,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti22 = _t[22U];
uint32_t
v21 =
- vb22
- +
- ((va21 + ((vb22 & vd22) | (vc22 & ~vd22)) + xk21 + ti22)
- << 14U
- | (va21 + ((vb22 & vd22) | (vc22 & ~vd22)) + xk21 + ti22) >> 18U);
+ vb22 +
+ ((va21 + ((vb22 & vd22) | (vc22 & ~vd22)) + xk21 + ti22) << 14U |
+ (va21 + ((vb22 & vd22) | (vc22 & ~vd22)) + xk21 + ti22) >> 18U);
abcd[2U] = v21;
uint32_t va22 = abcd[1U];
uint32_t vb23 = abcd[2U];
@@ -434,11 +388,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti23 = _t[23U];
uint32_t
v22 =
- vb23
- +
- ((va22 + ((vb23 & vd23) | (vc23 & ~vd23)) + xk22 + ti23)
- << 20U
- | (va22 + ((vb23 & vd23) | (vc23 & ~vd23)) + xk22 + ti23) >> 12U);
+ vb23 +
+ ((va22 + ((vb23 & vd23) | (vc23 & ~vd23)) + xk22 + ti23) << 20U |
+ (va22 + ((vb23 & vd23) | (vc23 & ~vd23)) + xk22 + ti23) >> 12U);
abcd[1U] = v22;
uint32_t va23 = abcd[0U];
uint32_t vb24 = abcd[1U];
@@ -450,11 +402,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti24 = _t[24U];
uint32_t
v23 =
- vb24
- +
- ((va23 + ((vb24 & vd24) | (vc24 & ~vd24)) + xk23 + ti24)
- << 5U
- | (va23 + ((vb24 & vd24) | (vc24 & ~vd24)) + xk23 + ti24) >> 27U);
+ vb24 +
+ ((va23 + ((vb24 & vd24) | (vc24 & ~vd24)) + xk23 + ti24) << 5U |
+ (va23 + ((vb24 & vd24) | (vc24 & ~vd24)) + xk23 + ti24) >> 27U);
abcd[0U] = v23;
uint32_t va24 = abcd[3U];
uint32_t vb25 = abcd[0U];
@@ -466,11 +416,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti25 = _t[25U];
uint32_t
v24 =
- vb25
- +
- ((va24 + ((vb25 & vd25) | (vc25 & ~vd25)) + xk24 + ti25)
- << 9U
- | (va24 + ((vb25 & vd25) | (vc25 & ~vd25)) + xk24 + ti25) >> 23U);
+ vb25 +
+ ((va24 + ((vb25 & vd25) | (vc25 & ~vd25)) + xk24 + ti25) << 9U |
+ (va24 + ((vb25 & vd25) | (vc25 & ~vd25)) + xk24 + ti25) >> 23U);
abcd[3U] = v24;
uint32_t va25 = abcd[2U];
uint32_t vb26 = abcd[3U];
@@ -482,11 +430,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti26 = _t[26U];
uint32_t
v25 =
- vb26
- +
- ((va25 + ((vb26 & vd26) | (vc26 & ~vd26)) + xk25 + ti26)
- << 14U
- | (va25 + ((vb26 & vd26) | (vc26 & ~vd26)) + xk25 + ti26) >> 18U);
+ vb26 +
+ ((va25 + ((vb26 & vd26) | (vc26 & ~vd26)) + xk25 + ti26) << 14U |
+ (va25 + ((vb26 & vd26) | (vc26 & ~vd26)) + xk25 + ti26) >> 18U);
abcd[2U] = v25;
uint32_t va26 = abcd[1U];
uint32_t vb27 = abcd[2U];
@@ -498,11 +444,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti27 = _t[27U];
uint32_t
v26 =
- vb27
- +
- ((va26 + ((vb27 & vd27) | (vc27 & ~vd27)) + xk26 + ti27)
- << 20U
- | (va26 + ((vb27 & vd27) | (vc27 & ~vd27)) + xk26 + ti27) >> 12U);
+ vb27 +
+ ((va26 + ((vb27 & vd27) | (vc27 & ~vd27)) + xk26 + ti27) << 20U |
+ (va26 + ((vb27 & vd27) | (vc27 & ~vd27)) + xk26 + ti27) >> 12U);
abcd[1U] = v26;
uint32_t va27 = abcd[0U];
uint32_t vb28 = abcd[1U];
@@ -514,11 +458,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti28 = _t[28U];
uint32_t
v27 =
- vb28
- +
- ((va27 + ((vb28 & vd28) | (vc28 & ~vd28)) + xk27 + ti28)
- << 5U
- | (va27 + ((vb28 & vd28) | (vc28 & ~vd28)) + xk27 + ti28) >> 27U);
+ vb28 +
+ ((va27 + ((vb28 & vd28) | (vc28 & ~vd28)) + xk27 + ti28) << 5U |
+ (va27 + ((vb28 & vd28) | (vc28 & ~vd28)) + xk27 + ti28) >> 27U);
abcd[0U] = v27;
uint32_t va28 = abcd[3U];
uint32_t vb29 = abcd[0U];
@@ -530,11 +472,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti29 = _t[29U];
uint32_t
v28 =
- vb29
- +
- ((va28 + ((vb29 & vd29) | (vc29 & ~vd29)) + xk28 + ti29)
- << 9U
- | (va28 + ((vb29 & vd29) | (vc29 & ~vd29)) + xk28 + ti29) >> 23U);
+ vb29 +
+ ((va28 + ((vb29 & vd29) | (vc29 & ~vd29)) + xk28 + ti29) << 9U |
+ (va28 + ((vb29 & vd29) | (vc29 & ~vd29)) + xk28 + ti29) >> 23U);
abcd[3U] = v28;
uint32_t va29 = abcd[2U];
uint32_t vb30 = abcd[3U];
@@ -546,11 +486,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti30 = _t[30U];
uint32_t
v29 =
- vb30
- +
- ((va29 + ((vb30 & vd30) | (vc30 & ~vd30)) + xk29 + ti30)
- << 14U
- | (va29 + ((vb30 & vd30) | (vc30 & ~vd30)) + xk29 + ti30) >> 18U);
+ vb30 +
+ ((va29 + ((vb30 & vd30) | (vc30 & ~vd30)) + xk29 + ti30) << 14U |
+ (va29 + ((vb30 & vd30) | (vc30 & ~vd30)) + xk29 + ti30) >> 18U);
abcd[2U] = v29;
uint32_t va30 = abcd[1U];
uint32_t vb31 = abcd[2U];
@@ -562,11 +500,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti31 = _t[31U];
uint32_t
v30 =
- vb31
- +
- ((va30 + ((vb31 & vd31) | (vc31 & ~vd31)) + xk30 + ti31)
- << 20U
- | (va30 + ((vb31 & vd31) | (vc31 & ~vd31)) + xk30 + ti31) >> 12U);
+ vb31 +
+ ((va30 + ((vb31 & vd31) | (vc31 & ~vd31)) + xk30 + ti31) << 20U |
+ (va30 + ((vb31 & vd31) | (vc31 & ~vd31)) + xk30 + ti31) >> 12U);
abcd[1U] = v30;
uint32_t va31 = abcd[0U];
uint32_t vb32 = abcd[1U];
@@ -578,11 +514,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti32 = _t[32U];
uint32_t
v31 =
- vb32
- +
- ((va31 + (vb32 ^ (vc32 ^ vd32)) + xk31 + ti32)
- << 4U
- | (va31 + (vb32 ^ (vc32 ^ vd32)) + xk31 + ti32) >> 28U);
+ vb32 +
+ ((va31 + (vb32 ^ (vc32 ^ vd32)) + xk31 + ti32) << 4U |
+ (va31 + (vb32 ^ (vc32 ^ vd32)) + xk31 + ti32) >> 28U);
abcd[0U] = v31;
uint32_t va32 = abcd[3U];
uint32_t vb33 = abcd[0U];
@@ -594,11 +528,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti33 = _t[33U];
uint32_t
v32 =
- vb33
- +
- ((va32 + (vb33 ^ (vc33 ^ vd33)) + xk32 + ti33)
- << 11U
- | (va32 + (vb33 ^ (vc33 ^ vd33)) + xk32 + ti33) >> 21U);
+ vb33 +
+ ((va32 + (vb33 ^ (vc33 ^ vd33)) + xk32 + ti33) << 11U |
+ (va32 + (vb33 ^ (vc33 ^ vd33)) + xk32 + ti33) >> 21U);
abcd[3U] = v32;
uint32_t va33 = abcd[2U];
uint32_t vb34 = abcd[3U];
@@ -610,11 +542,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti34 = _t[34U];
uint32_t
v33 =
- vb34
- +
- ((va33 + (vb34 ^ (vc34 ^ vd34)) + xk33 + ti34)
- << 16U
- | (va33 + (vb34 ^ (vc34 ^ vd34)) + xk33 + ti34) >> 16U);
+ vb34 +
+ ((va33 + (vb34 ^ (vc34 ^ vd34)) + xk33 + ti34) << 16U |
+ (va33 + (vb34 ^ (vc34 ^ vd34)) + xk33 + ti34) >> 16U);
abcd[2U] = v33;
uint32_t va34 = abcd[1U];
uint32_t vb35 = abcd[2U];
@@ -626,11 +556,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti35 = _t[35U];
uint32_t
v34 =
- vb35
- +
- ((va34 + (vb35 ^ (vc35 ^ vd35)) + xk34 + ti35)
- << 23U
- | (va34 + (vb35 ^ (vc35 ^ vd35)) + xk34 + ti35) >> 9U);
+ vb35 +
+ ((va34 + (vb35 ^ (vc35 ^ vd35)) + xk34 + ti35) << 23U |
+ (va34 + (vb35 ^ (vc35 ^ vd35)) + xk34 + ti35) >> 9U);
abcd[1U] = v34;
uint32_t va35 = abcd[0U];
uint32_t vb36 = abcd[1U];
@@ -642,11 +570,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti36 = _t[36U];
uint32_t
v35 =
- vb36
- +
- ((va35 + (vb36 ^ (vc36 ^ vd36)) + xk35 + ti36)
- << 4U
- | (va35 + (vb36 ^ (vc36 ^ vd36)) + xk35 + ti36) >> 28U);
+ vb36 +
+ ((va35 + (vb36 ^ (vc36 ^ vd36)) + xk35 + ti36) << 4U |
+ (va35 + (vb36 ^ (vc36 ^ vd36)) + xk35 + ti36) >> 28U);
abcd[0U] = v35;
uint32_t va36 = abcd[3U];
uint32_t vb37 = abcd[0U];
@@ -658,11 +584,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti37 = _t[37U];
uint32_t
v36 =
- vb37
- +
- ((va36 + (vb37 ^ (vc37 ^ vd37)) + xk36 + ti37)
- << 11U
- | (va36 + (vb37 ^ (vc37 ^ vd37)) + xk36 + ti37) >> 21U);
+ vb37 +
+ ((va36 + (vb37 ^ (vc37 ^ vd37)) + xk36 + ti37) << 11U |
+ (va36 + (vb37 ^ (vc37 ^ vd37)) + xk36 + ti37) >> 21U);
abcd[3U] = v36;
uint32_t va37 = abcd[2U];
uint32_t vb38 = abcd[3U];
@@ -674,11 +598,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti38 = _t[38U];
uint32_t
v37 =
- vb38
- +
- ((va37 + (vb38 ^ (vc38 ^ vd38)) + xk37 + ti38)
- << 16U
- | (va37 + (vb38 ^ (vc38 ^ vd38)) + xk37 + ti38) >> 16U);
+ vb38 +
+ ((va37 + (vb38 ^ (vc38 ^ vd38)) + xk37 + ti38) << 16U |
+ (va37 + (vb38 ^ (vc38 ^ vd38)) + xk37 + ti38) >> 16U);
abcd[2U] = v37;
uint32_t va38 = abcd[1U];
uint32_t vb39 = abcd[2U];
@@ -690,11 +612,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti39 = _t[39U];
uint32_t
v38 =
- vb39
- +
- ((va38 + (vb39 ^ (vc39 ^ vd39)) + xk38 + ti39)
- << 23U
- | (va38 + (vb39 ^ (vc39 ^ vd39)) + xk38 + ti39) >> 9U);
+ vb39 +
+ ((va38 + (vb39 ^ (vc39 ^ vd39)) + xk38 + ti39) << 23U |
+ (va38 + (vb39 ^ (vc39 ^ vd39)) + xk38 + ti39) >> 9U);
abcd[1U] = v38;
uint32_t va39 = abcd[0U];
uint32_t vb40 = abcd[1U];
@@ -706,11 +626,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti40 = _t[40U];
uint32_t
v39 =
- vb40
- +
- ((va39 + (vb40 ^ (vc40 ^ vd40)) + xk39 + ti40)
- << 4U
- | (va39 + (vb40 ^ (vc40 ^ vd40)) + xk39 + ti40) >> 28U);
+ vb40 +
+ ((va39 + (vb40 ^ (vc40 ^ vd40)) + xk39 + ti40) << 4U |
+ (va39 + (vb40 ^ (vc40 ^ vd40)) + xk39 + ti40) >> 28U);
abcd[0U] = v39;
uint32_t va40 = abcd[3U];
uint32_t vb41 = abcd[0U];
@@ -722,11 +640,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti41 = _t[41U];
uint32_t
v40 =
- vb41
- +
- ((va40 + (vb41 ^ (vc41 ^ vd41)) + xk40 + ti41)
- << 11U
- | (va40 + (vb41 ^ (vc41 ^ vd41)) + xk40 + ti41) >> 21U);
+ vb41 +
+ ((va40 + (vb41 ^ (vc41 ^ vd41)) + xk40 + ti41) << 11U |
+ (va40 + (vb41 ^ (vc41 ^ vd41)) + xk40 + ti41) >> 21U);
abcd[3U] = v40;
uint32_t va41 = abcd[2U];
uint32_t vb42 = abcd[3U];
@@ -738,11 +654,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti42 = _t[42U];
uint32_t
v41 =
- vb42
- +
- ((va41 + (vb42 ^ (vc42 ^ vd42)) + xk41 + ti42)
- << 16U
- | (va41 + (vb42 ^ (vc42 ^ vd42)) + xk41 + ti42) >> 16U);
+ vb42 +
+ ((va41 + (vb42 ^ (vc42 ^ vd42)) + xk41 + ti42) << 16U |
+ (va41 + (vb42 ^ (vc42 ^ vd42)) + xk41 + ti42) >> 16U);
abcd[2U] = v41;
uint32_t va42 = abcd[1U];
uint32_t vb43 = abcd[2U];
@@ -754,11 +668,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti43 = _t[43U];
uint32_t
v42 =
- vb43
- +
- ((va42 + (vb43 ^ (vc43 ^ vd43)) + xk42 + ti43)
- << 23U
- | (va42 + (vb43 ^ (vc43 ^ vd43)) + xk42 + ti43) >> 9U);
+ vb43 +
+ ((va42 + (vb43 ^ (vc43 ^ vd43)) + xk42 + ti43) << 23U |
+ (va42 + (vb43 ^ (vc43 ^ vd43)) + xk42 + ti43) >> 9U);
abcd[1U] = v42;
uint32_t va43 = abcd[0U];
uint32_t vb44 = abcd[1U];
@@ -770,11 +682,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti44 = _t[44U];
uint32_t
v43 =
- vb44
- +
- ((va43 + (vb44 ^ (vc44 ^ vd44)) + xk43 + ti44)
- << 4U
- | (va43 + (vb44 ^ (vc44 ^ vd44)) + xk43 + ti44) >> 28U);
+ vb44 +
+ ((va43 + (vb44 ^ (vc44 ^ vd44)) + xk43 + ti44) << 4U |
+ (va43 + (vb44 ^ (vc44 ^ vd44)) + xk43 + ti44) >> 28U);
abcd[0U] = v43;
uint32_t va44 = abcd[3U];
uint32_t vb45 = abcd[0U];
@@ -786,11 +696,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti45 = _t[45U];
uint32_t
v44 =
- vb45
- +
- ((va44 + (vb45 ^ (vc45 ^ vd45)) + xk44 + ti45)
- << 11U
- | (va44 + (vb45 ^ (vc45 ^ vd45)) + xk44 + ti45) >> 21U);
+ vb45 +
+ ((va44 + (vb45 ^ (vc45 ^ vd45)) + xk44 + ti45) << 11U |
+ (va44 + (vb45 ^ (vc45 ^ vd45)) + xk44 + ti45) >> 21U);
abcd[3U] = v44;
uint32_t va45 = abcd[2U];
uint32_t vb46 = abcd[3U];
@@ -802,11 +710,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti46 = _t[46U];
uint32_t
v45 =
- vb46
- +
- ((va45 + (vb46 ^ (vc46 ^ vd46)) + xk45 + ti46)
- << 16U
- | (va45 + (vb46 ^ (vc46 ^ vd46)) + xk45 + ti46) >> 16U);
+ vb46 +
+ ((va45 + (vb46 ^ (vc46 ^ vd46)) + xk45 + ti46) << 16U |
+ (va45 + (vb46 ^ (vc46 ^ vd46)) + xk45 + ti46) >> 16U);
abcd[2U] = v45;
uint32_t va46 = abcd[1U];
uint32_t vb47 = abcd[2U];
@@ -818,11 +724,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti47 = _t[47U];
uint32_t
v46 =
- vb47
- +
- ((va46 + (vb47 ^ (vc47 ^ vd47)) + xk46 + ti47)
- << 23U
- | (va46 + (vb47 ^ (vc47 ^ vd47)) + xk46 + ti47) >> 9U);
+ vb47 +
+ ((va46 + (vb47 ^ (vc47 ^ vd47)) + xk46 + ti47) << 23U |
+ (va46 + (vb47 ^ (vc47 ^ vd47)) + xk46 + ti47) >> 9U);
abcd[1U] = v46;
uint32_t va47 = abcd[0U];
uint32_t vb48 = abcd[1U];
@@ -834,11 +738,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti48 = _t[48U];
uint32_t
v47 =
- vb48
- +
- ((va47 + (vc48 ^ (vb48 | ~vd48)) + xk47 + ti48)
- << 6U
- | (va47 + (vc48 ^ (vb48 | ~vd48)) + xk47 + ti48) >> 26U);
+ vb48 +
+ ((va47 + (vc48 ^ (vb48 | ~vd48)) + xk47 + ti48) << 6U |
+ (va47 + (vc48 ^ (vb48 | ~vd48)) + xk47 + ti48) >> 26U);
abcd[0U] = v47;
uint32_t va48 = abcd[3U];
uint32_t vb49 = abcd[0U];
@@ -850,11 +752,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti49 = _t[49U];
uint32_t
v48 =
- vb49
- +
- ((va48 + (vc49 ^ (vb49 | ~vd49)) + xk48 + ti49)
- << 10U
- | (va48 + (vc49 ^ (vb49 | ~vd49)) + xk48 + ti49) >> 22U);
+ vb49 +
+ ((va48 + (vc49 ^ (vb49 | ~vd49)) + xk48 + ti49) << 10U |
+ (va48 + (vc49 ^ (vb49 | ~vd49)) + xk48 + ti49) >> 22U);
abcd[3U] = v48;
uint32_t va49 = abcd[2U];
uint32_t vb50 = abcd[3U];
@@ -866,11 +766,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti50 = _t[50U];
uint32_t
v49 =
- vb50
- +
- ((va49 + (vc50 ^ (vb50 | ~vd50)) + xk49 + ti50)
- << 15U
- | (va49 + (vc50 ^ (vb50 | ~vd50)) + xk49 + ti50) >> 17U);
+ vb50 +
+ ((va49 + (vc50 ^ (vb50 | ~vd50)) + xk49 + ti50) << 15U |
+ (va49 + (vc50 ^ (vb50 | ~vd50)) + xk49 + ti50) >> 17U);
abcd[2U] = v49;
uint32_t va50 = abcd[1U];
uint32_t vb51 = abcd[2U];
@@ -882,11 +780,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti51 = _t[51U];
uint32_t
v50 =
- vb51
- +
- ((va50 + (vc51 ^ (vb51 | ~vd51)) + xk50 + ti51)
- << 21U
- | (va50 + (vc51 ^ (vb51 | ~vd51)) + xk50 + ti51) >> 11U);
+ vb51 +
+ ((va50 + (vc51 ^ (vb51 | ~vd51)) + xk50 + ti51) << 21U |
+ (va50 + (vc51 ^ (vb51 | ~vd51)) + xk50 + ti51) >> 11U);
abcd[1U] = v50;
uint32_t va51 = abcd[0U];
uint32_t vb52 = abcd[1U];
@@ -898,11 +794,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti52 = _t[52U];
uint32_t
v51 =
- vb52
- +
- ((va51 + (vc52 ^ (vb52 | ~vd52)) + xk51 + ti52)
- << 6U
- | (va51 + (vc52 ^ (vb52 | ~vd52)) + xk51 + ti52) >> 26U);
+ vb52 +
+ ((va51 + (vc52 ^ (vb52 | ~vd52)) + xk51 + ti52) << 6U |
+ (va51 + (vc52 ^ (vb52 | ~vd52)) + xk51 + ti52) >> 26U);
abcd[0U] = v51;
uint32_t va52 = abcd[3U];
uint32_t vb53 = abcd[0U];
@@ -914,11 +808,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti53 = _t[53U];
uint32_t
v52 =
- vb53
- +
- ((va52 + (vc53 ^ (vb53 | ~vd53)) + xk52 + ti53)
- << 10U
- | (va52 + (vc53 ^ (vb53 | ~vd53)) + xk52 + ti53) >> 22U);
+ vb53 +
+ ((va52 + (vc53 ^ (vb53 | ~vd53)) + xk52 + ti53) << 10U |
+ (va52 + (vc53 ^ (vb53 | ~vd53)) + xk52 + ti53) >> 22U);
abcd[3U] = v52;
uint32_t va53 = abcd[2U];
uint32_t vb54 = abcd[3U];
@@ -930,11 +822,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti54 = _t[54U];
uint32_t
v53 =
- vb54
- +
- ((va53 + (vc54 ^ (vb54 | ~vd54)) + xk53 + ti54)
- << 15U
- | (va53 + (vc54 ^ (vb54 | ~vd54)) + xk53 + ti54) >> 17U);
+ vb54 +
+ ((va53 + (vc54 ^ (vb54 | ~vd54)) + xk53 + ti54) << 15U |
+ (va53 + (vc54 ^ (vb54 | ~vd54)) + xk53 + ti54) >> 17U);
abcd[2U] = v53;
uint32_t va54 = abcd[1U];
uint32_t vb55 = abcd[2U];
@@ -946,11 +836,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti55 = _t[55U];
uint32_t
v54 =
- vb55
- +
- ((va54 + (vc55 ^ (vb55 | ~vd55)) + xk54 + ti55)
- << 21U
- | (va54 + (vc55 ^ (vb55 | ~vd55)) + xk54 + ti55) >> 11U);
+ vb55 +
+ ((va54 + (vc55 ^ (vb55 | ~vd55)) + xk54 + ti55) << 21U |
+ (va54 + (vc55 ^ (vb55 | ~vd55)) + xk54 + ti55) >> 11U);
abcd[1U] = v54;
uint32_t va55 = abcd[0U];
uint32_t vb56 = abcd[1U];
@@ -962,11 +850,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti56 = _t[56U];
uint32_t
v55 =
- vb56
- +
- ((va55 + (vc56 ^ (vb56 | ~vd56)) + xk55 + ti56)
- << 6U
- | (va55 + (vc56 ^ (vb56 | ~vd56)) + xk55 + ti56) >> 26U);
+ vb56 +
+ ((va55 + (vc56 ^ (vb56 | ~vd56)) + xk55 + ti56) << 6U |
+ (va55 + (vc56 ^ (vb56 | ~vd56)) + xk55 + ti56) >> 26U);
abcd[0U] = v55;
uint32_t va56 = abcd[3U];
uint32_t vb57 = abcd[0U];
@@ -978,11 +864,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti57 = _t[57U];
uint32_t
v56 =
- vb57
- +
- ((va56 + (vc57 ^ (vb57 | ~vd57)) + xk56 + ti57)
- << 10U
- | (va56 + (vc57 ^ (vb57 | ~vd57)) + xk56 + ti57) >> 22U);
+ vb57 +
+ ((va56 + (vc57 ^ (vb57 | ~vd57)) + xk56 + ti57) << 10U |
+ (va56 + (vc57 ^ (vb57 | ~vd57)) + xk56 + ti57) >> 22U);
abcd[3U] = v56;
uint32_t va57 = abcd[2U];
uint32_t vb58 = abcd[3U];
@@ -994,11 +878,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti58 = _t[58U];
uint32_t
v57 =
- vb58
- +
- ((va57 + (vc58 ^ (vb58 | ~vd58)) + xk57 + ti58)
- << 15U
- | (va57 + (vc58 ^ (vb58 | ~vd58)) + xk57 + ti58) >> 17U);
+ vb58 +
+ ((va57 + (vc58 ^ (vb58 | ~vd58)) + xk57 + ti58) << 15U |
+ (va57 + (vc58 ^ (vb58 | ~vd58)) + xk57 + ti58) >> 17U);
abcd[2U] = v57;
uint32_t va58 = abcd[1U];
uint32_t vb59 = abcd[2U];
@@ -1010,11 +892,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti59 = _t[59U];
uint32_t
v58 =
- vb59
- +
- ((va58 + (vc59 ^ (vb59 | ~vd59)) + xk58 + ti59)
- << 21U
- | (va58 + (vc59 ^ (vb59 | ~vd59)) + xk58 + ti59) >> 11U);
+ vb59 +
+ ((va58 + (vc59 ^ (vb59 | ~vd59)) + xk58 + ti59) << 21U |
+ (va58 + (vc59 ^ (vb59 | ~vd59)) + xk58 + ti59) >> 11U);
abcd[1U] = v58;
uint32_t va59 = abcd[0U];
uint32_t vb60 = abcd[1U];
@@ -1026,11 +906,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti60 = _t[60U];
uint32_t
v59 =
- vb60
- +
- ((va59 + (vc60 ^ (vb60 | ~vd60)) + xk59 + ti60)
- << 6U
- | (va59 + (vc60 ^ (vb60 | ~vd60)) + xk59 + ti60) >> 26U);
+ vb60 +
+ ((va59 + (vc60 ^ (vb60 | ~vd60)) + xk59 + ti60) << 6U |
+ (va59 + (vc60 ^ (vb60 | ~vd60)) + xk59 + ti60) >> 26U);
abcd[0U] = v59;
uint32_t va60 = abcd[3U];
uint32_t vb61 = abcd[0U];
@@ -1042,11 +920,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti61 = _t[61U];
uint32_t
v60 =
- vb61
- +
- ((va60 + (vc61 ^ (vb61 | ~vd61)) + xk60 + ti61)
- << 10U
- | (va60 + (vc61 ^ (vb61 | ~vd61)) + xk60 + ti61) >> 22U);
+ vb61 +
+ ((va60 + (vc61 ^ (vb61 | ~vd61)) + xk60 + ti61) << 10U |
+ (va60 + (vc61 ^ (vb61 | ~vd61)) + xk60 + ti61) >> 22U);
abcd[3U] = v60;
uint32_t va61 = abcd[2U];
uint32_t vb62 = abcd[3U];
@@ -1058,11 +934,9 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti62 = _t[62U];
uint32_t
v61 =
- vb62
- +
- ((va61 + (vc62 ^ (vb62 | ~vd62)) + xk61 + ti62)
- << 15U
- | (va61 + (vc62 ^ (vb62 | ~vd62)) + xk61 + ti62) >> 17U);
+ vb62 +
+ ((va61 + (vc62 ^ (vb62 | ~vd62)) + xk61 + ti62) << 15U |
+ (va61 + (vc62 ^ (vb62 | ~vd62)) + xk61 + ti62) >> 17U);
abcd[2U] = v61;
uint32_t va62 = abcd[1U];
uint32_t vb = abcd[2U];
@@ -1074,11 +948,8 @@ static void update(uint32_t *abcd, uint8_t *x)
uint32_t ti = _t[63U];
uint32_t
v62 =
- vb
- +
- ((va62 + (vc ^ (vb | ~vd)) + xk62 + ti)
- << 21U
- | (va62 + (vc ^ (vb | ~vd)) + xk62 + ti) >> 11U);
+ vb +
+ ((va62 + (vc ^ (vb | ~vd)) + xk62 + ti) << 21U | (va62 + (vc ^ (vb | ~vd)) + xk62 + ti) >> 11U);
abcd[1U] = v62;
uint32_t a = abcd[0U];
uint32_t b = abcd[1U];
@@ -1282,8 +1153,7 @@ Hacl_Hash_MD5_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -1328,8 +1198,7 @@ Hacl_Hash_MD5_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t
Hacl_Hash_MD5_update_multi(block_state1, data1, data1_len / 64U);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -1359,8 +1228,7 @@ Hacl_Hash_MD5_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state10,
@@ -1403,8 +1271,7 @@ Hacl_Hash_MD5_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t
Hacl_Hash_MD5_update_multi(block_state1, data1, data1_len / 64U);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
diff --git a/Modules/_hacl/Hacl_Hash_SHA1.c b/Modules/_hacl/Hacl_Hash_SHA1.c
index 508e447bf27..97bd4f2204c 100644
--- a/Modules/_hacl/Hacl_Hash_SHA1.c
+++ b/Modules/_hacl/Hacl_Hash_SHA1.c
@@ -315,8 +315,7 @@ Hacl_Hash_SHA1_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -361,8 +360,7 @@ Hacl_Hash_SHA1_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_
Hacl_Hash_SHA1_update_multi(block_state1, data1, data1_len / 64U);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -392,8 +390,7 @@ Hacl_Hash_SHA1_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state10,
@@ -436,8 +433,7 @@ Hacl_Hash_SHA1_update(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_
Hacl_Hash_SHA1_update_multi(block_state1, data1, data1_len / 64U);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
diff --git a/Modules/_hacl/Hacl_Hash_SHA2.c b/Modules/_hacl/Hacl_Hash_SHA2.c
index d612bafa72c..d2ee0c9ef51 100644
--- a/Modules/_hacl/Hacl_Hash_SHA2.c
+++ b/Modules/_hacl/Hacl_Hash_SHA2.c
@@ -100,15 +100,14 @@ static inline void sha256_update(uint8_t *b, uint32_t *hash)
uint32_t k_e_t = k_t;
uint32_t
t1 =
- h02
- + ((e0 << 26U | e0 >> 6U) ^ ((e0 << 21U | e0 >> 11U) ^ (e0 << 7U | e0 >> 25U)))
- + ((e0 & f0) ^ (~e0 & g0))
+ h02 + ((e0 << 26U | e0 >> 6U) ^ ((e0 << 21U | e0 >> 11U) ^ (e0 << 7U | e0 >> 25U))) +
+ ((e0 & f0) ^ (~e0 & g0))
+ k_e_t
+ ws_t;
uint32_t
t2 =
- ((a0 << 30U | a0 >> 2U) ^ ((a0 << 19U | a0 >> 13U) ^ (a0 << 10U | a0 >> 22U)))
- + ((a0 & b0) ^ ((a0 & c0) ^ (b0 & c0)));
+ ((a0 << 30U | a0 >> 2U) ^ ((a0 << 19U | a0 >> 13U) ^ (a0 << 10U | a0 >> 22U))) +
+ ((a0 & b0) ^ ((a0 & c0) ^ (b0 & c0)));
uint32_t a1 = t1 + t2;
uint32_t b1 = a0;
uint32_t c1 = b0;
@@ -301,15 +300,14 @@ static inline void sha512_update(uint8_t *b, uint64_t *hash)
uint64_t k_e_t = k_t;
uint64_t
t1 =
- h02
- + ((e0 << 50U | e0 >> 14U) ^ ((e0 << 46U | e0 >> 18U) ^ (e0 << 23U | e0 >> 41U)))
- + ((e0 & f0) ^ (~e0 & g0))
+ h02 + ((e0 << 50U | e0 >> 14U) ^ ((e0 << 46U | e0 >> 18U) ^ (e0 << 23U | e0 >> 41U))) +
+ ((e0 & f0) ^ (~e0 & g0))
+ k_e_t
+ ws_t;
uint64_t
t2 =
- ((a0 << 36U | a0 >> 28U) ^ ((a0 << 30U | a0 >> 34U) ^ (a0 << 25U | a0 >> 39U)))
- + ((a0 & b0) ^ ((a0 & c0) ^ (b0 & c0)));
+ ((a0 << 36U | a0 >> 28U) ^ ((a0 << 30U | a0 >> 34U) ^ (a0 << 25U | a0 >> 39U))) +
+ ((a0 & b0) ^ ((a0 & c0) ^ (b0 & c0)));
uint64_t a1 = t1 + t2;
uint64_t b1 = a0;
uint64_t c1 = b0;
@@ -639,8 +637,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t chunk
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -685,8 +682,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t chunk
Hacl_Hash_SHA2_sha256_update_nblocks(data1_len / 64U * 64U, data1, block_state1);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -716,8 +712,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t chunk
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state10,
@@ -760,8 +755,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *state, uint8_t *chunk, uint32_t chunk
Hacl_Hash_SHA2_sha256_update_nblocks(data1_len / 64U * 64U, data1, block_state1);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_32){
.block_state = block_state1,
@@ -1205,8 +1199,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *state, uint8_t *chunk, uint32_t chunk
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_64){
.block_state = block_state1,
@@ -1251,8 +1244,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *state, uint8_t *chunk, uint32_t chunk
Hacl_Hash_SHA2_sha512_update_nblocks(data1_len / 128U * 128U, data1, block_state1);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_64){
.block_state = block_state1,
@@ -1282,8 +1274,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *state, uint8_t *chunk, uint32_t chunk
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_64){
.block_state = block_state10,
@@ -1326,8 +1317,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *state, uint8_t *chunk, uint32_t chunk
Hacl_Hash_SHA2_sha512_update_nblocks(data1_len / 128U * 128U, data1, block_state1);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_MD_state_64){
.block_state = block_state1,
diff --git a/Modules/_hacl/Hacl_Hash_SHA3.c b/Modules/_hacl/Hacl_Hash_SHA3.c
index 87638df9549..466d2b96c0c 100644
--- a/Modules/_hacl/Hacl_Hash_SHA3.c
+++ b/Modules/_hacl/Hacl_Hash_SHA3.c
@@ -866,8 +866,7 @@ Hacl_Hash_SHA3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *chunk, uint32_t ch
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
((Hacl_Hash_SHA3_state_t){ .block_state = block_state1, .buf = buf, .total_len = total_len2 });
}
else if (sz == 0U)
@@ -910,8 +909,7 @@ Hacl_Hash_SHA3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *chunk, uint32_t ch
Hacl_Hash_SHA3_update_multi_sha3(a1, s2, data1, data1_len / block_len(a1));
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_SHA3_state_t){
.block_state = block_state1,
@@ -941,8 +939,7 @@ Hacl_Hash_SHA3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *chunk, uint32_t ch
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Hash_SHA3_state_t){
.block_state = block_state10,
@@ -972,10 +969,8 @@ Hacl_Hash_SHA3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *chunk, uint32_t ch
uint32_t ite;
if
(
- (uint64_t)(chunk_len - diff)
- % (uint64_t)block_len(i)
- == 0ULL
- && (uint64_t)(chunk_len - diff) > 0ULL
+ (uint64_t)(chunk_len - diff) % (uint64_t)block_len(i) == 0ULL &&
+ (uint64_t)(chunk_len - diff) > 0ULL
)
{
ite = block_len(i);
@@ -994,8 +989,7 @@ Hacl_Hash_SHA3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *chunk, uint32_t ch
Hacl_Hash_SHA3_update_multi_sha3(a1, s2, data1, data1_len / block_len(a1));
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Hash_SHA3_state_t){
.block_state = block_state1,
@@ -2422,9 +2416,7 @@ Hacl_Hash_SHA3_shake128_squeeze_nblocks(
5U,
1U,
_C[i] =
- state[i
- + 0U]
- ^ (state[i + 5U] ^ (state[i + 10U] ^ (state[i + 15U] ^ state[i + 20U]))););
+ state[i + 0U] ^ (state[i + 5U] ^ (state[i + 10U] ^ (state[i + 15U] ^ state[i + 20U]))););
KRML_MAYBE_FOR5(i2,
0U,
5U,
diff --git a/Modules/_hacl/Hacl_Streaming_HMAC.c b/Modules/_hacl/Hacl_Streaming_HMAC.c
index d28b39792af..8dd7e2c0bf3 100644
--- a/Modules/_hacl/Hacl_Streaming_HMAC.c
+++ b/Modules/_hacl/Hacl_Streaming_HMAC.c
@@ -198,8 +198,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- = ((Hacl_Agile_Hash_state_s){ .tag = Hacl_Agile_Hash_MD5_a, { .case_MD5_a = s1 } });
+ st[0U] = ((Hacl_Agile_Hash_state_s){ .tag = Hacl_Agile_Hash_MD5_a, { .case_MD5_a = s1 } });
}
if (st == NULL)
{
@@ -220,8 +219,8 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- = ((Hacl_Agile_Hash_state_s){ .tag = Hacl_Agile_Hash_SHA1_a, { .case_SHA1_a = s1 } });
+ st[0U] =
+ ((Hacl_Agile_Hash_state_s){ .tag = Hacl_Agile_Hash_SHA1_a, { .case_SHA1_a = s1 } });
}
if (st == NULL)
{
@@ -242,8 +241,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA2_224_a,
@@ -270,8 +268,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA2_256_a,
@@ -298,8 +295,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA2_384_a,
@@ -326,8 +322,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA2_512_a,
@@ -354,8 +349,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA3_224_a,
@@ -382,8 +376,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA3_256_a,
@@ -410,8 +403,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA3_384_a,
@@ -438,8 +430,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_SHA3_512_a,
@@ -466,8 +457,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_Blake2S_a,
@@ -495,8 +485,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_Blake2S_128_a,
@@ -531,8 +520,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_Blake2B_a,
@@ -560,8 +548,7 @@ static Hacl_Agile_Hash_state_s *malloc_(Hacl_Agile_Hash_impl a)
*st = (Hacl_Agile_Hash_state_s *)KRML_HOST_MALLOC(sizeof (Hacl_Agile_Hash_state_s));
if (st != NULL)
{
- st[0U]
- =
+ st[0U] =
(
(Hacl_Agile_Hash_state_s){
.tag = Hacl_Agile_Hash_Blake2B_256_a,
@@ -2059,8 +2046,8 @@ Hacl_Streaming_HMAC_update(
Hacl_Streaming_HMAC_Definitions_index i1 = Hacl_Streaming_HMAC_index_of_state(block_state);
if
(
- (uint64_t)chunk_len
- > max_input_len64(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) - total_len
+ (uint64_t)chunk_len >
+ max_input_len64(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) - total_len
)
{
return Hacl_Streaming_Types_MaximumLengthExceeded;
@@ -2068,9 +2055,7 @@ Hacl_Streaming_HMAC_update(
uint32_t sz;
if
(
- total_len
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
- == 0ULL
+ total_len % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) == 0ULL
&& total_len > 0ULL
)
{
@@ -2079,8 +2064,8 @@ Hacl_Streaming_HMAC_update(
else
{
sz =
- (uint32_t)(total_len
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)(total_len %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
if (chunk_len <= block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) - sz)
{
@@ -2091,9 +2076,7 @@ Hacl_Streaming_HMAC_update(
uint32_t sz1;
if
(
- total_len1
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
- == 0ULL
+ total_len1 % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) == 0ULL
&& total_len1 > 0ULL
)
{
@@ -2102,14 +2085,13 @@ Hacl_Streaming_HMAC_update(
else
{
sz1 =
- (uint32_t)(total_len1
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)(total_len1 %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
uint8_t *buf2 = buf + sz1;
memcpy(buf2, chunk, chunk_len * sizeof (uint8_t));
uint64_t total_len2 = total_len1 + (uint64_t)chunk_len;
- *state
- =
+ *state =
(
(Hacl_Streaming_HMAC_agile_state){
.block_state = block_state1,
@@ -2127,9 +2109,7 @@ Hacl_Streaming_HMAC_update(
uint32_t sz1;
if
(
- total_len1
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
- == 0ULL
+ total_len1 % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) == 0ULL
&& total_len1 > 0ULL
)
{
@@ -2138,8 +2118,8 @@ Hacl_Streaming_HMAC_update(
else
{
sz1 =
- (uint32_t)(total_len1
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)(total_len1 %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
if (!(sz1 == 0U))
{
@@ -2153,8 +2133,8 @@ Hacl_Streaming_HMAC_update(
uint32_t ite;
if
(
- (uint64_t)chunk_len
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
+ (uint64_t)chunk_len %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
== 0ULL
&& (uint64_t)chunk_len > 0ULL
)
@@ -2164,8 +2144,8 @@ Hacl_Streaming_HMAC_update(
else
{
ite =
- (uint32_t)((uint64_t)chunk_len
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)((uint64_t)chunk_len %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
uint32_t
n_blocks = (chunk_len - ite) / block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)));
@@ -2178,8 +2158,7 @@ Hacl_Streaming_HMAC_update(
update_multi(s11, total_len1, data1, data1_len);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_HMAC_agile_state){
.block_state = block_state1,
@@ -2200,9 +2179,8 @@ Hacl_Streaming_HMAC_update(
uint32_t sz10;
if
(
- total_len10
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
- == 0ULL
+ total_len10 % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) ==
+ 0ULL
&& total_len10 > 0ULL
)
{
@@ -2211,14 +2189,13 @@ Hacl_Streaming_HMAC_update(
else
{
sz10 =
- (uint32_t)(total_len10
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)(total_len10 %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
uint8_t *buf2 = buf0 + sz10;
memcpy(buf2, chunk1, diff * sizeof (uint8_t));
uint64_t total_len2 = total_len10 + (uint64_t)diff;
- *state
- =
+ *state =
(
(Hacl_Streaming_HMAC_agile_state){
.block_state = block_state10,
@@ -2233,9 +2210,7 @@ Hacl_Streaming_HMAC_update(
uint32_t sz1;
if
(
- total_len1
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
- == 0ULL
+ total_len1 % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) == 0ULL
&& total_len1 > 0ULL
)
{
@@ -2244,8 +2219,8 @@ Hacl_Streaming_HMAC_update(
else
{
sz1 =
- (uint32_t)(total_len1
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)(total_len1 %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
if (!(sz1 == 0U))
{
@@ -2259,8 +2234,8 @@ Hacl_Streaming_HMAC_update(
uint32_t ite;
if
(
- (uint64_t)(chunk_len - diff)
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
+ (uint64_t)(chunk_len - diff) %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
== 0ULL
&& (uint64_t)(chunk_len - diff) > 0ULL
)
@@ -2270,13 +2245,12 @@ Hacl_Streaming_HMAC_update(
else
{
ite =
- (uint32_t)((uint64_t)(chunk_len - diff)
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)((uint64_t)(chunk_len - diff) %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
uint32_t
n_blocks =
- (chunk_len - diff - ite)
- / block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)));
+ (chunk_len - diff - ite) / block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)));
uint32_t
data1_len = n_blocks * block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)));
uint32_t data2_len = chunk_len - diff - data1_len;
@@ -2286,8 +2260,7 @@ Hacl_Streaming_HMAC_update(
update_multi(s11, total_len1, data1, data1_len);
uint8_t *dst = buf;
memcpy(dst, data2, data2_len * sizeof (uint8_t));
- *state
- =
+ *state =
(
(Hacl_Streaming_HMAC_agile_state){
.block_state = block_state1,
@@ -2324,9 +2297,7 @@ Hacl_Streaming_HMAC_digest(
uint32_t r;
if
(
- total_len
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1)))
- == 0ULL
+ total_len % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))) == 0ULL
&& total_len > 0ULL
)
{
@@ -2335,8 +2306,8 @@ Hacl_Streaming_HMAC_digest(
else
{
r =
- (uint32_t)(total_len
- % (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
+ (uint32_t)(total_len %
+ (uint64_t)block_len(alg_of_impl(dfst__Hacl_Agile_Hash_impl_uint32_t(i1))));
}
uint8_t *buf_1 = buf_;
Hacl_Agile_Hash_state_s *s110 = malloc_(dfst__Hacl_Agile_Hash_impl_uint32_t(i1));
diff --git a/Modules/_hacl/Lib_Memzero0.c b/Modules/_hacl/Lib_Memzero0.c
index 28abd1aa4e2..f94e0e2254a 100644
--- a/Modules/_hacl/Lib_Memzero0.c
+++ b/Modules/_hacl/Lib_Memzero0.c
@@ -11,18 +11,18 @@
#if defined(__APPLE__) && defined(__MACH__)
#include <AvailabilityMacros.h>
// memset_s is available from macOS 10.9, iOS 7, watchOS 2, and on all tvOS and visionOS versions.
-# if (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9))
-# define APPLE_HAS_MEMSET_S 1
-# elif (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0))
-# define APPLE_HAS_MEMSET_S 1
+# if (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && defined(MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9))
+# define APPLE_HAS_MEMSET_S
+# elif (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0))
+# define APPLE_HAS_MEMSET_S
# elif (defined(TARGET_OS_TV) && TARGET_OS_TV)
-# define APPLE_HAS_MEMSET_S 1
-# elif (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && (__WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_2_0))
-# define APPLE_HAS_MEMSET_S 1
+# define APPLE_HAS_MEMSET_S
+# elif (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && defined(__WATCHOS_2_0) && (__WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_2_0))
+# define APPLE_HAS_MEMSET_S
# elif (defined(TARGET_OS_VISION) && TARGET_OS_VISION)
-# define APPLE_HAS_MEMSET_S 1
+# define APPLE_HAS_MEMSET_S
# else
-# define APPLE_HAS_MEMSET_S 0
+# undef APPLE_HAS_MEMSET_S
# endif
#endif
@@ -55,7 +55,7 @@ void Lib_Memzero0_memzero0(void *dst, uint64_t len) {
#ifdef _WIN32
SecureZeroMemory(dst, len_);
- #elif defined(__APPLE__) && defined(__MACH__) && APPLE_HAS_MEMSET_S
+ #elif defined(__APPLE__) && defined(__MACH__) && defined(APPLE_HAS_MEMSET_S)
memset_s(dst, len_, 0, len_);
#elif (defined(__linux__) && !defined(LINUX_NO_EXPLICIT_BZERO)) || defined(__FreeBSD__) || defined(__OpenBSD__)
explicit_bzero(dst, len_);
diff --git a/Modules/_hacl/include/krml/FStar_UInt128_Verified.h b/Modules/_hacl/include/krml/FStar_UInt128_Verified.h
index d4a90220bea..f85982f3373 100644
--- a/Modules/_hacl/include/krml/FStar_UInt128_Verified.h
+++ b/Modules/_hacl/include/krml/FStar_UInt128_Verified.h
@@ -257,11 +257,11 @@ FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128 lit;
lit.low =
- (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high))
- | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low));
+ (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) |
+ (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low));
lit.high =
- (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high))
- | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low));
+ (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) |
+ (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low));
return lit;
}
@@ -294,14 +294,12 @@ static inline FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y)
{
FStar_UInt128_uint128 lit;
lit.low =
- FStar_UInt128_u32_combine((x >> FStar_UInt128_u32_32)
- * (uint64_t)y
- + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32),
+ FStar_UInt128_u32_combine((x >> FStar_UInt128_u32_32) * (uint64_t)y +
+ (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32),
FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * (uint64_t)y));
lit.high =
- ((x >> FStar_UInt128_u32_32)
- * (uint64_t)y
- + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32))
+ ((x >> FStar_UInt128_u32_32) * (uint64_t)y +
+ (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32))
>> FStar_UInt128_u32_32;
return lit;
}
@@ -315,28 +313,19 @@ static inline FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t
{
FStar_UInt128_uint128 lit;
lit.low =
- FStar_UInt128_u32_combine_(FStar_UInt128_u64_mod_32(x)
- * (y >> FStar_UInt128_u32_32)
- +
- FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32)
- * FStar_UInt128_u64_mod_32(y)
- + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)),
+ FStar_UInt128_u32_combine_(FStar_UInt128_u64_mod_32(x) * (y >> FStar_UInt128_u32_32) +
+ FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) +
+ (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)),
FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y)));
lit.high =
- (x >> FStar_UInt128_u32_32)
- * (y >> FStar_UInt128_u32_32)
- +
- (((x >> FStar_UInt128_u32_32)
- * FStar_UInt128_u64_mod_32(y)
- + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32))
+ (x >> FStar_UInt128_u32_32) * (y >> FStar_UInt128_u32_32) +
+ (((x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) +
+ (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32))
>> FStar_UInt128_u32_32)
+
- ((FStar_UInt128_u64_mod_32(x)
- * (y >> FStar_UInt128_u32_32)
- +
- FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32)
- * FStar_UInt128_u64_mod_32(y)
- + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)))
+ ((FStar_UInt128_u64_mod_32(x) * (y >> FStar_UInt128_u32_32) +
+ FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) +
+ (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)))
>> FStar_UInt128_u32_32);
return lit;
}
diff --git a/Modules/_hacl/python_hacl_namespaces.h b/Modules/_hacl/python_hacl_namespaces.h
index 1c2f7fea5c8..d0b4500395e 100644
--- a/Modules/_hacl/python_hacl_namespaces.h
+++ b/Modules/_hacl/python_hacl_namespaces.h
@@ -2,95 +2,43 @@
#define _PYTHON_HACL_NAMESPACES_H
/*
- * C's excuse for namespaces: Use globally unique names to avoid linkage
- * conflicts with builds linking or dynamically loading other code potentially
- * using HACL* libraries.
+ * Use globally unique names to avoid linkage conflicts with builds linking
+ * or dynamically loading other code potentially using HACL* libraries.
*
- * Something like this to generate new entries for the list:
- *
- * nm *.o | grep Hacl | cut -c 20- | sort | uniq | grep -v _Py_LibHacl_ | egrep ^_ | sed 's/_\(.*\)/#define \1 _Py_LibHacl_\1/g'
- */
+ * Assuming that the current working directory is Modules/_hacl,
+ * use the following command to generate a list of candidates:
-#define Lib_Memzero0_memzero0 _Py_LibHacl_Lib_Memzero0_memzero0
+ nm -j *.o | grep -i hacl | grep -P '^[a-zA-Z_][a-zA-Z0-9_]+' \
+ | sed -e 's/^_Py_LibHacl_//g' \
+ | sed 's/\(.*\)/#define \1 _Py_LibHacl_\1/g' \
+ | sort -u
-#define Hacl_Hash_SHA2_state_sha2_224_s _Py_LibHacl_Hacl_Hash_SHA2_state_sha2_224_s
-#define Hacl_Hash_SHA2_state_sha2_224 _Py_LibHacl_Hacl_Hash_SHA2_state_sha2_224
-#define Hacl_Hash_SHA2_state_sha2_256 _Py_LibHacl_Hacl_Hash_SHA2_state_sha2_256
-#define Hacl_Hash_SHA2_state_sha2_384_s _Py_LibHacl_Hacl_Hash_SHA2_state_sha2_384_s
-#define Hacl_Hash_SHA2_state_sha2_384 _Py_LibHacl_Hacl_Hash_SHA2_state_sha2_384
-#define Hacl_Hash_SHA2_state_sha2_512 _Py_LibHacl_Hacl_Hash_SHA2_state_sha2_512
-#define Hacl_Hash_SHA2_malloc_256 _Py_LibHacl_Hacl_Hash_SHA2_malloc_256
-#define Hacl_Hash_SHA2_malloc_224 _Py_LibHacl_Hacl_Hash_SHA2_malloc_224
-#define Hacl_Hash_SHA2_malloc_512 _Py_LibHacl_Hacl_Hash_SHA2_malloc_512
-#define Hacl_Hash_SHA2_malloc_384 _Py_LibHacl_Hacl_Hash_SHA2_malloc_384
-#define Hacl_Hash_SHA2_copy_256 _Py_LibHacl_Hacl_Hash_SHA2_copy_256
-#define Hacl_Hash_SHA2_copy_224 _Py_LibHacl_Hacl_Hash_SHA2_copy_224
-#define Hacl_Hash_SHA2_copy_512 _Py_LibHacl_Hacl_Hash_SHA2_copy_512
-#define Hacl_Hash_SHA2_copy_384 _Py_LibHacl_Hacl_Hash_SHA2_copy_384
-#define Hacl_Hash_SHA2_init_256 _Py_LibHacl_Hacl_Hash_SHA2_init_256
-#define Hacl_Hash_SHA2_init_224 _Py_LibHacl_Hacl_Hash_SHA2_init_224
-#define Hacl_Hash_SHA2_init_512 _Py_LibHacl_Hacl_Hash_SHA2_init_512
-#define Hacl_Hash_SHA2_init_384 _Py_LibHacl_Hacl_Hash_SHA2_init_384
-#define Hacl_SHA2_Scalar32_sha512_init _Py_LibHacl_Hacl_SHA2_Scalar32_sha512_init
-#define Hacl_Hash_SHA2_update_256 _Py_LibHacl_Hacl_Hash_SHA2_update_256
-#define Hacl_Hash_SHA2_update_224 _Py_LibHacl_Hacl_Hash_SHA2_update_224
-#define Hacl_Hash_SHA2_update_512 _Py_LibHacl_Hacl_Hash_SHA2_update_512
-#define Hacl_Hash_SHA2_update_384 _Py_LibHacl_Hacl_Hash_SHA2_update_384
-#define Hacl_Hash_SHA2_digest_256 _Py_LibHacl_Hacl_Hash_SHA2_digest_256
-#define Hacl_Hash_SHA2_digest_224 _Py_LibHacl_Hacl_Hash_SHA2_digest_224
-#define Hacl_Hash_SHA2_digest_512 _Py_LibHacl_Hacl_Hash_SHA2_digest_512
-#define Hacl_Hash_SHA2_digest_384 _Py_LibHacl_Hacl_Hash_SHA2_digest_384
-#define Hacl_Hash_SHA2_free_256 _Py_LibHacl_Hacl_Hash_SHA2_free_256
-#define Hacl_Hash_SHA2_free_224 _Py_LibHacl_Hacl_Hash_SHA2_free_224
-#define Hacl_Hash_SHA2_free_512 _Py_LibHacl_Hacl_Hash_SHA2_free_512
-#define Hacl_Hash_SHA2_free_384 _Py_LibHacl_Hacl_Hash_SHA2_free_384
-#define Hacl_Hash_SHA2_sha256 _Py_LibHacl_Hacl_Hash_SHA2_sha256
-#define Hacl_Hash_SHA2_sha224 _Py_LibHacl_Hacl_Hash_SHA2_sha224
-#define Hacl_Hash_SHA2_sha512 _Py_LibHacl_Hacl_Hash_SHA2_sha512
-#define Hacl_Hash_SHA2_sha384 _Py_LibHacl_Hacl_Hash_SHA2_sha384
+ * Compare the entries to add as follows:
-#define Hacl_Hash_MD5_malloc _Py_LibHacl_Hacl_Hash_MD5_malloc
-#define Hacl_Hash_MD5_init _Py_LibHacl_Hacl_Hash_MD5_init
-#define Hacl_Hash_MD5_update _Py_LibHacl_Hacl_Hash_MD5_update
-#define Hacl_Hash_MD5_digest _Py_LibHacl_Hacl_Hash_MD5_digest
-#define Hacl_Hash_MD5_free _Py_LibHacl_Hacl_Hash_MD5_free
-#define Hacl_Hash_MD5_copy _Py_LibHacl_Hacl_Hash_MD5_copy
-#define Hacl_Hash_MD5_hash _Py_LibHacl_Hacl_Hash_MD5_hash
-
-#define Hacl_Hash_SHA1_malloc _Py_LibHacl_Hacl_Hash_SHA1_malloc
-#define Hacl_Hash_SHA1_init _Py_LibHacl_Hacl_Hash_SHA1_init
-#define Hacl_Hash_SHA1_update _Py_LibHacl_Hacl_Hash_SHA1_update
-#define Hacl_Hash_SHA1_digest _Py_LibHacl_Hacl_Hash_SHA1_digest
-#define Hacl_Hash_SHA1_free _Py_LibHacl_Hacl_Hash_SHA1_free
-#define Hacl_Hash_SHA1_copy _Py_LibHacl_Hacl_Hash_SHA1_copy
-#define Hacl_Hash_SHA1_hash _Py_LibHacl_Hacl_Hash_SHA1_hash
-
-#define Hacl_Hash_SHA3_update_last_sha3 _Py_LibHacl_Hacl_Hash_SHA3_update_last_sha3
-#define Hacl_Hash_SHA3_update_multi_sha3 _Py_LibHacl_Hacl_Hash_SHA3_update_multi_sha3
-#define Hacl_Impl_SHA3_absorb_inner _Py_LibHacl_Hacl_Impl_SHA3_absorb_inner
-#define Hacl_Impl_SHA3_keccak _Py_LibHacl_Hacl_Impl_SHA3_keccak
-#define Hacl_Impl_SHA3_loadState _Py_LibHacl_Hacl_Impl_SHA3_loadState
-#define Hacl_Impl_SHA3_squeeze _Py_LibHacl_Hacl_Impl_SHA3_squeeze
-#define Hacl_Impl_SHA3_state_permute _Py_LibHacl_Hacl_Impl_SHA3_state_permute
-#define Hacl_SHA3_sha3_224 _Py_LibHacl_Hacl_SHA3_sha3_224
-#define Hacl_SHA3_sha3_256 _Py_LibHacl_Hacl_SHA3_sha3_256
-#define Hacl_SHA3_sha3_384 _Py_LibHacl_Hacl_SHA3_sha3_384
-#define Hacl_SHA3_sha3_512 _Py_LibHacl_Hacl_SHA3_sha3_512
-#define Hacl_SHA3_shake128_hacl _Py_LibHacl_Hacl_SHA3_shake128_hacl
-#define Hacl_SHA3_shake256_hacl _Py_LibHacl_Hacl_SHA3_shake256_hacl
-#define Hacl_Hash_SHA3_block_len _Py_LibHacl_Hacl_Hash_SHA3_block_len
-#define Hacl_Hash_SHA3_copy _Py_LibHacl_Hacl_Hash_SHA3_copy
-#define Hacl_Hash_SHA3_digest _Py_LibHacl_Hacl_Hash_SHA3_digest
-#define Hacl_Hash_SHA3_free _Py_LibHacl_Hacl_Hash_SHA3_free
-#define Hacl_Hash_SHA3_get_alg _Py_LibHacl_Hacl_Hash_SHA3_get_alg
-#define Hacl_Hash_SHA3_hash_len _Py_LibHacl_Hacl_Hash_SHA3_hash_len
-#define Hacl_Hash_SHA3_is_shake _Py_LibHacl_Hacl_Hash_SHA3_is_shake
-#define Hacl_Hash_SHA3_init_ _Py_LibHacl_Hacl_Hash_SHA3_init_
-#define Hacl_Hash_SHA3_malloc _Py_LibHacl_Hacl_Hash_SHA3_malloc
-#define Hacl_Hash_SHA3_reset _Py_LibHacl_Hacl_Hash_SHA3_reset
-#define Hacl_Hash_SHA3_update _Py_LibHacl_Hacl_Hash_SHA3_update
-#define Hacl_Hash_SHA3_squeeze _Py_LibHacl_Hacl_Hash_SHA3_squeeze
+ diff -y --suppress-common-lines \
+ <(grep -P '^#define (?!_PY.+_H)' python_hacl_namespaces.h | sort -u) \
+ <(nm -j *.o | grep -i hacl | grep -P '^[a-zA-Z_][a-zA-Z0-9_]+' \
+ | sed -e 's/^_Py_LibHacl_//g' \
+ | sed 's/\(.*\)/#define \1 _Py_LibHacl_\1/g' | sort -u)
+ */
+// --- Utils ------------------------------------------------------------------
+#define Lib_Memzero0_memzero0 _Py_LibHacl_Lib_Memzero0_memzero0
+// --- HASH-BLAKE-2b ----------------------------------------------------------
+#define Hacl_Hash_Blake2b_copy _Py_LibHacl_Hacl_Hash_Blake2b_copy
+#define Hacl_Hash_Blake2b_digest _Py_LibHacl_Hacl_Hash_Blake2b_digest
+#define Hacl_Hash_Blake2b_finish _Py_LibHacl_Hacl_Hash_Blake2b_finish
+#define Hacl_Hash_Blake2b_free _Py_LibHacl_Hacl_Hash_Blake2b_free
+#define Hacl_Hash_Blake2b_hash_with_key _Py_LibHacl_Hacl_Hash_Blake2b_hash_with_key
+#define Hacl_Hash_Blake2b_hash_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2b_hash_with_key_and_params
+#define Hacl_Hash_Blake2b_info _Py_LibHacl_Hacl_Hash_Blake2b_info
+#define Hacl_Hash_Blake2b_init _Py_LibHacl_Hacl_Hash_Blake2b_init
+#define Hacl_Hash_Blake2b_malloc _Py_LibHacl_Hacl_Hash_Blake2b_malloc
+#define Hacl_Hash_Blake2b_malloc_with_key _Py_LibHacl_Hacl_Hash_Blake2b_malloc_with_key
+#define Hacl_Hash_Blake2b_malloc_with_params_and_key _Py_LibHacl_Hacl_Hash_Blake2b_malloc_with_params_and_key
+#define Hacl_Hash_Blake2b_reset _Py_LibHacl_Hacl_Hash_Blake2b_reset
+#define Hacl_Hash_Blake2b_reset_with_key _Py_LibHacl_Hacl_Hash_Blake2b_reset_with_key
+#define Hacl_Hash_Blake2b_reset_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2b_reset_with_key_and_params
#define Hacl_Hash_Blake2b_Simd256_copy _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_copy
#define Hacl_Hash_Blake2b_Simd256_copy_internal_state _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_copy_internal_state
#define Hacl_Hash_Blake2b_Simd256_digest _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_digest
@@ -104,7 +52,6 @@
#define Hacl_Hash_Blake2b_Simd256_malloc _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_malloc
#define Hacl_Hash_Blake2b_Simd256_malloc_internal_state_with_key _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_malloc_internal_state_with_key
#define Hacl_Hash_Blake2b_Simd256_malloc_with_key _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_malloc_with_key
-#define Hacl_Hash_Blake2b_Simd256_malloc_with_key0 _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_malloc_with_key0
#define Hacl_Hash_Blake2b_Simd256_malloc_with_params_and_key _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_malloc_with_params_and_key
#define Hacl_Hash_Blake2b_Simd256_reset _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_reset
#define Hacl_Hash_Blake2b_Simd256_reset_with_key _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_reset_with_key
@@ -115,23 +62,24 @@
#define Hacl_Hash_Blake2b_Simd256_update_last_no_inline _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_update_last_no_inline
#define Hacl_Hash_Blake2b_Simd256_update_multi _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_update_multi
#define Hacl_Hash_Blake2b_Simd256_update_multi_no_inline _Py_LibHacl_Hacl_Hash_Blake2b_Simd256_update_multi_no_inline
-#define Hacl_Hash_Blake2b_copy _Py_LibHacl_Hacl_Hash_Blake2b_copy
-#define Hacl_Hash_Blake2b_digest _Py_LibHacl_Hacl_Hash_Blake2b_digest
-#define Hacl_Hash_Blake2b_finish _Py_LibHacl_Hacl_Hash_Blake2b_finish
-#define Hacl_Hash_Blake2b_free _Py_LibHacl_Hacl_Hash_Blake2b_free
-#define Hacl_Hash_Blake2b_hash_with_key _Py_LibHacl_Hacl_Hash_Blake2b_hash_with_key
-#define Hacl_Hash_Blake2b_hash_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2b_hash_with_key_and_params
-#define Hacl_Hash_Blake2b_info _Py_LibHacl_Hacl_Hash_Blake2b_info
-#define Hacl_Hash_Blake2b_init _Py_LibHacl_Hacl_Hash_Blake2b_init
-#define Hacl_Hash_Blake2b_malloc _Py_LibHacl_Hacl_Hash_Blake2b_malloc
-#define Hacl_Hash_Blake2b_malloc_with_key _Py_LibHacl_Hacl_Hash_Blake2b_malloc_with_key
-#define Hacl_Hash_Blake2b_malloc_with_params_and_key _Py_LibHacl_Hacl_Hash_Blake2b_malloc_with_params_and_key
-#define Hacl_Hash_Blake2b_reset _Py_LibHacl_Hacl_Hash_Blake2b_reset
-#define Hacl_Hash_Blake2b_reset_with_key _Py_LibHacl_Hacl_Hash_Blake2b_reset_with_key
-#define Hacl_Hash_Blake2b_reset_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2b_reset_with_key_and_params
#define Hacl_Hash_Blake2b_update _Py_LibHacl_Hacl_Hash_Blake2b_update
#define Hacl_Hash_Blake2b_update_last _Py_LibHacl_Hacl_Hash_Blake2b_update_last
#define Hacl_Hash_Blake2b_update_multi _Py_LibHacl_Hacl_Hash_Blake2b_update_multi
+// --- HASH-BLAKE-2s ----------------------------------------------------------
+#define Hacl_Hash_Blake2s_copy _Py_LibHacl_Hacl_Hash_Blake2s_copy
+#define Hacl_Hash_Blake2s_digest _Py_LibHacl_Hacl_Hash_Blake2s_digest
+#define Hacl_Hash_Blake2s_finish _Py_LibHacl_Hacl_Hash_Blake2s_finish
+#define Hacl_Hash_Blake2s_free _Py_LibHacl_Hacl_Hash_Blake2s_free
+#define Hacl_Hash_Blake2s_hash_with_key _Py_LibHacl_Hacl_Hash_Blake2s_hash_with_key
+#define Hacl_Hash_Blake2s_hash_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2s_hash_with_key_and_params
+#define Hacl_Hash_Blake2s_info _Py_LibHacl_Hacl_Hash_Blake2s_info
+#define Hacl_Hash_Blake2s_init _Py_LibHacl_Hacl_Hash_Blake2s_init
+#define Hacl_Hash_Blake2s_malloc _Py_LibHacl_Hacl_Hash_Blake2s_malloc
+#define Hacl_Hash_Blake2s_malloc_with_key _Py_LibHacl_Hacl_Hash_Blake2s_malloc_with_key
+#define Hacl_Hash_Blake2s_malloc_with_params_and_key _Py_LibHacl_Hacl_Hash_Blake2s_malloc_with_params_and_key
+#define Hacl_Hash_Blake2s_reset _Py_LibHacl_Hacl_Hash_Blake2s_reset
+#define Hacl_Hash_Blake2s_reset_with_key _Py_LibHacl_Hacl_Hash_Blake2s_reset_with_key
+#define Hacl_Hash_Blake2s_reset_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2s_reset_with_key_and_params
#define Hacl_Hash_Blake2s_Simd128_copy _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_copy
#define Hacl_Hash_Blake2s_Simd128_copy_internal_state _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_copy_internal_state
#define Hacl_Hash_Blake2s_Simd128_digest _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_digest
@@ -145,7 +93,6 @@
#define Hacl_Hash_Blake2s_Simd128_malloc _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_malloc
#define Hacl_Hash_Blake2s_Simd128_malloc_internal_state_with_key _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_malloc_internal_state_with_key
#define Hacl_Hash_Blake2s_Simd128_malloc_with_key _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_malloc_with_key
-#define Hacl_Hash_Blake2s_Simd128_malloc_with_key0 _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_malloc_with_key0
#define Hacl_Hash_Blake2s_Simd128_malloc_with_params_and_key _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_malloc_with_params_and_key
#define Hacl_Hash_Blake2s_Simd128_reset _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_reset
#define Hacl_Hash_Blake2s_Simd128_reset_with_key _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_reset_with_key
@@ -156,37 +103,54 @@
#define Hacl_Hash_Blake2s_Simd128_update_last_no_inline _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_update_last_no_inline
#define Hacl_Hash_Blake2s_Simd128_update_multi _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_update_multi
#define Hacl_Hash_Blake2s_Simd128_update_multi_no_inline _Py_LibHacl_Hacl_Hash_Blake2s_Simd128_update_multi_no_inline
-#define Hacl_Hash_Blake2s_copy _Py_LibHacl_Hacl_Hash_Blake2s_copy
-#define Hacl_Hash_Blake2s_digest _Py_LibHacl_Hacl_Hash_Blake2s_digest
-#define Hacl_Hash_Blake2s_finish _Py_LibHacl_Hacl_Hash_Blake2s_finish
-#define Hacl_Hash_Blake2s_free _Py_LibHacl_Hacl_Hash_Blake2s_free
-#define Hacl_Hash_Blake2s_hash_with_key _Py_LibHacl_Hacl_Hash_Blake2s_hash_with_key
-#define Hacl_Hash_Blake2s_hash_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2s_hash_with_key_and_params
-#define Hacl_Hash_Blake2s_info _Py_LibHacl_Hacl_Hash_Blake2s_info
-#define Hacl_Hash_Blake2s_init _Py_LibHacl_Hacl_Hash_Blake2s_init
-#define Hacl_Hash_Blake2s_malloc _Py_LibHacl_Hacl_Hash_Blake2s_malloc
-#define Hacl_Hash_Blake2s_malloc_with_key _Py_LibHacl_Hacl_Hash_Blake2s_malloc_with_key
-#define Hacl_Hash_Blake2s_malloc_with_params_and_key _Py_LibHacl_Hacl_Hash_Blake2s_malloc_with_params_and_key
-#define Hacl_Hash_Blake2s_reset _Py_LibHacl_Hacl_Hash_Blake2s_reset
-#define Hacl_Hash_Blake2s_reset_with_key _Py_LibHacl_Hacl_Hash_Blake2s_reset_with_key
-#define Hacl_Hash_Blake2s_reset_with_key_and_params _Py_LibHacl_Hacl_Hash_Blake2s_reset_with_key_and_params
#define Hacl_Hash_Blake2s_update _Py_LibHacl_Hacl_Hash_Blake2s_update
#define Hacl_Hash_Blake2s_update_last _Py_LibHacl_Hacl_Hash_Blake2s_update_last
#define Hacl_Hash_Blake2s_update_multi _Py_LibHacl_Hacl_Hash_Blake2s_update_multi
+// --- HASH-MD5 ---------------------------------------------------------------
+#define Hacl_Hash_MD5_copy _Py_LibHacl_Hacl_Hash_MD5_copy
+#define Hacl_Hash_MD5_digest _Py_LibHacl_Hacl_Hash_MD5_digest
#define Hacl_Hash_MD5_finish _Py_LibHacl_Hacl_Hash_MD5_finish
+#define Hacl_Hash_MD5_free _Py_LibHacl_Hacl_Hash_MD5_free
+#define Hacl_Hash_MD5_hash _Py_LibHacl_Hacl_Hash_MD5_hash
#define Hacl_Hash_MD5_hash_oneshot _Py_LibHacl_Hacl_Hash_MD5_hash_oneshot
+#define Hacl_Hash_MD5_init _Py_LibHacl_Hacl_Hash_MD5_init
+#define Hacl_Hash_MD5_malloc _Py_LibHacl_Hacl_Hash_MD5_malloc
#define Hacl_Hash_MD5_reset _Py_LibHacl_Hacl_Hash_MD5_reset
+#define Hacl_Hash_MD5_update _Py_LibHacl_Hacl_Hash_MD5_update
#define Hacl_Hash_MD5_update_last _Py_LibHacl_Hacl_Hash_MD5_update_last
#define Hacl_Hash_MD5_update_multi _Py_LibHacl_Hacl_Hash_MD5_update_multi
+// --- HASH-SHA-1 -------------------------------------------------------------
+#define Hacl_Hash_SHA1_copy _Py_LibHacl_Hacl_Hash_SHA1_copy
+#define Hacl_Hash_SHA1_digest _Py_LibHacl_Hacl_Hash_SHA1_digest
#define Hacl_Hash_SHA1_finish _Py_LibHacl_Hacl_Hash_SHA1_finish
+#define Hacl_Hash_SHA1_free _Py_LibHacl_Hacl_Hash_SHA1_free
+#define Hacl_Hash_SHA1_hash _Py_LibHacl_Hacl_Hash_SHA1_hash
#define Hacl_Hash_SHA1_hash_oneshot _Py_LibHacl_Hacl_Hash_SHA1_hash_oneshot
+#define Hacl_Hash_SHA1_init _Py_LibHacl_Hacl_Hash_SHA1_init
+#define Hacl_Hash_SHA1_malloc _Py_LibHacl_Hacl_Hash_SHA1_malloc
#define Hacl_Hash_SHA1_reset _Py_LibHacl_Hacl_Hash_SHA1_reset
+#define Hacl_Hash_SHA1_update _Py_LibHacl_Hacl_Hash_SHA1_update
#define Hacl_Hash_SHA1_update_last _Py_LibHacl_Hacl_Hash_SHA1_update_last
#define Hacl_Hash_SHA1_update_multi _Py_LibHacl_Hacl_Hash_SHA1_update_multi
+// --- HASH-SHA-2 -------------------------------------------------------------
+#define Hacl_Hash_SHA2_copy_256 _Py_LibHacl_Hacl_Hash_SHA2_copy_256
+#define Hacl_Hash_SHA2_copy_512 _Py_LibHacl_Hacl_Hash_SHA2_copy_512
+#define Hacl_Hash_SHA2_digest_224 _Py_LibHacl_Hacl_Hash_SHA2_digest_224
+#define Hacl_Hash_SHA2_digest_256 _Py_LibHacl_Hacl_Hash_SHA2_digest_256
+#define Hacl_Hash_SHA2_digest_384 _Py_LibHacl_Hacl_Hash_SHA2_digest_384
+#define Hacl_Hash_SHA2_digest_512 _Py_LibHacl_Hacl_Hash_SHA2_digest_512
+#define Hacl_Hash_SHA2_free_224 _Py_LibHacl_Hacl_Hash_SHA2_free_224
+#define Hacl_Hash_SHA2_free_256 _Py_LibHacl_Hacl_Hash_SHA2_free_256
+#define Hacl_Hash_SHA2_free_384 _Py_LibHacl_Hacl_Hash_SHA2_free_384
+#define Hacl_Hash_SHA2_free_512 _Py_LibHacl_Hacl_Hash_SHA2_free_512
#define Hacl_Hash_SHA2_hash_224 _Py_LibHacl_Hacl_Hash_SHA2_hash_224
#define Hacl_Hash_SHA2_hash_256 _Py_LibHacl_Hacl_Hash_SHA2_hash_256
#define Hacl_Hash_SHA2_hash_384 _Py_LibHacl_Hacl_Hash_SHA2_hash_384
#define Hacl_Hash_SHA2_hash_512 _Py_LibHacl_Hacl_Hash_SHA2_hash_512
+#define Hacl_Hash_SHA2_malloc_224 _Py_LibHacl_Hacl_Hash_SHA2_malloc_224
+#define Hacl_Hash_SHA2_malloc_256 _Py_LibHacl_Hacl_Hash_SHA2_malloc_256
+#define Hacl_Hash_SHA2_malloc_384 _Py_LibHacl_Hacl_Hash_SHA2_malloc_384
+#define Hacl_Hash_SHA2_malloc_512 _Py_LibHacl_Hacl_Hash_SHA2_malloc_512
#define Hacl_Hash_SHA2_reset_224 _Py_LibHacl_Hacl_Hash_SHA2_reset_224
#define Hacl_Hash_SHA2_reset_256 _Py_LibHacl_Hacl_Hash_SHA2_reset_256
#define Hacl_Hash_SHA2_reset_384 _Py_LibHacl_Hacl_Hash_SHA2_reset_384
@@ -207,10 +171,25 @@
#define Hacl_Hash_SHA2_sha512_init _Py_LibHacl_Hacl_Hash_SHA2_sha512_init
#define Hacl_Hash_SHA2_sha512_update_last _Py_LibHacl_Hacl_Hash_SHA2_sha512_update_last
#define Hacl_Hash_SHA2_sha512_update_nblocks _Py_LibHacl_Hacl_Hash_SHA2_sha512_update_nblocks
+#define Hacl_Hash_SHA2_update_224 _Py_LibHacl_Hacl_Hash_SHA2_update_224
+#define Hacl_Hash_SHA2_update_256 _Py_LibHacl_Hacl_Hash_SHA2_update_256
+#define Hacl_Hash_SHA2_update_384 _Py_LibHacl_Hacl_Hash_SHA2_update_384
+#define Hacl_Hash_SHA2_update_512 _Py_LibHacl_Hacl_Hash_SHA2_update_512
+// --- HASH-SHA-3 -------------------------------------------------------------
#define Hacl_Hash_SHA3_absorb_inner_32 _Py_LibHacl_Hacl_Hash_SHA3_absorb_inner_32
+#define Hacl_Hash_SHA3_block_len _Py_LibHacl_Hacl_Hash_SHA3_block_len
+#define Hacl_Hash_SHA3_copy _Py_LibHacl_Hacl_Hash_SHA3_copy
+#define Hacl_Hash_SHA3_digest _Py_LibHacl_Hacl_Hash_SHA3_digest
+#define Hacl_Hash_SHA3_free _Py_LibHacl_Hacl_Hash_SHA3_free
+#define Hacl_Hash_SHA3_get_alg _Py_LibHacl_Hacl_Hash_SHA3_get_alg
+#define Hacl_Hash_SHA3_hash_len _Py_LibHacl_Hacl_Hash_SHA3_hash_len
+#define Hacl_Hash_SHA3_init_ _Py_LibHacl_Hacl_Hash_SHA3_init_
+#define Hacl_Hash_SHA3_is_shake _Py_LibHacl_Hacl_Hash_SHA3_is_shake
#define Hacl_Hash_SHA3_keccak_piln _Py_LibHacl_Hacl_Hash_SHA3_keccak_piln
#define Hacl_Hash_SHA3_keccak_rndc _Py_LibHacl_Hacl_Hash_SHA3_keccak_rndc
#define Hacl_Hash_SHA3_keccak_rotc _Py_LibHacl_Hacl_Hash_SHA3_keccak_rotc
+#define Hacl_Hash_SHA3_malloc _Py_LibHacl_Hacl_Hash_SHA3_malloc
+#define Hacl_Hash_SHA3_reset _Py_LibHacl_Hacl_Hash_SHA3_reset
#define Hacl_Hash_SHA3_sha3_224 _Py_LibHacl_Hacl_Hash_SHA3_sha3_224
#define Hacl_Hash_SHA3_sha3_256 _Py_LibHacl_Hacl_Hash_SHA3_sha3_256
#define Hacl_Hash_SHA3_sha3_384 _Py_LibHacl_Hacl_Hash_SHA3_sha3_384
@@ -220,37 +199,39 @@
#define Hacl_Hash_SHA3_shake128_absorb_nblocks _Py_LibHacl_Hacl_Hash_SHA3_shake128_absorb_nblocks
#define Hacl_Hash_SHA3_shake128_squeeze_nblocks _Py_LibHacl_Hacl_Hash_SHA3_shake128_squeeze_nblocks
#define Hacl_Hash_SHA3_shake256 _Py_LibHacl_Hacl_Hash_SHA3_shake256
+#define Hacl_Hash_SHA3_squeeze _Py_LibHacl_Hacl_Hash_SHA3_squeeze
#define Hacl_Hash_SHA3_state_free _Py_LibHacl_Hacl_Hash_SHA3_state_free
#define Hacl_Hash_SHA3_state_malloc _Py_LibHacl_Hacl_Hash_SHA3_state_malloc
-
-// Streaming HMAC
+#define Hacl_Hash_SHA3_update _Py_LibHacl_Hacl_Hash_SHA3_update
+#define Hacl_Hash_SHA3_update_last_sha3 _Py_LibHacl_Hacl_Hash_SHA3_update_last_sha3
+#define Hacl_Hash_SHA3_update_multi_sha3 _Py_LibHacl_Hacl_Hash_SHA3_update_multi_sha3
+// --- STREAMING-MAC ----------------------------------------------------------
+#define Hacl_Streaming_HMAC_copy _Py_LibHacl_Hacl_Streaming_HMAC_copy
+#define Hacl_Streaming_HMAC_digest _Py_LibHacl_Hacl_Streaming_HMAC_digest
+#define Hacl_Streaming_HMAC_free _Py_LibHacl_Hacl_Streaming_HMAC_free
+#define Hacl_Streaming_HMAC_get_impl _Py_LibHacl_Hacl_Streaming_HMAC_get_impl
#define Hacl_Streaming_HMAC_index_of_state _Py_LibHacl_Hacl_Streaming_HMAC_index_of_state
#define Hacl_Streaming_HMAC_malloc_ _Py_LibHacl_Hacl_Streaming_HMAC_malloc_
-#define Hacl_Streaming_HMAC_get_impl _Py_LibHacl_Hacl_Streaming_HMAC_get_impl
#define Hacl_Streaming_HMAC_reset _Py_LibHacl_Hacl_Streaming_HMAC_reset
-#define Hacl_Streaming_HMAC_update _Py_LibHacl_Hacl_Streaming_HMAC_update
-#define Hacl_Streaming_HMAC_digest _Py_LibHacl_Hacl_Streaming_HMAC_digest
-#define Hacl_Streaming_HMAC_copy _Py_LibHacl_Hacl_Streaming_HMAC_copy
-#define Hacl_Streaming_HMAC_free _Py_LibHacl_Hacl_Streaming_HMAC_free
#define Hacl_Streaming_HMAC_s1 _Py_LibHacl_Hacl_Streaming_HMAC_s1
#define Hacl_Streaming_HMAC_s2 _Py_LibHacl_Hacl_Streaming_HMAC_s2
-
-// HMAC-MD5
+#define Hacl_Streaming_HMAC_update _Py_LibHacl_Hacl_Streaming_HMAC_update
+// --- HMAC-MD5 ---------------------------------------------------------------
#define Hacl_HMAC_compute_md5 _Py_LibHacl_Hacl_HMAC_compute_md5
-// HMAC-SHA-1
+// --- HMAC-SHA-1 -------------------------------------------------------------
#define Hacl_HMAC_compute_sha1 _Py_LibHacl_Hacl_HMAC_compute_sha1
-// HMAC-SHA-2
+// --- HMAC-SHA-2 -------------------------------------------------------------
#define Hacl_HMAC_compute_sha2_224 _Py_LibHacl_Hacl_HMAC_compute_sha2_224
#define Hacl_HMAC_compute_sha2_256 _Py_LibHacl_Hacl_HMAC_compute_sha2_256
#define Hacl_HMAC_compute_sha2_384 _Py_LibHacl_Hacl_HMAC_compute_sha2_384
#define Hacl_HMAC_compute_sha2_512 _Py_LibHacl_Hacl_HMAC_compute_sha2_512
-// HMAC-SHA-3
+// --- HMAC-SHA-3 -------------------------------------------------------------
#define Hacl_HMAC_compute_sha3_224 _Py_LibHacl_Hacl_HMAC_compute_sha3_224
#define Hacl_HMAC_compute_sha3_256 _Py_LibHacl_Hacl_HMAC_compute_sha3_256
#define Hacl_HMAC_compute_sha3_384 _Py_LibHacl_Hacl_HMAC_compute_sha3_384
#define Hacl_HMAC_compute_sha3_512 _Py_LibHacl_Hacl_HMAC_compute_sha3_512
-// HMAC-BLAKE
-#define Hacl_HMAC_compute_blake2s_32 _Py_LibHacl_Hacl_HMAC_compute_blake2s_32
+// --- HMAC-BLAKE-2 -----------------------------------------------------------
#define Hacl_HMAC_compute_blake2b_32 _Py_LibHacl_Hacl_HMAC_compute_blake2b_32
+#define Hacl_HMAC_compute_blake2s_32 _Py_LibHacl_Hacl_HMAC_compute_blake2s_32
#endif // _PYTHON_HACL_NAMESPACES_H
diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh
index d91650b44bb..a6776282423 100755
--- a/Modules/_hacl/refresh.sh
+++ b/Modules/_hacl/refresh.sh
@@ -22,7 +22,7 @@ fi
# Update this when updating to a new version after verifying that the changes
# the update brings in are good.
-expected_hacl_star_rev=7720f6d4fc0468a99d5ea6120976bcc271e42727
+expected_hacl_star_rev=4ef25b547b377dcef855db4289c6a00580e7221c
hacl_dir="$(realpath "$1")"
cd "$(dirname "$0")"
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index 48eed5eac97..90a7391ebb0 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -38,6 +38,10 @@
#include <stdbool.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# define Py_HAS_OPENSSL3_SUPPORT
+#endif
+
#ifndef OPENSSL_THREADS
# error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL"
#endif
@@ -55,7 +59,7 @@
#define PY_OPENSSL_HAS_BLAKE2 1
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifdef Py_HAS_OPENSSL3_SUPPORT
#define PY_EVP_MD EVP_MD
#define PY_EVP_MD_fetch(algorithm, properties) EVP_MD_fetch(NULL, algorithm, properties)
#define PY_EVP_MD_up_ref(md) EVP_MD_up_ref(md)
@@ -77,12 +81,12 @@
* py_alias as keys.
*/
-enum Py_hash_type {
- Py_ht_evp, // usedforsecurity=True / default
- Py_ht_evp_nosecurity, // usedforsecurity=False
- Py_ht_mac, // HMAC
- Py_ht_pbkdf2, // PKBDF2
-};
+typedef enum Py_hash_type {
+ Py_ht_evp, // usedforsecurity=True / default
+ Py_ht_evp_nosecurity, // usedforsecurity=False
+ Py_ht_mac, // HMAC
+ Py_ht_pbkdf2, // PKBDF2
+} Py_hash_type;
typedef struct {
const char *py_name;
@@ -251,14 +255,15 @@ py_hashentry_table_new(void) {
return NULL;
}
-/* Module state */
+// --- Module state -----------------------------------------------------------
+
static PyModuleDef _hashlibmodule;
typedef struct {
- PyTypeObject *EVPtype;
- PyTypeObject *HMACtype;
+ PyTypeObject *HASH_type; // based on EVP_MD
+ PyTypeObject *HMAC_type;
#ifdef PY_OPENSSL_HAS_SHAKE
- PyTypeObject *EVPXOFtype;
+ PyTypeObject *HASHXOF_type; // based on EVP_MD
#endif
PyObject *constructs;
PyObject *unsupported_digestmod_error;
@@ -273,42 +278,41 @@ get_hashlib_state(PyObject *module)
return (_hashlibstate *)state;
}
+// --- Module objects ---------------------------------------------------------
+
typedef struct {
- PyObject_HEAD
- EVP_MD_CTX *ctx; /* OpenSSL message digest context */
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex; /* OpenSSL context lock */
-} EVPobject;
+ HASHLIB_OBJECT_HEAD
+ EVP_MD_CTX *ctx; /* OpenSSL message digest context */
+} HASHobject;
-#define EVPobject_CAST(op) ((EVPobject *)(op))
+#define HASHobject_CAST(op) ((HASHobject *)(op))
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
HMAC_CTX *ctx; /* OpenSSL hmac context */
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex; /* HMAC context lock */
} HMACobject;
#define HMACobject_CAST(op) ((HMACobject *)(op))
-#include "clinic/_hashopenssl.c.h"
+// --- Module clinic configuration --------------------------------------------
+
/*[clinic input]
module _hashlib
-class _hashlib.HASH "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPtype"
-class _hashlib.HASHXOF "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPXOFtype"
-class _hashlib.HMAC "HMACobject *" "((_hashlibstate *)PyModule_GetState(module))->HMACtype"
+class _hashlib.HASH "HASHobject *" "&PyType_Type"
+class _hashlib.HASHXOF "HASHobject *" "&PyType_Type"
+class _hashlib.HMAC "HMACobject *" "&PyType_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7df1bcf6f75cb8ef]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6b5c9ce5c28bdc58]*/
+#include "clinic/_hashopenssl.c.h"
/* LCOV_EXCL_START */
/* Set an exception of given type using the given OpenSSL error code. */
static void
-set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode)
+set_ssl_exception_from_errcode(PyObject *exc_type, unsigned long errcode)
{
+ assert(exc_type != NULL);
assert(errcode != 0);
/* ERR_ERROR_STRING(3) ensures that the messages below are ASCII */
@@ -317,13 +321,29 @@ set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode)
const char *reason = ERR_reason_error_string(errcode);
if (lib && func) {
- PyErr_Format(exc, "[%s: %s] %s", lib, func, reason);
+ PyErr_Format(exc_type, "[%s: %s] %s", lib, func, reason);
}
else if (lib) {
- PyErr_Format(exc, "[%s] %s", lib, reason);
+ PyErr_Format(exc_type, "[%s] %s", lib, reason);
}
else {
- PyErr_SetString(exc, reason);
+ PyErr_SetString(exc_type, reason);
+ }
+}
+
+/*
+ * Get an appropriate exception type for the given OpenSSL error code.
+ *
+ * The exception type depends on the error code reason.
+ */
+static PyObject *
+get_smart_ssl_exception_type(unsigned long errcode, PyObject *default_exc_type)
+{
+ switch (ERR_GET_REASON(errcode)) {
+ case ERR_R_MALLOC_FAILURE:
+ return PyExc_MemoryError;
+ default:
+ return default_exc_type;
}
}
@@ -331,73 +351,171 @@ set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode)
* Set an exception of given type.
*
* By default, the exception's message is constructed by using the last SSL
- * error that occurred. If no error occurred, the 'fallback_format' is used
- * to create a C-style formatted fallback message.
+ * error that occurred. If no error occurred, the 'fallback_message' is used
+ * to create an exception message.
*/
static void
-raise_ssl_error(PyObject *exc, const char *fallback_format, ...)
+raise_ssl_error(PyObject *exc_type, const char *fallback_message)
+{
+ assert(fallback_message != NULL);
+ unsigned long errcode = ERR_peek_last_error();
+ if (errcode) {
+ ERR_clear_error();
+ set_ssl_exception_from_errcode(exc_type, errcode);
+ }
+ else {
+ PyErr_SetString(exc_type, fallback_message);
+ }
+}
+
+/* Same as raise_ssl_error() but with a C-style formatted message. */
+static void
+raise_ssl_error_f(PyObject *exc_type, const char *fallback_format, ...)
{
assert(fallback_format != NULL);
unsigned long errcode = ERR_peek_last_error();
if (errcode) {
ERR_clear_error();
- set_ssl_exception_from_errcode(exc, errcode);
+ set_ssl_exception_from_errcode(exc_type, errcode);
}
else {
va_list vargs;
va_start(vargs, fallback_format);
- PyErr_FormatV(exc, fallback_format, vargs);
+ PyErr_FormatV(exc_type, fallback_format, vargs);
+ va_end(vargs);
+ }
+}
+
+/* Same as raise_ssl_error_f() with smart exception types. */
+static void
+raise_smart_ssl_error_f(PyObject *exc_type, const char *fallback_format, ...)
+{
+ unsigned long errcode = ERR_peek_last_error();
+ if (errcode) {
+ ERR_clear_error();
+ exc_type = get_smart_ssl_exception_type(errcode, exc_type);
+ set_ssl_exception_from_errcode(exc_type, errcode);
+ }
+ else {
+ va_list vargs;
+ va_start(vargs, fallback_format);
+ PyErr_FormatV(exc_type, fallback_format, vargs);
va_end(vargs);
}
}
/*
- * Set an exception with a generic default message after an error occurred.
- *
- * It can also be used without previous calls to SSL built-in functions,
- * in which case a generic error message is provided.
+ * Raise a ValueError with a default message after an error occurred.
+ * It can also be used without previous calls to SSL built-in functions.
*/
static inline void
-notify_ssl_error_occurred(void)
+notify_ssl_error_occurred(const char *message)
{
- raise_ssl_error(PyExc_ValueError, "no reason supplied");
+ raise_ssl_error(PyExc_ValueError, message);
}
-/* LCOV_EXCL_STOP */
-static PyObject*
-py_digest_name(const EVP_MD *md)
+/* Same as notify_ssl_error_occurred() for failed OpenSSL functions. */
+static inline void
+notify_ssl_error_occurred_in(const char *funcname)
{
- assert(md != NULL);
- int nid = EVP_MD_nid(md);
- const char *name = NULL;
- const py_hashentry_t *h;
+ raise_ssl_error_f(PyExc_ValueError,
+ "error in OpenSSL function %s()", funcname);
+}
+
+/* Same as notify_ssl_error_occurred_in() with smart exception types. */
+static inline void
+notify_smart_ssl_error_occurred_in(const char *funcname)
+{
+ raise_smart_ssl_error_f(PyExc_ValueError,
+ "error in OpenSSL function %s()", funcname);
+}
+/* LCOV_EXCL_STOP */
+
+/*
+ * OpenSSL provides a way to go from NIDs to digest names for hash functions
+ * but lacks this granularity for MAC objects where it is not possible to get
+ * the underlying digest name (only the block size and digest size are allowed
+ * to be recovered).
+ *
+ * In addition, OpenSSL aliases pollute the list of known digest names
+ * as OpenSSL appears to have its own definition of alias. In particular,
+ * the resulting list still contains duplicate and alternate names for several
+ * algorithms.
+ *
+ * Therefore, digest names, whether they are used by hash functions or HMAC,
+ * are handled through EVP_MD objects or directly by using some NID.
+ */
- for (h = py_hashes; h->py_name != NULL; h++) {
+/* Get a cached entry by OpenSSL NID. */
+static const py_hashentry_t *
+get_hashentry_by_nid(int nid)
+{
+ for (const py_hashentry_t *h = py_hashes; h->py_name != NULL; h++) {
if (h->ossl_nid == nid) {
- name = h->py_name;
- break;
+ return h;
}
}
+ return NULL;
+}
+
+/*
+ * Convert the NID to a string via OBJ_nid2*() functions.
+ *
+ * If 'nid' cannot be resolved, set an exception and return NULL.
+ */
+static const char *
+get_asn1_utf8name_by_nid(int nid)
+{
+ const char *name = OBJ_nid2ln(nid);
if (name == NULL) {
- /* Ignore aliased names and only use long, lowercase name. The aliases
- * pollute the list and OpenSSL appears to have its own definition of
- * alias as the resulting list still contains duplicate and alternate
- * names for several algorithms.
- */
- name = OBJ_nid2ln(nid);
- if (name == NULL)
- name = OBJ_nid2sn(nid);
+ // In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise.
+ assert(ERR_peek_last_error() != 0);
+ if (ERR_GET_REASON(ERR_peek_last_error()) != OBJ_R_UNKNOWN_NID) {
+ goto error;
+ }
+ // fallback to short name and unconditionally propagate errors
+ name = OBJ_nid2sn(nid);
+ if (name == NULL) {
+ goto error;
+ }
}
+ return name;
- return PyUnicode_FromString(name);
+error:
+ raise_ssl_error_f(PyExc_ValueError, "cannot resolve NID %d", nid);
+ return NULL;
}
-/* Get EVP_MD by HID and purpose */
-static PY_EVP_MD*
-py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
+/*
+ * Convert the NID to an OpenSSL digest name.
+ *
+ * On error, set an exception and return NULL.
+ */
+static const char *
+get_hashlib_utf8name_by_nid(int nid)
{
- PY_EVP_MD *digest = NULL;
- PY_EVP_MD *other_digest = NULL;
+ const py_hashentry_t *e = get_hashentry_by_nid(nid);
+ return e ? e->py_name : get_asn1_utf8name_by_nid(nid);
+}
+
+/* Same as get_hashlib_utf8name_by_nid() but using an EVP_MD object. */
+static const char *
+get_hashlib_utf8name_by_evp_md(const EVP_MD *md)
+{
+ assert(md != NULL);
+ return get_hashlib_utf8name_by_nid(EVP_MD_nid(md));
+}
+
+/*
+ * Get a new reference to an EVP_MD object described by name and purpose.
+ *
+ * If 'name' is an OpenSSL indexed name, the return value is cached.
+ */
+static PY_EVP_MD *
+get_openssl_evp_md_by_utf8name(PyObject *module, const char *name,
+ Py_hash_type py_ht)
+{
+ PY_EVP_MD *digest = NULL, *other_digest = NULL;
_hashlibstate *state = get_hashlib_state(module);
py_hashentry_t *entry = (py_hashentry_t *)_Py_hashtable_get(
state->hashtable, (const void*)name
@@ -431,15 +549,16 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
#endif
}
break;
+ default:
+ goto invalid_hash_type;
}
// if another thread same thing at same time make sure we got same ptr
assert(other_digest == NULL || other_digest == digest);
- if (digest != NULL) {
- if (other_digest == NULL) {
- PY_EVP_MD_up_ref(digest);
- }
+ if (digest != NULL && other_digest == NULL) {
+ PY_EVP_MD_up_ref(digest);
}
- } else {
+ }
+ else {
// Fall back for looking up an unindexed OpenSSL specific name.
switch (py_ht) {
case Py_ht_evp:
@@ -450,66 +569,94 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
case Py_ht_evp_nosecurity:
digest = PY_EVP_MD_fetch(name, "-fips");
break;
+ default:
+ goto invalid_hash_type;
}
}
if (digest == NULL) {
- raise_ssl_error(state->unsupported_digestmod_error,
- "unsupported hash type %s", name);
+ raise_ssl_error_f(state->unsupported_digestmod_error,
+ "unsupported digest name: %s", name);
return NULL;
}
return digest;
+
+invalid_hash_type:
+ assert(digest == NULL);
+ PyErr_Format(PyExc_SystemError, "unsupported hash type %d", py_ht);
+ return NULL;
}
-/* Get digest EVP from object
+/*
+ * Raise an exception indicating that 'digestmod' is not supported.
+ */
+static void
+raise_unsupported_digestmod_error(PyObject *module, PyObject *digestmod)
+{
+ _hashlibstate *state = get_hashlib_state(module);
+ PyErr_Format(state->unsupported_digestmod_error,
+ "Unsupported digestmod %R", digestmod);
+}
+
+/*
+ * Get a new reference to an EVP_MD described by 'digestmod' and purpose.
+ *
+ * On error, set an exception and return NULL.
*
- * * string
- * * _hashopenssl builtin function
+ * Parameters
*
- * on error returns NULL with exception set.
+ * digestmod A digest name or a _hashopenssl builtin function
+ * py_ht The message digest purpose.
*/
-static PY_EVP_MD*
-py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type py_ht) {
- PyObject *name_obj = NULL;
+static PY_EVP_MD *
+get_openssl_evp_md(PyObject *module, PyObject *digestmod, Py_hash_type py_ht)
+{
const char *name;
-
if (PyUnicode_Check(digestmod)) {
- name_obj = digestmod;
- } else {
- _hashlibstate *state = get_hashlib_state(module);
- // borrowed ref
- name_obj = PyDict_GetItemWithError(state->constructs, digestmod);
+ name = PyUnicode_AsUTF8(digestmod);
+ }
+ else {
+ PyObject *dict = get_hashlib_state(module)->constructs;
+ assert(dict != NULL);
+ PyObject *borrowed_ref = PyDict_GetItemWithError(dict, digestmod);
+ name = borrowed_ref == NULL ? NULL : PyUnicode_AsUTF8(borrowed_ref);
}
- if (name_obj == NULL) {
+ if (name == NULL) {
if (!PyErr_Occurred()) {
- _hashlibstate *state = get_hashlib_state(module);
- PyErr_Format(
- state->unsupported_digestmod_error,
- "Unsupported digestmod %R", digestmod);
+ raise_unsupported_digestmod_error(module, digestmod);
}
return NULL;
}
+ return get_openssl_evp_md_by_utf8name(module, name, py_ht);
+}
- name = PyUnicode_AsUTF8(name_obj);
- if (name == NULL) {
+// --- OpenSSL HASH wrappers --------------------------------------------------
+
+/* Thin wrapper around EVP_MD_CTX_new() which sets an exception on failure. */
+static EVP_MD_CTX *
+py_wrapper_EVP_MD_CTX_new(void)
+{
+ EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ if (ctx == NULL) {
+ PyErr_NoMemory();
return NULL;
}
-
- return py_digest_by_name(module, name, py_ht);
+ return ctx;
}
-static EVPobject *
-newEVPobject(PyTypeObject *type)
+// --- HASH interface ---------------------------------------------------------
+
+static HASHobject *
+new_hash_object(PyTypeObject *type)
{
- EVPobject *retval = PyObject_New(EVPobject, type);
+ HASHobject *retval = PyObject_New(HASHobject, type);
if (retval == NULL) {
return NULL;
}
HASHLIB_INIT_MUTEX(retval);
- retval->ctx = EVP_MD_CTX_new();
+ retval->ctx = py_wrapper_EVP_MD_CTX_new();
if (retval->ctx == NULL) {
Py_DECREF(retval);
- PyErr_NoMemory();
return NULL;
}
@@ -517,7 +664,7 @@ newEVPobject(PyTypeObject *type)
}
static int
-EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
+_hashlib_HASH_hash(HASHobject *self, const void *vp, Py_ssize_t len)
{
unsigned int process;
const unsigned char *cp = (const unsigned char *)vp;
@@ -527,7 +674,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
else
process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
if (!EVP_DigestUpdate(self->ctx, (const void*)cp, process)) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestUpdate));
return -1;
}
len -= process;
@@ -539,9 +686,9 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
/* Internal methods for a hash object */
static void
-EVP_dealloc(PyObject *op)
+_hashlib_HASH_dealloc(PyObject *op)
{
- EVPobject *self = EVPobject_CAST(op);
+ HASHobject *self = HASHobject_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
EVP_MD_CTX_free(self->ctx);
PyObject_Free(self);
@@ -549,120 +696,98 @@ EVP_dealloc(PyObject *op)
}
static int
-locked_EVP_MD_CTX_copy(EVP_MD_CTX *new_ctx_p, EVPobject *self)
+_hashlib_HASH_copy_locked(HASHobject *self, EVP_MD_CTX *new_ctx_p)
{
int result;
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
result = EVP_MD_CTX_copy(new_ctx_p, self->ctx);
- LEAVE_HASHLIB(self);
- return result;
+ HASHLIB_RELEASE_LOCK(self);
+ if (result == 0) {
+ notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MD_CTX_copy));
+ return -1;
+ }
+ return 0;
}
/* External methods for a hash object */
/*[clinic input]
-_hashlib.HASH.copy as EVP_copy
+_hashlib.HASH.copy
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
-EVP_copy_impl(EVPobject *self)
-/*[clinic end generated code: output=b370c21cdb8ca0b4 input=31455b6a3e638069]*/
+_hashlib_HASH_copy_impl(HASHobject *self)
+/*[clinic end generated code: output=2545541af18d53d7 input=814b19202cd08a26]*/
{
- EVPobject *newobj;
+ HASHobject *newobj;
- if ((newobj = newEVPobject(Py_TYPE(self))) == NULL)
+ if ((newobj = new_hash_object(Py_TYPE(self))) == NULL)
return NULL;
- if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) {
+ if (_hashlib_HASH_copy_locked(self, newobj->ctx) < 0) {
Py_DECREF(newobj);
- notify_ssl_error_occurred();
return NULL;
}
return (PyObject *)newobj;
}
-/*[clinic input]
-_hashlib.HASH.digest as EVP_digest
-
-Return the digest value as a bytes object.
-[clinic start generated code]*/
-
-static PyObject *
-EVP_digest_impl(EVPobject *self)
-/*[clinic end generated code: output=0f6a3a0da46dc12d input=03561809a419bf00]*/
+static Py_ssize_t
+_hashlib_HASH_digest_compute(HASHobject *self, unsigned char *digest)
{
- unsigned char digest[EVP_MAX_MD_SIZE];
- EVP_MD_CTX *temp_ctx;
- PyObject *retval;
- unsigned int digest_size;
-
- temp_ctx = EVP_MD_CTX_new();
- if (temp_ctx == NULL) {
- PyErr_NoMemory();
- return NULL;
+ EVP_MD_CTX *ctx = py_wrapper_EVP_MD_CTX_new();
+ if (ctx == NULL) {
+ return -1;
}
-
- if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
+ if (_hashlib_HASH_copy_locked(self, ctx) < 0) {
goto error;
}
- digest_size = EVP_MD_CTX_size(temp_ctx);
- if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
+ Py_ssize_t digest_size = EVP_MD_CTX_size(ctx);
+ if (!EVP_DigestFinal(ctx, digest, NULL)) {
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinal));
goto error;
}
-
- retval = PyBytes_FromStringAndSize((const char *)digest, digest_size);
- EVP_MD_CTX_free(temp_ctx);
- return retval;
+ EVP_MD_CTX_free(ctx);
+ return digest_size;
error:
- EVP_MD_CTX_free(temp_ctx);
- notify_ssl_error_occurred();
- return NULL;
+ EVP_MD_CTX_free(ctx);
+ return -1;
}
/*[clinic input]
-_hashlib.HASH.hexdigest as EVP_hexdigest
+_hashlib.HASH.digest
-Return the digest value as a string of hexadecimal digits.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-EVP_hexdigest_impl(EVPobject *self)
-/*[clinic end generated code: output=18e6decbaf197296 input=aff9cf0e4c741a9a]*/
+_hashlib_HASH_digest_impl(HASHobject *self)
+/*[clinic end generated code: output=3fc6f9671d712850 input=d8d528d6e50af0de]*/
{
unsigned char digest[EVP_MAX_MD_SIZE];
- EVP_MD_CTX *temp_ctx;
- unsigned int digest_size;
-
- temp_ctx = EVP_MD_CTX_new();
- if (temp_ctx == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
-
- /* Get the raw (binary) digest value */
- if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
- goto error;
- }
- digest_size = EVP_MD_CTX_size(temp_ctx);
- if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
- goto error;
- }
+ Py_ssize_t n = _hashlib_HASH_digest_compute(self, digest);
+ return n < 0 ? NULL : PyBytes_FromStringAndSize((const char *)digest, n);
+}
- EVP_MD_CTX_free(temp_ctx);
+/*[clinic input]
+_hashlib.HASH.hexdigest
- return _Py_strhex((const char *)digest, (Py_ssize_t)digest_size);
+Return the digest value as a string of hexadecimal digits.
+[clinic start generated code]*/
-error:
- EVP_MD_CTX_free(temp_ctx);
- notify_ssl_error_occurred();
- return NULL;
+static PyObject *
+_hashlib_HASH_hexdigest_impl(HASHobject *self)
+/*[clinic end generated code: output=1b8e60d9711e7f4d input=ae7553f78f8372d8]*/
+{
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ Py_ssize_t n = _hashlib_HASH_digest_compute(self, digest);
+ return n < 0 ? NULL : _Py_strhex((const char *)digest, n);
}
/*[clinic input]
-_hashlib.HASH.update as EVP_update
+_hashlib.HASH.update
obj: object
/
@@ -671,82 +796,70 @@ Update this hash object's state with the provided string.
[clinic start generated code]*/
static PyObject *
-EVP_update_impl(EVPobject *self, PyObject *obj)
-/*[clinic end generated code: output=d56f91c68348f95f input=9b30ec848f015501]*/
+_hashlib_HASH_update_impl(HASHobject *self, PyObject *obj)
+/*[clinic end generated code: output=62ad989754946b86 input=aa1ce20e3f92ceb6]*/
{
int result;
Py_buffer view;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
-
- if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- result = EVP_hash(self, view.buf, view.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- result = EVP_hash(self, view.buf, view.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, view.len,
+ result = _hashlib_HASH_hash(self, view.buf, view.len)
+ );
PyBuffer_Release(&view);
-
- if (result == -1)
- return NULL;
- Py_RETURN_NONE;
+ return result < 0 ? NULL : Py_None;
}
-static PyMethodDef EVP_methods[] = {
- EVP_UPDATE_METHODDEF
- EVP_DIGEST_METHODDEF
- EVP_HEXDIGEST_METHODDEF
- EVP_COPY_METHODDEF
+static PyMethodDef HASH_methods[] = {
+ _HASHLIB_HASH_COPY_METHODDEF
+ _HASHLIB_HASH_DIGEST_METHODDEF
+ _HASHLIB_HASH_HEXDIGEST_METHODDEF
+ _HASHLIB_HASH_UPDATE_METHODDEF
{NULL, NULL} /* sentinel */
};
static PyObject *
-EVP_get_block_size(PyObject *op, void *Py_UNUSED(closure))
+_hashlib_HASH_get_blocksize(PyObject *op, void *Py_UNUSED(closure))
{
- EVPobject *self = EVPobject_CAST(op);
+ HASHobject *self = HASHobject_CAST(op);
long block_size = EVP_MD_CTX_block_size(self->ctx);
return PyLong_FromLong(block_size);
}
static PyObject *
-EVP_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
+_hashlib_HASH_get_digestsize(PyObject *op, void *Py_UNUSED(closure))
{
- EVPobject *self = EVPobject_CAST(op);
+ HASHobject *self = HASHobject_CAST(op);
long size = EVP_MD_CTX_size(self->ctx);
return PyLong_FromLong(size);
}
static PyObject *
-EVP_get_name(PyObject *op, void *Py_UNUSED(closure))
+_hashlib_HASH_get_name(PyObject *op, void *Py_UNUSED(closure))
{
- EVPobject *self = EVPobject_CAST(op);
+ HASHobject *self = HASHobject_CAST(op);
const EVP_MD *md = EVP_MD_CTX_md(self->ctx);
if (md == NULL) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred("missing EVP_MD for HASH context");
return NULL;
}
- return py_digest_name(md);
+ const char *name = get_hashlib_utf8name_by_evp_md(md);
+ assert(name != NULL || PyErr_Occurred());
+ return name == NULL ? NULL : PyUnicode_FromString(name);
}
-static PyGetSetDef EVP_getseters[] = {
- {"digest_size", EVP_get_digest_size, NULL, NULL, NULL},
- {"block_size", EVP_get_block_size, NULL, NULL, NULL},
- {"name", EVP_get_name, NULL, NULL, PyDoc_STR("algorithm name.")},
+static PyGetSetDef HASH_getsets[] = {
+ {"digest_size", _hashlib_HASH_get_digestsize, NULL, NULL, NULL},
+ {"block_size", _hashlib_HASH_get_blocksize, NULL, NULL, NULL},
+ {"name", _hashlib_HASH_get_name, NULL, NULL, PyDoc_STR("algorithm name.")},
{NULL} /* Sentinel */
};
static PyObject *
-EVP_repr(PyObject *self)
+_hashlib_HASH_repr(PyObject *self)
{
- PyObject *name = EVP_get_name(self, NULL);
+ PyObject *name = _hashlib_HASH_get_name(self, NULL);
if (name == NULL) {
return NULL;
}
@@ -756,7 +869,7 @@ EVP_repr(PyObject *self)
return repr;
}
-PyDoc_STRVAR(hashtype_doc,
+PyDoc_STRVAR(HASHobject_type_doc,
"HASH(name, string=b\'\')\n"
"--\n"
"\n"
@@ -774,27 +887,31 @@ PyDoc_STRVAR(hashtype_doc,
"name -- the hash algorithm being used by this object\n"
"digest_size -- number of bytes in this hashes output");
-static PyType_Slot EVPtype_slots[] = {
- {Py_tp_dealloc, EVP_dealloc},
- {Py_tp_repr, EVP_repr},
- {Py_tp_doc, (char *)hashtype_doc},
- {Py_tp_methods, EVP_methods},
- {Py_tp_getset, EVP_getseters},
+static PyType_Slot HASHobject_type_slots[] = {
+ {Py_tp_dealloc, _hashlib_HASH_dealloc},
+ {Py_tp_repr, _hashlib_HASH_repr},
+ {Py_tp_doc, (char *)HASHobject_type_doc},
+ {Py_tp_methods, HASH_methods},
+ {Py_tp_getset, HASH_getsets},
{0, 0},
};
-static PyType_Spec EVPtype_spec = {
- "_hashlib.HASH", /*tp_name*/
- sizeof(EVPobject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
- EVPtype_slots
+static PyType_Spec HASHobject_type_spec = {
+ .name = "_hashlib.HASH",
+ .basicsize = sizeof(HASHobject),
+ .flags = (
+ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_DISALLOW_INSTANTIATION
+ | Py_TPFLAGS_IMMUTABLETYPE
+ ),
+ .slots = HASHobject_type_slots
};
#ifdef PY_OPENSSL_HAS_SHAKE
/*[clinic input]
-_hashlib.HASHXOF.digest as EVPXOF_digest
+_hashlib.HASHXOF.digest
length: Py_ssize_t
@@ -802,30 +919,40 @@ Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
-/*[clinic end generated code: output=ef9320c23280efad input=816a6537cea3d1db]*/
+_hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length)
+/*[clinic end generated code: output=dcb09335dd2fe908 input=3eb034ce03c55b21]*/
{
EVP_MD_CTX *temp_ctx;
- PyObject *retval = PyBytes_FromStringAndSize(NULL, length);
+ PyObject *retval;
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative digest length");
+ return NULL;
+ }
+
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+
+ retval = PyBytes_FromStringAndSize(NULL, length);
if (retval == NULL) {
return NULL;
}
- temp_ctx = EVP_MD_CTX_new();
+ temp_ctx = py_wrapper_EVP_MD_CTX_new();
if (temp_ctx == NULL) {
Py_DECREF(retval);
- PyErr_NoMemory();
return NULL;
}
- if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
+ if (_hashlib_HASH_copy_locked(self, temp_ctx) < 0) {
goto error;
}
if (!EVP_DigestFinalXOF(temp_ctx,
(unsigned char*)PyBytes_AS_STRING(retval),
length))
{
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinalXOF));
goto error;
}
@@ -835,12 +962,11 @@ EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
error:
Py_DECREF(retval);
EVP_MD_CTX_free(temp_ctx);
- notify_ssl_error_occurred();
return NULL;
}
/*[clinic input]
-_hashlib.HASHXOF.hexdigest as EVPXOF_hexdigest
+_hashlib.HASHXOF.hexdigest
length: Py_ssize_t
@@ -848,31 +974,40 @@ Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
-EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
-/*[clinic end generated code: output=eb3e6ee7788bf5b2 input=5f9d6a8f269e34df]*/
+_hashlib_HASHXOF_hexdigest_impl(HASHobject *self, Py_ssize_t length)
+/*[clinic end generated code: output=519431cafa014f39 input=0e58f7238adb7ab8]*/
{
unsigned char *digest;
EVP_MD_CTX *temp_ctx;
PyObject *retval;
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative digest length");
+ return NULL;
+ }
+
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
+ }
+
digest = (unsigned char*)PyMem_Malloc(length);
if (digest == NULL) {
- PyErr_NoMemory();
+ (void)PyErr_NoMemory();
return NULL;
}
- temp_ctx = EVP_MD_CTX_new();
+ temp_ctx = py_wrapper_EVP_MD_CTX_new();
if (temp_ctx == NULL) {
PyMem_Free(digest);
- PyErr_NoMemory();
return NULL;
}
/* Get the raw (binary) digest value */
- if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
+ if (_hashlib_HASH_copy_locked(self, temp_ctx) < 0) {
goto error;
}
if (!EVP_DigestFinalXOF(temp_ctx, digest, length)) {
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinalXOF));
goto error;
}
@@ -885,29 +1020,29 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
error:
PyMem_Free(digest);
EVP_MD_CTX_free(temp_ctx);
- notify_ssl_error_occurred();
return NULL;
}
-static PyMethodDef EVPXOF_methods[] = {
- EVPXOF_DIGEST_METHODDEF
- EVPXOF_HEXDIGEST_METHODDEF
+static PyMethodDef HASHXOFobject_methods[] = {
+ _HASHLIB_HASHXOF_DIGEST_METHODDEF
+ _HASHLIB_HASHXOF_HEXDIGEST_METHODDEF
{NULL, NULL} /* sentinel */
};
static PyObject *
-EVPXOF_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure))
+_hashlib_HASHXOF_digest_size(PyObject *Py_UNUSED(self),
+ void *Py_UNUSED(closure))
{
return PyLong_FromLong(0);
}
-static PyGetSetDef EVPXOF_getseters[] = {
- {"digest_size", EVPXOF_get_digest_size, NULL, NULL, NULL},
+static PyGetSetDef HASHXOFobject_getsets[] = {
+ {"digest_size", _hashlib_HASHXOF_digest_size, NULL, NULL, NULL},
{NULL} /* Sentinel */
};
-PyDoc_STRVAR(hashxoftype_doc,
+PyDoc_STRVAR(HASHXOFobject_type_doc,
"HASHXOF(name, string=b\'\')\n"
"--\n"
"\n"
@@ -925,38 +1060,42 @@ PyDoc_STRVAR(hashxoftype_doc,
"name -- the hash algorithm being used by this object\n"
"digest_size -- number of bytes in this hashes output");
-static PyType_Slot EVPXOFtype_slots[] = {
- {Py_tp_doc, (char *)hashxoftype_doc},
- {Py_tp_methods, EVPXOF_methods},
- {Py_tp_getset, EVPXOF_getseters},
+static PyType_Slot HASHXOFobject_type_slots[] = {
+ {Py_tp_doc, (char *)HASHXOFobject_type_doc},
+ {Py_tp_methods, HASHXOFobject_methods},
+ {Py_tp_getset, HASHXOFobject_getsets},
{0, 0},
};
-static PyType_Spec EVPXOFtype_spec = {
- "_hashlib.HASHXOF", /*tp_name*/
- sizeof(EVPobject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
- EVPXOFtype_slots
+static PyType_Spec HASHXOFobject_type_spec = {
+ .name = "_hashlib.HASHXOF",
+ .basicsize = sizeof(HASHobject),
+ .flags = (
+ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_DISALLOW_INSTANTIATION
+ | Py_TPFLAGS_IMMUTABLETYPE
+ ),
+ .slots = HASHXOFobject_type_slots
};
#endif
-static PyObject*
-py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
- int usedforsecurity)
+static PyObject *
+_hashlib_HASH(PyObject *module, const char *digestname, PyObject *data_obj,
+ int usedforsecurity)
{
Py_buffer view = { 0 };
PY_EVP_MD *digest = NULL;
PyTypeObject *type;
- EVPobject *self = NULL;
+ HASHobject *self = NULL;
if (data_obj != NULL) {
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
}
- digest = py_digest_by_name(
+ digest = get_openssl_evp_md_by_utf8name(
module, digestname, usedforsecurity ? Py_ht_evp : Py_ht_evp_nosecurity
);
if (digest == NULL) {
@@ -964,12 +1103,12 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
}
if ((EVP_MD_flags(digest) & EVP_MD_FLAG_XOF) == EVP_MD_FLAG_XOF) {
- type = get_hashlib_state(module)->EVPXOFtype;
+ type = get_hashlib_state(module)->HASHXOF_type;
} else {
- type = get_hashlib_state(module)->EVPtype;
+ type = get_hashlib_state(module)->HASH_type;
}
- self = newEVPobject(type);
+ self = new_hash_object(type);
if (self == NULL) {
goto exit;
}
@@ -984,21 +1123,18 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
int result = EVP_DigestInit_ex(self->ctx, digest, NULL);
if (!result) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestInit_ex));
Py_CLEAR(self);
goto exit;
}
if (view.buf && view.len) {
- if (view.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- result = EVP_hash(self, view.buf, view.len);
- Py_END_ALLOW_THREADS
- } else {
- result = EVP_hash(self, view.buf, view.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ view.len,
+ result = _hashlib_HASH_hash(self, view.buf, view.len)
+ );
if (result == -1) {
assert(PyErr_Occurred());
Py_CLEAR(self);
@@ -1017,16 +1153,25 @@ exit:
return (PyObject *)self;
}
+#define CALL_HASHLIB_NEW(MODULE, NAME, DATA, STRING, USEDFORSECURITY) \
+ do { \
+ PyObject *data_obj; \
+ if (_Py_hashlib_data_argument(&data_obj, DATA, STRING) < 0) { \
+ return NULL; \
+ } \
+ return _hashlib_HASH(MODULE, NAME, data_obj, USEDFORSECURITY); \
+ } while (0)
/* The module-level function: new() */
/*[clinic input]
-_hashlib.new as EVP_new
+_hashlib.new as _hashlib_HASH_new
- name as name_obj: object
- string as data_obj: object(c_default="NULL") = b''
+ name: str
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Return a new hash object using the named algorithm.
@@ -1037,136 +1182,137 @@ The MD5 and SHA1 algorithms are always supported.
[clinic start generated code]*/
static PyObject *
-EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=ddd5053f92dffe90 input=c24554d0337be1b0]*/
+_hashlib_HASH_new_impl(PyObject *module, const char *name, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=b905aaf9840c1bbd input=c34af6c6e696d44e]*/
{
- char *name;
- if (!PyArg_Parse(name_obj, "s", &name)) {
- PyErr_SetString(PyExc_TypeError, "name must be a string");
- return NULL;
- }
- return py_evp_fromname(module, name, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, name, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_md5
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a md5 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=87b0186440a44f8c input=990e36d5e689b16e]*/
+_hashlib_openssl_md5_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=ca8cf184d90f7432 input=e7c0adbd6a867db1]*/
{
- return py_evp_fromname(module, Py_hash_md5, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_md5, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha1
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha1 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=6813024cf690670d input=948f2f4b6deabc10]*/
+_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=1736fb7b310d64be input=f7e5bb1711e952d8]*/
{
- return py_evp_fromname(module, Py_hash_sha1, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha1, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha224
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha224 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=a2dfe7cc4eb14ebb input=f9272821fadca505]*/
+_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=0d6ff57be5e5c140 input=3820fff7ed3a53b8]*/
{
- return py_evp_fromname(module, Py_hash_sha224, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha224, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha256
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha256 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=1f874a34870f0a68 input=549fad9d2930d4c5]*/
+_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=412ea7111555b6e7 input=9a2f115cf1f7e0eb]*/
{
- return py_evp_fromname(module, Py_hash_sha256, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha256, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha384
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha384 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=58529eff9ca457b2 input=48601a6e3bf14ad7]*/
+_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=2e0dc395b59ed726 input=1ea48f6f01e77cfb]*/
{
- return py_evp_fromname(module, Py_hash_sha384, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha384, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha512
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha512 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=2c744c9e4a40d5f6 input=c5c46a2a817aa98f]*/
+_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=4bdd760388dbfc0f input=3cf56903e07d1f5c]*/
{
- return py_evp_fromname(module, Py_hash_sha512, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha512, data, string, usedforsecurity);
}
@@ -1175,77 +1321,81 @@ _hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj,
/*[clinic input]
_hashlib.openssl_sha3_224
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha3-224 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=144641c1d144b974 input=e3a01b2888916157]*/
+_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=6d8dc2a924f3ba35 input=7f14f16a9f6a3158]*/
{
- return py_evp_fromname(module, Py_hash_sha3_224, data_obj, usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha3_224, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha3_256
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha3-256 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=c61f1ab772d06668 input=e2908126c1b6deed]*/
+_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=9e520f537b3a4622 input=7987150939d5e352]*/
{
- return py_evp_fromname(module, Py_hash_sha3_256, data_obj , usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha3_256, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha3_384
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha3-384 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=f68e4846858cf0ee input=ec0edf5c792f8252]*/
+_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=d239ba0463fd6138 input=fc943401f67e3b81]*/
{
- return py_evp_fromname(module, Py_hash_sha3_384, data_obj , usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha3_384, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_sha3_512
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a sha3-512 hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=2eede478c159354a input=64e2cc0c094d56f4]*/
+_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=17662f21038c2278 input=6601ddd2c6c1516d]*/
{
- return py_evp_fromname(module, Py_hash_sha3_512, data_obj , usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_sha3_512, data, string, usedforsecurity);
}
#endif /* PY_OPENSSL_HAS_SHA3 */
@@ -1253,42 +1403,46 @@ _hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj,
/*[clinic input]
_hashlib.openssl_shake_128
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a shake-128 variable hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=bc49cdd8ada1fa97 input=6c9d67440eb33ec8]*/
+_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=4e6afed8d18980ad input=373c3f1c93d87b37]*/
{
- return py_evp_fromname(module, Py_hash_shake_128, data_obj , usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_shake_128, data, string, usedforsecurity);
}
/*[clinic input]
_hashlib.openssl_shake_256
- string as data_obj: object(py_default="b''") = NULL
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Returns a shake-256 variable hash object; optionally initialized with a string
[clinic start generated code]*/
static PyObject *
-_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity)
-/*[clinic end generated code: output=358d213be8852df7 input=479cbe9fefd4a9f8]*/
+_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string)
+/*[clinic end generated code: output=62481bce4a77d16c input=101c139ea2ddfcbf]*/
{
- return py_evp_fromname(module, Py_hash_shake_256, data_obj , usedforsecurity);
+ CALL_HASHLIB_NEW(module, Py_hash_shake_256, data, string, usedforsecurity);
}
#endif /* PY_OPENSSL_HAS_SHAKE */
+#undef CALL_HASHLIB_NEW
+
/*[clinic input]
_hashlib.pbkdf2_hmac as pbkdf2_hmac
@@ -1312,7 +1466,7 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name,
long dklen;
int retval;
- PY_EVP_MD *digest = py_digest_by_name(module, hash_name, Py_ht_pbkdf2);
+ PY_EVP_MD *digest = get_openssl_evp_md_by_utf8name(module, hash_name, Py_ht_pbkdf2);
if (digest == NULL) {
goto end;
}
@@ -1375,7 +1529,7 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name,
if (!retval) {
Py_CLEAR(key_obj);
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(PKCS5_PBKDF2_HMAC));
goto end;
}
@@ -1451,8 +1605,8 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
/* let OpenSSL validate the rest */
retval = EVP_PBE_scrypt(NULL, 0, NULL, 0, n, r, p, maxmem, NULL, 0);
if (!retval) {
- raise_ssl_error(PyExc_ValueError,
- "Invalid parameter combination for n, r, p, maxmem.");
+ notify_ssl_error_occurred(
+ "Invalid parameter combination for n, r, p, maxmem.");
return NULL;
}
@@ -1473,7 +1627,7 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
if (!retval) {
Py_CLEAR(key_obj);
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_PBE_scrypt));
return NULL;
}
return key_obj;
@@ -1514,7 +1668,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
return NULL;
}
- evp = py_digest_by_digestmod(module, digest, Py_ht_mac);
+ evp = get_openssl_evp_md(module, digest, Py_ht_mac);
if (evp == NULL) {
return NULL;
}
@@ -1530,7 +1684,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
PY_EVP_MD_free(evp);
if (result == NULL) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC));
return NULL;
}
return PyBytes_FromStringAndSize((const char*)md, md_len);
@@ -1539,6 +1693,18 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
/* OpenSSL-based HMAC implementation
*/
+/* Thin wrapper around HMAC_CTX_new() which sets an exception on failure. */
+static HMAC_CTX *
+py_openssl_wrapper_HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx = HMAC_CTX_new();
+ if (ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ return ctx;
+}
+
static int _hmac_update(HMACobject*, PyObject*);
static const EVP_MD *
@@ -1546,7 +1712,7 @@ _hashlib_hmac_get_md(HMACobject *self)
{
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
if (md == NULL) {
- raise_ssl_error(PyExc_ValueError, "missing EVP_MD for HMAC context");
+ notify_ssl_error_occurred("missing EVP_MD for HMAC context");
}
return md;
}
@@ -1583,27 +1749,26 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
return NULL;
}
- digest = py_digest_by_digestmod(module, digestmod, Py_ht_mac);
+ digest = get_openssl_evp_md(module, digestmod, Py_ht_mac);
if (digest == NULL) {
return NULL;
}
- ctx = HMAC_CTX_new();
+ ctx = py_openssl_wrapper_HMAC_CTX_new();
if (ctx == NULL) {
PY_EVP_MD_free(digest);
- PyErr_NoMemory();
goto error;
}
r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */);
PY_EVP_MD_free(digest);
if (r == 0) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Init_ex));
goto error;
}
_hashlibstate *state = get_hashlib_state(module);
- self = PyObject_New(HMACobject, state->HMACtype);
+ self = PyObject_New(HMACobject, state->HMAC_type);
if (self == NULL) {
goto error;
}
@@ -1630,10 +1795,14 @@ static int
locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
{
int result;
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
result = HMAC_CTX_copy(new_ctx_p, self->ctx);
- LEAVE_HASHLIB(self);
- return result;
+ HASHLIB_RELEASE_LOCK(self);
+ if (result == 0) {
+ notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy));
+ return -1;
+ }
+ return 0;
}
/* returning 0 means that an error occurred and an exception is set */
@@ -1647,7 +1816,7 @@ _hashlib_hmac_digest_size(HMACobject *self)
unsigned int digest_size = EVP_MD_size(md);
assert(digest_size <= EVP_MAX_MD_SIZE);
if (digest_size == 0) {
- raise_ssl_error(PyExc_ValueError, "invalid digest size");
+ notify_ssl_error_occurred("invalid digest size");
}
return digest_size;
}
@@ -1659,28 +1828,16 @@ _hmac_update(HMACobject *self, PyObject *obj)
Py_buffer view = {0};
GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0);
-
- if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- r = HMAC_Update(self->ctx,
- (const unsigned char *)view.buf,
- (size_t)view.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- r = HMAC_Update(self->ctx,
- (const unsigned char *)view.buf,
- (size_t)view.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, view.len,
+ r = HMAC_Update(
+ self->ctx, (const unsigned char *)view.buf, (size_t)view.len
+ )
+ );
PyBuffer_Release(&view);
if (r == 0) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Update));
return 0;
}
return 1;
@@ -1698,13 +1855,12 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
{
HMACobject *retval;
- HMAC_CTX *ctx = HMAC_CTX_new();
+ HMAC_CTX *ctx = py_openssl_wrapper_HMAC_CTX_new();
if (ctx == NULL) {
- return PyErr_NoMemory();
+ return NULL;
}
- if (!locked_HMAC_CTX_copy(ctx, self)) {
+ if (locked_HMAC_CTX_copy(ctx, self) < 0) {
HMAC_CTX_free(ctx);
- notify_ssl_error_occurred();
return NULL;
}
@@ -1735,20 +1891,15 @@ _hmac_dealloc(PyObject *op)
static PyObject *
_hmac_repr(PyObject *op)
{
+ const char *digest_name;
HMACobject *self = HMACobject_CAST(op);
const EVP_MD *md = _hashlib_hmac_get_md(self);
- if (md == NULL) {
- return NULL;
- }
- PyObject *digest_name = py_digest_name(md);
+ digest_name = md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md);
if (digest_name == NULL) {
+ assert(PyErr_Occurred());
return NULL;
}
- PyObject *repr = PyUnicode_FromFormat(
- "<%U HMAC object @ %p>", digest_name, self
- );
- Py_DECREF(digest_name);
- return repr;
+ return PyUnicode_FromFormat("<%s HMAC object @ %p>", digest_name, self);
}
/*[clinic input]
@@ -1771,20 +1922,18 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg)
static int
_hmac_digest(HMACobject *self, unsigned char *buf, unsigned int len)
{
- HMAC_CTX *temp_ctx = HMAC_CTX_new();
+ HMAC_CTX *temp_ctx = py_openssl_wrapper_HMAC_CTX_new();
if (temp_ctx == NULL) {
- (void)PyErr_NoMemory();
return 0;
}
- if (!locked_HMAC_CTX_copy(temp_ctx, self)) {
+ if (locked_HMAC_CTX_copy(temp_ctx, self) < 0) {
HMAC_CTX_free(temp_ctx);
- notify_ssl_error_occurred();
return 0;
}
int r = HMAC_Final(temp_ctx, buf, &len);
HMAC_CTX_free(temp_ctx);
if (r == 0) {
- notify_ssl_error_occurred();
+ notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Final));
return 0;
}
return 1;
@@ -1860,13 +2009,12 @@ _hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure))
if (md == NULL) {
return NULL;
}
- PyObject *digest_name = py_digest_name(md);
+ const char *digest_name = get_hashlib_utf8name_by_evp_md(md);
if (digest_name == NULL) {
+ assert(PyErr_Occurred());
return NULL;
}
- PyObject *name = PyUnicode_FromFormat("hmac-%U", digest_name);
- Py_DECREF(digest_name);
- return name;
+ return PyUnicode_FromFormat("hmac-%s", digest_name);
}
static PyMethodDef HMAC_methods[] = {
@@ -1926,7 +2074,7 @@ typedef struct _internal_name_mapper_state {
/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
static void
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifdef Py_HAS_OPENSSL3_SUPPORT
_openssl_hash_name_mapper(EVP_MD *md, void *arg)
#else
_openssl_hash_name_mapper(const EVP_MD *md, const char *from,
@@ -1942,7 +2090,9 @@ _openssl_hash_name_mapper(const EVP_MD *md, const char *from,
return;
}
- py_name = py_digest_name(md);
+ const char *name = get_hashlib_utf8name_by_evp_md(md);
+ assert(name != NULL || PyErr_Occurred());
+ py_name = name == NULL ? NULL : PyUnicode_FromString(name);
if (py_name == NULL) {
state->error = 1;
} else {
@@ -1966,7 +2116,7 @@ hashlib_md_meth_names(PyObject *module)
return -1;
}
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifdef Py_HAS_OPENSSL3_SUPPORT
// get algorithms from all activated providers in default context
EVP_MD_do_all_provided(NULL, &_openssl_hash_name_mapper, &state);
#else
@@ -1999,21 +2149,18 @@ _hashlib_get_fips_mode_impl(PyObject *module)
/*[clinic end generated code: output=87eece1bab4d3fa9 input=2db61538c41c6fef]*/
{
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifdef Py_HAS_OPENSSL3_SUPPORT
return EVP_default_properties_is_fips_enabled(NULL);
#else
ERR_clear_error();
int result = FIPS_mode();
- if (result == 0) {
+ if (result == 0 && ERR_peek_last_error()) {
// "If the library was built without support of the FIPS Object Module,
// then the function will return 0 with an error code of
// CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)."
// But 0 is also a valid result value.
- unsigned long errcode = ERR_peek_last_error();
- if (errcode) {
- notify_ssl_error_occurred();
- return -1;
- }
+ notify_ssl_error_occurred_in(Py_STRINGIFY(FIPS_mode));
+ return -1;
}
return result;
#endif
@@ -2134,7 +2281,7 @@ _hashlib_compare_digest_impl(PyObject *module, PyObject *a, PyObject *b)
/* List of functions exported by this module */
static struct PyMethodDef EVP_functions[] = {
- EVP_NEW_METHODDEF
+ _HASHLIB_HASH_NEW_METHODDEF
PBKDF2_HMAC_METHODDEF
_HASHLIB_SCRYPT_METHODDEF
_HASHLIB_GET_FIPS_MODE_METHODDEF
@@ -2163,10 +2310,10 @@ static int
hashlib_traverse(PyObject *m, visitproc visit, void *arg)
{
_hashlibstate *state = get_hashlib_state(m);
- Py_VISIT(state->EVPtype);
- Py_VISIT(state->HMACtype);
+ Py_VISIT(state->HASH_type);
+ Py_VISIT(state->HMAC_type);
#ifdef PY_OPENSSL_HAS_SHAKE
- Py_VISIT(state->EVPXOFtype);
+ Py_VISIT(state->HASHXOF_type);
#endif
Py_VISIT(state->constructs);
Py_VISIT(state->unsupported_digestmod_error);
@@ -2177,10 +2324,10 @@ static int
hashlib_clear(PyObject *m)
{
_hashlibstate *state = get_hashlib_state(m);
- Py_CLEAR(state->EVPtype);
- Py_CLEAR(state->HMACtype);
+ Py_CLEAR(state->HASH_type);
+ Py_CLEAR(state->HMAC_type);
#ifdef PY_OPENSSL_HAS_SHAKE
- Py_CLEAR(state->EVPXOFtype);
+ Py_CLEAR(state->HASHXOF_type);
#endif
Py_CLEAR(state->constructs);
Py_CLEAR(state->unsupported_digestmod_error);
@@ -2214,37 +2361,37 @@ hashlib_init_hashtable(PyObject *module)
}
static int
-hashlib_init_evptype(PyObject *module)
+hashlib_init_HASH_type(PyObject *module)
{
_hashlibstate *state = get_hashlib_state(module);
- state->EVPtype = (PyTypeObject *)PyType_FromSpec(&EVPtype_spec);
- if (state->EVPtype == NULL) {
+ state->HASH_type = (PyTypeObject *)PyType_FromSpec(&HASHobject_type_spec);
+ if (state->HASH_type == NULL) {
return -1;
}
- if (PyModule_AddType(module, state->EVPtype) < 0) {
+ if (PyModule_AddType(module, state->HASH_type) < 0) {
return -1;
}
return 0;
}
static int
-hashlib_init_evpxoftype(PyObject *module)
+hashlib_init_HASHXOF_type(PyObject *module)
{
#ifdef PY_OPENSSL_HAS_SHAKE
_hashlibstate *state = get_hashlib_state(module);
- if (state->EVPtype == NULL) {
+ if (state->HASH_type == NULL) {
return -1;
}
- state->EVPXOFtype = (PyTypeObject *)PyType_FromSpecWithBases(
- &EVPXOFtype_spec, (PyObject *)state->EVPtype
+ state->HASHXOF_type = (PyTypeObject *)PyType_FromSpecWithBases(
+ &HASHXOFobject_type_spec, (PyObject *)state->HASH_type
);
- if (state->EVPXOFtype == NULL) {
+ if (state->HASHXOF_type == NULL) {
return -1;
}
- if (PyModule_AddType(module, state->EVPXOFtype) < 0) {
+ if (PyModule_AddType(module, state->HASHXOF_type) < 0) {
return -1;
}
#endif
@@ -2256,11 +2403,11 @@ hashlib_init_hmactype(PyObject *module)
{
_hashlibstate *state = get_hashlib_state(module);
- state->HMACtype = (PyTypeObject *)PyType_FromSpec(&HMACtype_spec);
- if (state->HMACtype == NULL) {
+ state->HMAC_type = (PyTypeObject *)PyType_FromSpec(&HMACtype_spec);
+ if (state->HMAC_type == NULL) {
return -1;
}
- if (PyModule_AddType(module, state->HMACtype) < 0) {
+ if (PyModule_AddType(module, state->HMAC_type) < 0) {
return -1;
}
return 0;
@@ -2341,8 +2488,8 @@ hashlib_constants(PyObject *module)
static PyModuleDef_Slot hashlib_slots[] = {
{Py_mod_exec, hashlib_init_hashtable},
- {Py_mod_exec, hashlib_init_evptype},
- {Py_mod_exec, hashlib_init_evpxoftype},
+ {Py_mod_exec, hashlib_init_HASH_type},
+ {Py_mod_exec, hashlib_init_HASHXOF_type},
{Py_mod_exec, hashlib_init_hmactype},
{Py_mod_exec, hashlib_md_meth_names},
{Py_mod_exec, hashlib_init_constructors},
diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c
index 80fe9cff985..560fe431fca 100644
--- a/Modules/_heapqmodule.c
+++ b/Modules/_heapqmodule.c
@@ -11,7 +11,8 @@ annotated by François Pinard, and converted to C by Raymond Hettinger.
#endif
#include "Python.h"
-#include "pycore_list.h" // _PyList_ITEMS()
+#include "pycore_list.h" // _PyList_ITEMS(), _PyList_AppendTakeRef()
+#include "pycore_pyatomic_ft_wrappers.h"
#include "clinic/_heapqmodule.c.h"
@@ -59,8 +60,8 @@ siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
arr = _PyList_ITEMS(heap);
parent = arr[parentpos];
newitem = arr[pos];
- arr[parentpos] = newitem;
- arr[pos] = parent;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[parentpos], newitem);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], parent);
pos = parentpos;
}
return 0;
@@ -108,8 +109,8 @@ siftup(PyListObject *heap, Py_ssize_t pos)
/* Move the smaller child up. */
tmp1 = arr[childpos];
tmp2 = arr[pos];
- arr[childpos] = tmp2;
- arr[pos] = tmp1;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[childpos], tmp2);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], tmp1);
pos = childpos;
}
/* Bubble it up to its final resting place (by sifting its parents down). */
@@ -117,6 +118,7 @@ siftup(PyListObject *heap, Py_ssize_t pos)
}
/*[clinic input]
+@critical_section heap
_heapq.heappush
heap: object(subclass_of='&PyList_Type')
@@ -128,13 +130,22 @@ Push item onto heap, maintaining the heap invariant.
static PyObject *
_heapq_heappush_impl(PyObject *module, PyObject *heap, PyObject *item)
-/*[clinic end generated code: output=912c094f47663935 input=7c69611f3698aceb]*/
+/*[clinic end generated code: output=912c094f47663935 input=f7a4f03ef8d52e67]*/
{
- if (PyList_Append(heap, item))
+ if (item == NULL) {
+ PyErr_BadInternalCall();
return NULL;
+ }
- if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
+ // In a free-threaded build, the heap is locked at this point.
+ // Therefore, calling _PyList_AppendTakeRef() is safe and no overhead.
+ if (_PyList_AppendTakeRef((PyListObject *)heap, Py_NewRef(item))) {
return NULL;
+ }
+
+ if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1)) {
+ return NULL;
+ }
Py_RETURN_NONE;
}
@@ -162,8 +173,9 @@ heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
if (!n)
return lastelt;
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, lastelt);
- if (siftup_func((PyListObject *)heap, 0)) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], lastelt);
+ if (siftup_func(list, 0)) {
Py_DECREF(returnitem);
return NULL;
}
@@ -171,6 +183,7 @@ heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
}
/*[clinic input]
+@critical_section heap
_heapq.heappop
heap: object(subclass_of='&PyList_Type')
@@ -181,7 +194,7 @@ Pop the smallest item off the heap, maintaining the heap invariant.
static PyObject *
_heapq_heappop_impl(PyObject *module, PyObject *heap)
-/*[clinic end generated code: output=96dfe82d37d9af76 input=91487987a583c856]*/
+/*[clinic end generated code: output=96dfe82d37d9af76 input=ed396461b153dd51]*/
{
return heappop_internal(heap, siftup);
}
@@ -197,8 +210,9 @@ heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObjec
}
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, Py_NewRef(item));
- if (siftup_func((PyListObject *)heap, 0)) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], Py_NewRef(item));
+ if (siftup_func(list, 0)) {
Py_DECREF(returnitem);
return NULL;
}
@@ -207,6 +221,7 @@ heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObjec
/*[clinic input]
+@critical_section heap
_heapq.heapreplace
heap: object(subclass_of='&PyList_Type')
@@ -226,12 +241,13 @@ this routine unless written as part of a conditional replacement:
static PyObject *
_heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item)
-/*[clinic end generated code: output=82ea55be8fbe24b4 input=719202ac02ba10c8]*/
+/*[clinic end generated code: output=82ea55be8fbe24b4 input=9be1678b817ef1a9]*/
{
return heapreplace_internal(heap, item, siftup);
}
/*[clinic input]
+@critical_section heap
_heapq.heappushpop
heap: object(subclass_of='&PyList_Type')
@@ -246,7 +262,7 @@ a separate call to heappop().
static PyObject *
_heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
-/*[clinic end generated code: output=67231dc98ed5774f input=5dc701f1eb4a4aa7]*/
+/*[clinic end generated code: output=67231dc98ed5774f input=db05c81b1dd92c44]*/
{
PyObject *returnitem;
int cmp;
@@ -271,8 +287,9 @@ _heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
}
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, Py_NewRef(item));
- if (siftup((PyListObject *)heap, 0)) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], Py_NewRef(item));
+ if (siftup(list, 0)) {
Py_DECREF(returnitem);
return NULL;
}
@@ -371,6 +388,7 @@ heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
}
/*[clinic input]
+@critical_section heap
_heapq.heapify
heap: object(subclass_of='&PyList_Type')
@@ -381,7 +399,7 @@ Transform list into a heap, in-place, in O(len(heap)) time.
static PyObject *
_heapq_heapify_impl(PyObject *module, PyObject *heap)
-/*[clinic end generated code: output=e63a636fcf83d6d0 input=53bb7a2166febb73]*/
+/*[clinic end generated code: output=e63a636fcf83d6d0 input=aaaaa028b9b6af08]*/
{
return heapify_internal(heap, siftup);
}
@@ -423,8 +441,8 @@ siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
arr = _PyList_ITEMS(heap);
parent = arr[parentpos];
newitem = arr[pos];
- arr[parentpos] = newitem;
- arr[pos] = parent;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[parentpos], newitem);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], parent);
pos = parentpos;
}
return 0;
@@ -472,17 +490,50 @@ siftup_max(PyListObject *heap, Py_ssize_t pos)
/* Move the smaller child up. */
tmp1 = arr[childpos];
tmp2 = arr[pos];
- arr[childpos] = tmp2;
- arr[pos] = tmp1;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[childpos], tmp2);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], tmp1);
pos = childpos;
}
/* Bubble it up to its final resting place (by sifting its parents down). */
return siftdown_max(heap, startpos, pos);
}
+/*[clinic input]
+@critical_section heap
+_heapq.heappush_max
+
+ heap: object(subclass_of='&PyList_Type')
+ item: object
+ /
+
+Push item onto max heap, maintaining the heap invariant.
+[clinic start generated code]*/
+
+static PyObject *
+_heapq_heappush_max_impl(PyObject *module, PyObject *heap, PyObject *item)
+/*[clinic end generated code: output=c869d5f9deb08277 input=c437e3d1ff8dcb70]*/
+{
+ if (item == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ // In a free-threaded build, the heap is locked at this point.
+ // Therefore, calling _PyList_AppendTakeRef() is safe and no overhead.
+ if (_PyList_AppendTakeRef((PyListObject *)heap, Py_NewRef(item))) {
+ return NULL;
+ }
+
+ if (siftdown_max((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1)) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
/*[clinic input]
-_heapq._heappop_max
+@critical_section heap
+_heapq.heappop_max
heap: object(subclass_of='&PyList_Type')
/
@@ -491,14 +542,15 @@ Maxheap variant of heappop.
[clinic start generated code]*/
static PyObject *
-_heapq__heappop_max_impl(PyObject *module, PyObject *heap)
-/*[clinic end generated code: output=9e77aadd4e6a8760 input=362c06e1c7484793]*/
+_heapq_heappop_max_impl(PyObject *module, PyObject *heap)
+/*[clinic end generated code: output=2f051195ab404b77 input=5d70c997798aec64]*/
{
return heappop_internal(heap, siftup_max);
}
/*[clinic input]
-_heapq._heapreplace_max
+@critical_section heap
+_heapq.heapreplace_max
heap: object(subclass_of='&PyList_Type')
item: object
@@ -508,15 +560,15 @@ Maxheap variant of heapreplace.
[clinic start generated code]*/
static PyObject *
-_heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
- PyObject *item)
-/*[clinic end generated code: output=8ad7545e4a5e8adb input=f2dd27cbadb948d7]*/
+_heapq_heapreplace_max_impl(PyObject *module, PyObject *heap, PyObject *item)
+/*[clinic end generated code: output=8770778b5a9cbe9b input=fe70175356e4a649]*/
{
return heapreplace_internal(heap, item, siftup_max);
}
/*[clinic input]
-_heapq._heapify_max
+@critical_section heap
+_heapq.heapify_max
heap: object(subclass_of='&PyList_Type')
/
@@ -525,21 +577,76 @@ Maxheap variant of heapify.
[clinic start generated code]*/
static PyObject *
-_heapq__heapify_max_impl(PyObject *module, PyObject *heap)
-/*[clinic end generated code: output=2cb028beb4a8b65e input=c1f765ee69f124b8]*/
+_heapq_heapify_max_impl(PyObject *module, PyObject *heap)
+/*[clinic end generated code: output=8401af3856529807 input=4eee63231e7d1573]*/
{
return heapify_internal(heap, siftup_max);
}
+/*[clinic input]
+@critical_section heap
+_heapq.heappushpop_max
+
+ heap: object(subclass_of='&PyList_Type')
+ item: object
+ /
+
+Maxheap variant of heappushpop.
+
+The combined action runs more efficiently than heappush_max() followed by
+a separate call to heappop_max().
+[clinic start generated code]*/
+
+static PyObject *
+_heapq_heappushpop_max_impl(PyObject *module, PyObject *heap, PyObject *item)
+/*[clinic end generated code: output=ff0019f0941aca0d input=24d0defa6fd6df4a]*/
+{
+ PyObject *returnitem;
+ int cmp;
+
+ if (PyList_GET_SIZE(heap) == 0) {
+ return Py_NewRef(item);
+ }
+
+ PyObject *top = PyList_GET_ITEM(heap, 0);
+ Py_INCREF(top);
+ cmp = PyObject_RichCompareBool(item, top, Py_LT);
+ Py_DECREF(top);
+ if (cmp < 0) {
+ return NULL;
+ }
+ if (cmp == 0) {
+ return Py_NewRef(item);
+ }
+
+ if (PyList_GET_SIZE(heap) == 0) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+
+ returnitem = PyList_GET_ITEM(heap, 0);
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], Py_NewRef(item));
+ if (siftup_max(list, 0) < 0) {
+ Py_DECREF(returnitem);
+ return NULL;
+ }
+ return returnitem;
+}
+
static PyMethodDef heapq_methods[] = {
_HEAPQ_HEAPPUSH_METHODDEF
_HEAPQ_HEAPPUSHPOP_METHODDEF
_HEAPQ_HEAPPOP_METHODDEF
_HEAPQ_HEAPREPLACE_METHODDEF
_HEAPQ_HEAPIFY_METHODDEF
- _HEAPQ__HEAPPOP_MAX_METHODDEF
- _HEAPQ__HEAPIFY_MAX_METHODDEF
- _HEAPQ__HEAPREPLACE_MAX_METHODDEF
+
+ _HEAPQ_HEAPPUSH_MAX_METHODDEF
+ _HEAPQ_HEAPPUSHPOP_MAX_METHODDEF
+ _HEAPQ_HEAPPOP_MAX_METHODDEF
+ _HEAPQ_HEAPREPLACE_MAX_METHODDEF
+ _HEAPQ_HEAPIFY_MAX_METHODDEF
+
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c
index 172cebcaa48..9c1f8615161 100644
--- a/Modules/_interpchannelsmodule.c
+++ b/Modules/_interpchannelsmodule.c
@@ -20,9 +20,11 @@
#endif
#define REGISTERS_HEAP_TYPES
+#define HAS_FALLBACK
#define HAS_UNBOUND_ITEMS
#include "_interpreters_common.h"
#undef HAS_UNBOUND_ITEMS
+#undef HAS_FALLBACK
#undef REGISTERS_HEAP_TYPES
@@ -218,6 +220,22 @@ wait_for_lock(PyThread_type_lock mutex, PY_TIMEOUT_T timeout)
return 0;
}
+static int
+ensure_highlevel_module_loaded(void)
+{
+ PyObject *highlevel =
+ PyImport_ImportModule("concurrent.interpreters._channels");
+ if (highlevel == NULL) {
+ PyErr_Clear();
+ highlevel = PyImport_ImportModule("test.support.channels");
+ if (highlevel == NULL) {
+ return -1;
+ }
+ }
+ Py_DECREF(highlevel);
+ return 0;
+}
+
/* module state *************************************************************/
@@ -252,10 +270,10 @@ _get_current_module_state(void)
{
PyObject *mod = _get_current_module();
if (mod == NULL) {
- // XXX import it?
- PyErr_SetString(PyExc_RuntimeError,
- MODULE_NAME_STR " module not imported yet");
- return NULL;
+ mod = PyImport_ImportModule(MODULE_NAME_STR);
+ if (mod == NULL) {
+ return NULL;
+ }
}
module_state *state = get_module_state(mod);
Py_DECREF(mod);
@@ -523,7 +541,7 @@ typedef struct _channelitem {
int64_t interpid;
_PyXIData_t *data;
_waiting_t *waiting;
- int unboundop;
+ unboundop_t unboundop;
struct _channelitem *next;
} _channelitem;
@@ -536,7 +554,7 @@ _channelitem_ID(_channelitem *item)
static void
_channelitem_init(_channelitem *item,
int64_t interpid, _PyXIData_t *data,
- _waiting_t *waiting, int unboundop)
+ _waiting_t *waiting, unboundop_t unboundop)
{
if (interpid < 0) {
interpid = _get_interpid(data);
@@ -583,7 +601,7 @@ _channelitem_clear(_channelitem *item)
static _channelitem *
_channelitem_new(int64_t interpid, _PyXIData_t *data,
- _waiting_t *waiting, int unboundop)
+ _waiting_t *waiting, unboundop_t unboundop)
{
_channelitem *item = GLOBAL_MALLOC(_channelitem);
if (item == NULL) {
@@ -694,7 +712,7 @@ _channelqueue_free(_channelqueue *queue)
static int
_channelqueue_put(_channelqueue *queue,
int64_t interpid, _PyXIData_t *data,
- _waiting_t *waiting, int unboundop)
+ _waiting_t *waiting, unboundop_t unboundop)
{
_channelitem *item = _channelitem_new(interpid, data, waiting, unboundop);
if (item == NULL) {
@@ -798,7 +816,7 @@ _channelqueue_remove(_channelqueue *queue, _channelitem_id_t itemid,
}
queue->count -= 1;
- int unboundop;
+ unboundop_t unboundop;
_channelitem_popped(item, p_data, p_waiting, &unboundop);
}
@@ -1083,16 +1101,18 @@ typedef struct _channel {
PyThread_type_lock mutex;
_channelqueue *queue;
_channelends *ends;
- struct {
- int unboundop;
+ struct _channeldefaults {
+ unboundop_t unboundop;
+ xidata_fallback_t fallback;
} defaults;
int open;
struct _channel_closing *closing;
} _channel_state;
static _channel_state *
-_channel_new(PyThread_type_lock mutex, int unboundop)
+_channel_new(PyThread_type_lock mutex, struct _channeldefaults defaults)
{
+ assert(check_unbound(defaults.unboundop));
_channel_state *chan = GLOBAL_MALLOC(_channel_state);
if (chan == NULL) {
return NULL;
@@ -1109,7 +1129,7 @@ _channel_new(PyThread_type_lock mutex, int unboundop)
GLOBAL_FREE(chan);
return NULL;
}
- chan->defaults.unboundop = unboundop;
+ chan->defaults = defaults;
chan->open = 1;
chan->closing = NULL;
return chan;
@@ -1130,7 +1150,7 @@ _channel_free(_channel_state *chan)
static int
_channel_add(_channel_state *chan, int64_t interpid,
- _PyXIData_t *data, _waiting_t *waiting, int unboundop)
+ _PyXIData_t *data, _waiting_t *waiting, unboundop_t unboundop)
{
int res = -1;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
@@ -1611,7 +1631,7 @@ done:
struct channel_id_and_info {
int64_t id;
- int unboundop;
+ struct _channeldefaults defaults;
};
static struct channel_id_and_info *
@@ -1628,7 +1648,7 @@ _channels_list_all(_channels *channels, int64_t *count)
for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
ids[i] = (struct channel_id_and_info){
.id = ref->cid,
- .unboundop = ref->chan->defaults.unboundop,
+ .defaults = ref->chan->defaults,
};
}
*count = channels->numopen;
@@ -1714,13 +1734,13 @@ _channel_finish_closing(_channel_state *chan) {
// Create a new channel.
static int64_t
-channel_create(_channels *channels, int unboundop)
+channel_create(_channels *channels, struct _channeldefaults defaults)
{
PyThread_type_lock mutex = PyThread_allocate_lock();
if (mutex == NULL) {
return ERR_CHANNEL_MUTEX_INIT;
}
- _channel_state *chan = _channel_new(mutex, unboundop);
+ _channel_state *chan = _channel_new(mutex, defaults);
if (chan == NULL) {
PyThread_free_lock(mutex);
return -1;
@@ -1752,7 +1772,7 @@ channel_destroy(_channels *channels, int64_t cid)
// Optionally request to be notified when it is received.
static int
channel_send(_channels *channels, int64_t cid, PyObject *obj,
- _waiting_t *waiting, int unboundop)
+ _waiting_t *waiting, unboundop_t unboundop, xidata_fallback_t fallback)
{
PyThreadState *tstate = _PyThreadState_GET();
PyInterpreterState *interp = tstate->interp;
@@ -1779,7 +1799,7 @@ channel_send(_channels *channels, int64_t cid, PyObject *obj,
PyThread_release_lock(mutex);
return -1;
}
- if (_PyObject_GetXIData(tstate, obj, data) != 0) {
+ if (_PyObject_GetXIData(tstate, obj, fallback, data) != 0) {
PyThread_release_lock(mutex);
GLOBAL_FREE(data);
return -1;
@@ -1823,7 +1843,8 @@ channel_clear_sent(_channels *channels, int64_t cid, _waiting_t *waiting)
// Like channel_send(), but strictly wait for the object to be received.
static int
channel_send_wait(_channels *channels, int64_t cid, PyObject *obj,
- int unboundop, PY_TIMEOUT_T timeout)
+ unboundop_t unboundop, PY_TIMEOUT_T timeout,
+ xidata_fallback_t fallback)
{
// We use a stack variable here, so we must ensure that &waiting
// is not held by any channel item at the point this function exits.
@@ -1834,7 +1855,7 @@ channel_send_wait(_channels *channels, int64_t cid, PyObject *obj,
}
/* Queue up the object. */
- int res = channel_send(channels, cid, obj, &waiting, unboundop);
+ int res = channel_send(channels, cid, obj, &waiting, unboundop, fallback);
if (res < 0) {
assert(waiting.status == WAITING_NO_STATUS);
goto finally;
@@ -2006,6 +2027,20 @@ channel_is_associated(_channels *channels, int64_t cid, int64_t interpid,
}
static int
+channel_get_defaults(_channels *channels, int64_t cid, struct _channeldefaults *defaults)
+{
+ PyThread_type_lock mutex = NULL;
+ _channel_state *channel = NULL;
+ int err = _channels_lookup(channels, cid, &mutex, &channel);
+ if (err != 0) {
+ return err;
+ }
+ *defaults = channel->defaults;
+ PyThread_release_lock(mutex);
+ return 0;
+}
+
+static int
_channel_get_count(_channels *channels, int64_t cid, Py_ssize_t *p_count)
{
PyThread_type_lock mutex = NULL;
@@ -2694,7 +2729,7 @@ add_channelid_type(PyObject *mod)
Py_DECREF(cls);
return NULL;
}
- if (ensure_xid_class(cls, _channelid_shared) < 0) {
+ if (ensure_xid_class(cls, GETDATA(_channelid_shared)) < 0) {
Py_DECREF(cls);
return NULL;
}
@@ -2723,15 +2758,9 @@ _get_current_channelend_type(int end)
}
if (cls == NULL) {
// Force the module to be loaded, to register the type.
- PyObject *highlevel = PyImport_ImportModule("interpreters.channels");
- if (highlevel == NULL) {
- PyErr_Clear();
- highlevel = PyImport_ImportModule("test.support.interpreters.channels");
- if (highlevel == NULL) {
- return NULL;
- }
+ if (ensure_highlevel_module_loaded() < 0) {
+ return NULL;
}
- Py_DECREF(highlevel);
if (end == CHANNEL_SEND) {
cls = state->send_channel_type;
}
@@ -2797,12 +2826,12 @@ set_channelend_types(PyObject *mod, PyTypeObject *send, PyTypeObject *recv)
// Add and register the types.
state->send_channel_type = (PyTypeObject *)Py_NewRef(send);
state->recv_channel_type = (PyTypeObject *)Py_NewRef(recv);
- if (ensure_xid_class(send, _channelend_shared) < 0) {
+ if (ensure_xid_class(send, GETDATA(_channelend_shared)) < 0) {
Py_CLEAR(state->send_channel_type);
Py_CLEAR(state->recv_channel_type);
return -1;
}
- if (ensure_xid_class(recv, _channelend_shared) < 0) {
+ if (ensure_xid_class(recv, GETDATA(_channelend_shared)) < 0) {
(void)clear_xid_class(state->send_channel_type);
Py_CLEAR(state->send_channel_type);
Py_CLEAR(state->recv_channel_type);
@@ -2881,20 +2910,27 @@ clear_interpreter(void *data)
static PyObject *
channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"unboundop", NULL};
- int unboundop;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:create", kwlist,
- &unboundop))
+ static char *kwlist[] = {"unboundop", "fallback", NULL};
+ int unboundarg = -1;
+ int fallbackarg = -1;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:create", kwlist,
+ &unboundarg, &fallbackarg))
{
return NULL;
}
- if (!check_unbound(unboundop)) {
- PyErr_Format(PyExc_ValueError,
- "unsupported unboundop %d", unboundop);
+ struct _channeldefaults defaults = {0};
+ if (resolve_unboundop(unboundarg, UNBOUND_REPLACE,
+ &defaults.unboundop) < 0)
+ {
+ return NULL;
+ }
+ if (resolve_fallback(fallbackarg, _PyXIDATA_FULL_FALLBACK,
+ &defaults.fallback) < 0)
+ {
return NULL;
}
- int64_t cid = channel_create(&_globals.channels, unboundop);
+ int64_t cid = channel_create(&_globals.channels, defaults);
if (cid < 0) {
(void)handle_channel_error(-1, self, cid);
return NULL;
@@ -2987,7 +3023,9 @@ channelsmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
}
assert(cidobj != NULL);
- PyObject *item = Py_BuildValue("Oi", cidobj, cur->unboundop);
+ PyObject *item = Py_BuildValue("Oii", cidobj,
+ cur->defaults.unboundop,
+ cur->defaults.fallback);
Py_DECREF(cidobj);
if (item == NULL) {
Py_SETREF(ids, NULL);
@@ -3075,40 +3113,54 @@ receive end.");
static PyObject *
channelsmod_send(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"cid", "obj", "unboundop", "blocking", "timeout",
- NULL};
+ static char *kwlist[] = {"cid", "obj", "unboundop", "fallback",
+ "blocking", "timeout", NULL};
struct channel_id_converter_data cid_data = {
.module = self,
};
PyObject *obj;
- int unboundop = UNBOUND_REPLACE;
+ int unboundarg = -1;
+ int fallbackarg = -1;
int blocking = 1;
PyObject *timeout_obj = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O|i$pO:channel_send", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O&O|ii$pO:channel_send", kwlist,
channel_id_converter, &cid_data, &obj,
- &unboundop, &blocking, &timeout_obj))
+ &unboundarg, &fallbackarg,
+ &blocking, &timeout_obj))
{
return NULL;
}
- if (!check_unbound(unboundop)) {
- PyErr_Format(PyExc_ValueError,
- "unsupported unboundop %d", unboundop);
- return NULL;
- }
-
int64_t cid = cid_data.cid;
PY_TIMEOUT_T timeout;
if (PyThread_ParseTimeoutArg(timeout_obj, blocking, &timeout) < 0) {
return NULL;
}
+ struct _channeldefaults defaults = {-1, -1};
+ if (unboundarg < 0 || fallbackarg < 0) {
+ int err = channel_get_defaults(&_globals.channels, cid, &defaults);
+ if (handle_channel_error(err, self, cid)) {
+ return NULL;
+ }
+ }
+ unboundop_t unboundop;
+ if (resolve_unboundop(unboundarg, defaults.unboundop, &unboundop) < 0) {
+ return NULL;
+ }
+ xidata_fallback_t fallback;
+ if (resolve_fallback(fallbackarg, defaults.fallback, &fallback) < 0) {
+ return NULL;
+ }
/* Queue up the object. */
int err = 0;
if (blocking) {
- err = channel_send_wait(&_globals.channels, cid, obj, unboundop, timeout);
+ err = channel_send_wait(
+ &_globals.channels, cid, obj, unboundop, timeout, fallback);
}
else {
- err = channel_send(&_globals.channels, cid, obj, NULL, unboundop);
+ err = channel_send(
+ &_globals.channels, cid, obj, NULL, unboundop, fallback);
}
if (handle_channel_error(err, self, cid)) {
return NULL;
@@ -3126,32 +3178,44 @@ By default this waits for the object to be received.");
static PyObject *
channelsmod_send_buffer(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"cid", "obj", "unboundop", "blocking", "timeout",
- NULL};
+ static char *kwlist[] = {"cid", "obj", "unboundop", "fallback",
+ "blocking", "timeout", NULL};
struct channel_id_converter_data cid_data = {
.module = self,
};
PyObject *obj;
- int unboundop = UNBOUND_REPLACE;
- int blocking = 1;
+ int unboundarg = -1;
+ int fallbackarg = -1;
+ int blocking = -1;
PyObject *timeout_obj = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "O&O|i$pO:channel_send_buffer", kwlist,
+ "O&O|ii$pO:channel_send_buffer", kwlist,
channel_id_converter, &cid_data, &obj,
- &unboundop, &blocking, &timeout_obj)) {
- return NULL;
- }
- if (!check_unbound(unboundop)) {
- PyErr_Format(PyExc_ValueError,
- "unsupported unboundop %d", unboundop);
+ &unboundarg, &fallbackarg,
+ &blocking, &timeout_obj))
+ {
return NULL;
}
-
int64_t cid = cid_data.cid;
PY_TIMEOUT_T timeout;
if (PyThread_ParseTimeoutArg(timeout_obj, blocking, &timeout) < 0) {
return NULL;
}
+ struct _channeldefaults defaults = {-1, -1};
+ if (unboundarg < 0 || fallbackarg < 0) {
+ int err = channel_get_defaults(&_globals.channels, cid, &defaults);
+ if (handle_channel_error(err, self, cid)) {
+ return NULL;
+ }
+ }
+ unboundop_t unboundop;
+ if (resolve_unboundop(unboundarg, defaults.unboundop, &unboundop) < 0) {
+ return NULL;
+ }
+ xidata_fallback_t fallback;
+ if (resolve_fallback(fallbackarg, defaults.fallback, &fallback) < 0) {
+ return NULL;
+ }
PyObject *tempobj = PyMemoryView_FromObject(obj);
if (tempobj == NULL) {
@@ -3162,10 +3226,11 @@ channelsmod_send_buffer(PyObject *self, PyObject *args, PyObject *kwds)
int err = 0;
if (blocking) {
err = channel_send_wait(
- &_globals.channels, cid, tempobj, unboundop, timeout);
+ &_globals.channels, cid, tempobj, unboundop, timeout, fallback);
}
else {
- err = channel_send(&_globals.channels, cid, tempobj, NULL, unboundop);
+ err = channel_send(
+ &_globals.channels, cid, tempobj, NULL, unboundop, fallback);
}
Py_DECREF(tempobj);
if (handle_channel_error(err, self, cid)) {
@@ -3197,7 +3262,7 @@ channelsmod_recv(PyObject *self, PyObject *args, PyObject *kwds)
cid = cid_data.cid;
PyObject *obj = NULL;
- int unboundop = 0;
+ unboundop_t unboundop = 0;
int err = channel_recv(&_globals.channels, cid, &obj, &unboundop);
if (err == ERR_CHANNEL_EMPTY && dflt != NULL) {
// Use the default.
@@ -3388,17 +3453,14 @@ channelsmod_get_channel_defaults(PyObject *self, PyObject *args, PyObject *kwds)
}
int64_t cid = cid_data.cid;
- PyThread_type_lock mutex = NULL;
- _channel_state *channel = NULL;
- int err = _channels_lookup(&_globals.channels, cid, &mutex, &channel);
+ struct _channeldefaults defaults = {0};
+ int err = channel_get_defaults(&_globals.channels, cid, &defaults);
if (handle_channel_error(err, self, cid)) {
return NULL;
}
- int unboundop = channel->defaults.unboundop;
- PyThread_release_lock(mutex);
- PyObject *defaults = Py_BuildValue("i", unboundop);
- return defaults;
+ PyObject *res = Py_BuildValue("ii", defaults.unboundop, defaults.fallback);
+ return res;
}
PyDoc_STRVAR(channelsmod_get_channel_defaults_doc,
@@ -3552,8 +3614,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
{
module_state *state = get_module_state(mod);
assert(state != NULL);
- (void)traverse_module_state(state, visit, arg);
- return 0;
+ return traverse_module_state(state, visit, arg);
}
static int
@@ -3563,8 +3624,7 @@ module_clear(PyObject *mod)
assert(state != NULL);
// Now we clear the module state.
- (void)clear_module_state(state);
- return 0;
+ return clear_module_state(state);
}
static void
diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c
index 526249a0e1a..e5afe746f90 100644
--- a/Modules/_interpqueuesmodule.c
+++ b/Modules/_interpqueuesmodule.c
@@ -9,9 +9,11 @@
#include "pycore_crossinterp.h" // _PyXIData_t
#define REGISTERS_HEAP_TYPES
+#define HAS_FALLBACK
#define HAS_UNBOUND_ITEMS
#include "_interpreters_common.h"
#undef HAS_UNBOUND_ITEMS
+#undef HAS_FALLBACK
#undef REGISTERS_HEAP_TYPES
@@ -134,13 +136,10 @@ idarg_int64_converter(PyObject *arg, void *ptr)
static int
ensure_highlevel_module_loaded(void)
{
- PyObject *highlevel = PyImport_ImportModule("interpreters.queues");
+ PyObject *highlevel =
+ PyImport_ImportModule("concurrent.interpreters._queues");
if (highlevel == NULL) {
- PyErr_Clear();
- highlevel = PyImport_ImportModule("test.support.interpreters.queues");
- if (highlevel == NULL) {
- return -1;
- }
+ return -1;
}
Py_DECREF(highlevel);
return 0;
@@ -297,7 +296,7 @@ add_QueueError(PyObject *mod)
{
module_state *state = get_module_state(mod);
-#define PREFIX "test.support.interpreters."
+#define PREFIX "concurrent.interpreters."
#define ADD_EXCTYPE(NAME, BASE, DOC) \
assert(state->NAME == NULL); \
if (add_exctype(mod, &state->NAME, PREFIX #NAME, DOC, BASE) < 0) { \
@@ -401,14 +400,13 @@ typedef struct _queueitem {
meaning the interpreter has been destroyed. */
int64_t interpid;
_PyXIData_t *data;
- int fmt;
- int unboundop;
+ unboundop_t unboundop;
struct _queueitem *next;
} _queueitem;
static void
_queueitem_init(_queueitem *item,
- int64_t interpid, _PyXIData_t *data, int fmt, int unboundop)
+ int64_t interpid, _PyXIData_t *data, unboundop_t unboundop)
{
if (interpid < 0) {
interpid = _get_interpid(data);
@@ -422,7 +420,6 @@ _queueitem_init(_queueitem *item,
*item = (_queueitem){
.interpid = interpid,
.data = data,
- .fmt = fmt,
.unboundop = unboundop,
};
}
@@ -446,14 +443,14 @@ _queueitem_clear(_queueitem *item)
}
static _queueitem *
-_queueitem_new(int64_t interpid, _PyXIData_t *data, int fmt, int unboundop)
+_queueitem_new(int64_t interpid, _PyXIData_t *data, int unboundop)
{
_queueitem *item = GLOBAL_MALLOC(_queueitem);
if (item == NULL) {
PyErr_NoMemory();
return NULL;
}
- _queueitem_init(item, interpid, data, fmt, unboundop);
+ _queueitem_init(item, interpid, data, unboundop);
return item;
}
@@ -476,10 +473,9 @@ _queueitem_free_all(_queueitem *item)
static void
_queueitem_popped(_queueitem *item,
- _PyXIData_t **p_data, int *p_fmt, int *p_unboundop)
+ _PyXIData_t **p_data, unboundop_t *p_unboundop)
{
*p_data = item->data;
- *p_fmt = item->fmt;
*p_unboundop = item->unboundop;
// We clear them here, so they won't be released in _queueitem_clear().
item->data = NULL;
@@ -527,16 +523,16 @@ typedef struct _queue {
_queueitem *first;
_queueitem *last;
} items;
- struct {
- int fmt;
+ struct _queuedefaults {
+ xidata_fallback_t fallback;
int unboundop;
} defaults;
} _queue;
static int
-_queue_init(_queue *queue, Py_ssize_t maxsize, int fmt, int unboundop)
+_queue_init(_queue *queue, Py_ssize_t maxsize, struct _queuedefaults defaults)
{
- assert(check_unbound(unboundop));
+ assert(check_unbound(defaults.unboundop));
PyThread_type_lock mutex = PyThread_allocate_lock();
if (mutex == NULL) {
return ERR_QUEUE_ALLOC;
@@ -547,10 +543,7 @@ _queue_init(_queue *queue, Py_ssize_t maxsize, int fmt, int unboundop)
.items = {
.maxsize = maxsize,
},
- .defaults = {
- .fmt = fmt,
- .unboundop = unboundop,
- },
+ .defaults = defaults,
};
return 0;
}
@@ -631,8 +624,7 @@ _queue_unlock(_queue *queue)
}
static int
-_queue_add(_queue *queue, int64_t interpid, _PyXIData_t *data,
- int fmt, int unboundop)
+_queue_add(_queue *queue, int64_t interpid, _PyXIData_t *data, int unboundop)
{
int err = _queue_lock(queue);
if (err < 0) {
@@ -648,7 +640,7 @@ _queue_add(_queue *queue, int64_t interpid, _PyXIData_t *data,
return ERR_QUEUE_FULL;
}
- _queueitem *item = _queueitem_new(interpid, data, fmt, unboundop);
+ _queueitem *item = _queueitem_new(interpid, data, unboundop);
if (item == NULL) {
_queue_unlock(queue);
return -1;
@@ -668,8 +660,7 @@ _queue_add(_queue *queue, int64_t interpid, _PyXIData_t *data,
}
static int
-_queue_next(_queue *queue,
- _PyXIData_t **p_data, int *p_fmt, int *p_unboundop)
+_queue_next(_queue *queue, _PyXIData_t **p_data, int *p_unboundop)
{
int err = _queue_lock(queue);
if (err < 0) {
@@ -688,7 +679,7 @@ _queue_next(_queue *queue,
}
queue->items.count -= 1;
- _queueitem_popped(item, p_data, p_fmt, p_unboundop);
+ _queueitem_popped(item, p_data, p_unboundop);
_queue_unlock(queue);
return 0;
@@ -716,8 +707,11 @@ _queue_is_full(_queue *queue, int *p_is_full)
return err;
}
- assert(queue->items.count <= queue->items.maxsize);
- *p_is_full = queue->items.count == queue->items.maxsize;
+ assert(queue->items.maxsize <= 0
+ || queue->items.count <= queue->items.maxsize);
+ *p_is_full = queue->items.maxsize > 0
+ ? queue->items.count == queue->items.maxsize
+ : 0;
_queue_unlock(queue);
return 0;
@@ -1035,8 +1029,7 @@ finally:
struct queue_id_and_info {
int64_t id;
- int fmt;
- int unboundop;
+ struct _queuedefaults defaults;
};
static struct queue_id_and_info *
@@ -1053,8 +1046,7 @@ _queues_list_all(_queues *queues, int64_t *p_count)
for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
ids[i].id = ref->qid;
assert(ref->queue != NULL);
- ids[i].fmt = ref->queue->defaults.fmt;
- ids[i].unboundop = ref->queue->defaults.unboundop;
+ ids[i].defaults = ref->queue->defaults;
}
*p_count = queues->count;
@@ -1090,13 +1082,14 @@ _queue_free(_queue *queue)
// Create a new queue.
static int64_t
-queue_create(_queues *queues, Py_ssize_t maxsize, int fmt, int unboundop)
+queue_create(_queues *queues, Py_ssize_t maxsize,
+ struct _queuedefaults defaults)
{
_queue *queue = GLOBAL_MALLOC(_queue);
if (queue == NULL) {
return ERR_QUEUE_ALLOC;
}
- int err = _queue_init(queue, maxsize, fmt, unboundop);
+ int err = _queue_init(queue, maxsize, defaults);
if (err < 0) {
GLOBAL_FREE(queue);
return (int64_t)err;
@@ -1125,7 +1118,8 @@ queue_destroy(_queues *queues, int64_t qid)
// Push an object onto the queue.
static int
-queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
+queue_put(_queues *queues, int64_t qid, PyObject *obj, unboundop_t unboundop,
+ xidata_fallback_t fallback)
{
PyThreadState *tstate = PyThreadState_Get();
@@ -1138,27 +1132,27 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
assert(queue != NULL);
// Convert the object to cross-interpreter data.
- _PyXIData_t *data = _PyXIData_New();
- if (data == NULL) {
+ _PyXIData_t *xidata = _PyXIData_New();
+ if (xidata == NULL) {
_queue_unmark_waiter(queue, queues->mutex);
return -1;
}
- if (_PyObject_GetXIData(tstate, obj, data) != 0) {
+ if (_PyObject_GetXIData(tstate, obj, fallback, xidata) != 0) {
_queue_unmark_waiter(queue, queues->mutex);
- GLOBAL_FREE(data);
+ GLOBAL_FREE(xidata);
return -1;
}
- assert(_PyXIData_INTERPID(data) ==
+ assert(_PyXIData_INTERPID(xidata) ==
PyInterpreterState_GetID(tstate->interp));
// Add the data to the queue.
int64_t interpid = -1; // _queueitem_init() will set it.
- int res = _queue_add(queue, interpid, data, fmt, unboundop);
+ int res = _queue_add(queue, interpid, xidata, unboundop);
_queue_unmark_waiter(queue, queues->mutex);
if (res != 0) {
// We may chain an exception here:
- (void)_release_xid_data(data, 0);
- GLOBAL_FREE(data);
+ (void)_release_xid_data(xidata, 0);
+ GLOBAL_FREE(xidata);
return res;
}
@@ -1169,7 +1163,7 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
// XXX Support a "wait" mutex?
static int
queue_get(_queues *queues, int64_t qid,
- PyObject **res, int *p_fmt, int *p_unboundop)
+ PyObject **res, int *p_unboundop)
{
int err;
*res = NULL;
@@ -1185,7 +1179,7 @@ queue_get(_queues *queues, int64_t qid,
// Pop off the next item from the queue.
_PyXIData_t *data = NULL;
- err = _queue_next(queue, &data, p_fmt, p_unboundop);
+ err = _queue_next(queue, &data, p_unboundop);
_queue_unmark_waiter(queue, queues->mutex);
if (err != 0) {
return err;
@@ -1217,6 +1211,20 @@ queue_get(_queues *queues, int64_t qid,
}
static int
+queue_get_defaults(_queues *queues, int64_t qid,
+ struct _queuedefaults *p_defaults)
+{
+ _queue *queue = NULL;
+ int err = _queues_lookup(queues, qid, &queue);
+ if (err != 0) {
+ return err;
+ }
+ *p_defaults = queue->defaults;
+ _queue_unmark_waiter(queue, queues->mutex);
+ return 0;
+}
+
+static int
queue_get_maxsize(_queues *queues, int64_t qid, Py_ssize_t *p_maxsize)
{
_queue *queue = NULL;
@@ -1270,7 +1278,7 @@ set_external_queue_type(module_state *state, PyTypeObject *queue_type)
}
// Add and register the new type.
- if (ensure_xid_class(queue_type, _queueobj_shared) < 0) {
+ if (ensure_xid_class(queue_type, GETDATA(_queueobj_shared)) < 0) {
return -1;
}
state->queue_type = (PyTypeObject *)Py_NewRef(queue_type);
@@ -1348,10 +1356,10 @@ _queueobj_from_xid(_PyXIData_t *data)
PyObject *mod = _get_current_module();
if (mod == NULL) {
- // XXX import it?
- PyErr_SetString(PyExc_RuntimeError,
- MODULE_NAME_STR " module not imported yet");
- return NULL;
+ mod = PyImport_ImportModule(MODULE_NAME_STR);
+ if (mod == NULL) {
+ return NULL;
+ }
}
PyTypeObject *cls = get_external_queue_type(mod);
@@ -1474,22 +1482,28 @@ qidarg_converter(PyObject *arg, void *ptr)
static PyObject *
queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"maxsize", "fmt", "unboundop", NULL};
+ static char *kwlist[] = {"maxsize", "unboundop", "fallback", NULL};
Py_ssize_t maxsize;
- int fmt;
- int unboundop;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "nii:create", kwlist,
- &maxsize, &fmt, &unboundop))
+ int unboundarg = -1;
+ int fallbackarg = -1;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "n|ii:create", kwlist,
+ &maxsize, &unboundarg, &fallbackarg))
{
return NULL;
}
- if (!check_unbound(unboundop)) {
- PyErr_Format(PyExc_ValueError,
- "unsupported unboundop %d", unboundop);
+ struct _queuedefaults defaults = {0};
+ if (resolve_unboundop(unboundarg, UNBOUND_REPLACE,
+ &defaults.unboundop) < 0)
+ {
+ return NULL;
+ }
+ if (resolve_fallback(fallbackarg, _PyXIDATA_FULL_FALLBACK,
+ &defaults.fallback) < 0)
+ {
return NULL;
}
- int64_t qid = queue_create(&_globals.queues, maxsize, fmt, unboundop);
+ int64_t qid = queue_create(&_globals.queues, maxsize, defaults);
if (qid < 0) {
(void)handle_queue_error((int)qid, self, qid);
return NULL;
@@ -1511,7 +1525,7 @@ queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(queuesmod_create_doc,
-"create(maxsize, fmt, unboundop) -> qid\n\
+"create(maxsize, unboundop, fallback) -> qid\n\
\n\
Create a new cross-interpreter queue and return its unique generated ID.\n\
It is a new reference as though bind() had been called on the queue.\n\
@@ -1560,8 +1574,9 @@ queuesmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
}
struct queue_id_and_info *cur = qids;
for (int64_t i=0; i < count; cur++, i++) {
- PyObject *item = Py_BuildValue("Lii", cur->id, cur->fmt,
- cur->unboundop);
+ PyObject *item = Py_BuildValue("Lii", cur->id,
+ cur->defaults.unboundop,
+ cur->defaults.fallback);
if (item == NULL) {
Py_SETREF(ids, NULL);
break;
@@ -1575,34 +1590,44 @@ finally:
}
PyDoc_STRVAR(queuesmod_list_all_doc,
-"list_all() -> [(qid, fmt)]\n\
+"list_all() -> [(qid, unboundop, fallback)]\n\
\n\
Return the list of IDs for all queues.\n\
-Each corresponding default format is also included.");
+Each corresponding default unbound op and fallback is also included.");
static PyObject *
queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"qid", "obj", "fmt", "unboundop", NULL};
+ static char *kwlist[] = {"qid", "obj", "unboundop", "fallback", NULL};
qidarg_converter_data qidarg = {0};
PyObject *obj;
- int fmt;
- int unboundop;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&Oii:put", kwlist,
- qidarg_converter, &qidarg, &obj, &fmt,
- &unboundop))
+ int unboundarg = -1;
+ int fallbackarg = -1;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O|ii$p:put", kwlist,
+ qidarg_converter, &qidarg, &obj,
+ &unboundarg, &fallbackarg))
{
return NULL;
}
int64_t qid = qidarg.id;
- if (!check_unbound(unboundop)) {
- PyErr_Format(PyExc_ValueError,
- "unsupported unboundop %d", unboundop);
+ struct _queuedefaults defaults = {-1, -1};
+ if (unboundarg < 0 || fallbackarg < 0) {
+ int err = queue_get_defaults(&_globals.queues, qid, &defaults);
+ if (handle_queue_error(err, self, qid)) {
+ return NULL;
+ }
+ }
+ unboundop_t unboundop;
+ if (resolve_unboundop(unboundarg, defaults.unboundop, &unboundop) < 0) {
+ return NULL;
+ }
+ xidata_fallback_t fallback;
+ if (resolve_fallback(fallbackarg, defaults.fallback, &fallback) < 0) {
return NULL;
}
/* Queue up the object. */
- int err = queue_put(&_globals.queues, qid, obj, fmt, unboundop);
+ int err = queue_put(&_globals.queues, qid, obj, unboundop, fallback);
// This is the only place that raises QueueFull.
if (handle_queue_error(err, self, qid)) {
return NULL;
@@ -1612,7 +1637,7 @@ queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(queuesmod_put_doc,
-"put(qid, obj, fmt)\n\
+"put(qid, obj)\n\
\n\
Add the object's data to the queue.");
@@ -1628,27 +1653,26 @@ queuesmod_get(PyObject *self, PyObject *args, PyObject *kwds)
int64_t qid = qidarg.id;
PyObject *obj = NULL;
- int fmt = 0;
int unboundop = 0;
- int err = queue_get(&_globals.queues, qid, &obj, &fmt, &unboundop);
+ int err = queue_get(&_globals.queues, qid, &obj, &unboundop);
// This is the only place that raises QueueEmpty.
if (handle_queue_error(err, self, qid)) {
return NULL;
}
if (obj == NULL) {
- return Py_BuildValue("Oii", Py_None, fmt, unboundop);
+ return Py_BuildValue("Oi", Py_None, unboundop);
}
- PyObject *res = Py_BuildValue("OiO", obj, fmt, Py_None);
+ PyObject *res = Py_BuildValue("OO", obj, Py_None);
Py_DECREF(obj);
return res;
}
PyDoc_STRVAR(queuesmod_get_doc,
-"get(qid) -> (obj, fmt)\n\
+"get(qid) -> (obj, unboundop)\n\
\n\
Return a new object from the data at the front of the queue.\n\
-The object's format is also returned.\n\
+The unbound op is also returned.\n\
\n\
If there is nothing to receive then raise QueueEmpty.");
@@ -1748,17 +1772,14 @@ queuesmod_get_queue_defaults(PyObject *self, PyObject *args, PyObject *kwds)
}
int64_t qid = qidarg.id;
- _queue *queue = NULL;
- int err = _queues_lookup(&_globals.queues, qid, &queue);
+ struct _queuedefaults defaults = {0};
+ int err = queue_get_defaults(&_globals.queues, qid, &defaults);
if (handle_queue_error(err, self, qid)) {
return NULL;
}
- int fmt = queue->defaults.fmt;
- int unboundop = queue->defaults.unboundop;
- _queue_unmark_waiter(queue, _globals.queues.mutex);
- PyObject *defaults = Py_BuildValue("ii", fmt, unboundop);
- return defaults;
+ PyObject *res = Py_BuildValue("ii", defaults.unboundop, defaults.fallback);
+ return res;
}
PyDoc_STRVAR(queuesmod_get_queue_defaults_doc,
@@ -1931,8 +1952,7 @@ static int
module_traverse(PyObject *mod, visitproc visit, void *arg)
{
module_state *state = get_module_state(mod);
- (void)traverse_module_state(state, visit, arg);
- return 0;
+ return traverse_module_state(state, visit, arg);
}
static int
@@ -1941,8 +1961,7 @@ module_clear(PyObject *mod)
module_state *state = get_module_state(mod);
// Now we clear the module state.
- (void)clear_module_state(state);
- return 0;
+ return clear_module_state(state);
}
static void
diff --git a/Modules/_interpreters_common.h b/Modules/_interpreters_common.h
index edd65577284..40fd51d752e 100644
--- a/Modules/_interpreters_common.h
+++ b/Modules/_interpreters_common.h
@@ -5,8 +5,10 @@
_RESOLVE_MODINIT_FUNC_NAME(NAME)
+#define GETDATA(FUNC) ((_PyXIData_getdata_t){.basic=FUNC})
+
static int
-ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
+ensure_xid_class(PyTypeObject *cls, _PyXIData_getdata_t getdata)
{
PyThreadState *tstate = PyThreadState_Get();
return _PyXIData_RegisterClass(tstate, cls, getdata);
@@ -37,10 +39,37 @@ _get_interpid(_PyXIData_t *data)
}
+#ifdef HAS_FALLBACK
+static int
+resolve_fallback(int arg, xidata_fallback_t dflt,
+ xidata_fallback_t *p_fallback)
+{
+ if (arg < 0) {
+ *p_fallback = dflt;
+ return 0;
+ }
+ xidata_fallback_t fallback;
+ if (arg == _PyXIDATA_XIDATA_ONLY) {
+ fallback =_PyXIDATA_XIDATA_ONLY;
+ }
+ else if (arg == _PyXIDATA_FULL_FALLBACK) {
+ fallback = _PyXIDATA_FULL_FALLBACK;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError, "unsupported fallback %d", arg);
+ return -1;
+ }
+ *p_fallback = fallback;
+ return 0;
+}
+#endif
+
+
/* unbound items ************************************************************/
#ifdef HAS_UNBOUND_ITEMS
+typedef int unboundop_t;
#define UNBOUND_REMOVE 1
#define UNBOUND_ERROR 2
#define UNBOUND_REPLACE 3
@@ -51,6 +80,7 @@ _get_interpid(_PyXIData_t *data)
// object is released but the underlying data is copied (with the "raw"
// allocator) and used when the item is popped off the queue.
+#ifndef NDEBUG
static int
check_unbound(int unboundop)
{
@@ -63,5 +93,31 @@ check_unbound(int unboundop)
return 0;
}
}
+#endif
+
+static int
+resolve_unboundop(int arg, unboundop_t dflt, unboundop_t *p_unboundop)
+{
+ if (arg < 0) {
+ *p_unboundop = dflt;
+ return 0;
+ }
+ unboundop_t op;
+ if (arg == UNBOUND_REMOVE) {
+ op = UNBOUND_REMOVE;
+ }
+ else if (arg == UNBOUND_ERROR) {
+ op = UNBOUND_ERROR;
+ }
+ else if (arg == UNBOUND_REPLACE) {
+ op = UNBOUND_REPLACE;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError, "unsupported unboundop %d", arg);
+ return -1;
+ }
+ *p_unboundop = op;
+ return 0;
+}
#endif
diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c
index 77678f7c126..e7feaa7f186 100644
--- a/Modules/_interpretersmodule.c
+++ b/Modules/_interpretersmodule.c
@@ -8,6 +8,7 @@
#include "Python.h"
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
#include "pycore_crossinterp.h" // _PyXIData_t
+#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
#include "pycore_modsupport.h" // _PyArg_BadArgument()
#include "pycore_namespace.h" // _PyNamespace_New()
@@ -71,6 +72,22 @@ is_running_main(PyInterpreterState *interp)
}
+static inline int
+is_notshareable_raised(PyThreadState *tstate)
+{
+ PyObject *exctype = _PyXIData_GetNotShareableErrorType(tstate);
+ return _PyErr_ExceptionMatches(tstate, exctype);
+}
+
+static void
+unwrap_not_shareable(PyThreadState *tstate, _PyXI_failure *failure)
+{
+ if (_PyXI_UnwrapNotShareableError(tstate, failure) < 0) {
+ _PyErr_Clear(tstate);
+ }
+}
+
+
/* Cross-interpreter Buffer Views *******************************************/
/* When a memoryview object is "shared" between interpreters,
@@ -286,7 +303,7 @@ register_memoryview_xid(PyObject *mod, PyTypeObject **p_state)
*p_state = cls;
// Register XID for the builtin memoryview type.
- if (ensure_xid_class(&PyMemoryView_Type, _pybuffer_shared) < 0) {
+ if (ensure_xid_class(&PyMemoryView_Type, GETDATA(_pybuffer_shared)) < 0) {
return -1;
}
// We don't ever bother un-registering memoryview.
@@ -319,10 +336,10 @@ _get_current_module_state(void)
{
PyObject *mod = _get_current_module();
if (mod == NULL) {
- // XXX import it?
- PyErr_SetString(PyExc_RuntimeError,
- MODULE_NAME_STR " module not imported yet");
- return NULL;
+ mod = PyImport_ImportModule(MODULE_NAME_STR);
+ if (mod == NULL) {
+ return NULL;
+ }
}
module_state *state = get_module_state(mod);
Py_DECREF(mod);
@@ -359,96 +376,6 @@ _get_current_xibufferview_type(void)
}
-/* Python code **************************************************************/
-
-static const char *
-check_code_str(PyUnicodeObject *text)
-{
- assert(text != NULL);
- if (PyUnicode_GET_LENGTH(text) == 0) {
- return "too short";
- }
-
- // XXX Verify that it parses?
-
- return NULL;
-}
-
-static const char *
-check_code_object(PyCodeObject *code)
-{
- assert(code != NULL);
- if (code->co_argcount > 0
- || code->co_posonlyargcount > 0
- || code->co_kwonlyargcount > 0
- || code->co_flags & (CO_VARARGS | CO_VARKEYWORDS))
- {
- return "arguments not supported";
- }
- if (code->co_ncellvars > 0) {
- return "closures not supported";
- }
- // We trust that no code objects under co_consts have unbound cell vars.
-
- if (_PyCode_HAS_EXECUTORS(code) || _PyCode_HAS_INSTRUMENTATION(code)) {
- return "only basic functions are supported";
- }
- if (code->_co_monitoring != NULL) {
- return "only basic functions are supported";
- }
- if (code->co_extra != NULL) {
- return "only basic functions are supported";
- }
-
- return NULL;
-}
-
-#define RUN_TEXT 1
-#define RUN_CODE 2
-
-static const char *
-get_code_str(PyObject *arg, Py_ssize_t *len_p, PyObject **bytes_p, int *flags_p)
-{
- const char *codestr = NULL;
- Py_ssize_t len = -1;
- PyObject *bytes_obj = NULL;
- int flags = 0;
-
- if (PyUnicode_Check(arg)) {
- assert(PyUnicode_Check(arg)
- && (check_code_str((PyUnicodeObject *)arg) == NULL));
- codestr = PyUnicode_AsUTF8AndSize(arg, &len);
- if (codestr == NULL) {
- return NULL;
- }
- if (strlen(codestr) != (size_t)len) {
- PyErr_SetString(PyExc_ValueError,
- "source code string cannot contain null bytes");
- return NULL;
- }
- flags = RUN_TEXT;
- }
- else {
- assert(PyCode_Check(arg)
- && (check_code_object((PyCodeObject *)arg) == NULL));
- flags = RUN_CODE;
-
- // Serialize the code object.
- bytes_obj = PyMarshal_WriteObjectToString(arg, Py_MARSHAL_VERSION);
- if (bytes_obj == NULL) {
- return NULL;
- }
- codestr = PyBytes_AS_STRING(bytes_obj);
- len = PyBytes_GET_SIZE(bytes_obj);
- }
-
- *flags_p = flags;
- *bytes_p = bytes_obj;
- *len_p = len;
- return codestr;
-}
-
-
/* interpreter-specific code ************************************************/
static int
@@ -511,73 +438,290 @@ config_from_object(PyObject *configobj, PyInterpreterConfig *config)
}
+struct interp_call {
+ _PyXIData_t *func;
+ _PyXIData_t *args;
+ _PyXIData_t *kwargs;
+ struct {
+ _PyXIData_t func;
+ _PyXIData_t args;
+ _PyXIData_t kwargs;
+ } _preallocated;
+};
+
+static void
+_interp_call_clear(struct interp_call *call)
+{
+ if (call->func != NULL) {
+ _PyXIData_Clear(NULL, call->func);
+ }
+ if (call->args != NULL) {
+ _PyXIData_Clear(NULL, call->args);
+ }
+ if (call->kwargs != NULL) {
+ _PyXIData_Clear(NULL, call->kwargs);
+ }
+ *call = (struct interp_call){0};
+}
+
static int
-_run_script(PyObject *ns, const char *codestr, Py_ssize_t codestrlen, int flags)
+_interp_call_pack(PyThreadState *tstate, struct interp_call *call,
+ PyObject *func, PyObject *args, PyObject *kwargs)
{
- PyObject *result = NULL;
- if (flags & RUN_TEXT) {
- result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
- }
- else if (flags & RUN_CODE) {
- PyObject *code = PyMarshal_ReadObjectFromString(codestr, codestrlen);
- if (code != NULL) {
- result = PyEval_EvalCode(code, ns, ns);
- Py_DECREF(code);
+ xidata_fallback_t fallback = _PyXIDATA_FULL_FALLBACK;
+ assert(call->func == NULL);
+ assert(call->args == NULL);
+ assert(call->kwargs == NULL);
+ // Handle the func.
+ if (!PyCallable_Check(func)) {
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "expected a callable, got %R", func);
+ return -1;
+ }
+ if (_PyFunction_GetXIData(tstate, func, &call->_preallocated.func) < 0) {
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ if (_PyPickle_GetXIData(tstate, func, &call->_preallocated.func) < 0) {
+ _PyErr_SetRaisedException(tstate, exc);
+ return -1;
}
+ Py_DECREF(exc);
+ }
+ call->func = &call->_preallocated.func;
+ // Handle the args.
+ if (args == NULL || args == Py_None) {
+ // Leave it empty.
}
else {
- Py_UNREACHABLE();
+ assert(PyTuple_Check(args));
+ if (PyTuple_GET_SIZE(args) > 0) {
+ if (_PyObject_GetXIData(
+ tstate, args, fallback, &call->_preallocated.args) < 0)
+ {
+ _interp_call_clear(call);
+ return -1;
+ }
+ call->args = &call->_preallocated.args;
+ }
}
- if (result == NULL) {
- return -1;
+ // Handle the kwargs.
+ if (kwargs == NULL || kwargs == Py_None) {
+ // Leave it empty.
+ }
+ else {
+ assert(PyDict_Check(kwargs));
+ if (PyDict_GET_SIZE(kwargs) > 0) {
+ if (_PyObject_GetXIData(
+ tstate, kwargs, fallback, &call->_preallocated.kwargs) < 0)
+ {
+ _interp_call_clear(call);
+ return -1;
+ }
+ call->kwargs = &call->_preallocated.kwargs;
+ }
}
- Py_DECREF(result); // We throw away the result.
return 0;
}
+static void
+wrap_notshareable(PyThreadState *tstate, const char *label)
+{
+ if (!is_notshareable_raised(tstate)) {
+ return;
+ }
+ assert(label != NULL && strlen(label) > 0);
+ PyObject *cause = _PyErr_GetRaisedException(tstate);
+ _PyXIData_FormatNotShareableError(tstate, "%s not shareable", label);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ PyException_SetCause(exc, cause);
+ _PyErr_SetRaisedException(tstate, exc);
+}
+
static int
-_run_in_interpreter(PyInterpreterState *interp,
- const char *codestr, Py_ssize_t codestrlen,
- PyObject *shareables, int flags,
- PyObject **p_excinfo)
+_interp_call_unpack(struct interp_call *call,
+ PyObject **p_func, PyObject **p_args, PyObject **p_kwargs)
{
- assert(!PyErr_Occurred());
- _PyXI_session session = {0};
+ PyThreadState *tstate = PyThreadState_Get();
- // Prep and switch interpreters.
- if (_PyXI_Enter(&session, interp, shareables) < 0) {
- if (PyErr_Occurred()) {
- // If an error occured at this step, it means that interp
- // was not prepared and switched.
+ // Unpack the func.
+ PyObject *func = _PyXIData_NewObject(call->func);
+ if (func == NULL) {
+ wrap_notshareable(tstate, "func");
+ return -1;
+ }
+ // Unpack the args.
+ PyObject *args;
+ if (call->args == NULL) {
+ args = PyTuple_New(0);
+ if (args == NULL) {
+ Py_DECREF(func);
return -1;
}
- // Now, apply the error from another interpreter:
- PyObject *excinfo = _PyXI_ApplyError(session.error);
- if (excinfo != NULL) {
- *p_excinfo = excinfo;
+ }
+ else {
+ args = _PyXIData_NewObject(call->args);
+ if (args == NULL) {
+ wrap_notshareable(tstate, "args");
+ Py_DECREF(func);
+ return -1;
}
- assert(PyErr_Occurred());
+ assert(PyTuple_Check(args));
+ }
+ // Unpack the kwargs.
+ PyObject *kwargs = NULL;
+ if (call->kwargs != NULL) {
+ kwargs = _PyXIData_NewObject(call->kwargs);
+ if (kwargs == NULL) {
+ wrap_notshareable(tstate, "kwargs");
+ Py_DECREF(func);
+ Py_DECREF(args);
+ return -1;
+ }
+ assert(PyDict_Check(kwargs));
+ }
+ *p_func = func;
+ *p_args = args;
+ *p_kwargs = kwargs;
+ return 0;
+}
+
+static int
+_make_call(struct interp_call *call,
+ PyObject **p_result, _PyXI_failure *failure)
+{
+ assert(call != NULL && call->func != NULL);
+ PyThreadState *tstate = _PyThreadState_GET();
+
+ // Get the func and args.
+ PyObject *func = NULL, *args = NULL, *kwargs = NULL;
+ if (_interp_call_unpack(call, &func, &args, &kwargs) < 0) {
+ assert(func == NULL);
+ assert(args == NULL);
+ assert(kwargs == NULL);
+ _PyXI_InitFailure(failure, _PyXI_ERR_OTHER, NULL);
+ unwrap_not_shareable(tstate, failure);
return -1;
}
+ assert(!_PyErr_Occurred(tstate));
- // Run the script.
- int res = _run_script(session.main_ns, codestr, codestrlen, flags);
+ // Make the call.
+ PyObject *resobj = PyObject_Call(func, args, kwargs);
+ Py_DECREF(func);
+ Py_XDECREF(args);
+ Py_XDECREF(kwargs);
+ if (resobj == NULL) {
+ return -1;
+ }
+ *p_result = resobj;
+ return 0;
+}
- // Clean up and switch back.
- _PyXI_Exit(&session);
+static int
+_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_failure *failure)
+{
+ PyObject *code = _PyXIData_NewObject(script);
+ if (code == NULL) {
+ _PyXI_InitFailure(failure, _PyXI_ERR_NOT_SHAREABLE, NULL);
+ return -1;
+ }
+ PyObject *result = PyEval_EvalCode(code, ns, ns);
+ Py_DECREF(code);
+ if (result == NULL) {
+ _PyXI_InitFailure(failure, _PyXI_ERR_UNCAUGHT_EXCEPTION, NULL);
+ return -1;
+ }
+ assert(result == Py_None);
+ Py_DECREF(result); // We throw away the result.
+ return 0;
+}
- // Propagate any exception out to the caller.
- assert(!PyErr_Occurred());
- if (res < 0) {
- PyObject *excinfo = _PyXI_ApplyCapturedException(&session);
- if (excinfo != NULL) {
- *p_excinfo = excinfo;
+struct run_result {
+ PyObject *result;
+ PyObject *excinfo;
+};
+
+static void
+_run_result_clear(struct run_result *runres)
+{
+ Py_CLEAR(runres->result);
+ Py_CLEAR(runres->excinfo);
+}
+
+static int
+_run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
+ _PyXIData_t *script, struct interp_call *call,
+ PyObject *shareables, struct run_result *runres)
+{
+ assert(!_PyErr_Occurred(tstate));
+ int res = -1;
+ _PyXI_failure *failure = _PyXI_NewFailure();
+ if (failure == NULL) {
+ return -1;
+ }
+ _PyXI_session *session = _PyXI_NewSession();
+ if (session == NULL) {
+ _PyXI_FreeFailure(failure);
+ return -1;
+ }
+ _PyXI_session_result result = {0};
+
+ // Prep and switch interpreters.
+ if (_PyXI_Enter(session, interp, shareables, &result) < 0) {
+ // If an error occured at this step, it means that interp
+ // was not prepared and switched.
+ _PyXI_FreeSession(session);
+ _PyXI_FreeFailure(failure);
+ assert(result.excinfo == NULL);
+ return -1;
+ }
+
+ // Run in the interpreter.
+ if (script != NULL) {
+ assert(call == NULL);
+ PyObject *mainns = _PyXI_GetMainNamespace(session, failure);
+ if (mainns == NULL) {
+ goto finally;
}
+ res = _run_script(script, mainns, failure);
}
else {
- assert(!_PyXI_HasCapturedException(&session));
+ assert(call != NULL);
+ PyObject *resobj;
+ res = _make_call(call, &resobj, failure);
+ if (res == 0) {
+ res = _PyXI_Preserve(session, "resobj", resobj, failure);
+ Py_DECREF(resobj);
+ if (res < 0) {
+ goto finally;
+ }
+ }
}
+finally:
+ // Clean up and switch back.
+ (void)res;
+ int exitres = _PyXI_Exit(session, failure, &result);
+ assert(res == 0 || exitres != 0);
+ _PyXI_FreeSession(session);
+ _PyXI_FreeFailure(failure);
+
+ res = exitres;
+ if (_PyErr_Occurred(tstate)) {
+ // It's a directly propagated exception.
+ assert(res < 0);
+ }
+ else if (res < 0) {
+ assert(result.excinfo != NULL);
+ runres->excinfo = Py_NewRef(result.excinfo);
+ res = -1;
+ }
+ else {
+ assert(result.excinfo == NULL);
+ runres->result = _PyXI_GetPreserved(&result, "resobj");
+ if (_PyErr_Occurred(tstate)) {
+ res = -1;
+ }
+ }
+ _PyXI_ClearResult(&result);
return res;
}
@@ -895,8 +1039,8 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
PyObject *id, *updates;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "OO|$p:" MODULE_NAME_STR ".set___main___attrs",
- kwlist, &id, &updates, &restricted))
+ "OO!|$p:" MODULE_NAME_STR ".set___main___attrs",
+ kwlist, &id, &PyDict_Type, &updates, &restricted))
{
return NULL;
}
@@ -910,34 +1054,39 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
}
// Check the updates.
- if (updates != Py_None) {
- Py_ssize_t size = PyObject_Size(updates);
- if (size < 0) {
- return NULL;
- }
- if (size == 0) {
- PyErr_SetString(PyExc_ValueError,
- "arg 2 must be a non-empty mapping");
- return NULL;
- }
+ Py_ssize_t size = PyDict_Size(updates);
+ if (size < 0) {
+ return NULL;
+ }
+ if (size == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "arg 2 must be a non-empty dict");
+ return NULL;
}
- _PyXI_session session = {0};
+ _PyXI_session *session = _PyXI_NewSession();
+ if (session == NULL) {
+ return NULL;
+ }
// Prep and switch interpreters, including apply the updates.
- if (_PyXI_Enter(&session, interp, updates) < 0) {
- if (!PyErr_Occurred()) {
- _PyXI_ApplyCapturedException(&session);
- assert(PyErr_Occurred());
- }
- else {
- assert(!_PyXI_HasCapturedException(&session));
- }
+ if (_PyXI_Enter(session, interp, updates, NULL) < 0) {
+ _PyXI_FreeSession(session);
return NULL;
}
// Clean up and switch back.
- _PyXI_Exit(&session);
+ assert(!PyErr_Occurred());
+ int res = _PyXI_Exit(session, NULL, NULL);
+ _PyXI_FreeSession(session);
+ assert(res == 0);
+ if (res < 0) {
+ // unreachable
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_RuntimeError, "unresolved error");
+ }
+ return NULL;
+ }
Py_RETURN_NONE;
}
@@ -948,122 +1097,31 @@ PyDoc_STRVAR(set___main___attrs_doc,
Bind the given attributes in the interpreter's __main__ module.");
-static PyUnicodeObject *
-convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
- const char *expected)
-{
- PyUnicodeObject *str = NULL;
- if (PyUnicode_CheckExact(arg)) {
- str = (PyUnicodeObject *)Py_NewRef(arg);
- }
- else if (PyUnicode_Check(arg)) {
- // XXX str = PyUnicode_FromObject(arg);
- str = (PyUnicodeObject *)Py_NewRef(arg);
- }
- else {
- _PyArg_BadArgument(fname, displayname, expected, arg);
- return NULL;
- }
-
- const char *err = check_code_str(str);
- if (err != NULL) {
- Py_DECREF(str);
- PyErr_Format(PyExc_ValueError,
- "%.200s(): bad script text (%s)", fname, err);
- return NULL;
- }
-
- return str;
-}
-
-static PyCodeObject *
-convert_code_arg(PyObject *arg, const char *fname, const char *displayname,
- const char *expected)
+static PyObject *
+_handle_script_error(struct run_result *runres)
{
- const char *kind = NULL;
- PyCodeObject *code = NULL;
- if (PyFunction_Check(arg)) {
- if (PyFunction_GetClosure(arg) != NULL) {
- PyErr_Format(PyExc_ValueError,
- "%.200s(): closures not supported", fname);
- return NULL;
- }
- code = (PyCodeObject *)PyFunction_GetCode(arg);
- if (code == NULL) {
- if (PyErr_Occurred()) {
- // This chains.
- PyErr_Format(PyExc_ValueError,
- "%.200s(): bad func", fname);
- }
- else {
- PyErr_Format(PyExc_ValueError,
- "%.200s(): func.__code__ missing", fname);
- }
- return NULL;
- }
- Py_INCREF(code);
- kind = "func";
- }
- else if (PyCode_Check(arg)) {
- code = (PyCodeObject *)Py_NewRef(arg);
- kind = "code object";
- }
- else {
- _PyArg_BadArgument(fname, displayname, expected, arg);
- return NULL;
- }
-
- const char *err = check_code_object(code);
- if (err != NULL) {
- Py_DECREF(code);
- PyErr_Format(PyExc_ValueError,
- "%.200s(): bad %s (%s)", fname, kind, err);
+ assert(runres->result == NULL);
+ if (runres->excinfo == NULL) {
+ assert(PyErr_Occurred());
return NULL;
}
-
- return code;
-}
-
-static int
-_interp_exec(PyObject *self, PyInterpreterState *interp,
- PyObject *code_arg, PyObject *shared_arg, PyObject **p_excinfo)
-{
- if (shared_arg != NULL && !PyDict_CheckExact(shared_arg)) {
- PyErr_SetString(PyExc_TypeError, "expected 'shared' to be a dict");
- return -1;
- }
-
- // Extract code.
- Py_ssize_t codestrlen = -1;
- PyObject *bytes_obj = NULL;
- int flags = 0;
- const char *codestr = get_code_str(code_arg,
- &codestrlen, &bytes_obj, &flags);
- if (codestr == NULL) {
- return -1;
- }
-
- // Run the code in the interpreter.
- int res = _run_in_interpreter(interp, codestr, codestrlen,
- shared_arg, flags, p_excinfo);
- Py_XDECREF(bytes_obj);
- if (res < 0) {
- return -1;
- }
-
- return 0;
+ assert(!PyErr_Occurred());
+ return runres->excinfo;
}
static PyObject *
interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
{
+#define FUNCNAME MODULE_NAME_STR ".exec"
+ PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "code", "shared", "restrict", NULL};
PyObject *id, *code;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "OO|O$p:" MODULE_NAME_STR ".exec", kwlist,
- &id, &code, &shared, &restricted))
+ "OO|O!$p:" FUNCNAME, kwlist,
+ &id, &code, &PyDict_Type, &shared,
+ &restricted))
{
return NULL;
}
@@ -1075,27 +1133,24 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- const char *expected = "a string, a function, or a code object";
- if (PyUnicode_Check(code)) {
- code = (PyObject *)convert_script_arg(code, MODULE_NAME_STR ".exec",
- "argument 2", expected);
- }
- else {
- code = (PyObject *)convert_code_arg(code, MODULE_NAME_STR ".exec",
- "argument 2", expected);
- }
- if (code == NULL) {
+ // We don't need the script to be "pure", which means it can use
+ // global variables. They will be resolved against __main__.
+ _PyXIData_t xidata = {0};
+ if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
+ unwrap_not_shareable(tstate, NULL);
return NULL;
}
- PyObject *excinfo = NULL;
- int res = _interp_exec(self, interp, code, shared, &excinfo);
- Py_DECREF(code);
+ struct run_result runres = {0};
+ int res = _run_in_interpreter(
+ tstate, interp, &xidata, NULL, shared, &runres);
+ _PyXIData_Release(&xidata);
if (res < 0) {
- assert((excinfo == NULL) != (PyErr_Occurred() == NULL));
- return excinfo;
+ return _handle_script_error(&runres);
}
+ assert(runres.result == NULL);
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(exec_doc,
@@ -1118,13 +1173,16 @@ is ignored, including its __globals__ dict.");
static PyObject *
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
{
+#define FUNCNAME MODULE_NAME_STR ".run_string"
+ PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "script", "shared", "restrict", NULL};
PyObject *id, *script;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "OU|O$p:" MODULE_NAME_STR ".run_string",
- kwlist, &id, &script, &shared, &restricted))
+ "OU|O!$p:" FUNCNAME, kwlist,
+ &id, &script, &PyDict_Type, &shared,
+ &restricted))
{
return NULL;
}
@@ -1136,20 +1194,27 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- script = (PyObject *)convert_script_arg(script, MODULE_NAME_STR ".run_string",
- "argument 2", "a string");
- if (script == NULL) {
+ if (PyFunction_Check(script) || PyCode_Check(script)) {
+ _PyArg_BadArgument(FUNCNAME, "argument 2", "a string", script);
+ return NULL;
+ }
+
+ _PyXIData_t xidata = {0};
+ if (_PyCode_GetScriptXIData(tstate, script, &xidata) < 0) {
+ unwrap_not_shareable(tstate, NULL);
return NULL;
}
- PyObject *excinfo = NULL;
- int res = _interp_exec(self, interp, script, shared, &excinfo);
- Py_DECREF(script);
+ struct run_result runres = {0};
+ int res = _run_in_interpreter(
+ tstate, interp, &xidata, NULL, shared, &runres);
+ _PyXIData_Release(&xidata);
if (res < 0) {
- assert((excinfo == NULL) != (PyErr_Occurred() == NULL));
- return excinfo;
+ return _handle_script_error(&runres);
}
+ assert(runres.result == NULL);
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(run_string_doc,
@@ -1162,13 +1227,16 @@ Execute the provided string in the identified interpreter.\n\
static PyObject *
interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
{
+#define FUNCNAME MODULE_NAME_STR ".run_func"
+ PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "func", "shared", "restrict", NULL};
PyObject *id, *func;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "OO|O$p:" MODULE_NAME_STR ".run_func",
- kwlist, &id, &func, &shared, &restricted))
+ "OO|O!$p:" FUNCNAME, kwlist,
+ &id, &func, &PyDict_Type, &shared,
+ &restricted))
{
return NULL;
}
@@ -1180,21 +1248,36 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- PyCodeObject *code = convert_code_arg(func, MODULE_NAME_STR ".exec",
- "argument 2",
- "a function or a code object");
- if (code == NULL) {
+ // We don't worry about checking globals. They will be resolved
+ // against __main__.
+ PyObject *code;
+ if (PyFunction_Check(func)) {
+ code = PyFunction_GET_CODE(func);
+ }
+ else if (PyCode_Check(func)) {
+ code = func;
+ }
+ else {
+ _PyArg_BadArgument(FUNCNAME, "argument 2", "a function", func);
return NULL;
}
- PyObject *excinfo = NULL;
- int res = _interp_exec(self, interp, (PyObject *)code, shared, &excinfo);
- Py_DECREF(code);
+ _PyXIData_t xidata = {0};
+ if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
+ unwrap_not_shareable(tstate, NULL);
+ return NULL;
+ }
+
+ struct run_result runres = {0};
+ int res = _run_in_interpreter(
+ tstate, interp, &xidata, NULL, shared, &runres);
+ _PyXIData_Release(&xidata);
if (res < 0) {
- assert((excinfo == NULL) != (PyErr_Occurred() == NULL));
- return excinfo;
+ return _handle_script_error(&runres);
}
+ assert(runres.result == NULL);
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(run_func_doc,
@@ -1209,16 +1292,21 @@ are not supported. Methods and other callables are not supported either.\n\
static PyObject *
interp_call(PyObject *self, PyObject *args, PyObject *kwds)
{
+#define FUNCNAME MODULE_NAME_STR ".call"
+ PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "callable", "args", "kwargs",
- "restrict", NULL};
+ "preserve_exc", "restrict", NULL};
PyObject *id, *callable;
PyObject *args_obj = NULL;
PyObject *kwargs_obj = NULL;
+ int preserve_exc = 0;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "OO|OO$p:" MODULE_NAME_STR ".call", kwlist,
- &id, &callable, &args_obj, &kwargs_obj,
- &restricted))
+ "OO|O!O!$pp:" FUNCNAME, kwlist,
+ &id, &callable,
+ &PyTuple_Type, &args_obj,
+ &PyDict_Type, &kwargs_obj,
+ &preserve_exc, &restricted))
{
return NULL;
}
@@ -1230,42 +1318,37 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- if (args_obj != NULL) {
- PyErr_SetString(PyExc_ValueError, "got unexpected args");
- return NULL;
- }
- if (kwargs_obj != NULL) {
- PyErr_SetString(PyExc_ValueError, "got unexpected kwargs");
+ struct interp_call call = {0};
+ if (_interp_call_pack(tstate, &call, callable, args_obj, kwargs_obj) < 0) {
return NULL;
}
- PyObject *code = (PyObject *)convert_code_arg(callable, MODULE_NAME_STR ".call",
- "argument 2", "a function");
- if (code == NULL) {
- return NULL;
+ PyObject *res_and_exc = NULL;
+ struct run_result runres = {0};
+ if (_run_in_interpreter(tstate, interp, NULL, &call, NULL, &runres) < 0) {
+ if (runres.excinfo == NULL) {
+ assert(_PyErr_Occurred(tstate));
+ goto finally;
+ }
+ assert(!_PyErr_Occurred(tstate));
}
+ assert(runres.result == NULL || runres.excinfo == NULL);
+ res_and_exc = Py_BuildValue("OO",
+ (runres.result ? runres.result : Py_None),
+ (runres.excinfo ? runres.excinfo : Py_None));
- PyObject *excinfo = NULL;
- int res = _interp_exec(self, interp, code, NULL, &excinfo);
- Py_DECREF(code);
- if (res < 0) {
- assert((excinfo == NULL) != (PyErr_Occurred() == NULL));
- return excinfo;
- }
- Py_RETURN_NONE;
+finally:
+ _interp_call_clear(&call);
+ _run_result_clear(&runres);
+ return res_and_exc;
+#undef FUNCNAME
}
PyDoc_STRVAR(call_doc,
"call(id, callable, args=None, kwargs=None, *, restrict=False)\n\
\n\
Call the provided object in the identified interpreter.\n\
-Pass the given args and kwargs, if possible.\n\
-\n\
-\"callable\" may be a plain function with no free vars that takes\n\
-no arguments.\n\
-\n\
-The function's code object is used and all its state\n\
-is ignored, including its __globals__ dict.");
+Pass the given args and kwargs, if possible.");
static PyObject *
@@ -1472,16 +1555,16 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
}
PyObject *captured = NULL;
- _PyXI_excinfo info = {0};
- if (_PyXI_InitExcInfo(&info, exc) < 0) {
+ _PyXI_excinfo *info = _PyXI_NewExcInfo(exc);
+ if (info == NULL) {
goto finally;
}
- captured = _PyXI_ExcInfoAsObject(&info);
+ captured = _PyXI_ExcInfoAsObject(info);
if (captured == NULL) {
goto finally;
}
- PyObject *formatted = _PyXI_FormatExcInfo(&info);
+ PyObject *formatted = _PyXI_FormatExcInfo(info);
if (formatted == NULL) {
Py_CLEAR(captured);
goto finally;
@@ -1494,7 +1577,7 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
}
finally:
- _PyXI_ClearExcInfo(&info);
+ _PyXI_FreeExcInfo(info);
if (exc != exc_arg) {
if (PyErr_Occurred()) {
PyErr_SetRaisedException(exc);
@@ -1623,8 +1706,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
{
module_state *state = get_module_state(mod);
assert(state != NULL);
- (void)traverse_module_state(state, visit, arg);
- return 0;
+ return traverse_module_state(state, visit, arg);
}
static int
@@ -1632,8 +1714,7 @@ module_clear(PyObject *mod)
{
module_state *state = get_module_state(mod);
assert(state != NULL);
- (void)clear_module_state(state);
- return 0;
+ return clear_module_state(state);
}
static void
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 2189b1f3800..25c8bf8b3d5 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -13,6 +13,7 @@
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _Py_FatalErrorFormat()
#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
@@ -421,8 +422,7 @@ buffered_dealloc(PyObject *op)
return;
_PyObject_GC_UNTRACK(self);
self->ok = 0;
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
if (self->buffer) {
PyMem_Free(self->buffer);
self->buffer = NULL;
@@ -2312,8 +2312,7 @@ bufferedrwpair_dealloc(PyObject *op)
rwpair *self = rwpair_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
(void)bufferedrwpair_clear(op);
tp->tp_free(self);
Py_DECREF(tp);
@@ -2555,8 +2554,7 @@ static PyMethodDef bufferedreader_methods[] = {
_IO__BUFFERED_TRUNCATE_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
@@ -2615,8 +2613,7 @@ static PyMethodDef bufferedwriter_methods[] = {
_IO__BUFFERED_TELL_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
@@ -2733,8 +2730,7 @@ static PyMethodDef bufferedrandom_methods[] = {
_IO_BUFFEREDWRITER_WRITE_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
index e45a2d1a16d..1c71bce4fbb 100644
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -1,8 +1,11 @@
#include "Python.h"
+#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION()
#include "pycore_object.h"
-#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
+#include "pycore_pyatomic_ft_wrappers.h"
+#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
-#include <stddef.h> // offsetof()
+#include <stddef.h> // offsetof()
#include "_iomodule.h"
/*[clinic input]
@@ -50,7 +53,7 @@ check_closed(bytesio *self)
static int
check_exports(bytesio *self)
{
- if (self->exports > 0) {
+ if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
PyErr_SetString(PyExc_BufferError,
"Existing exports of data: object cannot be re-sized");
return 1;
@@ -68,15 +71,17 @@ check_exports(bytesio *self)
return NULL; \
}
-#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1)
+#define SHARED_BUF(self) (!_PyObject_IsUniquelyReferenced((self)->buf))
/* Internal routine to get a line from the buffer of a BytesIO
object. Returns the length between the current position to the
next newline character. */
static Py_ssize_t
-scan_eol(bytesio *self, Py_ssize_t len)
+scan_eol_lock_held(bytesio *self, Py_ssize_t len)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
const char *start, *n;
Py_ssize_t maxlen;
@@ -109,11 +114,13 @@ scan_eol(bytesio *self, Py_ssize_t len)
The caller should ensure that the 'size' argument is non-negative and
not lesser than self->string_size. Returns 0 on success, -1 otherwise. */
static int
-unshare_buffer(bytesio *self, size_t size)
+unshare_buffer_lock_held(bytesio *self, size_t size)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
PyObject *new_buf;
assert(SHARED_BUF(self));
- assert(self->exports == 0);
+ assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0);
assert(size >= (size_t)self->string_size);
new_buf = PyBytes_FromStringAndSize(NULL, size);
if (new_buf == NULL)
@@ -128,10 +135,12 @@ unshare_buffer(bytesio *self, size_t size)
The caller should ensure that the 'size' argument is non-negative. Returns
0 on success, -1 otherwise. */
static int
-resize_buffer(bytesio *self, size_t size)
+resize_buffer_lock_held(bytesio *self, size_t size)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
assert(self->buf != NULL);
- assert(self->exports == 0);
+ assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0);
/* Here, unsigned types are used to avoid dealing with signed integer
overflow, which is undefined in C. */
@@ -160,7 +169,7 @@ resize_buffer(bytesio *self, size_t size)
}
if (SHARED_BUF(self)) {
- if (unshare_buffer(self, alloc) < 0)
+ if (unshare_buffer_lock_held(self, alloc) < 0)
return -1;
}
else {
@@ -181,8 +190,10 @@ resize_buffer(bytesio *self, size_t size)
Inlining is disabled because it's significantly decreases performance
of writelines() in PGO build. */
Py_NO_INLINE static Py_ssize_t
-write_bytes(bytesio *self, PyObject *b)
+write_bytes_lock_held(bytesio *self, PyObject *b)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
if (check_closed(self)) {
return -1;
}
@@ -202,13 +213,13 @@ write_bytes(bytesio *self, PyObject *b)
assert(self->pos >= 0);
size_t endpos = (size_t)self->pos + len;
if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) {
- if (resize_buffer(self, endpos) < 0) {
+ if (resize_buffer_lock_held(self, endpos) < 0) {
len = -1;
goto done;
}
}
else if (SHARED_BUF(self)) {
- if (unshare_buffer(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) {
+ if (unshare_buffer_lock_held(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) {
len = -1;
goto done;
}
@@ -245,13 +256,17 @@ write_bytes(bytesio *self, PyObject *b)
static PyObject *
bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure))
{
+ PyObject *ret;
bytesio *self = bytesio_CAST(op);
+ Py_BEGIN_CRITICAL_SECTION(self);
if (self->buf == NULL) {
- Py_RETURN_TRUE;
+ ret = Py_True;
}
else {
- Py_RETURN_FALSE;
+ ret = Py_False;
}
+ Py_END_CRITICAL_SECTION();
+ return ret;
}
/*[clinic input]
@@ -311,6 +326,7 @@ _io_BytesIO_flush_impl(bytesio *self)
}
/*[clinic input]
+@critical_section
_io.BytesIO.getbuffer
cls: defining_class
@@ -321,7 +337,7 @@ Get a read-write view over the contents of the BytesIO object.
static PyObject *
_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls)
-/*[clinic end generated code: output=045091d7ce87fe4e input=0668fbb48f95dffa]*/
+/*[clinic end generated code: output=045091d7ce87fe4e input=8295764061be77fd]*/
{
_PyIO_State *state = get_io_state_by_cls(cls);
PyTypeObject *type = state->PyBytesIOBuffer_Type;
@@ -340,6 +356,7 @@ _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls)
}
/*[clinic input]
+@critical_section
_io.BytesIO.getvalue
Retrieve the entire contents of the BytesIO object.
@@ -347,16 +364,16 @@ Retrieve the entire contents of the BytesIO object.
static PyObject *
_io_BytesIO_getvalue_impl(bytesio *self)
-/*[clinic end generated code: output=b3f6a3233c8fd628 input=4b403ac0af3973ed]*/
+/*[clinic end generated code: output=b3f6a3233c8fd628 input=c91bff398df0c352]*/
{
CHECK_CLOSED(self);
- if (self->string_size <= 1 || self->exports > 0)
+ if (self->string_size <= 1 || FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0)
return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf),
self->string_size);
if (self->string_size != PyBytes_GET_SIZE(self->buf)) {
if (SHARED_BUF(self)) {
- if (unshare_buffer(self, self->string_size) < 0)
+ if (unshare_buffer_lock_held(self, self->string_size) < 0)
return NULL;
}
else {
@@ -384,6 +401,7 @@ _io_BytesIO_isatty_impl(bytesio *self)
}
/*[clinic input]
+@critical_section
_io.BytesIO.tell
Current file position, an integer.
@@ -391,22 +409,24 @@ Current file position, an integer.
static PyObject *
_io_BytesIO_tell_impl(bytesio *self)
-/*[clinic end generated code: output=b54b0f93cd0e5e1d input=b106adf099cb3657]*/
+/*[clinic end generated code: output=b54b0f93cd0e5e1d input=2c7b0e8f82e05c4d]*/
{
CHECK_CLOSED(self);
return PyLong_FromSsize_t(self->pos);
}
static PyObject *
-read_bytes(bytesio *self, Py_ssize_t size)
+read_bytes_lock_held(bytesio *self, Py_ssize_t size)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
const char *output;
assert(self->buf != NULL);
assert(size <= self->string_size);
if (size > 1 &&
self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
- self->exports == 0) {
+ FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
self->pos += size;
return Py_NewRef(self->buf);
}
@@ -417,6 +437,7 @@ read_bytes(bytesio *self, Py_ssize_t size)
}
/*[clinic input]
+@critical_section
_io.BytesIO.read
size: Py_ssize_t(accept={int, NoneType}) = -1
/
@@ -429,7 +450,7 @@ Return an empty bytes object at EOF.
static PyObject *
_io_BytesIO_read_impl(bytesio *self, Py_ssize_t size)
-/*[clinic end generated code: output=9cc025f21c75bdd2 input=74344a39f431c3d7]*/
+/*[clinic end generated code: output=9cc025f21c75bdd2 input=9e2f7ff3075fdd39]*/
{
Py_ssize_t n;
@@ -443,11 +464,12 @@ _io_BytesIO_read_impl(bytesio *self, Py_ssize_t size)
size = 0;
}
- return read_bytes(self, size);
+ return read_bytes_lock_held(self, size);
}
/*[clinic input]
+@critical_section
_io.BytesIO.read1
size: Py_ssize_t(accept={int, NoneType}) = -1
/
@@ -460,12 +482,13 @@ Return an empty bytes object at EOF.
static PyObject *
_io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size)
-/*[clinic end generated code: output=d0f843285aa95f1c input=440a395bf9129ef5]*/
+/*[clinic end generated code: output=d0f843285aa95f1c input=a08fc9e507ab380c]*/
{
return _io_BytesIO_read_impl(self, size);
}
/*[clinic input]
+@critical_section
_io.BytesIO.readline
size: Py_ssize_t(accept={int, NoneType}) = -1
/
@@ -479,18 +502,19 @@ Return an empty bytes object at EOF.
static PyObject *
_io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size)
-/*[clinic end generated code: output=4bff3c251df8ffcd input=e7c3fbd1744e2783]*/
+/*[clinic end generated code: output=4bff3c251df8ffcd input=db09d47e23cf2c9e]*/
{
Py_ssize_t n;
CHECK_CLOSED(self);
- n = scan_eol(self, size);
+ n = scan_eol_lock_held(self, size);
- return read_bytes(self, n);
+ return read_bytes_lock_held(self, n);
}
/*[clinic input]
+@critical_section
_io.BytesIO.readlines
size as arg: object = None
/
@@ -504,7 +528,7 @@ total number of bytes in the lines returned.
static PyObject *
_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
-/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/
+/*[clinic end generated code: output=09b8e34c880808ff input=5c57d7d78e409985]*/
{
Py_ssize_t maxsize, size, n;
PyObject *result, *line;
@@ -533,7 +557,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
return NULL;
output = PyBytes_AS_STRING(self->buf) + self->pos;
- while ((n = scan_eol(self, -1)) != 0) {
+ while ((n = scan_eol_lock_held(self, -1)) != 0) {
self->pos += n;
line = PyBytes_FromStringAndSize(output, n);
if (!line)
@@ -556,6 +580,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
}
/*[clinic input]
+@critical_section
_io.BytesIO.readinto
buffer: Py_buffer(accept={rwbuffer})
/
@@ -568,7 +593,7 @@ is set not to block and has no data to read.
static PyObject *
_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
-/*[clinic end generated code: output=a5d407217dcf0639 input=1424d0fdce857919]*/
+/*[clinic end generated code: output=a5d407217dcf0639 input=093a8d330de3fcd1]*/
{
Py_ssize_t len, n;
@@ -583,17 +608,18 @@ _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
len = 0;
}
- memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
assert(self->pos + len < PY_SSIZE_T_MAX);
assert(len >= 0);
+ memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
self->pos += len;
return PyLong_FromSsize_t(len);
}
/*[clinic input]
+@critical_section
_io.BytesIO.truncate
- size: Py_ssize_t(accept={int, NoneType}, c_default="((bytesio *)self)->pos") = None
+ size: object = None
/
Truncate the file to at most size bytes.
@@ -603,44 +629,68 @@ The current file position is unchanged. Returns the new size.
[clinic start generated code]*/
static PyObject *
-_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size)
-/*[clinic end generated code: output=9ad17650c15fa09b input=dae4295e11c1bbb4]*/
+_io_BytesIO_truncate_impl(bytesio *self, PyObject *size)
+/*[clinic end generated code: output=ab42491b4824f384 input=b4acb5f80481c053]*/
{
CHECK_CLOSED(self);
CHECK_EXPORTS(self);
- if (size < 0) {
- PyErr_Format(PyExc_ValueError,
- "negative size value %zd", size);
- return NULL;
+ Py_ssize_t new_size;
+
+ if (size == Py_None) {
+ new_size = self->pos;
+ }
+ else {
+ new_size = PyLong_AsLong(size);
+ if (new_size == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (new_size < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "negative size value %zd", new_size);
+ return NULL;
+ }
}
- if (size < self->string_size) {
- self->string_size = size;
- if (resize_buffer(self, size) < 0)
+ if (new_size < self->string_size) {
+ self->string_size = new_size;
+ if (resize_buffer_lock_held(self, new_size) < 0)
return NULL;
}
- return PyLong_FromSsize_t(size);
+ return PyLong_FromSsize_t(new_size);
}
static PyObject *
-bytesio_iternext(PyObject *op)
+bytesio_iternext_lock_held(PyObject *op)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+
Py_ssize_t n;
bytesio *self = bytesio_CAST(op);
CHECK_CLOSED(self);
- n = scan_eol(self, -1);
+ n = scan_eol_lock_held(self, -1);
if (n == 0)
return NULL;
- return read_bytes(self, n);
+ return read_bytes_lock_held(self, n);
+}
+
+static PyObject *
+bytesio_iternext(PyObject *op)
+{
+ PyObject *ret;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ ret = bytesio_iternext_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return ret;
}
/*[clinic input]
+@critical_section
_io.BytesIO.seek
pos: Py_ssize_t
whence: int = 0
@@ -657,7 +707,7 @@ Returns the new absolute position.
static PyObject *
_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
-/*[clinic end generated code: output=c26204a68e9190e4 input=1e875e6ebc652948]*/
+/*[clinic end generated code: output=c26204a68e9190e4 input=20f05ddf659255df]*/
{
CHECK_CLOSED(self);
@@ -700,6 +750,7 @@ _io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
}
/*[clinic input]
+@critical_section
_io.BytesIO.write
b: object
/
@@ -711,13 +762,14 @@ Return the number of bytes written.
static PyObject *
_io_BytesIO_write_impl(bytesio *self, PyObject *b)
-/*[clinic end generated code: output=d3e46bcec8d9e21c input=f5ec7c8c64ed720a]*/
+/*[clinic end generated code: output=d3e46bcec8d9e21c input=46c0c17eac7474a4]*/
{
- Py_ssize_t n = write_bytes(self, b);
+ Py_ssize_t n = write_bytes_lock_held(self, b);
return n >= 0 ? PyLong_FromSsize_t(n) : NULL;
}
/*[clinic input]
+@critical_section
_io.BytesIO.writelines
lines: object
/
@@ -731,7 +783,7 @@ each element.
static PyObject *
_io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
-/*[clinic end generated code: output=03a43a75773bc397 input=e972539176fc8fc1]*/
+/*[clinic end generated code: output=03a43a75773bc397 input=5d6a616ae39dc9ca]*/
{
PyObject *it, *item;
@@ -742,7 +794,7 @@ _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
return NULL;
while ((item = PyIter_Next(it)) != NULL) {
- Py_ssize_t ret = write_bytes(self, item);
+ Py_ssize_t ret = write_bytes_lock_held(self, item);
Py_DECREF(item);
if (ret < 0) {
Py_DECREF(it);
@@ -759,6 +811,7 @@ _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
}
/*[clinic input]
+@critical_section
_io.BytesIO.close
Disable all I/O operations.
@@ -766,7 +819,7 @@ Disable all I/O operations.
static PyObject *
_io_BytesIO_close_impl(bytesio *self)
-/*[clinic end generated code: output=1471bb9411af84a0 input=37e1f55556e61f60]*/
+/*[clinic end generated code: output=1471bb9411af84a0 input=34ce76d8bd17a23b]*/
{
CHECK_EXPORTS(self);
Py_CLEAR(self->buf);
@@ -788,35 +841,49 @@ _io_BytesIO_close_impl(bytesio *self)
function to use the efficient instance representation of PEP 307.
*/
+ static PyObject *
+ bytesio_getstate_lock_held(PyObject *op)
+ {
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+
+ bytesio *self = bytesio_CAST(op);
+ PyObject *initvalue = _io_BytesIO_getvalue_impl(self);
+ PyObject *dict;
+ PyObject *state;
+
+ if (initvalue == NULL)
+ return NULL;
+ if (self->dict == NULL) {
+ dict = Py_NewRef(Py_None);
+ }
+ else {
+ dict = PyDict_Copy(self->dict);
+ if (dict == NULL) {
+ Py_DECREF(initvalue);
+ return NULL;
+ }
+ }
+
+ state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
+ Py_DECREF(initvalue);
+ return state;
+}
+
static PyObject *
bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy))
{
- bytesio *self = bytesio_CAST(op);
- PyObject *initvalue = _io_BytesIO_getvalue_impl(self);
- PyObject *dict;
- PyObject *state;
-
- if (initvalue == NULL)
- return NULL;
- if (self->dict == NULL) {
- dict = Py_NewRef(Py_None);
- }
- else {
- dict = PyDict_Copy(self->dict);
- if (dict == NULL) {
- Py_DECREF(initvalue);
- return NULL;
- }
- }
-
- state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
- Py_DECREF(initvalue);
- return state;
+ PyObject *ret;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ ret = bytesio_getstate_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return ret;
}
static PyObject *
-bytesio_setstate(PyObject *op, PyObject *state)
+bytesio_setstate_lock_held(PyObject *op, PyObject *state)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+
PyObject *result;
PyObject *position_obj;
PyObject *dict;
@@ -890,21 +957,30 @@ bytesio_setstate(PyObject *op, PyObject *state)
Py_RETURN_NONE;
}
+static PyObject *
+bytesio_setstate(PyObject *op, PyObject *state)
+{
+ PyObject *ret;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ ret = bytesio_setstate_lock_held(op, state);
+ Py_END_CRITICAL_SECTION();
+ return ret;
+}
+
static void
bytesio_dealloc(PyObject *op)
{
bytesio *self = bytesio_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
- if (self->exports > 0) {
+ if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
PyErr_SetString(PyExc_SystemError,
"deallocated BytesIO object has exported buffers");
PyErr_Print();
}
Py_CLEAR(self->buf);
Py_CLEAR(self->dict);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}
@@ -932,6 +1008,7 @@ bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
/*[clinic input]
+@critical_section
_io.BytesIO.__init__
initial_bytes as initvalue: object(c_default="NULL") = b''
@@ -940,13 +1017,13 @@ Buffered I/O implementation using an in-memory bytes buffer.
static int
_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
-/*[clinic end generated code: output=65c0c51e24c5b621 input=aac7f31b67bf0fb6]*/
+/*[clinic end generated code: output=65c0c51e24c5b621 input=3da5a74ee4c4f1ac]*/
{
/* In case, __init__ is called multiple times. */
self->string_size = 0;
self->pos = 0;
- if (self->exports > 0) {
+ if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
PyErr_SetString(PyExc_BufferError,
"Existing exports of data: object cannot be re-sized");
return -1;
@@ -970,8 +1047,10 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
}
static PyObject *
-bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
+bytesio_sizeof_lock_held(PyObject *op)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+
bytesio *self = bytesio_CAST(op);
size_t res = _PyObject_SIZE(Py_TYPE(self));
if (self->buf && !SHARED_BUF(self)) {
@@ -984,6 +1063,16 @@ bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
return PyLong_FromSize_t(res);
}
+static PyObject *
+bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
+{
+ PyObject *ret;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ ret = bytesio_sizeof_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return ret;
+}
+
static int
bytesio_traverse(PyObject *op, visitproc visit, void *arg)
{
@@ -999,7 +1088,7 @@ bytesio_clear(PyObject *op)
{
bytesio *self = bytesio_CAST(op);
Py_CLEAR(self->dict);
- if (self->exports == 0) {
+ if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
Py_CLEAR(self->buf);
}
return 0;
@@ -1077,18 +1166,15 @@ PyType_Spec bytesio_spec = {
*/
static int
-bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
+bytesiobuf_getbuffer_lock_held(PyObject *op, Py_buffer *view, int flags)
{
bytesiobuf *obj = bytesiobuf_CAST(op);
bytesio *b = bytesio_CAST(obj->source);
- if (view == NULL) {
- PyErr_SetString(PyExc_BufferError,
- "bytesiobuf_getbuffer: view==NULL argument is obsolete");
- return -1;
- }
- if (b->exports == 0 && SHARED_BUF(b)) {
- if (unshare_buffer(b, b->string_size) < 0)
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(b);
+
+ if (FT_ATOMIC_LOAD_SSIZE_RELAXED(b->exports) == 0 && SHARED_BUF(b)) {
+ if (unshare_buffer_lock_held(b, b->string_size) < 0)
return -1;
}
@@ -1096,16 +1182,32 @@ bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
(void)PyBuffer_FillInfo(view, op,
PyBytes_AS_STRING(b->buf), b->string_size,
0, flags);
- b->exports++;
+ FT_ATOMIC_ADD_SSIZE(b->exports, 1);
return 0;
}
+static int
+bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
+{
+ if (view == NULL) {
+ PyErr_SetString(PyExc_BufferError,
+ "bytesiobuf_getbuffer: view==NULL argument is obsolete");
+ return -1;
+ }
+
+ int ret;
+ Py_BEGIN_CRITICAL_SECTION(bytesiobuf_CAST(op)->source);
+ ret = bytesiobuf_getbuffer_lock_held(op, view, flags);
+ Py_END_CRITICAL_SECTION();
+ return ret;
+}
+
static void
bytesiobuf_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view))
{
bytesiobuf *obj = bytesiobuf_CAST(op);
bytesio *b = bytesio_CAST(obj->source);
- b->exports--;
+ FT_ATOMIC_ADD_SSIZE(b->exports, -1);
}
static int
diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h
index aaf4884d173..8553ed05f70 100644
--- a/Modules/_io/clinic/bytesio.c.h
+++ b/Modules/_io/clinic/bytesio.c.h
@@ -7,6 +7,7 @@ preserve
# include "pycore_runtime.h" // _Py_ID()
#endif
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(_io_BytesIO_readable__doc__,
@@ -96,11 +97,18 @@ _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls);
static PyObject *
_io_BytesIO_getbuffer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments");
- return NULL;
+ goto exit;
}
- return _io_BytesIO_getbuffer_impl((bytesio *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _io_BytesIO_getbuffer_impl((bytesio *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_io_BytesIO_getvalue__doc__,
@@ -118,7 +126,13 @@ _io_BytesIO_getvalue_impl(bytesio *self);
static PyObject *
_io_BytesIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return _io_BytesIO_getvalue_impl((bytesio *)self);
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _io_BytesIO_getvalue_impl((bytesio *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
}
PyDoc_STRVAR(_io_BytesIO_isatty__doc__,
@@ -156,7 +170,13 @@ _io_BytesIO_tell_impl(bytesio *self);
static PyObject *
_io_BytesIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return _io_BytesIO_tell_impl((bytesio *)self);
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _io_BytesIO_tell_impl((bytesio *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
}
PyDoc_STRVAR(_io_BytesIO_read__doc__,
@@ -190,7 +210,9 @@ _io_BytesIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
goto exit;
}
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_read_impl((bytesio *)self, size);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -227,7 +249,9 @@ _io_BytesIO_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
goto exit;
}
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_read1_impl((bytesio *)self, size);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -265,7 +289,9 @@ _io_BytesIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
goto exit;
}
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_readline_impl((bytesio *)self, size);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -301,7 +327,9 @@ _io_BytesIO_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
}
arg = args[0];
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_readlines_impl((bytesio *)self, arg);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -332,7 +360,9 @@ _io_BytesIO_readinto(PyObject *self, PyObject *arg)
_PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg);
goto exit;
}
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_readinto_impl((bytesio *)self, &buffer);
+ Py_END_CRITICAL_SECTION();
exit:
/* Cleanup for buffer */
@@ -356,13 +386,13 @@ PyDoc_STRVAR(_io_BytesIO_truncate__doc__,
{"truncate", _PyCFunction_CAST(_io_BytesIO_truncate), METH_FASTCALL, _io_BytesIO_truncate__doc__},
static PyObject *
-_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size);
+_io_BytesIO_truncate_impl(bytesio *self, PyObject *size);
static PyObject *
_io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
- Py_ssize_t size = ((bytesio *)self)->pos;
+ PyObject *size = Py_None;
if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) {
goto exit;
@@ -370,11 +400,11 @@ _io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
if (nargs < 1) {
goto skip_optional;
}
- if (!_Py_convert_optional_to_ssize_t(args[0], &size)) {
- goto exit;
- }
+ size = args[0];
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_truncate_impl((bytesio *)self, size);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -428,7 +458,9 @@ _io_BytesIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
goto exit;
}
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_seek_impl((bytesio *)self, pos, whence);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -453,7 +485,9 @@ _io_BytesIO_write(PyObject *self, PyObject *b)
{
PyObject *return_value = NULL;
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_write_impl((bytesio *)self, b);
+ Py_END_CRITICAL_SECTION();
return return_value;
}
@@ -479,7 +513,9 @@ _io_BytesIO_writelines(PyObject *self, PyObject *lines)
{
PyObject *return_value = NULL;
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO_writelines_impl((bytesio *)self, lines);
+ Py_END_CRITICAL_SECTION();
return return_value;
}
@@ -499,7 +535,13 @@ _io_BytesIO_close_impl(bytesio *self);
static PyObject *
_io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return _io_BytesIO_close_impl((bytesio *)self);
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _io_BytesIO_close_impl((bytesio *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
}
PyDoc_STRVAR(_io_BytesIO___init____doc__,
@@ -558,9 +600,11 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
}
initvalue = fastargs[0];
skip_optional_pos:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
-/*[clinic end generated code: output=6dbfd82f4e9d4ef3 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=580205daa01def2e input=a9049054013a1b77]*/
diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h
index 8e8cd8df9ab..83165e5f7ad 100644
--- a/Modules/_io/clinic/stringio.c.h
+++ b/Modules/_io/clinic/stringio.c.h
@@ -149,13 +149,13 @@ PyDoc_STRVAR(_io_StringIO_truncate__doc__,
{"truncate", _PyCFunction_CAST(_io_StringIO_truncate), METH_FASTCALL, _io_StringIO_truncate__doc__},
static PyObject *
-_io_StringIO_truncate_impl(stringio *self, Py_ssize_t size);
+_io_StringIO_truncate_impl(stringio *self, PyObject *pos);
static PyObject *
_io_StringIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
- Py_ssize_t size = ((stringio *)self)->pos;
+ PyObject *pos = Py_None;
if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) {
goto exit;
@@ -163,12 +163,10 @@ _io_StringIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
if (nargs < 1) {
goto skip_optional;
}
- if (!_Py_convert_optional_to_ssize_t(args[0], &size)) {
- goto exit;
- }
+ pos = args[0];
skip_optional:
Py_BEGIN_CRITICAL_SECTION(self);
- return_value = _io_StringIO_truncate_impl((stringio *)self, size);
+ return_value = _io_StringIO_truncate_impl((stringio *)self, pos);
Py_END_CRITICAL_SECTION();
exit:
@@ -552,4 +550,4 @@ _io_StringIO_newlines_get(PyObject *self, void *Py_UNUSED(context))
return return_value;
}
-/*[clinic end generated code: output=5bfaaab7f41ee6b5 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=bccc25ef8e6ce9ef input=a9049054013a1b77]*/
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 0c5424954be..26537fc6395 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -4,6 +4,7 @@
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stdbool.h> // bool
#ifdef HAVE_UNISTD_H
@@ -570,9 +571,7 @@ fileio_dealloc(PyObject *op)
PyMem_Free(self->stat_atopen);
self->stat_atopen = NULL;
}
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
(void)fileio_clear(op);
PyTypeObject *tp = Py_TYPE(op);
@@ -1262,8 +1261,7 @@ static PyMethodDef fileio_methods[] = {
_IO_FILEIO_ISATTY_METHODDEF
{"_isatty_open_only", _io_FileIO_isatty_open_only, METH_NOARGS},
{"_dealloc_warn", fileio_dealloc_warn, METH_O, NULL},
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
index cd4c7e7cead..044f6b7803c 100644
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -14,6 +14,7 @@
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_object.h" // _PyType_HasFeature()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "_iomodule.h"
@@ -383,8 +384,7 @@ iobase_dealloc(PyObject *op)
}
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
Py_CLEAR(self->dict);
tp->tp_free(self);
Py_DECREF(tp);
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
index 9d1bfa3ea05..20b7cfc0088 100644
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -1,6 +1,7 @@
#include "Python.h"
#include <stddef.h> // offsetof()
#include "pycore_object.h"
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
/* Implementation note: the buffer is always at least one character longer
@@ -444,7 +445,7 @@ stringio_iternext(PyObject *op)
/*[clinic input]
@critical_section
_io.StringIO.truncate
- pos as size: Py_ssize_t(accept={int, NoneType}, c_default="((stringio *)self)->pos") = None
+ pos: object = None
/
Truncate size to pos.
@@ -455,16 +456,26 @@ Returns the new absolute position.
[clinic start generated code]*/
static PyObject *
-_io_StringIO_truncate_impl(stringio *self, Py_ssize_t size)
-/*[clinic end generated code: output=eb3aef8e06701365 input=fa8a6c98bb2ba780]*/
+_io_StringIO_truncate_impl(stringio *self, PyObject *pos)
+/*[clinic end generated code: output=c76c43b5ecfaf4e2 input=d59fd2ee49757ae6]*/
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
- if (size < 0) {
- PyErr_Format(PyExc_ValueError,
- "Negative size value %zd", size);
- return NULL;
+ Py_ssize_t size;
+ if (pos == Py_None) {
+ size = self->pos;
+ }
+ else {
+ size = PyLong_AsLong(pos);
+ if (size == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (size < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "negative pos value %zd", size);
+ return NULL;
+ }
}
if (size < self->string_size) {
@@ -628,9 +639,7 @@ stringio_dealloc(PyObject *op)
}
PyUnicodeWriter_Discard(self->writer);
(void)stringio_clear(op);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index a5b2ca7240a..5354cf63442 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -16,6 +16,7 @@
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_unicodeobject.h" // _PyUnicode_AsASCIIString()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
@@ -1469,8 +1470,7 @@ textiowrapper_dealloc(PyObject *op)
return;
self->ok = 0;
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
(void)textiowrapper_clear(op);
tp->tp_free(self);
Py_DECREF(tp);
@@ -1578,6 +1578,8 @@ _io_TextIOWrapper_detach_impl(textio *self)
static int
_textiowrapper_writeflush(textio *self)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
if (self->pending_bytes == NULL)
return 0;
@@ -3173,8 +3175,9 @@ _io_TextIOWrapper_close_impl(textio *self)
}
static PyObject *
-textiowrapper_iternext(PyObject *op)
+textiowrapper_iternext_lock_held(PyObject *op)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
PyObject *line;
textio *self = textio_CAST(op);
@@ -3210,6 +3213,16 @@ textiowrapper_iternext(PyObject *op)
return line;
}
+static PyObject *
+textiowrapper_iternext(PyObject *op)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = textiowrapper_iternext_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
@critical_section
@getter
@@ -3366,8 +3379,7 @@ static PyMethodDef textiowrapper_methods[] = {
_IO_TEXTIOWRAPPER_TELL_METHODDEF
_IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c
index 3e783b9da45..950b7fe241c 100644
--- a/Modules/_io/winconsoleio.c
+++ b/Modules/_io/winconsoleio.c
@@ -10,6 +10,7 @@
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#ifdef HAVE_WINDOWS_CONSOLE_IO
@@ -518,8 +519,7 @@ winconsoleio_dealloc(PyObject *op)
if (_PyIOBase_finalize(op) < 0)
return;
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
Py_CLEAR(self->dict);
tp->tp_free(self);
Py_DECREF(tp);
diff --git a/Modules/_json.c b/Modules/_json.c
index 89b0a41dd10..6b5f6ea42df 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -360,13 +360,6 @@ _build_rval_index_tuple(PyObject *rval, Py_ssize_t idx) {
return tpl;
}
-static inline int
-_PyUnicodeWriter_IsEmpty(PyUnicodeWriter *writer_pub)
-{
- _PyUnicodeWriter *writer = (_PyUnicodeWriter*)writer_pub;
- return (writer->pos == 0);
-}
-
static PyObject *
scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr)
{
@@ -385,10 +378,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
const void *buf;
int kind;
- PyUnicodeWriter *writer = PyUnicodeWriter_Create(0);
- if (writer == NULL) {
- goto bail;
- }
+ PyUnicodeWriter *writer = NULL;
len = PyUnicode_GET_LENGTH(pystr);
buf = PyUnicode_DATA(pystr);
@@ -419,12 +409,11 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
if (c == '"') {
// Fast path for simple case.
- if (_PyUnicodeWriter_IsEmpty(writer)) {
+ if (writer == NULL) {
PyObject *ret = PyUnicode_Substring(pystr, end, next);
if (ret == NULL) {
goto bail;
}
- PyUnicodeWriter_Discard(writer);
*next_end_ptr = next + 1;;
return ret;
}
@@ -432,6 +421,11 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
else if (c != '\\') {
raise_errmsg("Unterminated string starting at", pystr, begin);
goto bail;
+ } else if (writer == NULL) {
+ writer = PyUnicodeWriter_Create(0);
+ if (writer == NULL) {
+ goto bail;
+ }
}
/* Pick up this chunk if it's not zero length */
@@ -1476,13 +1470,13 @@ encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer,
int rv;
if (obj == Py_None) {
- return PyUnicodeWriter_WriteUTF8(writer, "null", 4);
+ return PyUnicodeWriter_WriteASCII(writer, "null", 4);
}
else if (obj == Py_True) {
- return PyUnicodeWriter_WriteUTF8(writer, "true", 4);
+ return PyUnicodeWriter_WriteASCII(writer, "true", 4);
}
else if (obj == Py_False) {
- return PyUnicodeWriter_WriteUTF8(writer, "false", 5);
+ return PyUnicodeWriter_WriteASCII(writer, "false", 5);
}
else if (PyUnicode_Check(obj)) {
PyObject *encoded = encoder_encode_string(s, obj);
@@ -1609,6 +1603,12 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs
if (*first) {
*first = false;
+ if (s->indent != Py_None) {
+ if (write_newline_indent(writer, indent_level, indent_cache) < 0) {
+ Py_DECREF(keystr);
+ return -1;
+ }
+ }
}
else {
if (PyUnicodeWriter_WriteStr(writer, item_separator) < 0) {
@@ -1649,7 +1649,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
if (PyDict_GET_SIZE(dct) == 0) {
/* Fast path */
- return PyUnicodeWriter_WriteUTF8(writer, "{}", 2);
+ return PyUnicodeWriter_WriteASCII(writer, "{}", 2);
}
if (s->markers != Py_None) {
@@ -1676,11 +1676,8 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
if (s->indent != Py_None) {
indent_level++;
separator = get_item_separator(s, indent_level, indent_cache);
- if (separator == NULL ||
- write_newline_indent(writer, indent_level, indent_cache) < 0)
- {
+ if (separator == NULL)
goto bail;
- }
}
if (s->sort_keys || !PyDict_CheckExact(dct)) {
@@ -1720,7 +1717,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
goto bail;
Py_CLEAR(ident);
}
- if (s->indent != Py_None) {
+ if (s->indent != Py_None && !first) {
indent_level--;
if (write_newline_indent(writer, indent_level, indent_cache) < 0) {
goto bail;
@@ -1753,7 +1750,7 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer,
return -1;
if (PySequence_Fast_GET_SIZE(s_fast) == 0) {
Py_DECREF(s_fast);
- return PyUnicodeWriter_WriteUTF8(writer, "[]", 2);
+ return PyUnicodeWriter_WriteASCII(writer, "[]", 2);
}
if (s->markers != Py_None) {
diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c
index ad618398d5b..c1f56008b7c 100644
--- a/Modules/_localemodule.c
+++ b/Modules/_localemodule.c
@@ -692,7 +692,17 @@ _locale_nl_langinfo_impl(PyObject *module, int item)
result = result != NULL ? result : "";
char *oldloc = NULL;
if (langinfo_constants[i].category != LC_CTYPE
- && !is_all_ascii(result)
+ && (
+#ifdef __GLIBC__
+ // gh-133740: Always change the locale for ALT_DIGITS and ERA
+# ifdef ALT_DIGITS
+ item == ALT_DIGITS ||
+# endif
+# ifdef ERA
+ item == ERA ||
+# endif
+#endif
+ !is_all_ascii(result))
&& change_locale(langinfo_constants[i].category, &oldloc) < 0)
{
return NULL;
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index 626c176715b..d0074b2a0d1 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -632,6 +632,27 @@ _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code,
}
/*[clinic input]
+_lsprof.Profiler._pythrow_callback
+
+ code: object
+ instruction_offset: object
+ exception: object
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+_lsprof_Profiler__pythrow_callback_impl(ProfilerObject *self, PyObject *code,
+ PyObject *instruction_offset,
+ PyObject *exception)
+/*[clinic end generated code: output=0a32988919dfb94c input=fd728fc2c074f5e6]*/
+{
+ ptrace_enter_call((PyObject*)self, (void *)code, code);
+
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
_lsprof.Profiler._pyreturn_callback
code: object
@@ -747,7 +768,7 @@ static const struct {
} callback_table[] = {
{PY_MONITORING_EVENT_PY_START, "_pystart_callback"},
{PY_MONITORING_EVENT_PY_RESUME, "_pystart_callback"},
- {PY_MONITORING_EVENT_PY_THROW, "_pystart_callback"},
+ {PY_MONITORING_EVENT_PY_THROW, "_pythrow_callback"},
{PY_MONITORING_EVENT_PY_RETURN, "_pyreturn_callback"},
{PY_MONITORING_EVENT_PY_YIELD, "_pyreturn_callback"},
{PY_MONITORING_EVENT_PY_UNWIND, "_pyreturn_callback"},
@@ -782,7 +803,7 @@ _lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls,
return NULL;
}
- PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring");
+ PyObject* monitoring = PySys_GetAttrString("monitoring");
if (!monitoring) {
return NULL;
}
@@ -864,7 +885,7 @@ _lsprof_Profiler_disable_impl(ProfilerObject *self)
}
if (self->flags & POF_ENABLED) {
PyObject* result = NULL;
- PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring");
+ PyObject* monitoring = PySys_GetAttrString("monitoring");
if (!monitoring) {
return NULL;
@@ -983,7 +1004,7 @@ profiler_init_impl(ProfilerObject *self, PyObject *timer, double timeunit,
Py_XSETREF(self->externalTimer, Py_XNewRef(timer));
self->tool_id = PY_MONITORING_PROFILER_ID;
- PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring");
+ PyObject* monitoring = PySys_GetAttrString("monitoring");
if (!monitoring) {
return -1;
}
@@ -1002,6 +1023,7 @@ static PyMethodDef profiler_methods[] = {
_LSPROF_PROFILER_DISABLE_METHODDEF
_LSPROF_PROFILER_CLEAR_METHODDEF
_LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF
+ _LSPROF_PROFILER__PYTHROW_CALLBACK_METHODDEF
_LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF
_LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF
_LSPROF_PROFILER__CRETURN_CALLBACK_METHODDEF
diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c
index f9b4c2a170e..462c2181fa6 100644
--- a/Modules/_lzmamodule.c
+++ b/Modules/_lzmamodule.c
@@ -17,6 +17,7 @@
#include <lzma.h>
+#include "pycore_long.h" // _PyLong_UInt32_Converter()
// Blocks output buffer wrappers
#include "pycore_blocks_output_buffer.h"
@@ -223,8 +224,6 @@ FUNCNAME(PyObject *obj, void *ptr) \
return 1; \
}
-INT_TYPE_CONVERTER_FUNC(uint32_t, uint32_converter)
-INT_TYPE_CONVERTER_FUNC(uint64_t, uint64_converter)
INT_TYPE_CONVERTER_FUNC(lzma_vli, lzma_vli_converter)
INT_TYPE_CONVERTER_FUNC(lzma_mode, lzma_mode_converter)
INT_TYPE_CONVERTER_FUNC(lzma_match_finder, lzma_mf_converter)
@@ -254,7 +253,7 @@ parse_filter_spec_lzma(_lzma_state *state, PyObject *spec)
return NULL;
}
if (preset_obj != NULL) {
- int ok = uint32_converter(preset_obj, &preset);
+ int ok = _PyLong_UInt32_Converter(preset_obj, &preset);
Py_DECREF(preset_obj);
if (!ok) {
return NULL;
@@ -275,14 +274,14 @@ parse_filter_spec_lzma(_lzma_state *state, PyObject *spec)
if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec,
"|OOO&O&O&O&O&O&O&O&", optnames,
&id, &preset_obj,
- uint32_converter, &options->dict_size,
- uint32_converter, &options->lc,
- uint32_converter, &options->lp,
- uint32_converter, &options->pb,
+ _PyLong_UInt32_Converter, &options->dict_size,
+ _PyLong_UInt32_Converter, &options->lc,
+ _PyLong_UInt32_Converter, &options->lp,
+ _PyLong_UInt32_Converter, &options->pb,
lzma_mode_converter, &options->mode,
- uint32_converter, &options->nice_len,
+ _PyLong_UInt32_Converter, &options->nice_len,
lzma_mf_converter, &options->mf,
- uint32_converter, &options->depth)) {
+ _PyLong_UInt32_Converter, &options->depth)) {
PyErr_SetString(PyExc_ValueError,
"Invalid filter specifier for LZMA filter");
PyMem_Free(options);
@@ -301,7 +300,7 @@ parse_filter_spec_delta(_lzma_state *state, PyObject *spec)
lzma_options_delta *options;
if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OO&", optnames,
- &id, uint32_converter, &dist)) {
+ &id, _PyLong_UInt32_Converter, &dist)) {
PyErr_SetString(PyExc_ValueError,
"Invalid filter specifier for delta filter");
return NULL;
@@ -325,7 +324,7 @@ parse_filter_spec_bcj(_lzma_state *state, PyObject *spec)
lzma_options_bcj *options;
if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OO&", optnames,
- &id, uint32_converter, &start_offset)) {
+ &id, _PyLong_UInt32_Converter, &start_offset)) {
PyErr_SetString(PyExc_ValueError,
"Invalid filter specifier for BCJ filter");
return NULL;
@@ -806,7 +805,7 @@ Compressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
return NULL;
}
- if (preset_obj != Py_None && !uint32_converter(preset_obj, &preset)) {
+ if (preset_obj != Py_None && !_PyLong_UInt32_Converter(preset_obj, &preset)) {
return NULL;
}
@@ -1226,7 +1225,7 @@ _lzma_LZMADecompressor_impl(PyTypeObject *type, int format,
"Cannot specify memory limit with FORMAT_RAW");
return NULL;
}
- if (!uint64_converter(memlimit, &memlimit_)) {
+ if (!_PyLong_UInt64_Converter(memlimit, &memlimit_)) {
return NULL;
}
}
diff --git a/Modules/_opcode.c b/Modules/_opcode.c
index c295f7b3152..ef271b6ef56 100644
--- a/Modules/_opcode.c
+++ b/Modules/_opcode.c
@@ -5,7 +5,7 @@
#include "Python.h"
#include "compile.h"
#include "opcode.h"
-#include "pycore_ceval.h"
+#include "pycore_ceval.h" // SPECIAL_MAX
#include "pycore_code.h"
#include "pycore_compile.h"
#include "pycore_intrinsics.h"
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index d260f1a68f8..cf3ceb43fb3 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -1879,6 +1879,10 @@ _checkmodule(PyObject *module_name, PyObject *module,
_PyUnicode_EqualToASCIIString(module_name, "__main__")) {
return -1;
}
+ if (PyUnicode_Check(module_name) &&
+ _PyUnicode_EqualToASCIIString(module_name, "__mp_main__")) {
+ return -1;
+ }
PyObject *candidate = getattribute(module, dotted_path, 0);
if (candidate == NULL) {
@@ -1911,7 +1915,7 @@ whichmodule(PickleState *st, PyObject *global, PyObject *global_name, PyObject *
__module__ can be None. If it is so, then search sys.modules for
the module of global. */
Py_CLEAR(module_name);
- modules = _PySys_GetRequiredAttr(&_Py_ID(modules));
+ modules = PySys_GetAttr(&_Py_ID(modules));
if (modules == NULL) {
return NULL;
}
@@ -5539,17 +5543,16 @@ static int
load_counted_binstring(PickleState *st, UnpicklerObject *self, int nbytes)
{
PyObject *obj;
- Py_ssize_t size;
+ long size;
char *s;
if (_Unpickler_Read(self, st, &s, nbytes) < 0)
return -1;
- size = calc_binsize(s, nbytes);
+ size = calc_binint(s, nbytes);
if (size < 0) {
- PyErr_Format(st->UnpicklingError,
- "BINSTRING exceeds system's maximum size of %zd bytes",
- PY_SSIZE_T_MAX);
+ PyErr_SetString(st->UnpicklingError,
+ "BINSTRING pickle has negative byte count");
return -1;
}
diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c
index 3ee14b61b82..01235c77bd7 100644
--- a/Modules/_queuemodule.c
+++ b/Modules/_queuemodule.c
@@ -7,6 +7,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_parking_lot.h"
#include "pycore_time.h" // _PyTime_FromSecondsObject()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stdbool.h>
#include <stddef.h> // offsetof()
@@ -221,9 +222,7 @@ simplequeue_dealloc(PyObject *op)
PyObject_GC_UnTrack(self);
(void)simplequeue_clear(op);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}
diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c
index d5bac2f5b78..2f4f388ce11 100644
--- a/Modules/_randommodule.c
+++ b/Modules/_randommodule.c
@@ -497,34 +497,32 @@ _random_Random_setstate_impl(RandomObject *self, PyObject *state)
_random.Random.getrandbits
self: self(type="RandomObject *")
- k: int
+ k: uint64
/
getrandbits(k) -> x. Generates an int with k random bits.
[clinic start generated code]*/
static PyObject *
-_random_Random_getrandbits_impl(RandomObject *self, int k)
-/*[clinic end generated code: output=b402f82a2158887f input=87603cd60f79f730]*/
+_random_Random_getrandbits_impl(RandomObject *self, uint64_t k)
+/*[clinic end generated code: output=c30ef8435f3433cf input=64226ac13bb4d2a3]*/
{
- int i, words;
+ Py_ssize_t i, words;
uint32_t r;
uint32_t *wordarray;
PyObject *result;
- if (k < 0) {
- PyErr_SetString(PyExc_ValueError,
- "number of bits must be non-negative");
- return NULL;
- }
-
if (k == 0)
return PyLong_FromLong(0);
if (k <= 32) /* Fast path */
return PyLong_FromUnsignedLong(genrand_uint32(self) >> (32 - k));
- words = (k - 1) / 32 + 1;
+ if ((k - 1u) / 32u + 1u > PY_SSIZE_T_MAX / 4u) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ words = (k - 1u) / 32u + 1u;
wordarray = (uint32_t *)PyMem_Malloc(words * 4);
if (wordarray == NULL) {
PyErr_NoMemory();
diff --git a/Modules/_remote_debugging_module.c b/Modules/_remote_debugging_module.c
new file mode 100644
index 00000000000..ce7189637c2
--- /dev/null
+++ b/Modules/_remote_debugging_module.c
@@ -0,0 +1,3139 @@
+/******************************************************************************
+ * Python Remote Debugging Module
+ *
+ * This module provides functionality to debug Python processes remotely by
+ * reading their memory and reconstructing stack traces and asyncio task states.
+ ******************************************************************************/
+
+#define _GNU_SOURCE
+
+/* ============================================================================
+ * HEADERS AND INCLUDES
+ * ============================================================================ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+#include "Python.h"
+#include <internal/pycore_debug_offsets.h> // _Py_DebugOffsets
+#include <internal/pycore_frame.h> // FRAME_SUSPENDED_YIELD_FROM
+#include <internal/pycore_interpframe.h> // FRAME_OWNED_BY_CSTACK
+#include <internal/pycore_llist.h> // struct llist_node
+#include <internal/pycore_stackref.h> // Py_TAG_BITS
+#include "../Python/remote_debug.h"
+
+#ifndef HAVE_PROCESS_VM_READV
+# define HAVE_PROCESS_VM_READV 0
+#endif
+
+/* ============================================================================
+ * TYPE DEFINITIONS AND STRUCTURES
+ * ============================================================================ */
+
+#define GET_MEMBER(type, obj, offset) (*(type*)((char*)(obj) + (offset)))
+#define CLEAR_PTR_TAG(ptr) (((uintptr_t)(ptr) & ~Py_TAG_BITS))
+#define GET_MEMBER_NO_TAG(type, obj, offset) (type)(CLEAR_PTR_TAG(*(type*)((char*)(obj) + (offset))))
+
+/* Size macros for opaque buffers */
+#define SIZEOF_BYTES_OBJ sizeof(PyBytesObject)
+#define SIZEOF_CODE_OBJ sizeof(PyCodeObject)
+#define SIZEOF_GEN_OBJ sizeof(PyGenObject)
+#define SIZEOF_INTERP_FRAME sizeof(_PyInterpreterFrame)
+#define SIZEOF_LLIST_NODE sizeof(struct llist_node)
+#define SIZEOF_PAGE_CACHE_ENTRY sizeof(page_cache_entry_t)
+#define SIZEOF_PYOBJECT sizeof(PyObject)
+#define SIZEOF_SET_OBJ sizeof(PySetObject)
+#define SIZEOF_TASK_OBJ 4096
+#define SIZEOF_THREAD_STATE sizeof(PyThreadState)
+#define SIZEOF_TYPE_OBJ sizeof(PyTypeObject)
+#define SIZEOF_UNICODE_OBJ sizeof(PyUnicodeObject)
+#define SIZEOF_LONG_OBJ sizeof(PyLongObject)
+
+// Calculate the minimum buffer size needed to read interpreter state fields
+// We need to read code_object_generation and potentially tlbc_generation
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifdef Py_GIL_DISABLED
+#define INTERP_STATE_MIN_SIZE MAX(MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \
+ offsetof(PyInterpreterState, tlbc_indices.tlbc_generation) + sizeof(uint32_t)), \
+ offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \
+ offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*))
+#else
+#define INTERP_STATE_MIN_SIZE MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \
+ offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \
+ offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*))
+#endif
+#define INTERP_STATE_BUFFER_SIZE MAX(INTERP_STATE_MIN_SIZE, 256)
+
+
+
+// Copied from Modules/_asynciomodule.c because it's not exported
+
+struct _Py_AsyncioModuleDebugOffsets {
+ struct _asyncio_task_object {
+ uint64_t size;
+ uint64_t task_name;
+ uint64_t task_awaited_by;
+ uint64_t task_is_task;
+ uint64_t task_awaited_by_is_set;
+ uint64_t task_coro;
+ uint64_t task_node;
+ } asyncio_task_object;
+ struct _asyncio_interpreter_state {
+ uint64_t size;
+ uint64_t asyncio_tasks_head;
+ } asyncio_interpreter_state;
+ struct _asyncio_thread_state {
+ uint64_t size;
+ uint64_t asyncio_running_loop;
+ uint64_t asyncio_running_task;
+ uint64_t asyncio_tasks_head;
+ } asyncio_thread_state;
+};
+
+/* ============================================================================
+ * STRUCTSEQ TYPE DEFINITIONS
+ * ============================================================================ */
+
+// TaskInfo structseq type - replaces 4-tuple (task_id, task_name, coroutine_stack, awaited_by)
+static PyStructSequence_Field TaskInfo_fields[] = {
+ {"task_id", "Task ID (memory address)"},
+ {"task_name", "Task name"},
+ {"coroutine_stack", "Coroutine call stack"},
+ {"awaited_by", "Tasks awaiting this task"},
+ {NULL}
+};
+
+static PyStructSequence_Desc TaskInfo_desc = {
+ "_remote_debugging.TaskInfo",
+ "Information about an asyncio task",
+ TaskInfo_fields,
+ 4
+};
+
+// FrameInfo structseq type - replaces 3-tuple (filename, lineno, funcname)
+static PyStructSequence_Field FrameInfo_fields[] = {
+ {"filename", "Source code filename"},
+ {"lineno", "Line number"},
+ {"funcname", "Function name"},
+ {NULL}
+};
+
+static PyStructSequence_Desc FrameInfo_desc = {
+ "_remote_debugging.FrameInfo",
+ "Information about a frame",
+ FrameInfo_fields,
+ 3
+};
+
+// CoroInfo structseq type - replaces 2-tuple (call_stack, task_name)
+static PyStructSequence_Field CoroInfo_fields[] = {
+ {"call_stack", "Coroutine call stack"},
+ {"task_name", "Task name"},
+ {NULL}
+};
+
+static PyStructSequence_Desc CoroInfo_desc = {
+ "_remote_debugging.CoroInfo",
+ "Information about a coroutine",
+ CoroInfo_fields,
+ 2
+};
+
+// ThreadInfo structseq type - replaces 2-tuple (thread_id, frame_info)
+static PyStructSequence_Field ThreadInfo_fields[] = {
+ {"thread_id", "Thread ID"},
+ {"frame_info", "Frame information"},
+ {NULL}
+};
+
+static PyStructSequence_Desc ThreadInfo_desc = {
+ "_remote_debugging.ThreadInfo",
+ "Information about a thread",
+ ThreadInfo_fields,
+ 2
+};
+
+// AwaitedInfo structseq type - replaces 2-tuple (tid, awaited_by_list)
+static PyStructSequence_Field AwaitedInfo_fields[] = {
+ {"thread_id", "Thread ID"},
+ {"awaited_by", "List of tasks awaited by this thread"},
+ {NULL}
+};
+
+static PyStructSequence_Desc AwaitedInfo_desc = {
+ "_remote_debugging.AwaitedInfo",
+ "Information about what a thread is awaiting",
+ AwaitedInfo_fields,
+ 2
+};
+
+typedef struct {
+ PyObject *func_name;
+ PyObject *file_name;
+ int first_lineno;
+ PyObject *linetable; // bytes
+ uintptr_t addr_code_adaptive;
+} CachedCodeMetadata;
+
+typedef struct {
+ /* Types */
+ PyTypeObject *RemoteDebugging_Type;
+ PyTypeObject *TaskInfo_Type;
+ PyTypeObject *FrameInfo_Type;
+ PyTypeObject *CoroInfo_Type;
+ PyTypeObject *ThreadInfo_Type;
+ PyTypeObject *AwaitedInfo_Type;
+} RemoteDebuggingState;
+
+typedef struct {
+ PyObject_HEAD
+ proc_handle_t handle;
+ uintptr_t runtime_start_address;
+ struct _Py_DebugOffsets debug_offsets;
+ int async_debug_offsets_available;
+ struct _Py_AsyncioModuleDebugOffsets async_debug_offsets;
+ uintptr_t interpreter_addr;
+ uintptr_t tstate_addr;
+ uint64_t code_object_generation;
+ _Py_hashtable_t *code_object_cache;
+ int debug;
+ int only_active_thread;
+ RemoteDebuggingState *cached_state; // Cached module state
+#ifdef Py_GIL_DISABLED
+ // TLBC cache invalidation tracking
+ uint32_t tlbc_generation; // Track TLBC index pool changes
+ _Py_hashtable_t *tlbc_cache; // Cache of TLBC arrays by code object address
+#endif
+} RemoteUnwinderObject;
+
+#define RemoteUnwinder_CAST(op) ((RemoteUnwinderObject *)(op))
+
+typedef struct
+{
+ int lineno;
+ int end_lineno;
+ int column;
+ int end_column;
+} LocationInfo;
+
+typedef struct {
+ uintptr_t remote_addr;
+ size_t size;
+ void *local_copy;
+} StackChunkInfo;
+
+typedef struct {
+ StackChunkInfo *chunks;
+ size_t count;
+} StackChunkList;
+
+#include "clinic/_remote_debugging_module.c.h"
+
+/*[clinic input]
+module _remote_debugging
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5f507d5b2e76a7f7]*/
+
+
+/* ============================================================================
+ * FORWARD DECLARATIONS
+ * ============================================================================ */
+
+static inline int
+is_frame_valid(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t frame_addr,
+ uintptr_t code_object_addr
+);
+
+static int
+parse_tasks_in_set(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t set_addr,
+ PyObject *awaited_by,
+ int recurse_task
+);
+
+static int
+parse_task(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t task_address,
+ PyObject *render_to,
+ int recurse_task
+);
+
+static int
+parse_coro_chain(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t coro_address,
+ PyObject *render_to
+);
+
+/* Forward declarations for task parsing functions */
+static int parse_frame_object(
+ RemoteUnwinderObject *unwinder,
+ PyObject** result,
+ uintptr_t address,
+ uintptr_t* previous_frame
+);
+
+/* ============================================================================
+ * UTILITY FUNCTIONS AND HELPERS
+ * ============================================================================ */
+
+#define set_exception_cause(unwinder, exc_type, message) \
+ if (unwinder->debug) { \
+ _set_debug_exception_cause(exc_type, message); \
+ }
+
+static void
+cached_code_metadata_destroy(void *ptr)
+{
+ CachedCodeMetadata *meta = (CachedCodeMetadata *)ptr;
+ Py_DECREF(meta->func_name);
+ Py_DECREF(meta->file_name);
+ Py_DECREF(meta->linetable);
+ PyMem_RawFree(meta);
+}
+
+static inline RemoteDebuggingState *
+RemoteDebugging_GetState(PyObject *module)
+{
+ void *state = _PyModule_GetState(module);
+ assert(state != NULL);
+ return (RemoteDebuggingState *)state;
+}
+
+static inline RemoteDebuggingState *
+RemoteDebugging_GetStateFromType(PyTypeObject *type)
+{
+ PyObject *module = PyType_GetModule(type);
+ assert(module != NULL);
+ return RemoteDebugging_GetState(module);
+}
+
+static inline RemoteDebuggingState *
+RemoteDebugging_GetStateFromObject(PyObject *obj)
+{
+ RemoteUnwinderObject *unwinder = (RemoteUnwinderObject *)obj;
+ if (unwinder->cached_state == NULL) {
+ unwinder->cached_state = RemoteDebugging_GetStateFromType(Py_TYPE(obj));
+ }
+ return unwinder->cached_state;
+}
+
+static inline int
+RemoteDebugging_InitState(RemoteDebuggingState *st)
+{
+ return 0;
+}
+
+static int
+is_prerelease_version(uint64_t version)
+{
+ return (version & 0xF0) != 0xF0;
+}
+
+static inline int
+validate_debug_offsets(struct _Py_DebugOffsets *debug_offsets)
+{
+ if (memcmp(debug_offsets->cookie, _Py_Debug_Cookie, sizeof(debug_offsets->cookie)) != 0) {
+ // The remote is probably running a Python version predating debug offsets.
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "Can't determine the Python version of the remote process");
+ return -1;
+ }
+
+ // Assume debug offsets could change from one pre-release version to another,
+ // or one minor version to another, but are stable across patch versions.
+ if (is_prerelease_version(Py_Version) && Py_Version != debug_offsets->version) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "Can't attach from a pre-release Python interpreter"
+ " to a process running a different Python version");
+ return -1;
+ }
+
+ if (is_prerelease_version(debug_offsets->version) && Py_Version != debug_offsets->version) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "Can't attach to a pre-release Python interpreter"
+ " from a process running a different Python version");
+ return -1;
+ }
+
+ unsigned int remote_major = (debug_offsets->version >> 24) & 0xFF;
+ unsigned int remote_minor = (debug_offsets->version >> 16) & 0xFF;
+
+ if (PY_MAJOR_VERSION != remote_major || PY_MINOR_VERSION != remote_minor) {
+ PyErr_Format(
+ PyExc_RuntimeError,
+ "Can't attach from a Python %d.%d process to a Python %d.%d process",
+ PY_MAJOR_VERSION, PY_MINOR_VERSION, remote_major, remote_minor);
+ return -1;
+ }
+
+ // The debug offsets differ between free threaded and non-free threaded builds.
+ if (_Py_Debug_Free_Threaded && !debug_offsets->free_threaded) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "Cannot attach from a free-threaded Python process"
+ " to a process running a non-free-threaded version");
+ return -1;
+ }
+
+ if (!_Py_Debug_Free_Threaded && debug_offsets->free_threaded) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "Cannot attach to a free-threaded Python process"
+ " from a process running a non-free-threaded version");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* ============================================================================
+ * MEMORY READING FUNCTIONS
+ * ============================================================================ */
+
+static inline int
+read_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *ptr_addr)
+{
+ int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address, sizeof(void*), ptr_addr);
+ if (result < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read pointer from remote memory");
+ return -1;
+ }
+ return 0;
+}
+
+static inline int
+read_Py_ssize_t(RemoteUnwinderObject *unwinder, uintptr_t address, Py_ssize_t *size)
+{
+ int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address, sizeof(Py_ssize_t), size);
+ if (result < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read Py_ssize_t from remote memory");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *ptr_addr)
+{
+ if (read_ptr(unwinder, address, ptr_addr)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read Python pointer");
+ return -1;
+ }
+ *ptr_addr &= ~Py_TAG_BITS;
+ return 0;
+}
+
+static int
+read_char(RemoteUnwinderObject *unwinder, uintptr_t address, char *result)
+{
+ int res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address, sizeof(char), result);
+ if (res < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read char from remote memory");
+ return -1;
+ }
+ return 0;
+}
+
+/* ============================================================================
+ * PYTHON OBJECT READING FUNCTIONS
+ * ============================================================================ */
+
+static PyObject *
+read_py_str(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t address,
+ Py_ssize_t max_len
+) {
+ PyObject *result = NULL;
+ char *buf = NULL;
+
+ // Read the entire PyUnicodeObject at once
+ char unicode_obj[SIZEOF_UNICODE_OBJ];
+ int res = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address,
+ SIZEOF_UNICODE_OBJ,
+ unicode_obj
+ );
+ if (res < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyUnicodeObject");
+ goto err;
+ }
+
+ Py_ssize_t len = GET_MEMBER(Py_ssize_t, unicode_obj, unwinder->debug_offsets.unicode_object.length);
+ if (len < 0 || len > max_len) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Invalid string length (%zd) at 0x%lx", len, address);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid string length in remote Unicode object");
+ return NULL;
+ }
+
+ buf = (char *)PyMem_RawMalloc(len+1);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate buffer for string reading");
+ return NULL;
+ }
+
+ size_t offset = unwinder->debug_offsets.unicode_object.asciiobject_size;
+ res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address + offset, len, buf);
+ if (res < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read string data from remote memory");
+ goto err;
+ }
+ buf[len] = '\0';
+
+ result = PyUnicode_FromStringAndSize(buf, len);
+ if (result == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create PyUnicode from remote string data");
+ goto err;
+ }
+
+ PyMem_RawFree(buf);
+ assert(result != NULL);
+ return result;
+
+err:
+ if (buf != NULL) {
+ PyMem_RawFree(buf);
+ }
+ return NULL;
+}
+
+static PyObject *
+read_py_bytes(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t address,
+ Py_ssize_t max_len
+) {
+ PyObject *result = NULL;
+ char *buf = NULL;
+
+ // Read the entire PyBytesObject at once
+ char bytes_obj[SIZEOF_BYTES_OBJ];
+ int res = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address,
+ SIZEOF_BYTES_OBJ,
+ bytes_obj
+ );
+ if (res < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyBytesObject");
+ goto err;
+ }
+
+ Py_ssize_t len = GET_MEMBER(Py_ssize_t, bytes_obj, unwinder->debug_offsets.bytes_object.ob_size);
+ if (len < 0 || len > max_len) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Invalid bytes length (%zd) at 0x%lx", len, address);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid bytes length in remote bytes object");
+ return NULL;
+ }
+
+ buf = (char *)PyMem_RawMalloc(len+1);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate buffer for bytes reading");
+ return NULL;
+ }
+
+ size_t offset = unwinder->debug_offsets.bytes_object.ob_sval;
+ res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address + offset, len, buf);
+ if (res < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read bytes data from remote memory");
+ goto err;
+ }
+ buf[len] = '\0';
+
+ result = PyBytes_FromStringAndSize(buf, len);
+ if (result == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create PyBytes from remote bytes data");
+ goto err;
+ }
+
+ PyMem_RawFree(buf);
+ assert(result != NULL);
+ return result;
+
+err:
+ if (buf != NULL) {
+ PyMem_RawFree(buf);
+ }
+ return NULL;
+}
+
+static long
+read_py_long(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t address
+)
+{
+ unsigned int shift = PYLONG_BITS_IN_DIGIT;
+
+ // Read the entire PyLongObject at once
+ char long_obj[SIZEOF_LONG_OBJ];
+ int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address,
+ unwinder->debug_offsets.long_object.size,
+ long_obj);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyLongObject");
+ return -1;
+ }
+
+ uintptr_t lv_tag = GET_MEMBER(uintptr_t, long_obj, unwinder->debug_offsets.long_object.lv_tag);
+ int negative = (lv_tag & 3) == 2;
+ Py_ssize_t size = lv_tag >> 3;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ // If the long object has inline digits, use them directly
+ digit *digits;
+ if (size <= _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS) {
+ // For small integers, digits are inline in the long_value.ob_digit array
+ digits = (digit *)PyMem_RawMalloc(size * sizeof(digit));
+ if (!digits) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for small PyLong");
+ return -1;
+ }
+ memcpy(digits, long_obj + unwinder->debug_offsets.long_object.ob_digit, size * sizeof(digit));
+ } else {
+ // For larger integers, we need to read the digits separately
+ digits = (digit *)PyMem_RawMalloc(size * sizeof(digit));
+ if (!digits) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for large PyLong");
+ return -1;
+ }
+
+ bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address + unwinder->debug_offsets.long_object.ob_digit,
+ sizeof(digit) * size,
+ digits
+ );
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyLong digits from remote memory");
+ goto error;
+ }
+ }
+
+ long long value = 0;
+
+ // In theory this can overflow, but because of llvm/llvm-project#16778
+ // we can't use __builtin_mul_overflow because it fails to link with
+ // __muloti4 on aarch64. In practice this is fine because all we're
+ // testing here are task numbers that would fit in a single byte.
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ long long factor = digits[i] * (1UL << (Py_ssize_t)(shift * i));
+ value += factor;
+ }
+ PyMem_RawFree(digits);
+ if (negative) {
+ value *= -1;
+ }
+ return (long)value;
+error:
+ PyMem_RawFree(digits);
+ return -1;
+}
+
+/* ============================================================================
+ * ASYNCIO DEBUG FUNCTIONS
+ * ============================================================================ */
+
+// Get the PyAsyncioDebug section address for any platform
+static uintptr_t
+_Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
+{
+ uintptr_t address;
+
+#ifdef MS_WINDOWS
+ // On Windows, search for asyncio debug in executable or DLL
+ address = search_windows_map_for_section(handle, "AsyncioD", L"_asyncio");
+ if (address == 0) {
+ // Error out: 'python' substring covers both executable and DLL
+ PyObject *exc = PyErr_GetRaisedException();
+ PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process.");
+ _PyErr_ChainExceptions1(exc);
+ }
+#elif defined(__linux__)
+ // On Linux, search for asyncio debug in executable or DLL
+ address = search_linux_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
+ if (address == 0) {
+ // Error out: 'python' substring covers both executable and DLL
+ PyObject *exc = PyErr_GetRaisedException();
+ PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process.");
+ _PyErr_ChainExceptions1(exc);
+ }
+#elif defined(__APPLE__) && TARGET_OS_OSX
+ // On macOS, try libpython first, then fall back to python
+ address = search_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
+ if (address == 0) {
+ PyErr_Clear();
+ address = search_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
+ }
+ if (address == 0) {
+ // Error out: 'python' substring covers both executable and DLL
+ PyObject *exc = PyErr_GetRaisedException();
+ PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process.");
+ _PyErr_ChainExceptions1(exc);
+ }
+#else
+ Py_UNREACHABLE();
+#endif
+
+ return address;
+}
+
+static int
+read_async_debug(
+ RemoteUnwinderObject *unwinder
+) {
+ uintptr_t async_debug_addr = _Py_RemoteDebug_GetAsyncioDebugAddress(&unwinder->handle);
+ if (!async_debug_addr) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to get AsyncioDebug address");
+ return -1;
+ }
+
+ size_t size = sizeof(struct _Py_AsyncioModuleDebugOffsets);
+ int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, async_debug_addr, size, &unwinder->async_debug_offsets);
+ if (result < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read AsyncioDebug offsets");
+ }
+ return result;
+}
+
+/* ============================================================================
+ * ASYNCIO TASK PARSING FUNCTIONS
+ * ============================================================================ */
+
+static PyObject *
+parse_task_name(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t task_address
+) {
+ // Read the entire TaskObj at once
+ char task_obj[SIZEOF_TASK_OBJ];
+ int err = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ task_address,
+ unwinder->async_debug_offsets.asyncio_task_object.size,
+ task_obj);
+ if (err < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object");
+ return NULL;
+ }
+
+ uintptr_t task_name_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_name);
+
+ // The task name can be a long or a string so we need to check the type
+ char task_name_obj[SIZEOF_PYOBJECT];
+ err = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ task_name_addr,
+ SIZEOF_PYOBJECT,
+ task_name_obj);
+ if (err < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task name object");
+ return NULL;
+ }
+
+ // Now read the type object to get the flags
+ char type_obj[SIZEOF_TYPE_OBJ];
+ err = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ GET_MEMBER(uintptr_t, task_name_obj, unwinder->debug_offsets.pyobject.ob_type),
+ SIZEOF_TYPE_OBJ,
+ type_obj);
+ if (err < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task name type object");
+ return NULL;
+ }
+
+ if ((GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_LONG_SUBCLASS)) {
+ long res = read_py_long(unwinder, task_name_addr);
+ if (res == -1) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Task name PyLong parsing failed");
+ return NULL;
+ }
+ return PyUnicode_FromFormat("Task-%d", res);
+ }
+
+ if(!(GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_UNICODE_SUBCLASS)) {
+ PyErr_SetString(PyExc_RuntimeError, "Invalid task name object");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Task name object is neither long nor unicode");
+ return NULL;
+ }
+
+ return read_py_str(
+ unwinder,
+ task_name_addr,
+ 255
+ );
+}
+
+static int parse_task_awaited_by(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t task_address,
+ PyObject *awaited_by,
+ int recurse_task
+) {
+ // Read the entire TaskObj at once
+ char task_obj[SIZEOF_TASK_OBJ];
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address,
+ unwinder->async_debug_offsets.asyncio_task_object.size,
+ task_obj) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object in awaited_by parsing");
+ return -1;
+ }
+
+ uintptr_t task_ab_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by);
+
+ if ((void*)task_ab_addr == NULL) {
+ return 0;
+ }
+
+ char awaited_by_is_a_set = GET_MEMBER(char, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by_is_set);
+
+ if (awaited_by_is_a_set) {
+ if (parse_tasks_in_set(unwinder, task_ab_addr, awaited_by, recurse_task)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse tasks in awaited_by set");
+ return -1;
+ }
+ } else {
+ if (parse_task(unwinder, task_ab_addr, awaited_by, recurse_task)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse single awaited_by task");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+handle_yield_from_frame(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t gi_iframe_addr,
+ uintptr_t gen_type_addr,
+ PyObject *render_to
+) {
+ // Read the entire interpreter frame at once
+ char iframe[SIZEOF_INTERP_FRAME];
+ int err = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ gi_iframe_addr,
+ SIZEOF_INTERP_FRAME,
+ iframe);
+ if (err < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame in yield_from handler");
+ return -1;
+ }
+
+ if (GET_MEMBER(char, iframe, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "generator doesn't own its frame \\_o_/");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Frame ownership mismatch in yield_from");
+ return -1;
+ }
+
+ uintptr_t stackpointer_addr = GET_MEMBER_NO_TAG(uintptr_t, iframe, unwinder->debug_offsets.interpreter_frame.stackpointer);
+
+ if ((void*)stackpointer_addr != NULL) {
+ uintptr_t gi_await_addr;
+ err = read_py_ptr(
+ unwinder,
+ stackpointer_addr - sizeof(void*),
+ &gi_await_addr);
+ if (err) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read gi_await address");
+ return -1;
+ }
+
+ if ((void*)gi_await_addr != NULL) {
+ uintptr_t gi_await_addr_type_addr;
+ err = read_ptr(
+ unwinder,
+ gi_await_addr + unwinder->debug_offsets.pyobject.ob_type,
+ &gi_await_addr_type_addr);
+ if (err) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read gi_await type address");
+ return -1;
+ }
+
+ if (gen_type_addr == gi_await_addr_type_addr) {
+ /* This needs an explanation. We always start with parsing
+ native coroutine / generator frames. Ultimately they
+ are awaiting on something. That something can be
+ a native coroutine frame or... an iterator.
+ If it's the latter -- we can't continue building
+ our chain. So the condition to bail out of this is
+ to do that when the type of the current coroutine
+ doesn't match the type of whatever it points to
+ in its cr_await.
+ */
+ err = parse_coro_chain(unwinder, gi_await_addr, render_to);
+ if (err) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain in yield_from");
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+parse_coro_chain(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t coro_address,
+ PyObject *render_to
+) {
+ assert((void*)coro_address != NULL);
+
+ // Read the entire generator object at once
+ char gen_object[SIZEOF_GEN_OBJ];
+ int err = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ coro_address,
+ SIZEOF_GEN_OBJ,
+ gen_object);
+ if (err < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read generator object in coro chain");
+ return -1;
+ }
+
+ int8_t frame_state = GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state);
+ if (frame_state == FRAME_CLEARED) {
+ return 0;
+ }
+
+ uintptr_t gen_type_addr = GET_MEMBER(uintptr_t, gen_object, unwinder->debug_offsets.pyobject.ob_type);
+
+ PyObject* name = NULL;
+
+ // Parse the previous frame using the gi_iframe from local copy
+ uintptr_t prev_frame;
+ uintptr_t gi_iframe_addr = coro_address + unwinder->debug_offsets.gen_object.gi_iframe;
+ if (parse_frame_object(unwinder, &name, gi_iframe_addr, &prev_frame) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in coro chain");
+ return -1;
+ }
+
+ if (PyList_Append(render_to, name)) {
+ Py_DECREF(name);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to coro chain");
+ return -1;
+ }
+ Py_DECREF(name);
+
+ if (frame_state == FRAME_SUSPENDED_YIELD_FROM) {
+ return handle_yield_from_frame(unwinder, gi_iframe_addr, gen_type_addr, render_to);
+ }
+
+ return 0;
+}
+
+static PyObject*
+create_task_result(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t task_address,
+ int recurse_task
+) {
+ PyObject* result = NULL;
+ PyObject *call_stack = NULL;
+ PyObject *tn = NULL;
+ char task_obj[SIZEOF_TASK_OBJ];
+ uintptr_t coro_addr;
+
+ // Create call_stack first since it's the first tuple element
+ call_stack = PyList_New(0);
+ if (call_stack == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create call stack list");
+ goto error;
+ }
+
+ // Create task name/address for second tuple element
+ if (recurse_task) {
+ tn = parse_task_name(unwinder, task_address);
+ } else {
+ tn = PyLong_FromUnsignedLongLong(task_address);
+ }
+ if (tn == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name/address");
+ goto error;
+ }
+
+ // Parse coroutine chain
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address,
+ unwinder->async_debug_offsets.asyncio_task_object.size,
+ task_obj) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object for coro chain");
+ goto error;
+ }
+
+ coro_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_coro);
+
+ if ((void*)coro_addr != NULL) {
+ if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain");
+ goto error;
+ }
+
+ if (PyList_Reverse(call_stack)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reverse call stack");
+ goto error;
+ }
+ }
+
+ // Create final CoroInfo result
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result = PyStructSequence_New(state->CoroInfo_Type);
+ if (result == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create CoroInfo");
+ goto error;
+ }
+
+ // PyStructSequence_SetItem steals references, so we don't need to DECREF on success
+ PyStructSequence_SetItem(result, 0, call_stack); // This steals the reference
+ PyStructSequence_SetItem(result, 1, tn); // This steals the reference
+
+ return result;
+
+error:
+ Py_XDECREF(result);
+ Py_XDECREF(call_stack);
+ Py_XDECREF(tn);
+ return NULL;
+}
+
+static int
+parse_task(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t task_address,
+ PyObject *render_to,
+ int recurse_task
+) {
+ char is_task;
+ PyObject* result = NULL;
+ int err;
+
+ err = read_char(
+ unwinder,
+ task_address + unwinder->async_debug_offsets.asyncio_task_object.task_is_task,
+ &is_task);
+ if (err) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read is_task flag");
+ goto error;
+ }
+
+ if (is_task) {
+ result = create_task_result(unwinder, task_address, recurse_task);
+ if (!result) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task result");
+ goto error;
+ }
+ } else {
+ // Create an empty CoroInfo for non-task objects
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result = PyStructSequence_New(state->CoroInfo_Type);
+ if (result == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty CoroInfo");
+ goto error;
+ }
+ PyObject *empty_list = PyList_New(0);
+ if (empty_list == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty list");
+ goto error;
+ }
+ PyObject *task_name = PyLong_FromUnsignedLongLong(task_address);
+ if (task_name == NULL) {
+ Py_DECREF(empty_list);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name");
+ goto error;
+ }
+ PyStructSequence_SetItem(result, 0, empty_list); // This steals the reference
+ PyStructSequence_SetItem(result, 1, task_name); // This steals the reference
+ }
+
+ if (PyList_Append(render_to, result)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task result to render list");
+ goto error;
+ }
+ Py_DECREF(result);
+ return 0;
+
+error:
+ Py_XDECREF(result);
+ return -1;
+}
+
+static int
+process_set_entry(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t table_ptr,
+ PyObject *awaited_by,
+ int recurse_task
+) {
+ uintptr_t key_addr;
+ if (read_py_ptr(unwinder, table_ptr, &key_addr)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set entry key");
+ return -1;
+ }
+
+ if ((void*)key_addr != NULL) {
+ Py_ssize_t ref_cnt;
+ if (read_Py_ssize_t(unwinder, table_ptr, &ref_cnt)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set entry reference count");
+ return -1;
+ }
+
+ if (ref_cnt) {
+ // if 'ref_cnt=0' it's a set dummy marker
+ if (parse_task(unwinder, key_addr, awaited_by, recurse_task)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task in set entry");
+ return -1;
+ }
+ return 1; // Successfully processed a valid entry
+ }
+ }
+ return 0; // Entry was NULL or dummy marker
+}
+
+static int
+parse_tasks_in_set(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t set_addr,
+ PyObject *awaited_by,
+ int recurse_task
+) {
+ char set_object[SIZEOF_SET_OBJ];
+ int err = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ set_addr,
+ SIZEOF_SET_OBJ,
+ set_object);
+ if (err < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set object");
+ return -1;
+ }
+
+ Py_ssize_t num_els = GET_MEMBER(Py_ssize_t, set_object, unwinder->debug_offsets.set_object.used);
+ Py_ssize_t set_len = GET_MEMBER(Py_ssize_t, set_object, unwinder->debug_offsets.set_object.mask) + 1; // The set contains the `mask+1` element slots.
+ uintptr_t table_ptr = GET_MEMBER(uintptr_t, set_object, unwinder->debug_offsets.set_object.table);
+
+ Py_ssize_t i = 0;
+ Py_ssize_t els = 0;
+ while (i < set_len && els < num_els) {
+ int result = process_set_entry(unwinder, table_ptr, awaited_by, recurse_task);
+
+ if (result < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process set entry");
+ return -1;
+ }
+ if (result > 0) {
+ els++;
+ }
+
+ table_ptr += sizeof(void*) * 2;
+ i++;
+ }
+ return 0;
+}
+
+
+static int
+setup_async_result_structure(RemoteUnwinderObject *unwinder, PyObject **result, PyObject **calls)
+{
+ *result = PyList_New(1);
+ if (*result == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create async result structure");
+ return -1;
+ }
+
+ *calls = PyList_New(0);
+ if (*calls == NULL) {
+ Py_DECREF(*result);
+ *result = NULL;
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create calls list in async result");
+ return -1;
+ }
+
+ if (PyList_SetItem(*result, 0, *calls)) { /* steals ref to 'calls' */
+ Py_DECREF(*calls);
+ Py_DECREF(*result);
+ *result = NULL;
+ *calls = NULL;
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to set calls list in async result");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+add_task_info_to_result(
+ RemoteUnwinderObject *unwinder,
+ PyObject *result,
+ uintptr_t running_task_addr
+) {
+ PyObject *tn = parse_task_name(unwinder, running_task_addr);
+ if (tn == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task name for result");
+ return -1;
+ }
+
+ if (PyList_Append(result, tn)) {
+ Py_DECREF(tn);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task name to result");
+ return -1;
+ }
+ Py_DECREF(tn);
+
+ PyObject* awaited_by = PyList_New(0);
+ if (awaited_by == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by list for result");
+ return -1;
+ }
+
+ if (PyList_Append(result, awaited_by)) {
+ Py_DECREF(awaited_by);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by to result");
+ return -1;
+ }
+ Py_DECREF(awaited_by);
+
+ if (parse_task_awaited_by(
+ unwinder, running_task_addr, awaited_by, 1) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse awaited_by for result");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+process_single_task_node(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t task_addr,
+ PyObject *result
+) {
+ PyObject *tn = NULL;
+ PyObject *current_awaited_by = NULL;
+ PyObject *task_id = NULL;
+ PyObject *result_item = NULL;
+ PyObject *coroutine_stack = NULL;
+
+ tn = parse_task_name(unwinder, task_addr);
+ if (tn == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task name in single task node");
+ goto error;
+ }
+
+ current_awaited_by = PyList_New(0);
+ if (current_awaited_by == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by list in single task node");
+ goto error;
+ }
+
+ // Extract the coroutine stack for this task
+ coroutine_stack = PyList_New(0);
+ if (coroutine_stack == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coroutine stack list in single task node");
+ goto error;
+ }
+
+ if (parse_task(unwinder, task_addr, coroutine_stack, 0) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task coroutine stack in single task node");
+ goto error;
+ }
+
+ task_id = PyLong_FromUnsignedLongLong(task_addr);
+ if (task_id == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task ID in single task node");
+ goto error;
+ }
+
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result_item = PyStructSequence_New(state->TaskInfo_Type);
+ if (result_item == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create TaskInfo in single task node");
+ goto error;
+ }
+
+ PyStructSequence_SetItem(result_item, 0, task_id); // steals ref
+ PyStructSequence_SetItem(result_item, 1, tn); // steals ref
+ PyStructSequence_SetItem(result_item, 2, coroutine_stack); // steals ref
+ PyStructSequence_SetItem(result_item, 3, current_awaited_by); // steals ref
+
+ // References transferred to tuple
+ task_id = NULL;
+ tn = NULL;
+ coroutine_stack = NULL;
+ current_awaited_by = NULL;
+
+ if (PyList_Append(result, result_item)) {
+ Py_DECREF(result_item);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append result item in single task node");
+ return -1;
+ }
+ Py_DECREF(result_item);
+
+ // Get back current_awaited_by reference for parse_task_awaited_by
+ current_awaited_by = PyStructSequence_GetItem(result_item, 3);
+ if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by, 0) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse awaited_by in single task node");
+ // No cleanup needed here since all references were transferred to result_item
+ // and result_item was already added to result list and decreffed
+ return -1;
+ }
+
+ return 0;
+
+error:
+ Py_XDECREF(tn);
+ Py_XDECREF(current_awaited_by);
+ Py_XDECREF(task_id);
+ Py_XDECREF(result_item);
+ Py_XDECREF(coroutine_stack);
+ return -1;
+}
+
+/* ============================================================================
+ * TLBC CACHING FUNCTIONS
+ * ============================================================================ */
+
+#ifdef Py_GIL_DISABLED
+
+typedef struct {
+ void *tlbc_array; // Local copy of the TLBC array
+ Py_ssize_t tlbc_array_size; // Size of the TLBC array
+ uint32_t generation; // Generation when this was cached
+} TLBCCacheEntry;
+
+static void
+tlbc_cache_entry_destroy(void *ptr)
+{
+ TLBCCacheEntry *entry = (TLBCCacheEntry *)ptr;
+ if (entry->tlbc_array) {
+ PyMem_RawFree(entry->tlbc_array);
+ }
+ PyMem_RawFree(entry);
+}
+
+static TLBCCacheEntry *
+get_tlbc_cache_entry(RemoteUnwinderObject *self, uintptr_t code_addr, uint32_t current_generation)
+{
+ void *key = (void *)code_addr;
+ TLBCCacheEntry *entry = _Py_hashtable_get(self->tlbc_cache, key);
+
+ if (entry && entry->generation != current_generation) {
+ // Entry is stale, remove it by setting to NULL
+ _Py_hashtable_set(self->tlbc_cache, key, NULL);
+ entry = NULL;
+ }
+
+ return entry;
+}
+
+static int
+cache_tlbc_array(RemoteUnwinderObject *unwinder, uintptr_t code_addr, uintptr_t tlbc_array_addr, uint32_t generation)
+{
+ uintptr_t tlbc_array_ptr;
+ void *tlbc_array = NULL;
+ TLBCCacheEntry *entry = NULL;
+
+ // Read the TLBC array pointer
+ if (read_ptr(unwinder, tlbc_array_addr, &tlbc_array_ptr) != 0 || tlbc_array_ptr == 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array pointer");
+ return 0; // No TLBC array
+ }
+
+ // Read the TLBC array size
+ Py_ssize_t tlbc_size;
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(tlbc_size), &tlbc_size) != 0 || tlbc_size <= 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array size");
+ return 0; // Invalid size
+ }
+
+ // Allocate and read the entire TLBC array
+ size_t array_data_size = tlbc_size * sizeof(void*);
+ tlbc_array = PyMem_RawMalloc(sizeof(Py_ssize_t) + array_data_size);
+ if (!tlbc_array) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate TLBC array");
+ return 0; // Memory error
+ }
+
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(Py_ssize_t) + array_data_size, tlbc_array) != 0) {
+ PyMem_RawFree(tlbc_array);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array data");
+ return 0; // Read error
+ }
+
+ // Create cache entry
+ entry = PyMem_RawMalloc(sizeof(TLBCCacheEntry));
+ if (!entry) {
+ PyMem_RawFree(tlbc_array);
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate TLBC cache entry");
+ return 0; // Memory error
+ }
+
+ entry->tlbc_array = tlbc_array;
+ entry->tlbc_array_size = tlbc_size;
+ entry->generation = generation;
+
+ // Store in cache
+ void *key = (void *)code_addr;
+ if (_Py_hashtable_set(unwinder->tlbc_cache, key, entry) < 0) {
+ tlbc_cache_entry_destroy(entry);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to store TLBC entry in cache");
+ return 0; // Cache error
+ }
+
+ return 1; // Success
+}
+
+
+
+#endif
+
+/* ============================================================================
+ * LINE TABLE PARSING FUNCTIONS
+ * ============================================================================ */
+
+static int
+scan_varint(const uint8_t **ptr)
+{
+ unsigned int read = **ptr;
+ *ptr = *ptr + 1;
+ unsigned int val = read & 63;
+ unsigned int shift = 0;
+ while (read & 64) {
+ read = **ptr;
+ *ptr = *ptr + 1;
+ shift += 6;
+ val |= (read & 63) << shift;
+ }
+ return val;
+}
+
+static int
+scan_signed_varint(const uint8_t **ptr)
+{
+ unsigned int uval = scan_varint(ptr);
+ if (uval & 1) {
+ return -(int)(uval >> 1);
+ }
+ else {
+ return uval >> 1;
+ }
+}
+
+static bool
+parse_linetable(const uintptr_t addrq, const char* linetable, int firstlineno, LocationInfo* info)
+{
+ const uint8_t* ptr = (const uint8_t*)(linetable);
+ uint64_t addr = 0;
+ info->lineno = firstlineno;
+
+ while (*ptr != '\0') {
+ // See InternalDocs/code_objects.md for where these magic numbers are from
+ // and for the decoding algorithm.
+ uint8_t first_byte = *(ptr++);
+ uint8_t code = (first_byte >> 3) & 15;
+ size_t length = (first_byte & 7) + 1;
+ uintptr_t end_addr = addr + length;
+ switch (code) {
+ case PY_CODE_LOCATION_INFO_NONE: {
+ break;
+ }
+ case PY_CODE_LOCATION_INFO_LONG: {
+ int line_delta = scan_signed_varint(&ptr);
+ info->lineno += line_delta;
+ info->end_lineno = info->lineno + scan_varint(&ptr);
+ info->column = scan_varint(&ptr) - 1;
+ info->end_column = scan_varint(&ptr) - 1;
+ break;
+ }
+ case PY_CODE_LOCATION_INFO_NO_COLUMNS: {
+ int line_delta = scan_signed_varint(&ptr);
+ info->lineno += line_delta;
+ info->column = info->end_column = -1;
+ break;
+ }
+ case PY_CODE_LOCATION_INFO_ONE_LINE0:
+ case PY_CODE_LOCATION_INFO_ONE_LINE1:
+ case PY_CODE_LOCATION_INFO_ONE_LINE2: {
+ int line_delta = code - 10;
+ info->lineno += line_delta;
+ info->end_lineno = info->lineno;
+ info->column = *(ptr++);
+ info->end_column = *(ptr++);
+ break;
+ }
+ default: {
+ uint8_t second_byte = *(ptr++);
+ if ((second_byte & 128) != 0) {
+ return false;
+ }
+ info->column = code << 3 | (second_byte >> 4);
+ info->end_column = info->column + (second_byte & 15);
+ break;
+ }
+ }
+ if (addr <= addrq && end_addr > addrq) {
+ return true;
+ }
+ addr = end_addr;
+ }
+ return false;
+}
+
+/* ============================================================================
+ * CODE OBJECT AND FRAME PARSING FUNCTIONS
+ * ============================================================================ */
+
+static int
+parse_code_object(RemoteUnwinderObject *unwinder,
+ PyObject **result,
+ uintptr_t address,
+ uintptr_t instruction_pointer,
+ uintptr_t *previous_frame,
+ int32_t tlbc_index)
+{
+ void *key = (void *)address;
+ CachedCodeMetadata *meta = NULL;
+ PyObject *func = NULL;
+ PyObject *file = NULL;
+ PyObject *linetable = NULL;
+ PyObject *lineno = NULL;
+ PyObject *tuple = NULL;
+
+#ifdef Py_GIL_DISABLED
+ // In free threading builds, code object addresses might have the low bit set
+ // as a flag, so we need to mask it off to get the real address
+ uintptr_t real_address = address & (~1);
+#else
+ uintptr_t real_address = address;
+#endif
+
+ if (unwinder && unwinder->code_object_cache != NULL) {
+ meta = _Py_hashtable_get(unwinder->code_object_cache, key);
+ }
+
+ if (meta == NULL) {
+ char code_object[SIZEOF_CODE_OBJ];
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle, real_address, SIZEOF_CODE_OBJ, code_object) < 0)
+ {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read code object");
+ goto error;
+ }
+
+ func = read_py_str(unwinder,
+ GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.qualname), 1024);
+ if (!func) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read function name from code object");
+ goto error;
+ }
+
+ file = read_py_str(unwinder,
+ GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.filename), 1024);
+ if (!file) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read filename from code object");
+ goto error;
+ }
+
+ linetable = read_py_bytes(unwinder,
+ GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.linetable), 4096);
+ if (!linetable) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read linetable from code object");
+ goto error;
+ }
+
+ meta = PyMem_RawMalloc(sizeof(CachedCodeMetadata));
+ if (!meta) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate cached code metadata");
+ goto error;
+ }
+
+ meta->func_name = func;
+ meta->file_name = file;
+ meta->linetable = linetable;
+ meta->first_lineno = GET_MEMBER(int, code_object, unwinder->debug_offsets.code_object.firstlineno);
+ meta->addr_code_adaptive = real_address + unwinder->debug_offsets.code_object.co_code_adaptive;
+
+ if (unwinder && unwinder->code_object_cache && _Py_hashtable_set(unwinder->code_object_cache, key, meta) < 0) {
+ cached_code_metadata_destroy(meta);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to cache code metadata");
+ goto error;
+ }
+
+ // Ownership transferred to meta
+ func = NULL;
+ file = NULL;
+ linetable = NULL;
+ }
+
+ uintptr_t ip = instruction_pointer;
+ ptrdiff_t addrq;
+
+#ifdef Py_GIL_DISABLED
+ // Handle thread-local bytecode (TLBC) in free threading builds
+ if (tlbc_index == 0 || unwinder->debug_offsets.code_object.co_tlbc == 0 || unwinder == NULL) {
+ // No TLBC or no unwinder - use main bytecode directly
+ addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive;
+ goto done_tlbc;
+ }
+
+ // Try to get TLBC data from cache (we'll get generation from the caller)
+ TLBCCacheEntry *tlbc_entry = get_tlbc_cache_entry(unwinder, real_address, unwinder->tlbc_generation);
+
+ if (!tlbc_entry) {
+ // Cache miss - try to read and cache TLBC array
+ if (!cache_tlbc_array(unwinder, real_address, real_address + unwinder->debug_offsets.code_object.co_tlbc, unwinder->tlbc_generation)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to cache TLBC array");
+ goto error;
+ }
+ tlbc_entry = get_tlbc_cache_entry(unwinder, real_address, unwinder->tlbc_generation);
+ }
+
+ if (tlbc_entry && tlbc_index < tlbc_entry->tlbc_array_size) {
+ // Use cached TLBC data
+ uintptr_t *entries = (uintptr_t *)((char *)tlbc_entry->tlbc_array + sizeof(Py_ssize_t));
+ uintptr_t tlbc_bytecode_addr = entries[tlbc_index];
+
+ if (tlbc_bytecode_addr != 0) {
+ // Calculate offset from TLBC bytecode
+ addrq = (uint16_t *)ip - (uint16_t *)tlbc_bytecode_addr;
+ goto done_tlbc;
+ }
+ }
+
+ // Fall back to main bytecode
+ addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive;
+
+done_tlbc:
+#else
+ // Non-free-threaded build, always use the main bytecode
+ (void)tlbc_index; // Suppress unused parameter warning
+ (void)unwinder; // Suppress unused parameter warning
+ addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive;
+#endif
+ ; // Empty statement to avoid C23 extension warning
+ LocationInfo info = {0};
+ bool ok = parse_linetable(addrq, PyBytes_AS_STRING(meta->linetable),
+ meta->first_lineno, &info);
+ if (!ok) {
+ info.lineno = -1;
+ }
+
+ lineno = PyLong_FromLong(info.lineno);
+ if (!lineno) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create line number object");
+ goto error;
+ }
+
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ tuple = PyStructSequence_New(state->FrameInfo_Type);
+ if (!tuple) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create FrameInfo for code object");
+ goto error;
+ }
+
+ Py_INCREF(meta->func_name);
+ Py_INCREF(meta->file_name);
+ PyStructSequence_SetItem(tuple, 0, meta->file_name);
+ PyStructSequence_SetItem(tuple, 1, lineno);
+ PyStructSequence_SetItem(tuple, 2, meta->func_name);
+
+ *result = tuple;
+ return 0;
+
+error:
+ Py_XDECREF(func);
+ Py_XDECREF(file);
+ Py_XDECREF(linetable);
+ Py_XDECREF(lineno);
+ Py_XDECREF(tuple);
+ return -1;
+}
+
+/* ============================================================================
+ * STACK CHUNK MANAGEMENT FUNCTIONS
+ * ============================================================================ */
+
+static void
+cleanup_stack_chunks(StackChunkList *chunks)
+{
+ for (size_t i = 0; i < chunks->count; ++i) {
+ PyMem_RawFree(chunks->chunks[i].local_copy);
+ }
+ PyMem_RawFree(chunks->chunks);
+}
+
+static int
+process_single_stack_chunk(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t chunk_addr,
+ StackChunkInfo *chunk_info
+) {
+ // Start with default size assumption
+ size_t current_size = _PY_DATA_STACK_CHUNK_SIZE;
+
+ char *this_chunk = PyMem_RawMalloc(current_size);
+ if (!this_chunk) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate stack chunk buffer");
+ return -1;
+ }
+
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, current_size, this_chunk) < 0) {
+ PyMem_RawFree(this_chunk);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read stack chunk");
+ return -1;
+ }
+
+ // Check actual size and reread if necessary
+ size_t actual_size = GET_MEMBER(size_t, this_chunk, offsetof(_PyStackChunk, size));
+ if (actual_size != current_size) {
+ this_chunk = PyMem_RawRealloc(this_chunk, actual_size);
+ if (!this_chunk) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to reallocate stack chunk buffer");
+ return -1;
+ }
+
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, actual_size, this_chunk) < 0) {
+ PyMem_RawFree(this_chunk);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reread stack chunk with correct size");
+ return -1;
+ }
+ current_size = actual_size;
+ }
+
+ chunk_info->remote_addr = chunk_addr;
+ chunk_info->size = current_size;
+ chunk_info->local_copy = this_chunk;
+ return 0;
+}
+
+static int
+copy_stack_chunks(RemoteUnwinderObject *unwinder,
+ uintptr_t tstate_addr,
+ StackChunkList *out_chunks)
+{
+ uintptr_t chunk_addr;
+ StackChunkInfo *chunks = NULL;
+ size_t count = 0;
+ size_t max_chunks = 16;
+
+ if (read_ptr(unwinder, tstate_addr + unwinder->debug_offsets.thread_state.datastack_chunk, &chunk_addr)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read initial stack chunk address");
+ return -1;
+ }
+
+ chunks = PyMem_RawMalloc(max_chunks * sizeof(StackChunkInfo));
+ if (!chunks) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate stack chunks array");
+ return -1;
+ }
+
+ while (chunk_addr != 0) {
+ // Grow array if needed
+ if (count >= max_chunks) {
+ max_chunks *= 2;
+ StackChunkInfo *new_chunks = PyMem_RawRealloc(chunks, max_chunks * sizeof(StackChunkInfo));
+ if (!new_chunks) {
+ PyErr_NoMemory();
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to grow stack chunks array");
+ goto error;
+ }
+ chunks = new_chunks;
+ }
+
+ // Process this chunk
+ if (process_single_stack_chunk(unwinder, chunk_addr, &chunks[count]) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process stack chunk");
+ goto error;
+ }
+
+ // Get next chunk address and increment count
+ chunk_addr = GET_MEMBER(uintptr_t, chunks[count].local_copy, offsetof(_PyStackChunk, previous));
+ count++;
+ }
+
+ out_chunks->chunks = chunks;
+ out_chunks->count = count;
+ return 0;
+
+error:
+ for (size_t i = 0; i < count; ++i) {
+ PyMem_RawFree(chunks[i].local_copy);
+ }
+ PyMem_RawFree(chunks);
+ return -1;
+}
+
+static void *
+find_frame_in_chunks(StackChunkList *chunks, uintptr_t remote_ptr)
+{
+ for (size_t i = 0; i < chunks->count; ++i) {
+ uintptr_t base = chunks->chunks[i].remote_addr + offsetof(_PyStackChunk, data);
+ size_t payload = chunks->chunks[i].size - offsetof(_PyStackChunk, data);
+
+ if (remote_ptr >= base && remote_ptr < base + payload) {
+ return (char *)chunks->chunks[i].local_copy + (remote_ptr - chunks->chunks[i].remote_addr);
+ }
+ }
+ return NULL;
+}
+
+static int
+parse_frame_from_chunks(
+ RemoteUnwinderObject *unwinder,
+ PyObject **result,
+ uintptr_t address,
+ uintptr_t *previous_frame,
+ StackChunkList *chunks
+) {
+ void *frame_ptr = find_frame_in_chunks(chunks, address);
+ if (!frame_ptr) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Frame not found in stack chunks");
+ return -1;
+ }
+
+ char *frame = (char *)frame_ptr;
+ *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
+ uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame_ptr, unwinder->debug_offsets.interpreter_frame.executable);
+ int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object);
+ if (frame_valid != 1) {
+ return frame_valid;
+ }
+
+ uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr);
+
+ // Get tlbc_index for free threading builds
+ int32_t tlbc_index = 0;
+#ifdef Py_GIL_DISABLED
+ if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) {
+ tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index);
+ }
+#endif
+
+ return parse_code_object(unwinder, result, code_object, instruction_pointer, previous_frame, tlbc_index);
+}
+
+/* ============================================================================
+ * INTERPRETER STATE AND THREAD DISCOVERY FUNCTIONS
+ * ============================================================================ */
+
+static int
+populate_initial_state_data(
+ int all_threads,
+ RemoteUnwinderObject *unwinder,
+ uintptr_t runtime_start_address,
+ uintptr_t *interpreter_state,
+ uintptr_t *tstate
+) {
+ uint64_t interpreter_state_list_head =
+ unwinder->debug_offsets.runtime_state.interpreters_head;
+
+ uintptr_t address_of_interpreter_state;
+ int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ runtime_start_address + interpreter_state_list_head,
+ sizeof(void*),
+ &address_of_interpreter_state);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter state address");
+ return -1;
+ }
+
+ if (address_of_interpreter_state == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state is NULL");
+ return -1;
+ }
+
+ *interpreter_state = address_of_interpreter_state;
+
+ if (all_threads) {
+ *tstate = 0;
+ return 0;
+ }
+
+ uintptr_t address_of_thread = address_of_interpreter_state +
+ unwinder->debug_offsets.interpreter_state.threads_main;
+
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address_of_thread,
+ sizeof(void*),
+ tstate) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read main thread state address");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+find_running_frame(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t runtime_start_address,
+ uintptr_t *frame
+) {
+ uint64_t interpreter_state_list_head =
+ unwinder->debug_offsets.runtime_state.interpreters_head;
+
+ uintptr_t address_of_interpreter_state;
+ int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ runtime_start_address + interpreter_state_list_head,
+ sizeof(void*),
+ &address_of_interpreter_state);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter state for running frame");
+ return -1;
+ }
+
+ if (address_of_interpreter_state == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state is NULL in running frame search");
+ return -1;
+ }
+
+ uintptr_t address_of_thread;
+ bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address_of_interpreter_state +
+ unwinder->debug_offsets.interpreter_state.threads_main,
+ sizeof(void*),
+ &address_of_thread);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread address for running frame");
+ return -1;
+ }
+
+ // No Python frames are available for us (can happen at tear-down).
+ if ((void*)address_of_thread != NULL) {
+ int err = read_ptr(
+ unwinder,
+ address_of_thread + unwinder->debug_offsets.thread_state.current_frame,
+ frame);
+ if (err) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read current frame pointer");
+ return -1;
+ }
+ return 0;
+ }
+
+ *frame = (uintptr_t)NULL;
+ return 0;
+}
+
+static int
+find_running_task(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t *running_task_addr
+) {
+ *running_task_addr = (uintptr_t)NULL;
+
+ uint64_t interpreter_state_list_head =
+ unwinder->debug_offsets.runtime_state.interpreters_head;
+
+ uintptr_t address_of_interpreter_state;
+ int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ unwinder->runtime_start_address + interpreter_state_list_head,
+ sizeof(void*),
+ &address_of_interpreter_state);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter state for running task");
+ return -1;
+ }
+
+ if (address_of_interpreter_state == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state is NULL in running task search");
+ return -1;
+ }
+
+ uintptr_t address_of_thread;
+ bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address_of_interpreter_state +
+ unwinder->debug_offsets.interpreter_state.threads_head,
+ sizeof(void*),
+ &address_of_thread);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread head for running task");
+ return -1;
+ }
+
+ uintptr_t address_of_running_loop;
+ // No Python frames are available for us (can happen at tear-down).
+ if ((void*)address_of_thread == NULL) {
+ return 0;
+ }
+
+ bytes_read = read_py_ptr(
+ unwinder,
+ address_of_thread
+ + unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_loop,
+ &address_of_running_loop);
+ if (bytes_read == -1) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running loop address");
+ return -1;
+ }
+
+ // no asyncio loop is now running
+ if ((void*)address_of_running_loop == NULL) {
+ return 0;
+ }
+
+ int err = read_ptr(
+ unwinder,
+ address_of_thread
+ + unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_task,
+ running_task_addr);
+ if (err) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running task address");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+find_running_task_and_coro(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t *running_task_addr,
+ uintptr_t *running_coro_addr,
+ uintptr_t *running_task_code_obj
+) {
+ *running_task_addr = (uintptr_t)NULL;
+ if (find_running_task(
+ unwinder, running_task_addr) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Running task search failed");
+ return -1;
+ }
+
+ if ((void*)*running_task_addr == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "No running task found");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Running task address is NULL");
+ return -1;
+ }
+
+ if (read_py_ptr(
+ unwinder,
+ *running_task_addr + unwinder->async_debug_offsets.asyncio_task_object.task_coro,
+ running_coro_addr) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro read failed");
+ return -1;
+ }
+
+ if ((void*)*running_coro_addr == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro address is NULL");
+ return -1;
+ }
+
+ // note: genobject's gi_iframe is an embedded struct so the address to
+ // the offset leads directly to its first field: f_executable
+ if (read_py_ptr(
+ unwinder,
+ *running_coro_addr + unwinder->debug_offsets.gen_object.gi_iframe,
+ running_task_code_obj) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running task code object");
+ return -1;
+ }
+
+ if ((void*)*running_task_code_obj == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "Running task code object is NULL");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Running task code object address is NULL");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* ============================================================================
+ * FRAME PARSING FUNCTIONS
+ * ============================================================================ */
+
+static inline int
+is_frame_valid(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t frame_addr,
+ uintptr_t code_object_addr
+) {
+ if ((void*)code_object_addr == NULL) {
+ return 0;
+ }
+
+ void* frame = (void*)frame_addr;
+
+ if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_CSTACK ||
+ GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_INTERPRETER) {
+ return 0; // C frame
+ }
+
+ if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR
+ && GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_THREAD) {
+ PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n",
+ GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner));
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Unhandled frame owner type in async frame");
+ return -1;
+ }
+ return 1;
+}
+
+static int
+parse_frame_object(
+ RemoteUnwinderObject *unwinder,
+ PyObject** result,
+ uintptr_t address,
+ uintptr_t* previous_frame
+) {
+ char frame[SIZEOF_INTERP_FRAME];
+
+ Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address,
+ SIZEOF_INTERP_FRAME,
+ frame
+ );
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame");
+ return -1;
+ }
+
+ *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
+ uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable);
+ int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object);
+ if (frame_valid != 1) {
+ return frame_valid;
+ }
+
+ uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr);
+
+ // Get tlbc_index for free threading builds
+ int32_t tlbc_index = 0;
+#ifdef Py_GIL_DISABLED
+ if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) {
+ tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index);
+ }
+#endif
+
+ return parse_code_object(unwinder, result, code_object,instruction_pointer, previous_frame, tlbc_index);
+}
+
+static int
+parse_async_frame_object(
+ RemoteUnwinderObject *unwinder,
+ PyObject** result,
+ uintptr_t address,
+ uintptr_t* previous_frame,
+ uintptr_t* code_object
+) {
+ char frame[SIZEOF_INTERP_FRAME];
+
+ Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ address,
+ SIZEOF_INTERP_FRAME,
+ frame
+ );
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read async frame");
+ return -1;
+ }
+
+ *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
+ *code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable);
+ int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, *code_object);
+ if (frame_valid != 1) {
+ return frame_valid;
+ }
+
+ uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr);
+
+ // Get tlbc_index for free threading builds
+ int32_t tlbc_index = 0;
+#ifdef Py_GIL_DISABLED
+ if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) {
+ tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index);
+ }
+#endif
+
+ if (parse_code_object(
+ unwinder, result, *code_object, instruction_pointer, previous_frame, tlbc_index)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse code object in async frame");
+ return -1;
+ }
+
+ return 1;
+}
+
+static int
+parse_async_frame_chain(
+ RemoteUnwinderObject *unwinder,
+ PyObject *calls,
+ uintptr_t running_task_code_obj
+) {
+ uintptr_t address_of_current_frame;
+ if (find_running_frame(unwinder, unwinder->runtime_start_address, &address_of_current_frame) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Running frame search failed in async chain");
+ return -1;
+ }
+
+ uintptr_t address_of_code_object;
+ while ((void*)address_of_current_frame != NULL) {
+ PyObject* frame_info = NULL;
+ int res = parse_async_frame_object(
+ unwinder,
+ &frame_info,
+ address_of_current_frame,
+ &address_of_current_frame,
+ &address_of_code_object
+ );
+
+ if (res < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Async frame object parsing failed in chain");
+ return -1;
+ }
+
+ if (!frame_info) {
+ continue;
+ }
+
+ if (PyList_Append(calls, frame_info) == -1) {
+ Py_DECREF(frame_info);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame info to async chain");
+ return -1;
+ }
+
+ Py_DECREF(frame_info);
+
+ if (address_of_code_object == running_task_code_obj) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* ============================================================================
+ * AWAITED BY PARSING FUNCTIONS
+ * ============================================================================ */
+
+static int
+append_awaited_by_for_thread(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t head_addr,
+ PyObject *result
+) {
+ char task_node[SIZEOF_LLIST_NODE];
+
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, head_addr,
+ sizeof(task_node), task_node) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task node head");
+ return -1;
+ }
+
+ size_t iteration_count = 0;
+ const size_t MAX_ITERATIONS = 2 << 15; // A reasonable upper bound
+
+ while (GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) != head_addr) {
+ if (++iteration_count > MAX_ITERATIONS) {
+ PyErr_SetString(PyExc_RuntimeError, "Task list appears corrupted");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Task list iteration limit exceeded");
+ return -1;
+ }
+
+ if (GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) == 0) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Invalid linked list structure reading remote memory");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "NULL pointer in task linked list");
+ return -1;
+ }
+
+ uintptr_t task_addr = (uintptr_t)GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next)
+ - unwinder->async_debug_offsets.asyncio_task_object.task_node;
+
+ if (process_single_task_node(unwinder, task_addr, result) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process task node in awaited_by");
+ return -1;
+ }
+
+ // Read next node
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle,
+ (uintptr_t)GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next),
+ sizeof(task_node),
+ task_node) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read next task node in awaited_by");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+append_awaited_by(
+ RemoteUnwinderObject *unwinder,
+ unsigned long tid,
+ uintptr_t head_addr,
+ PyObject *result)
+{
+ PyObject *tid_py = PyLong_FromUnsignedLong(tid);
+ if (tid_py == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID object");
+ return -1;
+ }
+
+ PyObject* awaited_by_for_thread = PyList_New(0);
+ if (awaited_by_for_thread == NULL) {
+ Py_DECREF(tid_py);
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by thread list");
+ return -1;
+ }
+
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ PyObject *result_item = PyStructSequence_New(state->AwaitedInfo_Type);
+ if (result_item == NULL) {
+ Py_DECREF(tid_py);
+ Py_DECREF(awaited_by_for_thread);
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo");
+ return -1;
+ }
+
+ PyStructSequence_SetItem(result_item, 0, tid_py); // steals ref
+ PyStructSequence_SetItem(result_item, 1, awaited_by_for_thread); // steals ref
+ if (PyList_Append(result, result_item)) {
+ Py_DECREF(result_item);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by result item");
+ return -1;
+ }
+ Py_DECREF(result_item);
+
+ if (append_awaited_by_for_thread(unwinder, head_addr, awaited_by_for_thread))
+ {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by for thread");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* ============================================================================
+ * STACK UNWINDING FUNCTIONS
+ * ============================================================================ */
+
+static int
+process_frame_chain(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t initial_frame_addr,
+ StackChunkList *chunks,
+ PyObject *frame_info
+) {
+ uintptr_t frame_addr = initial_frame_addr;
+ uintptr_t prev_frame_addr = 0;
+ const size_t MAX_FRAMES = 1024;
+ size_t frame_count = 0;
+
+ while ((void*)frame_addr != NULL) {
+ PyObject *frame = NULL;
+ uintptr_t next_frame_addr = 0;
+
+ if (++frame_count > MAX_FRAMES) {
+ PyErr_SetString(PyExc_RuntimeError, "Too many stack frames (possible infinite loop)");
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Frame chain iteration limit exceeded");
+ return -1;
+ }
+
+ // Try chunks first, fallback to direct memory read
+ if (parse_frame_from_chunks(unwinder, &frame, frame_addr, &next_frame_addr, chunks) < 0) {
+ PyErr_Clear();
+ if (parse_frame_object(unwinder, &frame, frame_addr, &next_frame_addr) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in chain");
+ return -1;
+ }
+ }
+
+ if (!frame) {
+ break;
+ }
+
+ if (prev_frame_addr && frame_addr != prev_frame_addr) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Broken frame chain: expected frame at 0x%lx, got 0x%lx",
+ prev_frame_addr, frame_addr);
+ Py_DECREF(frame);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Frame chain consistency check failed");
+ return -1;
+ }
+
+ if (PyList_Append(frame_info, frame) == -1) {
+ Py_DECREF(frame);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to frame info list");
+ return -1;
+ }
+ Py_DECREF(frame);
+
+ prev_frame_addr = next_frame_addr;
+ frame_addr = next_frame_addr;
+ }
+
+ return 0;
+}
+
+static PyObject*
+unwind_stack_for_thread(
+ RemoteUnwinderObject *unwinder,
+ uintptr_t *current_tstate
+) {
+ PyObject *frame_info = NULL;
+ PyObject *thread_id = NULL;
+ PyObject *result = NULL;
+ StackChunkList chunks = {0};
+
+ char ts[SIZEOF_THREAD_STATE];
+ int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
+ &unwinder->handle, *current_tstate, unwinder->debug_offsets.thread_state.size, ts);
+ if (bytes_read < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread state");
+ goto error;
+ }
+
+ uintptr_t frame_addr = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.current_frame);
+
+ frame_info = PyList_New(0);
+ if (!frame_info) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create frame info list");
+ goto error;
+ }
+
+ if (copy_stack_chunks(unwinder, *current_tstate, &chunks) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to copy stack chunks");
+ goto error;
+ }
+
+ if (process_frame_chain(unwinder, frame_addr, &chunks, frame_info) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process frame chain");
+ goto error;
+ }
+
+ *current_tstate = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.next);
+
+ thread_id = PyLong_FromLongLong(
+ GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.native_thread_id));
+ if (thread_id == NULL) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID");
+ goto error;
+ }
+
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result = PyStructSequence_New(state->ThreadInfo_Type);
+ if (result == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create ThreadInfo");
+ goto error;
+ }
+
+ PyStructSequence_SetItem(result, 0, thread_id); // Steals reference
+ PyStructSequence_SetItem(result, 1, frame_info); // Steals reference
+
+ cleanup_stack_chunks(&chunks);
+ return result;
+
+error:
+ Py_XDECREF(frame_info);
+ Py_XDECREF(thread_id);
+ Py_XDECREF(result);
+ cleanup_stack_chunks(&chunks);
+ return NULL;
+}
+
+
+/* ============================================================================
+ * REMOTEUNWINDER CLASS IMPLEMENTATION
+ * ============================================================================ */
+
+/*[clinic input]
+class _remote_debugging.RemoteUnwinder "RemoteUnwinderObject *" "&RemoteUnwinder_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=55f164d8803318be]*/
+
+/*[clinic input]
+_remote_debugging.RemoteUnwinder.__init__
+ pid: int
+ *
+ all_threads: bool = False
+ only_active_thread: bool = False
+ debug: bool = False
+
+Initialize a new RemoteUnwinder object for debugging a remote Python process.
+
+Args:
+ pid: Process ID of the target Python process to debug
+ all_threads: If True, initialize state for all threads in the process.
+ If False, only initialize for the main thread.
+ only_active_thread: If True, only sample the thread holding the GIL.
+ Cannot be used together with all_threads=True.
+ debug: If True, chain exceptions to explain the sequence of events that
+ lead to the exception.
+
+The RemoteUnwinder provides functionality to inspect and debug a running Python
+process, including examining thread states, stack frames and other runtime data.
+
+Raises:
+ PermissionError: If access to the target process is denied
+ OSError: If unable to attach to the target process or access its memory
+ RuntimeError: If unable to read debug information from the target process
+ ValueError: If both all_threads and only_active_thread are True
+[clinic start generated code]*/
+
+static int
+_remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self,
+ int pid, int all_threads,
+ int only_active_thread,
+ int debug)
+/*[clinic end generated code: output=13ba77598ecdcbe1 input=8f8f12504e17da04]*/
+{
+ // Validate that all_threads and only_active_thread are not both True
+ if (all_threads && only_active_thread) {
+ PyErr_SetString(PyExc_ValueError,
+ "all_threads and only_active_thread cannot both be True");
+ return -1;
+ }
+
+#ifdef Py_GIL_DISABLED
+ if (only_active_thread) {
+ PyErr_SetString(PyExc_ValueError,
+ "only_active_thread is not supported when Py_GIL_DISABLED is not defined");
+ return -1;
+ }
+#endif
+
+ self->debug = debug;
+ self->only_active_thread = only_active_thread;
+ self->cached_state = NULL;
+ if (_Py_RemoteDebug_InitProcHandle(&self->handle, pid) < 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to initialize process handle");
+ return -1;
+ }
+
+ self->runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(&self->handle);
+ if (self->runtime_start_address == 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to get Python runtime address");
+ return -1;
+ }
+
+ if (_Py_RemoteDebug_ReadDebugOffsets(&self->handle,
+ &self->runtime_start_address,
+ &self->debug_offsets) < 0)
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to read debug offsets");
+ return -1;
+ }
+
+ // Validate that the debug offsets are valid
+ if(validate_debug_offsets(&self->debug_offsets) == -1) {
+ set_exception_cause(self, PyExc_RuntimeError, "Invalid debug offsets found");
+ return -1;
+ }
+
+ // Try to read async debug offsets, but don't fail if they're not available
+ self->async_debug_offsets_available = 1;
+ if (read_async_debug(self) < 0) {
+ PyErr_Clear();
+ memset(&self->async_debug_offsets, 0, sizeof(self->async_debug_offsets));
+ self->async_debug_offsets_available = 0;
+ }
+
+ if (populate_initial_state_data(all_threads, self, self->runtime_start_address,
+ &self->interpreter_addr ,&self->tstate_addr) < 0)
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to populate initial state data");
+ return -1;
+ }
+
+ self->code_object_cache = _Py_hashtable_new_full(
+ _Py_hashtable_hash_ptr,
+ _Py_hashtable_compare_direct,
+ NULL, // keys are stable pointers, don't destroy
+ cached_code_metadata_destroy,
+ NULL
+ );
+ if (self->code_object_cache == NULL) {
+ PyErr_NoMemory();
+ set_exception_cause(self, PyExc_MemoryError, "Failed to create code object cache");
+ return -1;
+ }
+
+#ifdef Py_GIL_DISABLED
+ // Initialize TLBC cache
+ self->tlbc_generation = 0;
+ self->tlbc_cache = _Py_hashtable_new_full(
+ _Py_hashtable_hash_ptr,
+ _Py_hashtable_compare_direct,
+ NULL, // keys are stable pointers, don't destroy
+ tlbc_cache_entry_destroy,
+ NULL
+ );
+ if (self->tlbc_cache == NULL) {
+ _Py_hashtable_destroy(self->code_object_cache);
+ PyErr_NoMemory();
+ set_exception_cause(self, PyExc_MemoryError, "Failed to create TLBC cache");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+/*[clinic input]
+@critical_section
+_remote_debugging.RemoteUnwinder.get_stack_trace
+
+Returns a list of stack traces for threads in the target process.
+
+Each element in the returned list is a tuple of (thread_id, frame_list), where:
+- thread_id is the OS thread identifier
+- frame_list is a list of tuples (function_name, filename, line_number) representing
+ the Python stack frames for that thread, ordered from most recent to oldest
+
+The threads returned depend on the initialization parameters:
+- If only_active_thread was True: returns only the thread holding the GIL
+- If all_threads was True: returns all threads
+- Otherwise: returns only the main thread
+
+Example:
+ [
+ (1234, [
+ ('process_data', 'worker.py', 127),
+ ('run_worker', 'worker.py', 45),
+ ('main', 'app.py', 23)
+ ]),
+ (1235, [
+ ('handle_request', 'server.py', 89),
+ ('serve_forever', 'server.py', 52)
+ ])
+ ]
+
+Raises:
+ RuntimeError: If there is an error copying memory from the target process
+ OSError: If there is an error accessing the target process
+ PermissionError: If access to the target process is denied
+ UnicodeDecodeError: If there is an error decoding strings from the target process
+
+[clinic start generated code]*/
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self)
+/*[clinic end generated code: output=666192b90c69d567 input=f756f341206f9116]*/
+{
+ PyObject* result = NULL;
+ // Read interpreter state into opaque buffer
+ char interp_state_buffer[INTERP_STATE_BUFFER_SIZE];
+ if (_Py_RemoteDebug_PagedReadRemoteMemory(
+ &self->handle,
+ self->interpreter_addr,
+ INTERP_STATE_BUFFER_SIZE,
+ interp_state_buffer) < 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to read interpreter state buffer");
+ goto exit;
+ }
+
+ // Get code object generation from buffer
+ uint64_t code_object_generation = GET_MEMBER(uint64_t, interp_state_buffer,
+ self->debug_offsets.interpreter_state.code_object_generation);
+
+ if (code_object_generation != self->code_object_generation) {
+ self->code_object_generation = code_object_generation;
+ _Py_hashtable_clear(self->code_object_cache);
+ }
+
+ // If only_active_thread is true, we need to determine which thread holds the GIL
+ PyThreadState* gil_holder = NULL;
+ if (self->only_active_thread) {
+ // The GIL state is already in interp_state_buffer, just read from there
+ // Check if GIL is locked
+ int gil_locked = GET_MEMBER(int, interp_state_buffer,
+ self->debug_offsets.interpreter_state.gil_runtime_state_locked);
+
+ if (gil_locked) {
+ // Get the last holder (current holder when GIL is locked)
+ gil_holder = GET_MEMBER(PyThreadState*, interp_state_buffer,
+ self->debug_offsets.interpreter_state.gil_runtime_state_holder);
+ } else {
+ // GIL is not locked, return empty list
+ result = PyList_New(0);
+ if (!result) {
+ set_exception_cause(self, PyExc_MemoryError, "Failed to create empty result list");
+ }
+ goto exit;
+ }
+ }
+
+#ifdef Py_GIL_DISABLED
+ // Check TLBC generation and invalidate cache if needed
+ uint32_t current_tlbc_generation = GET_MEMBER(uint32_t, interp_state_buffer,
+ self->debug_offsets.interpreter_state.tlbc_generation);
+ if (current_tlbc_generation != self->tlbc_generation) {
+ self->tlbc_generation = current_tlbc_generation;
+ _Py_hashtable_clear(self->tlbc_cache);
+ }
+#endif
+
+ uintptr_t current_tstate;
+ if (self->only_active_thread && gil_holder != NULL) {
+ // We have the GIL holder, process only that thread
+ current_tstate = (uintptr_t)gil_holder;
+ } else if (self->tstate_addr == 0) {
+ // Get threads head from buffer
+ current_tstate = GET_MEMBER(uintptr_t, interp_state_buffer,
+ self->debug_offsets.interpreter_state.threads_head);
+ } else {
+ current_tstate = self->tstate_addr;
+ }
+
+ result = PyList_New(0);
+ if (!result) {
+ set_exception_cause(self, PyExc_MemoryError, "Failed to create stack trace result list");
+ goto exit;
+ }
+
+ while (current_tstate != 0) {
+ PyObject* frame_info = unwind_stack_for_thread(self, &current_tstate);
+ if (!frame_info) {
+ Py_CLEAR(result);
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to unwind stack for thread");
+ goto exit;
+ }
+
+ if (PyList_Append(result, frame_info) == -1) {
+ Py_DECREF(frame_info);
+ Py_CLEAR(result);
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to append thread frame info");
+ goto exit;
+ }
+ Py_DECREF(frame_info);
+
+ // We are targeting a single tstate, break here
+ if (self->tstate_addr) {
+ break;
+ }
+
+ // If we're only processing the GIL holder, we're done after one iteration
+ if (self->only_active_thread && gil_holder != NULL) {
+ break;
+ }
+ }
+
+exit:
+ return result;
+}
+
+/*[clinic input]
+@critical_section
+_remote_debugging.RemoteUnwinder.get_all_awaited_by
+
+Get all tasks and their awaited_by relationships from the remote process.
+
+This provides a tree structure showing which tasks are waiting for other tasks.
+
+For each task, returns:
+1. The call stack frames leading to where the task is currently executing
+2. The name of the task
+3. A list of tasks that this task is waiting for, with their own frames/names/etc
+
+Returns a list of [frames, task_name, subtasks] where:
+- frames: List of (func_name, filename, lineno) showing the call stack
+- task_name: String identifier for the task
+- subtasks: List of tasks being awaited by this task, in same format
+
+Raises:
+ RuntimeError: If AsyncioDebug section is not available in the remote process
+ MemoryError: If memory allocation fails
+ OSError: If reading from the remote process fails
+
+Example output:
+[
+ # Task c2_root waiting for two subtasks
+ [
+ # Call stack of c2_root
+ [("c5", "script.py", 10), ("c4", "script.py", 14)],
+ "c2_root",
+ [
+ # First subtask (sub_main_2) and what it's waiting for
+ [
+ [("c1", "script.py", 23)],
+ "sub_main_2",
+ [...]
+ ],
+ # Second subtask and its waiters
+ [...]
+ ]
+ ]
+]
+[clinic start generated code]*/
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *self)
+/*[clinic end generated code: output=6a49cd345e8aec53 input=a452c652bb00701a]*/
+{
+ if (!self->async_debug_offsets_available) {
+ PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available");
+ set_exception_cause(self, PyExc_RuntimeError, "AsyncioDebug section unavailable in get_all_awaited_by");
+ return NULL;
+ }
+
+ PyObject *result = PyList_New(0);
+ if (result == NULL) {
+ set_exception_cause(self, PyExc_MemoryError, "Failed to create awaited_by result list");
+ goto result_err;
+ }
+
+ uintptr_t thread_state_addr;
+ unsigned long tid = 0;
+ if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
+ &self->handle,
+ self->interpreter_addr
+ + self->debug_offsets.interpreter_state.threads_main,
+ sizeof(void*),
+ &thread_state_addr))
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to read main thread state in get_all_awaited_by");
+ goto result_err;
+ }
+
+ uintptr_t head_addr;
+ while (thread_state_addr != 0) {
+ if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
+ &self->handle,
+ thread_state_addr
+ + self->debug_offsets.thread_state.native_thread_id,
+ sizeof(tid),
+ &tid))
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to read thread ID in get_all_awaited_by");
+ goto result_err;
+ }
+
+ head_addr = thread_state_addr
+ + self->async_debug_offsets.asyncio_thread_state.asyncio_tasks_head;
+
+ if (append_awaited_by(self, tid, head_addr, result))
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to append awaited_by for thread in get_all_awaited_by");
+ goto result_err;
+ }
+
+ if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
+ &self->handle,
+ thread_state_addr + self->debug_offsets.thread_state.next,
+ sizeof(void*),
+ &thread_state_addr))
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to read next thread state in get_all_awaited_by");
+ goto result_err;
+ }
+ }
+
+ head_addr = self->interpreter_addr
+ + self->async_debug_offsets.asyncio_interpreter_state.asyncio_tasks_head;
+
+ // On top of a per-thread task lists used by default by asyncio to avoid
+ // contention, there is also a fallback per-interpreter list of tasks;
+ // any tasks still pending when a thread is destroyed will be moved to the
+ // per-interpreter task list. It's unlikely we'll find anything here, but
+ // interesting for debugging.
+ if (append_awaited_by(self, 0, head_addr, result))
+ {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to append interpreter awaited_by in get_all_awaited_by");
+ goto result_err;
+ }
+
+ return result;
+
+result_err:
+ Py_XDECREF(result);
+ return NULL;
+}
+
+/*[clinic input]
+@critical_section
+_remote_debugging.RemoteUnwinder.get_async_stack_trace
+
+Returns information about the currently running async task and its stack trace.
+
+Returns a tuple of (task_info, stack_frames) where:
+- task_info is a tuple of (task_id, task_name) identifying the task
+- stack_frames is a list of tuples (function_name, filename, line_number) representing
+ the Python stack frames for the task, ordered from most recent to oldest
+
+Example:
+ ((4345585712, 'Task-1'), [
+ ('run_echo_server', 'server.py', 127),
+ ('serve_forever', 'server.py', 45),
+ ('main', 'app.py', 23)
+ ])
+
+Raises:
+ RuntimeError: If AsyncioDebug section is not available in the target process
+ RuntimeError: If there is an error copying memory from the target process
+ OSError: If there is an error accessing the target process
+ PermissionError: If access to the target process is denied
+ UnicodeDecodeError: If there is an error decoding strings from the target process
+
+[clinic start generated code]*/
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject *self)
+/*[clinic end generated code: output=6433d52b55e87bbe input=11b7150c59d4c60f]*/
+{
+ if (!self->async_debug_offsets_available) {
+ PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available");
+ set_exception_cause(self, PyExc_RuntimeError, "AsyncioDebug section unavailable in get_async_stack_trace");
+ return NULL;
+ }
+
+ PyObject *result = NULL;
+ PyObject *calls = NULL;
+
+ if (setup_async_result_structure(self, &result, &calls) < 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to setup async result structure");
+ goto cleanup;
+ }
+
+ uintptr_t running_task_addr, running_coro_addr, running_task_code_obj;
+ if (find_running_task_and_coro(self, &running_task_addr,
+ &running_coro_addr, &running_task_code_obj) < 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to find running task and coro");
+ goto cleanup;
+ }
+
+ if (parse_async_frame_chain(self, calls, running_task_code_obj) < 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to parse async frame chain");
+ goto cleanup;
+ }
+
+ if (add_task_info_to_result(self, result, running_task_addr) < 0) {
+ set_exception_cause(self, PyExc_RuntimeError, "Failed to add task info to result");
+ goto cleanup;
+ }
+
+ return result;
+
+cleanup:
+ Py_XDECREF(result);
+ return NULL;
+}
+
+static PyMethodDef RemoteUnwinder_methods[] = {
+ _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STACK_TRACE_METHODDEF
+ _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ALL_AWAITED_BY_METHODDEF
+ _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ASYNC_STACK_TRACE_METHODDEF
+ {NULL, NULL}
+};
+
+static void
+RemoteUnwinder_dealloc(PyObject *op)
+{
+ RemoteUnwinderObject *self = RemoteUnwinder_CAST(op);
+ PyTypeObject *tp = Py_TYPE(self);
+ if (self->code_object_cache) {
+ _Py_hashtable_destroy(self->code_object_cache);
+ }
+#ifdef Py_GIL_DISABLED
+ if (self->tlbc_cache) {
+ _Py_hashtable_destroy(self->tlbc_cache);
+ }
+#endif
+ if (self->handle.pid != 0) {
+ _Py_RemoteDebug_CleanupProcHandle(&self->handle);
+ }
+ PyObject_Del(self);
+ Py_DECREF(tp);
+}
+
+static PyType_Slot RemoteUnwinder_slots[] = {
+ {Py_tp_doc, (void *)"RemoteUnwinder(pid): Inspect stack of a remote Python process."},
+ {Py_tp_methods, RemoteUnwinder_methods},
+ {Py_tp_init, _remote_debugging_RemoteUnwinder___init__},
+ {Py_tp_dealloc, RemoteUnwinder_dealloc},
+ {0, NULL}
+};
+
+static PyType_Spec RemoteUnwinder_spec = {
+ .name = "_remote_debugging.RemoteUnwinder",
+ .basicsize = sizeof(RemoteUnwinderObject),
+ .flags = Py_TPFLAGS_DEFAULT,
+ .slots = RemoteUnwinder_slots,
+};
+
+/* ============================================================================
+ * MODULE INITIALIZATION
+ * ============================================================================ */
+
+static int
+_remote_debugging_exec(PyObject *m)
+{
+ RemoteDebuggingState *st = RemoteDebugging_GetState(m);
+#define CREATE_TYPE(mod, type, spec) \
+ do { \
+ type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \
+ if (type == NULL) { \
+ return -1; \
+ } \
+ } while (0)
+
+ CREATE_TYPE(m, st->RemoteDebugging_Type, &RemoteUnwinder_spec);
+
+ if (PyModule_AddType(m, st->RemoteDebugging_Type) < 0) {
+ return -1;
+ }
+
+ // Initialize structseq types
+ st->TaskInfo_Type = PyStructSequence_NewType(&TaskInfo_desc);
+ if (st->TaskInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->TaskInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->FrameInfo_Type = PyStructSequence_NewType(&FrameInfo_desc);
+ if (st->FrameInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->FrameInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->CoroInfo_Type = PyStructSequence_NewType(&CoroInfo_desc);
+ if (st->CoroInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->CoroInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->ThreadInfo_Type = PyStructSequence_NewType(&ThreadInfo_desc);
+ if (st->ThreadInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->ThreadInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->AwaitedInfo_Type = PyStructSequence_NewType(&AwaitedInfo_desc);
+ if (st->AwaitedInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->AwaitedInfo_Type) < 0) {
+ return -1;
+ }
+#ifdef Py_GIL_DISABLED
+ PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
+#endif
+ int rc = PyModule_AddIntConstant(m, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV);
+ if (rc < 0) {
+ return -1;
+ }
+ if (RemoteDebugging_InitState(st) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static int
+remote_debugging_traverse(PyObject *mod, visitproc visit, void *arg)
+{
+ RemoteDebuggingState *state = RemoteDebugging_GetState(mod);
+ Py_VISIT(state->RemoteDebugging_Type);
+ Py_VISIT(state->TaskInfo_Type);
+ Py_VISIT(state->FrameInfo_Type);
+ Py_VISIT(state->CoroInfo_Type);
+ Py_VISIT(state->ThreadInfo_Type);
+ Py_VISIT(state->AwaitedInfo_Type);
+ return 0;
+}
+
+static int
+remote_debugging_clear(PyObject *mod)
+{
+ RemoteDebuggingState *state = RemoteDebugging_GetState(mod);
+ Py_CLEAR(state->RemoteDebugging_Type);
+ Py_CLEAR(state->TaskInfo_Type);
+ Py_CLEAR(state->FrameInfo_Type);
+ Py_CLEAR(state->CoroInfo_Type);
+ Py_CLEAR(state->ThreadInfo_Type);
+ Py_CLEAR(state->AwaitedInfo_Type);
+ return 0;
+}
+
+static void
+remote_debugging_free(void *mod)
+{
+ (void)remote_debugging_clear((PyObject *)mod);
+}
+
+static PyModuleDef_Slot remote_debugging_slots[] = {
+ {Py_mod_exec, _remote_debugging_exec},
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
+ {0, NULL},
+};
+
+static PyMethodDef remote_debugging_methods[] = {
+ {NULL, NULL, 0, NULL},
+};
+
+static struct PyModuleDef remote_debugging_module = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_remote_debugging",
+ .m_size = sizeof(RemoteDebuggingState),
+ .m_methods = remote_debugging_methods,
+ .m_slots = remote_debugging_slots,
+ .m_traverse = remote_debugging_traverse,
+ .m_clear = remote_debugging_clear,
+ .m_free = remote_debugging_free,
+};
+
+PyMODINIT_FUNC
+PyInit__remote_debugging(void)
+{
+ return PyModuleDef_Init(&remote_debugging_module);
+}
diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c
index 35d090e3ca2..aafefbf316e 100644
--- a/Modules/_sqlite/blob.c
+++ b/Modules/_sqlite/blob.c
@@ -4,6 +4,7 @@
#include "blob.h"
#include "util.h"
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
#include "clinic/blob.c.h"
@@ -56,9 +57,7 @@ blob_dealloc(PyObject *op)
close_blob(self);
- if (self->in_weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->in_weakreflist);
(void)tp->tp_clear(op);
tp->tp_free(self);
Py_DECREF(tp);
diff --git a/Modules/_sqlite/clinic/_sqlite3.connect.c.h b/Modules/_sqlite/clinic/_sqlite3.connect.c.h
index 1bcda7702c2..e9d560666c1 100644
--- a/Modules/_sqlite/clinic/_sqlite3.connect.c.h
+++ b/Modules/_sqlite/clinic/_sqlite3.connect.c.h
@@ -9,23 +9,17 @@ preserve
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(pysqlite_connect__doc__,
-"connect($module, /, database, timeout=5.0, detect_types=0,\n"
+"connect($module, /, database, *, timeout=5.0, detect_types=0,\n"
" isolation_level=\'\', check_same_thread=True,\n"
-" factory=ConnectionType, cached_statements=128, uri=False, *,\n"
+" factory=ConnectionType, cached_statements=128, uri=False,\n"
" autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL)\n"
"--\n"
"\n"
"Open a connection to the SQLite database file \'database\'.\n"
"\n"
"You can use \":memory:\" to open a database connection to a database that\n"
-"resides in RAM instead of on disk.\n"
-"\n"
-"Note: Passing more than 1 positional argument to _sqlite3.connect() is\n"
-"deprecated. Parameters \'timeout\', \'detect_types\', \'isolation_level\',\n"
-"\'check_same_thread\', \'factory\', \'cached_statements\' and \'uri\' will\n"
-"become keyword-only parameters in Python 3.15.\n"
-"");
+"resides in RAM instead of on disk.");
#define PYSQLITE_CONNECT_METHODDEF \
{"connect", _PyCFunction_CAST(pysqlite_connect), METH_FASTCALL|METH_KEYWORDS, pysqlite_connect__doc__},
-/*[clinic end generated code: output=69b9b00da71c3c0a input=a9049054013a1b77]*/
+/*[clinic end generated code: output=3d83139ba65e0bb5 input=a9049054013a1b77]*/
diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h
index c8e1d0b7a73..f0e9fdb8894 100644
--- a/Modules/_sqlite/clinic/connection.c.h
+++ b/Modules/_sqlite/clinic/connection.c.h
@@ -16,17 +16,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
int cache_size, int uri,
enum autocommit_mode autocommit);
-// Emit compiler warnings when we get to Python 3.15.
-#if PY_VERSION_HEX >= 0x030f00C0
-# error "Update the clinic input of '_sqlite3.Connection.__init__'."
-#elif PY_VERSION_HEX >= 0x030f00A0
-# ifdef _MSC_VER
-# pragma message ("Update the clinic input of '_sqlite3.Connection.__init__'.")
-# else
-# warning "Update the clinic input of '_sqlite3.Connection.__init__'."
-# endif
-#endif
-
static int
pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
{
@@ -72,25 +61,14 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
int uri = 0;
enum autocommit_mode autocommit = LEGACY_TRANSACTION_CONTROL;
- if (nargs > 1 && nargs <= 8) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing more than 1 positional argument to _sqlite3.Connection()"
- " is deprecated. Parameters 'timeout', 'detect_types', "
- "'isolation_level', 'check_same_thread', 'factory', "
- "'cached_statements' and 'uri' will become keyword-only "
- "parameters in Python 3.15.", 1))
- {
- goto exit;
- }
- }
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
- /*minpos*/ 1, /*maxpos*/ 8, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!fastargs) {
goto exit;
}
database = fastargs[0];
if (!noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
if (fastargs[1]) {
if (PyFloat_CheckExact(fastargs[1])) {
@@ -104,7 +82,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
}
}
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
if (fastargs[2]) {
@@ -113,7 +91,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
if (fastargs[3]) {
@@ -121,7 +99,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
if (fastargs[4]) {
@@ -130,13 +108,13 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
if (fastargs[5]) {
factory = fastargs[5];
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
if (fastargs[6]) {
@@ -145,7 +123,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
if (fastargs[7]) {
@@ -154,13 +132,9 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
if (!--noptargs) {
- goto skip_optional_pos;
+ goto skip_optional_kwonly;
}
}
-skip_optional_pos:
- if (!noptargs) {
- goto skip_optional_kwonly;
- }
if (!autocommit_converter(fastargs[8], &autocommit)) {
goto exit;
}
@@ -424,15 +398,10 @@ pysqlite_connection_rollback(PyObject *self, PyObject *Py_UNUSED(ignored))
}
PyDoc_STRVAR(pysqlite_connection_create_function__doc__,
-"create_function($self, /, name, narg, func, *, deterministic=False)\n"
+"create_function($self, name, narg, func, /, *, deterministic=False)\n"
"--\n"
"\n"
-"Creates a new function.\n"
-"\n"
-"Note: Passing keyword arguments \'name\', \'narg\' and \'func\' to\n"
-"_sqlite3.Connection.create_function() is deprecated. Parameters\n"
-"\'name\', \'narg\' and \'func\' will become positional-only in Python 3.15.\n"
-"");
+"Creates a new function.");
#define PYSQLITE_CONNECTION_CREATE_FUNCTION_METHODDEF \
{"create_function", _PyCFunction_CAST(pysqlite_connection_create_function), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_function__doc__},
@@ -443,24 +412,13 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,
int narg, PyObject *func,
int deterministic);
-// Emit compiler warnings when we get to Python 3.15.
-#if PY_VERSION_HEX >= 0x030f00C0
-# error "Update the clinic input of '_sqlite3.Connection.create_function'."
-#elif PY_VERSION_HEX >= 0x030f00A0
-# ifdef _MSC_VER
-# pragma message ("Update the clinic input of '_sqlite3.Connection.create_function'.")
-# else
-# warning "Update the clinic input of '_sqlite3.Connection.create_function'."
-# endif
-#endif
-
static PyObject *
pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 4
+ #define NUM_KEYWORDS 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -469,7 +427,7 @@ pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(name), &_Py_ID(narg), &_Py_ID(func), &_Py_ID(deterministic), },
+ .ob_item = { &_Py_ID(deterministic), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -478,7 +436,7 @@ pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"name", "narg", "func", "deterministic", NULL};
+ static const char * const _keywords[] = {"", "", "", "deterministic", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "create_function",
@@ -497,18 +455,8 @@ pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject
if (!args) {
goto exit;
}
- if (nargs < 3) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing keyword arguments 'name', 'narg' and 'func' to "
- "_sqlite3.Connection.create_function() is deprecated. Parameters "
- "'name', 'narg' and 'func' will become positional-only in Python "
- "3.15.", 1))
- {
- goto exit;
- }
- }
if (!PyUnicode_Check(args[0])) {
- _PyArg_BadArgument("create_function", "argument 'name'", "str", args[0]);
+ _PyArg_BadArgument("create_function", "argument 1", "str", args[0]);
goto exit;
}
Py_ssize_t name_length;
@@ -618,16 +566,10 @@ exit:
#endif /* defined(HAVE_WINDOW_FUNCTIONS) */
PyDoc_STRVAR(pysqlite_connection_create_aggregate__doc__,
-"create_aggregate($self, /, name, n_arg, aggregate_class)\n"
+"create_aggregate($self, name, n_arg, aggregate_class, /)\n"
"--\n"
"\n"
-"Creates a new aggregate.\n"
-"\n"
-"Note: Passing keyword arguments \'name\', \'n_arg\' and \'aggregate_class\'\n"
-"to _sqlite3.Connection.create_aggregate() is deprecated. Parameters\n"
-"\'name\', \'n_arg\' and \'aggregate_class\' will become positional-only in\n"
-"Python 3.15.\n"
-"");
+"Creates a new aggregate.");
#define PYSQLITE_CONNECTION_CREATE_AGGREGATE_METHODDEF \
{"create_aggregate", _PyCFunction_CAST(pysqlite_connection_create_aggregate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_aggregate__doc__},
@@ -638,42 +580,17 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
const char *name, int n_arg,
PyObject *aggregate_class);
-// Emit compiler warnings when we get to Python 3.15.
-#if PY_VERSION_HEX >= 0x030f00C0
-# error "Update the clinic input of '_sqlite3.Connection.create_aggregate'."
-#elif PY_VERSION_HEX >= 0x030f00A0
-# ifdef _MSC_VER
-# pragma message ("Update the clinic input of '_sqlite3.Connection.create_aggregate'.")
-# else
-# warning "Update the clinic input of '_sqlite3.Connection.create_aggregate'."
-# endif
-#endif
-
static PyObject *
pysqlite_connection_create_aggregate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
-
- #define NUM_KEYWORDS 3
- static struct {
- PyGC_Head _this_is_not_used;
- PyObject_VAR_HEAD
- Py_hash_t ob_hash;
- PyObject *ob_item[NUM_KEYWORDS];
- } _kwtuple = {
- .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
- .ob_hash = -1,
- .ob_item = { &_Py_ID(name), &_Py_ID(n_arg), &_Py_ID(aggregate_class), },
- };
- #undef NUM_KEYWORDS
- #define KWTUPLE (&_kwtuple.ob_base.ob_base)
-
- #else // !Py_BUILD_CORE
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
# define KWTUPLE NULL
- #endif // !Py_BUILD_CORE
+ #endif
- static const char * const _keywords[] = {"name", "n_arg", "aggregate_class", NULL};
+ static const char * const _keywords[] = {"", "", "", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "create_aggregate",
@@ -690,18 +607,8 @@ pysqlite_connection_create_aggregate(PyObject *self, PyTypeObject *cls, PyObject
if (!args) {
goto exit;
}
- if (nargs < 3) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing keyword arguments 'name', 'n_arg' and 'aggregate_class' "
- "to _sqlite3.Connection.create_aggregate() is deprecated. "
- "Parameters 'name', 'n_arg' and 'aggregate_class' will become "
- "positional-only in Python 3.15.", 1))
- {
- goto exit;
- }
- }
if (!PyUnicode_Check(args[0])) {
- _PyArg_BadArgument("create_aggregate", "argument 'name'", "str", args[0]);
+ _PyArg_BadArgument("create_aggregate", "argument 1", "str", args[0]);
goto exit;
}
Py_ssize_t name_length;
@@ -725,15 +632,10 @@ exit:
}
PyDoc_STRVAR(pysqlite_connection_set_authorizer__doc__,
-"set_authorizer($self, /, authorizer_callback)\n"
+"set_authorizer($self, authorizer_callback, /)\n"
"--\n"
"\n"
-"Set authorizer callback.\n"
-"\n"
-"Note: Passing keyword argument \'authorizer_callback\' to\n"
-"_sqlite3.Connection.set_authorizer() is deprecated. Parameter\n"
-"\'authorizer_callback\' will become positional-only in Python 3.15.\n"
-"");
+"Set authorizer callback.");
#define PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF \
{"set_authorizer", _PyCFunction_CAST(pysqlite_connection_set_authorizer), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_authorizer__doc__},
@@ -743,42 +645,17 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable);
-// Emit compiler warnings when we get to Python 3.15.
-#if PY_VERSION_HEX >= 0x030f00C0
-# error "Update the clinic input of '_sqlite3.Connection.set_authorizer'."
-#elif PY_VERSION_HEX >= 0x030f00A0
-# ifdef _MSC_VER
-# pragma message ("Update the clinic input of '_sqlite3.Connection.set_authorizer'.")
-# else
-# warning "Update the clinic input of '_sqlite3.Connection.set_authorizer'."
-# endif
-#endif
-
static PyObject *
pysqlite_connection_set_authorizer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
-
- #define NUM_KEYWORDS 1
- static struct {
- PyGC_Head _this_is_not_used;
- PyObject_VAR_HEAD
- Py_hash_t ob_hash;
- PyObject *ob_item[NUM_KEYWORDS];
- } _kwtuple = {
- .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
- .ob_hash = -1,
- .ob_item = { &_Py_ID(authorizer_callback), },
- };
- #undef NUM_KEYWORDS
- #define KWTUPLE (&_kwtuple.ob_base.ob_base)
-
- #else // !Py_BUILD_CORE
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
# define KWTUPLE NULL
- #endif // !Py_BUILD_CORE
+ #endif
- static const char * const _keywords[] = {"authorizer_callback", NULL};
+ static const char * const _keywords[] = {"", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "set_authorizer",
@@ -793,16 +670,6 @@ pysqlite_connection_set_authorizer(PyObject *self, PyTypeObject *cls, PyObject *
if (!args) {
goto exit;
}
- if (nargs < 1) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing keyword argument 'authorizer_callback' to "
- "_sqlite3.Connection.set_authorizer() is deprecated. Parameter "
- "'authorizer_callback' will become positional-only in Python "
- "3.15.", 1))
- {
- goto exit;
- }
- }
callable = args[0];
return_value = pysqlite_connection_set_authorizer_impl((pysqlite_Connection *)self, cls, callable);
@@ -811,7 +678,7 @@ exit:
}
PyDoc_STRVAR(pysqlite_connection_set_progress_handler__doc__,
-"set_progress_handler($self, /, progress_handler, n)\n"
+"set_progress_handler($self, progress_handler, /, n)\n"
"--\n"
"\n"
"Set progress handler callback.\n"
@@ -824,12 +691,7 @@ PyDoc_STRVAR(pysqlite_connection_set_progress_handler__doc__,
" The number of SQLite virtual machine instructions that are\n"
" executed between invocations of \'progress_handler\'.\n"
"\n"
-"If \'progress_handler\' is None or \'n\' is 0, the progress handler is disabled.\n"
-"\n"
-"Note: Passing keyword argument \'progress_handler\' to\n"
-"_sqlite3.Connection.set_progress_handler() is deprecated. Parameter\n"
-"\'progress_handler\' will become positional-only in Python 3.15.\n"
-"");
+"If \'progress_handler\' is None or \'n\' is 0, the progress handler is disabled.");
#define PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF \
{"set_progress_handler", _PyCFunction_CAST(pysqlite_connection_set_progress_handler), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_progress_handler__doc__},
@@ -839,24 +701,13 @@ pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable, int n);
-// Emit compiler warnings when we get to Python 3.15.
-#if PY_VERSION_HEX >= 0x030f00C0
-# error "Update the clinic input of '_sqlite3.Connection.set_progress_handler'."
-#elif PY_VERSION_HEX >= 0x030f00A0
-# ifdef _MSC_VER
-# pragma message ("Update the clinic input of '_sqlite3.Connection.set_progress_handler'.")
-# else
-# warning "Update the clinic input of '_sqlite3.Connection.set_progress_handler'."
-# endif
-#endif
-
static PyObject *
pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -865,7 +716,7 @@ pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyOb
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(progress_handler), _Py_LATIN1_CHR('n'), },
+ .ob_item = { _Py_LATIN1_CHR('n'), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -874,7 +725,7 @@ pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyOb
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"progress_handler", "n", NULL};
+ static const char * const _keywords[] = {"", "n", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "set_progress_handler",
@@ -890,16 +741,6 @@ pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyOb
if (!args) {
goto exit;
}
- if (nargs < 1) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing keyword argument 'progress_handler' to "
- "_sqlite3.Connection.set_progress_handler() is deprecated. "
- "Parameter 'progress_handler' will become positional-only in "
- "Python 3.15.", 1))
- {
- goto exit;
- }
- }
callable = args[0];
n = PyLong_AsInt(args[1]);
if (n == -1 && PyErr_Occurred()) {
@@ -912,15 +753,10 @@ exit:
}
PyDoc_STRVAR(pysqlite_connection_set_trace_callback__doc__,
-"set_trace_callback($self, /, trace_callback)\n"
+"set_trace_callback($self, trace_callback, /)\n"
"--\n"
"\n"
-"Set a trace callback called for each SQL statement (passed as unicode).\n"
-"\n"
-"Note: Passing keyword argument \'trace_callback\' to\n"
-"_sqlite3.Connection.set_trace_callback() is deprecated. Parameter\n"
-"\'trace_callback\' will become positional-only in Python 3.15.\n"
-"");
+"Set a trace callback called for each SQL statement (passed as unicode).");
#define PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF \
{"set_trace_callback", _PyCFunction_CAST(pysqlite_connection_set_trace_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_trace_callback__doc__},
@@ -930,42 +766,17 @@ pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable);
-// Emit compiler warnings when we get to Python 3.15.
-#if PY_VERSION_HEX >= 0x030f00C0
-# error "Update the clinic input of '_sqlite3.Connection.set_trace_callback'."
-#elif PY_VERSION_HEX >= 0x030f00A0
-# ifdef _MSC_VER
-# pragma message ("Update the clinic input of '_sqlite3.Connection.set_trace_callback'.")
-# else
-# warning "Update the clinic input of '_sqlite3.Connection.set_trace_callback'."
-# endif
-#endif
-
static PyObject *
pysqlite_connection_set_trace_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
-
- #define NUM_KEYWORDS 1
- static struct {
- PyGC_Head _this_is_not_used;
- PyObject_VAR_HEAD
- Py_hash_t ob_hash;
- PyObject *ob_item[NUM_KEYWORDS];
- } _kwtuple = {
- .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
- .ob_hash = -1,
- .ob_item = { &_Py_ID(trace_callback), },
- };
- #undef NUM_KEYWORDS
- #define KWTUPLE (&_kwtuple.ob_base.ob_base)
-
- #else // !Py_BUILD_CORE
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
# define KWTUPLE NULL
- #endif // !Py_BUILD_CORE
+ #endif
- static const char * const _keywords[] = {"trace_callback", NULL};
+ static const char * const _keywords[] = {"", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "set_trace_callback",
@@ -980,16 +791,6 @@ pysqlite_connection_set_trace_callback(PyObject *self, PyTypeObject *cls, PyObje
if (!args) {
goto exit;
}
- if (nargs < 1) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing keyword argument 'trace_callback' to "
- "_sqlite3.Connection.set_trace_callback() is deprecated. "
- "Parameter 'trace_callback' will become positional-only in Python"
- " 3.15.", 1))
- {
- goto exit;
- }
- }
callable = args[0];
return_value = pysqlite_connection_set_trace_callback_impl((pysqlite_Connection *)self, cls, callable);
@@ -1921,4 +1722,4 @@ exit:
#ifndef DESERIALIZE_METHODDEF
#define DESERIALIZE_METHODDEF
#endif /* !defined(DESERIALIZE_METHODDEF) */
-/*[clinic end generated code: output=2f325c2444b4bb47 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6cb96e557133d553 input=a9049054013a1b77]*/
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index 2a184f78754..16ec6efc850 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -215,7 +215,7 @@ class sqlite3_int64_converter(CConverter):
_sqlite3.Connection.__init__ as pysqlite_connection_init
database: object
- * [from 3.15]
+ *
timeout: double = 5.0
detect_types: int = 0
isolation_level: IsolationLevel = ""
@@ -223,7 +223,6 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init
factory: object(c_default='(PyObject*)clinic_state()->ConnectionType') = ConnectionType
cached_statements as cache_size: int = 128
uri: bool = False
- *
autocommit: Autocommit(c_default='LEGACY_TRANSACTION_CONTROL') = sqlite3.LEGACY_TRANSACTION_CONTROL
[clinic start generated code]*/
@@ -234,7 +233,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
int check_same_thread, PyObject *factory,
int cache_size, int uri,
enum autocommit_mode autocommit)
-/*[clinic end generated code: output=cba057313ea7712f input=219c3dbecbae7d99]*/
+/*[clinic end generated code: output=cba057313ea7712f input=5ca4883d8747a49b]*/
{
if (PySys_Audit("sqlite3.connect", "O", database) < 0) {
return -1;
@@ -1158,11 +1157,10 @@ check_num_params(pysqlite_Connection *self, const int n, const char *name)
_sqlite3.Connection.create_function as pysqlite_connection_create_function
cls: defining_class
- /
name: str
narg: int
func: object
- / [from 3.15]
+ /
*
deterministic: bool = False
@@ -1174,7 +1172,7 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,
PyTypeObject *cls, const char *name,
int narg, PyObject *func,
int deterministic)
-/*[clinic end generated code: output=8a811529287ad240 input=c7c313b0ca8b519e]*/
+/*[clinic end generated code: output=8a811529287ad240 input=a896096ed5390ae1]*/
{
int rc;
int flags = SQLITE_UTF8;
@@ -1366,11 +1364,10 @@ create_window_function_impl(pysqlite_Connection *self, PyTypeObject *cls,
_sqlite3.Connection.create_aggregate as pysqlite_connection_create_aggregate
cls: defining_class
- /
name: str
n_arg: int
aggregate_class: object
- / [from 3.15]
+ /
Creates a new aggregate.
[clinic start generated code]*/
@@ -1380,7 +1377,7 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
PyTypeObject *cls,
const char *name, int n_arg,
PyObject *aggregate_class)
-/*[clinic end generated code: output=1b02d0f0aec7ff96 input=8087056db6eae1cf]*/
+/*[clinic end generated code: output=1b02d0f0aec7ff96 input=aa2773f6a42f7e17]*/
{
int rc;
@@ -1531,7 +1528,7 @@ _sqlite3.Connection.set_authorizer as pysqlite_connection_set_authorizer
cls: defining_class
authorizer_callback as callable: object
- / [from 3.15]
+ /
Set authorizer callback.
[clinic start generated code]*/
@@ -1540,7 +1537,7 @@ static PyObject *
pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable)
-/*[clinic end generated code: output=75fa60114fc971c3 input=a52bd4937c588752]*/
+/*[clinic end generated code: output=75fa60114fc971c3 input=e76469ab0bb1bbcd]*/
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
@@ -1576,7 +1573,7 @@ _sqlite3.Connection.set_progress_handler as pysqlite_connection_set_progress_han
A callable that takes no arguments.
If the callable returns non-zero, the current query is terminated,
and an exception is raised.
- / [from 3.15]
+ /
n: int
The number of SQLite virtual machine instructions that are
executed between invocations of 'progress_handler'.
@@ -1590,7 +1587,7 @@ static PyObject *
pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable, int n)
-/*[clinic end generated code: output=0739957fd8034a50 input=b4d6e2ef8b4d32f9]*/
+/*[clinic end generated code: output=0739957fd8034a50 input=74c943f1ae7d8880]*/
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
@@ -1617,7 +1614,7 @@ _sqlite3.Connection.set_trace_callback as pysqlite_connection_set_trace_callback
cls: defining_class
trace_callback as callable: object
- / [from 3.15]
+ /
Set a trace callback called for each SQL statement (passed as unicode).
[clinic start generated code]*/
@@ -1626,7 +1623,7 @@ static PyObject *
pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable)
-/*[clinic end generated code: output=d91048c03bfcee05 input=d705d592ec03cf28]*/
+/*[clinic end generated code: output=d91048c03bfcee05 input=f4f59bf2f87f2026]*/
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 7943bfcca36..0c3f43d0e50 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -31,6 +31,7 @@
#include "util.h"
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
typedef enum {
TYPE_LONG,
@@ -185,9 +186,7 @@ cursor_dealloc(PyObject *op)
pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- if (self->in_weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->in_weakreflist);
(void)tp->tp_clear(op);
tp->tp_free(self);
Py_DECREF(tp);
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index 27e8dab92e0..5464fd1227a 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -32,6 +32,7 @@
#include "microprotocols.h"
#include "row.h"
#include "blob.h"
+#include "util.h"
#if SQLITE_VERSION_NUMBER < 3015002
#error "SQLite 3.15.2 or higher required"
@@ -60,26 +61,16 @@ pysqlite_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargsf,
pysqlite_state *state = pysqlite_get_state(module);
PyObject *factory = (PyObject *)state->ConnectionType;
- static const int FACTORY_POS = 5;
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
- if (nargs > 1 && nargs <= 8) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing more than 1 positional argument to sqlite3.connect()"
- " is deprecated. Parameters 'timeout', 'detect_types', "
- "'isolation_level', 'check_same_thread', 'factory', "
- "'cached_statements' and 'uri' will become keyword-only "
- "parameters in Python 3.15.", 1))
- {
- return NULL;
- }
- }
- if (nargs > FACTORY_POS) {
- factory = args[FACTORY_POS];
+ if (nargs > 1) {
+ PyErr_Format(PyExc_TypeError,
+ "connect() takes at most 1 positional arguments (%zd given)", nargs);
+ return NULL;
}
- else if (kwnames != NULL) {
+ if (kwnames != NULL) {
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) {
PyObject *item = PyTuple_GET_ITEM(kwnames, i); // borrowed ref.
- if (PyUnicode_CompareWithASCIIString(item, "factory") == 0) {
+ if (PyUnicode_EqualToUTF8(item, "factory")) {
factory = args[nargs + i];
break;
}
@@ -415,6 +406,40 @@ pysqlite_error_name(int rc)
}
static int
+add_keyword_tuple(PyObject *module)
+{
+#if SQLITE_VERSION_NUMBER >= 3024000
+ int count = sqlite3_keyword_count();
+ PyObject *keywords = PyTuple_New(count);
+ if (keywords == NULL) {
+ return -1;
+ }
+ for (int i = 0; i < count; i++) {
+ const char *keyword;
+ int size;
+ int result = sqlite3_keyword_name(i, &keyword, &size);
+ if (result != SQLITE_OK) {
+ pysqlite_state *state = pysqlite_get_state(module);
+ set_error_from_code(state, result);
+ goto error;
+ }
+ PyObject *kwd = PyUnicode_FromStringAndSize(keyword, size);
+ if (!kwd) {
+ goto error;
+ }
+ PyTuple_SET_ITEM(keywords, i, kwd);
+ }
+ return PyModule_Add(module, "SQLITE_KEYWORDS", keywords);
+
+error:
+ Py_DECREF(keywords);
+ return -1;
+#else
+ return 0;
+#endif
+}
+
+static int
add_integer_constants(PyObject *module) {
#define ADD_INT(ival) \
do { \
@@ -712,6 +737,10 @@ module_exec(PyObject *module)
goto error;
}
+ if (add_keyword_tuple(module) < 0) {
+ goto error;
+ }
+
if (PyModule_AddStringConstant(module, "sqlite_version", sqlite3_libversion())) {
goto error;
}
diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c
index 602d0ab8588..e8943920043 100644
--- a/Modules/_sre/sre.c
+++ b/Modules/_sre/sre.c
@@ -44,6 +44,7 @@ static const char copyright[] =
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_unicodeobject.h" // _PyUnicode_Copy
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "sre.h" // SRE_CODE
@@ -736,10 +737,7 @@ pattern_dealloc(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- PatternObject *obj = _PatternObject_CAST(self);
- if (obj->weakreflist != NULL) {
- PyObject_ClearWeakRefs(self);
- }
+ FT_CLEAR_WEAKREFS(self, _PatternObject_CAST(self)->weakreflist);
(void)pattern_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 97a29f4d0e1..014e624f6c2 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -563,7 +563,7 @@ fill_and_set_sslerror(_sslmodulestate *state,
goto fail;
}
}
- if (PyUnicodeWriter_WriteUTF8(writer, "] ", 2) < 0) {
+ if (PyUnicodeWriter_WriteASCII(writer, "] ", 2) < 0) {
goto fail;
}
}
@@ -4427,7 +4427,7 @@ _ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath)
FILE *f;
DH *dh;
-#if defined(MS_WINDOWS) && defined(_DEBUG)
+#if defined(MS_WINDOWS) && defined(Py_DEBUG)
PyErr_SetString(PyExc_NotImplementedError,
"load_dh_params: unavailable on Windows debug build");
return NULL;
@@ -6626,6 +6626,12 @@ sslmodule_init_constants(PyObject *m)
addbool(m, "HAS_PSK", 1);
#endif
+#ifdef OPENSSL_NO_EXTERNAL_PSK_TLS13
+ addbool(m, "HAS_PSK_TLS13", 0);
+#else
+ addbool(m, "HAS_PSK_TLS13", 1);
+#endif
+
#ifdef SSL_VERIFY_POST_HANDSHAKE
addbool(m, "HAS_PHA", 1);
#else
diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c
index 7c0b4876f43..f0a0a1674f3 100644
--- a/Modules/_ssl/debughelpers.c
+++ b/Modules/_ssl/debughelpers.c
@@ -175,7 +175,7 @@ _PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg,
PySSLContext *self = PySSLContext_CAST(op);
FILE *fp;
-#if defined(MS_WINDOWS) && defined(_DEBUG)
+#if defined(MS_WINDOWS) && defined(Py_DEBUG)
PyErr_SetString(PyExc_NotImplementedError,
"set_keylog_filename: unavailable on Windows debug build");
return -1;
diff --git a/Modules/_stat.c b/Modules/_stat.c
index f11ca7d23b4..1dabf2f6d5b 100644
--- a/Modules/_stat.c
+++ b/Modules/_stat.c
@@ -57,7 +57,7 @@ typedef unsigned short mode_t;
* Only the names are defined by POSIX but not their value. All common file
* types seems to have the same numeric value on all platforms, though.
*
- * pyport.h guarantees S_IFMT, S_IFDIR, S_IFCHR, S_IFREG and S_IFLNK
+ * fileutils.h guarantees S_IFMT, S_IFDIR, S_IFCHR, S_IFREG and S_IFLNK
*/
#ifndef S_IFBLK
@@ -86,7 +86,7 @@ typedef unsigned short mode_t;
/* S_ISXXX()
- * pyport.h defines S_ISDIR(), S_ISREG() and S_ISCHR()
+ * fileutils.h defines S_ISDIR(), S_ISREG() and S_ISCHR()
*/
#ifndef S_ISBLK
diff --git a/Modules/_struct.c b/Modules/_struct.c
index e400f607b55..3fad35a8c94 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -11,6 +11,7 @@
#include "pycore_bytesobject.h" // _PyBytesWriter
#include "pycore_long.h" // _PyLong_AsByteArray()
#include "pycore_moduleobject.h" // _PyModule_GetState()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
@@ -853,8 +854,8 @@ static const formatdef native_table[] = {
{'e', sizeof(short), _Alignof(short), nu_halffloat, np_halffloat},
{'f', sizeof(float), _Alignof(float), nu_float, np_float},
{'d', sizeof(double), _Alignof(double), nu_double, np_double},
- {'F', 2*sizeof(float), _Alignof(float[2]), nu_float_complex, np_float_complex},
- {'D', 2*sizeof(double), _Alignof(double[2]), nu_double_complex, np_double_complex},
+ {'F', 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex},
+ {'D', 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex},
{'P', sizeof(void *), _Alignof(void *), nu_void_p, np_void_p},
{0}
};
@@ -1794,9 +1795,7 @@ s_dealloc(PyObject *op)
PyStructObject *s = PyStructObject_CAST(op);
PyTypeObject *tp = Py_TYPE(s);
PyObject_GC_UnTrack(s);
- if (s->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, s->weakreflist);
if (s->s_codes != NULL) {
PyMem_Free(s->s_codes);
}
diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c
index 42243023a45..6313abf5485 100644
--- a/Modules/_testcapi/long.c
+++ b/Modules/_testcapi/long.c
@@ -228,7 +228,7 @@ pylongwriter_create(PyObject *module, PyObject *args)
goto error;
}
- if (num < 0 || num >= PyLong_BASE) {
+ if (num < 0 || num >= (long)PyLong_BASE) {
PyErr_SetString(PyExc_ValueError, "digit doesn't fit into digit");
goto error;
}
diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c
index 5c67adfee29..798ef97c495 100644
--- a/Modules/_testcapi/object.c
+++ b/Modules/_testcapi/object.c
@@ -478,6 +478,13 @@ clear_managed_dict(PyObject *self, PyObject *obj)
}
+static PyObject *
+is_uniquely_referenced(PyObject *self, PyObject *op)
+{
+ return PyBool_FromLong(PyUnstable_Object_IsUniquelyReferenced(op));
+}
+
+
static PyMethodDef test_methods[] = {
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
@@ -503,6 +510,7 @@ static PyMethodDef test_methods[] = {
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
+ {"is_uniquely_referenced", is_uniquely_referenced, METH_O},
{NULL},
};
diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c
index b8ecf53f4f8..203282dd53d 100644
--- a/Modules/_testcapi/unicode.c
+++ b/Modules/_testcapi/unicode.c
@@ -220,6 +220,12 @@ unicode_copycharacters(PyObject *self, PyObject *args)
return Py_BuildValue("(Nn)", to_copy, copied);
}
+static PyObject*
+unicode_GET_CACHED_HASH(PyObject *self, PyObject *arg)
+{
+ return PyLong_FromSsize_t(PyUnstable_Unicode_GET_CACHED_HASH(arg));
+}
+
// --- PyUnicodeWriter type -------------------------------------------------
@@ -333,6 +339,27 @@ writer_write_utf8(PyObject *self_raw, PyObject *args)
static PyObject*
+writer_write_ascii(PyObject *self_raw, PyObject *args)
+{
+ WriterObject *self = (WriterObject *)self_raw;
+ if (writer_check(self) < 0) {
+ return NULL;
+ }
+
+ char *str;
+ Py_ssize_t size;
+ if (!PyArg_ParseTuple(args, "yn", &str, &size)) {
+ return NULL;
+ }
+
+ if (PyUnicodeWriter_WriteASCII(self->writer, str, size) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
writer_write_widechar(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
@@ -513,6 +540,7 @@ writer_finish(PyObject *self_raw, PyObject *Py_UNUSED(args))
static PyMethodDef writer_methods[] = {
{"write_char", _PyCFunction_CAST(writer_write_char), METH_VARARGS},
{"write_utf8", _PyCFunction_CAST(writer_write_utf8), METH_VARARGS},
+ {"write_ascii", _PyCFunction_CAST(writer_write_ascii), METH_VARARGS},
{"write_widechar", _PyCFunction_CAST(writer_write_widechar), METH_VARARGS},
{"write_ucs4", _PyCFunction_CAST(writer_write_ucs4), METH_VARARGS},
{"write_str", _PyCFunction_CAST(writer_write_str), METH_VARARGS},
@@ -548,6 +576,7 @@ static PyMethodDef TestMethods[] = {
{"unicode_asucs4copy", unicode_asucs4copy, METH_VARARGS},
{"unicode_asutf8", unicode_asutf8, METH_VARARGS},
{"unicode_copycharacters", unicode_copycharacters, METH_VARARGS},
+ {"unicode_GET_CACHED_HASH", unicode_GET_CACHED_HASH, METH_O},
{NULL},
};
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 3aa6e4c9e43..71fffedee14 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2424,7 +2424,7 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args))
// Used by `finalize_thread_hang`.
-#ifdef _POSIX_THREADS
+#if defined(_POSIX_THREADS) && !defined(__wasi__)
static void finalize_thread_hang_cleanup_callback(void *Py_UNUSED(arg)) {
// Should not reach here.
Py_FatalError("pthread thread termination was triggered unexpectedly");
@@ -3175,6 +3175,48 @@ create_manual_heap_type(void)
return (PyObject *)type;
}
+typedef struct {
+ PyObject_VAR_HEAD
+} ManagedDictObject;
+
+int ManagedDict_traverse(PyObject *self, visitproc visit, void *arg) {
+ PyObject_VisitManagedDict(self, visit, arg);
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
+
+int ManagedDict_clear(PyObject *self) {
+ PyObject_ClearManagedDict(self);
+ return 0;
+}
+
+static PyGetSetDef ManagedDict_getset[] = {
+ {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, NULL, NULL},
+ {NULL, NULL, NULL, NULL, NULL},
+};
+
+static PyType_Slot ManagedDict_slots[] = {
+ {Py_tp_new, (void *)PyType_GenericNew},
+ {Py_tp_getset, (void *)ManagedDict_getset},
+ {Py_tp_traverse, (void *)ManagedDict_traverse},
+ {Py_tp_clear, (void *)ManagedDict_clear},
+ {0}
+};
+
+static PyType_Spec ManagedDict_spec = {
+ "_testcapi.ManagedDictType",
+ sizeof(ManagedDictObject),
+ 0, // itemsize
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_HAVE_GC,
+ ManagedDict_slots
+};
+
+static PyObject *
+create_managed_dict_type(void)
+{
+ return PyType_FromSpec(&ManagedDict_spec);
+}
+
static struct PyModuleDef _testcapimodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_testcapi",
@@ -3315,6 +3357,13 @@ PyInit__testcapi(void)
return NULL;
}
+ PyObject *managed_dict_type = create_managed_dict_type();
+ if (managed_dict_type == NULL) {
+ return NULL;
+ }
+ if (PyModule_Add(m, "ManagedDictType", managed_dict_type) < 0) {
+ return NULL;
+ }
/* Include tests from the _testcapi/ directory */
if (_PyTestCapi_Init_Vectorcall(m) < 0) {
diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c
index 3e903b6d87d..7e4ea0901fe 100644
--- a/Modules/_testclinic.c
+++ b/Modules/_testclinic.c
@@ -1734,14 +1734,14 @@ output impl_definition block
class _testclinic.DeprStarNew "PyObject *" "PyObject"
@classmethod
_testclinic.DeprStarNew.__new__ as depr_star_new
- * [from 3.14]
+ * [from 3.37]
a: object = None
The deprecation message should use the class name instead of __new__.
[clinic start generated code]*/
static PyObject *
depr_star_new_impl(PyTypeObject *type, PyObject *a)
-/*[clinic end generated code: output=bdbb36244f90cf46 input=fdd640db964b4dc1]*/
+/*[clinic end generated code: output=bdbb36244f90cf46 input=df8930826b302c3a]*/
{
return type->tp_alloc(type, 0);
}
@@ -1775,14 +1775,14 @@ static PyTypeObject DeprStarNew = {
/*[clinic input]
class _testclinic.DeprStarInit "PyObject *" "PyObject"
_testclinic.DeprStarInit.__init__ as depr_star_init
- * [from 3.14]
+ * [from 3.37]
a: object = None
The deprecation message should use the class name instead of __init__.
[clinic start generated code]*/
static int
depr_star_init_impl(PyObject *self, PyObject *a)
-/*[clinic end generated code: output=8d27b43c286d3ecc input=5575b77229d5e2be]*/
+/*[clinic end generated code: output=8d27b43c286d3ecc input=07a5c35e04f526c5]*/
{
return 0;
}
@@ -1818,7 +1818,7 @@ static PyTypeObject DeprStarInit = {
class _testclinic.DeprStarInitNoInline "PyObject *" "PyObject"
_testclinic.DeprStarInitNoInline.__init__ as depr_star_init_noinline
a: object
- * [from 3.14]
+ * [from 3.37]
b: object
c: object = None
*
@@ -1829,7 +1829,7 @@ _testclinic.DeprStarInitNoInline.__init__ as depr_star_init_noinline
static int
depr_star_init_noinline_impl(PyObject *self, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length)
-/*[clinic end generated code: output=9b31fc167f1bf9f7 input=5a887543122bca48]*/
+/*[clinic end generated code: output=9b31fc167f1bf9f7 input=45171504f009a391]*/
{
return 0;
}
@@ -1849,13 +1849,13 @@ class _testclinic.DeprKwdNew "PyObject *" "PyObject"
@classmethod
_testclinic.DeprKwdNew.__new__ as depr_kwd_new
a: object = None
- / [from 3.14]
+ / [from 3.37]
The deprecation message should use the class name instead of __new__.
[clinic start generated code]*/
static PyObject *
depr_kwd_new_impl(PyTypeObject *type, PyObject *a)
-/*[clinic end generated code: output=618d07afc5616149 input=6c7d13c471013c10]*/
+/*[clinic end generated code: output=618d07afc5616149 input=1bfb1b86f56ad2e6]*/
{
return type->tp_alloc(type, 0);
}
@@ -1873,13 +1873,13 @@ static PyTypeObject DeprKwdNew = {
class _testclinic.DeprKwdInit "PyObject *" "PyObject"
_testclinic.DeprKwdInit.__init__ as depr_kwd_init
a: object = None
- / [from 3.14]
+ / [from 3.37]
The deprecation message should use the class name instead of __init__.
[clinic start generated code]*/
static int
depr_kwd_init_impl(PyObject *self, PyObject *a)
-/*[clinic end generated code: output=6e02eb724a85d840 input=b9bf3c20f012d539]*/
+/*[clinic end generated code: output=6e02eb724a85d840 input=6f4daaa912ec24b2]*/
{
return 0;
}
@@ -1901,7 +1901,7 @@ _testclinic.DeprKwdInitNoInline.__init__ as depr_kwd_init_noinline
/
b: object
c: object = None
- / [from 3.14]
+ / [from 3.37]
# Force to use _PyArg_ParseTupleAndKeywordsFast.
d: str(accept={str, robuffer}, zeroes=True) = ''
[clinic start generated code]*/
@@ -1909,7 +1909,7 @@ _testclinic.DeprKwdInitNoInline.__init__ as depr_kwd_init_noinline
static int
depr_kwd_init_noinline_impl(PyObject *self, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length)
-/*[clinic end generated code: output=27759d70ddd25873 input=c19d982c8c70a930]*/
+/*[clinic end generated code: output=27759d70ddd25873 input=a022ad17f4b6008c]*/
{
return 0;
}
@@ -1926,13 +1926,13 @@ static PyTypeObject DeprKwdInitNoInline = {
/*[clinic input]
depr_star_pos0_len1
- * [from 3.14]
+ * [from 3.37]
a: object
[clinic start generated code]*/
static PyObject *
depr_star_pos0_len1_impl(PyObject *module, PyObject *a)
-/*[clinic end generated code: output=e1c6c2b423129499 input=089b9aee25381b69]*/
+/*[clinic end generated code: output=e1c6c2b423129499 input=c8f49d8c6165ab6c]*/
{
Py_RETURN_NONE;
}
@@ -1940,14 +1940,14 @@ depr_star_pos0_len1_impl(PyObject *module, PyObject *a)
/*[clinic input]
depr_star_pos0_len2
- * [from 3.14]
+ * [from 3.37]
a: object
b: object
[clinic start generated code]*/
static PyObject *
depr_star_pos0_len2_impl(PyObject *module, PyObject *a, PyObject *b)
-/*[clinic end generated code: output=96df9be39859c7e4 input=65c83a32e01495c6]*/
+/*[clinic end generated code: output=96df9be39859c7e4 input=aca96f36892eda25]*/
{
Py_RETURN_NONE;
}
@@ -1955,7 +1955,7 @@ depr_star_pos0_len2_impl(PyObject *module, PyObject *a, PyObject *b)
/*[clinic input]
depr_star_pos0_len3_with_kwd
- * [from 3.14]
+ * [from 3.37]
a: object
b: object
c: object
@@ -1966,7 +1966,7 @@ depr_star_pos0_len3_with_kwd
static PyObject *
depr_star_pos0_len3_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d)
-/*[clinic end generated code: output=7f2531eda837052f input=b33f620f57d9270f]*/
+/*[clinic end generated code: output=7f2531eda837052f input=5602f0bced3d5094]*/
{
Py_RETURN_NONE;
}
@@ -1975,13 +1975,13 @@ depr_star_pos0_len3_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
/*[clinic input]
depr_star_pos1_len1_opt
a: object
- * [from 3.14]
+ * [from 3.37]
b: object = None
[clinic start generated code]*/
static PyObject *
depr_star_pos1_len1_opt_impl(PyObject *module, PyObject *a, PyObject *b)
-/*[clinic end generated code: output=b5b4e326ee3b216f input=4a4b8ff72eae9ff7]*/
+/*[clinic end generated code: output=b5b4e326ee3b216f input=070817da1d6ccf49]*/
{
Py_RETURN_NONE;
}
@@ -1990,13 +1990,13 @@ depr_star_pos1_len1_opt_impl(PyObject *module, PyObject *a, PyObject *b)
/*[clinic input]
depr_star_pos1_len1
a: object
- * [from 3.14]
+ * [from 3.37]
b: object
[clinic start generated code]*/
static PyObject *
depr_star_pos1_len1_impl(PyObject *module, PyObject *a, PyObject *b)
-/*[clinic end generated code: output=eab92e37d5b0a480 input=1e7787a9fe5f62a0]*/
+/*[clinic end generated code: output=eab92e37d5b0a480 input=2e3a30c71edd0f30]*/
{
Py_RETURN_NONE;
}
@@ -2005,7 +2005,7 @@ depr_star_pos1_len1_impl(PyObject *module, PyObject *a, PyObject *b)
/*[clinic input]
depr_star_pos1_len2_with_kwd
a: object
- * [from 3.14]
+ * [from 3.37]
b: object
c: object
*
@@ -2015,7 +2015,7 @@ depr_star_pos1_len2_with_kwd
static PyObject *
depr_star_pos1_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d)
-/*[clinic end generated code: output=3bccab672b7cfbb8 input=6bc7bd742fa8be15]*/
+/*[clinic end generated code: output=3bccab672b7cfbb8 input=48492b028a4f281c]*/
{
Py_RETURN_NONE;
}
@@ -2025,14 +2025,14 @@ depr_star_pos1_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
depr_star_pos2_len1
a: object
b: object
- * [from 3.14]
+ * [from 3.37]
c: object
[clinic start generated code]*/
static PyObject *
depr_star_pos2_len1_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c)
-/*[clinic end generated code: output=20f5b230e9beeb70 input=5fc3e1790dec00d5]*/
+/*[clinic end generated code: output=20f5b230e9beeb70 input=80ee46e15cd14cf3]*/
{
Py_RETURN_NONE;
}
@@ -2042,7 +2042,7 @@ depr_star_pos2_len1_impl(PyObject *module, PyObject *a, PyObject *b,
depr_star_pos2_len2
a: object
b: object
- * [from 3.14]
+ * [from 3.37]
c: object
d: object
[clinic start generated code]*/
@@ -2050,7 +2050,7 @@ depr_star_pos2_len2
static PyObject *
depr_star_pos2_len2_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d)
-/*[clinic end generated code: output=9f90ed8fbce27d7a input=9cc8003b89d38779]*/
+/*[clinic end generated code: output=9f90ed8fbce27d7a input=ac57914cf40a011b]*/
{
Py_RETURN_NONE;
}
@@ -2060,7 +2060,7 @@ depr_star_pos2_len2_impl(PyObject *module, PyObject *a, PyObject *b,
depr_star_pos2_len2_with_kwd
a: object
b: object
- * [from 3.14]
+ * [from 3.37]
c: object
d: object
*
@@ -2070,7 +2070,7 @@ depr_star_pos2_len2_with_kwd
static PyObject *
depr_star_pos2_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d, PyObject *e)
-/*[clinic end generated code: output=05432c4f20527215 input=831832d90534da91]*/
+/*[clinic end generated code: output=05432c4f20527215 input=98f25e33c01285a3]*/
{
Py_RETURN_NONE;
}
@@ -2079,7 +2079,7 @@ depr_star_pos2_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
/*[clinic input]
depr_star_noinline
a: object
- * [from 3.14]
+ * [from 3.37]
b: object
c: object = None
*
@@ -2090,7 +2090,7 @@ depr_star_noinline
static PyObject *
depr_star_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length)
-/*[clinic end generated code: output=cc27dacf5c2754af input=d36cc862a2daef98]*/
+/*[clinic end generated code: output=cc27dacf5c2754af input=a829784557a42349]*/
{
Py_RETURN_NONE;
}
@@ -2099,12 +2099,12 @@ depr_star_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
/*[clinic input]
depr_star_multi
a: object
- * [from 3.16]
+ * [from 3.39]
b: object
- * [from 3.15]
+ * [from 3.38]
c: object
d: object
- * [from 3.14]
+ * [from 3.37]
e: object
f: object
g: object
@@ -2116,7 +2116,7 @@ static PyObject *
depr_star_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
PyObject *d, PyObject *e, PyObject *f, PyObject *g,
PyObject *h)
-/*[clinic end generated code: output=77681653f4202068 input=3ebd05d888a957ea]*/
+/*[clinic end generated code: output=77681653f4202068 input=6798940a18b2e62b]*/
{
Py_RETURN_NONE;
}
@@ -2127,12 +2127,12 @@ depr_kwd_required_1
a: object
/
b: object
- / [from 3.14]
+ / [from 3.37]
[clinic start generated code]*/
static PyObject *
depr_kwd_required_1_impl(PyObject *module, PyObject *a, PyObject *b)
-/*[clinic end generated code: output=1d8ab19ea78418af input=53f2c398b828462d]*/
+/*[clinic end generated code: output=1d8ab19ea78418af input=37853d8548d42df5]*/
{
Py_RETURN_NONE;
}
@@ -2144,13 +2144,13 @@ depr_kwd_required_2
/
b: object
c: object
- / [from 3.14]
+ / [from 3.37]
[clinic start generated code]*/
static PyObject *
depr_kwd_required_2_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c)
-/*[clinic end generated code: output=44a89cb82509ddde input=a2b0ef37de8a01a7]*/
+/*[clinic end generated code: output=44a89cb82509ddde input=0e1faedd8ec248b1]*/
{
Py_RETURN_NONE;
}
@@ -2161,12 +2161,12 @@ depr_kwd_optional_1
a: object
/
b: object = None
- / [from 3.14]
+ / [from 3.37]
[clinic start generated code]*/
static PyObject *
depr_kwd_optional_1_impl(PyObject *module, PyObject *a, PyObject *b)
-/*[clinic end generated code: output=a8a3d67efcc7b058 input=e416981eb78c3053]*/
+/*[clinic end generated code: output=a8a3d67efcc7b058 input=adb240416511b30a]*/
{
Py_RETURN_NONE;
}
@@ -2178,13 +2178,13 @@ depr_kwd_optional_2
/
b: object = None
c: object = None
- / [from 3.14]
+ / [from 3.37]
[clinic start generated code]*/
static PyObject *
depr_kwd_optional_2_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c)
-/*[clinic end generated code: output=aa2d967f26fdb9f6 input=cae3afb783bfc855]*/
+/*[clinic end generated code: output=aa2d967f26fdb9f6 input=fb8a82d0087f8732]*/
{
Py_RETURN_NONE;
}
@@ -2195,13 +2195,13 @@ depr_kwd_optional_3
a: object = None
b: object = None
c: object = None
- / [from 3.14]
+ / [from 3.37]
[clinic start generated code]*/
static PyObject *
depr_kwd_optional_3_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c)
-/*[clinic end generated code: output=a26025bf6118fd07 input=c9183b2f9ccaf992]*/
+/*[clinic end generated code: output=a26025bf6118fd07 input=e54bbbacd8624fa7]*/
{
Py_RETURN_NONE;
}
@@ -2213,13 +2213,13 @@ depr_kwd_required_optional
/
b: object
c: object = None
- / [from 3.14]
+ / [from 3.37]
[clinic start generated code]*/
static PyObject *
depr_kwd_required_optional_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c)
-/*[clinic end generated code: output=e53a8b7a250d8ffc input=23237a046f8388f5]*/
+/*[clinic end generated code: output=e53a8b7a250d8ffc input=285105a1ffb784b5]*/
{
Py_RETURN_NONE;
}
@@ -2231,7 +2231,7 @@ depr_kwd_noinline
/
b: object
c: object = None
- / [from 3.14]
+ / [from 3.37]
# Force to use _PyArg_ParseStackAndKeywords.
d: str(accept={str, robuffer}, zeroes=True) = ''
[clinic start generated code]*/
@@ -2239,7 +2239,7 @@ depr_kwd_noinline
static PyObject *
depr_kwd_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length)
-/*[clinic end generated code: output=f59da8113f2bad7c input=1d6db65bebb069d7]*/
+/*[clinic end generated code: output=f59da8113f2bad7c input=3773d1bdc1f82298]*/
{
Py_RETURN_NONE;
}
@@ -2250,14 +2250,14 @@ depr_kwd_multi
a: object
/
b: object
- / [from 3.14]
+ / [from 3.37]
c: object
d: object
- / [from 3.15]
+ / [from 3.38]
e: object
f: object
g: object
- / [from 3.16]
+ / [from 3.39]
h: object
[clinic start generated code]*/
@@ -2265,7 +2265,7 @@ static PyObject *
depr_kwd_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
PyObject *d, PyObject *e, PyObject *f, PyObject *g,
PyObject *h)
-/*[clinic end generated code: output=ddfbde80fe1942e1 input=7a074e621c79efd7]*/
+/*[clinic end generated code: output=ddfbde80fe1942e1 input=a84c447a74284174]*/
{
Py_RETURN_NONE;
}
@@ -2276,13 +2276,13 @@ depr_multi
a: object
/
b: object
- / [from 3.14]
+ / [from 3.37]
c: object
- / [from 3.15]
+ / [from 3.38]
d: object
- * [from 3.15]
+ * [from 3.38]
e: object
- * [from 3.14]
+ * [from 3.37]
f: object
*
g: object
@@ -2291,7 +2291,7 @@ depr_multi
static PyObject *
depr_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
PyObject *d, PyObject *e, PyObject *f, PyObject *g)
-/*[clinic end generated code: output=f81c92852ca2d4ee input=5b847c5e44bedd02]*/
+/*[clinic end generated code: output=f81c92852ca2d4ee input=0e859e8b8eda75d7]*/
{
Py_RETURN_NONE;
}
diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c
deleted file mode 100644
index b43e8b21557..00000000000
--- a/Modules/_testexternalinspection.c
+++ /dev/null
@@ -1,1543 +0,0 @@
-#define _GNU_SOURCE
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef Py_BUILD_CORE_BUILTIN
-# define Py_BUILD_CORE_MODULE 1
-#endif
-#include "Python.h"
-#include <internal/pycore_debug_offsets.h> // _Py_DebugOffsets
-#include <internal/pycore_frame.h> // FRAME_SUSPENDED_YIELD_FROM
-#include <internal/pycore_interpframe.h> // FRAME_OWNED_BY_CSTACK
-#include <internal/pycore_llist.h> // struct llist_node
-#include <internal/pycore_stackref.h> // Py_TAG_BITS
-#include "../Python/remote_debug.h"
-
-#ifndef HAVE_PROCESS_VM_READV
-# define HAVE_PROCESS_VM_READV 0
-#endif
-
-struct _Py_AsyncioModuleDebugOffsets {
- struct _asyncio_task_object {
- uint64_t size;
- uint64_t task_name;
- uint64_t task_awaited_by;
- uint64_t task_is_task;
- uint64_t task_awaited_by_is_set;
- uint64_t task_coro;
- uint64_t task_node;
- } asyncio_task_object;
- struct _asyncio_interpreter_state {
- uint64_t size;
- uint64_t asyncio_tasks_head;
- } asyncio_interpreter_state;
- struct _asyncio_thread_state {
- uint64_t size;
- uint64_t asyncio_running_loop;
- uint64_t asyncio_running_task;
- uint64_t asyncio_tasks_head;
- } asyncio_thread_state;
-};
-
-// Get the PyAsyncioDebug section address for any platform
-static uintptr_t
-_Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
-{
- uintptr_t address;
-
-#ifdef MS_WINDOWS
- // On Windows, search for asyncio debug in executable or DLL
- address = search_windows_map_for_section(handle, "AsyncioD", L"_asyncio");
-#elif defined(__linux__)
- // On Linux, search for asyncio debug in executable or DLL
- address = search_linux_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
-#elif defined(__APPLE__) && TARGET_OS_OSX
- // On macOS, try libpython first, then fall back to python
- address = search_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
- if (address == 0) {
- PyErr_Clear();
- address = search_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
- }
-#else
- address = 0;
-#endif
-
- return address;
-}
-
-static int
-read_string(
- proc_handle_t *handle,
- _Py_DebugOffsets* debug_offsets,
- uintptr_t address,
- char* buffer,
- Py_ssize_t size
-) {
- Py_ssize_t len;
- int result = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address + debug_offsets->unicode_object.length,
- sizeof(Py_ssize_t),
- &len
- );
- if (result < 0) {
- return -1;
- }
- if (len >= size) {
- PyErr_SetString(PyExc_RuntimeError, "Buffer too small");
- return -1;
- }
- size_t offset = debug_offsets->unicode_object.asciiobject_size;
- result = _Py_RemoteDebug_ReadRemoteMemory(handle, address + offset, len, buffer);
- if (result < 0) {
- return -1;
- }
- buffer[len] = '\0';
- return 0;
-}
-
-static inline int
-read_ptr(proc_handle_t *handle, uintptr_t address, uintptr_t *ptr_addr)
-{
- int result = _Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(void*), ptr_addr);
- if (result < 0) {
- return -1;
- }
- return 0;
-}
-
-static inline int
-read_Py_ssize_t(proc_handle_t *handle, uintptr_t address, Py_ssize_t *size)
-{
- int result = _Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(Py_ssize_t), size);
- if (result < 0) {
- return -1;
- }
- return 0;
-}
-
-static int
-read_py_ptr(proc_handle_t *handle, uintptr_t address, uintptr_t *ptr_addr)
-{
- if (read_ptr(handle, address, ptr_addr)) {
- return -1;
- }
- *ptr_addr &= ~Py_TAG_BITS;
- return 0;
-}
-
-static int
-read_char(proc_handle_t *handle, uintptr_t address, char *result)
-{
- int res = _Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(char), result);
- if (res < 0) {
- return -1;
- }
- return 0;
-}
-
-static int
-read_int(proc_handle_t *handle, uintptr_t address, int *result)
-{
- int res = _Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(int), result);
- if (res < 0) {
- return -1;
- }
- return 0;
-}
-
-static int
-read_unsigned_long(proc_handle_t *handle, uintptr_t address, unsigned long *result)
-{
- int res = _Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(unsigned long), result);
- if (res < 0) {
- return -1;
- }
- return 0;
-}
-
-static int
-read_pyobj(proc_handle_t *handle, uintptr_t address, PyObject *ptr_addr)
-{
- int res = _Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(PyObject), ptr_addr);
- if (res < 0) {
- return -1;
- }
- return 0;
-}
-
-static PyObject *
-read_py_str(
- proc_handle_t *handle,
- _Py_DebugOffsets* debug_offsets,
- uintptr_t address,
- Py_ssize_t max_len
-) {
- assert(max_len > 0);
-
- PyObject *result = NULL;
-
- char *buf = (char *)PyMem_RawMalloc(max_len);
- if (buf == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- if (read_string(handle, debug_offsets, address, buf, max_len)) {
- goto err;
- }
-
- result = PyUnicode_FromString(buf);
- if (result == NULL) {
- goto err;
- }
-
- PyMem_RawFree(buf);
- assert(result != NULL);
- return result;
-
-err:
- PyMem_RawFree(buf);
- return NULL;
-}
-
-static long
-read_py_long(proc_handle_t *handle, _Py_DebugOffsets* offsets, uintptr_t address)
-{
- unsigned int shift = PYLONG_BITS_IN_DIGIT;
-
- Py_ssize_t size;
- uintptr_t lv_tag;
-
- int bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle, address + offsets->long_object.lv_tag,
- sizeof(uintptr_t),
- &lv_tag);
- if (bytes_read < 0) {
- return -1;
- }
-
- int negative = (lv_tag & 3) == 2;
- size = lv_tag >> 3;
-
- if (size == 0) {
- return 0;
- }
-
- digit *digits = (digit *)PyMem_RawMalloc(size * sizeof(digit));
- if (!digits) {
- PyErr_NoMemory();
- return -1;
- }
-
- bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address + offsets->long_object.ob_digit,
- sizeof(digit) * size,
- digits
- );
- if (bytes_read < 0) {
- goto error;
- }
-
- long long value = 0;
-
- // In theory this can overflow, but because of llvm/llvm-project#16778
- // we can't use __builtin_mul_overflow because it fails to link with
- // __muloti4 on aarch64. In practice this is fine because all we're
- // testing here are task numbers that would fit in a single byte.
- for (Py_ssize_t i = 0; i < size; ++i) {
- long long factor = digits[i] * (1UL << (Py_ssize_t)(shift * i));
- value += factor;
- }
- PyMem_RawFree(digits);
- if (negative) {
- value *= -1;
- }
- return (long)value;
-error:
- PyMem_RawFree(digits);
- return -1;
-}
-
-static PyObject *
-parse_task_name(
- proc_handle_t *handle,
- _Py_DebugOffsets* offsets,
- struct _Py_AsyncioModuleDebugOffsets* async_offsets,
- uintptr_t task_address
-) {
- uintptr_t task_name_addr;
- int err = read_py_ptr(
- handle,
- task_address + async_offsets->asyncio_task_object.task_name,
- &task_name_addr);
- if (err) {
- return NULL;
- }
-
- // The task name can be a long or a string so we need to check the type
-
- PyObject task_name_obj;
- err = read_pyobj(
- handle,
- task_name_addr,
- &task_name_obj);
- if (err) {
- return NULL;
- }
-
- unsigned long flags;
- err = read_unsigned_long(
- handle,
- (uintptr_t)task_name_obj.ob_type + offsets->type_object.tp_flags,
- &flags);
- if (err) {
- return NULL;
- }
-
- if ((flags & Py_TPFLAGS_LONG_SUBCLASS)) {
- long res = read_py_long(handle, offsets, task_name_addr);
- if (res == -1) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to get task name");
- return NULL;
- }
- return PyUnicode_FromFormat("Task-%d", res);
- }
-
- if(!(flags & Py_TPFLAGS_UNICODE_SUBCLASS)) {
- PyErr_SetString(PyExc_RuntimeError, "Invalid task name object");
- return NULL;
- }
-
- return read_py_str(
- handle,
- offsets,
- task_name_addr,
- 255
- );
-}
-
-static int
-parse_coro_chain(
- proc_handle_t *handle,
- struct _Py_DebugOffsets* offsets,
- struct _Py_AsyncioModuleDebugOffsets* async_offsets,
- uintptr_t coro_address,
- PyObject *render_to
-) {
- assert((void*)coro_address != NULL);
-
- uintptr_t gen_type_addr;
- int err = read_ptr(
- handle,
- coro_address + sizeof(void*),
- &gen_type_addr);
- if (err) {
- return -1;
- }
-
- uintptr_t gen_name_addr;
- err = read_py_ptr(
- handle,
- coro_address + offsets->gen_object.gi_name,
- &gen_name_addr);
- if (err) {
- return -1;
- }
-
- PyObject *name = read_py_str(
- handle,
- offsets,
- gen_name_addr,
- 255
- );
- if (name == NULL) {
- return -1;
- }
-
- if (PyList_Append(render_to, name)) {
- Py_DECREF(name);
- return -1;
- }
- Py_DECREF(name);
-
- int gi_frame_state;
- err = read_int(
- handle,
- coro_address + offsets->gen_object.gi_frame_state,
- &gi_frame_state);
- if (err) {
- return -1;
- }
-
- if (gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) {
- char owner;
- err = read_char(
- handle,
- coro_address + offsets->gen_object.gi_iframe +
- offsets->interpreter_frame.owner,
- &owner
- );
- if (err) {
- return -1;
- }
- if (owner != FRAME_OWNED_BY_GENERATOR) {
- PyErr_SetString(
- PyExc_RuntimeError,
- "generator doesn't own its frame \\_o_/");
- return -1;
- }
-
- uintptr_t stackpointer_addr;
- err = read_py_ptr(
- handle,
- coro_address + offsets->gen_object.gi_iframe +
- offsets->interpreter_frame.stackpointer,
- &stackpointer_addr);
- if (err) {
- return -1;
- }
-
- if ((void*)stackpointer_addr != NULL) {
- uintptr_t gi_await_addr;
- err = read_py_ptr(
- handle,
- stackpointer_addr - sizeof(void*),
- &gi_await_addr);
- if (err) {
- return -1;
- }
-
- if ((void*)gi_await_addr != NULL) {
- uintptr_t gi_await_addr_type_addr;
- int err = read_ptr(
- handle,
- gi_await_addr + sizeof(void*),
- &gi_await_addr_type_addr);
- if (err) {
- return -1;
- }
-
- if (gen_type_addr == gi_await_addr_type_addr) {
- /* This needs an explanation. We always start with parsing
- native coroutine / generator frames. Ultimately they
- are awaiting on something. That something can be
- a native coroutine frame or... an iterator.
- If it's the latter -- we can't continue building
- our chain. So the condition to bail out of this is
- to do that when the type of the current coroutine
- doesn't match the type of whatever it points to
- in its cr_await.
- */
- err = parse_coro_chain(
- handle,
- offsets,
- async_offsets,
- gi_await_addr,
- render_to
- );
- if (err) {
- return -1;
- }
- }
- }
- }
-
- }
-
- return 0;
-}
-
-
-static int
-parse_task_awaited_by(
- proc_handle_t *handle,
- struct _Py_DebugOffsets* offsets,
- struct _Py_AsyncioModuleDebugOffsets* async_offsets,
- uintptr_t task_address,
- PyObject *awaited_by
-);
-
-
-static int
-parse_task(
- proc_handle_t *handle,
- struct _Py_DebugOffsets* offsets,
- struct _Py_AsyncioModuleDebugOffsets* async_offsets,
- uintptr_t task_address,
- PyObject *render_to
-) {
- char is_task;
- int err = read_char(
- handle,
- task_address + async_offsets->asyncio_task_object.task_is_task,
- &is_task);
- if (err) {
- return -1;
- }
-
- uintptr_t refcnt;
- read_ptr(handle, task_address + sizeof(Py_ssize_t), &refcnt);
-
- PyObject* result = PyList_New(0);
- if (result == NULL) {
- return -1;
- }
-
- PyObject *call_stack = PyList_New(0);
- if (call_stack == NULL) {
- goto err;
- }
- if (PyList_Append(result, call_stack)) {
- Py_DECREF(call_stack);
- goto err;
- }
- /* we can operate on a borrowed one to simplify cleanup */
- Py_DECREF(call_stack);
-
- if (is_task) {
- PyObject *tn = parse_task_name(
- handle, offsets, async_offsets, task_address);
- if (tn == NULL) {
- goto err;
- }
- if (PyList_Append(result, tn)) {
- Py_DECREF(tn);
- goto err;
- }
- Py_DECREF(tn);
-
- uintptr_t coro_addr;
- err = read_py_ptr(
- handle,
- task_address + async_offsets->asyncio_task_object.task_coro,
- &coro_addr);
- if (err) {
- goto err;
- }
-
- if ((void*)coro_addr != NULL) {
- err = parse_coro_chain(
- handle,
- offsets,
- async_offsets,
- coro_addr,
- call_stack
- );
- if (err) {
- goto err;
- }
-
- if (PyList_Reverse(call_stack)) {
- goto err;
- }
- }
- }
-
- if (PyList_Append(render_to, result)) {
- goto err;
- }
-
- PyObject *awaited_by = PyList_New(0);
- if (awaited_by == NULL) {
- goto err;
- }
- if (PyList_Append(result, awaited_by)) {
- Py_DECREF(awaited_by);
- goto err;
- }
- /* we can operate on a borrowed one to simplify cleanup */
- Py_DECREF(awaited_by);
-
- if (parse_task_awaited_by(handle, offsets, async_offsets,
- task_address, awaited_by)
- ) {
- goto err;
- }
- Py_DECREF(result);
-
- return 0;
-
-err:
- Py_DECREF(result);
- return -1;
-}
-
-static int
-parse_tasks_in_set(
- proc_handle_t *handle,
- struct _Py_DebugOffsets* offsets,
- struct _Py_AsyncioModuleDebugOffsets* async_offsets,
- uintptr_t set_addr,
- PyObject *awaited_by
-) {
- uintptr_t set_obj;
- if (read_py_ptr(
- handle,
- set_addr,
- &set_obj)
- ) {
- return -1;
- }
-
- Py_ssize_t num_els;
- if (read_Py_ssize_t(
- handle,
- set_obj + offsets->set_object.used,
- &num_els)
- ) {
- return -1;
- }
-
- Py_ssize_t set_len;
- if (read_Py_ssize_t(
- handle,
- set_obj + offsets->set_object.mask,
- &set_len)
- ) {
- return -1;
- }
- set_len++; // The set contains the `mask+1` element slots.
-
- uintptr_t table_ptr;
- if (read_ptr(
- handle,
- set_obj + offsets->set_object.table,
- &table_ptr)
- ) {
- return -1;
- }
-
- Py_ssize_t i = 0;
- Py_ssize_t els = 0;
- while (i < set_len) {
- uintptr_t key_addr;
- if (read_py_ptr(handle, table_ptr, &key_addr)) {
- return -1;
- }
-
- if ((void*)key_addr != NULL) {
- Py_ssize_t ref_cnt;
- if (read_Py_ssize_t(handle, table_ptr, &ref_cnt)) {
- return -1;
- }
-
- if (ref_cnt) {
- // if 'ref_cnt=0' it's a set dummy marker
-
- if (parse_task(
- handle,
- offsets,
- async_offsets,
- key_addr,
- awaited_by)
- ) {
- return -1;
- }
-
- if (++els == num_els) {
- break;
- }
- }
- }
-
- table_ptr += sizeof(void*) * 2;
- i++;
- }
- return 0;
-}
-
-
-static int
-parse_task_awaited_by(
- proc_handle_t *handle,
- struct _Py_DebugOffsets* offsets,
- struct _Py_AsyncioModuleDebugOffsets* async_offsets,
- uintptr_t task_address,
- PyObject *awaited_by
-) {
- uintptr_t task_ab_addr;
- int err = read_py_ptr(
- handle,
- task_address + async_offsets->asyncio_task_object.task_awaited_by,
- &task_ab_addr);
- if (err) {
- return -1;
- }
-
- if ((void*)task_ab_addr == NULL) {
- return 0;
- }
-
- char awaited_by_is_a_set;
- err = read_char(
- handle,
- task_address + async_offsets->asyncio_task_object.task_awaited_by_is_set,
- &awaited_by_is_a_set);
- if (err) {
- return -1;
- }
-
- if (awaited_by_is_a_set) {
- if (parse_tasks_in_set(
- handle,
- offsets,
- async_offsets,
- task_address + async_offsets->asyncio_task_object.task_awaited_by,
- awaited_by)
- ) {
- return -1;
- }
- } else {
- uintptr_t sub_task;
- if (read_py_ptr(
- handle,
- task_address + async_offsets->asyncio_task_object.task_awaited_by,
- &sub_task)
- ) {
- return -1;
- }
-
- if (parse_task(
- handle,
- offsets,
- async_offsets,
- sub_task,
- awaited_by)
- ) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static int
-parse_code_object(
- proc_handle_t *handle,
- PyObject* result,
- struct _Py_DebugOffsets* offsets,
- uintptr_t address,
- uintptr_t* previous_frame
-) {
- uintptr_t address_of_function_name;
- int bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address + offsets->code_object.name,
- sizeof(void*),
- &address_of_function_name
- );
- if (bytes_read < 0) {
- return -1;
- }
-
- if ((void*)address_of_function_name == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "No function name found");
- return -1;
- }
-
- PyObject* py_function_name = read_py_str(
- handle, offsets, address_of_function_name, 256);
- if (py_function_name == NULL) {
- return -1;
- }
-
- if (PyList_Append(result, py_function_name) == -1) {
- Py_DECREF(py_function_name);
- return -1;
- }
- Py_DECREF(py_function_name);
-
- return 0;
-}
-
-static int
-parse_frame_object(
- proc_handle_t *handle,
- PyObject* result,
- struct _Py_DebugOffsets* offsets,
- uintptr_t address,
- uintptr_t* previous_frame
-) {
- int err;
-
- Py_ssize_t bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address + offsets->interpreter_frame.previous,
- sizeof(void*),
- previous_frame
- );
- if (bytes_read < 0) {
- return -1;
- }
-
- char owner;
- if (read_char(handle, address + offsets->interpreter_frame.owner, &owner)) {
- return -1;
- }
-
- if (owner >= FRAME_OWNED_BY_INTERPRETER) {
- return 0;
- }
-
- uintptr_t address_of_code_object;
- err = read_py_ptr(
- handle,
- address + offsets->interpreter_frame.executable,
- &address_of_code_object
- );
- if (err) {
- return -1;
- }
-
- if ((void*)address_of_code_object == NULL) {
- return 0;
- }
-
- return parse_code_object(
- handle, result, offsets, address_of_code_object, previous_frame);
-}
-
-static int
-parse_async_frame_object(
- proc_handle_t *handle,
- PyObject* result,
- struct _Py_DebugOffsets* offsets,
- uintptr_t address,
- uintptr_t* previous_frame,
- uintptr_t* code_object
-) {
- int err;
-
- Py_ssize_t bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address + offsets->interpreter_frame.previous,
- sizeof(void*),
- previous_frame
- );
- if (bytes_read < 0) {
- return -1;
- }
-
- char owner;
- bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle, address + offsets->interpreter_frame.owner, sizeof(char), &owner);
- if (bytes_read < 0) {
- return -1;
- }
-
- if (owner == FRAME_OWNED_BY_CSTACK || owner == FRAME_OWNED_BY_INTERPRETER) {
- return 0; // C frame
- }
-
- if (owner != FRAME_OWNED_BY_GENERATOR
- && owner != FRAME_OWNED_BY_THREAD) {
- PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n", owner);
- return -1;
- }
-
- err = read_py_ptr(
- handle,
- address + offsets->interpreter_frame.executable,
- code_object
- );
- if (err) {
- return -1;
- }
-
- assert(code_object != NULL);
- if ((void*)*code_object == NULL) {
- return 0;
- }
-
- if (parse_code_object(
- handle, result, offsets, *code_object, previous_frame)) {
- return -1;
- }
-
- return 1;
-}
-
-static int
-read_async_debug(
- proc_handle_t *handle,
- struct _Py_AsyncioModuleDebugOffsets* async_debug
-) {
- uintptr_t async_debug_addr = _Py_RemoteDebug_GetAsyncioDebugAddress(handle);
- if (!async_debug_addr) {
- return -1;
- }
-
- size_t size = sizeof(struct _Py_AsyncioModuleDebugOffsets);
- int result = _Py_RemoteDebug_ReadRemoteMemory(handle, async_debug_addr, size, async_debug);
- return result;
-}
-
-static int
-find_running_frame(
- proc_handle_t *handle,
- uintptr_t runtime_start_address,
- _Py_DebugOffsets* local_debug_offsets,
- uintptr_t *frame
-) {
- uint64_t interpreter_state_list_head =
- local_debug_offsets->runtime_state.interpreters_head;
-
- uintptr_t address_of_interpreter_state;
- int bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- runtime_start_address + interpreter_state_list_head,
- sizeof(void*),
- &address_of_interpreter_state);
- if (bytes_read < 0) {
- return -1;
- }
-
- if (address_of_interpreter_state == 0) {
- PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
- return -1;
- }
-
- uintptr_t address_of_thread;
- bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address_of_interpreter_state +
- local_debug_offsets->interpreter_state.threads_main,
- sizeof(void*),
- &address_of_thread);
- if (bytes_read < 0) {
- return -1;
- }
-
- // No Python frames are available for us (can happen at tear-down).
- if ((void*)address_of_thread != NULL) {
- int err = read_ptr(
- handle,
- address_of_thread + local_debug_offsets->thread_state.current_frame,
- frame);
- if (err) {
- return -1;
- }
- return 0;
- }
-
- *frame = (uintptr_t)NULL;
- return 0;
-}
-
-static int
-find_running_task(
- proc_handle_t *handle,
- uintptr_t runtime_start_address,
- _Py_DebugOffsets *local_debug_offsets,
- struct _Py_AsyncioModuleDebugOffsets *async_offsets,
- uintptr_t *running_task_addr
-) {
- *running_task_addr = (uintptr_t)NULL;
-
- uint64_t interpreter_state_list_head =
- local_debug_offsets->runtime_state.interpreters_head;
-
- uintptr_t address_of_interpreter_state;
- int bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- runtime_start_address + interpreter_state_list_head,
- sizeof(void*),
- &address_of_interpreter_state);
- if (bytes_read < 0) {
- return -1;
- }
-
- if (address_of_interpreter_state == 0) {
- PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
- return -1;
- }
-
- uintptr_t address_of_thread;
- bytes_read = _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- address_of_interpreter_state +
- local_debug_offsets->interpreter_state.threads_head,
- sizeof(void*),
- &address_of_thread);
- if (bytes_read < 0) {
- return -1;
- }
-
- uintptr_t address_of_running_loop;
- // No Python frames are available for us (can happen at tear-down).
- if ((void*)address_of_thread == NULL) {
- return 0;
- }
-
- bytes_read = read_py_ptr(
- handle,
- address_of_thread
- + async_offsets->asyncio_thread_state.asyncio_running_loop,
- &address_of_running_loop);
- if (bytes_read == -1) {
- return -1;
- }
-
- // no asyncio loop is now running
- if ((void*)address_of_running_loop == NULL) {
- return 0;
- }
-
- int err = read_ptr(
- handle,
- address_of_thread
- + async_offsets->asyncio_thread_state.asyncio_running_task,
- running_task_addr);
- if (err) {
- return -1;
- }
-
- return 0;
-}
-
-static int
-append_awaited_by_for_thread(
- proc_handle_t *handle,
- uintptr_t head_addr,
- struct _Py_DebugOffsets *debug_offsets,
- struct _Py_AsyncioModuleDebugOffsets *async_offsets,
- PyObject *result
-) {
- struct llist_node task_node;
-
- if (0 > _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- head_addr,
- sizeof(task_node),
- &task_node))
- {
- return -1;
- }
-
- size_t iteration_count = 0;
- const size_t MAX_ITERATIONS = 2 << 15; // A reasonable upper bound
- while ((uintptr_t)task_node.next != head_addr) {
- if (++iteration_count > MAX_ITERATIONS) {
- PyErr_SetString(PyExc_RuntimeError, "Task list appears corrupted");
- return -1;
- }
-
- if (task_node.next == NULL) {
- PyErr_SetString(
- PyExc_RuntimeError,
- "Invalid linked list structure reading remote memory");
- return -1;
- }
-
- uintptr_t task_addr = (uintptr_t)task_node.next
- - async_offsets->asyncio_task_object.task_node;
-
- PyObject *tn = parse_task_name(
- handle,
- debug_offsets,
- async_offsets,
- task_addr);
- if (tn == NULL) {
- return -1;
- }
-
- PyObject *current_awaited_by = PyList_New(0);
- if (current_awaited_by == NULL) {
- Py_DECREF(tn);
- return -1;
- }
-
- PyObject *result_item = PyTuple_New(2);
- if (result_item == NULL) {
- Py_DECREF(tn);
- Py_DECREF(current_awaited_by);
- return -1;
- }
-
- PyTuple_SET_ITEM(result_item, 0, tn); // steals ref
- PyTuple_SET_ITEM(result_item, 1, current_awaited_by); // steals ref
- if (PyList_Append(result, result_item)) {
- Py_DECREF(result_item);
- return -1;
- }
- Py_DECREF(result_item);
-
- if (parse_task_awaited_by(handle, debug_offsets, async_offsets,
- task_addr, current_awaited_by))
- {
- return -1;
- }
-
- // onto the next one...
- if (0 > _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- (uintptr_t)task_node.next,
- sizeof(task_node),
- &task_node))
- {
- return -1;
- }
- }
-
- return 0;
-}
-
-static int
-append_awaited_by(
- proc_handle_t *handle,
- unsigned long tid,
- uintptr_t head_addr,
- struct _Py_DebugOffsets *debug_offsets,
- struct _Py_AsyncioModuleDebugOffsets *async_offsets,
- PyObject *result)
-{
- PyObject *tid_py = PyLong_FromUnsignedLong(tid);
- if (tid_py == NULL) {
- return -1;
- }
-
- PyObject *result_item = PyTuple_New(2);
- if (result_item == NULL) {
- Py_DECREF(tid_py);
- return -1;
- }
-
- PyObject* awaited_by_for_thread = PyList_New(0);
- if (awaited_by_for_thread == NULL) {
- Py_DECREF(tid_py);
- Py_DECREF(result_item);
- return -1;
- }
-
- PyTuple_SET_ITEM(result_item, 0, tid_py); // steals ref
- PyTuple_SET_ITEM(result_item, 1, awaited_by_for_thread); // steals ref
- if (PyList_Append(result, result_item)) {
- Py_DECREF(result_item);
- return -1;
- }
- Py_DECREF(result_item);
-
- if (append_awaited_by_for_thread(
- handle,
- head_addr,
- debug_offsets,
- async_offsets,
- awaited_by_for_thread))
- {
- return -1;
- }
-
- return 0;
-}
-
-static PyObject*
-get_all_awaited_by(PyObject* self, PyObject* args)
-{
-#if (!defined(__linux__) && !defined(__APPLE__)) && !defined(MS_WINDOWS) || \
- (defined(__linux__) && !HAVE_PROCESS_VM_READV)
- PyErr_SetString(
- PyExc_RuntimeError,
- "get_all_awaited_by is not implemented on this platform");
- return NULL;
-#endif
-
- int pid;
- if (!PyArg_ParseTuple(args, "i", &pid)) {
- return NULL;
- }
-
- proc_handle_t the_handle;
- proc_handle_t *handle = &the_handle;
- if (_Py_RemoteDebug_InitProcHandle(handle, pid) < 0) {
- return 0;
- }
-
- uintptr_t runtime_start_addr = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
- if (runtime_start_addr == 0) {
- if (!PyErr_Occurred()) {
- PyErr_SetString(
- PyExc_RuntimeError, "Failed to get .PyRuntime address");
- }
- return NULL;
- }
- struct _Py_DebugOffsets local_debug_offsets;
-
- if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_addr, &local_debug_offsets)) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
- return NULL;
- }
-
- struct _Py_AsyncioModuleDebugOffsets local_async_debug;
- if (read_async_debug(handle, &local_async_debug)) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
- return NULL;
- }
-
- PyObject *result = PyList_New(0);
- if (result == NULL) {
- return NULL;
- }
-
- uint64_t interpreter_state_list_head =
- local_debug_offsets.runtime_state.interpreters_head;
-
- uintptr_t interpreter_state_addr;
- if (0 > _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- runtime_start_addr + interpreter_state_list_head,
- sizeof(void*),
- &interpreter_state_addr))
- {
- goto result_err;
- }
-
- uintptr_t thread_state_addr;
- unsigned long tid = 0;
- if (0 > _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- interpreter_state_addr
- + local_debug_offsets.interpreter_state.threads_head,
- sizeof(void*),
- &thread_state_addr))
- {
- goto result_err;
- }
-
- uintptr_t head_addr;
- while (thread_state_addr != 0) {
- if (0 > _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- thread_state_addr
- + local_debug_offsets.thread_state.native_thread_id,
- sizeof(tid),
- &tid))
- {
- goto result_err;
- }
-
- head_addr = thread_state_addr
- + local_async_debug.asyncio_thread_state.asyncio_tasks_head;
-
- if (append_awaited_by(handle, tid, head_addr, &local_debug_offsets,
- &local_async_debug, result))
- {
- goto result_err;
- }
-
- if (0 > _Py_RemoteDebug_ReadRemoteMemory(
- handle,
- thread_state_addr + local_debug_offsets.thread_state.next,
- sizeof(void*),
- &thread_state_addr))
- {
- goto result_err;
- }
- }
-
- head_addr = interpreter_state_addr
- + local_async_debug.asyncio_interpreter_state.asyncio_tasks_head;
-
- // On top of a per-thread task lists used by default by asyncio to avoid
- // contention, there is also a fallback per-interpreter list of tasks;
- // any tasks still pending when a thread is destroyed will be moved to the
- // per-interpreter task list. It's unlikely we'll find anything here, but
- // interesting for debugging.
- if (append_awaited_by(handle, 0, head_addr, &local_debug_offsets,
- &local_async_debug, result))
- {
- goto result_err;
- }
-
- _Py_RemoteDebug_CleanupProcHandle(handle);
- return result;
-
-result_err:
- Py_DECREF(result);
- _Py_RemoteDebug_CleanupProcHandle(handle);
- return NULL;
-}
-
-static PyObject*
-get_stack_trace(PyObject* self, PyObject* args)
-{
-#if (!defined(__linux__) && !defined(__APPLE__)) && !defined(MS_WINDOWS) || \
- (defined(__linux__) && !HAVE_PROCESS_VM_READV)
- PyErr_SetString(
- PyExc_RuntimeError,
- "get_stack_trace is not supported on this platform");
- return NULL;
-#endif
-
- int pid;
- if (!PyArg_ParseTuple(args, "i", &pid)) {
- return NULL;
- }
-
- proc_handle_t the_handle;
- proc_handle_t *handle = &the_handle;
- if (_Py_RemoteDebug_InitProcHandle(handle, pid) < 0) {
- return 0;
- }
-
- PyObject* result = NULL;
-
- uintptr_t runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
- if (runtime_start_address == 0) {
- if (!PyErr_Occurred()) {
- PyErr_SetString(
- PyExc_RuntimeError, "Failed to get .PyRuntime address");
- }
- goto result_err;
- }
- struct _Py_DebugOffsets local_debug_offsets;
-
- if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
- goto result_err;
- }
-
- uintptr_t address_of_current_frame;
- if (find_running_frame(
- handle, runtime_start_address, &local_debug_offsets,
- &address_of_current_frame)
- ) {
- goto result_err;
- }
-
- result = PyList_New(0);
- if (result == NULL) {
- goto result_err;
- }
-
- while ((void*)address_of_current_frame != NULL) {
- if (parse_frame_object(
- handle,
- result,
- &local_debug_offsets,
- address_of_current_frame,
- &address_of_current_frame)
- < 0)
- {
- Py_DECREF(result);
- goto result_err;
- }
- }
-
-result_err:
- _Py_RemoteDebug_CleanupProcHandle(handle);
- return result;
-}
-
-static PyObject*
-get_async_stack_trace(PyObject* self, PyObject* args)
-{
-#if (!defined(__linux__) && !defined(__APPLE__)) && !defined(MS_WINDOWS) || \
- (defined(__linux__) && !HAVE_PROCESS_VM_READV)
- PyErr_SetString(
- PyExc_RuntimeError,
- "get_stack_trace is not supported on this platform");
- return NULL;
-#endif
- int pid;
-
- if (!PyArg_ParseTuple(args, "i", &pid)) {
- return NULL;
- }
-
- proc_handle_t the_handle;
- proc_handle_t *handle = &the_handle;
- if (_Py_RemoteDebug_InitProcHandle(handle, pid) < 0) {
- return 0;
- }
-
- uintptr_t runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
- if (runtime_start_address == 0) {
- if (!PyErr_Occurred()) {
- PyErr_SetString(
- PyExc_RuntimeError, "Failed to get .PyRuntime address");
- }
- return NULL;
- }
- struct _Py_DebugOffsets local_debug_offsets;
-
- if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
- return NULL;
- }
-
- struct _Py_AsyncioModuleDebugOffsets local_async_debug;
- if (read_async_debug(handle, &local_async_debug)) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
- return NULL;
- }
-
- PyObject* result = PyList_New(1);
- if (result == NULL) {
- return NULL;
- }
- PyObject* calls = PyList_New(0);
- if (calls == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- if (PyList_SetItem(result, 0, calls)) { /* steals ref to 'calls' */
- Py_DECREF(result);
- Py_DECREF(calls);
- return NULL;
- }
-
- uintptr_t running_task_addr = (uintptr_t)NULL;
- if (find_running_task(
- handle, runtime_start_address, &local_debug_offsets, &local_async_debug,
- &running_task_addr)
- ) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to find running task");
- goto result_err;
- }
-
- if ((void*)running_task_addr == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "No running task found");
- goto result_err;
- }
-
- uintptr_t running_coro_addr;
- if (read_py_ptr(
- handle,
- running_task_addr + local_async_debug.asyncio_task_object.task_coro,
- &running_coro_addr
- )) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to read running task coro");
- goto result_err;
- }
-
- if ((void*)running_coro_addr == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL");
- goto result_err;
- }
-
- // note: genobject's gi_iframe is an embedded struct so the address to
- // the offset leads directly to its first field: f_executable
- uintptr_t address_of_running_task_code_obj;
- if (read_py_ptr(
- handle,
- running_coro_addr + local_debug_offsets.gen_object.gi_iframe,
- &address_of_running_task_code_obj
- )) {
- goto result_err;
- }
-
- if ((void*)address_of_running_task_code_obj == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "Running task code object is NULL");
- goto result_err;
- }
-
- uintptr_t address_of_current_frame;
- if (find_running_frame(
- handle, runtime_start_address, &local_debug_offsets,
- &address_of_current_frame)
- ) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to find running frame");
- goto result_err;
- }
-
- uintptr_t address_of_code_object;
- while ((void*)address_of_current_frame != NULL) {
- int res = parse_async_frame_object(
- handle,
- calls,
- &local_debug_offsets,
- address_of_current_frame,
- &address_of_current_frame,
- &address_of_code_object
- );
-
- if (res < 0) {
- PyErr_SetString(PyExc_RuntimeError, "Failed to parse async frame object");
- goto result_err;
- }
-
- if (address_of_code_object == address_of_running_task_code_obj) {
- break;
- }
- }
-
- PyObject *tn = parse_task_name(
- handle, &local_debug_offsets, &local_async_debug, running_task_addr);
- if (tn == NULL) {
- goto result_err;
- }
- if (PyList_Append(result, tn)) {
- Py_DECREF(tn);
- goto result_err;
- }
- Py_DECREF(tn);
-
- PyObject* awaited_by = PyList_New(0);
- if (awaited_by == NULL) {
- goto result_err;
- }
- if (PyList_Append(result, awaited_by)) {
- Py_DECREF(awaited_by);
- goto result_err;
- }
- Py_DECREF(awaited_by);
-
- if (parse_task_awaited_by(
- handle, &local_debug_offsets, &local_async_debug,
- running_task_addr, awaited_by)
- ) {
- goto result_err;
- }
-
- _Py_RemoteDebug_CleanupProcHandle(handle);
- return result;
-
-result_err:
- _Py_RemoteDebug_CleanupProcHandle(handle);
- Py_DECREF(result);
- return NULL;
-}
-
-
-static PyMethodDef methods[] = {
- {"get_stack_trace", get_stack_trace, METH_VARARGS,
- "Get the Python stack from a given pod"},
- {"get_async_stack_trace", get_async_stack_trace, METH_VARARGS,
- "Get the asyncio stack from a given pid"},
- {"get_all_awaited_by", get_all_awaited_by, METH_VARARGS,
- "Get all tasks and their awaited_by from a given pid"},
- {NULL, NULL, 0, NULL},
-};
-
-static struct PyModuleDef module = {
- .m_base = PyModuleDef_HEAD_INIT,
- .m_name = "_testexternalinspection",
- .m_size = -1,
- .m_methods = methods,
-};
-
-PyMODINIT_FUNC
-PyInit__testexternalinspection(void)
-{
- PyObject* mod = PyModule_Create(&module);
- if (mod == NULL) {
- return NULL;
- }
-#ifdef Py_GIL_DISABLED
- PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED);
-#endif
- int rc = PyModule_AddIntConstant(
- mod, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV);
- if (rc < 0) {
- Py_DECREF(mod);
- return NULL;
- }
- return mod;
-}
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 065f4135b75..fdf22a0c994 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -21,6 +21,7 @@
#include "pycore_fileutils.h" // _Py_normpath()
#include "pycore_flowgraph.h" // _PyCompile_OptimizeCfg()
#include "pycore_frame.h" // _PyInterpreterFrame
+#include "pycore_function.h" // _PyFunction_GET_BUILTINS
#include "pycore_gc.h" // PyGC_Head
#include "pycore_hashtable.h" // _Py_hashtable_new()
#include "pycore_import.h" // _PyImport_ClearExtension()
@@ -1000,9 +1001,213 @@ get_co_localskinds(PyObject *self, PyObject *arg)
}
static PyObject *
-jit_enabled(PyObject *self, PyObject *arg)
+get_code_var_counts(PyObject *self, PyObject *_args, PyObject *_kwargs)
{
- return PyBool_FromLong(_PyInterpreterState_GET()->jit);
+ PyThreadState *tstate = _PyThreadState_GET();
+ PyObject *codearg;
+ PyObject *globalnames = NULL;
+ PyObject *attrnames = NULL;
+ PyObject *globalsns = NULL;
+ PyObject *builtinsns = NULL;
+ static char *kwlist[] = {"code", "globalnames", "attrnames", "globalsns",
+ "builtinsns", NULL};
+ if (!PyArg_ParseTupleAndKeywords(_args, _kwargs,
+ "O|OOO!O!:get_code_var_counts", kwlist,
+ &codearg, &globalnames, &attrnames,
+ &PyDict_Type, &globalsns, &PyDict_Type, &builtinsns))
+ {
+ return NULL;
+ }
+ if (PyFunction_Check(codearg)) {
+ if (globalsns == NULL) {
+ globalsns = PyFunction_GET_GLOBALS(codearg);
+ }
+ if (builtinsns == NULL) {
+ builtinsns = _PyFunction_GET_BUILTINS(codearg);
+ }
+ codearg = PyFunction_GET_CODE(codearg);
+ }
+ else if (!PyCode_Check(codearg)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a code object or a function");
+ return NULL;
+ }
+ PyCodeObject *code = (PyCodeObject *)codearg;
+
+ _PyCode_var_counts_t counts = {0};
+ _PyCode_GetVarCounts(code, &counts);
+ if (_PyCode_SetUnboundVarCounts(
+ tstate, code, &counts, globalnames, attrnames,
+ globalsns, builtinsns) < 0)
+ {
+ return NULL;
+ }
+
+#define SET_COUNT(DICT, STRUCT, NAME) \
+ do { \
+ PyObject *count = PyLong_FromLong(STRUCT.NAME); \
+ if (count == NULL) { \
+ goto error; \
+ } \
+ int res = PyDict_SetItemString(DICT, #NAME, count); \
+ Py_DECREF(count); \
+ if (res < 0) { \
+ goto error; \
+ } \
+ } while (0)
+
+ PyObject *locals = NULL;
+ PyObject *args = NULL;
+ PyObject *cells = NULL;
+ PyObject *hidden = NULL;
+ PyObject *unbound = NULL;
+ PyObject *globals = NULL;
+ PyObject *countsobj = PyDict_New();
+ if (countsobj == NULL) {
+ return NULL;
+ }
+ SET_COUNT(countsobj, counts, total);
+
+ // locals
+ locals = PyDict_New();
+ if (locals == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(countsobj, "locals", locals) < 0) {
+ goto error;
+ }
+ SET_COUNT(locals, counts.locals, total);
+
+ // locals.args
+ args = PyDict_New();
+ if (args == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(locals, "args", args) < 0) {
+ goto error;
+ }
+ SET_COUNT(args, counts.locals.args, total);
+ SET_COUNT(args, counts.locals.args, numposonly);
+ SET_COUNT(args, counts.locals.args, numposorkw);
+ SET_COUNT(args, counts.locals.args, numkwonly);
+ SET_COUNT(args, counts.locals.args, varargs);
+ SET_COUNT(args, counts.locals.args, varkwargs);
+
+ // locals.numpure
+ SET_COUNT(locals, counts.locals, numpure);
+
+ // locals.cells
+ cells = PyDict_New();
+ if (cells == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(locals, "cells", cells) < 0) {
+ goto error;
+ }
+ SET_COUNT(cells, counts.locals.cells, total);
+ SET_COUNT(cells, counts.locals.cells, numargs);
+ SET_COUNT(cells, counts.locals.cells, numothers);
+
+ // locals.hidden
+ hidden = PyDict_New();
+ if (hidden == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(locals, "hidden", hidden) < 0) {
+ goto error;
+ }
+ SET_COUNT(hidden, counts.locals.hidden, total);
+ SET_COUNT(hidden, counts.locals.hidden, numpure);
+ SET_COUNT(hidden, counts.locals.hidden, numcells);
+
+ // numfree
+ SET_COUNT(countsobj, counts, numfree);
+
+ // unbound
+ unbound = PyDict_New();
+ if (unbound == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(countsobj, "unbound", unbound) < 0) {
+ goto error;
+ }
+ SET_COUNT(unbound, counts.unbound, total);
+ SET_COUNT(unbound, counts.unbound, numattrs);
+ SET_COUNT(unbound, counts.unbound, numunknown);
+
+ // unbound.globals
+ globals = PyDict_New();
+ if (globals == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(unbound, "globals", globals) < 0) {
+ goto error;
+ }
+ SET_COUNT(globals, counts.unbound.globals, total);
+ SET_COUNT(globals, counts.unbound.globals, numglobal);
+ SET_COUNT(globals, counts.unbound.globals, numbuiltin);
+ SET_COUNT(globals, counts.unbound.globals, numunknown);
+
+#undef SET_COUNT
+
+ Py_DECREF(locals);
+ Py_DECREF(args);
+ Py_DECREF(cells);
+ Py_DECREF(hidden);
+ Py_DECREF(unbound);
+ Py_DECREF(globals);
+ return countsobj;
+
+error:
+ Py_DECREF(countsobj);
+ Py_XDECREF(locals);
+ Py_XDECREF(args);
+ Py_XDECREF(cells);
+ Py_XDECREF(hidden);
+ Py_XDECREF(unbound);
+ Py_XDECREF(globals);
+ return NULL;
+}
+
+static PyObject *
+verify_stateless_code(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ PyObject *codearg;
+ PyObject *globalnames = NULL;
+ PyObject *globalsns = NULL;
+ PyObject *builtinsns = NULL;
+ static char *kwlist[] = {"code", "globalnames",
+ "globalsns", "builtinsns", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O|O!O!O!:get_code_var_counts", kwlist,
+ &codearg, &PySet_Type, &globalnames,
+ &PyDict_Type, &globalsns, &PyDict_Type, &builtinsns))
+ {
+ return NULL;
+ }
+ if (PyFunction_Check(codearg)) {
+ if (globalsns == NULL) {
+ globalsns = PyFunction_GET_GLOBALS(codearg);
+ }
+ if (builtinsns == NULL) {
+ builtinsns = _PyFunction_GET_BUILTINS(codearg);
+ }
+ codearg = PyFunction_GET_CODE(codearg);
+ }
+ else if (!PyCode_Check(codearg)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a code object or a function");
+ return NULL;
+ }
+ PyCodeObject *code = (PyCodeObject *)codearg;
+
+ if (_PyCode_VerifyStateless(
+ tstate, code, globalnames, globalsns, builtinsns) < 0)
+ {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
#ifdef _Py_TIER2
@@ -1489,11 +1694,12 @@ create_interpreter(PyObject *self, PyObject *args, PyObject *kwargs)
static PyObject *
destroy_interpreter(PyObject *self, PyObject *args, PyObject *kwargs)
{
- static char *kwlist[] = {"id", NULL};
+ static char *kwlist[] = {"id", "basic", NULL};
PyObject *idobj = NULL;
+ int basic = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "O:destroy_interpreter", kwlist,
- &idobj))
+ "O|p:destroy_interpreter", kwlist,
+ &idobj, &basic))
{
return NULL;
}
@@ -1503,7 +1709,27 @@ destroy_interpreter(PyObject *self, PyObject *args, PyObject *kwargs)
return NULL;
}
- _PyXI_EndInterpreter(interp, NULL, NULL);
+ if (basic)
+ {
+ // Test the basic Py_EndInterpreter with weird out of order thread states
+ PyThreadState *t1, *t2;
+ PyThreadState *prev;
+ t1 = interp->threads.head;
+ if (t1 == NULL) {
+ t1 = PyThreadState_New(interp);
+ }
+ t2 = PyThreadState_New(interp);
+ prev = PyThreadState_Swap(t2);
+ PyThreadState_Clear(t1);
+ PyThreadState_Delete(t1);
+ Py_EndInterpreter(t2);
+ PyThreadState_Swap(prev);
+ }
+ else
+ {
+ // use the cross interpreter _PyXI_EndInterpreter normally
+ _PyXI_EndInterpreter(interp, NULL, NULL);
+ }
Py_RETURN_NONE;
}
@@ -1563,9 +1789,9 @@ finally:
/* To run some code in a sub-interpreter.
-Generally you can use test.support.interpreters,
+Generally you can use the interpreters module,
but we keep this helper as a distinct implementation.
-That's especially important for testing test.support.interpreters.
+That's especially important for testing the interpreters module.
*/
static PyObject *
run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -1769,7 +1995,14 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs)
return NULL;
}
if (strcmp(mode, "xidata") == 0) {
- if (_PyObject_GetXIData(tstate, obj, xidata) != 0) {
+ if (_PyObject_GetXIDataNoFallback(tstate, obj, xidata) != 0) {
+ goto error;
+ }
+ }
+ else if (strcmp(mode, "fallback") == 0) {
+ xidata_fallback_t fallback = _PyXIDATA_FULL_FALLBACK;
+ if (_PyObject_GetXIData(tstate, obj, fallback, xidata) != 0)
+ {
goto error;
}
}
@@ -1783,6 +2016,26 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs)
goto error;
}
}
+ else if (strcmp(mode, "code") == 0) {
+ if (_PyCode_GetXIData(tstate, obj, xidata) != 0) {
+ goto error;
+ }
+ }
+ else if (strcmp(mode, "func") == 0) {
+ if (_PyFunction_GetXIData(tstate, obj, xidata) != 0) {
+ goto error;
+ }
+ }
+ else if (strcmp(mode, "script") == 0) {
+ if (_PyCode_GetScriptXIData(tstate, obj, xidata) != 0) {
+ goto error;
+ }
+ }
+ else if (strcmp(mode, "script-pure") == 0) {
+ if (_PyCode_GetPureScriptXIData(tstate, obj, xidata) != 0) {
+ goto error;
+ }
+ }
else {
PyErr_Format(PyExc_ValueError, "unsupported mode %R", modeobj);
goto error;
@@ -2125,7 +2378,10 @@ static PyMethodDef module_functions[] = {
{"code_returns_only_none", code_returns_only_none, METH_O, NULL},
{"get_co_framesize", get_co_framesize, METH_O, NULL},
{"get_co_localskinds", get_co_localskinds, METH_O, NULL},
- {"jit_enabled", jit_enabled, METH_NOARGS, NULL},
+ {"get_code_var_counts", _PyCFunction_CAST(get_code_var_counts),
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"verify_stateless_code", _PyCFunction_CAST(verify_stateless_code),
+ METH_VARARGS | METH_KEYWORDS, NULL},
#ifdef _Py_TIER2
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
{"invalidate_executors", invalidate_executors, METH_O, NULL},
diff --git a/Modules/_testinternalcapi/test_lock.c b/Modules/_testinternalcapi/test_lock.c
index 8d678412fe7..8d8cb992b0e 100644
--- a/Modules/_testinternalcapi/test_lock.c
+++ b/Modules/_testinternalcapi/test_lock.c
@@ -57,7 +57,10 @@ lock_thread(void *arg)
_Py_atomic_store_int(&test_data->started, 1);
PyMutex_Lock(m);
- assert(m->_bits == 1);
+ // gh-135641: in rare cases the lock may still have `_Py_HAS_PARKED` set
+ // (m->_bits == 3) due to bucket collisions in the parking lot hash table
+ // between this mutex and the `test_data.done` event.
+ assert(m->_bits == 1 || m->_bits == 3);
PyMutex_Unlock(m);
assert(m->_bits == 0);
diff --git a/Modules/_testlimitedcapi/import.c b/Modules/_testlimitedcapi/import.c
index 3707dbedeea..f85daee57d7 100644
--- a/Modules/_testlimitedcapi/import.c
+++ b/Modules/_testlimitedcapi/import.c
@@ -108,20 +108,19 @@ pyimport_importmodule(PyObject *Py_UNUSED(module), PyObject *args)
}
-/* Test PyImport_ImportModuleNoBlock() */
+/* Test PyImport_ImportModuleNoBlock() (removed in 3.15) */
static PyObject *
pyimport_importmodulenoblock(PyObject *Py_UNUSED(module), PyObject *args)
{
+ // Get the function from the stable ABI.
+ PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock(const char *name);
+
const char *name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "z#", &name, &size)) {
return NULL;
}
-
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
return PyImport_ImportModuleNoBlock(name);
- _Py_COMP_DIAG_POP
}
diff --git a/Modules/_testlimitedcapi/sys.c b/Modules/_testlimitedcapi/sys.c
index 7d8b7a8569e..cec7f8ab612 100644
--- a/Modules/_testlimitedcapi/sys.c
+++ b/Modules/_testlimitedcapi/sys.c
@@ -1,8 +1,77 @@
+#include "pyconfig.h" // Py_GIL_DISABLED
+// Need limited C API version 3.15 for PySys_GetAttr() etc
+#if !defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API)
+# define Py_LIMITED_API 0x030f0000
+#endif
#include "parts.h"
#include "util.h"
static PyObject *
+sys_getattr(PyObject *Py_UNUSED(module), PyObject *name)
+{
+ NULLABLE(name);
+ return PySys_GetAttr(name);
+}
+
+static PyObject *
+sys_getattrstring(PyObject *Py_UNUSED(module), PyObject *arg)
+{
+ const char *name;
+ Py_ssize_t size;
+ if (!PyArg_Parse(arg, "z#", &name, &size)) {
+ return NULL;
+ }
+ return PySys_GetAttrString(name);
+}
+
+static PyObject *
+sys_getoptionalattr(PyObject *Py_UNUSED(module), PyObject *name)
+{
+ PyObject *value = UNINITIALIZED_PTR;
+ NULLABLE(name);
+
+ switch (PySys_GetOptionalAttr(name, &value)) {
+ case -1:
+ assert(value == NULL);
+ assert(PyErr_Occurred());
+ return NULL;
+ case 0:
+ assert(value == NULL);
+ return Py_NewRef(PyExc_AttributeError);
+ case 1:
+ return value;
+ default:
+ Py_FatalError("PySys_GetOptionalAttr() returned invalid code");
+ }
+}
+
+static PyObject *
+sys_getoptionalattrstring(PyObject *Py_UNUSED(module), PyObject *arg)
+{
+ PyObject *value = UNINITIALIZED_PTR;
+ const char *name;
+ Py_ssize_t size;
+ if (!PyArg_Parse(arg, "z#", &name, &size)) {
+ return NULL;
+ }
+
+ switch (PySys_GetOptionalAttrString(name, &value)) {
+ case -1:
+ assert(value == NULL);
+ assert(PyErr_Occurred());
+ return NULL;
+ case 0:
+ assert(value == NULL);
+ return Py_NewRef(PyExc_AttributeError);
+ case 1:
+ return value;
+ default:
+ Py_FatalError("PySys_GetOptionalAttrString() returned invalid code");
+ }
+}
+
+static PyObject *
sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg)
{
const char *name;
@@ -39,6 +108,10 @@ sys_getxoptions(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(ignored))
static PyMethodDef test_methods[] = {
+ {"sys_getattr", sys_getattr, METH_O},
+ {"sys_getattrstring", sys_getattrstring, METH_O},
+ {"sys_getoptionalattr", sys_getoptionalattr, METH_O},
+ {"sys_getoptionalattrstring", sys_getoptionalattrstring, METH_O},
{"sys_getobject", sys_getobject, METH_O},
{"sys_setobject", sys_setobject, METH_VARARGS},
{"sys_getxoptions", sys_getxoptions, METH_NOARGS},
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 9776a32755d..b6ccca943f2 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -10,7 +10,6 @@
#include "pycore_object_deferred.h" // _PyObject_SetDeferredRefcount()
#include "pycore_pylifecycle.h"
#include "pycore_pystate.h" // _PyThreadState_SetCurrent()
-#include "pycore_sysmodule.h" // _PySys_GetOptionalAttr()
#include "pycore_time.h" // _PyTime_FromSeconds()
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
@@ -19,8 +18,6 @@
# include <signal.h> // SIGINT
#endif
-#include "clinic/_threadmodule.c.h"
-
// ThreadError is just an alias to PyExc_RuntimeError
#define ThreadError PyExc_RuntimeError
@@ -31,6 +28,7 @@ static struct PyModuleDef thread_module;
typedef struct {
PyTypeObject *excepthook_type;
PyTypeObject *lock_type;
+ PyTypeObject *rlock_type;
PyTypeObject *local_type;
PyTypeObject *local_dummy_type;
PyTypeObject *thread_handle_type;
@@ -48,6 +46,17 @@ get_thread_state(PyObject *module)
return (thread_module_state *)state;
}
+static inline thread_module_state*
+get_thread_state_by_cls(PyTypeObject *cls)
+{
+ // Use PyType_GetModuleByDef() to handle (R)Lock subclasses.
+ PyObject *module = PyType_GetModuleByDef(cls, &thread_module);
+ if (module == NULL) {
+ return NULL;
+ }
+ return get_thread_state(module);
+}
+
#ifdef MS_WINDOWS
typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*);
@@ -59,9 +68,14 @@ static PF_SET_THREAD_DESCRIPTION pSetThreadDescription = NULL;
/*[clinic input]
module _thread
+class _thread.lock "lockobject *" "clinic_state()->lock_type"
+class _thread.RLock "rlockobject *" "clinic_state()->rlock_type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=be8dbe5cc4b16df7]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c5a0f8c492a0c263]*/
+#define clinic_state() get_thread_state_by_cls(type)
+#include "clinic/_threadmodule.c.h"
+#undef clinic_state
// _ThreadHandle type
@@ -281,6 +295,12 @@ _PyThread_AfterFork(struct _pythread_runtime_state *state)
continue;
}
+ // Keep handles for threads that have not been started yet. They are
+ // safe to start in the child process.
+ if (handle->state == THREAD_HANDLE_NOT_STARTED) {
+ continue;
+ }
+
// Mark all threads as done. Any attempts to join or detach the
// underlying OS thread (if any) could crash. We are the only thread;
// it's safe to set this non-atomically.
@@ -916,25 +936,21 @@ lock__at_fork_reinit(PyObject *op, PyObject *Py_UNUSED(dummy))
}
#endif /* HAVE_FORK */
-static lockobject *newlockobject(PyObject *module);
+/*[clinic input]
+@classmethod
+_thread.lock.__new__ as lock_new
+[clinic start generated code]*/
static PyObject *
-lock_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+lock_new_impl(PyTypeObject *type)
+/*[clinic end generated code: output=eab660d5a4c05c8a input=260208a4e277d250]*/
{
- // convert to AC?
- if (!_PyArg_NoKeywords("lock", kwargs)) {
- goto error;
- }
- if (!_PyArg_CheckPositional("lock", PyTuple_GET_SIZE(args), 0, 0)) {
- goto error;
+ lockobject *self = (lockobject *)type->tp_alloc(type, 0);
+ if (self == NULL) {
+ return NULL;
}
-
- PyObject *module = PyType_GetModuleByDef(type, &thread_module);
- assert(module != NULL);
- return (PyObject *)newlockobject(module);
-
-error:
- return NULL;
+ self->lock = (PyMutex){0};
+ return (PyObject *)self;
}
@@ -1011,6 +1027,11 @@ rlock_traverse(PyObject *self, visitproc visit, void *arg)
return 0;
}
+static int
+rlock_locked_impl(rlockobject *self)
+{
+ return PyMutex_IsLocked(&self->lock.mutex);
+}
static void
rlock_dealloc(PyObject *self)
@@ -1100,7 +1121,7 @@ static PyObject *
rlock_locked(PyObject *op, PyObject *Py_UNUSED(ignored))
{
rlockobject *self = rlockobject_CAST(op);
- int is_locked = _PyRecursiveMutex_IsLockedByCurrentThread(&self->lock);
+ int is_locked = rlock_locked_impl(self);
return PyBool_FromLong(is_locked);
}
@@ -1186,8 +1207,14 @@ PyDoc_STRVAR(rlock_is_owned_doc,
\n\
For internal use by `threading.Condition`.");
+/*[clinic input]
+@classmethod
+_thread.RLock.__new__ as rlock_new
+[clinic start generated code]*/
+
static PyObject *
-rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+rlock_new_impl(PyTypeObject *type)
+/*[clinic end generated code: output=bb4fb1edf6818df5 input=013591361bf1ac6e]*/
{
rlockobject *self = (rlockobject *) type->tp_alloc(type, 0);
if (self == NULL) {
@@ -1202,10 +1229,17 @@ rlock_repr(PyObject *op)
{
rlockobject *self = rlockobject_CAST(op);
PyThread_ident_t owner = self->lock.thread;
- size_t count = self->lock.level + 1;
+ int locked = rlock_locked_impl(self);
+ size_t count;
+ if (locked) {
+ count = self->lock.level + 1;
+ }
+ else {
+ count = 0;
+ }
return PyUnicode_FromFormat(
"<%s %s object owner=%" PY_FORMAT_THREAD_IDENT_T " count=%zu at %p>",
- owner ? "locked" : "unlocked",
+ locked ? "locked" : "unlocked",
Py_TYPE(self)->tp_name, owner,
count, self);
}
@@ -1267,20 +1301,6 @@ static PyType_Spec rlock_type_spec = {
.slots = rlock_type_slots,
};
-static lockobject *
-newlockobject(PyObject *module)
-{
- thread_module_state *state = get_thread_state(module);
-
- PyTypeObject *type = state->lock_type;
- lockobject *self = (lockobject *)type->tp_alloc(type, 0);
- if (self == NULL) {
- return NULL;
- }
- self->lock = (PyMutex){0};
- return self;
-}
-
/* Thread-local objects */
/* Quick overview:
@@ -1345,9 +1365,7 @@ static void
localdummy_dealloc(PyObject *op)
{
localdummyobject *self = localdummyobject_CAST(op);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
PyTypeObject *tp = Py_TYPE(self);
tp->tp_free(self);
Py_DECREF(tp);
@@ -2035,7 +2053,8 @@ Note: the default signal handler for SIGINT raises ``KeyboardInterrupt``."
static PyObject *
thread_PyThread_allocate_lock(PyObject *module, PyObject *Py_UNUSED(ignored))
{
- return (PyObject *) newlockobject(module);
+ thread_module_state *state = get_thread_state(module);
+ return lock_new_impl(state->lock_type);
}
PyDoc_STRVAR(allocate_lock_doc,
@@ -2268,7 +2287,7 @@ thread_excepthook(PyObject *module, PyObject *args)
PyObject *thread = PyStructSequence_GET_ITEM(args, 3);
PyObject *file;
- if (_PySys_GetOptionalAttr( &_Py_ID(stderr), &file) < 0) {
+ if (PySys_GetOptionalAttr( &_Py_ID(stderr), &file) < 0) {
return NULL;
}
if (file == NULL || file == Py_None) {
@@ -2645,15 +2664,13 @@ thread_module_exec(PyObject *module)
}
// RLock
- PyTypeObject *rlock_type = (PyTypeObject *)PyType_FromSpec(&rlock_type_spec);
- if (rlock_type == NULL) {
+ state->rlock_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &rlock_type_spec, NULL);
+ if (state->rlock_type == NULL) {
return -1;
}
- if (PyModule_AddType(module, rlock_type) < 0) {
- Py_DECREF(rlock_type);
+ if (PyModule_AddType(module, state->rlock_type) < 0) {
return -1;
}
- Py_DECREF(rlock_type);
// Local dummy
state->local_dummy_type = (PyTypeObject *)PyType_FromSpec(&local_dummy_type_spec);
@@ -2740,6 +2757,7 @@ thread_module_traverse(PyObject *module, visitproc visit, void *arg)
thread_module_state *state = get_thread_state(module);
Py_VISIT(state->excepthook_type);
Py_VISIT(state->lock_type);
+ Py_VISIT(state->rlock_type);
Py_VISIT(state->local_type);
Py_VISIT(state->local_dummy_type);
Py_VISIT(state->thread_handle_type);
@@ -2752,6 +2770,7 @@ thread_module_clear(PyObject *module)
thread_module_state *state = get_thread_state(module);
Py_CLEAR(state->excepthook_type);
Py_CLEAR(state->lock_type);
+ Py_CLEAR(state->rlock_type);
Py_CLEAR(state->local_type);
Py_CLEAR(state->local_dummy_type);
Py_CLEAR(state->thread_handle_type);
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 77695401919..875840bd6a6 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -31,7 +31,6 @@ Copyright (C) 1994 Steen Lumholt.
#endif
#include "pycore_long.h" // _PyLong_IsNegative()
-#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString()
#include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String
#ifdef MS_WINDOWS
@@ -146,7 +145,7 @@ _get_tcl_lib_path(void)
int stat_return_value;
PyObject *prefix;
- (void) _PySys_GetOptionalAttrString("base_prefix", &prefix);
+ (void) PySys_GetOptionalAttrString("base_prefix", &prefix);
if (prefix == NULL) {
return NULL;
}
@@ -3547,7 +3546,7 @@ PyInit__tkinter(void)
/* This helps the dynamic loader; in Unicode aware Tcl versions
it also helps Tcl find its encodings. */
- (void) _PySys_GetOptionalAttrString("executable", &uexe);
+ (void) PySys_GetOptionalAttrString("executable", &uexe);
if (uexe && PyUnicode_Check(uexe)) { // sys.executable can be None
cexe = PyUnicode_EncodeFSDefault(uexe);
Py_DECREF(uexe);
diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c
index c5e78b1510b..c31a7e8fea5 100644
--- a/Modules/_uuidmodule.c
+++ b/Modules/_uuidmodule.c
@@ -78,23 +78,47 @@ py_UuidCreate(PyObject *Py_UNUSED(context),
return NULL;
}
+static int
+py_windows_has_stable_node(void)
+{
+ UUID uuid;
+ RPC_STATUS res;
+ Py_BEGIN_ALLOW_THREADS
+ res = UuidCreateSequential(&uuid);
+ Py_END_ALLOW_THREADS
+ return res == RPC_S_OK;
+}
#endif /* MS_WINDOWS */
static int
-uuid_exec(PyObject *module) {
+uuid_exec(PyObject *module)
+{
+#define ADD_INT(NAME, VALUE) \
+ do { \
+ if (PyModule_AddIntConstant(module, (NAME), (VALUE)) < 0) { \
+ return -1; \
+ } \
+ } while (0)
+
assert(sizeof(uuid_t) == 16);
#if defined(MS_WINDOWS)
- int has_uuid_generate_time_safe = 0;
+ ADD_INT("has_uuid_generate_time_safe", 0);
#elif defined(HAVE_UUID_GENERATE_TIME_SAFE)
- int has_uuid_generate_time_safe = 1;
+ ADD_INT("has_uuid_generate_time_safe", 1);
#else
- int has_uuid_generate_time_safe = 0;
+ ADD_INT("has_uuid_generate_time_safe", 0);
#endif
- if (PyModule_AddIntConstant(module, "has_uuid_generate_time_safe",
- has_uuid_generate_time_safe) < 0) {
- return -1;
- }
+
+#if defined(MS_WINDOWS)
+ ADD_INT("has_stable_extractable_node", py_windows_has_stable_node());
+#elif defined(HAVE_UUID_GENERATE_TIME_SAFE_STABLE_MAC)
+ ADD_INT("has_stable_extractable_node", 1);
+#else
+ ADD_INT("has_stable_extractable_node", 0);
+#endif
+
+#undef ADD_INT
return 0;
}
diff --git a/Modules/_winapi.c b/Modules/_winapi.c
index 02817e09b93..b4cfbebcb1b 100644
--- a/Modules/_winapi.c
+++ b/Modules/_winapi.c
@@ -1573,6 +1573,7 @@ static PyObject *
_winapi_GetLongPathName_impl(PyObject *module, LPCWSTR path)
/*[clinic end generated code: output=c4774b080275a2d0 input=9872e211e3a4a88f]*/
{
+#if defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)
DWORD cchBuffer;
PyObject *result = NULL;
@@ -1596,6 +1597,9 @@ _winapi_GetLongPathName_impl(PyObject *module, LPCWSTR path)
PyErr_SetFromWindowsErr(0);
}
return result;
+#else
+ return PyUnicode_FromWideChar(path, -1);
+#endif
}
/*[clinic input]
@@ -1629,9 +1633,11 @@ _winapi_GetModuleFileName_impl(PyObject *module, HMODULE module_handle)
if (! result)
return PyErr_SetFromWindowsErr(GetLastError());
- return PyUnicode_FromWideChar(filename, wcslen(filename));
+ return PyUnicode_FromWideChar(filename, -1);
}
+#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
+
/*[clinic input]
_winapi.GetShortPathName
@@ -1674,6 +1680,8 @@ _winapi_GetShortPathName_impl(PyObject *module, LPCWSTR path)
return result;
}
+#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */
+
/*[clinic input]
_winapi.GetStdHandle -> HANDLE
@@ -2740,6 +2748,19 @@ _winapi_GetACP_impl(PyObject *module)
}
/*[clinic input]
+_winapi.GetOEMCP
+
+Get the current Windows ANSI code page identifier.
+[clinic start generated code]*/
+
+static PyObject *
+_winapi_GetOEMCP_impl(PyObject *module)
+/*[clinic end generated code: output=4def5b07a8be1b3b input=e8caf4353a28e28e]*/
+{
+ return PyLong_FromUnsignedLong(GetOEMCP());
+}
+
+/*[clinic input]
_winapi.GetFileType -> DWORD
handle: HANDLE
@@ -2883,6 +2904,7 @@ _winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module,
LPCWSTR exe_name)
/*[clinic end generated code: output=a65ec879502b58fc input=972aac88a1ec2f00]*/
{
+#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
BOOL result;
Py_BEGIN_ALLOW_THREADS
@@ -2890,6 +2912,9 @@ _winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module,
Py_END_ALLOW_THREADS
return result;
+#else
+ return TRUE;
+#endif
}
@@ -2995,6 +3020,7 @@ static PyMethodDef winapi_functions[] = {
_WINAPI_WAITFORSINGLEOBJECT_METHODDEF
_WINAPI_WRITEFILE_METHODDEF
_WINAPI_GETACP_METHODDEF
+ _WINAPI_GETOEMCP_METHODDEF
_WINAPI_GETFILETYPE_METHODDEF
_WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
_WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c
index abd53436b21..5c5383d260a 100644
--- a/Modules/_zoneinfo.c
+++ b/Modules/_zoneinfo.c
@@ -7,6 +7,7 @@
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_typeobject.h" // _PyType_GetModuleState()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "datetime.h" // PyDateTime_TZInfo
@@ -375,9 +376,7 @@ zoneinfo_dealloc(PyObject *obj_self)
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs(obj_self);
- }
+ FT_CLEAR_WEAKREFS(obj_self, self->weakreflist);
if (self->trans_list_utc != NULL) {
PyMem_Free(self->trans_list_utc);
diff --git a/Modules/_zstd/_zstdmodule.c b/Modules/_zstd/_zstdmodule.c
new file mode 100644
index 00000000000..d75c0779474
--- /dev/null
+++ b/Modules/_zstd/_zstdmodule.c
@@ -0,0 +1,767 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+
+#include "Python.h"
+
+#include "_zstdmodule.h"
+
+#include <zstd.h> // ZSTD_*()
+#include <zdict.h> // ZDICT_*()
+
+/*[clinic input]
+module _zstd
+
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b5f5587aac15c14]*/
+#include "clinic/_zstdmodule.c.h"
+
+
+ZstdDict *
+_Py_parse_zstd_dict(const _zstd_state *state, PyObject *dict, int *ptype)
+{
+ if (state == NULL) {
+ return NULL;
+ }
+
+ /* Check ZstdDict */
+ if (PyObject_TypeCheck(dict, state->ZstdDict_type)) {
+ return (ZstdDict*)dict;
+ }
+
+ /* Check (ZstdDict, type) */
+ if (PyTuple_CheckExact(dict) && PyTuple_GET_SIZE(dict) == 2
+ && PyObject_TypeCheck(PyTuple_GET_ITEM(dict, 0), state->ZstdDict_type)
+ && PyLong_Check(PyTuple_GET_ITEM(dict, 1)))
+ {
+ int type = PyLong_AsInt(PyTuple_GET_ITEM(dict, 1));
+ if (type == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (type == DICT_TYPE_DIGESTED
+ || type == DICT_TYPE_UNDIGESTED
+ || type == DICT_TYPE_PREFIX)
+ {
+ *ptype = type;
+ return (ZstdDict*)PyTuple_GET_ITEM(dict, 0);
+ }
+ }
+
+ /* Wrong type */
+ PyErr_SetString(PyExc_TypeError,
+ "zstd_dict argument should be a ZstdDict object.");
+ return NULL;
+}
+
+/* Format error message and set ZstdError. */
+void
+set_zstd_error(const _zstd_state *state, error_type type, size_t zstd_ret)
+{
+ const char *msg;
+ assert(ZSTD_isError(zstd_ret));
+
+ if (state == NULL) {
+ return;
+ }
+ switch (type) {
+ case ERR_DECOMPRESS:
+ msg = "Unable to decompress Zstandard data: %s";
+ break;
+ case ERR_COMPRESS:
+ msg = "Unable to compress Zstandard data: %s";
+ break;
+ case ERR_SET_PLEDGED_INPUT_SIZE:
+ msg = "Unable to set pledged uncompressed content size: %s";
+ break;
+
+ case ERR_LOAD_D_DICT:
+ msg = "Unable to load Zstandard dictionary or prefix for "
+ "decompression: %s";
+ break;
+ case ERR_LOAD_C_DICT:
+ msg = "Unable to load Zstandard dictionary or prefix for "
+ "compression: %s";
+ break;
+
+ case ERR_GET_C_BOUNDS:
+ msg = "Unable to get zstd compression parameter bounds: %s";
+ break;
+ case ERR_GET_D_BOUNDS:
+ msg = "Unable to get zstd decompression parameter bounds: %s";
+ break;
+ case ERR_SET_C_LEVEL:
+ msg = "Unable to set zstd compression level: %s";
+ break;
+
+ case ERR_TRAIN_DICT:
+ msg = "Unable to train the Zstandard dictionary: %s";
+ break;
+ case ERR_FINALIZE_DICT:
+ msg = "Unable to finalize the Zstandard dictionary: %s";
+ break;
+
+ default:
+ Py_UNREACHABLE();
+ }
+ PyErr_Format(state->ZstdError, msg, ZSTD_getErrorName(zstd_ret));
+}
+
+typedef struct {
+ int parameter;
+ char parameter_name[32];
+} ParameterInfo;
+
+static const ParameterInfo cp_list[] = {
+ {ZSTD_c_compressionLevel, "compression_level"},
+ {ZSTD_c_windowLog, "window_log"},
+ {ZSTD_c_hashLog, "hash_log"},
+ {ZSTD_c_chainLog, "chain_log"},
+ {ZSTD_c_searchLog, "search_log"},
+ {ZSTD_c_minMatch, "min_match"},
+ {ZSTD_c_targetLength, "target_length"},
+ {ZSTD_c_strategy, "strategy"},
+
+ {ZSTD_c_enableLongDistanceMatching, "enable_long_distance_matching"},
+ {ZSTD_c_ldmHashLog, "ldm_hash_log"},
+ {ZSTD_c_ldmMinMatch, "ldm_min_match"},
+ {ZSTD_c_ldmBucketSizeLog, "ldm_bucket_size_log"},
+ {ZSTD_c_ldmHashRateLog, "ldm_hash_rate_log"},
+
+ {ZSTD_c_contentSizeFlag, "content_size_flag"},
+ {ZSTD_c_checksumFlag, "checksum_flag"},
+ {ZSTD_c_dictIDFlag, "dict_id_flag"},
+
+ {ZSTD_c_nbWorkers, "nb_workers"},
+ {ZSTD_c_jobSize, "job_size"},
+ {ZSTD_c_overlapLog, "overlap_log"}
+};
+
+static const ParameterInfo dp_list[] = {
+ {ZSTD_d_windowLogMax, "window_log_max"}
+};
+
+void
+set_parameter_error(int is_compress, int key_v, int value_v)
+{
+ ParameterInfo const *list;
+ int list_size;
+ char *type;
+ ZSTD_bounds bounds;
+ char pos_msg[64];
+
+ if (is_compress) {
+ list = cp_list;
+ list_size = Py_ARRAY_LENGTH(cp_list);
+ type = "compression";
+ }
+ else {
+ list = dp_list;
+ list_size = Py_ARRAY_LENGTH(dp_list);
+ type = "decompression";
+ }
+
+ /* Find parameter's name */
+ char const *name = NULL;
+ for (int i = 0; i < list_size; i++) {
+ if (key_v == (list+i)->parameter) {
+ name = (list+i)->parameter_name;
+ break;
+ }
+ }
+
+ /* Unknown parameter */
+ if (name == NULL) {
+ PyOS_snprintf(pos_msg, sizeof(pos_msg),
+ "unknown parameter (key %d)", key_v);
+ name = pos_msg;
+ }
+
+ /* Get parameter bounds */
+ if (is_compress) {
+ bounds = ZSTD_cParam_getBounds(key_v);
+ }
+ else {
+ bounds = ZSTD_dParam_getBounds(key_v);
+ }
+ if (ZSTD_isError(bounds.error)) {
+ PyErr_Format(PyExc_ValueError, "invalid %s parameter '%s'",
+ type, name);
+ return;
+ }
+
+ /* Error message */
+ PyErr_Format(PyExc_ValueError,
+ "%s parameter '%s' received an illegal value %d; "
+ "the valid range is [%d, %d]",
+ type, name, value_v, bounds.lowerBound, bounds.upperBound);
+}
+
+static inline _zstd_state*
+get_zstd_state(PyObject *module)
+{
+ void *state = PyModule_GetState(module);
+ assert(state != NULL);
+ return (_zstd_state *)state;
+}
+
+static Py_ssize_t
+calculate_samples_stats(PyBytesObject *samples_bytes, PyObject *samples_sizes,
+ size_t **chunk_sizes)
+{
+ Py_ssize_t chunks_number;
+ Py_ssize_t sizes_sum;
+ Py_ssize_t i;
+
+ chunks_number = PyTuple_GET_SIZE(samples_sizes);
+ if ((size_t) chunks_number > UINT32_MAX) {
+ PyErr_Format(PyExc_ValueError,
+ "The number of samples should be <= %u.", UINT32_MAX);
+ return -1;
+ }
+
+ /* Prepare chunk_sizes */
+ *chunk_sizes = PyMem_New(size_t, chunks_number);
+ if (*chunk_sizes == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ sizes_sum = PyBytes_GET_SIZE(samples_bytes);
+ for (i = 0; i < chunks_number; i++) {
+ size_t size = PyLong_AsSize_t(PyTuple_GET_ITEM(samples_sizes, i));
+ (*chunk_sizes)[i] = size;
+ if (size == (size_t)-1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ goto sum_error;
+ }
+ return -1;
+ }
+ if ((size_t)sizes_sum < size) {
+ goto sum_error;
+ }
+ sizes_sum -= size;
+ }
+
+ if (sizes_sum != 0) {
+sum_error:
+ PyErr_SetString(PyExc_ValueError,
+ "The samples size tuple doesn't match the "
+ "concatenation's size.");
+ return -1;
+ }
+ return chunks_number;
+}
+
+
+/*[clinic input]
+_zstd.train_dict
+
+ samples_bytes: PyBytesObject
+ Concatenation of samples.
+ samples_sizes: object(subclass_of='&PyTuple_Type')
+ Tuple of samples' sizes.
+ dict_size: Py_ssize_t
+ The size of the dictionary.
+ /
+
+Train a Zstandard dictionary on sample data.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
+ PyObject *samples_sizes, Py_ssize_t dict_size)
+/*[clinic end generated code: output=8e87fe43935e8f77 input=d20dedb21c72cb62]*/
+{
+ PyObject *dst_dict_bytes = NULL;
+ size_t *chunk_sizes = NULL;
+ Py_ssize_t chunks_number;
+ size_t zstd_ret;
+
+ /* Check arguments */
+ if (dict_size <= 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "dict_size argument should be positive number.");
+ return NULL;
+ }
+
+ /* Check that the samples are valid and get their sizes */
+ chunks_number = calculate_samples_stats(samples_bytes, samples_sizes,
+ &chunk_sizes);
+ if (chunks_number < 0) {
+ goto error;
+ }
+
+ /* Allocate dict buffer */
+ dst_dict_bytes = PyBytes_FromStringAndSize(NULL, dict_size);
+ if (dst_dict_bytes == NULL) {
+ goto error;
+ }
+
+ /* Train the dictionary */
+ char *dst_dict_buffer = PyBytes_AS_STRING(dst_dict_bytes);
+ const char *samples_buffer = PyBytes_AS_STRING(samples_bytes);
+ Py_BEGIN_ALLOW_THREADS
+ zstd_ret = ZDICT_trainFromBuffer(dst_dict_buffer, dict_size,
+ samples_buffer,
+ chunk_sizes, (uint32_t)chunks_number);
+ Py_END_ALLOW_THREADS
+
+ /* Check Zstandard dict error */
+ if (ZDICT_isError(zstd_ret)) {
+ _zstd_state* mod_state = get_zstd_state(module);
+ set_zstd_error(mod_state, ERR_TRAIN_DICT, zstd_ret);
+ goto error;
+ }
+
+ /* Resize dict_buffer */
+ if (_PyBytes_Resize(&dst_dict_bytes, zstd_ret) < 0) {
+ goto error;
+ }
+
+ goto success;
+
+error:
+ Py_CLEAR(dst_dict_bytes);
+
+success:
+ PyMem_Free(chunk_sizes);
+ return dst_dict_bytes;
+}
+
+/*[clinic input]
+_zstd.finalize_dict
+
+ custom_dict_bytes: PyBytesObject
+ Custom dictionary content.
+ samples_bytes: PyBytesObject
+ Concatenation of samples.
+ samples_sizes: object(subclass_of='&PyTuple_Type')
+ Tuple of samples' sizes.
+ dict_size: Py_ssize_t
+ The size of the dictionary.
+ compression_level: int
+ Optimize for a specific Zstandard compression level, 0 means default.
+ /
+
+Finalize a Zstandard dictionary.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
+ PyBytesObject *samples_bytes,
+ PyObject *samples_sizes, Py_ssize_t dict_size,
+ int compression_level)
+/*[clinic end generated code: output=f91821ba5ae85bda input=3c7e2480aa08fb56]*/
+{
+ Py_ssize_t chunks_number;
+ size_t *chunk_sizes = NULL;
+ PyObject *dst_dict_bytes = NULL;
+ size_t zstd_ret;
+ ZDICT_params_t params;
+
+ /* Check arguments */
+ if (dict_size <= 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "dict_size argument should be positive number.");
+ return NULL;
+ }
+
+ /* Check that the samples are valid and get their sizes */
+ chunks_number = calculate_samples_stats(samples_bytes, samples_sizes,
+ &chunk_sizes);
+ if (chunks_number < 0) {
+ goto error;
+ }
+
+ /* Allocate dict buffer */
+ dst_dict_bytes = PyBytes_FromStringAndSize(NULL, dict_size);
+ if (dst_dict_bytes == NULL) {
+ goto error;
+ }
+
+ /* Parameters */
+
+ /* Optimize for a specific Zstandard compression level, 0 means default. */
+ params.compressionLevel = compression_level;
+ /* Write log to stderr, 0 = none. */
+ params.notificationLevel = 0;
+ /* Force dictID value, 0 means auto mode (32-bits random value). */
+ params.dictID = 0;
+
+ /* Finalize the dictionary */
+ Py_BEGIN_ALLOW_THREADS
+ zstd_ret = ZDICT_finalizeDictionary(
+ PyBytes_AS_STRING(dst_dict_bytes), dict_size,
+ PyBytes_AS_STRING(custom_dict_bytes),
+ Py_SIZE(custom_dict_bytes),
+ PyBytes_AS_STRING(samples_bytes), chunk_sizes,
+ (uint32_t)chunks_number, params);
+ Py_END_ALLOW_THREADS
+
+ /* Check Zstandard dict error */
+ if (ZDICT_isError(zstd_ret)) {
+ _zstd_state* mod_state = get_zstd_state(module);
+ set_zstd_error(mod_state, ERR_FINALIZE_DICT, zstd_ret);
+ goto error;
+ }
+
+ /* Resize dict_buffer */
+ if (_PyBytes_Resize(&dst_dict_bytes, zstd_ret) < 0) {
+ goto error;
+ }
+
+ goto success;
+
+error:
+ Py_CLEAR(dst_dict_bytes);
+
+success:
+ PyMem_Free(chunk_sizes);
+ return dst_dict_bytes;
+}
+
+
+/*[clinic input]
+_zstd.get_param_bounds
+
+ parameter: int
+ The parameter to get bounds.
+ is_compress: bool
+ True for CompressionParameter, False for DecompressionParameter.
+
+Get CompressionParameter/DecompressionParameter bounds.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_get_param_bounds_impl(PyObject *module, int parameter, int is_compress)
+/*[clinic end generated code: output=4acf5a876f0620ca input=45742ef0a3531b65]*/
+{
+ ZSTD_bounds bound;
+ if (is_compress) {
+ bound = ZSTD_cParam_getBounds(parameter);
+ if (ZSTD_isError(bound.error)) {
+ _zstd_state* mod_state = get_zstd_state(module);
+ set_zstd_error(mod_state, ERR_GET_C_BOUNDS, bound.error);
+ return NULL;
+ }
+ }
+ else {
+ bound = ZSTD_dParam_getBounds(parameter);
+ if (ZSTD_isError(bound.error)) {
+ _zstd_state* mod_state = get_zstd_state(module);
+ set_zstd_error(mod_state, ERR_GET_D_BOUNDS, bound.error);
+ return NULL;
+ }
+ }
+
+ return Py_BuildValue("ii", bound.lowerBound, bound.upperBound);
+}
+
+/*[clinic input]
+_zstd.get_frame_size
+
+ frame_buffer: Py_buffer
+ A bytes-like object, it should start from the beginning of a frame,
+ and contains at least one complete frame.
+
+Get the size of a Zstandard frame, including the header and optional checksum.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_get_frame_size_impl(PyObject *module, Py_buffer *frame_buffer)
+/*[clinic end generated code: output=a7384c2f8780f442 input=3b9f73f8c8129d38]*/
+{
+ size_t frame_size;
+
+ frame_size = ZSTD_findFrameCompressedSize(frame_buffer->buf,
+ frame_buffer->len);
+ if (ZSTD_isError(frame_size)) {
+ _zstd_state* mod_state = get_zstd_state(module);
+ PyErr_Format(mod_state->ZstdError,
+ "Error when finding the compressed size of a Zstandard frame. "
+ "Ensure the frame_buffer argument starts from the "
+ "beginning of a frame, and its length is not less than this "
+ "complete frame. Zstd error message: %s.",
+ ZSTD_getErrorName(frame_size));
+ return NULL;
+ }
+
+ return PyLong_FromSize_t(frame_size);
+}
+
+/*[clinic input]
+_zstd.get_frame_info
+
+ frame_buffer: Py_buffer
+ A bytes-like object, containing the header of a Zstandard frame.
+
+Get Zstandard frame infomation from a frame header.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_get_frame_info_impl(PyObject *module, Py_buffer *frame_buffer)
+/*[clinic end generated code: output=56e033cf48001929 input=94b240583ae22ca5]*/
+{
+ uint64_t decompressed_size;
+ uint32_t dict_id;
+
+ /* ZSTD_getFrameContentSize */
+ decompressed_size = ZSTD_getFrameContentSize(frame_buffer->buf,
+ frame_buffer->len);
+
+ /* #define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
+ #define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) */
+ if (decompressed_size == ZSTD_CONTENTSIZE_ERROR) {
+ _zstd_state* mod_state = get_zstd_state(module);
+ PyErr_SetString(mod_state->ZstdError,
+ "Error when getting information from the header of "
+ "a Zstandard frame. Ensure the frame_buffer argument "
+ "starts from the beginning of a frame, and its length "
+ "is not less than the frame header (6~18 bytes).");
+ return NULL;
+ }
+
+ /* ZSTD_getDictID_fromFrame */
+ dict_id = ZSTD_getDictID_fromFrame(frame_buffer->buf, frame_buffer->len);
+
+ /* Build tuple */
+ if (decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
+ return Py_BuildValue("OI", Py_None, dict_id);
+ }
+ return Py_BuildValue("KI", decompressed_size, dict_id);
+}
+
+/*[clinic input]
+_zstd.set_parameter_types
+
+ c_parameter_type: object(subclass_of='&PyType_Type')
+ CompressionParameter IntEnum type object
+ d_parameter_type: object(subclass_of='&PyType_Type')
+ DecompressionParameter IntEnum type object
+
+Set CompressionParameter and DecompressionParameter types for validity check.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_set_parameter_types_impl(PyObject *module, PyObject *c_parameter_type,
+ PyObject *d_parameter_type)
+/*[clinic end generated code: output=f3313b1294f19502 input=75d7a953580fae5f]*/
+{
+ _zstd_state* mod_state = get_zstd_state(module);
+
+ Py_INCREF(c_parameter_type);
+ Py_XSETREF(mod_state->CParameter_type, (PyTypeObject*)c_parameter_type);
+ Py_INCREF(d_parameter_type);
+ Py_XSETREF(mod_state->DParameter_type, (PyTypeObject*)d_parameter_type);
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef _zstd_methods[] = {
+ _ZSTD_TRAIN_DICT_METHODDEF
+ _ZSTD_FINALIZE_DICT_METHODDEF
+ _ZSTD_GET_PARAM_BOUNDS_METHODDEF
+ _ZSTD_GET_FRAME_SIZE_METHODDEF
+ _ZSTD_GET_FRAME_INFO_METHODDEF
+ _ZSTD_SET_PARAMETER_TYPES_METHODDEF
+ {NULL, NULL}
+};
+
+static int
+_zstd_exec(PyObject *m)
+{
+#define ADD_TYPE(TYPE, SPEC) \
+do { \
+ TYPE = (PyTypeObject *)PyType_FromModuleAndSpec(m, &(SPEC), NULL); \
+ if (TYPE == NULL) { \
+ return -1; \
+ } \
+ if (PyModule_AddType(m, TYPE) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
+#define ADD_INT_MACRO(MACRO) \
+ if (PyModule_AddIntConstant((m), #MACRO, (MACRO)) < 0) { \
+ return -1; \
+ }
+
+#define ADD_INT_CONST_TO_TYPE(TYPE, NAME, VALUE) \
+do { \
+ PyObject *v = PyLong_FromLong((VALUE)); \
+ if (v == NULL || PyObject_SetAttrString((PyObject *)(TYPE), \
+ (NAME), v) < 0) { \
+ Py_XDECREF(v); \
+ return -1; \
+ } \
+ Py_DECREF(v); \
+} while (0)
+
+ _zstd_state* mod_state = get_zstd_state(m);
+
+ /* Reusable objects & variables */
+ mod_state->CParameter_type = NULL;
+ mod_state->DParameter_type = NULL;
+
+ /* Create and add heap types */
+ ADD_TYPE(mod_state->ZstdDict_type, zstd_dict_type_spec);
+ ADD_TYPE(mod_state->ZstdCompressor_type, zstd_compressor_type_spec);
+ ADD_TYPE(mod_state->ZstdDecompressor_type, zstd_decompressor_type_spec);
+ mod_state->ZstdError = PyErr_NewExceptionWithDoc(
+ "compression.zstd.ZstdError",
+ "An error occurred in the zstd library.",
+ NULL, NULL);
+ if (mod_state->ZstdError == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, (PyTypeObject *)mod_state->ZstdError) < 0) {
+ return -1;
+ }
+
+ /* Add constants */
+ if (PyModule_AddIntConstant(m, "zstd_version_number",
+ ZSTD_versionNumber()) < 0) {
+ return -1;
+ }
+
+ if (PyModule_AddStringConstant(m, "zstd_version",
+ ZSTD_versionString()) < 0) {
+ return -1;
+ }
+
+#if ZSTD_VERSION_NUMBER >= 10500
+ if (PyModule_AddIntConstant(m, "ZSTD_CLEVEL_DEFAULT",
+ ZSTD_defaultCLevel()) < 0) {
+ return -1;
+ }
+#else
+ ADD_INT_MACRO(ZSTD_CLEVEL_DEFAULT);
+#endif
+
+ if (PyModule_Add(m, "ZSTD_DStreamOutSize",
+ PyLong_FromSize_t(ZSTD_DStreamOutSize())) < 0) {
+ return -1;
+ }
+
+ /* Add zstd compression parameters. All should also be in cp_list. */
+ ADD_INT_MACRO(ZSTD_c_compressionLevel);
+ ADD_INT_MACRO(ZSTD_c_windowLog);
+ ADD_INT_MACRO(ZSTD_c_hashLog);
+ ADD_INT_MACRO(ZSTD_c_chainLog);
+ ADD_INT_MACRO(ZSTD_c_searchLog);
+ ADD_INT_MACRO(ZSTD_c_minMatch);
+ ADD_INT_MACRO(ZSTD_c_targetLength);
+ ADD_INT_MACRO(ZSTD_c_strategy);
+
+ ADD_INT_MACRO(ZSTD_c_enableLongDistanceMatching);
+ ADD_INT_MACRO(ZSTD_c_ldmHashLog);
+ ADD_INT_MACRO(ZSTD_c_ldmMinMatch);
+ ADD_INT_MACRO(ZSTD_c_ldmBucketSizeLog);
+ ADD_INT_MACRO(ZSTD_c_ldmHashRateLog);
+
+ ADD_INT_MACRO(ZSTD_c_contentSizeFlag);
+ ADD_INT_MACRO(ZSTD_c_checksumFlag);
+ ADD_INT_MACRO(ZSTD_c_dictIDFlag);
+
+ ADD_INT_MACRO(ZSTD_c_nbWorkers);
+ ADD_INT_MACRO(ZSTD_c_jobSize);
+ ADD_INT_MACRO(ZSTD_c_overlapLog);
+
+ /* Add zstd decompression parameters. All should also be in dp_list. */
+ ADD_INT_MACRO(ZSTD_d_windowLogMax);
+
+ /* Add ZSTD_strategy enum members */
+ ADD_INT_MACRO(ZSTD_fast);
+ ADD_INT_MACRO(ZSTD_dfast);
+ ADD_INT_MACRO(ZSTD_greedy);
+ ADD_INT_MACRO(ZSTD_lazy);
+ ADD_INT_MACRO(ZSTD_lazy2);
+ ADD_INT_MACRO(ZSTD_btlazy2);
+ ADD_INT_MACRO(ZSTD_btopt);
+ ADD_INT_MACRO(ZSTD_btultra);
+ ADD_INT_MACRO(ZSTD_btultra2);
+
+ /* Add ZSTD_EndDirective enum members to ZstdCompressor */
+ ADD_INT_CONST_TO_TYPE(mod_state->ZstdCompressor_type,
+ "CONTINUE", ZSTD_e_continue);
+ ADD_INT_CONST_TO_TYPE(mod_state->ZstdCompressor_type,
+ "FLUSH_BLOCK", ZSTD_e_flush);
+ ADD_INT_CONST_TO_TYPE(mod_state->ZstdCompressor_type,
+ "FLUSH_FRAME", ZSTD_e_end);
+
+ /* Make ZstdCompressor immutable (set Py_TPFLAGS_IMMUTABLETYPE) */
+ PyType_Freeze(mod_state->ZstdCompressor_type);
+
+#undef ADD_TYPE
+#undef ADD_INT_MACRO
+#undef ADD_ZSTD_COMPRESSOR_INT_CONST
+
+ return 0;
+}
+
+static int
+_zstd_traverse(PyObject *module, visitproc visit, void *arg)
+{
+ _zstd_state* mod_state = get_zstd_state(module);
+
+ Py_VISIT(mod_state->ZstdDict_type);
+ Py_VISIT(mod_state->ZstdCompressor_type);
+
+ Py_VISIT(mod_state->ZstdDecompressor_type);
+
+ Py_VISIT(mod_state->ZstdError);
+
+ Py_VISIT(mod_state->CParameter_type);
+ Py_VISIT(mod_state->DParameter_type);
+ return 0;
+}
+
+static int
+_zstd_clear(PyObject *module)
+{
+ _zstd_state* mod_state = get_zstd_state(module);
+
+ Py_CLEAR(mod_state->ZstdDict_type);
+ Py_CLEAR(mod_state->ZstdCompressor_type);
+
+ Py_CLEAR(mod_state->ZstdDecompressor_type);
+
+ Py_CLEAR(mod_state->ZstdError);
+
+ Py_CLEAR(mod_state->CParameter_type);
+ Py_CLEAR(mod_state->DParameter_type);
+ return 0;
+}
+
+static void
+_zstd_free(void *module)
+{
+ (void)_zstd_clear((PyObject *)module);
+}
+
+static struct PyModuleDef_Slot _zstd_slots[] = {
+ {Py_mod_exec, _zstd_exec},
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
+ {0, NULL},
+};
+
+static struct PyModuleDef _zstdmodule = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "_zstd",
+ .m_doc = "Implementation module for Zstandard compression.",
+ .m_size = sizeof(_zstd_state),
+ .m_slots = _zstd_slots,
+ .m_methods = _zstd_methods,
+ .m_traverse = _zstd_traverse,
+ .m_clear = _zstd_clear,
+ .m_free = _zstd_free,
+};
+
+PyMODINIT_FUNC
+PyInit__zstd(void)
+{
+ return PyModuleDef_Init(&_zstdmodule);
+}
diff --git a/Modules/_zstd/_zstdmodule.h b/Modules/_zstd/_zstdmodule.h
new file mode 100644
index 00000000000..4e8f708f223
--- /dev/null
+++ b/Modules/_zstd/_zstdmodule.h
@@ -0,0 +1,61 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+/* Declarations shared between different parts of the _zstd module*/
+
+#ifndef ZSTD_MODULE_H
+#define ZSTD_MODULE_H
+
+#include "zstddict.h"
+
+/* Type specs */
+extern PyType_Spec zstd_dict_type_spec;
+extern PyType_Spec zstd_compressor_type_spec;
+extern PyType_Spec zstd_decompressor_type_spec;
+
+typedef struct {
+ /* Module heap types. */
+ PyTypeObject *ZstdDict_type;
+ PyTypeObject *ZstdCompressor_type;
+ PyTypeObject *ZstdDecompressor_type;
+ PyObject *ZstdError;
+
+ /* enum types set by set_parameter_types. */
+ PyTypeObject *CParameter_type;
+ PyTypeObject *DParameter_type;
+} _zstd_state;
+
+typedef enum {
+ ERR_DECOMPRESS,
+ ERR_COMPRESS,
+ ERR_SET_PLEDGED_INPUT_SIZE,
+
+ ERR_LOAD_D_DICT,
+ ERR_LOAD_C_DICT,
+
+ ERR_GET_C_BOUNDS,
+ ERR_GET_D_BOUNDS,
+ ERR_SET_C_LEVEL,
+
+ ERR_TRAIN_DICT,
+ ERR_FINALIZE_DICT,
+} error_type;
+
+typedef enum {
+ DICT_TYPE_DIGESTED = 0,
+ DICT_TYPE_UNDIGESTED = 1,
+ DICT_TYPE_PREFIX = 2
+} dictionary_type;
+
+extern ZstdDict *
+_Py_parse_zstd_dict(const _zstd_state *state,
+ PyObject *dict, int *type);
+
+/* Format error message and set ZstdError. */
+extern void
+set_zstd_error(const _zstd_state *state,
+ error_type type, size_t zstd_ret);
+
+extern void
+set_parameter_error(int is_compress, int key_v, int value_v);
+
+#endif // !ZSTD_MODULE_H
diff --git a/Modules/_zstd/buffer.h b/Modules/_zstd/buffer.h
new file mode 100644
index 00000000000..4c885fa0d72
--- /dev/null
+++ b/Modules/_zstd/buffer.h
@@ -0,0 +1,108 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+#ifndef ZSTD_BUFFER_H
+#define ZSTD_BUFFER_H
+
+#include "pycore_blocks_output_buffer.h"
+
+#include <zstd.h> // ZSTD_outBuffer
+
+/* Blocks output buffer wrapper code */
+
+/* Initialize the buffer, and grow the buffer.
+ Return 0 on success
+ Return -1 on failure */
+static inline int
+_OutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob,
+ Py_ssize_t max_length)
+{
+ /* Ensure .list was set to NULL */
+ assert(buffer->list == NULL);
+
+ Py_ssize_t res = _BlocksOutputBuffer_InitAndGrow(buffer, max_length,
+ &ob->dst);
+ if (res < 0) {
+ return -1;
+ }
+ ob->size = (size_t) res;
+ ob->pos = 0;
+ return 0;
+}
+
+/* Initialize the buffer, with an initial size.
+ init_size: the initial size.
+ Return 0 on success
+ Return -1 on failure */
+static inline int
+_OutputBuffer_InitWithSize(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob,
+ Py_ssize_t max_length, Py_ssize_t init_size)
+{
+ Py_ssize_t block_size;
+
+ /* Ensure .list was set to NULL */
+ assert(buffer->list == NULL);
+
+ /* Get block size */
+ if (0 <= max_length && max_length < init_size) {
+ block_size = max_length;
+ }
+ else {
+ block_size = init_size;
+ }
+
+ Py_ssize_t res = _BlocksOutputBuffer_InitWithSize(buffer, block_size,
+ &ob->dst);
+ if (res < 0) {
+ return -1;
+ }
+ // Set max_length, InitWithSize doesn't do this
+ buffer->max_length = max_length;
+ ob->size = (size_t) res;
+ ob->pos = 0;
+ return 0;
+}
+
+/* Grow the buffer.
+ Return 0 on success
+ Return -1 on failure */
+static inline int
+_OutputBuffer_Grow(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob)
+{
+ assert(ob->pos == ob->size);
+ Py_ssize_t res = _BlocksOutputBuffer_Grow(buffer, &ob->dst, 0);
+ if (res < 0) {
+ return -1;
+ }
+ ob->size = (size_t) res;
+ ob->pos = 0;
+ return 0;
+}
+
+/* Finish the buffer.
+ Return a bytes object on success
+ Return NULL on failure */
+static inline PyObject *
+_OutputBuffer_Finish(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob)
+{
+ return _BlocksOutputBuffer_Finish(buffer, ob->size - ob->pos);
+}
+
+/* Clean up the buffer */
+static inline void
+_OutputBuffer_OnError(_BlocksOutputBuffer *buffer)
+{
+ _BlocksOutputBuffer_OnError(buffer);
+}
+
+/* Whether the output data has reached max_length.
+The avail_out must be 0, please check it before calling. */
+static inline int
+_OutputBuffer_ReachedMaxLength(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob)
+{
+ /* Ensure (data size == allocated size) */
+ assert(ob->pos == ob->size);
+
+ return buffer->allocated == buffer->max_length;
+}
+
+#endif // !ZSTD_BUFFER_H
diff --git a/Modules/_zstd/clinic/_zstdmodule.c.h b/Modules/_zstd/clinic/_zstdmodule.c.h
new file mode 100644
index 00000000000..766e1cfa776
--- /dev/null
+++ b/Modules/_zstd/clinic/_zstdmodule.c.h
@@ -0,0 +1,429 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_abstract.h" // _PyNumber_Index()
+#include "pycore_modsupport.h" // _PyArg_CheckPositional()
+
+PyDoc_STRVAR(_zstd_train_dict__doc__,
+"train_dict($module, samples_bytes, samples_sizes, dict_size, /)\n"
+"--\n"
+"\n"
+"Train a Zstandard dictionary on sample data.\n"
+"\n"
+" samples_bytes\n"
+" Concatenation of samples.\n"
+" samples_sizes\n"
+" Tuple of samples\' sizes.\n"
+" dict_size\n"
+" The size of the dictionary.");
+
+#define _ZSTD_TRAIN_DICT_METHODDEF \
+ {"train_dict", _PyCFunction_CAST(_zstd_train_dict), METH_FASTCALL, _zstd_train_dict__doc__},
+
+static PyObject *
+_zstd_train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
+ PyObject *samples_sizes, Py_ssize_t dict_size);
+
+static PyObject *
+_zstd_train_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyBytesObject *samples_bytes;
+ PyObject *samples_sizes;
+ Py_ssize_t dict_size;
+
+ if (!_PyArg_CheckPositional("train_dict", nargs, 3, 3)) {
+ goto exit;
+ }
+ if (!PyBytes_Check(args[0])) {
+ _PyArg_BadArgument("train_dict", "argument 1", "bytes", args[0]);
+ goto exit;
+ }
+ samples_bytes = (PyBytesObject *)args[0];
+ if (!PyTuple_Check(args[1])) {
+ _PyArg_BadArgument("train_dict", "argument 2", "tuple", args[1]);
+ goto exit;
+ }
+ samples_sizes = args[1];
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[2]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ dict_size = ival;
+ }
+ return_value = _zstd_train_dict_impl(module, samples_bytes, samples_sizes, dict_size);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_finalize_dict__doc__,
+"finalize_dict($module, custom_dict_bytes, samples_bytes, samples_sizes,\n"
+" dict_size, compression_level, /)\n"
+"--\n"
+"\n"
+"Finalize a Zstandard dictionary.\n"
+"\n"
+" custom_dict_bytes\n"
+" Custom dictionary content.\n"
+" samples_bytes\n"
+" Concatenation of samples.\n"
+" samples_sizes\n"
+" Tuple of samples\' sizes.\n"
+" dict_size\n"
+" The size of the dictionary.\n"
+" compression_level\n"
+" Optimize for a specific Zstandard compression level, 0 means default.");
+
+#define _ZSTD_FINALIZE_DICT_METHODDEF \
+ {"finalize_dict", _PyCFunction_CAST(_zstd_finalize_dict), METH_FASTCALL, _zstd_finalize_dict__doc__},
+
+static PyObject *
+_zstd_finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
+ PyBytesObject *samples_bytes,
+ PyObject *samples_sizes, Py_ssize_t dict_size,
+ int compression_level);
+
+static PyObject *
+_zstd_finalize_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyBytesObject *custom_dict_bytes;
+ PyBytesObject *samples_bytes;
+ PyObject *samples_sizes;
+ Py_ssize_t dict_size;
+ int compression_level;
+
+ if (!_PyArg_CheckPositional("finalize_dict", nargs, 5, 5)) {
+ goto exit;
+ }
+ if (!PyBytes_Check(args[0])) {
+ _PyArg_BadArgument("finalize_dict", "argument 1", "bytes", args[0]);
+ goto exit;
+ }
+ custom_dict_bytes = (PyBytesObject *)args[0];
+ if (!PyBytes_Check(args[1])) {
+ _PyArg_BadArgument("finalize_dict", "argument 2", "bytes", args[1]);
+ goto exit;
+ }
+ samples_bytes = (PyBytesObject *)args[1];
+ if (!PyTuple_Check(args[2])) {
+ _PyArg_BadArgument("finalize_dict", "argument 3", "tuple", args[2]);
+ goto exit;
+ }
+ samples_sizes = args[2];
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[3]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ dict_size = ival;
+ }
+ compression_level = PyLong_AsInt(args[4]);
+ if (compression_level == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = _zstd_finalize_dict_impl(module, custom_dict_bytes, samples_bytes, samples_sizes, dict_size, compression_level);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_get_param_bounds__doc__,
+"get_param_bounds($module, /, parameter, is_compress)\n"
+"--\n"
+"\n"
+"Get CompressionParameter/DecompressionParameter bounds.\n"
+"\n"
+" parameter\n"
+" The parameter to get bounds.\n"
+" is_compress\n"
+" True for CompressionParameter, False for DecompressionParameter.");
+
+#define _ZSTD_GET_PARAM_BOUNDS_METHODDEF \
+ {"get_param_bounds", _PyCFunction_CAST(_zstd_get_param_bounds), METH_FASTCALL|METH_KEYWORDS, _zstd_get_param_bounds__doc__},
+
+static PyObject *
+_zstd_get_param_bounds_impl(PyObject *module, int parameter, int is_compress);
+
+static PyObject *
+_zstd_get_param_bounds(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(parameter), &_Py_ID(is_compress), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"parameter", "is_compress", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "get_param_bounds",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ int parameter;
+ int is_compress;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ parameter = PyLong_AsInt(args[0]);
+ if (parameter == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ is_compress = PyObject_IsTrue(args[1]);
+ if (is_compress < 0) {
+ goto exit;
+ }
+ return_value = _zstd_get_param_bounds_impl(module, parameter, is_compress);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_get_frame_size__doc__,
+"get_frame_size($module, /, frame_buffer)\n"
+"--\n"
+"\n"
+"Get the size of a Zstandard frame, including the header and optional checksum.\n"
+"\n"
+" frame_buffer\n"
+" A bytes-like object, it should start from the beginning of a frame,\n"
+" and contains at least one complete frame.");
+
+#define _ZSTD_GET_FRAME_SIZE_METHODDEF \
+ {"get_frame_size", _PyCFunction_CAST(_zstd_get_frame_size), METH_FASTCALL|METH_KEYWORDS, _zstd_get_frame_size__doc__},
+
+static PyObject *
+_zstd_get_frame_size_impl(PyObject *module, Py_buffer *frame_buffer);
+
+static PyObject *
+_zstd_get_frame_size(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(frame_buffer), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"frame_buffer", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "get_frame_size",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ Py_buffer frame_buffer = {NULL, NULL};
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &frame_buffer, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ return_value = _zstd_get_frame_size_impl(module, &frame_buffer);
+
+exit:
+ /* Cleanup for frame_buffer */
+ if (frame_buffer.obj) {
+ PyBuffer_Release(&frame_buffer);
+ }
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_get_frame_info__doc__,
+"get_frame_info($module, /, frame_buffer)\n"
+"--\n"
+"\n"
+"Get Zstandard frame infomation from a frame header.\n"
+"\n"
+" frame_buffer\n"
+" A bytes-like object, containing the header of a Zstandard frame.");
+
+#define _ZSTD_GET_FRAME_INFO_METHODDEF \
+ {"get_frame_info", _PyCFunction_CAST(_zstd_get_frame_info), METH_FASTCALL|METH_KEYWORDS, _zstd_get_frame_info__doc__},
+
+static PyObject *
+_zstd_get_frame_info_impl(PyObject *module, Py_buffer *frame_buffer);
+
+static PyObject *
+_zstd_get_frame_info(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(frame_buffer), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"frame_buffer", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "get_frame_info",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ Py_buffer frame_buffer = {NULL, NULL};
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &frame_buffer, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ return_value = _zstd_get_frame_info_impl(module, &frame_buffer);
+
+exit:
+ /* Cleanup for frame_buffer */
+ if (frame_buffer.obj) {
+ PyBuffer_Release(&frame_buffer);
+ }
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_set_parameter_types__doc__,
+"set_parameter_types($module, /, c_parameter_type, d_parameter_type)\n"
+"--\n"
+"\n"
+"Set CompressionParameter and DecompressionParameter types for validity check.\n"
+"\n"
+" c_parameter_type\n"
+" CompressionParameter IntEnum type object\n"
+" d_parameter_type\n"
+" DecompressionParameter IntEnum type object");
+
+#define _ZSTD_SET_PARAMETER_TYPES_METHODDEF \
+ {"set_parameter_types", _PyCFunction_CAST(_zstd_set_parameter_types), METH_FASTCALL|METH_KEYWORDS, _zstd_set_parameter_types__doc__},
+
+static PyObject *
+_zstd_set_parameter_types_impl(PyObject *module, PyObject *c_parameter_type,
+ PyObject *d_parameter_type);
+
+static PyObject *
+_zstd_set_parameter_types(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(c_parameter_type), &_Py_ID(d_parameter_type), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"c_parameter_type", "d_parameter_type", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "set_parameter_types",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject *c_parameter_type;
+ PyObject *d_parameter_type;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!PyObject_TypeCheck(args[0], &PyType_Type)) {
+ _PyArg_BadArgument("set_parameter_types", "argument 'c_parameter_type'", (&PyType_Type)->tp_name, args[0]);
+ goto exit;
+ }
+ c_parameter_type = args[0];
+ if (!PyObject_TypeCheck(args[1], &PyType_Type)) {
+ _PyArg_BadArgument("set_parameter_types", "argument 'd_parameter_type'", (&PyType_Type)->tp_name, args[1]);
+ goto exit;
+ }
+ d_parameter_type = args[1];
+ return_value = _zstd_set_parameter_types_impl(module, c_parameter_type, d_parameter_type);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=437b084f149e68e5 input=a9049054013a1b77]*/
diff --git a/Modules/_zstd/clinic/compressor.c.h b/Modules/_zstd/clinic/compressor.c.h
new file mode 100644
index 00000000000..4f8d93fd9e8
--- /dev/null
+++ b/Modules/_zstd/clinic/compressor.c.h
@@ -0,0 +1,294 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+PyDoc_STRVAR(_zstd_ZstdCompressor_new__doc__,
+"ZstdCompressor(level=None, options=None, zstd_dict=None)\n"
+"--\n"
+"\n"
+"Create a compressor object for compressing data incrementally.\n"
+"\n"
+" level\n"
+" The compression level to use. Defaults to COMPRESSION_LEVEL_DEFAULT.\n"
+" options\n"
+" A dict object that contains advanced compression parameters.\n"
+" zstd_dict\n"
+" A ZstdDict object, a pre-trained Zstandard dictionary.\n"
+"\n"
+"Thread-safe at method level. For one-shot compression, use the compress()\n"
+"function instead.");
+
+static PyObject *
+_zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level,
+ PyObject *options, PyObject *zstd_dict);
+
+static PyObject *
+_zstd_ZstdCompressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 3
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(level), &_Py_ID(options), &_Py_ID(zstd_dict), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"level", "options", "zstd_dict", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "ZstdCompressor",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[3];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0;
+ PyObject *level = Py_None;
+ PyObject *options = Py_None;
+ PyObject *zstd_dict = Py_None;
+
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
+ /*minpos*/ 0, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ if (fastargs[0]) {
+ level = fastargs[0];
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
+ }
+ if (fastargs[1]) {
+ options = fastargs[1];
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
+ }
+ zstd_dict = fastargs[2];
+skip_optional_pos:
+ return_value = _zstd_ZstdCompressor_new_impl(type, level, options, zstd_dict);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_ZstdCompressor_compress__doc__,
+"compress($self, /, data, mode=ZstdCompressor.CONTINUE)\n"
+"--\n"
+"\n"
+"Provide data to the compressor object.\n"
+"\n"
+" mode\n"
+" Can be these 3 values ZstdCompressor.CONTINUE,\n"
+" ZstdCompressor.FLUSH_BLOCK, ZstdCompressor.FLUSH_FRAME\n"
+"\n"
+"Return a chunk of compressed data if possible, or b\'\' otherwise. When you have\n"
+"finished providing data to the compressor, call the flush() method to finish\n"
+"the compression process.");
+
+#define _ZSTD_ZSTDCOMPRESSOR_COMPRESS_METHODDEF \
+ {"compress", _PyCFunction_CAST(_zstd_ZstdCompressor_compress), METH_FASTCALL|METH_KEYWORDS, _zstd_ZstdCompressor_compress__doc__},
+
+static PyObject *
+_zstd_ZstdCompressor_compress_impl(ZstdCompressor *self, Py_buffer *data,
+ int mode);
+
+static PyObject *
+_zstd_ZstdCompressor_compress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(data), &_Py_ID(mode), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"data", "mode", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "compress",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+ Py_buffer data = {NULL, NULL};
+ int mode = ZSTD_e_continue;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ mode = PyLong_AsInt(args[1]);
+ if (mode == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional_pos:
+ return_value = _zstd_ZstdCompressor_compress_impl((ZstdCompressor *)self, &data, mode);
+
+exit:
+ /* Cleanup for data */
+ if (data.obj) {
+ PyBuffer_Release(&data);
+ }
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_ZstdCompressor_flush__doc__,
+"flush($self, /, mode=ZstdCompressor.FLUSH_FRAME)\n"
+"--\n"
+"\n"
+"Finish the compression process.\n"
+"\n"
+" mode\n"
+" Can be these 2 values ZstdCompressor.FLUSH_FRAME,\n"
+" ZstdCompressor.FLUSH_BLOCK\n"
+"\n"
+"Flush any remaining data left in internal buffers. Since Zstandard data\n"
+"consists of one or more independent frames, the compressor object can still\n"
+"be used after this method is called.");
+
+#define _ZSTD_ZSTDCOMPRESSOR_FLUSH_METHODDEF \
+ {"flush", _PyCFunction_CAST(_zstd_ZstdCompressor_flush), METH_FASTCALL|METH_KEYWORDS, _zstd_ZstdCompressor_flush__doc__},
+
+static PyObject *
+_zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode);
+
+static PyObject *
+_zstd_ZstdCompressor_flush(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(mode), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"mode", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "flush",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
+ int mode = ZSTD_e_end;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ mode = PyLong_AsInt(args[0]);
+ if (mode == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional_pos:
+ return_value = _zstd_ZstdCompressor_flush_impl((ZstdCompressor *)self, mode);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_ZstdCompressor_set_pledged_input_size__doc__,
+"set_pledged_input_size($self, size, /)\n"
+"--\n"
+"\n"
+"Set the uncompressed content size to be written into the frame header.\n"
+"\n"
+" size\n"
+" The size of the uncompressed data to be provided to the compressor.\n"
+"\n"
+"This method can be used to ensure the header of the frame about to be written\n"
+"includes the size of the data, unless the CompressionParameter.content_size_flag\n"
+"is set to False. If last_mode != FLUSH_FRAME, then a RuntimeError is raised.\n"
+"\n"
+"It is important to ensure that the pledged data size matches the actual data\n"
+"size. If they do not match the compressed output data may be corrupted and the\n"
+"final chunk written may be lost.");
+
+#define _ZSTD_ZSTDCOMPRESSOR_SET_PLEDGED_INPUT_SIZE_METHODDEF \
+ {"set_pledged_input_size", (PyCFunction)_zstd_ZstdCompressor_set_pledged_input_size, METH_O, _zstd_ZstdCompressor_set_pledged_input_size__doc__},
+
+static PyObject *
+_zstd_ZstdCompressor_set_pledged_input_size_impl(ZstdCompressor *self,
+ unsigned long long size);
+
+static PyObject *
+_zstd_ZstdCompressor_set_pledged_input_size(PyObject *self, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ unsigned long long size;
+
+ if (!zstd_contentsize_converter(arg, &size)) {
+ goto exit;
+ }
+ return_value = _zstd_ZstdCompressor_set_pledged_input_size_impl((ZstdCompressor *)self, size);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=c1d5c2cf06a8becd input=a9049054013a1b77]*/
diff --git a/Modules/_zstd/clinic/decompressor.c.h b/Modules/_zstd/clinic/decompressor.c.h
new file mode 100644
index 00000000000..c6fdae74ab0
--- /dev/null
+++ b/Modules/_zstd/clinic/decompressor.c.h
@@ -0,0 +1,223 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_abstract.h" // _PyNumber_Index()
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+PyDoc_STRVAR(_zstd_ZstdDecompressor_new__doc__,
+"ZstdDecompressor(zstd_dict=None, options=None)\n"
+"--\n"
+"\n"
+"Create a decompressor object for decompressing data incrementally.\n"
+"\n"
+" zstd_dict\n"
+" A ZstdDict object, a pre-trained Zstandard dictionary.\n"
+" options\n"
+" A dict object that contains advanced decompression parameters.\n"
+"\n"
+"Thread-safe at method level. For one-shot decompression, use the decompress()\n"
+"function instead.");
+
+static PyObject *
+_zstd_ZstdDecompressor_new_impl(PyTypeObject *type, PyObject *zstd_dict,
+ PyObject *options);
+
+static PyObject *
+_zstd_ZstdDecompressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(zstd_dict), &_Py_ID(options), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"zstd_dict", "options", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "ZstdDecompressor",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0;
+ PyObject *zstd_dict = Py_None;
+ PyObject *options = Py_None;
+
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
+ /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ if (fastargs[0]) {
+ zstd_dict = fastargs[0];
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
+ }
+ options = fastargs[1];
+skip_optional_pos:
+ return_value = _zstd_ZstdDecompressor_new_impl(type, zstd_dict, options);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_ZstdDecompressor_unused_data__doc__,
+"A bytes object of un-consumed input data.\n"
+"\n"
+"When ZstdDecompressor object stops after a frame is\n"
+"decompressed, unused input data after the frame. Otherwise this will be b\'\'.");
+#if defined(_zstd_ZstdDecompressor_unused_data_DOCSTR)
+# undef _zstd_ZstdDecompressor_unused_data_DOCSTR
+#endif
+#define _zstd_ZstdDecompressor_unused_data_DOCSTR _zstd_ZstdDecompressor_unused_data__doc__
+
+#if !defined(_zstd_ZstdDecompressor_unused_data_DOCSTR)
+# define _zstd_ZstdDecompressor_unused_data_DOCSTR NULL
+#endif
+#if defined(_ZSTD_ZSTDDECOMPRESSOR_UNUSED_DATA_GETSETDEF)
+# undef _ZSTD_ZSTDDECOMPRESSOR_UNUSED_DATA_GETSETDEF
+# define _ZSTD_ZSTDDECOMPRESSOR_UNUSED_DATA_GETSETDEF {"unused_data", (getter)_zstd_ZstdDecompressor_unused_data_get, (setter)_zstd_ZstdDecompressor_unused_data_set, _zstd_ZstdDecompressor_unused_data_DOCSTR},
+#else
+# define _ZSTD_ZSTDDECOMPRESSOR_UNUSED_DATA_GETSETDEF {"unused_data", (getter)_zstd_ZstdDecompressor_unused_data_get, NULL, _zstd_ZstdDecompressor_unused_data_DOCSTR},
+#endif
+
+static PyObject *
+_zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self);
+
+static PyObject *
+_zstd_ZstdDecompressor_unused_data_get(PyObject *self, void *Py_UNUSED(context))
+{
+ return _zstd_ZstdDecompressor_unused_data_get_impl((ZstdDecompressor *)self);
+}
+
+PyDoc_STRVAR(_zstd_ZstdDecompressor_decompress__doc__,
+"decompress($self, /, data, max_length=-1)\n"
+"--\n"
+"\n"
+"Decompress *data*, returning uncompressed bytes if possible, or b\'\' otherwise.\n"
+"\n"
+" data\n"
+" A bytes-like object, Zstandard data to be decompressed.\n"
+" max_length\n"
+" Maximum size of returned data. When it is negative, the size of\n"
+" output buffer is unlimited. When it is nonnegative, returns at\n"
+" most max_length bytes of decompressed data.\n"
+"\n"
+"If *max_length* is nonnegative, returns at most *max_length* bytes of\n"
+"decompressed data. If this limit is reached and further output can be\n"
+"produced, *self.needs_input* will be set to ``False``. In this case, the next\n"
+"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n"
+"\n"
+"If all of the input data was decompressed and returned (either because this\n"
+"was less than *max_length* bytes, or because *max_length* was negative),\n"
+"*self.needs_input* will be set to True.\n"
+"\n"
+"Attempting to decompress data after the end of a frame is reached raises an\n"
+"EOFError. Any data found after the end of the frame is ignored and saved in\n"
+"the self.unused_data attribute.");
+
+#define _ZSTD_ZSTDDECOMPRESSOR_DECOMPRESS_METHODDEF \
+ {"decompress", _PyCFunction_CAST(_zstd_ZstdDecompressor_decompress), METH_FASTCALL|METH_KEYWORDS, _zstd_ZstdDecompressor_decompress__doc__},
+
+static PyObject *
+_zstd_ZstdDecompressor_decompress_impl(ZstdDecompressor *self,
+ Py_buffer *data,
+ Py_ssize_t max_length);
+
+static PyObject *
+_zstd_ZstdDecompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(data), &_Py_ID(max_length), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"data", "max_length", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "decompress",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+ Py_buffer data = {NULL, NULL};
+ Py_ssize_t max_length = -1;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[1]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ max_length = ival;
+ }
+skip_optional_pos:
+ return_value = _zstd_ZstdDecompressor_decompress_impl((ZstdDecompressor *)self, &data, max_length);
+
+exit:
+ /* Cleanup for data */
+ if (data.obj) {
+ PyBuffer_Release(&data);
+ }
+
+ return return_value;
+}
+/*[clinic end generated code: output=30c12ef047027ede input=a9049054013a1b77]*/
diff --git a/Modules/_zstd/clinic/zstddict.c.h b/Modules/_zstd/clinic/zstddict.c.h
new file mode 100644
index 00000000000..79db85405d6
--- /dev/null
+++ b/Modules/_zstd/clinic/zstddict.c.h
@@ -0,0 +1,225 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+PyDoc_STRVAR(_zstd_ZstdDict_new__doc__,
+"ZstdDict(dict_content, /, *, is_raw=False)\n"
+"--\n"
+"\n"
+"Represents a Zstandard dictionary.\n"
+"\n"
+" dict_content\n"
+" The content of a Zstandard dictionary as a bytes-like object.\n"
+" is_raw\n"
+" If true, perform no checks on *dict_content*, useful for some\n"
+" advanced cases. Otherwise, check that the content represents\n"
+" a Zstandard dictionary created by the zstd library or CLI.\n"
+"\n"
+"The dictionary can be used for compression or decompression, and can be shared\n"
+"by multiple ZstdCompressor or ZstdDecompressor objects.");
+
+static PyObject *
+_zstd_ZstdDict_new_impl(PyTypeObject *type, Py_buffer *dict_content,
+ int is_raw);
+
+static PyObject *
+_zstd_ZstdDict_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(is_raw), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"", "is_raw", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "ZstdDict",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
+ Py_buffer dict_content = {NULL, NULL};
+ int is_raw = 0;
+
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(fastargs[0], &dict_content, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_kwonly;
+ }
+ is_raw = PyObject_IsTrue(fastargs[1]);
+ if (is_raw < 0) {
+ goto exit;
+ }
+skip_optional_kwonly:
+ return_value = _zstd_ZstdDict_new_impl(type, &dict_content, is_raw);
+
+exit:
+ /* Cleanup for dict_content */
+ if (dict_content.obj) {
+ PyBuffer_Release(&dict_content);
+ }
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_zstd_ZstdDict_dict_content__doc__,
+"The content of a Zstandard dictionary, as a bytes object.");
+#if defined(_zstd_ZstdDict_dict_content_DOCSTR)
+# undef _zstd_ZstdDict_dict_content_DOCSTR
+#endif
+#define _zstd_ZstdDict_dict_content_DOCSTR _zstd_ZstdDict_dict_content__doc__
+
+#if !defined(_zstd_ZstdDict_dict_content_DOCSTR)
+# define _zstd_ZstdDict_dict_content_DOCSTR NULL
+#endif
+#if defined(_ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF)
+# undef _ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF
+# define _ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF {"dict_content", (getter)_zstd_ZstdDict_dict_content_get, (setter)_zstd_ZstdDict_dict_content_set, _zstd_ZstdDict_dict_content_DOCSTR},
+#else
+# define _ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF {"dict_content", (getter)_zstd_ZstdDict_dict_content_get, NULL, _zstd_ZstdDict_dict_content_DOCSTR},
+#endif
+
+static PyObject *
+_zstd_ZstdDict_dict_content_get_impl(ZstdDict *self);
+
+static PyObject *
+_zstd_ZstdDict_dict_content_get(PyObject *self, void *Py_UNUSED(context))
+{
+ return _zstd_ZstdDict_dict_content_get_impl((ZstdDict *)self);
+}
+
+PyDoc_STRVAR(_zstd_ZstdDict_as_digested_dict__doc__,
+"Load as a digested dictionary to compressor.\n"
+"\n"
+"Pass this attribute as zstd_dict argument:\n"
+"compress(dat, zstd_dict=zd.as_digested_dict)\n"
+"\n"
+"1. Some advanced compression parameters of compressor may be overridden\n"
+" by parameters of digested dictionary.\n"
+"2. ZstdDict has a digested dictionaries cache for each compression level.\n"
+" It\'s faster when loading again a digested dictionary with the same\n"
+" compression level.\n"
+"3. No need to use this for decompression.");
+#if defined(_zstd_ZstdDict_as_digested_dict_DOCSTR)
+# undef _zstd_ZstdDict_as_digested_dict_DOCSTR
+#endif
+#define _zstd_ZstdDict_as_digested_dict_DOCSTR _zstd_ZstdDict_as_digested_dict__doc__
+
+#if !defined(_zstd_ZstdDict_as_digested_dict_DOCSTR)
+# define _zstd_ZstdDict_as_digested_dict_DOCSTR NULL
+#endif
+#if defined(_ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF)
+# undef _ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF
+# define _ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF {"as_digested_dict", (getter)_zstd_ZstdDict_as_digested_dict_get, (setter)_zstd_ZstdDict_as_digested_dict_set, _zstd_ZstdDict_as_digested_dict_DOCSTR},
+#else
+# define _ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF {"as_digested_dict", (getter)_zstd_ZstdDict_as_digested_dict_get, NULL, _zstd_ZstdDict_as_digested_dict_DOCSTR},
+#endif
+
+static PyObject *
+_zstd_ZstdDict_as_digested_dict_get_impl(ZstdDict *self);
+
+static PyObject *
+_zstd_ZstdDict_as_digested_dict_get(PyObject *self, void *Py_UNUSED(context))
+{
+ return _zstd_ZstdDict_as_digested_dict_get_impl((ZstdDict *)self);
+}
+
+PyDoc_STRVAR(_zstd_ZstdDict_as_undigested_dict__doc__,
+"Load as an undigested dictionary to compressor.\n"
+"\n"
+"Pass this attribute as zstd_dict argument:\n"
+"compress(dat, zstd_dict=zd.as_undigested_dict)\n"
+"\n"
+"1. The advanced compression parameters of compressor will not be overridden.\n"
+"2. Loading an undigested dictionary is costly. If load an undigested dictionary\n"
+" multiple times, consider reusing a compressor object.\n"
+"3. No need to use this for decompression.");
+#if defined(_zstd_ZstdDict_as_undigested_dict_DOCSTR)
+# undef _zstd_ZstdDict_as_undigested_dict_DOCSTR
+#endif
+#define _zstd_ZstdDict_as_undigested_dict_DOCSTR _zstd_ZstdDict_as_undigested_dict__doc__
+
+#if !defined(_zstd_ZstdDict_as_undigested_dict_DOCSTR)
+# define _zstd_ZstdDict_as_undigested_dict_DOCSTR NULL
+#endif
+#if defined(_ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF)
+# undef _ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF
+# define _ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF {"as_undigested_dict", (getter)_zstd_ZstdDict_as_undigested_dict_get, (setter)_zstd_ZstdDict_as_undigested_dict_set, _zstd_ZstdDict_as_undigested_dict_DOCSTR},
+#else
+# define _ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF {"as_undigested_dict", (getter)_zstd_ZstdDict_as_undigested_dict_get, NULL, _zstd_ZstdDict_as_undigested_dict_DOCSTR},
+#endif
+
+static PyObject *
+_zstd_ZstdDict_as_undigested_dict_get_impl(ZstdDict *self);
+
+static PyObject *
+_zstd_ZstdDict_as_undigested_dict_get(PyObject *self, void *Py_UNUSED(context))
+{
+ return _zstd_ZstdDict_as_undigested_dict_get_impl((ZstdDict *)self);
+}
+
+PyDoc_STRVAR(_zstd_ZstdDict_as_prefix__doc__,
+"Load as a prefix to compressor/decompressor.\n"
+"\n"
+"Pass this attribute as zstd_dict argument:\n"
+"compress(dat, zstd_dict=zd.as_prefix)\n"
+"\n"
+"1. Prefix is compatible with long distance matching, while dictionary is not.\n"
+"2. It only works for the first frame, then the compressor/decompressor will\n"
+" return to no prefix state.\n"
+"3. When decompressing, must use the same prefix as when compressing.\"");
+#if defined(_zstd_ZstdDict_as_prefix_DOCSTR)
+# undef _zstd_ZstdDict_as_prefix_DOCSTR
+#endif
+#define _zstd_ZstdDict_as_prefix_DOCSTR _zstd_ZstdDict_as_prefix__doc__
+
+#if !defined(_zstd_ZstdDict_as_prefix_DOCSTR)
+# define _zstd_ZstdDict_as_prefix_DOCSTR NULL
+#endif
+#if defined(_ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF)
+# undef _ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF
+# define _ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF {"as_prefix", (getter)_zstd_ZstdDict_as_prefix_get, (setter)_zstd_ZstdDict_as_prefix_set, _zstd_ZstdDict_as_prefix_DOCSTR},
+#else
+# define _ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF {"as_prefix", (getter)_zstd_ZstdDict_as_prefix_get, NULL, _zstd_ZstdDict_as_prefix_DOCSTR},
+#endif
+
+static PyObject *
+_zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self);
+
+static PyObject *
+_zstd_ZstdDict_as_prefix_get(PyObject *self, void *Py_UNUSED(context))
+{
+ return _zstd_ZstdDict_as_prefix_get_impl((ZstdDict *)self);
+}
+/*[clinic end generated code: output=4696cbc722e5fdfc input=a9049054013a1b77]*/
diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c
new file mode 100644
index 00000000000..bc9e6eff89a
--- /dev/null
+++ b/Modules/_zstd/compressor.c
@@ -0,0 +1,797 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+/* ZstdCompressor class definitions */
+
+/*[clinic input]
+module _zstd
+class _zstd.ZstdCompressor "ZstdCompressor *" "&zstd_compressor_type_spec"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7166021db1ef7df8]*/
+
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+
+#include "Python.h"
+
+#include "_zstdmodule.h"
+#include "buffer.h"
+#include "internal/pycore_lock.h" // PyMutex_IsLocked
+
+#include <stddef.h> // offsetof()
+#include <zstd.h> // ZSTD_*()
+
+typedef struct {
+ PyObject_HEAD
+
+ /* Compression context */
+ ZSTD_CCtx *cctx;
+
+ /* ZstdDict object in use */
+ PyObject *dict;
+
+ /* Last mode, initialized to ZSTD_e_end */
+ int last_mode;
+
+ /* (nbWorker >= 1) ? 1 : 0 */
+ int use_multithread;
+
+ /* Compression level */
+ int compression_level;
+
+ /* Lock to protect the compression context */
+ PyMutex lock;
+} ZstdCompressor;
+
+#define ZstdCompressor_CAST(op) ((ZstdCompressor *)op)
+
+/*[python input]
+
+class zstd_contentsize_converter(CConverter):
+ type = 'unsigned long long'
+ converter = 'zstd_contentsize_converter'
+
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=0932c350d633c7de]*/
+
+
+static int
+zstd_contentsize_converter(PyObject *size, unsigned long long *p)
+{
+ // None means the user indicates the size is unknown.
+ if (size == Py_None) {
+ *p = ZSTD_CONTENTSIZE_UNKNOWN;
+ }
+ else {
+ /* ZSTD_CONTENTSIZE_UNKNOWN is 0ULL - 1
+ ZSTD_CONTENTSIZE_ERROR is 0ULL - 2
+ Users should only pass values < ZSTD_CONTENTSIZE_ERROR */
+ unsigned long long pledged_size = PyLong_AsUnsignedLongLong(size);
+ /* Here we check for (unsigned long long)-1 as a sign of an error in
+ PyLong_AsUnsignedLongLong */
+ if (pledged_size == (unsigned long long)-1 && PyErr_Occurred()) {
+ *p = ZSTD_CONTENTSIZE_ERROR;
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ PyErr_Format(PyExc_ValueError,
+ "size argument should be a positive int less "
+ "than %ull", ZSTD_CONTENTSIZE_ERROR);
+ return 0;
+ }
+ return 0;
+ }
+ if (pledged_size >= ZSTD_CONTENTSIZE_ERROR) {
+ *p = ZSTD_CONTENTSIZE_ERROR;
+ PyErr_Format(PyExc_ValueError,
+ "size argument should be a positive int less "
+ "than %ull", ZSTD_CONTENTSIZE_ERROR);
+ return 0;
+ }
+ *p = pledged_size;
+ }
+ return 1;
+}
+
+#include "clinic/compressor.c.h"
+
+static int
+_zstd_set_c_level(ZstdCompressor *self, int level)
+{
+ /* Set integer compression level */
+ int min_level = ZSTD_minCLevel();
+ int max_level = ZSTD_maxCLevel();
+ if (level < min_level || level > max_level) {
+ PyErr_Format(PyExc_ValueError,
+ "illegal compression level %d; the valid range is [%d, %d]",
+ level, min_level, max_level);
+ return -1;
+ }
+
+ /* Save for generating ZSTD_CDICT */
+ self->compression_level = level;
+
+ /* Set compressionLevel to compression context */
+ size_t zstd_ret = ZSTD_CCtx_setParameter(
+ self->cctx, ZSTD_c_compressionLevel, level);
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ set_zstd_error(mod_state, ERR_SET_C_LEVEL, zstd_ret);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+_zstd_set_c_parameters(ZstdCompressor *self, PyObject *options)
+{
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ if (mod_state == NULL) {
+ return -1;
+ }
+
+ if (!PyDict_Check(options)) {
+ PyErr_Format(PyExc_TypeError,
+ "ZstdCompressor() argument 'options' must be dict, not %T",
+ options);
+ return -1;
+ }
+
+ Py_ssize_t pos = 0;
+ PyObject *key, *value;
+ while (PyDict_Next(options, &pos, &key, &value)) {
+ /* Check key type */
+ if (Py_TYPE(key) == mod_state->DParameter_type) {
+ PyErr_SetString(PyExc_TypeError,
+ "compression options dictionary key must not be a "
+ "DecompressionParameter attribute");
+ return -1;
+ }
+
+ Py_INCREF(key);
+ Py_INCREF(value);
+ int key_v = PyLong_AsInt(key);
+ Py_DECREF(key);
+ if (key_v == -1 && PyErr_Occurred()) {
+ Py_DECREF(value);
+ return -1;
+ }
+
+ int value_v = PyLong_AsInt(value);
+ Py_DECREF(value);
+ if (value_v == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ if (key_v == ZSTD_c_compressionLevel) {
+ if (_zstd_set_c_level(self, value_v) < 0) {
+ return -1;
+ }
+ continue;
+ }
+ if (key_v == ZSTD_c_nbWorkers) {
+ /* From the zstd library docs:
+ 1. When nbWorkers >= 1, triggers asynchronous mode when
+ used with ZSTD_compressStream2().
+ 2, Default value is `0`, aka "single-threaded mode" : no
+ worker is spawned, compression is performed inside
+ caller's thread, all invocations are blocking. */
+ if (value_v != 0) {
+ self->use_multithread = 1;
+ }
+ }
+
+ /* Set parameter to compression context */
+ size_t zstd_ret = ZSTD_CCtx_setParameter(self->cctx, key_v, value_v);
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ set_parameter_error(1, key_v, value_v);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void
+capsule_free_cdict(PyObject *capsule)
+{
+ ZSTD_CDict *cdict = PyCapsule_GetPointer(capsule, NULL);
+ ZSTD_freeCDict(cdict);
+}
+
+ZSTD_CDict *
+_get_CDict(ZstdDict *self, int compressionLevel)
+{
+ assert(PyMutex_IsLocked(&self->lock));
+ PyObject *level = NULL;
+ PyObject *capsule = NULL;
+ ZSTD_CDict *cdict;
+ int ret;
+
+
+ /* int level object */
+ level = PyLong_FromLong(compressionLevel);
+ if (level == NULL) {
+ goto error;
+ }
+
+ /* Get PyCapsule object from self->c_dicts */
+ ret = PyDict_GetItemRef(self->c_dicts, level, &capsule);
+ if (ret < 0) {
+ goto error;
+ }
+ if (capsule == NULL) {
+ /* Create ZSTD_CDict instance */
+ Py_BEGIN_ALLOW_THREADS
+ cdict = ZSTD_createCDict(self->dict_buffer, self->dict_len,
+ compressionLevel);
+ Py_END_ALLOW_THREADS
+
+ if (cdict == NULL) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ if (mod_state != NULL) {
+ PyErr_SetString(mod_state->ZstdError,
+ "Failed to create a ZSTD_CDict instance from "
+ "Zstandard dictionary content.");
+ }
+ goto error;
+ }
+
+ /* Put ZSTD_CDict instance into PyCapsule object */
+ capsule = PyCapsule_New(cdict, NULL, capsule_free_cdict);
+ if (capsule == NULL) {
+ ZSTD_freeCDict(cdict);
+ goto error;
+ }
+
+ /* Add PyCapsule object to self->c_dicts */
+ ret = PyDict_SetItem(self->c_dicts, level, capsule);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+ else {
+ /* ZSTD_CDict instance already exists */
+ cdict = PyCapsule_GetPointer(capsule, NULL);
+ }
+ goto success;
+
+error:
+ cdict = NULL;
+success:
+ Py_XDECREF(level);
+ Py_XDECREF(capsule);
+ return cdict;
+}
+
+static int
+_zstd_load_impl(ZstdCompressor *self, ZstdDict *zd,
+ _zstd_state *mod_state, int type)
+{
+ size_t zstd_ret;
+ if (type == DICT_TYPE_DIGESTED) {
+ /* Get ZSTD_CDict */
+ ZSTD_CDict *c_dict = _get_CDict(zd, self->compression_level);
+ if (c_dict == NULL) {
+ return -1;
+ }
+ /* Reference a prepared dictionary.
+ It overrides some compression context's parameters. */
+ zstd_ret = ZSTD_CCtx_refCDict(self->cctx, c_dict);
+ }
+ else if (type == DICT_TYPE_UNDIGESTED) {
+ /* Load a dictionary.
+ It doesn't override compression context's parameters. */
+ zstd_ret = ZSTD_CCtx_loadDictionary(self->cctx, zd->dict_buffer,
+ zd->dict_len);
+ }
+ else if (type == DICT_TYPE_PREFIX) {
+ /* Load a prefix */
+ zstd_ret = ZSTD_CCtx_refPrefix(self->cctx, zd->dict_buffer,
+ zd->dict_len);
+ }
+ else {
+ Py_UNREACHABLE();
+ }
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ set_zstd_error(mod_state, ERR_LOAD_C_DICT, zstd_ret);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+_zstd_load_c_dict(ZstdCompressor *self, PyObject *dict)
+{
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ /* When compressing, use undigested dictionary by default. */
+ int type = DICT_TYPE_UNDIGESTED;
+ ZstdDict *zd = _Py_parse_zstd_dict(mod_state, dict, &type);
+ if (zd == NULL) {
+ return -1;
+ }
+ int ret;
+ PyMutex_Lock(&zd->lock);
+ ret = _zstd_load_impl(self, zd, mod_state, type);
+ PyMutex_Unlock(&zd->lock);
+ return ret;
+}
+
+/*[clinic input]
+@classmethod
+_zstd.ZstdCompressor.__new__ as _zstd_ZstdCompressor_new
+ level: object = None
+ The compression level to use. Defaults to COMPRESSION_LEVEL_DEFAULT.
+ options: object = None
+ A dict object that contains advanced compression parameters.
+ zstd_dict: object = None
+ A ZstdDict object, a pre-trained Zstandard dictionary.
+
+Create a compressor object for compressing data incrementally.
+
+Thread-safe at method level. For one-shot compression, use the compress()
+function instead.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level,
+ PyObject *options, PyObject *zstd_dict)
+/*[clinic end generated code: output=cdef61eafecac3d7 input=92de0211ae20ffdc]*/
+{
+ ZstdCompressor* self = PyObject_GC_New(ZstdCompressor, type);
+ if (self == NULL) {
+ goto error;
+ }
+
+ self->use_multithread = 0;
+ self->dict = NULL;
+ self->lock = (PyMutex){0};
+
+ /* Compression context */
+ self->cctx = ZSTD_createCCtx();
+ if (self->cctx == NULL) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ if (mod_state != NULL) {
+ PyErr_SetString(mod_state->ZstdError,
+ "Unable to create ZSTD_CCtx instance.");
+ }
+ goto error;
+ }
+
+ /* Last mode */
+ self->last_mode = ZSTD_e_end;
+
+ if (level != Py_None && options != Py_None) {
+ PyErr_SetString(PyExc_TypeError,
+ "Only one of level or options should be used.");
+ goto error;
+ }
+
+ /* Set compression level */
+ if (level != Py_None) {
+ if (!PyLong_Check(level)) {
+ PyErr_SetString(PyExc_TypeError,
+ "invalid type for level, expected int");
+ goto error;
+ }
+ int level_v = PyLong_AsInt(level);
+ if (level_v == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ PyErr_Format(PyExc_ValueError,
+ "illegal compression level; the valid range is [%d, %d]",
+ ZSTD_minCLevel(), ZSTD_maxCLevel());
+ }
+ goto error;
+ }
+ if (_zstd_set_c_level(self, level_v) < 0) {
+ goto error;
+ }
+ }
+
+ /* Set options dictionary */
+ if (options != Py_None) {
+ if (_zstd_set_c_parameters(self, options) < 0) {
+ goto error;
+ }
+ }
+
+ /* Load Zstandard dictionary to compression context */
+ if (zstd_dict != Py_None) {
+ if (_zstd_load_c_dict(self, zstd_dict) < 0) {
+ goto error;
+ }
+ Py_INCREF(zstd_dict);
+ self->dict = zstd_dict;
+ }
+
+ // We can only start GC tracking once self->dict is set.
+ PyObject_GC_Track(self);
+
+ return (PyObject*)self;
+
+error:
+ Py_XDECREF(self);
+ return NULL;
+}
+
+static void
+ZstdCompressor_dealloc(PyObject *ob)
+{
+ ZstdCompressor *self = ZstdCompressor_CAST(ob);
+
+ PyObject_GC_UnTrack(self);
+
+ /* Free compression context */
+ if (self->cctx) {
+ ZSTD_freeCCtx(self->cctx);
+ }
+
+ assert(!PyMutex_IsLocked(&self->lock));
+
+ /* Py_XDECREF the dict after free the compression context */
+ Py_CLEAR(self->dict);
+
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject_GC_Del(ob);
+ Py_DECREF(tp);
+}
+
+static PyObject *
+compress_lock_held(ZstdCompressor *self, Py_buffer *data,
+ ZSTD_EndDirective end_directive)
+{
+ assert(PyMutex_IsLocked(&self->lock));
+ ZSTD_inBuffer in;
+ ZSTD_outBuffer out;
+ _BlocksOutputBuffer buffer = {.list = NULL};
+ size_t zstd_ret;
+ PyObject *ret;
+
+ /* Prepare input & output buffers */
+ if (data != NULL) {
+ in.src = data->buf;
+ in.size = data->len;
+ in.pos = 0;
+ }
+ else {
+ in.src = &in;
+ in.size = 0;
+ in.pos = 0;
+ }
+
+ /* Calculate output buffer's size */
+ size_t output_buffer_size = ZSTD_compressBound(in.size);
+ if (output_buffer_size > (size_t) PY_SSIZE_T_MAX) {
+ PyErr_NoMemory();
+ goto error;
+ }
+
+ if (_OutputBuffer_InitWithSize(&buffer, &out, -1,
+ (Py_ssize_t) output_buffer_size) < 0) {
+ goto error;
+ }
+
+
+ /* Zstandard stream compress */
+ while (1) {
+ Py_BEGIN_ALLOW_THREADS
+ zstd_ret = ZSTD_compressStream2(self->cctx, &out, &in, end_directive);
+ Py_END_ALLOW_THREADS
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ set_zstd_error(mod_state, ERR_COMPRESS, zstd_ret);
+ goto error;
+ }
+
+ /* Finished */
+ if (zstd_ret == 0) {
+ break;
+ }
+
+ /* Output buffer should be exhausted, grow the buffer. */
+ assert(out.pos == out.size);
+ if (out.pos == out.size) {
+ if (_OutputBuffer_Grow(&buffer, &out) < 0) {
+ goto error;
+ }
+ }
+ }
+
+ /* Return a bytes object */
+ ret = _OutputBuffer_Finish(&buffer, &out);
+ if (ret != NULL) {
+ return ret;
+ }
+
+error:
+ _OutputBuffer_OnError(&buffer);
+ return NULL;
+}
+
+#ifndef NDEBUG
+static inline int
+mt_continue_should_break(ZSTD_inBuffer *in, ZSTD_outBuffer *out)
+{
+ return in->size == in->pos && out->size != out->pos;
+}
+#endif
+
+static PyObject *
+compress_mt_continue_lock_held(ZstdCompressor *self, Py_buffer *data)
+{
+ assert(PyMutex_IsLocked(&self->lock));
+ ZSTD_inBuffer in;
+ ZSTD_outBuffer out;
+ _BlocksOutputBuffer buffer = {.list = NULL};
+ size_t zstd_ret;
+ PyObject *ret;
+
+ /* Prepare input & output buffers */
+ in.src = data->buf;
+ in.size = data->len;
+ in.pos = 0;
+
+ if (_OutputBuffer_InitAndGrow(&buffer, &out, -1) < 0) {
+ goto error;
+ }
+
+ /* Zstandard stream compress */
+ while (1) {
+ Py_BEGIN_ALLOW_THREADS
+ do {
+ zstd_ret = ZSTD_compressStream2(self->cctx, &out, &in,
+ ZSTD_e_continue);
+ } while (out.pos != out.size
+ && in.pos != in.size
+ && !ZSTD_isError(zstd_ret));
+ Py_END_ALLOW_THREADS
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ set_zstd_error(mod_state, ERR_COMPRESS, zstd_ret);
+ goto error;
+ }
+
+ /* Like compress_lock_held(), output as much as possible. */
+ if (out.pos == out.size) {
+ if (_OutputBuffer_Grow(&buffer, &out) < 0) {
+ goto error;
+ }
+ }
+ else if (in.pos == in.size) {
+ /* Finished */
+ assert(mt_continue_should_break(&in, &out));
+ break;
+ }
+ }
+
+ /* Return a bytes object */
+ ret = _OutputBuffer_Finish(&buffer, &out);
+ if (ret != NULL) {
+ return ret;
+ }
+
+error:
+ _OutputBuffer_OnError(&buffer);
+ return NULL;
+}
+
+/*[clinic input]
+_zstd.ZstdCompressor.compress
+
+ data: Py_buffer
+ mode: int(c_default="ZSTD_e_continue") = ZstdCompressor.CONTINUE
+ Can be these 3 values ZstdCompressor.CONTINUE,
+ ZstdCompressor.FLUSH_BLOCK, ZstdCompressor.FLUSH_FRAME
+
+Provide data to the compressor object.
+
+Return a chunk of compressed data if possible, or b'' otherwise. When you have
+finished providing data to the compressor, call the flush() method to finish
+the compression process.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdCompressor_compress_impl(ZstdCompressor *self, Py_buffer *data,
+ int mode)
+/*[clinic end generated code: output=ed7982d1cf7b4f98 input=ac2c21d180f579ea]*/
+{
+ PyObject *ret;
+
+ /* Check mode value */
+ if (mode != ZSTD_e_continue &&
+ mode != ZSTD_e_flush &&
+ mode != ZSTD_e_end)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "mode argument wrong value, it should be one of "
+ "ZstdCompressor.CONTINUE, ZstdCompressor.FLUSH_BLOCK, "
+ "ZstdCompressor.FLUSH_FRAME.");
+ return NULL;
+ }
+
+ /* Thread-safe code */
+ PyMutex_Lock(&self->lock);
+
+ /* Compress */
+ if (self->use_multithread && mode == ZSTD_e_continue) {
+ ret = compress_mt_continue_lock_held(self, data);
+ }
+ else {
+ ret = compress_lock_held(self, data, mode);
+ }
+
+ if (ret) {
+ self->last_mode = mode;
+ }
+ else {
+ self->last_mode = ZSTD_e_end;
+
+ /* Resetting cctx's session never fail */
+ ZSTD_CCtx_reset(self->cctx, ZSTD_reset_session_only);
+ }
+ PyMutex_Unlock(&self->lock);
+
+ return ret;
+}
+
+/*[clinic input]
+_zstd.ZstdCompressor.flush
+
+ mode: int(c_default="ZSTD_e_end") = ZstdCompressor.FLUSH_FRAME
+ Can be these 2 values ZstdCompressor.FLUSH_FRAME,
+ ZstdCompressor.FLUSH_BLOCK
+
+Finish the compression process.
+
+Flush any remaining data left in internal buffers. Since Zstandard data
+consists of one or more independent frames, the compressor object can still
+be used after this method is called.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode)
+/*[clinic end generated code: output=b7cf2c8d64dcf2e3 input=0ab19627f323cdbc]*/
+{
+ PyObject *ret;
+
+ /* Check mode value */
+ if (mode != ZSTD_e_end && mode != ZSTD_e_flush) {
+ PyErr_SetString(PyExc_ValueError,
+ "mode argument wrong value, it should be "
+ "ZstdCompressor.FLUSH_FRAME or "
+ "ZstdCompressor.FLUSH_BLOCK.");
+ return NULL;
+ }
+
+ /* Thread-safe code */
+ PyMutex_Lock(&self->lock);
+
+ ret = compress_lock_held(self, NULL, mode);
+
+ if (ret) {
+ self->last_mode = mode;
+ }
+ else {
+ self->last_mode = ZSTD_e_end;
+
+ /* Resetting cctx's session never fail */
+ ZSTD_CCtx_reset(self->cctx, ZSTD_reset_session_only);
+ }
+ PyMutex_Unlock(&self->lock);
+
+ return ret;
+}
+
+
+/*[clinic input]
+_zstd.ZstdCompressor.set_pledged_input_size
+
+ size: zstd_contentsize
+ The size of the uncompressed data to be provided to the compressor.
+ /
+
+Set the uncompressed content size to be written into the frame header.
+
+This method can be used to ensure the header of the frame about to be written
+includes the size of the data, unless the CompressionParameter.content_size_flag
+is set to False. If last_mode != FLUSH_FRAME, then a RuntimeError is raised.
+
+It is important to ensure that the pledged data size matches the actual data
+size. If they do not match the compressed output data may be corrupted and the
+final chunk written may be lost.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdCompressor_set_pledged_input_size_impl(ZstdCompressor *self,
+ unsigned long long size)
+/*[clinic end generated code: output=3a09e55cc0e3b4f9 input=afd8a7d78cff2eb5]*/
+{
+ // Error occured while converting argument, should be unreachable
+ assert(size != ZSTD_CONTENTSIZE_ERROR);
+
+ /* Thread-safe code */
+ PyMutex_Lock(&self->lock);
+
+ /* Check the current mode */
+ if (self->last_mode != ZSTD_e_end) {
+ PyErr_SetString(PyExc_ValueError,
+ "set_pledged_input_size() method must be called "
+ "when last_mode == FLUSH_FRAME");
+ PyMutex_Unlock(&self->lock);
+ return NULL;
+ }
+
+ /* Set pledged content size */
+ size_t zstd_ret = ZSTD_CCtx_setPledgedSrcSize(self->cctx, size);
+ PyMutex_Unlock(&self->lock);
+ if (ZSTD_isError(zstd_ret)) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ set_zstd_error(mod_state, ERR_SET_PLEDGED_INPUT_SIZE, zstd_ret);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef ZstdCompressor_methods[] = {
+ _ZSTD_ZSTDCOMPRESSOR_COMPRESS_METHODDEF
+ _ZSTD_ZSTDCOMPRESSOR_FLUSH_METHODDEF
+ _ZSTD_ZSTDCOMPRESSOR_SET_PLEDGED_INPUT_SIZE_METHODDEF
+ {NULL, NULL}
+};
+
+PyDoc_STRVAR(ZstdCompressor_last_mode_doc,
+"The last mode used to this compressor object, its value can be .CONTINUE,\n"
+".FLUSH_BLOCK, .FLUSH_FRAME. Initialized to .FLUSH_FRAME.\n\n"
+"It can be used to get the current state of a compressor, such as, data\n"
+"flushed, or a frame ended.");
+
+static PyMemberDef ZstdCompressor_members[] = {
+ {"last_mode", Py_T_INT, offsetof(ZstdCompressor, last_mode),
+ Py_READONLY, ZstdCompressor_last_mode_doc},
+ {NULL}
+};
+
+static int
+ZstdCompressor_traverse(PyObject *ob, visitproc visit, void *arg)
+{
+ ZstdCompressor *self = ZstdCompressor_CAST(ob);
+ Py_VISIT(self->dict);
+ return 0;
+}
+
+static int
+ZstdCompressor_clear(PyObject *ob)
+{
+ ZstdCompressor *self = ZstdCompressor_CAST(ob);
+ Py_CLEAR(self->dict);
+ return 0;
+}
+
+static PyType_Slot zstdcompressor_slots[] = {
+ {Py_tp_new, _zstd_ZstdCompressor_new},
+ {Py_tp_dealloc, ZstdCompressor_dealloc},
+ {Py_tp_methods, ZstdCompressor_methods},
+ {Py_tp_members, ZstdCompressor_members},
+ {Py_tp_doc, (void *)_zstd_ZstdCompressor_new__doc__},
+ {Py_tp_traverse, ZstdCompressor_traverse},
+ {Py_tp_clear, ZstdCompressor_clear},
+ {0, 0}
+};
+
+PyType_Spec zstd_compressor_type_spec = {
+ .name = "compression.zstd.ZstdCompressor",
+ .basicsize = sizeof(ZstdCompressor),
+ // Py_TPFLAGS_IMMUTABLETYPE is not used here as several
+ // associated constants need to be added to the type.
+ // PyType_Freeze is called later to set the flag.
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ .slots = zstdcompressor_slots,
+};
diff --git a/Modules/_zstd/decompressor.c b/Modules/_zstd/decompressor.c
new file mode 100644
index 00000000000..c53d6e4cb05
--- /dev/null
+++ b/Modules/_zstd/decompressor.c
@@ -0,0 +1,717 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+/* ZstdDecompressor class definition */
+
+/*[clinic input]
+module _zstd
+class _zstd.ZstdDecompressor "ZstdDecompressor *" "&zstd_decompressor_type_spec"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e2969ddf48a203e0]*/
+
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+
+#include "Python.h"
+
+#include "_zstdmodule.h"
+#include "buffer.h"
+#include "internal/pycore_lock.h" // PyMutex_IsLocked
+
+#include <stdbool.h> // bool
+#include <stddef.h> // offsetof()
+#include <zstd.h> // ZSTD_*()
+
+typedef struct {
+ PyObject_HEAD
+
+ /* Decompression context */
+ ZSTD_DCtx *dctx;
+
+ /* ZstdDict object in use */
+ PyObject *dict;
+
+ /* Unconsumed input data */
+ char *input_buffer;
+ size_t input_buffer_size;
+ size_t in_begin, in_end;
+
+ /* Unused data */
+ PyObject *unused_data;
+
+ /* 0 if decompressor has (or may has) unconsumed input data, 0 or 1. */
+ bool needs_input;
+
+ /* For ZstdDecompressor, 0 or 1.
+ 1 means the end of the first frame has been reached. */
+ bool eof;
+
+ /* Lock to protect the decompression context */
+ PyMutex lock;
+} ZstdDecompressor;
+
+#define ZstdDecompressor_CAST(op) ((ZstdDecompressor *)op)
+
+#include "clinic/decompressor.c.h"
+
+static inline ZSTD_DDict *
+_get_DDict(ZstdDict *self)
+{
+ assert(PyMutex_IsLocked(&self->lock));
+ ZSTD_DDict *ret;
+
+ if (self->d_dict == NULL) {
+ /* Create ZSTD_DDict instance from dictionary content */
+ Py_BEGIN_ALLOW_THREADS
+ ret = ZSTD_createDDict(self->dict_buffer, self->dict_len);
+ Py_END_ALLOW_THREADS
+ self->d_dict = ret;
+
+ if (self->d_dict == NULL) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ if (mod_state != NULL) {
+ PyErr_SetString(mod_state->ZstdError,
+ "Failed to create a ZSTD_DDict instance from "
+ "Zstandard dictionary content.");
+ }
+ }
+ }
+
+ return self->d_dict;
+}
+
+static int
+_zstd_set_d_parameters(ZstdDecompressor *self, PyObject *options)
+{
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ if (mod_state == NULL) {
+ return -1;
+ }
+
+ if (!PyDict_Check(options)) {
+ PyErr_Format(PyExc_TypeError,
+ "ZstdDecompressor() argument 'options' must be dict, not %T",
+ options);
+ return -1;
+ }
+
+ Py_ssize_t pos = 0;
+ PyObject *key, *value;
+ while (PyDict_Next(options, &pos, &key, &value)) {
+ /* Check key type */
+ if (Py_TYPE(key) == mod_state->CParameter_type) {
+ PyErr_SetString(PyExc_TypeError,
+ "compression options dictionary key must not be a "
+ "CompressionParameter attribute");
+ return -1;
+ }
+
+ Py_INCREF(key);
+ Py_INCREF(value);
+ int key_v = PyLong_AsInt(key);
+ Py_DECREF(key);
+ if (key_v == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ int value_v = PyLong_AsInt(value);
+ Py_DECREF(value);
+ if (value_v == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ /* Set parameter to compression context */
+ size_t zstd_ret = ZSTD_DCtx_setParameter(self->dctx, key_v, value_v);
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ set_parameter_error(0, key_v, value_v);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+_zstd_load_impl(ZstdDecompressor *self, ZstdDict *zd,
+ _zstd_state *mod_state, int type)
+{
+ size_t zstd_ret;
+ if (type == DICT_TYPE_DIGESTED) {
+ /* Get ZSTD_DDict */
+ ZSTD_DDict *d_dict = _get_DDict(zd);
+ if (d_dict == NULL) {
+ return -1;
+ }
+ /* Reference a prepared dictionary */
+ zstd_ret = ZSTD_DCtx_refDDict(self->dctx, d_dict);
+ }
+ else if (type == DICT_TYPE_UNDIGESTED) {
+ /* Load a dictionary */
+ zstd_ret = ZSTD_DCtx_loadDictionary(self->dctx, zd->dict_buffer,
+ zd->dict_len);
+ }
+ else if (type == DICT_TYPE_PREFIX) {
+ /* Load a prefix */
+ zstd_ret = ZSTD_DCtx_refPrefix(self->dctx, zd->dict_buffer,
+ zd->dict_len);
+ }
+ else {
+ /* Impossible code path */
+ PyErr_SetString(PyExc_SystemError,
+ "load_d_dict() impossible code path");
+ return -1;
+ }
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ set_zstd_error(mod_state, ERR_LOAD_D_DICT, zstd_ret);
+ return -1;
+ }
+ return 0;
+}
+
+/* Load dictionary or prefix to decompression context */
+static int
+_zstd_load_d_dict(ZstdDecompressor *self, PyObject *dict)
+{
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ /* When decompressing, use digested dictionary by default. */
+ int type = DICT_TYPE_DIGESTED;
+ ZstdDict *zd = _Py_parse_zstd_dict(mod_state, dict, &type);
+ if (zd == NULL) {
+ return -1;
+ }
+ int ret;
+ PyMutex_Lock(&zd->lock);
+ ret = _zstd_load_impl(self, zd, mod_state, type);
+ PyMutex_Unlock(&zd->lock);
+ return ret;
+}
+
+/*
+ Decompress implementation in pseudo code:
+
+ initialize_output_buffer
+ while True:
+ decompress_data
+ set_object_flag # .eof
+
+ if output_buffer_exhausted:
+ if output_buffer_reached_max_length:
+ finish
+ grow_output_buffer
+ elif input_buffer_exhausted:
+ finish
+
+ ZSTD_decompressStream()'s size_t return value:
+ - 0 when a frame is completely decoded and fully flushed,
+ zstd's internal buffer has no data.
+ - An error code, which can be tested using ZSTD_isError().
+ - Or any other value > 0, which means there is still some decoding or
+ flushing to do to complete current frame.
+
+ Note, decompressing "an empty input" in any case will make it > 0.
+*/
+static PyObject *
+decompress_lock_held(ZstdDecompressor *self, ZSTD_inBuffer *in,
+ Py_ssize_t max_length)
+{
+ size_t zstd_ret;
+ ZSTD_outBuffer out;
+ _BlocksOutputBuffer buffer = {.list = NULL};
+ PyObject *ret;
+
+ /* Initialize the output buffer */
+ if (_OutputBuffer_InitAndGrow(&buffer, &out, max_length) < 0) {
+ goto error;
+ }
+ assert(out.pos == 0);
+
+ while (1) {
+ /* Decompress */
+ Py_BEGIN_ALLOW_THREADS
+ zstd_ret = ZSTD_decompressStream(self->dctx, &out, in);
+ Py_END_ALLOW_THREADS
+
+ /* Check error */
+ if (ZSTD_isError(zstd_ret)) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ set_zstd_error(mod_state, ERR_DECOMPRESS, zstd_ret);
+ goto error;
+ }
+
+ /* Set .eof flag */
+ if (zstd_ret == 0) {
+ /* Stop when a frame is decompressed */
+ self->eof = 1;
+ break;
+ }
+
+ /* Need to check out before in. Maybe zstd's internal buffer still has
+ a few bytes that can be output, grow the buffer and continue. */
+ if (out.pos == out.size) {
+ /* Output buffer exhausted */
+
+ /* Output buffer reached max_length */
+ if (_OutputBuffer_ReachedMaxLength(&buffer, &out)) {
+ break;
+ }
+
+ /* Grow output buffer */
+ if (_OutputBuffer_Grow(&buffer, &out) < 0) {
+ goto error;
+ }
+ assert(out.pos == 0);
+
+ }
+ else if (in->pos == in->size) {
+ /* Finished */
+ break;
+ }
+ }
+
+ /* Return a bytes object */
+ ret = _OutputBuffer_Finish(&buffer, &out);
+ if (ret != NULL) {
+ return ret;
+ }
+
+error:
+ _OutputBuffer_OnError(&buffer);
+ return NULL;
+}
+
+static void
+decompressor_reset_session_lock_held(ZstdDecompressor *self)
+{
+ assert(PyMutex_IsLocked(&self->lock));
+
+ /* Reset variables */
+ self->in_begin = 0;
+ self->in_end = 0;
+
+ Py_CLEAR(self->unused_data);
+
+ /* Reset variables in one operation */
+ self->needs_input = 1;
+ self->eof = 0;
+
+ /* Resetting session is guaranteed to never fail */
+ ZSTD_DCtx_reset(self->dctx, ZSTD_reset_session_only);
+}
+
+static PyObject *
+stream_decompress_lock_held(ZstdDecompressor *self, Py_buffer *data,
+ Py_ssize_t max_length)
+{
+ assert(PyMutex_IsLocked(&self->lock));
+ ZSTD_inBuffer in;
+ PyObject *ret = NULL;
+ int use_input_buffer;
+
+ /* Check .eof flag */
+ if (self->eof) {
+ PyErr_SetString(PyExc_EOFError,
+ "Already at the end of a Zstandard frame.");
+ assert(ret == NULL);
+ return NULL;
+ }
+
+ /* Prepare input buffer w/wo unconsumed data */
+ if (self->in_begin == self->in_end) {
+ /* No unconsumed data */
+ use_input_buffer = 0;
+
+ in.src = data->buf;
+ in.size = data->len;
+ in.pos = 0;
+ }
+ else if (data->len == 0) {
+ /* Has unconsumed data, fast path for b'' */
+ assert(self->in_begin < self->in_end);
+
+ use_input_buffer = 1;
+
+ in.src = self->input_buffer + self->in_begin;
+ in.size = self->in_end - self->in_begin;
+ in.pos = 0;
+ }
+ else {
+ /* Has unconsumed data */
+ use_input_buffer = 1;
+
+ /* Unconsumed data size in input_buffer */
+ size_t used_now = self->in_end - self->in_begin;
+ assert(self->in_end > self->in_begin);
+
+ /* Number of bytes we can append to input buffer */
+ size_t avail_now = self->input_buffer_size - self->in_end;
+ assert(self->input_buffer_size >= self->in_end);
+
+ /* Number of bytes we can append if we move existing contents to
+ beginning of buffer */
+ size_t avail_total = self->input_buffer_size - used_now;
+ assert(self->input_buffer_size >= used_now);
+
+ if (avail_total < (size_t) data->len) {
+ char *tmp;
+ size_t new_size = used_now + data->len;
+
+ /* Allocate with new size */
+ tmp = PyMem_Malloc(new_size);
+ if (tmp == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+
+ /* Copy unconsumed data to the beginning of new buffer */
+ memcpy(tmp,
+ self->input_buffer + self->in_begin,
+ used_now);
+
+ /* Switch to new buffer */
+ PyMem_Free(self->input_buffer);
+ self->input_buffer = tmp;
+ self->input_buffer_size = new_size;
+
+ /* Set begin & end position */
+ self->in_begin = 0;
+ self->in_end = used_now;
+ }
+ else if (avail_now < (size_t) data->len) {
+ /* Move unconsumed data to the beginning.
+ Overlap is possible, so use memmove(). */
+ memmove(self->input_buffer,
+ self->input_buffer + self->in_begin,
+ used_now);
+
+ /* Set begin & end position */
+ self->in_begin = 0;
+ self->in_end = used_now;
+ }
+
+ /* Copy data to input buffer */
+ memcpy(self->input_buffer + self->in_end, data->buf, data->len);
+ self->in_end += data->len;
+
+ in.src = self->input_buffer + self->in_begin;
+ in.size = used_now + data->len;
+ in.pos = 0;
+ }
+ assert(in.pos == 0);
+
+ /* Decompress */
+ ret = decompress_lock_held(self, &in, max_length);
+ if (ret == NULL) {
+ goto error;
+ }
+
+ /* Unconsumed input data */
+ if (in.pos == in.size) {
+ if (Py_SIZE(ret) == max_length || self->eof) {
+ self->needs_input = 0;
+ }
+ else {
+ self->needs_input = 1;
+ }
+
+ if (use_input_buffer) {
+ /* Clear input_buffer */
+ self->in_begin = 0;
+ self->in_end = 0;
+ }
+ }
+ else {
+ size_t data_size = in.size - in.pos;
+
+ self->needs_input = 0;
+
+ if (!use_input_buffer) {
+ /* Discard buffer if it's too small
+ (resizing it may needlessly copy the current contents) */
+ if (self->input_buffer != NULL
+ && self->input_buffer_size < data_size)
+ {
+ PyMem_Free(self->input_buffer);
+ self->input_buffer = NULL;
+ self->input_buffer_size = 0;
+ }
+
+ /* Allocate if necessary */
+ if (self->input_buffer == NULL) {
+ self->input_buffer = PyMem_Malloc(data_size);
+ if (self->input_buffer == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ self->input_buffer_size = data_size;
+ }
+
+ /* Copy unconsumed data */
+ memcpy(self->input_buffer, (char*)in.src + in.pos, data_size);
+ self->in_begin = 0;
+ self->in_end = data_size;
+ }
+ else {
+ /* Use input buffer */
+ self->in_begin += in.pos;
+ }
+ }
+
+ return ret;
+
+error:
+ /* Reset decompressor's states/session */
+ decompressor_reset_session_lock_held(self);
+
+ Py_CLEAR(ret);
+ return NULL;
+}
+
+
+/*[clinic input]
+@classmethod
+_zstd.ZstdDecompressor.__new__ as _zstd_ZstdDecompressor_new
+ zstd_dict: object = None
+ A ZstdDict object, a pre-trained Zstandard dictionary.
+ options: object = None
+ A dict object that contains advanced decompression parameters.
+
+Create a decompressor object for decompressing data incrementally.
+
+Thread-safe at method level. For one-shot decompression, use the decompress()
+function instead.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDecompressor_new_impl(PyTypeObject *type, PyObject *zstd_dict,
+ PyObject *options)
+/*[clinic end generated code: output=590ca65c1102ff4a input=213daa57e3ea4062]*/
+{
+ ZstdDecompressor* self = PyObject_GC_New(ZstdDecompressor, type);
+ if (self == NULL) {
+ goto error;
+ }
+
+ self->input_buffer = NULL;
+ self->input_buffer_size = 0;
+ self->in_begin = -1;
+ self->in_end = -1;
+ self->unused_data = NULL;
+ self->eof = 0;
+ self->dict = NULL;
+ self->lock = (PyMutex){0};
+
+ /* needs_input flag */
+ self->needs_input = 1;
+
+ /* Decompression context */
+ self->dctx = ZSTD_createDCtx();
+ if (self->dctx == NULL) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ if (mod_state != NULL) {
+ PyErr_SetString(mod_state->ZstdError,
+ "Unable to create ZSTD_DCtx instance.");
+ }
+ goto error;
+ }
+
+ /* Load Zstandard dictionary to decompression context */
+ if (zstd_dict != Py_None) {
+ if (_zstd_load_d_dict(self, zstd_dict) < 0) {
+ goto error;
+ }
+ Py_INCREF(zstd_dict);
+ self->dict = zstd_dict;
+ }
+
+ /* Set options dictionary */
+ if (options != Py_None) {
+ if (_zstd_set_d_parameters(self, options) < 0) {
+ goto error;
+ }
+ }
+
+ // We can only start GC tracking once self->dict is set.
+ PyObject_GC_Track(self);
+
+ return (PyObject*)self;
+
+error:
+ Py_XDECREF(self);
+ return NULL;
+}
+
+static void
+ZstdDecompressor_dealloc(PyObject *ob)
+{
+ ZstdDecompressor *self = ZstdDecompressor_CAST(ob);
+
+ PyObject_GC_UnTrack(self);
+
+ /* Free decompression context */
+ if (self->dctx) {
+ ZSTD_freeDCtx(self->dctx);
+ }
+
+ assert(!PyMutex_IsLocked(&self->lock));
+
+ /* Py_CLEAR the dict after free decompression context */
+ Py_CLEAR(self->dict);
+
+ /* Free unconsumed input data buffer */
+ PyMem_Free(self->input_buffer);
+
+ /* Free unused data */
+ Py_CLEAR(self->unused_data);
+
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject_GC_Del(ob);
+ Py_DECREF(tp);
+}
+
+/*[clinic input]
+@getter
+_zstd.ZstdDecompressor.unused_data
+
+A bytes object of un-consumed input data.
+
+When ZstdDecompressor object stops after a frame is
+decompressed, unused input data after the frame. Otherwise this will be b''.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self)
+/*[clinic end generated code: output=f3a20940f11b6b09 input=54d41ecd681a3444]*/
+{
+ PyObject *ret;
+
+ PyMutex_Lock(&self->lock);
+
+ if (!self->eof) {
+ PyMutex_Unlock(&self->lock);
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+ else {
+ if (self->unused_data == NULL) {
+ self->unused_data = PyBytes_FromStringAndSize(
+ self->input_buffer + self->in_begin,
+ self->in_end - self->in_begin);
+ ret = self->unused_data;
+ Py_XINCREF(ret);
+ }
+ else {
+ ret = self->unused_data;
+ Py_INCREF(ret);
+ }
+ }
+
+ PyMutex_Unlock(&self->lock);
+ return ret;
+}
+
+/*[clinic input]
+_zstd.ZstdDecompressor.decompress
+
+ data: Py_buffer
+ A bytes-like object, Zstandard data to be decompressed.
+ max_length: Py_ssize_t = -1
+ Maximum size of returned data. When it is negative, the size of
+ output buffer is unlimited. When it is nonnegative, returns at
+ most max_length bytes of decompressed data.
+
+Decompress *data*, returning uncompressed bytes if possible, or b'' otherwise.
+
+If *max_length* is nonnegative, returns at most *max_length* bytes of
+decompressed data. If this limit is reached and further output can be
+produced, *self.needs_input* will be set to ``False``. In this case, the next
+call to *decompress()* may provide *data* as b'' to obtain more of the output.
+
+If all of the input data was decompressed and returned (either because this
+was less than *max_length* bytes, or because *max_length* was negative),
+*self.needs_input* will be set to True.
+
+Attempting to decompress data after the end of a frame is reached raises an
+EOFError. Any data found after the end of the frame is ignored and saved in
+the self.unused_data attribute.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDecompressor_decompress_impl(ZstdDecompressor *self,
+ Py_buffer *data,
+ Py_ssize_t max_length)
+/*[clinic end generated code: output=a4302b3c940dbec6 input=6463dfdf98091caa]*/
+{
+ PyObject *ret;
+ /* Thread-safe code */
+ PyMutex_Lock(&self->lock);
+ ret = stream_decompress_lock_held(self, data, max_length);
+ PyMutex_Unlock(&self->lock);
+ return ret;
+}
+
+static PyMethodDef ZstdDecompressor_methods[] = {
+ _ZSTD_ZSTDDECOMPRESSOR_DECOMPRESS_METHODDEF
+ {NULL, NULL}
+};
+
+PyDoc_STRVAR(ZstdDecompressor_eof_doc,
+"True means the end of the first frame has been reached. If decompress data\n"
+"after that, an EOFError exception will be raised.");
+
+PyDoc_STRVAR(ZstdDecompressor_needs_input_doc,
+"If the max_length output limit in .decompress() method has been reached,\n"
+"and the decompressor has (or may has) unconsumed input data, it will be set\n"
+"to False. In this case, passing b'' to the .decompress() method may output\n"
+"further data.");
+
+static PyMemberDef ZstdDecompressor_members[] = {
+ {"eof", Py_T_BOOL, offsetof(ZstdDecompressor, eof),
+ Py_READONLY, ZstdDecompressor_eof_doc},
+ {"needs_input", Py_T_BOOL, offsetof(ZstdDecompressor, needs_input),
+ Py_READONLY, ZstdDecompressor_needs_input_doc},
+ {NULL}
+};
+
+static PyGetSetDef ZstdDecompressor_getset[] = {
+ _ZSTD_ZSTDDECOMPRESSOR_UNUSED_DATA_GETSETDEF
+ {NULL}
+};
+
+static int
+ZstdDecompressor_traverse(PyObject *ob, visitproc visit, void *arg)
+{
+ ZstdDecompressor *self = ZstdDecompressor_CAST(ob);
+ Py_VISIT(self->dict);
+ return 0;
+}
+
+static int
+ZstdDecompressor_clear(PyObject *ob)
+{
+ ZstdDecompressor *self = ZstdDecompressor_CAST(ob);
+ Py_CLEAR(self->dict);
+ Py_CLEAR(self->unused_data);
+ return 0;
+}
+
+static PyType_Slot ZstdDecompressor_slots[] = {
+ {Py_tp_new, _zstd_ZstdDecompressor_new},
+ {Py_tp_dealloc, ZstdDecompressor_dealloc},
+ {Py_tp_methods, ZstdDecompressor_methods},
+ {Py_tp_members, ZstdDecompressor_members},
+ {Py_tp_getset, ZstdDecompressor_getset},
+ {Py_tp_doc, (void *)_zstd_ZstdDecompressor_new__doc__},
+ {Py_tp_traverse, ZstdDecompressor_traverse},
+ {Py_tp_clear, ZstdDecompressor_clear},
+ {0, 0}
+};
+
+PyType_Spec zstd_decompressor_type_spec = {
+ .name = "compression.zstd.ZstdDecompressor",
+ .basicsize = sizeof(ZstdDecompressor),
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE
+ | Py_TPFLAGS_HAVE_GC,
+ .slots = ZstdDecompressor_slots,
+};
diff --git a/Modules/_zstd/zstddict.c b/Modules/_zstd/zstddict.c
new file mode 100644
index 00000000000..14f74aaed46
--- /dev/null
+++ b/Modules/_zstd/zstddict.c
@@ -0,0 +1,273 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+/* ZstdDict class definitions */
+
+/*[clinic input]
+module _zstd
+class _zstd.ZstdDict "ZstdDict *" "&zstd_dict_type_spec"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3dcc175ec974f81c]*/
+
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+
+#include "Python.h"
+
+#include "_zstdmodule.h"
+#include "clinic/zstddict.c.h"
+#include "internal/pycore_lock.h" // PyMutex_IsLocked
+
+#include <zstd.h> // ZSTD_freeDDict(), ZSTD_getDictID_fromDict()
+
+#define ZstdDict_CAST(op) ((ZstdDict *)op)
+
+/*[clinic input]
+@classmethod
+_zstd.ZstdDict.__new__ as _zstd_ZstdDict_new
+ dict_content: Py_buffer
+ The content of a Zstandard dictionary as a bytes-like object.
+ /
+ *
+ is_raw: bool = False
+ If true, perform no checks on *dict_content*, useful for some
+ advanced cases. Otherwise, check that the content represents
+ a Zstandard dictionary created by the zstd library or CLI.
+
+Represents a Zstandard dictionary.
+
+The dictionary can be used for compression or decompression, and can be shared
+by multiple ZstdCompressor or ZstdDecompressor objects.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDict_new_impl(PyTypeObject *type, Py_buffer *dict_content,
+ int is_raw)
+/*[clinic end generated code: output=685b7406a48b0949 input=9e8c493e31c98383]*/
+{
+ /* All dictionaries must be at least 8 bytes */
+ if (dict_content->len < 8) {
+ PyErr_SetString(PyExc_ValueError,
+ "Zstandard dictionary content too short "
+ "(must have at least eight bytes)");
+ return NULL;
+ }
+
+ ZstdDict* self = PyObject_GC_New(ZstdDict, type);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->d_dict = NULL;
+ self->dict_buffer = NULL;
+ self->dict_id = 0;
+ self->lock = (PyMutex){0};
+
+ /* ZSTD_CDict dict */
+ self->c_dicts = PyDict_New();
+ if (self->c_dicts == NULL) {
+ goto error;
+ }
+
+ self->dict_buffer = PyMem_Malloc(dict_content->len);
+ if (!self->dict_buffer) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ memcpy(self->dict_buffer, dict_content->buf, dict_content->len);
+ self->dict_len = dict_content->len;
+
+ /* Get dict_id, 0 means "raw content" dictionary. */
+ self->dict_id = ZSTD_getDictID_fromDict(self->dict_buffer, self->dict_len);
+
+ /* Check validity for ordinary dictionary */
+ if (!is_raw && self->dict_id == 0) {
+ PyErr_SetString(PyExc_ValueError, "invalid Zstandard dictionary");
+ goto error;
+ }
+
+ PyObject_GC_Track(self);
+
+ return (PyObject *)self;
+
+error:
+ Py_XDECREF(self);
+ return NULL;
+}
+
+static void
+ZstdDict_dealloc(PyObject *ob)
+{
+ ZstdDict *self = ZstdDict_CAST(ob);
+
+ PyObject_GC_UnTrack(self);
+
+ /* Free ZSTD_DDict instance */
+ if (self->d_dict) {
+ ZSTD_freeDDict(self->d_dict);
+ }
+
+ assert(!PyMutex_IsLocked(&self->lock));
+
+ /* Release dict_buffer after freeing ZSTD_CDict/ZSTD_DDict instances */
+ PyMem_Free(self->dict_buffer);
+ Py_CLEAR(self->c_dicts);
+
+ PyTypeObject *tp = Py_TYPE(self);
+ tp->tp_free(self);
+ Py_DECREF(tp);
+}
+
+PyDoc_STRVAR(ZstdDict_dictid_doc,
+"the Zstandard dictionary, an int between 0 and 2**32.\n\n"
+"A non-zero value represents an ordinary Zstandard dictionary, "
+"conforming to the standardised format.\n\n"
+"The special value '0' means a 'raw content' dictionary,"
+"without any restrictions on format or content.");
+
+static PyObject *
+ZstdDict_repr(PyObject *ob)
+{
+ ZstdDict *dict = ZstdDict_CAST(ob);
+ return PyUnicode_FromFormat("<ZstdDict dict_id=%u dict_size=%zd>",
+ (unsigned int)dict->dict_id, dict->dict_len);
+}
+
+static PyMemberDef ZstdDict_members[] = {
+ {"dict_id", Py_T_UINT, offsetof(ZstdDict, dict_id), Py_READONLY, ZstdDict_dictid_doc},
+ {NULL}
+};
+
+/*[clinic input]
+@getter
+_zstd.ZstdDict.dict_content
+
+The content of a Zstandard dictionary, as a bytes object.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDict_dict_content_get_impl(ZstdDict *self)
+/*[clinic end generated code: output=0d05caa5b550eabb input=4ed526d1c151c596]*/
+{
+ return PyBytes_FromStringAndSize(self->dict_buffer, self->dict_len);
+}
+
+/*[clinic input]
+@getter
+_zstd.ZstdDict.as_digested_dict
+
+Load as a digested dictionary to compressor.
+
+Pass this attribute as zstd_dict argument:
+compress(dat, zstd_dict=zd.as_digested_dict)
+
+1. Some advanced compression parameters of compressor may be overridden
+ by parameters of digested dictionary.
+2. ZstdDict has a digested dictionaries cache for each compression level.
+ It's faster when loading again a digested dictionary with the same
+ compression level.
+3. No need to use this for decompression.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDict_as_digested_dict_get_impl(ZstdDict *self)
+/*[clinic end generated code: output=09b086e7a7320dbb input=ee45e1b4a48f6f2c]*/
+{
+ return Py_BuildValue("Oi", self, DICT_TYPE_DIGESTED);
+}
+
+/*[clinic input]
+@getter
+_zstd.ZstdDict.as_undigested_dict
+
+Load as an undigested dictionary to compressor.
+
+Pass this attribute as zstd_dict argument:
+compress(dat, zstd_dict=zd.as_undigested_dict)
+
+1. The advanced compression parameters of compressor will not be overridden.
+2. Loading an undigested dictionary is costly. If load an undigested dictionary
+ multiple times, consider reusing a compressor object.
+3. No need to use this for decompression.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDict_as_undigested_dict_get_impl(ZstdDict *self)
+/*[clinic end generated code: output=43c7a989e6d4253a input=d39210eedec76fed]*/
+{
+ return Py_BuildValue("Oi", self, DICT_TYPE_UNDIGESTED);
+}
+
+/*[clinic input]
+@getter
+_zstd.ZstdDict.as_prefix
+
+Load as a prefix to compressor/decompressor.
+
+Pass this attribute as zstd_dict argument:
+compress(dat, zstd_dict=zd.as_prefix)
+
+1. Prefix is compatible with long distance matching, while dictionary is not.
+2. It only works for the first frame, then the compressor/decompressor will
+ return to no prefix state.
+3. When decompressing, must use the same prefix as when compressing."
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self)
+/*[clinic end generated code: output=6f7130c356595a16 input=d59757b0b5a9551a]*/
+{
+ return Py_BuildValue("Oi", self, DICT_TYPE_PREFIX);
+}
+
+static PyGetSetDef ZstdDict_getset[] = {
+ _ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF
+ _ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF
+ _ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF
+ _ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF
+ {NULL}
+};
+
+static Py_ssize_t
+ZstdDict_length(PyObject *ob)
+{
+ ZstdDict *self = ZstdDict_CAST(ob);
+ return self->dict_len;
+}
+
+static int
+ZstdDict_traverse(PyObject *ob, visitproc visit, void *arg)
+{
+ ZstdDict *self = ZstdDict_CAST(ob);
+ Py_VISIT(self->c_dicts);
+ return 0;
+}
+
+static int
+ZstdDict_clear(PyObject *ob)
+{
+ ZstdDict *self = ZstdDict_CAST(ob);
+ Py_CLEAR(self->c_dicts);
+ return 0;
+}
+
+static PyType_Slot zstddict_slots[] = {
+ {Py_tp_members, ZstdDict_members},
+ {Py_tp_getset, ZstdDict_getset},
+ {Py_tp_new, _zstd_ZstdDict_new},
+ {Py_tp_dealloc, ZstdDict_dealloc},
+ {Py_tp_repr, ZstdDict_repr},
+ {Py_tp_doc, (void *)_zstd_ZstdDict_new__doc__},
+ {Py_sq_length, ZstdDict_length},
+ {Py_tp_traverse, ZstdDict_traverse},
+ {Py_tp_clear, ZstdDict_clear},
+ {0, 0}
+};
+
+PyType_Spec zstd_dict_type_spec = {
+ .name = "compression.zstd.ZstdDict",
+ .basicsize = sizeof(ZstdDict),
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE
+ | Py_TPFLAGS_HAVE_GC,
+ .slots = zstddict_slots,
+};
diff --git a/Modules/_zstd/zstddict.h b/Modules/_zstd/zstddict.h
new file mode 100644
index 00000000000..4a403416dbd
--- /dev/null
+++ b/Modules/_zstd/zstddict.h
@@ -0,0 +1,29 @@
+/* Low level interface to the Zstandard algorthm & the zstd library. */
+
+#ifndef ZSTD_DICT_H
+#define ZSTD_DICT_H
+
+#include <zstd.h> // ZSTD_DDict
+
+typedef struct {
+ PyObject_HEAD
+
+ /* Reusable compress/decompress dictionary, they are created once and
+ can be shared by multiple threads concurrently, since its usage is
+ read-only.
+ c_dicts is a dict, int(compressionLevel):PyCapsule(ZSTD_CDict*) */
+ ZSTD_DDict *d_dict;
+ PyObject *c_dicts;
+
+ /* Dictionary content. */
+ char *dict_buffer;
+ Py_ssize_t dict_len;
+
+ /* Dictionary id */
+ uint32_t dict_id;
+
+ /* Lock to protect the digested dictionaries */
+ PyMutex lock;
+} ZstdDict;
+
+#endif // !ZSTD_DICT_H
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 401a3a7072b..5d07de2fba9 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -13,6 +13,7 @@
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_moduleobject.h" // _PyModule_GetState()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include <stdbool.h>
@@ -728,9 +729,7 @@ array_dealloc(PyObject *op)
PyObject_GC_UnTrack(op);
arrayobject *self = arrayobject_CAST(op);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs(op);
- }
+ FT_CLEAR_WEAKREFS(op, self->weakreflist);
if (self->ob_item != NULL) {
PyMem_Free(self->ob_item);
}
diff --git a/Modules/blake2module.c b/Modules/blake2module.c
index f9acc57f1b2..163f238a426 100644
--- a/Modules/blake2module.c
+++ b/Modules/blake2module.c
@@ -2,6 +2,7 @@
* Written in 2013 by Dmitry Chestnykh <dmitry@codingrobots.com>
* Modified for CPython by Christian Heimes <christian@python.org>
* Updated to use HACL* by Jonathan Protzenko <jonathan@protzenko.fr>
+ * Additional work by Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
*
* To the extent possible under law, the author have dedicated all
* copyright and related and neighboring rights to this software to
@@ -13,7 +14,6 @@
# define Py_BUILD_CORE_MODULE 1
#endif
-#include "pyconfig.h"
#include "Python.h"
#include "hashlib.h"
#include "pycore_strhex.h" // _Py_strhex()
@@ -43,104 +43,27 @@
// SIMD256 can't be compiled on macOS ARM64, and performance of SIMD128 isn't
// great; but when compiling a universal2 binary, autoconf will set
-// HACL_CAN_COMPILE_SIMD128 and HACL_CAN_COMPILE_SIMD256 because they *can* be
-// compiled on x86_64. If we're on macOS ARM64, disable these preprocessor
-// symbols.
+// _Py_HACL_CAN_COMPILE_VEC{128,256} because they *can* be compiled on x86_64.
+// If we're on macOS ARM64, we however disable these preprocessor symbols.
#if defined(__APPLE__) && defined(__arm64__)
-# undef HACL_CAN_COMPILE_SIMD128
-# undef HACL_CAN_COMPILE_SIMD256
+# undef _Py_HACL_CAN_COMPILE_VEC128
+# undef _Py_HACL_CAN_COMPILE_VEC256
#endif
-// ECX
-#define ECX_SSE3 (1 << 0)
-#define ECX_SSSE3 (1 << 9)
-#define ECX_SSE4_1 (1 << 19)
-#define ECX_SSE4_2 (1 << 20)
-#define ECX_AVX (1 << 28)
-
-// EBX
-#define EBX_AVX2 (1 << 5)
-
-// EDX
-#define EDX_SSE (1 << 25)
-#define EDX_SSE2 (1 << 26)
-#define EDX_CMOV (1 << 15)
-
-// zero-initialized by default
-typedef struct {
- bool sse, sse2, sse3, sse41, sse42, cmov, avx, avx2;
- bool done;
-} cpu_flags;
+// HACL* expects HACL_CAN_COMPILE_VEC* macros to be set in order to enable
+// the corresponding SIMD instructions so we need to "forward" the values
+// we just deduced above.
+#define HACL_CAN_COMPILE_VEC128 _Py_HACL_CAN_COMPILE_VEC128
+#define HACL_CAN_COMPILE_VEC256 _Py_HACL_CAN_COMPILE_VEC256
-void detect_cpu_features(cpu_flags *flags) {
- if (!flags->done) {
- int eax1 = 0, ebx1 = 0, ecx1 = 0, edx1 = 0;
- int eax7 = 0, ebx7 = 0, ecx7 = 0, edx7 = 0;
-#if defined(__x86_64__) && defined(__GNUC__)
- __cpuid_count(1, 0, eax1, ebx1, ecx1, edx1);
- __cpuid_count(7, 0, eax7, ebx7, ecx7, edx7);
-#elif defined(_M_X64)
- int info1[4] = { 0 };
- int info7[4] = { 0 };
- __cpuidex(info1, 1, 0);
- __cpuidex(info7, 7, 0);
- eax1 = info1[0];
- ebx1 = info1[1];
- ecx1 = info1[2];
- edx1 = info1[3];
- eax7 = info7[0];
- ebx7 = info7[1];
- ecx7 = info7[2];
- edx7 = info7[3];
-#endif
- (void) eax1; (void) ebx1; (void) ecx1; (void) edx1;
- (void) eax7; (void) ebx7; (void) ecx7; (void) edx7;
-
-
- flags->avx = (ecx1 & ECX_AVX) != 0;
-
- flags->avx2 = (ebx7 & EBX_AVX2) != 0;
-
- flags->sse = (edx1 & EDX_SSE) != 0;
- flags->sse2 = (edx1 & EDX_SSE2) != 0;
- flags->cmov = (edx1 & EDX_CMOV) != 0;
-
- flags->sse3 = (ecx1 & ECX_SSE3) != 0;
- /* ssse3 = (ecx1 & ECX_SSSE3) != 0; */
- flags->sse41 = (ecx1 & ECX_SSE4_1) != 0;
- flags->sse42 = (ecx1 & ECX_SSE4_2) != 0;
-
- flags->done = true;
- }
-}
-
-#ifdef HACL_CAN_COMPILE_SIMD128
-static inline bool has_simd128(cpu_flags *flags) {
- // For now this is Intel-only, could conceivably be #ifdef'd to something
- // else.
- return flags->sse && flags->sse2 && flags->sse3 && flags->sse41 && flags->sse42 && flags->cmov;
-}
-#endif
-
-#ifdef HACL_CAN_COMPILE_SIMD256
-static inline bool has_simd256(cpu_flags *flags) {
- return flags->avx && flags->avx2;
-}
-#endif
-
-// Small mismatch between the variable names Python defines as part of configure
-// at the ones HACL* expects to be set in order to enable those headers.
-#define HACL_CAN_COMPILE_VEC128 HACL_CAN_COMPILE_SIMD128
-#define HACL_CAN_COMPILE_VEC256 HACL_CAN_COMPILE_SIMD256
-
-#include "_hacl/Hacl_Hash_Blake2b.h"
#include "_hacl/Hacl_Hash_Blake2s.h"
-#if HACL_CAN_COMPILE_SIMD256
-#include "_hacl/Hacl_Hash_Blake2b_Simd256.h"
-#endif
-#if HACL_CAN_COMPILE_SIMD128
+#include "_hacl/Hacl_Hash_Blake2b.h"
+#if _Py_HACL_CAN_COMPILE_VEC128
#include "_hacl/Hacl_Hash_Blake2s_Simd128.h"
#endif
+#if _Py_HACL_CAN_COMPILE_VEC256
+#include "_hacl/Hacl_Hash_Blake2b_Simd256.h"
+#endif
// MODULE TYPE SLOTS
@@ -148,16 +71,16 @@ static PyType_Spec blake2b_type_spec;
static PyType_Spec blake2s_type_spec;
PyDoc_STRVAR(blake2mod__doc__,
-"_blake2b provides BLAKE2b for hashlib\n"
-);
+ "_blake2 provides BLAKE2b and BLAKE2s for hashlib\n");
typedef struct {
- PyTypeObject* blake2b_type;
- PyTypeObject* blake2s_type;
- cpu_flags flags;
+ PyTypeObject *blake2b_type;
+ PyTypeObject *blake2s_type;
+ bool can_run_simd128;
+ bool can_run_simd256;
} Blake2State;
-static inline Blake2State*
+static inline Blake2State *
blake2_get_state(PyObject *module)
{
void *state = _PyModule_GetState(module);
@@ -165,8 +88,8 @@ blake2_get_state(PyObject *module)
return (Blake2State *)state;
}
-#if defined(HACL_CAN_COMPILE_SIMD128) || defined(HACL_CAN_COMPILE_SIMD256)
-static inline Blake2State*
+#if defined(_Py_HACL_CAN_COMPILE_VEC128) || defined(_Py_HACL_CAN_COMPILE_VEC256)
+static inline Blake2State *
blake2_get_state_from_type(PyTypeObject *module)
{
void *state = _PyType_GetModuleState(module);
@@ -203,31 +126,107 @@ _blake2_free(void *module)
(void)_blake2_clear((PyObject *)module);
}
-#define ADD_INT(d, name, value) do { \
- PyObject *x = PyLong_FromLong(value); \
- if (!x) \
- return -1; \
- if (PyDict_SetItemString(d, name, x) < 0) { \
- Py_DECREF(x); \
- return -1; \
- } \
- Py_DECREF(x); \
-} while(0)
-
-#define ADD_INT_CONST(NAME, VALUE) do { \
- if (PyModule_AddIntConstant(m, NAME, VALUE) < 0) { \
- return -1; \
- } \
-} while (0)
+static void
+blake2module_init_cpu_features(Blake2State *state)
+{
+ /* This must be kept in sync with hmacmodule_init_cpu_features()
+ * in hmacmodule.c */
+ int eax1 = 0, ebx1 = 0, ecx1 = 0, edx1 = 0;
+ int eax7 = 0, ebx7 = 0, ecx7 = 0, edx7 = 0;
+#if defined(__x86_64__) && defined(__GNUC__)
+ __cpuid_count(1, 0, eax1, ebx1, ecx1, edx1);
+ __cpuid_count(7, 0, eax7, ebx7, ecx7, edx7);
+#elif defined(_M_X64)
+ int info1[4] = {0};
+ __cpuidex(info1, 1, 0);
+ eax1 = info1[0], ebx1 = info1[1], ecx1 = info1[2], edx1 = info1[3];
+
+ int info7[4] = {0};
+ __cpuidex(info7, 7, 0);
+ eax7 = info7[0], ebx7 = info7[1], ecx7 = info7[2], edx7 = info7[3];
+#endif
+ // fmt: off
+ (void)eax1; (void)ebx1; (void)ecx1; (void)edx1;
+ (void)eax7; (void)ebx7; (void)ecx7; (void)edx7;
+ // fmt: on
+
+#define EBX_AVX2 (1 << 5)
+#define ECX_SSE3 (1 << 0)
+#define ECX_SSSE3 (1 << 9)
+#define ECX_SSE4_1 (1 << 19)
+#define ECX_SSE4_2 (1 << 20)
+#define ECX_AVX (1 << 28)
+#define EDX_SSE (1 << 25)
+#define EDX_SSE2 (1 << 26)
+#define EDX_CMOV (1 << 15)
+
+ bool avx = (ecx1 & ECX_AVX) != 0;
+ bool avx2 = (ebx7 & EBX_AVX2) != 0;
+
+ bool sse = (edx1 & EDX_SSE) != 0;
+ bool sse2 = (edx1 & EDX_SSE2) != 0;
+ bool cmov = (edx1 & EDX_CMOV) != 0;
+
+ bool sse3 = (ecx1 & ECX_SSE3) != 0;
+ bool sse41 = (ecx1 & ECX_SSE4_1) != 0;
+ bool sse42 = (ecx1 & ECX_SSE4_2) != 0;
+
+#undef EDX_CMOV
+#undef EDX_SSE2
+#undef EDX_SSE
+#undef ECX_AVX
+#undef ECX_SSE4_2
+#undef ECX_SSE4_1
+#undef ECX_SSSE3
+#undef ECX_SSE3
+#undef EBX_AVX2
+
+#if _Py_HACL_CAN_COMPILE_VEC128
+ // TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection
+ state->can_run_simd128 = sse && sse2 && sse3 && sse41 && sse42 && cmov;
+#else
+ // fmt: off
+ (void)sse; (void)sse2; (void)sse3; (void)sse41; (void)sse42; (void)cmov;
+ // fmt: on
+ state->can_run_simd128 = false;
+#endif
+
+#if _Py_HACL_CAN_COMPILE_VEC256
+ // TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection
+ state->can_run_simd256 = state->can_run_simd128 && avx && avx2;
+#else
+ // fmt: off
+ (void)avx; (void)avx2;
+ // fmt: on
+ state->can_run_simd256 = false;
+#endif
+}
static int
blake2_exec(PyObject *m)
{
- Blake2State* st = blake2_get_state(m);
-
- // This is called at module initialization-time, and so appears to be as
- // good a place as any to probe the CPU flags.
- detect_cpu_features(&st->flags);
+ Blake2State *st = blake2_get_state(m);
+ blake2module_init_cpu_features(st);
+
+#define ADD_INT(DICT, NAME, VALUE) \
+ do { \
+ PyObject *x = PyLong_FromLong(VALUE); \
+ if (x == NULL) { \
+ return -1; \
+ } \
+ int rc = PyDict_SetItemString(DICT, NAME, x); \
+ Py_DECREF(x); \
+ if (rc < 0) { \
+ return -1; \
+ } \
+ } while(0)
+
+#define ADD_INT_CONST(NAME, VALUE) \
+ do { \
+ if (PyModule_AddIntConstant(m, NAME, VALUE) < 0) { \
+ return -1; \
+ } \
+ } while (0)
ADD_INT_CONST("_GIL_MINSIZE", HASHLIB_GIL_MINSIZE);
@@ -237,7 +236,6 @@ blake2_exec(PyObject *m)
if (st->blake2b_type == NULL) {
return -1;
}
- /* BLAKE2b */
if (PyModule_AddType(m, st->blake2b_type) < 0) {
return -1;
}
@@ -257,9 +255,9 @@ blake2_exec(PyObject *m)
st->blake2s_type = (PyTypeObject *)PyType_FromModuleAndSpec(
m, &blake2s_type_spec, NULL);
- if (NULL == st->blake2s_type)
+ if (st->blake2s_type == NULL) {
return -1;
-
+ }
if (PyModule_AddType(m, st->blake2s_type) < 0) {
return -1;
}
@@ -275,12 +273,11 @@ blake2_exec(PyObject *m)
ADD_INT_CONST("BLAKE2S_MAX_KEY_SIZE", HACL_HASH_BLAKE2S_KEY_BYTES);
ADD_INT_CONST("BLAKE2S_MAX_DIGEST_SIZE", HACL_HASH_BLAKE2S_OUT_BYTES);
+#undef ADD_INT_CONST
+#undef ADD_INT
return 0;
}
-#undef ADD_INT
-#undef ADD_INT_CONST
-
static PyModuleDef_Slot _blake2_slots[] = {
{Py_mod_exec, blake2_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
@@ -320,65 +317,70 @@ PyInit__blake2(void)
// set.
typedef enum { Blake2s, Blake2b, Blake2s_128, Blake2b_256 } blake2_impl;
-static inline bool is_blake2b(blake2_impl impl) {
- return impl == Blake2b || impl == Blake2b_256;
+static inline bool
+is_blake2b(blake2_impl impl)
+{
+ return impl == Blake2b || impl == Blake2b_256;
}
-static inline bool is_blake2s(blake2_impl impl) {
- return !is_blake2b(impl);
+static inline bool
+is_blake2s(blake2_impl impl)
+{
+ return impl == Blake2s || impl == Blake2s_128;
}
-static inline blake2_impl type_to_impl(PyTypeObject *type) {
-#if defined(HACL_CAN_COMPILE_SIMD128) || defined(HACL_CAN_COMPILE_SIMD256)
- Blake2State* st = blake2_get_state_from_type(type);
+static inline blake2_impl
+type_to_impl(PyTypeObject *type)
+{
+#if defined(_Py_HACL_CAN_COMPILE_VEC128) || defined(_Py_HACL_CAN_COMPILE_VEC256)
+ Blake2State *st = blake2_get_state_from_type(type);
#endif
if (!strcmp(type->tp_name, blake2b_type_spec.name)) {
-#ifdef HACL_CAN_COMPILE_SIMD256
- if (has_simd256(&st->flags))
- return Blake2b_256;
- else
-#endif
+#if _Py_HACL_CAN_COMPILE_VEC256
+ return st->can_run_simd256 ? Blake2b_256 : Blake2b;
+#else
return Blake2b;
- } else if (!strcmp(type->tp_name, blake2s_type_spec.name)) {
-#ifdef HACL_CAN_COMPILE_SIMD128
- if (has_simd128(&st->flags))
- return Blake2s_128;
- else
#endif
+ }
+ else if (!strcmp(type->tp_name, blake2s_type_spec.name)) {
+#if _Py_HACL_CAN_COMPILE_VEC128
+ return st->can_run_simd128 ? Blake2s_128 : Blake2s;
+#else
return Blake2s;
- } else {
- Py_UNREACHABLE();
+#endif
}
+ Py_UNREACHABLE();
}
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
union {
Hacl_Hash_Blake2s_state_t *blake2s_state;
Hacl_Hash_Blake2b_state_t *blake2b_state;
-#ifdef HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
Hacl_Hash_Blake2s_Simd128_state_t *blake2s_128_state;
#endif
-#ifdef HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
Hacl_Hash_Blake2b_Simd256_state_t *blake2b_256_state;
#endif
};
blake2_impl impl;
- bool use_mutex;
- PyMutex mutex;
} Blake2Object;
#define _Blake2Object_CAST(op) ((Blake2Object *)(op))
-#include "clinic/blake2module.c.h"
+// --- Module clinic configuration --------------------------------------------
/*[clinic input]
module _blake2
-class _blake2.blake2b "Blake2Object *" "&PyBlake2_BLAKE2bType"
-class _blake2.blake2s "Blake2Object *" "&PyBlake2_BLAKE2sType"
+class _blake2.blake2b "Blake2Object *" "&PyType_Type"
+class _blake2.blake2s "Blake2Object *" "&PyType_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b7526666bd18af83]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=86b0972b0c41b3d0]*/
+
+#include "clinic/blake2module.c.h"
+// --- BLAKE-2 object interface -----------------------------------------------
static Blake2Object *
new_Blake2Object(PyTypeObject *type)
@@ -422,42 +424,127 @@ new_Blake2Object(PyTypeObject *type)
} while (0)
static void
-update(Blake2Object *self, uint8_t *buf, Py_ssize_t len)
+blake2_update_unlocked(Blake2Object *self, uint8_t *buf, Py_ssize_t len)
{
switch (self->impl) {
- // These need to be ifdef'd out otherwise it's an unresolved symbol at
- // link-time.
-#ifdef HACL_CAN_COMPILE_SIMD256
+ // blake2b_256_state and blake2s_128_state must be if'd since
+ // otherwise this results in an unresolved symbol at link-time.
+#if _Py_HACL_CAN_COMPILE_VEC256
case Blake2b_256:
- HACL_UPDATE(Hacl_Hash_Blake2b_Simd256_update,self->blake2b_256_state, buf, len);
+ HACL_UPDATE(Hacl_Hash_Blake2b_Simd256_update,
+ self->blake2b_256_state, buf, len);
return;
#endif
-#ifdef HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
case Blake2s_128:
- HACL_UPDATE(Hacl_Hash_Blake2s_Simd128_update,self->blake2s_128_state, buf, len);
+ HACL_UPDATE(Hacl_Hash_Blake2s_Simd128_update,
+ self->blake2s_128_state, buf, len);
return;
#endif
case Blake2b:
- HACL_UPDATE(Hacl_Hash_Blake2b_update,self->blake2b_state, buf, len);
+ HACL_UPDATE(Hacl_Hash_Blake2b_update,
+ self->blake2b_state, buf, len);
return;
case Blake2s:
- HACL_UPDATE(Hacl_Hash_Blake2s_update,self->blake2s_state, buf, len);
+ HACL_UPDATE(Hacl_Hash_Blake2s_update,
+ self->blake2s_state, buf, len);
return;
default:
Py_UNREACHABLE();
}
}
-static PyObject *
-py_blake2b_or_s_new(PyTypeObject *type, PyObject *data, int digest_size,
- Py_buffer *key, Py_buffer *salt, Py_buffer *person,
- int fanout, int depth, unsigned long leaf_size,
- unsigned long long node_offset, int node_depth,
- int inner_size, int last_node, int usedforsecurity)
+#define BLAKE2_IMPLNAME(SELF) \
+ (is_blake2b((SELF)->impl) ? "blake2b" : "blake2s")
+#define GET_BLAKE2_CONST(SELF, NAME) \
+ (is_blake2b((SELF)->impl) \
+ ? HACL_HASH_BLAKE2B_ ## NAME \
+ : HACL_HASH_BLAKE2S_ ## NAME)
+
+#define MAX_OUT_BYTES(SELF) GET_BLAKE2_CONST(SELF, OUT_BYTES)
+#define MAX_SALT_LENGTH(SELF) GET_BLAKE2_CONST(SELF, SALT_BYTES)
+#define MAX_KEY_BYTES(SELF) GET_BLAKE2_CONST(SELF, KEY_BYTES)
+#define MAX_PERSONAL_BYTES(SELF) GET_BLAKE2_CONST(SELF, PERSONAL_BYTES)
+static int
+py_blake2_validate_params(Blake2Object *self,
+ int digest_size,
+ Py_buffer *key, Py_buffer *salt, Py_buffer *person,
+ int fanout, int depth, unsigned long leaf_size,
+ unsigned long long node_offset, int node_depth,
+ int inner_size)
+{
+ /* Validate digest size. */
+ if (digest_size <= 0 || (unsigned int)digest_size > MAX_OUT_BYTES(self)) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "digest_size for %s must be between 1 and %d bytes, got %d",
+ BLAKE2_IMPLNAME(self), MAX_OUT_BYTES(self), digest_size
+ );
+ goto error;
+ }
+
+#define CHECK_LENGTH(NAME, VALUE, MAX) \
+ do { \
+ if ((size_t)(VALUE) > (size_t)(MAX)) { \
+ PyErr_Format(PyExc_ValueError, \
+ "maximum %s length is %zu bytes, got %zd", \
+ (NAME), (size_t)(MAX), (Py_ssize_t)(VALUE)); \
+ goto error; \
+ } \
+ } while (0)
+ /* Validate key parameter. */
+ if (key->obj && key->len) {
+ CHECK_LENGTH("key", key->len, MAX_KEY_BYTES(self));
+ }
+ /* Validate salt parameter. */
+ if (salt->obj && salt->len) {
+ CHECK_LENGTH("salt", salt->len, MAX_SALT_LENGTH(self));
+ }
+ /* Validate personalization parameter. */
+ if (person->obj && person->len) {
+ CHECK_LENGTH("person", person->len, MAX_PERSONAL_BYTES(self));
+ }
+#undef CHECK_LENGTH
+#define CHECK_TREE(NAME, VALUE, MIN, MAX) \
+ do { \
+ if ((VALUE) < (MIN) || (size_t)(VALUE) > (size_t)(MAX)) { \
+ PyErr_Format(PyExc_ValueError, \
+ "'%s' must be between %zu and %zu", \
+ (NAME), (size_t)(MIN), (size_t)(MAX)); \
+ goto error; \
+ } \
+ } while (0)
+ /* Validate tree parameters. */
+ CHECK_TREE("fanout", fanout, 0, 255);
+ CHECK_TREE("depth", depth, 1, 255);
+ CHECK_TREE("node_depth", node_depth, 0, 255);
+ CHECK_TREE("inner_size", inner_size, 0, MAX_OUT_BYTES(self));
+#undef CHECK_TREE
+ if (leaf_size > 0xFFFFFFFFU) {
+ /* maximum: 2**32 - 1 */
+ PyErr_SetString(PyExc_OverflowError, "'leaf_size' is too large");
+ goto error;
+ }
+ if (is_blake2s(self->impl) && node_offset > 0xFFFFFFFFFFFFULL) {
+ /* maximum: 2**48 - 1 */
+ PyErr_SetString(PyExc_OverflowError, "'node_offset' is too large");
+ goto error;
+ }
+ return 0;
+error:
+ return -1;
+}
+
+
+static PyObject *
+py_blake2_new(PyTypeObject *type, PyObject *data, int digest_size,
+ Py_buffer *key, Py_buffer *salt, Py_buffer *person,
+ int fanout, int depth, unsigned long leaf_size,
+ unsigned long long node_offset, int node_depth,
+ int inner_size, int last_node, int usedforsecurity)
{
Blake2Object *self = NULL;
- Py_buffer buf;
self = new_Blake2Object(type);
if (self == NULL) {
@@ -468,12 +555,12 @@ py_blake2b_or_s_new(PyTypeObject *type, PyObject *data, int digest_size,
// Ensure that the states are NULL-initialized in case of an error.
// See: py_blake2_clear() for more details.
switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
case Blake2b_256:
self->blake2b_256_state = NULL;
break;
#endif
-#if HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
case Blake2s_128:
self->blake2s_128_state = NULL;
break;
@@ -487,96 +574,31 @@ py_blake2b_or_s_new(PyTypeObject *type, PyObject *data, int digest_size,
default:
Py_UNREACHABLE();
}
- // Using Blake2b because we statically know that these are greater than the
- // Blake2s sizes -- this avoids a VLA.
- uint8_t salt_[HACL_HASH_BLAKE2B_SALT_BYTES] = { 0 };
- uint8_t personal_[HACL_HASH_BLAKE2B_PERSONAL_BYTES] = { 0 };
- /* Validate digest size. */
- if (digest_size <= 0 ||
- (unsigned) digest_size > (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_OUT_BYTES : HACL_HASH_BLAKE2S_OUT_BYTES))
+ // Unlike the state types, the parameters share a single (client-friendly)
+ // structure.
+ if (py_blake2_validate_params(self,
+ digest_size,
+ key, salt, person,
+ fanout, depth, leaf_size,
+ node_offset, node_depth, inner_size) < 0)
{
- PyErr_Format(PyExc_ValueError,
- "digest_size for %s must be between 1 and %d bytes, here it is %d",
- is_blake2b(self->impl) ? "Blake2b" : "Blake2s",
- is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_OUT_BYTES : HACL_HASH_BLAKE2S_OUT_BYTES,
- digest_size);
- goto error;
- }
-
- /* Validate salt parameter. */
- if ((salt->obj != NULL) && salt->len) {
- if ((size_t)salt->len > (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_SALT_BYTES : HACL_HASH_BLAKE2S_SALT_BYTES)) {
- PyErr_Format(PyExc_ValueError,
- "maximum salt length is %d bytes",
- (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_SALT_BYTES : HACL_HASH_BLAKE2S_SALT_BYTES));
- goto error;
- }
- memcpy(salt_, salt->buf, salt->len);
- }
-
- /* Validate personalization parameter. */
- if ((person->obj != NULL) && person->len) {
- if ((size_t)person->len > (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_PERSONAL_BYTES : HACL_HASH_BLAKE2S_PERSONAL_BYTES)) {
- PyErr_Format(PyExc_ValueError,
- "maximum person length is %d bytes",
- (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_PERSONAL_BYTES : HACL_HASH_BLAKE2S_PERSONAL_BYTES));
- goto error;
- }
- memcpy(personal_, person->buf, person->len);
- }
-
- /* Validate tree parameters. */
- if (fanout < 0 || fanout > 255) {
- PyErr_SetString(PyExc_ValueError,
- "fanout must be between 0 and 255");
- goto error;
- }
-
- if (depth <= 0 || depth > 255) {
- PyErr_SetString(PyExc_ValueError,
- "depth must be between 1 and 255");
- goto error;
- }
-
- if (leaf_size > 0xFFFFFFFFU) {
- PyErr_SetString(PyExc_OverflowError, "leaf_size is too large");
- goto error;
- }
-
- if (is_blake2s(self->impl) && node_offset > 0xFFFFFFFFFFFFULL) {
- /* maximum 2**48 - 1 */
- PyErr_SetString(PyExc_OverflowError, "node_offset is too large");
- goto error;
- }
-
- if (node_depth < 0 || node_depth > 255) {
- PyErr_SetString(PyExc_ValueError,
- "node_depth must be between 0 and 255");
goto error;
}
- if (inner_size < 0 ||
- (unsigned) inner_size > (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_OUT_BYTES : HACL_HASH_BLAKE2S_OUT_BYTES)) {
- PyErr_Format(PyExc_ValueError,
- "inner_size must be between 0 and is %d",
- (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_OUT_BYTES : HACL_HASH_BLAKE2S_OUT_BYTES));
- goto error;
+ // Using Blake2b because we statically know that these are greater than the
+ // Blake2s sizes -- this avoids a VLA.
+ uint8_t salt_buffer[HACL_HASH_BLAKE2B_SALT_BYTES] = {0};
+ uint8_t personal_buffer[HACL_HASH_BLAKE2B_PERSONAL_BYTES] = {0};
+ if (salt->obj != NULL) {
+ assert(salt->buf != NULL);
+ memcpy(salt_buffer, salt->buf, salt->len);
}
-
- /* Set key length. */
- if ((key->obj != NULL) && key->len) {
- if ((size_t)key->len > (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_KEY_BYTES : HACL_HASH_BLAKE2S_KEY_BYTES)) {
- PyErr_Format(PyExc_ValueError,
- "maximum key length is %d bytes",
- (is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_KEY_BYTES : HACL_HASH_BLAKE2S_KEY_BYTES));
- goto error;
- }
+ if (person->obj != NULL) {
+ assert(person->buf != NULL);
+ memcpy(personal_buffer, person->buf, person->len);
}
- // Unlike the state types, the parameters share a single (client-friendly)
- // structure.
-
Hacl_Hash_Blake2b_blake2_params params = {
.digest_length = digest_size,
.key_length = (uint8_t)key->len,
@@ -586,63 +608,52 @@ py_blake2b_or_s_new(PyTypeObject *type, PyObject *data, int digest_size,
.node_offset = node_offset,
.node_depth = node_depth,
.inner_length = inner_size,
- .salt = salt_,
- .personal = personal_
+ .salt = salt_buffer,
+ .personal = personal_buffer
};
+#define BLAKE2_MALLOC(TYPE, STATE) \
+ do { \
+ STATE = Hacl_Hash_ ## TYPE ## _malloc_with_params_and_key( \
+ &params, last_node, key->buf); \
+ if (STATE == NULL) { \
+ (void)PyErr_NoMemory(); \
+ goto error; \
+ } \
+ } while (0)
+
switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
- case Blake2b_256: {
- self->blake2b_256_state = Hacl_Hash_Blake2b_Simd256_malloc_with_params_and_key(&params, last_node, key->buf);
- if (self->blake2b_256_state == NULL) {
- (void)PyErr_NoMemory();
- goto error;
- }
+#if _Py_HACL_CAN_COMPILE_VEC256
+ case Blake2b_256:
+ BLAKE2_MALLOC(Blake2b_Simd256, self->blake2b_256_state);
break;
- }
#endif
-#if HACL_CAN_COMPILE_SIMD128
- case Blake2s_128: {
- self->blake2s_128_state = Hacl_Hash_Blake2s_Simd128_malloc_with_params_and_key(&params, last_node, key->buf);
- if (self->blake2s_128_state == NULL) {
- (void)PyErr_NoMemory();
- goto error;
- }
+#if _Py_HACL_CAN_COMPILE_VEC128
+ case Blake2s_128:
+ BLAKE2_MALLOC(Blake2s_Simd128, self->blake2s_128_state);
break;
- }
#endif
- case Blake2b: {
- self->blake2b_state = Hacl_Hash_Blake2b_malloc_with_params_and_key(&params, last_node, key->buf);
- if (self->blake2b_state == NULL) {
- (void)PyErr_NoMemory();
- goto error;
- }
+ case Blake2b:
+ BLAKE2_MALLOC(Blake2b, self->blake2b_state);
break;
- }
- case Blake2s: {
- self->blake2s_state = Hacl_Hash_Blake2s_malloc_with_params_and_key(&params, last_node, key->buf);
- if (self->blake2s_state == NULL) {
- (void)PyErr_NoMemory();
- goto error;
- }
+ case Blake2s:
+ BLAKE2_MALLOC(Blake2s, self->blake2s_state);
break;
- }
default:
Py_UNREACHABLE();
}
+#undef BLAKE2_MALLOC
/* Process initial data if any. */
if (data != NULL) {
+ Py_buffer buf;
GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
-
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- Py_BEGIN_ALLOW_THREADS
- update(self, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update(self, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ blake2_update_unlocked(self, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -655,8 +666,7 @@ error:
/*[clinic input]
@classmethod
_blake2.blake2b.__new__ as py_blake2b_new
- data: object(c_default="NULL") = b''
- /
+ data as data_obj: object(c_default="NULL") = b''
*
digest_size: int(c_default="HACL_HASH_BLAKE2B_OUT_BYTES") = _blake2.blake2b.MAX_DIGEST_SIZE
key: Py_buffer(c_default="NULL", py_default="b''") = None
@@ -670,26 +680,33 @@ _blake2.blake2b.__new__ as py_blake2b_new
inner_size: int = 0
last_node: bool = False
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Return a new BLAKE2b hash object.
[clinic start generated code]*/
static PyObject *
-py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
+py_blake2b_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size,
Py_buffer *key, Py_buffer *salt, Py_buffer *person,
int fanout, int depth, unsigned long leaf_size,
unsigned long long node_offset, int node_depth,
- int inner_size, int last_node, int usedforsecurity)
-/*[clinic end generated code: output=32bfd8f043c6896f input=8fee2b7b11428b2d]*/
+ int inner_size, int last_node, int usedforsecurity,
+ PyObject *string)
+/*[clinic end generated code: output=de64bd850606b6a0 input=78cf60a2922d2f90]*/
{
- return py_blake2b_or_s_new(type, data, digest_size, key, salt, person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity);
+ PyObject *data;
+ if (_Py_hashlib_data_argument(&data, data_obj, string) < 0) {
+ return NULL;
+ }
+ return py_blake2_new(type, data, digest_size, key, salt, person,
+ fanout, depth, leaf_size, node_offset, node_depth,
+ inner_size, last_node, usedforsecurity);
}
/*[clinic input]
@classmethod
_blake2.blake2s.__new__ as py_blake2s_new
- data: object(c_default="NULL") = b''
- /
+ data as data_obj: object(c_default="NULL") = b''
*
digest_size: int(c_default="HACL_HASH_BLAKE2S_OUT_BYTES") = _blake2.blake2s.MAX_DIGEST_SIZE
key: Py_buffer(c_default="NULL", py_default="b''") = None
@@ -703,61 +720,62 @@ _blake2.blake2s.__new__ as py_blake2s_new
inner_size: int = 0
last_node: bool = False
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Return a new BLAKE2s hash object.
[clinic start generated code]*/
static PyObject *
-py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
+py_blake2s_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size,
Py_buffer *key, Py_buffer *salt, Py_buffer *person,
int fanout, int depth, unsigned long leaf_size,
unsigned long long node_offset, int node_depth,
- int inner_size, int last_node, int usedforsecurity)
-/*[clinic end generated code: output=556181f73905c686 input=8165a11980eac7f3]*/
+ int inner_size, int last_node, int usedforsecurity,
+ PyObject *string)
+/*[clinic end generated code: output=582a0c4295cc3a3c input=6843d6332eefd295]*/
{
- return py_blake2b_or_s_new(type, data, digest_size, key, salt, person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity);
+ PyObject *data;
+ if (_Py_hashlib_data_argument(&data, data_obj, string) < 0) {
+ return NULL;
+ }
+ return py_blake2_new(type, data, digest_size, key, salt, person,
+ fanout, depth, leaf_size, node_offset, node_depth,
+ inner_size, last_node, usedforsecurity);
}
static int
-blake2_blake2b_copy_locked(Blake2Object *self, Blake2Object *cpy)
+blake2_blake2b_copy_unlocked(Blake2Object *self, Blake2Object *cpy)
{
assert(cpy != NULL);
+#define BLAKE2_COPY(TYPE, STATE_ATTR) \
+ do { \
+ cpy->STATE_ATTR = Hacl_Hash_ ## TYPE ## _copy(self->STATE_ATTR); \
+ if (cpy->STATE_ATTR == NULL) { \
+ goto error; \
+ } \
+ } while (0)
+
switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
- case Blake2b_256: {
- cpy->blake2b_256_state = Hacl_Hash_Blake2b_Simd256_copy(self->blake2b_256_state);
- if (cpy->blake2b_256_state == NULL) {
- goto error;
- }
+#if _Py_HACL_CAN_COMPILE_VEC256
+ case Blake2b_256:
+ BLAKE2_COPY(Blake2b_Simd256, blake2b_256_state);
break;
- }
#endif
-#if HACL_CAN_COMPILE_SIMD128
- case Blake2s_128: {
- cpy->blake2s_128_state = Hacl_Hash_Blake2s_Simd128_copy(self->blake2s_128_state);
- if (cpy->blake2s_128_state == NULL) {
- goto error;
- }
+#if _Py_HACL_CAN_COMPILE_VEC128
+ case Blake2s_128:
+ BLAKE2_COPY(Blake2s_Simd128, blake2s_128_state);
break;
- }
#endif
- case Blake2b: {
- cpy->blake2b_state = Hacl_Hash_Blake2b_copy(self->blake2b_state);
- if (cpy->blake2b_state == NULL) {
- goto error;
- }
+ case Blake2b:
+ BLAKE2_COPY(Blake2b, blake2b_state);
break;
- }
- case Blake2s: {
- cpy->blake2s_state = Hacl_Hash_Blake2s_copy(self->blake2s_state);
- if (cpy->blake2s_state == NULL) {
- goto error;
- }
+ case Blake2s:
+ BLAKE2_COPY(Blake2s, blake2s_state);
break;
- }
default:
Py_UNREACHABLE();
}
+#undef BLAKE2_COPY
cpy->impl = self->impl;
return 0;
@@ -769,23 +787,25 @@ error:
/*[clinic input]
_blake2.blake2b.copy
+ cls: defining_class
+
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
-_blake2_blake2b_copy_impl(Blake2Object *self)
-/*[clinic end generated code: output=622d1c56b91c50d8 input=e383c2d199fd8a2e]*/
+_blake2_blake2b_copy_impl(Blake2Object *self, PyTypeObject *cls)
+/*[clinic end generated code: output=5f8ea31c56c52287 input=f38f3475e9aec98d]*/
{
int rc;
Blake2Object *cpy;
- if ((cpy = new_Blake2Object(Py_TYPE(self))) == NULL) {
+ if ((cpy = new_Blake2Object(cls)) == NULL) {
return NULL;
}
- ENTER_HASHLIB(self);
- rc = blake2_blake2b_copy_locked(self, cpy);
- LEAVE_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
+ rc = blake2_blake2b_copy_unlocked(self, cpy);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(cpy);
return NULL;
@@ -807,62 +827,52 @@ _blake2_blake2b_update_impl(Blake2Object *self, PyObject *data)
/*[clinic end generated code: output=99330230068e8c99 input=ffc4aa6a6a225d31]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- update(self, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update(self, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ blake2_update_unlocked(self, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
-
Py_RETURN_NONE;
}
-/*[clinic input]
-_blake2.blake2b.digest
-
-Return the digest value as a bytes object.
-[clinic start generated code]*/
-
-static PyObject *
-_blake2_blake2b_digest_impl(Blake2Object *self)
-/*[clinic end generated code: output=31ab8ad477f4a2f7 input=7d21659e9c5fff02]*/
+static uint8_t
+blake2_blake2b_compute_digest(Blake2Object *self, uint8_t *digest)
{
- uint8_t digest[HACL_HASH_BLAKE2B_OUT_BYTES];
-
- ENTER_HASHLIB(self);
- uint8_t digest_length = 0;
switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
case Blake2b_256:
- digest_length = Hacl_Hash_Blake2b_Simd256_digest(self->blake2b_256_state, digest);
- break;
+ return Hacl_Hash_Blake2b_Simd256_digest(
+ self->blake2b_256_state, digest);
#endif
-#if HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
case Blake2s_128:
- digest_length = Hacl_Hash_Blake2s_Simd128_digest(self->blake2s_128_state, digest);
- break;
+ return Hacl_Hash_Blake2s_Simd128_digest(
+ self->blake2s_128_state, digest);
#endif
case Blake2b:
- digest_length = Hacl_Hash_Blake2b_digest(self->blake2b_state, digest);
- break;
+ return Hacl_Hash_Blake2b_digest(self->blake2b_state, digest);
case Blake2s:
- digest_length = Hacl_Hash_Blake2s_digest(self->blake2s_state, digest);
- break;
+ return Hacl_Hash_Blake2s_digest(self->blake2s_state, digest);
default:
Py_UNREACHABLE();
}
- LEAVE_HASHLIB(self);
+}
+
+/*[clinic input]
+_blake2.blake2b.digest
+
+Return the digest value as a bytes object.
+[clinic start generated code]*/
+
+static PyObject *
+_blake2_blake2b_digest_impl(Blake2Object *self)
+/*[clinic end generated code: output=31ab8ad477f4a2f7 input=7d21659e9c5fff02]*/
+{
+ uint8_t digest_length = 0, digest[HACL_HASH_BLAKE2B_OUT_BYTES];
+ HASHLIB_ACQUIRE_LOCK(self);
+ digest_length = blake2_blake2b_compute_digest(self, digest);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, digest_length);
}
@@ -876,31 +886,10 @@ static PyObject *
_blake2_blake2b_hexdigest_impl(Blake2Object *self)
/*[clinic end generated code: output=5ef54b138db6610a input=76930f6946351f56]*/
{
- uint8_t digest[HACL_HASH_BLAKE2B_OUT_BYTES];
-
- ENTER_HASHLIB(self);
- uint8_t digest_length = 0;
- switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
- case Blake2b_256:
- digest_length = Hacl_Hash_Blake2b_Simd256_digest(self->blake2b_256_state, digest);
- break;
-#endif
-#if HACL_CAN_COMPILE_SIMD128
- case Blake2s_128:
- digest_length = Hacl_Hash_Blake2s_Simd128_digest(self->blake2s_128_state, digest);
- break;
-#endif
- case Blake2b:
- digest_length = Hacl_Hash_Blake2b_digest(self->blake2b_state, digest);
- break;
- case Blake2s:
- digest_length = Hacl_Hash_Blake2s_digest(self->blake2s_state, digest);
- break;
- default:
- Py_UNREACHABLE();
- }
- LEAVE_HASHLIB(self);
+ uint8_t digest_length = 0, digest[HACL_HASH_BLAKE2B_OUT_BYTES];
+ HASHLIB_ACQUIRE_LOCK(self);
+ digest_length = blake2_blake2b_compute_digest(self, digest);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, digest_length);
}
@@ -918,43 +907,49 @@ static PyObject *
py_blake2b_get_name(PyObject *op, void *Py_UNUSED(closure))
{
Blake2Object *self = _Blake2Object_CAST(op);
- return PyUnicode_FromString(is_blake2b(self->impl) ? "blake2b" : "blake2s");
+ return PyUnicode_FromString(BLAKE2_IMPLNAME(self));
}
-
static PyObject *
py_blake2b_get_block_size(PyObject *op, void *Py_UNUSED(closure))
{
Blake2Object *self = _Blake2Object_CAST(op);
- return PyLong_FromLong(is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_BLOCK_BYTES : HACL_HASH_BLAKE2S_BLOCK_BYTES);
+ return PyLong_FromLong(GET_BLAKE2_CONST(self, BLOCK_BYTES));
}
-
-static PyObject *
-py_blake2b_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
+static Hacl_Hash_Blake2b_index
+hacl_get_blake2_info(Blake2Object *self)
{
- Blake2Object *self = _Blake2Object_CAST(op);
switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
case Blake2b_256:
- return PyLong_FromLong(Hacl_Hash_Blake2b_Simd256_info(self->blake2b_256_state).digest_length);
+ return Hacl_Hash_Blake2b_Simd256_info(self->blake2b_256_state);
#endif
-#if HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
case Blake2s_128:
- return PyLong_FromLong(Hacl_Hash_Blake2s_Simd128_info(self->blake2s_128_state).digest_length);
+ return Hacl_Hash_Blake2s_Simd128_info(self->blake2s_128_state);
#endif
case Blake2b:
- return PyLong_FromLong(Hacl_Hash_Blake2b_info(self->blake2b_state).digest_length);
+ return Hacl_Hash_Blake2b_info(self->blake2b_state);
case Blake2s:
- return PyLong_FromLong(Hacl_Hash_Blake2s_info(self->blake2s_state).digest_length);
+ return Hacl_Hash_Blake2s_info(self->blake2s_state);
default:
Py_UNREACHABLE();
}
}
+static PyObject *
+py_blake2b_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
+{
+ Blake2Object *self = _Blake2Object_CAST(op);
+ Hacl_Hash_Blake2b_index info = hacl_get_blake2_info(self);
+ return PyLong_FromLong(info.digest_length);
+}
+
+
static PyGetSetDef py_blake2b_getsetters[] = {
{"name", py_blake2b_get_name, NULL, NULL, NULL},
{"block_size", py_blake2b_get_block_size, NULL, NULL, NULL},
@@ -971,38 +966,35 @@ py_blake2_clear(PyObject *op)
// initializes the HACL* internal state to NULL before allocating
// it. If an error occurs in the constructor, we should only free
// states that were allocated (i.e. that are not NULL).
+#define BLAKE2_FREE(TYPE, STATE) \
+ do { \
+ if (STATE != NULL) { \
+ Hacl_Hash_ ## TYPE ## _free(STATE); \
+ STATE = NULL; \
+ } \
+ } while (0)
+
switch (self->impl) {
-#if HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
case Blake2b_256:
- if (self->blake2b_256_state != NULL) {
- Hacl_Hash_Blake2b_Simd256_free(self->blake2b_256_state);
- self->blake2b_256_state = NULL;
- }
+ BLAKE2_FREE(Blake2b_Simd256, self->blake2b_256_state);
break;
#endif
-#if HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
case Blake2s_128:
- if (self->blake2s_128_state != NULL) {
- Hacl_Hash_Blake2s_Simd128_free(self->blake2s_128_state);
- self->blake2s_128_state = NULL;
- }
+ BLAKE2_FREE(Blake2s_Simd128, self->blake2s_128_state);
break;
#endif
case Blake2b:
- if (self->blake2b_state != NULL) {
- Hacl_Hash_Blake2b_free(self->blake2b_state);
- self->blake2b_state = NULL;
- }
+ BLAKE2_FREE(Blake2b, self->blake2b_state);
break;
case Blake2s:
- if (self->blake2s_state != NULL) {
- Hacl_Hash_Blake2s_free(self->blake2s_state);
- self->blake2s_state = NULL;
- }
+ BLAKE2_FREE(Blake2s, self->blake2s_state);
break;
default:
Py_UNREACHABLE();
}
+#undef BLAKE2_FREE
return 0;
}
@@ -1031,7 +1023,7 @@ static PyType_Slot blake2b_type_slots[] = {
{Py_tp_methods, py_blake2b_methods},
{Py_tp_getset, py_blake2b_getsetters},
{Py_tp_new, py_blake2b_new},
- {0,0}
+ {0, 0}
};
static PyType_Slot blake2s_type_slots[] = {
@@ -1044,12 +1036,12 @@ static PyType_Slot blake2s_type_slots[] = {
// only the constructor differs, so that it can receive a clinic-generated
// default digest length suitable for blake2s
{Py_tp_new, py_blake2s_new},
- {0,0}
+ {0, 0}
};
static PyType_Spec blake2b_type_spec = {
.name = "_blake2.blake2b",
- .basicsize = sizeof(Blake2Object),
+ .basicsize = sizeof(Blake2Object),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE,
.slots = blake2b_type_slots
@@ -1057,7 +1049,7 @@ static PyType_Spec blake2b_type_spec = {
static PyType_Spec blake2s_type_spec = {
.name = "_blake2.blake2s",
- .basicsize = sizeof(Blake2Object),
+ .basicsize = sizeof(Blake2Object),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE,
.slots = blake2s_type_slots
diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h
index 6f4966825ec..75cf067c8aa 100644
--- a/Modules/clinic/_curses_panel.c.h
+++ b/Modules/clinic/_curses_panel.c.h
@@ -2,10 +2,7 @@
preserve
[clinic start generated code]*/
-#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
-# include "pycore_runtime.h" // _Py_SINGLETON()
-#endif
-#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(_curses_panel_panel_bottom__doc__,
"bottom($self, /)\n"
@@ -14,19 +11,15 @@ PyDoc_STRVAR(_curses_panel_panel_bottom__doc__,
"Push the panel to the bottom of the stack.");
#define _CURSES_PANEL_PANEL_BOTTOM_METHODDEF \
- {"bottom", _PyCFunction_CAST(_curses_panel_panel_bottom), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_bottom__doc__},
+ {"bottom", (PyCFunction)_curses_panel_panel_bottom, METH_NOARGS, _curses_panel_panel_bottom__doc__},
static PyObject *
-_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls);
+_curses_panel_panel_bottom_impl(PyCursesPanelObject *self);
static PyObject *
-_curses_panel_panel_bottom(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_bottom(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
- PyErr_SetString(PyExc_TypeError, "bottom() takes no arguments");
- return NULL;
- }
- return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self, cls);
+ return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self);
}
PyDoc_STRVAR(_curses_panel_panel_hide__doc__,
@@ -38,19 +31,15 @@ PyDoc_STRVAR(_curses_panel_panel_hide__doc__,
"This does not delete the object, it just makes the window on screen invisible.");
#define _CURSES_PANEL_PANEL_HIDE_METHODDEF \
- {"hide", _PyCFunction_CAST(_curses_panel_panel_hide), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_hide__doc__},
+ {"hide", (PyCFunction)_curses_panel_panel_hide, METH_NOARGS, _curses_panel_panel_hide__doc__},
static PyObject *
-_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls);
+_curses_panel_panel_hide_impl(PyCursesPanelObject *self);
static PyObject *
-_curses_panel_panel_hide(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_hide(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
- PyErr_SetString(PyExc_TypeError, "hide() takes no arguments");
- return NULL;
- }
- return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self, cls);
+ return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self);
}
PyDoc_STRVAR(_curses_panel_panel_show__doc__,
@@ -60,19 +49,15 @@ PyDoc_STRVAR(_curses_panel_panel_show__doc__,
"Display the panel (which might have been hidden).");
#define _CURSES_PANEL_PANEL_SHOW_METHODDEF \
- {"show", _PyCFunction_CAST(_curses_panel_panel_show), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_show__doc__},
+ {"show", (PyCFunction)_curses_panel_panel_show, METH_NOARGS, _curses_panel_panel_show__doc__},
static PyObject *
-_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls);
+_curses_panel_panel_show_impl(PyCursesPanelObject *self);
static PyObject *
-_curses_panel_panel_show(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_show(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
- PyErr_SetString(PyExc_TypeError, "show() takes no arguments");
- return NULL;
- }
- return _curses_panel_panel_show_impl((PyCursesPanelObject *)self, cls);
+ return _curses_panel_panel_show_impl((PyCursesPanelObject *)self);
}
PyDoc_STRVAR(_curses_panel_panel_top__doc__,
@@ -82,19 +67,15 @@ PyDoc_STRVAR(_curses_panel_panel_top__doc__,
"Push panel to the top of the stack.");
#define _CURSES_PANEL_PANEL_TOP_METHODDEF \
- {"top", _PyCFunction_CAST(_curses_panel_panel_top), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_top__doc__},
+ {"top", (PyCFunction)_curses_panel_panel_top, METH_NOARGS, _curses_panel_panel_top__doc__},
static PyObject *
-_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls);
+_curses_panel_panel_top_impl(PyCursesPanelObject *self);
static PyObject *
-_curses_panel_panel_top(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_top(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
- PyErr_SetString(PyExc_TypeError, "top() takes no arguments");
- return NULL;
- }
- return _curses_panel_panel_top_impl((PyCursesPanelObject *)self, cls);
+ return _curses_panel_panel_top_impl((PyCursesPanelObject *)self);
}
PyDoc_STRVAR(_curses_panel_panel_above__doc__,
@@ -158,36 +139,19 @@ PyDoc_STRVAR(_curses_panel_panel_move__doc__,
"Move the panel to the screen coordinates (y, x).");
#define _CURSES_PANEL_PANEL_MOVE_METHODDEF \
- {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_move__doc__},
+ {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_FASTCALL, _curses_panel_panel_move__doc__},
static PyObject *
-_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls,
- int y, int x);
+_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x);
static PyObject *
-_curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
- #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
- #else
- # define KWTUPLE NULL
- #endif
-
- static const char * const _keywords[] = {"", "", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "move",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[2];
int y;
int x;
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
- /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
- if (!args) {
+ if (!_PyArg_CheckPositional("move", nargs, 2, 2)) {
goto exit;
}
y = PyLong_AsInt(args[0]);
@@ -198,7 +162,7 @@ _curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *arg
if (x == -1 && PyErr_Occurred()) {
goto exit;
}
- return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, cls, y, x);
+ return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, y, x);
exit:
return return_value;
@@ -229,44 +193,24 @@ PyDoc_STRVAR(_curses_panel_panel_replace__doc__,
"Change the window associated with the panel to the window win.");
#define _CURSES_PANEL_PANEL_REPLACE_METHODDEF \
- {"replace", _PyCFunction_CAST(_curses_panel_panel_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_replace__doc__},
+ {"replace", (PyCFunction)_curses_panel_panel_replace, METH_O, _curses_panel_panel_replace__doc__},
static PyObject *
_curses_panel_panel_replace_impl(PyCursesPanelObject *self,
- PyTypeObject *cls,
PyCursesWindowObject *win);
static PyObject *
-_curses_panel_panel_replace(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_replace(PyObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
- #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
- #else
- # define KWTUPLE NULL
- #endif
-
- static const char * const _keywords[] = {"", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "replace",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[1];
PyCursesWindowObject *win;
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
- /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
- if (!args) {
- goto exit;
- }
- if (!PyObject_TypeCheck(args[0], &PyCursesWindow_Type)) {
- _PyArg_BadArgument("replace", "argument 1", (&PyCursesWindow_Type)->tp_name, args[0]);
+ if (!PyObject_TypeCheck(arg, &PyCursesWindow_Type)) {
+ _PyArg_BadArgument("replace", "argument", (&PyCursesWindow_Type)->tp_name, arg);
goto exit;
}
- win = (PyCursesWindowObject *)args[0];
- return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, cls, win);
+ win = (PyCursesWindowObject *)arg;
+ return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, win);
exit:
return return_value;
@@ -279,41 +223,19 @@ PyDoc_STRVAR(_curses_panel_panel_set_userptr__doc__,
"Set the panel\'s user pointer to obj.");
#define _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF \
- {"set_userptr", _PyCFunction_CAST(_curses_panel_panel_set_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_set_userptr__doc__},
+ {"set_userptr", (PyCFunction)_curses_panel_panel_set_userptr, METH_O, _curses_panel_panel_set_userptr__doc__},
static PyObject *
_curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
- PyTypeObject *cls, PyObject *obj);
+ PyObject *obj);
static PyObject *
-_curses_panel_panel_set_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_set_userptr(PyObject *self, PyObject *obj)
{
PyObject *return_value = NULL;
- #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
- #else
- # define KWTUPLE NULL
- #endif
-
- static const char * const _keywords[] = {"", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "set_userptr",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[1];
- PyObject *obj;
-
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
- /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
- if (!args) {
- goto exit;
- }
- obj = args[0];
- return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, cls, obj);
-exit:
+ return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, obj);
+
return return_value;
}
@@ -324,20 +246,15 @@ PyDoc_STRVAR(_curses_panel_panel_userptr__doc__,
"Return the user pointer for the panel.");
#define _CURSES_PANEL_PANEL_USERPTR_METHODDEF \
- {"userptr", _PyCFunction_CAST(_curses_panel_panel_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_userptr__doc__},
+ {"userptr", (PyCFunction)_curses_panel_panel_userptr, METH_NOARGS, _curses_panel_panel_userptr__doc__},
static PyObject *
-_curses_panel_panel_userptr_impl(PyCursesPanelObject *self,
- PyTypeObject *cls);
+_curses_panel_panel_userptr_impl(PyCursesPanelObject *self);
static PyObject *
-_curses_panel_panel_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_curses_panel_panel_userptr(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
- PyErr_SetString(PyExc_TypeError, "userptr() takes no arguments");
- return NULL;
- }
- return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self, cls);
+ return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self);
}
PyDoc_STRVAR(_curses_panel_bottom_panel__doc__,
@@ -424,4 +341,4 @@ _curses_panel_update_panels(PyObject *module, PyObject *Py_UNUSED(ignored))
{
return _curses_panel_update_panels_impl(module);
}
-/*[clinic end generated code: output=36853ecb4a979814 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=db2fe491582784aa input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h
index 3a1c1698b1b..49c864318c8 100644
--- a/Modules/clinic/_cursesmodule.c.h
+++ b/Modules/clinic/_cursesmodule.c.h
@@ -733,23 +733,13 @@ PyDoc_STRVAR(_curses_window_getbkgd__doc__,
#define _CURSES_WINDOW_GETBKGD_METHODDEF \
{"getbkgd", (PyCFunction)_curses_window_getbkgd, METH_NOARGS, _curses_window_getbkgd__doc__},
-static long
+static PyObject *
_curses_window_getbkgd_impl(PyCursesWindowObject *self);
static PyObject *
_curses_window_getbkgd(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- PyObject *return_value = NULL;
- long _return_value;
-
- _return_value = _curses_window_getbkgd_impl((PyCursesWindowObject *)self);
- if ((_return_value == -1) && PyErr_Occurred()) {
- goto exit;
- }
- return_value = PyLong_FromLong(_return_value);
-
-exit:
- return return_value;
+ return _curses_window_getbkgd_impl((PyCursesWindowObject *)self);
}
PyDoc_STRVAR(_curses_window_getch__doc__,
@@ -768,7 +758,7 @@ PyDoc_STRVAR(_curses_window_getch__doc__,
#define _CURSES_WINDOW_GETCH_METHODDEF \
{"getch", (PyCFunction)_curses_window_getch, METH_VARARGS, _curses_window_getch__doc__},
-static int
+static PyObject *
_curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1,
int y, int x);
@@ -779,7 +769,6 @@ _curses_window_getch(PyObject *self, PyObject *args)
int group_right_1 = 0;
int y = 0;
int x = 0;
- int _return_value;
switch (PyTuple_GET_SIZE(args)) {
case 0:
@@ -794,11 +783,7 @@ _curses_window_getch(PyObject *self, PyObject *args)
PyErr_SetString(PyExc_TypeError, "_curses.window.getch requires 0 to 2 arguments");
goto exit;
}
- _return_value = _curses_window_getch_impl((PyCursesWindowObject *)self, group_right_1, y, x);
- if ((_return_value == -1) && PyErr_Occurred()) {
- goto exit;
- }
- return_value = PyLong_FromLong((long)_return_value);
+ return_value = _curses_window_getch_impl((PyCursesWindowObject *)self, group_right_1, y, x);
exit:
return return_value;
@@ -1055,7 +1040,7 @@ PyDoc_STRVAR(_curses_window_inch__doc__,
#define _CURSES_WINDOW_INCH_METHODDEF \
{"inch", (PyCFunction)_curses_window_inch, METH_VARARGS, _curses_window_inch__doc__},
-static unsigned long
+static PyObject *
_curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1,
int y, int x);
@@ -1066,7 +1051,6 @@ _curses_window_inch(PyObject *self, PyObject *args)
int group_right_1 = 0;
int y = 0;
int x = 0;
- unsigned long _return_value;
switch (PyTuple_GET_SIZE(args)) {
case 0:
@@ -1081,11 +1065,7 @@ _curses_window_inch(PyObject *self, PyObject *args)
PyErr_SetString(PyExc_TypeError, "_curses.window.inch requires 0 to 2 arguments");
goto exit;
}
- _return_value = _curses_window_inch_impl((PyCursesWindowObject *)self, group_right_1, y, x);
- if ((_return_value == (unsigned long)-1) && PyErr_Occurred()) {
- goto exit;
- }
- return_value = PyLong_FromUnsignedLong(_return_value);
+ return_value = _curses_window_inch_impl((PyCursesWindowObject *)self, group_right_1, y, x);
exit:
return return_value;
@@ -4263,10 +4243,7 @@ PyDoc_STRVAR(_curses_use_default_colors__doc__,
"use_default_colors($module, /)\n"
"--\n"
"\n"
-"Allow use of default values for colors on terminals supporting this feature.\n"
-"\n"
-"Use this to support transparency in your application. The default color\n"
-"is assigned to the color number -1.");
+"Equivalent to assume_default_colors(-1, -1).");
#define _CURSES_USE_DEFAULT_COLORS_METHODDEF \
{"use_default_colors", (PyCFunction)_curses_use_default_colors, METH_NOARGS, _curses_use_default_colors__doc__},
@@ -4282,6 +4259,51 @@ _curses_use_default_colors(PyObject *module, PyObject *Py_UNUSED(ignored))
#endif /* !defined(STRICT_SYSV_CURSES) */
+#if !defined(STRICT_SYSV_CURSES)
+
+PyDoc_STRVAR(_curses_assume_default_colors__doc__,
+"assume_default_colors($module, fg, bg, /)\n"
+"--\n"
+"\n"
+"Allow use of default values for colors on terminals supporting this feature.\n"
+"\n"
+"Assign terminal default foreground/background colors to color number -1.\n"
+"Change the definition of the color-pair 0 to (fg, bg).\n"
+"\n"
+"Use this to support transparency in your application.");
+
+#define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF \
+ {"assume_default_colors", _PyCFunction_CAST(_curses_assume_default_colors), METH_FASTCALL, _curses_assume_default_colors__doc__},
+
+static PyObject *
+_curses_assume_default_colors_impl(PyObject *module, int fg, int bg);
+
+static PyObject *
+_curses_assume_default_colors(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int fg;
+ int bg;
+
+ if (!_PyArg_CheckPositional("assume_default_colors", nargs, 2, 2)) {
+ goto exit;
+ }
+ fg = PyLong_AsInt(args[0]);
+ if (fg == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ bg = PyLong_AsInt(args[1]);
+ if (bg == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = _curses_assume_default_colors_impl(module, fg, bg);
+
+exit:
+ return return_value;
+}
+
+#endif /* !defined(STRICT_SYSV_CURSES) */
+
PyDoc_STRVAR(_curses_has_extended_color_support__doc__,
"has_extended_color_support($module, /)\n"
"--\n"
@@ -4394,4 +4416,8 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored
#ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF
#define _CURSES_USE_DEFAULT_COLORS_METHODDEF
#endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */
-/*[clinic end generated code: output=dbbbe86a4171799a input=a9049054013a1b77]*/
+
+#ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
+ #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
+#endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */
+/*[clinic end generated code: output=a083473003179b30 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_dbmmodule.c.h b/Modules/clinic/_dbmmodule.c.h
index 5e503194408..091ce9edc43 100644
--- a/Modules/clinic/_dbmmodule.c.h
+++ b/Modules/clinic/_dbmmodule.c.h
@@ -5,6 +5,7 @@ preserve
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# include "pycore_runtime.h" // _Py_SINGLETON()
#endif
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(_dbm_dbm_close__doc__,
@@ -22,7 +23,13 @@ _dbm_dbm_close_impl(dbmobject *self);
static PyObject *
_dbm_dbm_close(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return _dbm_dbm_close_impl((dbmobject *)self);
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _dbm_dbm_close_impl((dbmobject *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
}
PyDoc_STRVAR(_dbm_dbm_keys__doc__,
@@ -40,11 +47,18 @@ _dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls);
static PyObject *
_dbm_dbm_keys(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "keys() takes no arguments");
- return NULL;
+ goto exit;
}
- return _dbm_dbm_keys_impl((dbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _dbm_dbm_keys_impl((dbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_dbm_dbm_get__doc__,
@@ -85,7 +99,9 @@ _dbm_dbm_get(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_
&key, &key_length, &default_value)) {
goto exit;
}
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _dbm_dbm_get_impl((dbmobject *)self, cls, key, key_length, default_value);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -131,7 +147,9 @@ _dbm_dbm_setdefault(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py
&key, &key_length, &default_value)) {
goto exit;
}
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _dbm_dbm_setdefault_impl((dbmobject *)self, cls, key, key_length, default_value);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -152,11 +170,18 @@ _dbm_dbm_clear_impl(dbmobject *self, PyTypeObject *cls);
static PyObject *
_dbm_dbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "clear() takes no arguments");
- return NULL;
+ goto exit;
}
- return _dbm_dbm_clear_impl((dbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _dbm_dbm_clear_impl((dbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(dbmopen__doc__,
@@ -221,4 +246,4 @@ skip_optional:
exit:
return return_value;
}
-/*[clinic end generated code: output=3b456118f231b160 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=279511ea7cda38dd input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h
index 00950f18e53..6fd6aa3da50 100644
--- a/Modules/clinic/_gdbmmodule.c.h
+++ b/Modules/clinic/_gdbmmodule.c.h
@@ -5,6 +5,7 @@ preserve
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# include "pycore_runtime.h" // _Py_SINGLETON()
#endif
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(_gdbm_gdbm_get__doc__,
@@ -70,7 +71,9 @@ _gdbm_gdbm_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
}
default_value = args[1];
skip_optional:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _gdbm_gdbm_setdefault_impl((gdbmobject *)self, key, default_value);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -91,7 +94,13 @@ _gdbm_gdbm_close_impl(gdbmobject *self);
static PyObject *
_gdbm_gdbm_close(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return _gdbm_gdbm_close_impl((gdbmobject *)self);
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _gdbm_gdbm_close_impl((gdbmobject *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_keys__doc__,
@@ -109,11 +118,18 @@ _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
_gdbm_gdbm_keys(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "keys() takes no arguments");
- return NULL;
+ goto exit;
}
- return _gdbm_gdbm_keys_impl((gdbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _gdbm_gdbm_keys_impl((gdbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__,
@@ -135,11 +151,18 @@ _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
_gdbm_gdbm_firstkey(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "firstkey() takes no arguments");
- return NULL;
+ goto exit;
}
- return _gdbm_gdbm_firstkey_impl((gdbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _gdbm_gdbm_firstkey_impl((gdbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__,
@@ -187,7 +210,9 @@ _gdbm_gdbm_nextkey(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_
&key, &key_length)) {
goto exit;
}
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = _gdbm_gdbm_nextkey_impl((gdbmobject *)self, cls, key, key_length);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -214,11 +239,18 @@ _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
_gdbm_gdbm_reorganize(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "reorganize() takes no arguments");
- return NULL;
+ goto exit;
}
- return _gdbm_gdbm_reorganize_impl((gdbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _gdbm_gdbm_reorganize_impl((gdbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_sync__doc__,
@@ -239,11 +271,18 @@ _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
_gdbm_gdbm_sync(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "sync() takes no arguments");
- return NULL;
+ goto exit;
}
- return _gdbm_gdbm_sync_impl((gdbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _gdbm_gdbm_sync_impl((gdbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_clear__doc__,
@@ -261,11 +300,18 @@ _gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
_gdbm_gdbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
+ PyObject *return_value = NULL;
+
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
PyErr_SetString(PyExc_TypeError, "clear() takes no arguments");
- return NULL;
+ goto exit;
}
- return _gdbm_gdbm_clear_impl((gdbmobject *)self, cls);
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _gdbm_gdbm_clear_impl((gdbmobject *)self, cls);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(dbmopen__doc__,
@@ -343,4 +389,4 @@ skip_optional:
exit:
return return_value;
}
-/*[clinic end generated code: output=d974cb39e4ee5d67 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=8bca34ce9d4493dd input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h
index 59ab46ca3f0..61ea10e2a48 100644
--- a/Modules/clinic/_hashopenssl.c.h
+++ b/Modules/clinic/_hashopenssl.c.h
@@ -10,98 +10,98 @@ preserve
#include "pycore_long.h" // _PyLong_UnsignedLong_Converter()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
-PyDoc_STRVAR(EVP_copy__doc__,
+PyDoc_STRVAR(_hashlib_HASH_copy__doc__,
"copy($self, /)\n"
"--\n"
"\n"
"Return a copy of the hash object.");
-#define EVP_COPY_METHODDEF \
- {"copy", (PyCFunction)EVP_copy, METH_NOARGS, EVP_copy__doc__},
+#define _HASHLIB_HASH_COPY_METHODDEF \
+ {"copy", (PyCFunction)_hashlib_HASH_copy, METH_NOARGS, _hashlib_HASH_copy__doc__},
static PyObject *
-EVP_copy_impl(EVPobject *self);
+_hashlib_HASH_copy_impl(HASHobject *self);
static PyObject *
-EVP_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
+_hashlib_HASH_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return EVP_copy_impl((EVPobject *)self);
+ return _hashlib_HASH_copy_impl((HASHobject *)self);
}
-PyDoc_STRVAR(EVP_digest__doc__,
+PyDoc_STRVAR(_hashlib_HASH_digest__doc__,
"digest($self, /)\n"
"--\n"
"\n"
"Return the digest value as a bytes object.");
-#define EVP_DIGEST_METHODDEF \
- {"digest", (PyCFunction)EVP_digest, METH_NOARGS, EVP_digest__doc__},
+#define _HASHLIB_HASH_DIGEST_METHODDEF \
+ {"digest", (PyCFunction)_hashlib_HASH_digest, METH_NOARGS, _hashlib_HASH_digest__doc__},
static PyObject *
-EVP_digest_impl(EVPobject *self);
+_hashlib_HASH_digest_impl(HASHobject *self);
static PyObject *
-EVP_digest(PyObject *self, PyObject *Py_UNUSED(ignored))
+_hashlib_HASH_digest(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return EVP_digest_impl((EVPobject *)self);
+ return _hashlib_HASH_digest_impl((HASHobject *)self);
}
-PyDoc_STRVAR(EVP_hexdigest__doc__,
+PyDoc_STRVAR(_hashlib_HASH_hexdigest__doc__,
"hexdigest($self, /)\n"
"--\n"
"\n"
"Return the digest value as a string of hexadecimal digits.");
-#define EVP_HEXDIGEST_METHODDEF \
- {"hexdigest", (PyCFunction)EVP_hexdigest, METH_NOARGS, EVP_hexdigest__doc__},
+#define _HASHLIB_HASH_HEXDIGEST_METHODDEF \
+ {"hexdigest", (PyCFunction)_hashlib_HASH_hexdigest, METH_NOARGS, _hashlib_HASH_hexdigest__doc__},
static PyObject *
-EVP_hexdigest_impl(EVPobject *self);
+_hashlib_HASH_hexdigest_impl(HASHobject *self);
static PyObject *
-EVP_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored))
+_hashlib_HASH_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- return EVP_hexdigest_impl((EVPobject *)self);
+ return _hashlib_HASH_hexdigest_impl((HASHobject *)self);
}
-PyDoc_STRVAR(EVP_update__doc__,
+PyDoc_STRVAR(_hashlib_HASH_update__doc__,
"update($self, obj, /)\n"
"--\n"
"\n"
"Update this hash object\'s state with the provided string.");
-#define EVP_UPDATE_METHODDEF \
- {"update", (PyCFunction)EVP_update, METH_O, EVP_update__doc__},
+#define _HASHLIB_HASH_UPDATE_METHODDEF \
+ {"update", (PyCFunction)_hashlib_HASH_update, METH_O, _hashlib_HASH_update__doc__},
static PyObject *
-EVP_update_impl(EVPobject *self, PyObject *obj);
+_hashlib_HASH_update_impl(HASHobject *self, PyObject *obj);
static PyObject *
-EVP_update(PyObject *self, PyObject *obj)
+_hashlib_HASH_update(PyObject *self, PyObject *obj)
{
PyObject *return_value = NULL;
- return_value = EVP_update_impl((EVPobject *)self, obj);
+ return_value = _hashlib_HASH_update_impl((HASHobject *)self, obj);
return return_value;
}
#if defined(PY_OPENSSL_HAS_SHAKE)
-PyDoc_STRVAR(EVPXOF_digest__doc__,
+PyDoc_STRVAR(_hashlib_HASHXOF_digest__doc__,
"digest($self, /, length)\n"
"--\n"
"\n"
"Return the digest value as a bytes object.");
-#define EVPXOF_DIGEST_METHODDEF \
- {"digest", _PyCFunction_CAST(EVPXOF_digest), METH_FASTCALL|METH_KEYWORDS, EVPXOF_digest__doc__},
+#define _HASHLIB_HASHXOF_DIGEST_METHODDEF \
+ {"digest", _PyCFunction_CAST(_hashlib_HASHXOF_digest), METH_FASTCALL|METH_KEYWORDS, _hashlib_HASHXOF_digest__doc__},
static PyObject *
-EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length);
+_hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length);
static PyObject *
-EVPXOF_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_hashlib_HASHXOF_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
@@ -151,7 +151,7 @@ EVPXOF_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject
}
length = ival;
}
- return_value = EVPXOF_digest_impl((EVPobject *)self, length);
+ return_value = _hashlib_HASHXOF_digest_impl((HASHobject *)self, length);
exit:
return return_value;
@@ -161,20 +161,20 @@ exit:
#if defined(PY_OPENSSL_HAS_SHAKE)
-PyDoc_STRVAR(EVPXOF_hexdigest__doc__,
+PyDoc_STRVAR(_hashlib_HASHXOF_hexdigest__doc__,
"hexdigest($self, /, length)\n"
"--\n"
"\n"
"Return the digest value as a string of hexadecimal digits.");
-#define EVPXOF_HEXDIGEST_METHODDEF \
- {"hexdigest", _PyCFunction_CAST(EVPXOF_hexdigest), METH_FASTCALL|METH_KEYWORDS, EVPXOF_hexdigest__doc__},
+#define _HASHLIB_HASHXOF_HEXDIGEST_METHODDEF \
+ {"hexdigest", _PyCFunction_CAST(_hashlib_HASHXOF_hexdigest), METH_FASTCALL|METH_KEYWORDS, _hashlib_HASHXOF_hexdigest__doc__},
static PyObject *
-EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length);
+_hashlib_HASHXOF_hexdigest_impl(HASHobject *self, Py_ssize_t length);
static PyObject *
-EVPXOF_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_hashlib_HASHXOF_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
@@ -224,7 +224,7 @@ EVPXOF_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje
}
length = ival;
}
- return_value = EVPXOF_hexdigest_impl((EVPobject *)self, length);
+ return_value = _hashlib_HASHXOF_hexdigest_impl((HASHobject *)self, length);
exit:
return return_value;
@@ -232,8 +232,8 @@ exit:
#endif /* defined(PY_OPENSSL_HAS_SHAKE) */
-PyDoc_STRVAR(EVP_new__doc__,
-"new($module, /, name, string=b\'\', *, usedforsecurity=True)\n"
+PyDoc_STRVAR(_hashlib_HASH_new__doc__,
+"new($module, /, name, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new hash object using the named algorithm.\n"
@@ -243,20 +243,20 @@ PyDoc_STRVAR(EVP_new__doc__,
"\n"
"The MD5 and SHA1 algorithms are always supported.");
-#define EVP_NEW_METHODDEF \
- {"new", _PyCFunction_CAST(EVP_new), METH_FASTCALL|METH_KEYWORDS, EVP_new__doc__},
+#define _HASHLIB_HASH_NEW_METHODDEF \
+ {"new", _PyCFunction_CAST(_hashlib_HASH_new), METH_FASTCALL|METH_KEYWORDS, _hashlib_HASH_new__doc__},
static PyObject *
-EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_HASH_new_impl(PyObject *module, const char *name, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
-EVP_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+_hashlib_HASH_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 3
+ #define NUM_KEYWORDS 4
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -265,7 +265,7 @@ EVP_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(name), &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(name), &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -274,30 +274,43 @@ EVP_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"name", "string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"name", "data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "new",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[3];
+ PyObject *argsbuf[4];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
- PyObject *name_obj;
- PyObject *data_obj = NULL;
+ const char *name;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
- name_obj = args[0];
+ if (!PyUnicode_Check(args[0])) {
+ _PyArg_BadArgument("new", "argument 'name'", "str", args[0]);
+ goto exit;
+ }
+ Py_ssize_t name_length;
+ name = PyUnicode_AsUTF8AndSize(args[0], &name_length);
+ if (name == NULL) {
+ goto exit;
+ }
+ if (strlen(name) != (size_t)name_length) {
+ PyErr_SetString(PyExc_ValueError, "embedded null character");
+ goto exit;
+ }
if (!noptargs) {
goto skip_optional_pos;
}
if (args[1]) {
- data_obj = args[1];
+ data = args[1];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -306,19 +319,25 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[2]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[2]) {
+ usedforsecurity = PyObject_IsTrue(args[2]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[3];
skip_optional_kwonly:
- return_value = EVP_new_impl(module, name_obj, data_obj, usedforsecurity);
+ return_value = _hashlib_HASH_new_impl(module, name, data, usedforsecurity, string);
exit:
return return_value;
}
PyDoc_STRVAR(_hashlib_openssl_md5__doc__,
-"openssl_md5($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_md5($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Returns a md5 hash object; optionally initialized with a string");
@@ -327,8 +346,8 @@ PyDoc_STRVAR(_hashlib_openssl_md5__doc__,
{"openssl_md5", _PyCFunction_CAST(_hashlib_openssl_md5), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_md5__doc__},
static PyObject *
-_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_md5_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -336,7 +355,7 @@ _hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -345,7 +364,7 @@ _hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -354,17 +373,18 @@ _hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_md5",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -375,7 +395,7 @@ _hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -384,19 +404,25 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_md5_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_md5_impl(module, data, usedforsecurity, string);
exit:
return return_value;
}
PyDoc_STRVAR(_hashlib_openssl_sha1__doc__,
-"openssl_sha1($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha1($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Returns a sha1 hash object; optionally initialized with a string");
@@ -405,8 +431,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha1__doc__,
{"openssl_sha1", _PyCFunction_CAST(_hashlib_openssl_sha1), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha1__doc__},
static PyObject *
-_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -414,7 +440,7 @@ _hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -423,7 +449,7 @@ _hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -432,17 +458,18 @@ _hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha1",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -453,7 +480,7 @@ _hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -462,19 +489,26 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha1_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha1_impl(module, data, usedforsecurity, string);
exit:
return return_value;
}
PyDoc_STRVAR(_hashlib_openssl_sha224__doc__,
-"openssl_sha224($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha224($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha224 hash object; optionally initialized with a string");
@@ -483,8 +517,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha224__doc__,
{"openssl_sha224", _PyCFunction_CAST(_hashlib_openssl_sha224), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha224__doc__},
static PyObject *
-_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -492,7 +526,7 @@ _hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t narg
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -501,7 +535,7 @@ _hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t narg
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -510,17 +544,18 @@ _hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t narg
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha224",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -531,7 +566,7 @@ _hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t narg
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -540,19 +575,26 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha224_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha224_impl(module, data, usedforsecurity, string);
exit:
return return_value;
}
PyDoc_STRVAR(_hashlib_openssl_sha256__doc__,
-"openssl_sha256($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha256($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha256 hash object; optionally initialized with a string");
@@ -561,8 +603,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha256__doc__,
{"openssl_sha256", _PyCFunction_CAST(_hashlib_openssl_sha256), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha256__doc__},
static PyObject *
-_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -570,7 +612,7 @@ _hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t narg
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -579,7 +621,7 @@ _hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t narg
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -588,17 +630,18 @@ _hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t narg
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha256",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -609,7 +652,7 @@ _hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t narg
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -618,19 +661,26 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha256_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha256_impl(module, data, usedforsecurity, string);
exit:
return return_value;
}
PyDoc_STRVAR(_hashlib_openssl_sha384__doc__,
-"openssl_sha384($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha384($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha384 hash object; optionally initialized with a string");
@@ -639,8 +689,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha384__doc__,
{"openssl_sha384", _PyCFunction_CAST(_hashlib_openssl_sha384), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha384__doc__},
static PyObject *
-_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -648,7 +698,7 @@ _hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t narg
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -657,7 +707,7 @@ _hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t narg
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -666,17 +716,18 @@ _hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t narg
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha384",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -687,7 +738,7 @@ _hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t narg
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -696,19 +747,26 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha384_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha384_impl(module, data, usedforsecurity, string);
exit:
return return_value;
}
PyDoc_STRVAR(_hashlib_openssl_sha512__doc__,
-"openssl_sha512($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha512($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha512 hash object; optionally initialized with a string");
@@ -717,8 +775,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha512__doc__,
{"openssl_sha512", _PyCFunction_CAST(_hashlib_openssl_sha512), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha512__doc__},
static PyObject *
-_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -726,7 +784,7 @@ _hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t narg
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -735,7 +793,7 @@ _hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t narg
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -744,17 +802,18 @@ _hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t narg
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha512",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -765,7 +824,7 @@ _hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t narg
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -774,12 +833,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha512_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha512_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -788,7 +853,8 @@ exit:
#if defined(PY_OPENSSL_HAS_SHA3)
PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__,
-"openssl_sha3_224($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha3_224($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha3-224 hash object; optionally initialized with a string");
@@ -797,8 +863,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__,
{"openssl_sha3_224", _PyCFunction_CAST(_hashlib_openssl_sha3_224), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_224__doc__},
static PyObject *
-_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -806,7 +872,7 @@ _hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t na
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -815,7 +881,7 @@ _hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t na
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -824,17 +890,18 @@ _hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t na
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha3_224",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -845,7 +912,7 @@ _hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t na
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -854,12 +921,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha3_224_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha3_224_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -870,7 +943,8 @@ exit:
#if defined(PY_OPENSSL_HAS_SHA3)
PyDoc_STRVAR(_hashlib_openssl_sha3_256__doc__,
-"openssl_sha3_256($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha3_256($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha3-256 hash object; optionally initialized with a string");
@@ -879,8 +953,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_256__doc__,
{"openssl_sha3_256", _PyCFunction_CAST(_hashlib_openssl_sha3_256), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_256__doc__},
static PyObject *
-_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -888,7 +962,7 @@ _hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t na
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -897,7 +971,7 @@ _hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t na
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -906,17 +980,18 @@ _hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t na
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha3_256",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -927,7 +1002,7 @@ _hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t na
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -936,12 +1011,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha3_256_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha3_256_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -952,7 +1033,8 @@ exit:
#if defined(PY_OPENSSL_HAS_SHA3)
PyDoc_STRVAR(_hashlib_openssl_sha3_384__doc__,
-"openssl_sha3_384($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha3_384($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha3-384 hash object; optionally initialized with a string");
@@ -961,8 +1043,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_384__doc__,
{"openssl_sha3_384", _PyCFunction_CAST(_hashlib_openssl_sha3_384), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_384__doc__},
static PyObject *
-_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -970,7 +1052,7 @@ _hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t na
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -979,7 +1061,7 @@ _hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t na
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -988,17 +1070,18 @@ _hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t na
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha3_384",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -1009,7 +1092,7 @@ _hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t na
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -1018,12 +1101,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha3_384_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha3_384_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -1034,7 +1123,8 @@ exit:
#if defined(PY_OPENSSL_HAS_SHA3)
PyDoc_STRVAR(_hashlib_openssl_sha3_512__doc__,
-"openssl_sha3_512($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_sha3_512($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a sha3-512 hash object; optionally initialized with a string");
@@ -1043,8 +1133,8 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_512__doc__,
{"openssl_sha3_512", _PyCFunction_CAST(_hashlib_openssl_sha3_512), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_512__doc__},
static PyObject *
-_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -1052,7 +1142,7 @@ _hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t na
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -1061,7 +1151,7 @@ _hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t na
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -1070,17 +1160,18 @@ _hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t na
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_sha3_512",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -1091,7 +1182,7 @@ _hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t na
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -1100,12 +1191,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_sha3_512_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_sha3_512_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -1116,7 +1213,8 @@ exit:
#if defined(PY_OPENSSL_HAS_SHAKE)
PyDoc_STRVAR(_hashlib_openssl_shake_128__doc__,
-"openssl_shake_128($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_shake_128($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a shake-128 variable hash object; optionally initialized with a string");
@@ -1125,8 +1223,8 @@ PyDoc_STRVAR(_hashlib_openssl_shake_128__doc__,
{"openssl_shake_128", _PyCFunction_CAST(_hashlib_openssl_shake_128), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_128__doc__},
static PyObject *
-_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -1134,7 +1232,7 @@ _hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t n
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -1143,7 +1241,7 @@ _hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t n
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -1152,17 +1250,18 @@ _hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t n
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_shake_128",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -1173,7 +1272,7 @@ _hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t n
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -1182,12 +1281,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_shake_128_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_shake_128_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -1198,7 +1303,8 @@ exit:
#if defined(PY_OPENSSL_HAS_SHAKE)
PyDoc_STRVAR(_hashlib_openssl_shake_256__doc__,
-"openssl_shake_256($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"openssl_shake_256($module, /, data=b\'\', *, usedforsecurity=True,\n"
+" string=None)\n"
"--\n"
"\n"
"Returns a shake-256 variable hash object; optionally initialized with a string");
@@ -1207,8 +1313,8 @@ PyDoc_STRVAR(_hashlib_openssl_shake_256__doc__,
{"openssl_shake_256", _PyCFunction_CAST(_hashlib_openssl_shake_256), METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_256__doc__},
static PyObject *
-_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj,
- int usedforsecurity);
+_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data,
+ int usedforsecurity, PyObject *string);
static PyObject *
_hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -1216,7 +1322,7 @@ _hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t n
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -1225,7 +1331,7 @@ _hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t n
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -1234,17 +1340,18 @@ _hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t n
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "openssl_shake_256",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *data_obj = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -1255,7 +1362,7 @@ _hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t n
goto skip_optional_pos;
}
if (args[0]) {
- data_obj = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -1264,12 +1371,18 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = args[2];
skip_optional_kwonly:
- return_value = _hashlib_openssl_shake_256_impl(module, data_obj, usedforsecurity);
+ return_value = _hashlib_openssl_shake_256_impl(module, data, usedforsecurity, string);
exit:
return return_value;
@@ -1836,13 +1949,13 @@ exit:
return return_value;
}
-#ifndef EVPXOF_DIGEST_METHODDEF
- #define EVPXOF_DIGEST_METHODDEF
-#endif /* !defined(EVPXOF_DIGEST_METHODDEF) */
+#ifndef _HASHLIB_HASHXOF_DIGEST_METHODDEF
+ #define _HASHLIB_HASHXOF_DIGEST_METHODDEF
+#endif /* !defined(_HASHLIB_HASHXOF_DIGEST_METHODDEF) */
-#ifndef EVPXOF_HEXDIGEST_METHODDEF
- #define EVPXOF_HEXDIGEST_METHODDEF
-#endif /* !defined(EVPXOF_HEXDIGEST_METHODDEF) */
+#ifndef _HASHLIB_HASHXOF_HEXDIGEST_METHODDEF
+ #define _HASHLIB_HASHXOF_HEXDIGEST_METHODDEF
+#endif /* !defined(_HASHLIB_HASHXOF_HEXDIGEST_METHODDEF) */
#ifndef _HASHLIB_OPENSSL_SHA3_224_METHODDEF
#define _HASHLIB_OPENSSL_SHA3_224_METHODDEF
@@ -1871,4 +1984,4 @@ exit:
#ifndef _HASHLIB_SCRYPT_METHODDEF
#define _HASHLIB_SCRYPT_METHODDEF
#endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */
-/*[clinic end generated code: output=2c78822e38be64a8 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=29f4aaf01714778e input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_heapqmodule.c.h b/Modules/clinic/_heapqmodule.c.h
index 90463079907..b43155b6c24 100644
--- a/Modules/clinic/_heapqmodule.c.h
+++ b/Modules/clinic/_heapqmodule.c.h
@@ -2,6 +2,7 @@
preserve
[clinic start generated code]*/
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(_heapq_heappush__doc__,
@@ -32,7 +33,9 @@ _heapq_heappush(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
}
heap = args[0];
item = args[1];
+ Py_BEGIN_CRITICAL_SECTION(heap);
return_value = _heapq_heappush_impl(module, heap, item);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -61,7 +64,9 @@ _heapq_heappop(PyObject *module, PyObject *arg)
goto exit;
}
heap = arg;
+ Py_BEGIN_CRITICAL_SECTION(heap);
return_value = _heapq_heappop_impl(module, heap);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -103,7 +108,9 @@ _heapq_heapreplace(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
}
heap = args[0];
item = args[1];
+ Py_BEGIN_CRITICAL_SECTION(heap);
return_value = _heapq_heapreplace_impl(module, heap, item);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -140,7 +147,9 @@ _heapq_heappushpop(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
}
heap = args[0];
item = args[1];
+ Py_BEGIN_CRITICAL_SECTION(heap);
return_value = _heapq_heappushpop_impl(module, heap, item);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
@@ -169,102 +178,184 @@ _heapq_heapify(PyObject *module, PyObject *arg)
goto exit;
}
heap = arg;
+ Py_BEGIN_CRITICAL_SECTION(heap);
return_value = _heapq_heapify_impl(module, heap);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
-PyDoc_STRVAR(_heapq__heappop_max__doc__,
-"_heappop_max($module, heap, /)\n"
+PyDoc_STRVAR(_heapq_heappush_max__doc__,
+"heappush_max($module, heap, item, /)\n"
+"--\n"
+"\n"
+"Push item onto max heap, maintaining the heap invariant.");
+
+#define _HEAPQ_HEAPPUSH_MAX_METHODDEF \
+ {"heappush_max", _PyCFunction_CAST(_heapq_heappush_max), METH_FASTCALL, _heapq_heappush_max__doc__},
+
+static PyObject *
+_heapq_heappush_max_impl(PyObject *module, PyObject *heap, PyObject *item);
+
+static PyObject *
+_heapq_heappush_max(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *heap;
+ PyObject *item;
+
+ if (!_PyArg_CheckPositional("heappush_max", nargs, 2, 2)) {
+ goto exit;
+ }
+ if (!PyList_Check(args[0])) {
+ _PyArg_BadArgument("heappush_max", "argument 1", "list", args[0]);
+ goto exit;
+ }
+ heap = args[0];
+ item = args[1];
+ Py_BEGIN_CRITICAL_SECTION(heap);
+ return_value = _heapq_heappush_max_impl(module, heap, item);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_heapq_heappop_max__doc__,
+"heappop_max($module, heap, /)\n"
"--\n"
"\n"
"Maxheap variant of heappop.");
-#define _HEAPQ__HEAPPOP_MAX_METHODDEF \
- {"_heappop_max", (PyCFunction)_heapq__heappop_max, METH_O, _heapq__heappop_max__doc__},
+#define _HEAPQ_HEAPPOP_MAX_METHODDEF \
+ {"heappop_max", (PyCFunction)_heapq_heappop_max, METH_O, _heapq_heappop_max__doc__},
static PyObject *
-_heapq__heappop_max_impl(PyObject *module, PyObject *heap);
+_heapq_heappop_max_impl(PyObject *module, PyObject *heap);
static PyObject *
-_heapq__heappop_max(PyObject *module, PyObject *arg)
+_heapq_heappop_max(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
PyObject *heap;
if (!PyList_Check(arg)) {
- _PyArg_BadArgument("_heappop_max", "argument", "list", arg);
+ _PyArg_BadArgument("heappop_max", "argument", "list", arg);
goto exit;
}
heap = arg;
- return_value = _heapq__heappop_max_impl(module, heap);
+ Py_BEGIN_CRITICAL_SECTION(heap);
+ return_value = _heapq_heappop_max_impl(module, heap);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
-PyDoc_STRVAR(_heapq__heapreplace_max__doc__,
-"_heapreplace_max($module, heap, item, /)\n"
+PyDoc_STRVAR(_heapq_heapreplace_max__doc__,
+"heapreplace_max($module, heap, item, /)\n"
"--\n"
"\n"
"Maxheap variant of heapreplace.");
-#define _HEAPQ__HEAPREPLACE_MAX_METHODDEF \
- {"_heapreplace_max", _PyCFunction_CAST(_heapq__heapreplace_max), METH_FASTCALL, _heapq__heapreplace_max__doc__},
+#define _HEAPQ_HEAPREPLACE_MAX_METHODDEF \
+ {"heapreplace_max", _PyCFunction_CAST(_heapq_heapreplace_max), METH_FASTCALL, _heapq_heapreplace_max__doc__},
static PyObject *
-_heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
- PyObject *item);
+_heapq_heapreplace_max_impl(PyObject *module, PyObject *heap, PyObject *item);
static PyObject *
-_heapq__heapreplace_max(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+_heapq_heapreplace_max(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *heap;
PyObject *item;
- if (!_PyArg_CheckPositional("_heapreplace_max", nargs, 2, 2)) {
+ if (!_PyArg_CheckPositional("heapreplace_max", nargs, 2, 2)) {
goto exit;
}
if (!PyList_Check(args[0])) {
- _PyArg_BadArgument("_heapreplace_max", "argument 1", "list", args[0]);
+ _PyArg_BadArgument("heapreplace_max", "argument 1", "list", args[0]);
goto exit;
}
heap = args[0];
item = args[1];
- return_value = _heapq__heapreplace_max_impl(module, heap, item);
+ Py_BEGIN_CRITICAL_SECTION(heap);
+ return_value = _heapq_heapreplace_max_impl(module, heap, item);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
-PyDoc_STRVAR(_heapq__heapify_max__doc__,
-"_heapify_max($module, heap, /)\n"
+PyDoc_STRVAR(_heapq_heapify_max__doc__,
+"heapify_max($module, heap, /)\n"
"--\n"
"\n"
"Maxheap variant of heapify.");
-#define _HEAPQ__HEAPIFY_MAX_METHODDEF \
- {"_heapify_max", (PyCFunction)_heapq__heapify_max, METH_O, _heapq__heapify_max__doc__},
+#define _HEAPQ_HEAPIFY_MAX_METHODDEF \
+ {"heapify_max", (PyCFunction)_heapq_heapify_max, METH_O, _heapq_heapify_max__doc__},
static PyObject *
-_heapq__heapify_max_impl(PyObject *module, PyObject *heap);
+_heapq_heapify_max_impl(PyObject *module, PyObject *heap);
static PyObject *
-_heapq__heapify_max(PyObject *module, PyObject *arg)
+_heapq_heapify_max(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
PyObject *heap;
if (!PyList_Check(arg)) {
- _PyArg_BadArgument("_heapify_max", "argument", "list", arg);
+ _PyArg_BadArgument("heapify_max", "argument", "list", arg);
goto exit;
}
heap = arg;
- return_value = _heapq__heapify_max_impl(module, heap);
+ Py_BEGIN_CRITICAL_SECTION(heap);
+ return_value = _heapq_heapify_max_impl(module, heap);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_heapq_heappushpop_max__doc__,
+"heappushpop_max($module, heap, item, /)\n"
+"--\n"
+"\n"
+"Maxheap variant of heappushpop.\n"
+"\n"
+"The combined action runs more efficiently than heappush_max() followed by\n"
+"a separate call to heappop_max().");
+
+#define _HEAPQ_HEAPPUSHPOP_MAX_METHODDEF \
+ {"heappushpop_max", _PyCFunction_CAST(_heapq_heappushpop_max), METH_FASTCALL, _heapq_heappushpop_max__doc__},
+
+static PyObject *
+_heapq_heappushpop_max_impl(PyObject *module, PyObject *heap, PyObject *item);
+
+static PyObject *
+_heapq_heappushpop_max(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *heap;
+ PyObject *item;
+
+ if (!_PyArg_CheckPositional("heappushpop_max", nargs, 2, 2)) {
+ goto exit;
+ }
+ if (!PyList_Check(args[0])) {
+ _PyArg_BadArgument("heappushpop_max", "argument 1", "list", args[0]);
+ goto exit;
+ }
+ heap = args[0];
+ item = args[1];
+ Py_BEGIN_CRITICAL_SECTION(heap);
+ return_value = _heapq_heappushpop_max_impl(module, heap, item);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
-/*[clinic end generated code: output=05f2afdf3bc54c9d input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e83d50002c29a96d input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h
index 2918a6bc7ab..c426cd6fe02 100644
--- a/Modules/clinic/_lsprof.c.h
+++ b/Modules/clinic/_lsprof.c.h
@@ -82,6 +82,39 @@ exit:
return return_value;
}
+PyDoc_STRVAR(_lsprof_Profiler__pythrow_callback__doc__,
+"_pythrow_callback($self, code, instruction_offset, exception, /)\n"
+"--\n"
+"\n");
+
+#define _LSPROF_PROFILER__PYTHROW_CALLBACK_METHODDEF \
+ {"_pythrow_callback", _PyCFunction_CAST(_lsprof_Profiler__pythrow_callback), METH_FASTCALL, _lsprof_Profiler__pythrow_callback__doc__},
+
+static PyObject *
+_lsprof_Profiler__pythrow_callback_impl(ProfilerObject *self, PyObject *code,
+ PyObject *instruction_offset,
+ PyObject *exception);
+
+static PyObject *
+_lsprof_Profiler__pythrow_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *code;
+ PyObject *instruction_offset;
+ PyObject *exception;
+
+ if (!_PyArg_CheckPositional("_pythrow_callback", nargs, 3, 3)) {
+ goto exit;
+ }
+ code = args[0];
+ instruction_offset = args[1];
+ exception = args[2];
+ return_value = _lsprof_Profiler__pythrow_callback_impl((ProfilerObject *)self, code, instruction_offset, exception);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(_lsprof_Profiler__pyreturn_callback__doc__,
"_pyreturn_callback($self, code, instruction_offset, retval, /)\n"
"--\n"
@@ -411,4 +444,4 @@ skip_optional_pos:
exit:
return return_value;
}
-/*[clinic end generated code: output=fe231309776df7a7 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=9e46985561166c37 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_randommodule.c.h b/Modules/clinic/_randommodule.c.h
index 1e989e970c9..2563a16aea0 100644
--- a/Modules/clinic/_randommodule.c.h
+++ b/Modules/clinic/_randommodule.c.h
@@ -3,6 +3,7 @@ preserve
[clinic start generated code]*/
#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
+#include "pycore_long.h" // _PyLong_UInt64_Converter()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(_random_Random_random__doc__,
@@ -124,16 +125,15 @@ PyDoc_STRVAR(_random_Random_getrandbits__doc__,
{"getrandbits", (PyCFunction)_random_Random_getrandbits, METH_O, _random_Random_getrandbits__doc__},
static PyObject *
-_random_Random_getrandbits_impl(RandomObject *self, int k);
+_random_Random_getrandbits_impl(RandomObject *self, uint64_t k);
static PyObject *
_random_Random_getrandbits(PyObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
- int k;
+ uint64_t k;
- k = PyLong_AsInt(arg);
- if (k == -1 && PyErr_Occurred()) {
+ if (!_PyLong_UInt64_Converter(arg, &k)) {
goto exit;
}
Py_BEGIN_CRITICAL_SECTION(self);
@@ -143,4 +143,4 @@ _random_Random_getrandbits(PyObject *self, PyObject *arg)
exit:
return return_value;
}
-/*[clinic end generated code: output=4458b5a69201ebea input=a9049054013a1b77]*/
+/*[clinic end generated code: output=7ce97b2194eecaf7 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_remote_debugging_module.c.h b/Modules/clinic/_remote_debugging_module.c.h
new file mode 100644
index 00000000000..e80b24b54c0
--- /dev/null
+++ b/Modules/clinic/_remote_debugging_module.c.h
@@ -0,0 +1,276 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+PyDoc_STRVAR(_remote_debugging_RemoteUnwinder___init____doc__,
+"RemoteUnwinder(pid, *, all_threads=False, only_active_thread=False,\n"
+" debug=False)\n"
+"--\n"
+"\n"
+"Initialize a new RemoteUnwinder object for debugging a remote Python process.\n"
+"\n"
+"Args:\n"
+" pid: Process ID of the target Python process to debug\n"
+" all_threads: If True, initialize state for all threads in the process.\n"
+" If False, only initialize for the main thread.\n"
+" only_active_thread: If True, only sample the thread holding the GIL.\n"
+" Cannot be used together with all_threads=True.\n"
+" debug: If True, chain exceptions to explain the sequence of events that\n"
+" lead to the exception.\n"
+"\n"
+"The RemoteUnwinder provides functionality to inspect and debug a running Python\n"
+"process, including examining thread states, stack frames and other runtime data.\n"
+"\n"
+"Raises:\n"
+" PermissionError: If access to the target process is denied\n"
+" OSError: If unable to attach to the target process or access its memory\n"
+" RuntimeError: If unable to read debug information from the target process\n"
+" ValueError: If both all_threads and only_active_thread are True");
+
+static int
+_remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self,
+ int pid, int all_threads,
+ int only_active_thread,
+ int debug);
+
+static int
+_remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ int return_value = -1;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 4
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(pid), &_Py_ID(all_threads), &_Py_ID(only_active_thread), &_Py_ID(debug), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"pid", "all_threads", "only_active_thread", "debug", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "RemoteUnwinder",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[4];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
+ int pid;
+ int all_threads = 0;
+ int only_active_thread = 0;
+ int debug = 0;
+
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ pid = PyLong_AsInt(fastargs[0]);
+ if (pid == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_kwonly;
+ }
+ if (fastargs[1]) {
+ all_threads = PyObject_IsTrue(fastargs[1]);
+ if (all_threads < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ if (fastargs[2]) {
+ only_active_thread = PyObject_IsTrue(fastargs[2]);
+ if (only_active_thread < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ debug = PyObject_IsTrue(fastargs[3]);
+ if (debug < 0) {
+ goto exit;
+ }
+skip_optional_kwonly:
+ return_value = _remote_debugging_RemoteUnwinder___init___impl((RemoteUnwinderObject *)self, pid, all_threads, only_active_thread, debug);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stack_trace__doc__,
+"get_stack_trace($self, /)\n"
+"--\n"
+"\n"
+"Returns a list of stack traces for threads in the target process.\n"
+"\n"
+"Each element in the returned list is a tuple of (thread_id, frame_list), where:\n"
+"- thread_id is the OS thread identifier\n"
+"- frame_list is a list of tuples (function_name, filename, line_number) representing\n"
+" the Python stack frames for that thread, ordered from most recent to oldest\n"
+"\n"
+"The threads returned depend on the initialization parameters:\n"
+"- If only_active_thread was True: returns only the thread holding the GIL\n"
+"- If all_threads was True: returns all threads\n"
+"- Otherwise: returns only the main thread\n"
+"\n"
+"Example:\n"
+" [\n"
+" (1234, [\n"
+" (\'process_data\', \'worker.py\', 127),\n"
+" (\'run_worker\', \'worker.py\', 45),\n"
+" (\'main\', \'app.py\', 23)\n"
+" ]),\n"
+" (1235, [\n"
+" (\'handle_request\', \'server.py\', 89),\n"
+" (\'serve_forever\', \'server.py\', 52)\n"
+" ])\n"
+" ]\n"
+"\n"
+"Raises:\n"
+" RuntimeError: If there is an error copying memory from the target process\n"
+" OSError: If there is an error accessing the target process\n"
+" PermissionError: If access to the target process is denied\n"
+" UnicodeDecodeError: If there is an error decoding strings from the target process");
+
+#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STACK_TRACE_METHODDEF \
+ {"get_stack_trace", (PyCFunction)_remote_debugging_RemoteUnwinder_get_stack_trace, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_stack_trace__doc__},
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self);
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_stack_trace(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _remote_debugging_RemoteUnwinder_get_stack_trace_impl((RemoteUnwinderObject *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_all_awaited_by__doc__,
+"get_all_awaited_by($self, /)\n"
+"--\n"
+"\n"
+"Get all tasks and their awaited_by relationships from the remote process.\n"
+"\n"
+"This provides a tree structure showing which tasks are waiting for other tasks.\n"
+"\n"
+"For each task, returns:\n"
+"1. The call stack frames leading to where the task is currently executing\n"
+"2. The name of the task\n"
+"3. A list of tasks that this task is waiting for, with their own frames/names/etc\n"
+"\n"
+"Returns a list of [frames, task_name, subtasks] where:\n"
+"- frames: List of (func_name, filename, lineno) showing the call stack\n"
+"- task_name: String identifier for the task\n"
+"- subtasks: List of tasks being awaited by this task, in same format\n"
+"\n"
+"Raises:\n"
+" RuntimeError: If AsyncioDebug section is not available in the remote process\n"
+" MemoryError: If memory allocation fails\n"
+" OSError: If reading from the remote process fails\n"
+"\n"
+"Example output:\n"
+"[\n"
+" [\n"
+" [(\"c5\", \"script.py\", 10), (\"c4\", \"script.py\", 14)],\n"
+" \"c2_root\",\n"
+" [\n"
+" [\n"
+" [(\"c1\", \"script.py\", 23)],\n"
+" \"sub_main_2\",\n"
+" [...]\n"
+" ],\n"
+" [...]\n"
+" ]\n"
+" ]\n"
+"]");
+
+#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ALL_AWAITED_BY_METHODDEF \
+ {"get_all_awaited_by", (PyCFunction)_remote_debugging_RemoteUnwinder_get_all_awaited_by, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_all_awaited_by__doc__},
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *self);
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_all_awaited_by(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl((RemoteUnwinderObject *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__,
+"get_async_stack_trace($self, /)\n"
+"--\n"
+"\n"
+"Returns information about the currently running async task and its stack trace.\n"
+"\n"
+"Returns a tuple of (task_info, stack_frames) where:\n"
+"- task_info is a tuple of (task_id, task_name) identifying the task\n"
+"- stack_frames is a list of tuples (function_name, filename, line_number) representing\n"
+" the Python stack frames for the task, ordered from most recent to oldest\n"
+"\n"
+"Example:\n"
+" ((4345585712, \'Task-1\'), [\n"
+" (\'run_echo_server\', \'server.py\', 127),\n"
+" (\'serve_forever\', \'server.py\', 45),\n"
+" (\'main\', \'app.py\', 23)\n"
+" ])\n"
+"\n"
+"Raises:\n"
+" RuntimeError: If AsyncioDebug section is not available in the target process\n"
+" RuntimeError: If there is an error copying memory from the target process\n"
+" OSError: If there is an error accessing the target process\n"
+" PermissionError: If access to the target process is denied\n"
+" UnicodeDecodeError: If there is an error decoding strings from the target process");
+
+#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ASYNC_STACK_TRACE_METHODDEF \
+ {"get_async_stack_trace", (PyCFunction)_remote_debugging_RemoteUnwinder_get_async_stack_trace, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__},
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject *self);
+
+static PyObject *
+_remote_debugging_RemoteUnwinder_get_async_stack_trace(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = _remote_debugging_RemoteUnwinder_get_async_stack_trace_impl((RemoteUnwinderObject *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
+}
+/*[clinic end generated code: output=a37ab223d5081b16 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_testclinic_depr.c.h b/Modules/clinic/_testclinic_depr.c.h
index a46d238801b..135197f06fd 100644
--- a/Modules/clinic/_testclinic_depr.c.h
+++ b/Modules/clinic/_testclinic_depr.c.h
@@ -19,16 +19,16 @@ PyDoc_STRVAR(depr_star_new__doc__,
"\n"
"Note: Passing positional arguments to _testclinic.DeprStarNew() is\n"
"deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
static PyObject *
depr_star_new_impl(PyTypeObject *type, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprStarNew.__new__'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprStarNew.__new__'.")
# else
@@ -77,7 +77,7 @@ depr_star_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to _testclinic.DeprStarNew() is "
"deprecated. Parameter 'a' will become a keyword-only parameter "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -104,7 +104,7 @@ PyDoc_STRVAR(depr_star_new_clone__doc__,
"\n"
"Note: Passing positional arguments to _testclinic.DeprStarNew.cloned()\n"
"is deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_STAR_NEW_CLONE_METHODDEF \
@@ -113,10 +113,10 @@ PyDoc_STRVAR(depr_star_new_clone__doc__,
static PyObject *
depr_star_new_clone_impl(PyObject *type, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprStarNew.cloned'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprStarNew.cloned'.")
# else
@@ -163,7 +163,7 @@ depr_star_new_clone(PyObject *type, PyObject *const *args, Py_ssize_t nargs, PyO
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to _testclinic.DeprStarNew.cloned()"
" is deprecated. Parameter 'a' will become a keyword-only "
- "parameter in Python 3.14.", 1))
+ "parameter in Python 3.37.", 1))
{
goto exit;
}
@@ -192,16 +192,16 @@ PyDoc_STRVAR(depr_star_init__doc__,
"\n"
"Note: Passing positional arguments to _testclinic.DeprStarInit() is\n"
"deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
static int
depr_star_init_impl(PyObject *self, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprStarInit.__init__'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprStarInit.__init__'.")
# else
@@ -250,7 +250,7 @@ depr_star_init(PyObject *self, PyObject *args, PyObject *kwargs)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to _testclinic.DeprStarInit() is "
"deprecated. Parameter 'a' will become a keyword-only parameter "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -277,7 +277,7 @@ PyDoc_STRVAR(depr_star_init_clone__doc__,
"\n"
"Note: Passing positional arguments to\n"
"_testclinic.DeprStarInit.cloned() is deprecated. Parameter \'a\' will\n"
-"become a keyword-only parameter in Python 3.14.\n"
+"become a keyword-only parameter in Python 3.37.\n"
"");
#define DEPR_STAR_INIT_CLONE_METHODDEF \
@@ -286,10 +286,10 @@ PyDoc_STRVAR(depr_star_init_clone__doc__,
static PyObject *
depr_star_init_clone_impl(PyObject *self, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprStarInit.cloned'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprStarInit.cloned'.")
# else
@@ -336,7 +336,7 @@ depr_star_init_clone(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to "
"_testclinic.DeprStarInit.cloned() is deprecated. Parameter 'a' "
- "will become a keyword-only parameter in Python 3.14.", 1))
+ "will become a keyword-only parameter in Python 3.37.", 1))
{
goto exit;
}
@@ -361,10 +361,10 @@ static int
depr_star_init_noinline_impl(PyObject *self, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprStarInitNoInline.__init__'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprStarInitNoInline.__init__'.")
# else
@@ -414,7 +414,7 @@ depr_star_init_noinline(PyObject *self, PyObject *args, PyObject *kwargs)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 1 positional argument to "
"_testclinic.DeprStarInitNoInline() is deprecated. Parameters 'b'"
- " and 'c' will become keyword-only parameters in Python 3.14.", 1))
+ " and 'c' will become keyword-only parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -436,16 +436,16 @@ PyDoc_STRVAR(depr_kwd_new__doc__,
"The deprecation message should use the class name instead of __new__.\n"
"\n"
"Note: Passing keyword argument \'a\' to _testclinic.DeprKwdNew() is\n"
-"deprecated. Parameter \'a\' will become positional-only in Python 3.14.\n"
+"deprecated. Parameter \'a\' will become positional-only in Python 3.37.\n"
"");
static PyObject *
depr_kwd_new_impl(PyTypeObject *type, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprKwdNew.__new__'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprKwdNew.__new__'.")
# else
@@ -499,7 +499,7 @@ depr_kwd_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword argument 'a' to _testclinic.DeprKwdNew() is "
"deprecated. Parameter 'a' will become positional-only in Python "
- "3.14.", 1))
+ "3.37.", 1))
{
goto exit;
}
@@ -522,16 +522,16 @@ PyDoc_STRVAR(depr_kwd_init__doc__,
"The deprecation message should use the class name instead of __init__.\n"
"\n"
"Note: Passing keyword argument \'a\' to _testclinic.DeprKwdInit() is\n"
-"deprecated. Parameter \'a\' will become positional-only in Python 3.14.\n"
+"deprecated. Parameter \'a\' will become positional-only in Python 3.37.\n"
"");
static int
depr_kwd_init_impl(PyObject *self, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprKwdInit.__init__'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprKwdInit.__init__'.")
# else
@@ -585,7 +585,7 @@ depr_kwd_init(PyObject *self, PyObject *args, PyObject *kwargs)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword argument 'a' to _testclinic.DeprKwdInit() is "
"deprecated. Parameter 'a' will become positional-only in Python "
- "3.14.", 1))
+ "3.37.", 1))
{
goto exit;
}
@@ -605,10 +605,10 @@ static int
depr_kwd_init_noinline_impl(PyObject *self, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of '_testclinic.DeprKwdInitNoInline.__init__'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of '_testclinic.DeprKwdInitNoInline.__init__'.")
# else
@@ -665,7 +665,7 @@ depr_kwd_init_noinline(PyObject *self, PyObject *args, PyObject *kwargs)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b' and 'c' to "
"_testclinic.DeprKwdInitNoInline() is deprecated. Parameters 'b' "
- "and 'c' will become positional-only in Python 3.14.", 1))
+ "and 'c' will become positional-only in Python 3.37.", 1))
{
goto exit;
}
@@ -682,7 +682,7 @@ PyDoc_STRVAR(depr_star_pos0_len1__doc__,
"\n"
"Note: Passing positional arguments to depr_star_pos0_len1() is\n"
"deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_STAR_POS0_LEN1_METHODDEF \
@@ -691,10 +691,10 @@ PyDoc_STRVAR(depr_star_pos0_len1__doc__,
static PyObject *
depr_star_pos0_len1_impl(PyObject *module, PyObject *a);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos0_len1'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos0_len1'.")
# else
@@ -740,7 +740,7 @@ depr_star_pos0_len1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to depr_star_pos0_len1() is "
"deprecated. Parameter 'a' will become a keyword-only parameter "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -763,7 +763,7 @@ PyDoc_STRVAR(depr_star_pos0_len2__doc__,
"\n"
"Note: Passing positional arguments to depr_star_pos0_len2() is\n"
"deprecated. Parameters \'a\' and \'b\' will become keyword-only parameters\n"
-"in Python 3.14.\n"
+"in Python 3.37.\n"
"");
#define DEPR_STAR_POS0_LEN2_METHODDEF \
@@ -772,10 +772,10 @@ PyDoc_STRVAR(depr_star_pos0_len2__doc__,
static PyObject *
depr_star_pos0_len2_impl(PyObject *module, PyObject *a, PyObject *b);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos0_len2'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos0_len2'.")
# else
@@ -822,7 +822,7 @@ depr_star_pos0_len2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to depr_star_pos0_len2() is "
"deprecated. Parameters 'a' and 'b' will become keyword-only "
- "parameters in Python 3.14.", 1))
+ "parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -846,7 +846,7 @@ PyDoc_STRVAR(depr_star_pos0_len3_with_kwd__doc__,
"\n"
"Note: Passing positional arguments to depr_star_pos0_len3_with_kwd()\n"
"is deprecated. Parameters \'a\', \'b\' and \'c\' will become keyword-only\n"
-"parameters in Python 3.14.\n"
+"parameters in Python 3.37.\n"
"");
#define DEPR_STAR_POS0_LEN3_WITH_KWD_METHODDEF \
@@ -856,10 +856,10 @@ static PyObject *
depr_star_pos0_len3_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos0_len3_with_kwd'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos0_len3_with_kwd'.")
# else
@@ -908,7 +908,7 @@ depr_star_pos0_len3_with_kwd(PyObject *module, PyObject *const *args, Py_ssize_t
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing positional arguments to depr_star_pos0_len3_with_kwd() "
"is deprecated. Parameters 'a', 'b' and 'c' will become "
- "keyword-only parameters in Python 3.14.", 1))
+ "keyword-only parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -934,7 +934,7 @@ PyDoc_STRVAR(depr_star_pos1_len1_opt__doc__,
"\n"
"Note: Passing 2 positional arguments to depr_star_pos1_len1_opt() is\n"
"deprecated. Parameter \'b\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_STAR_POS1_LEN1_OPT_METHODDEF \
@@ -943,10 +943,10 @@ PyDoc_STRVAR(depr_star_pos1_len1_opt__doc__,
static PyObject *
depr_star_pos1_len1_opt_impl(PyObject *module, PyObject *a, PyObject *b);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos1_len1_opt'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos1_len1_opt'.")
# else
@@ -994,7 +994,7 @@ depr_star_pos1_len1_opt(PyObject *module, PyObject *const *args, Py_ssize_t narg
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing 2 positional arguments to depr_star_pos1_len1_opt() is "
"deprecated. Parameter 'b' will become a keyword-only parameter "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -1022,7 +1022,7 @@ PyDoc_STRVAR(depr_star_pos1_len1__doc__,
"\n"
"Note: Passing 2 positional arguments to depr_star_pos1_len1() is\n"
"deprecated. Parameter \'b\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_STAR_POS1_LEN1_METHODDEF \
@@ -1031,10 +1031,10 @@ PyDoc_STRVAR(depr_star_pos1_len1__doc__,
static PyObject *
depr_star_pos1_len1_impl(PyObject *module, PyObject *a, PyObject *b);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos1_len1'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos1_len1'.")
# else
@@ -1081,7 +1081,7 @@ depr_star_pos1_len1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing 2 positional arguments to depr_star_pos1_len1() is "
"deprecated. Parameter 'b' will become a keyword-only parameter "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -1105,7 +1105,7 @@ PyDoc_STRVAR(depr_star_pos1_len2_with_kwd__doc__,
"\n"
"Note: Passing more than 1 positional argument to\n"
"depr_star_pos1_len2_with_kwd() is deprecated. Parameters \'b\' and \'c\'\n"
-"will become keyword-only parameters in Python 3.14.\n"
+"will become keyword-only parameters in Python 3.37.\n"
"");
#define DEPR_STAR_POS1_LEN2_WITH_KWD_METHODDEF \
@@ -1115,10 +1115,10 @@ static PyObject *
depr_star_pos1_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos1_len2_with_kwd'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos1_len2_with_kwd'.")
# else
@@ -1167,7 +1167,7 @@ depr_star_pos1_len2_with_kwd(PyObject *module, PyObject *const *args, Py_ssize_t
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 1 positional argument to "
"depr_star_pos1_len2_with_kwd() is deprecated. Parameters 'b' and"
- " 'c' will become keyword-only parameters in Python 3.14.", 1))
+ " 'c' will become keyword-only parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -1193,7 +1193,7 @@ PyDoc_STRVAR(depr_star_pos2_len1__doc__,
"\n"
"Note: Passing 3 positional arguments to depr_star_pos2_len1() is\n"
"deprecated. Parameter \'c\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_STAR_POS2_LEN1_METHODDEF \
@@ -1203,10 +1203,10 @@ static PyObject *
depr_star_pos2_len1_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos2_len1'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos2_len1'.")
# else
@@ -1254,7 +1254,7 @@ depr_star_pos2_len1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing 3 positional arguments to depr_star_pos2_len1() is "
"deprecated. Parameter 'c' will become a keyword-only parameter "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -1279,7 +1279,7 @@ PyDoc_STRVAR(depr_star_pos2_len2__doc__,
"\n"
"Note: Passing more than 2 positional arguments to\n"
"depr_star_pos2_len2() is deprecated. Parameters \'c\' and \'d\' will\n"
-"become keyword-only parameters in Python 3.14.\n"
+"become keyword-only parameters in Python 3.37.\n"
"");
#define DEPR_STAR_POS2_LEN2_METHODDEF \
@@ -1289,10 +1289,10 @@ static PyObject *
depr_star_pos2_len2_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos2_len2'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos2_len2'.")
# else
@@ -1341,7 +1341,7 @@ depr_star_pos2_len2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 2 positional arguments to "
"depr_star_pos2_len2() is deprecated. Parameters 'c' and 'd' will"
- " become keyword-only parameters in Python 3.14.", 1))
+ " become keyword-only parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -1367,7 +1367,7 @@ PyDoc_STRVAR(depr_star_pos2_len2_with_kwd__doc__,
"\n"
"Note: Passing more than 2 positional arguments to\n"
"depr_star_pos2_len2_with_kwd() is deprecated. Parameters \'c\' and \'d\'\n"
-"will become keyword-only parameters in Python 3.14.\n"
+"will become keyword-only parameters in Python 3.37.\n"
"");
#define DEPR_STAR_POS2_LEN2_WITH_KWD_METHODDEF \
@@ -1377,10 +1377,10 @@ static PyObject *
depr_star_pos2_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, PyObject *d, PyObject *e);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_pos2_len2_with_kwd'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_pos2_len2_with_kwd'.")
# else
@@ -1430,7 +1430,7 @@ depr_star_pos2_len2_with_kwd(PyObject *module, PyObject *const *args, Py_ssize_t
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 2 positional arguments to "
"depr_star_pos2_len2_with_kwd() is deprecated. Parameters 'c' and"
- " 'd' will become keyword-only parameters in Python 3.14.", 1))
+ " 'd' will become keyword-only parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -1457,7 +1457,7 @@ PyDoc_STRVAR(depr_star_noinline__doc__,
"\n"
"Note: Passing more than 1 positional argument to depr_star_noinline()\n"
"is deprecated. Parameters \'b\' and \'c\' will become keyword-only\n"
-"parameters in Python 3.14.\n"
+"parameters in Python 3.37.\n"
"");
#define DEPR_STAR_NOINLINE_METHODDEF \
@@ -1467,10 +1467,10 @@ static PyObject *
depr_star_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_noinline'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_noinline'.")
# else
@@ -1519,7 +1519,7 @@ depr_star_noinline(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 1 positional argument to depr_star_noinline() "
"is deprecated. Parameters 'b' and 'c' will become keyword-only "
- "parameters in Python 3.14.", 1))
+ "parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -1540,9 +1540,9 @@ PyDoc_STRVAR(depr_star_multi__doc__,
"\n"
"Note: Passing more than 1 positional argument to depr_star_multi() is\n"
"deprecated. Parameter \'b\' will become a keyword-only parameter in\n"
-"Python 3.16. Parameters \'c\' and \'d\' will become keyword-only\n"
-"parameters in Python 3.15. Parameters \'e\', \'f\' and \'g\' will become\n"
-"keyword-only parameters in Python 3.14.\n"
+"Python 3.39. Parameters \'c\' and \'d\' will become keyword-only\n"
+"parameters in Python 3.38. Parameters \'e\', \'f\' and \'g\' will become\n"
+"keyword-only parameters in Python 3.37.\n"
"");
#define DEPR_STAR_MULTI_METHODDEF \
@@ -1553,10 +1553,10 @@ depr_star_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
PyObject *d, PyObject *e, PyObject *f, PyObject *g,
PyObject *h);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_star_multi'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_star_multi'.")
# else
@@ -1609,9 +1609,9 @@ depr_star_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 1 positional argument to depr_star_multi() is "
"deprecated. Parameter 'b' will become a keyword-only parameter "
- "in Python 3.16. Parameters 'c' and 'd' will become keyword-only "
- "parameters in Python 3.15. Parameters 'e', 'f' and 'g' will "
- "become keyword-only parameters in Python 3.14.", 1))
+ "in Python 3.39. Parameters 'c' and 'd' will become keyword-only "
+ "parameters in Python 3.38. Parameters 'e', 'f' and 'g' will "
+ "become keyword-only parameters in Python 3.37.", 1))
{
goto exit;
}
@@ -1640,7 +1640,7 @@ PyDoc_STRVAR(depr_kwd_required_1__doc__,
"--\n"
"\n"
"Note: Passing keyword argument \'b\' to depr_kwd_required_1() is\n"
-"deprecated. Parameter \'b\' will become positional-only in Python 3.14.\n"
+"deprecated. Parameter \'b\' will become positional-only in Python 3.37.\n"
"");
#define DEPR_KWD_REQUIRED_1_METHODDEF \
@@ -1649,10 +1649,10 @@ PyDoc_STRVAR(depr_kwd_required_1__doc__,
static PyObject *
depr_kwd_required_1_impl(PyObject *module, PyObject *a, PyObject *b);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_required_1'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_required_1'.")
# else
@@ -1704,7 +1704,7 @@ depr_kwd_required_1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword argument 'b' to depr_kwd_required_1() is "
"deprecated. Parameter 'b' will become positional-only in Python "
- "3.14.", 1))
+ "3.37.", 1))
{
goto exit;
}
@@ -1723,7 +1723,7 @@ PyDoc_STRVAR(depr_kwd_required_2__doc__,
"\n"
"Note: Passing keyword arguments \'b\' and \'c\' to depr_kwd_required_2()\n"
"is deprecated. Parameters \'b\' and \'c\' will become positional-only in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_KWD_REQUIRED_2_METHODDEF \
@@ -1733,10 +1733,10 @@ static PyObject *
depr_kwd_required_2_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_required_2'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_required_2'.")
# else
@@ -1789,7 +1789,7 @@ depr_kwd_required_2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b' and 'c' to depr_kwd_required_2() "
"is deprecated. Parameters 'b' and 'c' will become "
- "positional-only in Python 3.14.", 1))
+ "positional-only in Python 3.37.", 1))
{
goto exit;
}
@@ -1808,7 +1808,7 @@ PyDoc_STRVAR(depr_kwd_optional_1__doc__,
"--\n"
"\n"
"Note: Passing keyword argument \'b\' to depr_kwd_optional_1() is\n"
-"deprecated. Parameter \'b\' will become positional-only in Python 3.14.\n"
+"deprecated. Parameter \'b\' will become positional-only in Python 3.37.\n"
"");
#define DEPR_KWD_OPTIONAL_1_METHODDEF \
@@ -1817,10 +1817,10 @@ PyDoc_STRVAR(depr_kwd_optional_1__doc__,
static PyObject *
depr_kwd_optional_1_impl(PyObject *module, PyObject *a, PyObject *b);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_optional_1'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_optional_1'.")
# else
@@ -1873,7 +1873,7 @@ depr_kwd_optional_1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword argument 'b' to depr_kwd_optional_1() is "
"deprecated. Parameter 'b' will become positional-only in Python "
- "3.14.", 1))
+ "3.37.", 1))
{
goto exit;
}
@@ -1896,7 +1896,7 @@ PyDoc_STRVAR(depr_kwd_optional_2__doc__,
"\n"
"Note: Passing keyword arguments \'b\' and \'c\' to depr_kwd_optional_2()\n"
"is deprecated. Parameters \'b\' and \'c\' will become positional-only in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_KWD_OPTIONAL_2_METHODDEF \
@@ -1906,10 +1906,10 @@ static PyObject *
depr_kwd_optional_2_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_optional_2'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_optional_2'.")
# else
@@ -1963,7 +1963,7 @@ depr_kwd_optional_2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b' and 'c' to depr_kwd_optional_2() "
"is deprecated. Parameters 'b' and 'c' will become "
- "positional-only in Python 3.14.", 1))
+ "positional-only in Python 3.37.", 1))
{
goto exit;
}
@@ -1992,7 +1992,7 @@ PyDoc_STRVAR(depr_kwd_optional_3__doc__,
"\n"
"Note: Passing keyword arguments \'a\', \'b\' and \'c\' to\n"
"depr_kwd_optional_3() is deprecated. Parameters \'a\', \'b\' and \'c\' will\n"
-"become positional-only in Python 3.14.\n"
+"become positional-only in Python 3.37.\n"
"");
#define DEPR_KWD_OPTIONAL_3_METHODDEF \
@@ -2002,10 +2002,10 @@ static PyObject *
depr_kwd_optional_3_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_optional_3'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_optional_3'.")
# else
@@ -2059,7 +2059,7 @@ depr_kwd_optional_3(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'a', 'b' and 'c' to "
"depr_kwd_optional_3() is deprecated. Parameters 'a', 'b' and 'c'"
- " will become positional-only in Python 3.14.", 1))
+ " will become positional-only in Python 3.37.", 1))
{
goto exit;
}
@@ -2093,7 +2093,7 @@ PyDoc_STRVAR(depr_kwd_required_optional__doc__,
"\n"
"Note: Passing keyword arguments \'b\' and \'c\' to\n"
"depr_kwd_required_optional() is deprecated. Parameters \'b\' and \'c\'\n"
-"will become positional-only in Python 3.14.\n"
+"will become positional-only in Python 3.37.\n"
"");
#define DEPR_KWD_REQUIRED_OPTIONAL_METHODDEF \
@@ -2103,10 +2103,10 @@ static PyObject *
depr_kwd_required_optional_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_required_optional'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_required_optional'.")
# else
@@ -2160,7 +2160,7 @@ depr_kwd_required_optional(PyObject *module, PyObject *const *args, Py_ssize_t n
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b' and 'c' to "
"depr_kwd_required_optional() is deprecated. Parameters 'b' and "
- "'c' will become positional-only in Python 3.14.", 1))
+ "'c' will become positional-only in Python 3.37.", 1))
{
goto exit;
}
@@ -2184,7 +2184,7 @@ PyDoc_STRVAR(depr_kwd_noinline__doc__,
"\n"
"Note: Passing keyword arguments \'b\' and \'c\' to depr_kwd_noinline() is\n"
"deprecated. Parameters \'b\' and \'c\' will become positional-only in\n"
-"Python 3.14.\n"
+"Python 3.37.\n"
"");
#define DEPR_KWD_NOINLINE_METHODDEF \
@@ -2194,10 +2194,10 @@ static PyObject *
depr_kwd_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c, const char *d, Py_ssize_t d_length);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_noinline'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_noinline'.")
# else
@@ -2253,7 +2253,7 @@ depr_kwd_noinline(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b' and 'c' to depr_kwd_noinline() is "
"deprecated. Parameters 'b' and 'c' will become positional-only "
- "in Python 3.14.", 1))
+ "in Python 3.37.", 1))
{
goto exit;
}
@@ -2270,9 +2270,9 @@ PyDoc_STRVAR(depr_kwd_multi__doc__,
"\n"
"Note: Passing keyword arguments \'b\', \'c\', \'d\', \'e\', \'f\' and \'g\' to\n"
"depr_kwd_multi() is deprecated. Parameter \'b\' will become positional-\n"
-"only in Python 3.14. Parameters \'c\' and \'d\' will become positional-\n"
-"only in Python 3.15. Parameters \'e\', \'f\' and \'g\' will become\n"
-"positional-only in Python 3.16.\n"
+"only in Python 3.37. Parameters \'c\' and \'d\' will become positional-\n"
+"only in Python 3.38. Parameters \'e\', \'f\' and \'g\' will become\n"
+"positional-only in Python 3.39.\n"
"");
#define DEPR_KWD_MULTI_METHODDEF \
@@ -2283,10 +2283,10 @@ depr_kwd_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
PyObject *d, PyObject *e, PyObject *f, PyObject *g,
PyObject *h);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_kwd_multi'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_kwd_multi'.")
# else
@@ -2344,9 +2344,9 @@ depr_kwd_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b', 'c', 'd', 'e', 'f' and 'g' to "
"depr_kwd_multi() is deprecated. Parameter 'b' will become "
- "positional-only in Python 3.14. Parameters 'c' and 'd' will "
- "become positional-only in Python 3.15. Parameters 'e', 'f' and "
- "'g' will become positional-only in Python 3.16.", 1))
+ "positional-only in Python 3.37. Parameters 'c' and 'd' will "
+ "become positional-only in Python 3.38. Parameters 'e', 'f' and "
+ "'g' will become positional-only in Python 3.39.", 1))
{
goto exit;
}
@@ -2370,14 +2370,14 @@ PyDoc_STRVAR(depr_multi__doc__,
"--\n"
"\n"
"Note: Passing keyword arguments \'b\' and \'c\' to depr_multi() is\n"
-"deprecated. Parameter \'b\' will become positional-only in Python 3.14.\n"
-"Parameter \'c\' will become positional-only in Python 3.15.\n"
+"deprecated. Parameter \'b\' will become positional-only in Python 3.37.\n"
+"Parameter \'c\' will become positional-only in Python 3.38.\n"
"\n"
"\n"
"Note: Passing more than 4 positional arguments to depr_multi() is\n"
"deprecated. Parameter \'e\' will become a keyword-only parameter in\n"
-"Python 3.15. Parameter \'f\' will become a keyword-only parameter in\n"
-"Python 3.14.\n"
+"Python 3.38. Parameter \'f\' will become a keyword-only parameter in\n"
+"Python 3.37.\n"
"");
#define DEPR_MULTI_METHODDEF \
@@ -2387,10 +2387,10 @@ static PyObject *
depr_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
PyObject *d, PyObject *e, PyObject *f, PyObject *g);
-// Emit compiler warnings when we get to Python 3.14.
-#if PY_VERSION_HEX >= 0x030e00C0
+// Emit compiler warnings when we get to Python 3.37.
+#if PY_VERSION_HEX >= 0x032500C0
# error "Update the clinic input of 'depr_multi'."
-#elif PY_VERSION_HEX >= 0x030e00A0
+#elif PY_VERSION_HEX >= 0x032500A0
# ifdef _MSC_VER
# pragma message ("Update the clinic input of 'depr_multi'.")
# else
@@ -2442,8 +2442,8 @@ depr_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing more than 4 positional arguments to depr_multi() is "
"deprecated. Parameter 'e' will become a keyword-only parameter "
- "in Python 3.15. Parameter 'f' will become a keyword-only "
- "parameter in Python 3.14.", 1))
+ "in Python 3.38. Parameter 'f' will become a keyword-only "
+ "parameter in Python 3.37.", 1))
{
goto exit;
}
@@ -2457,7 +2457,7 @@ depr_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Passing keyword arguments 'b' and 'c' to depr_multi() is "
"deprecated. Parameter 'b' will become positional-only in Python "
- "3.14. Parameter 'c' will become positional-only in Python 3.15.", 1))
+ "3.37. Parameter 'c' will become positional-only in Python 3.38.", 1))
{
goto exit;
}
@@ -2474,4 +2474,4 @@ depr_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
exit:
return return_value;
}
-/*[clinic end generated code: output=4e60af44fd6b7b94 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=517bb49913bafc4a input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_threadmodule.c.h b/Modules/clinic/_threadmodule.c.h
index 8930e54170c..fd8e32a2261 100644
--- a/Modules/clinic/_threadmodule.c.h
+++ b/Modules/clinic/_threadmodule.c.h
@@ -6,7 +6,53 @@ preserve
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
-#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+#include "pycore_modsupport.h" // _PyArg_NoKeywords()
+
+static PyObject *
+lock_new_impl(PyTypeObject *type);
+
+static PyObject *
+lock_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ PyTypeObject *base_tp = clinic_state()->lock_type;
+
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoPositional("lock", args)) {
+ goto exit;
+ }
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoKeywords("lock", kwargs)) {
+ goto exit;
+ }
+ return_value = lock_new_impl(type);
+
+exit:
+ return return_value;
+}
+
+static PyObject *
+rlock_new_impl(PyTypeObject *type);
+
+static PyObject *
+rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ PyTypeObject *base_tp = clinic_state()->rlock_type;
+
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoPositional("RLock", args)) {
+ goto exit;
+ }
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoKeywords("RLock", kwargs)) {
+ goto exit;
+ }
+ return_value = rlock_new_impl(type);
+
+exit:
+ return return_value;
+}
#if (defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP) || defined(MS_WINDOWS))
@@ -103,4 +149,4 @@ exit:
#ifndef _THREAD_SET_NAME_METHODDEF
#define _THREAD_SET_NAME_METHODDEF
#endif /* !defined(_THREAD_SET_NAME_METHODDEF) */
-/*[clinic end generated code: output=e978dc4615b9bc35 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=b381ec5e313198e7 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h
index f8b623fca08..bd685e75d93 100644
--- a/Modules/clinic/_winapi.c.h
+++ b/Modules/clinic/_winapi.c.h
@@ -857,6 +857,8 @@ exit:
return return_value;
}
+#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM))
+
PyDoc_STRVAR(_winapi_GetShortPathName__doc__,
"GetShortPathName($module, /, path)\n"
"--\n"
@@ -930,6 +932,8 @@ exit:
return return_value;
}
+#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */
+
PyDoc_STRVAR(_winapi_GetStdHandle__doc__,
"GetStdHandle($module, std_handle, /)\n"
"--\n"
@@ -1929,6 +1933,24 @@ _winapi_GetACP(PyObject *module, PyObject *Py_UNUSED(ignored))
return _winapi_GetACP_impl(module);
}
+PyDoc_STRVAR(_winapi_GetOEMCP__doc__,
+"GetOEMCP($module, /)\n"
+"--\n"
+"\n"
+"Get the current Windows ANSI code page identifier.");
+
+#define _WINAPI_GETOEMCP_METHODDEF \
+ {"GetOEMCP", (PyCFunction)_winapi_GetOEMCP, METH_NOARGS, _winapi_GetOEMCP__doc__},
+
+static PyObject *
+_winapi_GetOEMCP_impl(PyObject *module);
+
+static PyObject *
+_winapi_GetOEMCP(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return _winapi_GetOEMCP_impl(module);
+}
+
PyDoc_STRVAR(_winapi_GetFileType__doc__,
"GetFileType($module, /, handle)\n"
"--\n"
@@ -2161,4 +2183,8 @@ exit:
return return_value;
}
-/*[clinic end generated code: output=6cd07628af447d0a input=a9049054013a1b77]*/
+
+#ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF
+ #define _WINAPI_GETSHORTPATHNAME_METHODDEF
+#endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */
+/*[clinic end generated code: output=4581fd481c3c6293 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/blake2module.c.h b/Modules/clinic/blake2module.c.h
index bb2e308574a..97d010d03a4 100644
--- a/Modules/clinic/blake2module.c.h
+++ b/Modules/clinic/blake2module.c.h
@@ -10,20 +10,21 @@ preserve
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(py_blake2b_new__doc__,
-"blake2b(data=b\'\', /, *, digest_size=_blake2.blake2b.MAX_DIGEST_SIZE,\n"
+"blake2b(data=b\'\', *, digest_size=_blake2.blake2b.MAX_DIGEST_SIZE,\n"
" key=b\'\', salt=b\'\', person=b\'\', fanout=1, depth=1, leaf_size=0,\n"
" node_offset=0, node_depth=0, inner_size=0, last_node=False,\n"
-" usedforsecurity=True)\n"
+" usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new BLAKE2b hash object.");
static PyObject *
-py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
+py_blake2b_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size,
Py_buffer *key, Py_buffer *salt, Py_buffer *person,
int fanout, int depth, unsigned long leaf_size,
unsigned long long node_offset, int node_depth,
- int inner_size, int last_node, int usedforsecurity);
+ int inner_size, int last_node, int usedforsecurity,
+ PyObject *string);
static PyObject *
py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@@ -31,7 +32,7 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 12
+ #define NUM_KEYWORDS 14
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -40,7 +41,7 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(digest_size), &_Py_ID(key), &_Py_ID(salt), &_Py_ID(person), &_Py_ID(fanout), &_Py_ID(depth), &_Py_ID(leaf_size), &_Py_ID(node_offset), &_Py_ID(node_depth), &_Py_ID(inner_size), &_Py_ID(last_node), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(digest_size), &_Py_ID(key), &_Py_ID(salt), &_Py_ID(person), &_Py_ID(fanout), &_Py_ID(depth), &_Py_ID(leaf_size), &_Py_ID(node_offset), &_Py_ID(node_depth), &_Py_ID(inner_size), &_Py_ID(last_node), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -49,18 +50,18 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "blake2b",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[13];
+ PyObject *argsbuf[14];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0;
- PyObject *data = NULL;
+ PyObject *data_obj = NULL;
int digest_size = HACL_HASH_BLAKE2B_OUT_BYTES;
Py_buffer key = {NULL, NULL};
Py_buffer salt = {NULL, NULL};
@@ -73,18 +74,23 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
int inner_size = 0;
int last_node = 0;
int usedforsecurity = 1;
+ PyObject *string = NULL;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!fastargs) {
goto exit;
}
- if (nargs < 1) {
- goto skip_optional_posonly;
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ if (fastargs[0]) {
+ data_obj = fastargs[0];
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
}
- noptargs--;
- data = fastargs[0];
-skip_optional_posonly:
+skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
@@ -182,12 +188,18 @@ skip_optional_posonly:
goto skip_optional_kwonly;
}
}
- usedforsecurity = PyObject_IsTrue(fastargs[12]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (fastargs[12]) {
+ usedforsecurity = PyObject_IsTrue(fastargs[12]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = fastargs[13];
skip_optional_kwonly:
- return_value = py_blake2b_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity);
+ return_value = py_blake2b_new_impl(type, data_obj, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity, string);
exit:
/* Cleanup for key */
@@ -207,20 +219,21 @@ exit:
}
PyDoc_STRVAR(py_blake2s_new__doc__,
-"blake2s(data=b\'\', /, *, digest_size=_blake2.blake2s.MAX_DIGEST_SIZE,\n"
+"blake2s(data=b\'\', *, digest_size=_blake2.blake2s.MAX_DIGEST_SIZE,\n"
" key=b\'\', salt=b\'\', person=b\'\', fanout=1, depth=1, leaf_size=0,\n"
" node_offset=0, node_depth=0, inner_size=0, last_node=False,\n"
-" usedforsecurity=True)\n"
+" usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new BLAKE2s hash object.");
static PyObject *
-py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
+py_blake2s_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size,
Py_buffer *key, Py_buffer *salt, Py_buffer *person,
int fanout, int depth, unsigned long leaf_size,
unsigned long long node_offset, int node_depth,
- int inner_size, int last_node, int usedforsecurity);
+ int inner_size, int last_node, int usedforsecurity,
+ PyObject *string);
static PyObject *
py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@@ -228,7 +241,7 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 12
+ #define NUM_KEYWORDS 14
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -237,7 +250,7 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(digest_size), &_Py_ID(key), &_Py_ID(salt), &_Py_ID(person), &_Py_ID(fanout), &_Py_ID(depth), &_Py_ID(leaf_size), &_Py_ID(node_offset), &_Py_ID(node_depth), &_Py_ID(inner_size), &_Py_ID(last_node), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(digest_size), &_Py_ID(key), &_Py_ID(salt), &_Py_ID(person), &_Py_ID(fanout), &_Py_ID(depth), &_Py_ID(leaf_size), &_Py_ID(node_offset), &_Py_ID(node_depth), &_Py_ID(inner_size), &_Py_ID(last_node), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -246,18 +259,18 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "blake2s",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[13];
+ PyObject *argsbuf[14];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0;
- PyObject *data = NULL;
+ PyObject *data_obj = NULL;
int digest_size = HACL_HASH_BLAKE2S_OUT_BYTES;
Py_buffer key = {NULL, NULL};
Py_buffer salt = {NULL, NULL};
@@ -270,18 +283,23 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
int inner_size = 0;
int last_node = 0;
int usedforsecurity = 1;
+ PyObject *string = NULL;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!fastargs) {
goto exit;
}
- if (nargs < 1) {
- goto skip_optional_posonly;
+ if (!noptargs) {
+ goto skip_optional_pos;
}
- noptargs--;
- data = fastargs[0];
-skip_optional_posonly:
+ if (fastargs[0]) {
+ data_obj = fastargs[0];
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
+ }
+skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
@@ -379,12 +397,18 @@ skip_optional_posonly:
goto skip_optional_kwonly;
}
}
- usedforsecurity = PyObject_IsTrue(fastargs[12]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (fastargs[12]) {
+ usedforsecurity = PyObject_IsTrue(fastargs[12]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = fastargs[13];
skip_optional_kwonly:
- return_value = py_blake2s_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity);
+ return_value = py_blake2s_new_impl(type, data_obj, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity, string);
exit:
/* Cleanup for key */
@@ -410,15 +434,19 @@ PyDoc_STRVAR(_blake2_blake2b_copy__doc__,
"Return a copy of the hash object.");
#define _BLAKE2_BLAKE2B_COPY_METHODDEF \
- {"copy", (PyCFunction)_blake2_blake2b_copy, METH_NOARGS, _blake2_blake2b_copy__doc__},
+ {"copy", _PyCFunction_CAST(_blake2_blake2b_copy), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _blake2_blake2b_copy__doc__},
static PyObject *
-_blake2_blake2b_copy_impl(Blake2Object *self);
+_blake2_blake2b_copy_impl(Blake2Object *self, PyTypeObject *cls);
static PyObject *
-_blake2_blake2b_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2b_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
- return _blake2_blake2b_copy_impl((Blake2Object *)self);
+ if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
+ PyErr_SetString(PyExc_TypeError, "copy() takes no arguments");
+ return NULL;
+ }
+ return _blake2_blake2b_copy_impl((Blake2Object *)self, cls);
}
PyDoc_STRVAR(_blake2_blake2b_update__doc__,
@@ -478,4 +506,4 @@ _blake2_blake2b_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored))
{
return _blake2_blake2b_hexdigest_impl((Blake2Object *)self);
}
-/*[clinic end generated code: output=d30e8293bd8e2950 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=60a4abbcb8950fe5 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h
index 4c2c8acd8f6..a443c48faaa 100644
--- a/Modules/clinic/mathmodule.c.h
+++ b/Modules/clinic/mathmodule.c.h
@@ -84,6 +84,40 @@ PyDoc_STRVAR(math_floor__doc__,
#define MATH_FLOOR_METHODDEF \
{"floor", (PyCFunction)math_floor, METH_O, math_floor__doc__},
+PyDoc_STRVAR(math_signbit__doc__,
+"signbit($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if the sign of x is negative and False otherwise.");
+
+#define MATH_SIGNBIT_METHODDEF \
+ {"signbit", (PyCFunction)math_signbit, METH_O, math_signbit__doc__},
+
+static PyObject *
+math_signbit_impl(PyObject *module, double x);
+
+static PyObject *
+math_signbit(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_signbit_impl(module, x);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(math_fsum__doc__,
"fsum($module, seq, /)\n"
"--\n"
@@ -108,9 +142,7 @@ PyDoc_STRVAR(math_factorial__doc__,
"factorial($module, n, /)\n"
"--\n"
"\n"
-"Find n!.\n"
-"\n"
-"Raise a ValueError if x is negative or non-integral.");
+"Find n!.");
#define MATH_FACTORIAL_METHODDEF \
{"factorial", (PyCFunction)math_factorial, METH_O, math_factorial__doc__},
@@ -630,6 +662,74 @@ exit:
return return_value;
}
+PyDoc_STRVAR(math_isnormal__doc__,
+"isnormal($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if x is normal, and False otherwise.");
+
+#define MATH_ISNORMAL_METHODDEF \
+ {"isnormal", (PyCFunction)math_isnormal, METH_O, math_isnormal__doc__},
+
+static PyObject *
+math_isnormal_impl(PyObject *module, double x);
+
+static PyObject *
+math_isnormal(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_isnormal_impl(module, x);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(math_issubnormal__doc__,
+"issubnormal($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if x is subnormal, and False otherwise.");
+
+#define MATH_ISSUBNORMAL_METHODDEF \
+ {"issubnormal", (PyCFunction)math_issubnormal, METH_O, math_issubnormal__doc__},
+
+static PyObject *
+math_issubnormal_impl(PyObject *module, double x);
+
+static PyObject *
+math_issubnormal(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_issubnormal_impl(module, x);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(math_isnan__doc__,
"isnan($module, x, /)\n"
"--\n"
@@ -1112,4 +1212,4 @@ math_ulp(PyObject *module, PyObject *arg)
exit:
return return_value;
}
-/*[clinic end generated code: output=634773bd18cd3f93 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=4e3fa94d026f027b input=a9049054013a1b77]*/
diff --git a/Modules/clinic/md5module.c.h b/Modules/clinic/md5module.c.h
index 9ca4f6528ce..f76902586dd 100644
--- a/Modules/clinic/md5module.c.h
+++ b/Modules/clinic/md5module.c.h
@@ -89,7 +89,7 @@ MD5Type_update(PyObject *self, PyObject *obj)
}
PyDoc_STRVAR(_md5_md5__doc__,
-"md5($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"md5($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new MD5 hash object; optionally initialized with a string.");
@@ -98,7 +98,8 @@ PyDoc_STRVAR(_md5_md5__doc__,
{"md5", _PyCFunction_CAST(_md5_md5), METH_FASTCALL|METH_KEYWORDS, _md5_md5__doc__},
static PyObject *
-_md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity);
+_md5_md5_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj);
static PyObject *
_md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -106,7 +107,7 @@ _md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -115,7 +116,7 @@ _md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -124,17 +125,18 @@ _md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "md5",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *string = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string_obj = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -145,7 +147,7 @@ _md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw
goto skip_optional_pos;
}
if (args[0]) {
- string = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -154,14 +156,20 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string_obj = args[2];
skip_optional_kwonly:
- return_value = _md5_md5_impl(module, string, usedforsecurity);
+ return_value = _md5_md5_impl(module, data, usedforsecurity, string_obj);
exit:
return return_value;
}
-/*[clinic end generated code: output=73f4d2034d9fcc63 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=920fe54b9ed06f92 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 0125e247ee4..3621a062541 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -1471,7 +1471,7 @@ os_getcwdb(PyObject *module, PyObject *Py_UNUSED(ignored))
PyDoc_STRVAR(os_link__doc__,
"link($module, /, src, dst, *, src_dir_fd=None, dst_dir_fd=None,\n"
-" follow_symlinks=True)\n"
+" follow_symlinks=(os.name != \'nt\'))\n"
"--\n"
"\n"
"Create a hard link to a file.\n"
@@ -1530,7 +1530,7 @@ os_link(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn
path_t dst = PATH_T_INITIALIZE_P("link", "dst", 0, 0, 0, 0);
int src_dir_fd = DEFAULT_DIR_FD;
int dst_dir_fd = DEFAULT_DIR_FD;
- int follow_symlinks = 1;
+ int follow_symlinks = -1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -1659,7 +1659,7 @@ exit:
return return_value;
}
-#if defined(MS_WINDOWS)
+#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM))
PyDoc_STRVAR(os_listdrives__doc__,
"listdrives($module, /)\n"
@@ -1681,9 +1681,9 @@ os_listdrives(PyObject *module, PyObject *Py_UNUSED(ignored))
return os_listdrives_impl(module);
}
-#endif /* defined(MS_WINDOWS) */
+#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */
-#if defined(MS_WINDOWS)
+#if (defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM))
PyDoc_STRVAR(os_listvolumes__doc__,
"listvolumes($module, /)\n"
@@ -1705,9 +1705,9 @@ os_listvolumes(PyObject *module, PyObject *Py_UNUSED(ignored))
return os_listvolumes_impl(module);
}
-#endif /* defined(MS_WINDOWS) */
+#endif /* (defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) */
-#if defined(MS_WINDOWS)
+#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM))
PyDoc_STRVAR(os_listmounts__doc__,
"listmounts($module, /, volume)\n"
@@ -1774,7 +1774,7 @@ exit:
return return_value;
}
-#endif /* defined(MS_WINDOWS) */
+#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */
#if defined(MS_WINDOWS)
@@ -13398,4 +13398,4 @@ os__emscripten_debugger(PyObject *module, PyObject *Py_UNUSED(ignored))
#ifndef OS__EMSCRIPTEN_DEBUGGER_METHODDEF
#define OS__EMSCRIPTEN_DEBUGGER_METHODDEF
#endif /* !defined(OS__EMSCRIPTEN_DEBUGGER_METHODDEF) */
-/*[clinic end generated code: output=a5ca2541f2af5462 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=ae64df0389746258 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/sha1module.c.h b/Modules/clinic/sha1module.c.h
index 3e5fd1a41ce..4a58d0cd9b8 100644
--- a/Modules/clinic/sha1module.c.h
+++ b/Modules/clinic/sha1module.c.h
@@ -89,7 +89,7 @@ SHA1Type_update(PyObject *self, PyObject *obj)
}
PyDoc_STRVAR(_sha1_sha1__doc__,
-"sha1($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"sha1($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new SHA1 hash object; optionally initialized with a string.");
@@ -98,7 +98,8 @@ PyDoc_STRVAR(_sha1_sha1__doc__,
{"sha1", _PyCFunction_CAST(_sha1_sha1), METH_FASTCALL|METH_KEYWORDS, _sha1_sha1__doc__},
static PyObject *
-_sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity);
+_sha1_sha1_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj);
static PyObject *
_sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -106,7 +107,7 @@ _sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -115,7 +116,7 @@ _sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -124,17 +125,18 @@ _sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "sha1",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *string = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string_obj = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -145,7 +147,7 @@ _sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
goto skip_optional_pos;
}
if (args[0]) {
- string = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -154,14 +156,20 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string_obj = args[2];
skip_optional_kwonly:
- return_value = _sha1_sha1_impl(module, string, usedforsecurity);
+ return_value = _sha1_sha1_impl(module, data, usedforsecurity, string_obj);
exit:
return return_value;
}
-/*[clinic end generated code: output=06161e87e2d645d4 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=fd5a917404b68c4f input=a9049054013a1b77]*/
diff --git a/Modules/clinic/sha2module.c.h b/Modules/clinic/sha2module.c.h
index 26612125e75..07be91e4f6c 100644
--- a/Modules/clinic/sha2module.c.h
+++ b/Modules/clinic/sha2module.c.h
@@ -169,7 +169,7 @@ SHA512Type_update(PyObject *self, PyObject *obj)
}
PyDoc_STRVAR(_sha2_sha256__doc__,
-"sha256($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"sha256($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new SHA-256 hash object; optionally initialized with a string.");
@@ -178,7 +178,8 @@ PyDoc_STRVAR(_sha2_sha256__doc__,
{"sha256", _PyCFunction_CAST(_sha2_sha256), METH_FASTCALL|METH_KEYWORDS, _sha2_sha256__doc__},
static PyObject *
-_sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity);
+_sha2_sha256_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj);
static PyObject *
_sha2_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -186,7 +187,7 @@ _sha2_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -195,7 +196,7 @@ _sha2_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -204,17 +205,18 @@ _sha2_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "sha256",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *string = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string_obj = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -225,7 +227,7 @@ _sha2_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
goto skip_optional_pos;
}
if (args[0]) {
- string = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -234,19 +236,25 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string_obj = args[2];
skip_optional_kwonly:
- return_value = _sha2_sha256_impl(module, string, usedforsecurity);
+ return_value = _sha2_sha256_impl(module, data, usedforsecurity, string_obj);
exit:
return return_value;
}
PyDoc_STRVAR(_sha2_sha224__doc__,
-"sha224($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"sha224($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new SHA-224 hash object; optionally initialized with a string.");
@@ -255,7 +263,8 @@ PyDoc_STRVAR(_sha2_sha224__doc__,
{"sha224", _PyCFunction_CAST(_sha2_sha224), METH_FASTCALL|METH_KEYWORDS, _sha2_sha224__doc__},
static PyObject *
-_sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity);
+_sha2_sha224_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj);
static PyObject *
_sha2_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -263,7 +272,7 @@ _sha2_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -272,7 +281,7 @@ _sha2_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -281,17 +290,18 @@ _sha2_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "sha224",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *string = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string_obj = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -302,7 +312,7 @@ _sha2_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
goto skip_optional_pos;
}
if (args[0]) {
- string = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -311,19 +321,25 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string_obj = args[2];
skip_optional_kwonly:
- return_value = _sha2_sha224_impl(module, string, usedforsecurity);
+ return_value = _sha2_sha224_impl(module, data, usedforsecurity, string_obj);
exit:
return return_value;
}
PyDoc_STRVAR(_sha2_sha512__doc__,
-"sha512($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"sha512($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new SHA-512 hash object; optionally initialized with a string.");
@@ -332,7 +348,8 @@ PyDoc_STRVAR(_sha2_sha512__doc__,
{"sha512", _PyCFunction_CAST(_sha2_sha512), METH_FASTCALL|METH_KEYWORDS, _sha2_sha512__doc__},
static PyObject *
-_sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity);
+_sha2_sha512_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj);
static PyObject *
_sha2_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -340,7 +357,7 @@ _sha2_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -349,7 +366,7 @@ _sha2_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -358,17 +375,18 @@ _sha2_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "sha512",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *string = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string_obj = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -379,7 +397,7 @@ _sha2_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
goto skip_optional_pos;
}
if (args[0]) {
- string = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -388,19 +406,25 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string_obj = args[2];
skip_optional_kwonly:
- return_value = _sha2_sha512_impl(module, string, usedforsecurity);
+ return_value = _sha2_sha512_impl(module, data, usedforsecurity, string_obj);
exit:
return return_value;
}
PyDoc_STRVAR(_sha2_sha384__doc__,
-"sha384($module, /, string=b\'\', *, usedforsecurity=True)\n"
+"sha384($module, /, data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new SHA-384 hash object; optionally initialized with a string.");
@@ -409,7 +433,8 @@ PyDoc_STRVAR(_sha2_sha384__doc__,
{"sha384", _PyCFunction_CAST(_sha2_sha384), METH_FASTCALL|METH_KEYWORDS, _sha2_sha384__doc__},
static PyObject *
-_sha2_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity);
+_sha2_sha384_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj);
static PyObject *
_sha2_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -417,7 +442,7 @@ _sha2_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -426,7 +451,7 @@ _sha2_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -435,17 +460,18 @@ _sha2_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "sha384",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
- PyObject *string = NULL;
+ PyObject *data = NULL;
int usedforsecurity = 1;
+ PyObject *string_obj = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -456,7 +482,7 @@ _sha2_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
goto skip_optional_pos;
}
if (args[0]) {
- string = args[0];
+ data = args[0];
if (!--noptargs) {
goto skip_optional_pos;
}
@@ -465,14 +491,20 @@ skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(args[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (args[1]) {
+ usedforsecurity = PyObject_IsTrue(args[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string_obj = args[2];
skip_optional_kwonly:
- return_value = _sha2_sha384_impl(module, string, usedforsecurity);
+ return_value = _sha2_sha384_impl(module, data, usedforsecurity, string_obj);
exit:
return return_value;
}
-/*[clinic end generated code: output=af11090855b7c85a input=a9049054013a1b77]*/
+/*[clinic end generated code: output=90625b237c774a9f input=a9049054013a1b77]*/
diff --git a/Modules/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h
index 25f72b74f80..1f631ff406e 100644
--- a/Modules/clinic/sha3module.c.h
+++ b/Modules/clinic/sha3module.c.h
@@ -6,17 +6,18 @@ preserve
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
-#include "pycore_long.h" // _PyLong_UnsignedLong_Converter()
+#include "pycore_abstract.h" // _PyNumber_Index()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(py_sha3_new__doc__,
-"sha3_224(data=b\'\', /, *, usedforsecurity=True)\n"
+"sha3_224(data=b\'\', *, usedforsecurity=True, string=None)\n"
"--\n"
"\n"
"Return a new SHA3 hash object.");
static PyObject *
-py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity);
+py_sha3_new_impl(PyTypeObject *type, PyObject *data_obj, int usedforsecurity,
+ PyObject *string);
static PyObject *
py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@@ -24,7 +25,7 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 1
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -33,7 +34,7 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(usedforsecurity), },
+ .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -42,40 +43,51 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "usedforsecurity", NULL};
+ static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "sha3_224",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[2];
+ PyObject *argsbuf[3];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0;
- PyObject *data = NULL;
+ PyObject *data_obj = NULL;
int usedforsecurity = 1;
+ PyObject *string = NULL;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
/*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!fastargs) {
goto exit;
}
- if (nargs < 1) {
- goto skip_optional_posonly;
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ if (fastargs[0]) {
+ data_obj = fastargs[0];
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
}
- noptargs--;
- data = fastargs[0];
-skip_optional_posonly:
+skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
- usedforsecurity = PyObject_IsTrue(fastargs[1]);
- if (usedforsecurity < 0) {
- goto exit;
+ if (fastargs[1]) {
+ usedforsecurity = PyObject_IsTrue(fastargs[1]);
+ if (usedforsecurity < 0) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
}
+ string = fastargs[2];
skip_optional_kwonly:
- return_value = py_sha3_new_impl(type, data, usedforsecurity);
+ return_value = py_sha3_new_impl(type, data_obj, usedforsecurity, string);
exit:
return return_value;
@@ -88,15 +100,19 @@ PyDoc_STRVAR(_sha3_sha3_224_copy__doc__,
"Return a copy of the hash object.");
#define _SHA3_SHA3_224_COPY_METHODDEF \
- {"copy", (PyCFunction)_sha3_sha3_224_copy, METH_NOARGS, _sha3_sha3_224_copy__doc__},
+ {"copy", _PyCFunction_CAST(_sha3_sha3_224_copy), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _sha3_sha3_224_copy__doc__},
static PyObject *
-_sha3_sha3_224_copy_impl(SHA3object *self);
+_sha3_sha3_224_copy_impl(SHA3object *self, PyTypeObject *cls);
static PyObject *
-_sha3_sha3_224_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
+_sha3_sha3_224_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
- return _sha3_sha3_224_copy_impl((SHA3object *)self);
+ if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
+ PyErr_SetString(PyExc_TypeError, "copy() takes no arguments");
+ return NULL;
+ }
+ return _sha3_sha3_224_copy_impl((SHA3object *)self, cls);
}
PyDoc_STRVAR(_sha3_sha3_224_digest__doc__,
@@ -158,26 +174,68 @@ _sha3_sha3_224_update(PyObject *self, PyObject *data)
}
PyDoc_STRVAR(_sha3_shake_128_digest__doc__,
-"digest($self, length, /)\n"
+"digest($self, /, length)\n"
"--\n"
"\n"
"Return the digest value as a bytes object.");
#define _SHA3_SHAKE_128_DIGEST_METHODDEF \
- {"digest", (PyCFunction)_sha3_shake_128_digest, METH_O, _sha3_shake_128_digest__doc__},
+ {"digest", _PyCFunction_CAST(_sha3_shake_128_digest), METH_FASTCALL|METH_KEYWORDS, _sha3_shake_128_digest__doc__},
static PyObject *
-_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length);
+_sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length);
static PyObject *
-_sha3_shake_128_digest(PyObject *self, PyObject *arg)
+_sha3_shake_128_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
- unsigned long length;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(length), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
- if (!_PyLong_UnsignedLong_Converter(arg, &length)) {
+ static const char * const _keywords[] = {"length", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "digest",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ Py_ssize_t length;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
goto exit;
}
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[0]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ length = ival;
+ }
return_value = _sha3_shake_128_digest_impl((SHA3object *)self, length);
exit:
@@ -185,29 +243,71 @@ exit:
}
PyDoc_STRVAR(_sha3_shake_128_hexdigest__doc__,
-"hexdigest($self, length, /)\n"
+"hexdigest($self, /, length)\n"
"--\n"
"\n"
"Return the digest value as a string of hexadecimal digits.");
#define _SHA3_SHAKE_128_HEXDIGEST_METHODDEF \
- {"hexdigest", (PyCFunction)_sha3_shake_128_hexdigest, METH_O, _sha3_shake_128_hexdigest__doc__},
+ {"hexdigest", _PyCFunction_CAST(_sha3_shake_128_hexdigest), METH_FASTCALL|METH_KEYWORDS, _sha3_shake_128_hexdigest__doc__},
static PyObject *
-_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length);
+_sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length);
static PyObject *
-_sha3_shake_128_hexdigest(PyObject *self, PyObject *arg)
+_sha3_shake_128_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
- unsigned long length;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- if (!_PyLong_UnsignedLong_Converter(arg, &length)) {
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(length), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"length", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "hexdigest",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ Py_ssize_t length;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
goto exit;
}
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[0]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ length = ival;
+ }
return_value = _sha3_shake_128_hexdigest_impl((SHA3object *)self, length);
exit:
return return_value;
}
-/*[clinic end generated code: output=5b3ac1c06c6899ea input=a9049054013a1b77]*/
+/*[clinic end generated code: output=48be77f8a31e8a3e input=a9049054013a1b77]*/
diff --git a/Modules/clinic/socketmodule.c.h b/Modules/clinic/socketmodule.c.h
index 70ebbaa876b..0cedab597db 100644
--- a/Modules/clinic/socketmodule.c.h
+++ b/Modules/clinic/socketmodule.c.h
@@ -6,7 +6,8 @@ preserve
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
-#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+#include "pycore_long.h" // _PyLong_UInt16_Converter()
+#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(_socket_socket_close__doc__,
"close($self, /)\n"
@@ -28,6 +29,170 @@ _socket_socket_close(PyObject *s, PyObject *Py_UNUSED(ignored))
return _socket_socket_close_impl((PySocketSockObject *)s);
}
+PyDoc_STRVAR(_socket_socket_send__doc__,
+"send($self, data, flags=0, /)\n"
+"--\n"
+"\n"
+"Send a data string to the socket.\n"
+"\n"
+"For the optional flags argument, see the Unix manual.\n"
+"Return the number of bytes sent; this may be less than len(data) if the network is busy.");
+
+#define _SOCKET_SOCKET_SEND_METHODDEF \
+ {"send", _PyCFunction_CAST(_socket_socket_send), METH_FASTCALL, _socket_socket_send__doc__},
+
+static PyObject *
+_socket_socket_send_impl(PySocketSockObject *s, Py_buffer *pbuf, int flags);
+
+static PyObject *
+_socket_socket_send(PyObject *s, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ Py_buffer pbuf = {NULL, NULL};
+ int flags = 0;
+
+ if (!_PyArg_CheckPositional("send", nargs, 1, 2)) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &pbuf, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ if (nargs < 2) {
+ goto skip_optional;
+ }
+ flags = PyLong_AsInt(args[1]);
+ if (flags == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional:
+ return_value = _socket_socket_send_impl((PySocketSockObject *)s, &pbuf, flags);
+
+exit:
+ /* Cleanup for pbuf */
+ if (pbuf.obj) {
+ PyBuffer_Release(&pbuf);
+ }
+
+ return return_value;
+}
+
+PyDoc_STRVAR(_socket_socket_sendall__doc__,
+"sendall($self, data, flags=0, /)\n"
+"--\n"
+"\n"
+"Send a data string to the socket.\n"
+"\n"
+"For the optional flags argument, see the Unix manual.\n"
+"This calls send() repeatedly until all data is sent.\n"
+"If an error occurs, it\'s impossible to tell how much data has been sent.");
+
+#define _SOCKET_SOCKET_SENDALL_METHODDEF \
+ {"sendall", _PyCFunction_CAST(_socket_socket_sendall), METH_FASTCALL, _socket_socket_sendall__doc__},
+
+static PyObject *
+_socket_socket_sendall_impl(PySocketSockObject *s, Py_buffer *pbuf,
+ int flags);
+
+static PyObject *
+_socket_socket_sendall(PyObject *s, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ Py_buffer pbuf = {NULL, NULL};
+ int flags = 0;
+
+ if (!_PyArg_CheckPositional("sendall", nargs, 1, 2)) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &pbuf, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ if (nargs < 2) {
+ goto skip_optional;
+ }
+ flags = PyLong_AsInt(args[1]);
+ if (flags == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional:
+ return_value = _socket_socket_sendall_impl((PySocketSockObject *)s, &pbuf, flags);
+
+exit:
+ /* Cleanup for pbuf */
+ if (pbuf.obj) {
+ PyBuffer_Release(&pbuf);
+ }
+
+ return return_value;
+}
+
+#if defined(CMSG_LEN)
+
+PyDoc_STRVAR(_socket_socket_sendmsg__doc__,
+"sendmsg($self, buffers, ancdata=<unrepresentable>, flags=0,\n"
+" address=<unrepresentable>, /)\n"
+"--\n"
+"\n"
+"Send normal and ancillary data to the socket.\n"
+"\n"
+"It gathering the non-ancillary data from a series of buffers\n"
+"and concatenating it into a single message.\n"
+"The buffers argument specifies the non-ancillary\n"
+"data as an iterable of bytes-like objects (e.g. bytes objects).\n"
+"The ancdata argument specifies the ancillary data (control messages)\n"
+"as an iterable of zero or more tuples (cmsg_level, cmsg_type,\n"
+"cmsg_data), where cmsg_level and cmsg_type are integers specifying the\n"
+"protocol level and protocol-specific type respectively, and cmsg_data\n"
+"is a bytes-like object holding the associated data. The flags\n"
+"argument defaults to 0 and has the same meaning as for send(). If\n"
+"address is supplied and not None, it sets a destination address for\n"
+"the message. The return value is the number of bytes of non-ancillary\n"
+"data sent.");
+
+#define _SOCKET_SOCKET_SENDMSG_METHODDEF \
+ {"sendmsg", _PyCFunction_CAST(_socket_socket_sendmsg), METH_FASTCALL, _socket_socket_sendmsg__doc__},
+
+static PyObject *
+_socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg,
+ PyObject *cmsg_arg, int flags,
+ PyObject *addr_arg);
+
+static PyObject *
+_socket_socket_sendmsg(PyObject *s, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *data_arg;
+ PyObject *cmsg_arg = NULL;
+ int flags = 0;
+ PyObject *addr_arg = NULL;
+
+ if (!_PyArg_CheckPositional("sendmsg", nargs, 1, 4)) {
+ goto exit;
+ }
+ data_arg = args[0];
+ if (nargs < 2) {
+ goto skip_optional;
+ }
+ cmsg_arg = args[1];
+ if (nargs < 3) {
+ goto skip_optional;
+ }
+ flags = PyLong_AsInt(args[2]);
+ if (flags == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ if (nargs < 4) {
+ goto skip_optional;
+ }
+ addr_arg = args[3];
+skip_optional:
+ return_value = _socket_socket_sendmsg_impl((PySocketSockObject *)s, data_arg, cmsg_arg, flags, addr_arg);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(CMSG_LEN) */
+
static int
sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
PyObject *fdobj);
@@ -358,6 +523,10 @@ exit:
#endif /* (defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS)) */
+#ifndef _SOCKET_SOCKET_SENDMSG_METHODDEF
+ #define _SOCKET_SOCKET_SENDMSG_METHODDEF
+#endif /* !defined(_SOCKET_SOCKET_SENDMSG_METHODDEF) */
+
#ifndef _SOCKET_INET_NTOA_METHODDEF
#define _SOCKET_INET_NTOA_METHODDEF
#endif /* !defined(_SOCKET_INET_NTOA_METHODDEF) */
@@ -369,4 +538,4 @@ exit:
#ifndef _SOCKET_IF_INDEXTONAME_METHODDEF
#define _SOCKET_IF_INDEXTONAME_METHODDEF
#endif /* !defined(_SOCKET_IF_INDEXTONAME_METHODDEF) */
-/*[clinic end generated code: output=c971b79d2193b426 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=0376c46b76ae2bce input=a9049054013a1b77]*/
diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h
index 2710f65a840..146a7e25001 100644
--- a/Modules/clinic/zlibmodule.c.h
+++ b/Modules/clinic/zlibmodule.c.h
@@ -1044,6 +1044,65 @@ exit:
return return_value;
}
+PyDoc_STRVAR(zlib_adler32_combine__doc__,
+"adler32_combine($module, adler1, adler2, len2, /)\n"
+"--\n"
+"\n"
+"Combine two Adler-32 checksums into one.\n"
+"\n"
+" adler1\n"
+" Adler-32 checksum for sequence A\n"
+" adler2\n"
+" Adler-32 checksum for sequence B\n"
+" len2\n"
+" Length of sequence B\n"
+"\n"
+"Given the Adler-32 checksum \'adler1\' of a sequence A and the\n"
+"Adler-32 checksum \'adler2\' of a sequence B of length \'len2\',\n"
+"return the Adler-32 checksum of A and B concatenated.");
+
+#define ZLIB_ADLER32_COMBINE_METHODDEF \
+ {"adler32_combine", _PyCFunction_CAST(zlib_adler32_combine), METH_FASTCALL, zlib_adler32_combine__doc__},
+
+static unsigned int
+zlib_adler32_combine_impl(PyObject *module, unsigned int adler1,
+ unsigned int adler2, PyObject *len2);
+
+static PyObject *
+zlib_adler32_combine(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ unsigned int adler1;
+ unsigned int adler2;
+ PyObject *len2;
+ unsigned int _return_value;
+
+ if (!_PyArg_CheckPositional("adler32_combine", nargs, 3, 3)) {
+ goto exit;
+ }
+ adler1 = (unsigned int)PyLong_AsUnsignedLongMask(args[0]);
+ if (adler1 == (unsigned int)-1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ adler2 = (unsigned int)PyLong_AsUnsignedLongMask(args[1]);
+ if (adler2 == (unsigned int)-1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ if (!PyLong_Check(args[2])) {
+ _PyArg_BadArgument("adler32_combine", "argument 3", "int", args[2]);
+ goto exit;
+ }
+ len2 = args[2];
+ _return_value = zlib_adler32_combine_impl(module, adler1, adler2, len2);
+ if ((_return_value == (unsigned int)-1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromUnsignedLong((unsigned long)_return_value);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(zlib_crc32__doc__,
"crc32($module, data, value=0, /)\n"
"--\n"
@@ -1098,6 +1157,65 @@ exit:
return return_value;
}
+PyDoc_STRVAR(zlib_crc32_combine__doc__,
+"crc32_combine($module, crc1, crc2, len2, /)\n"
+"--\n"
+"\n"
+"Combine two CRC-32 checksums into one.\n"
+"\n"
+" crc1\n"
+" CRC-32 checksum for sequence A\n"
+" crc2\n"
+" CRC-32 checksum for sequence B\n"
+" len2\n"
+" Length of sequence B\n"
+"\n"
+"Given the CRC-32 checksum \'crc1\' of a sequence A and the\n"
+"CRC-32 checksum \'crc2\' of a sequence B of length \'len2\',\n"
+"return the CRC-32 checksum of A and B concatenated.");
+
+#define ZLIB_CRC32_COMBINE_METHODDEF \
+ {"crc32_combine", _PyCFunction_CAST(zlib_crc32_combine), METH_FASTCALL, zlib_crc32_combine__doc__},
+
+static unsigned int
+zlib_crc32_combine_impl(PyObject *module, unsigned int crc1,
+ unsigned int crc2, PyObject *len2);
+
+static PyObject *
+zlib_crc32_combine(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ unsigned int crc1;
+ unsigned int crc2;
+ PyObject *len2;
+ unsigned int _return_value;
+
+ if (!_PyArg_CheckPositional("crc32_combine", nargs, 3, 3)) {
+ goto exit;
+ }
+ crc1 = (unsigned int)PyLong_AsUnsignedLongMask(args[0]);
+ if (crc1 == (unsigned int)-1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ crc2 = (unsigned int)PyLong_AsUnsignedLongMask(args[1]);
+ if (crc2 == (unsigned int)-1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ if (!PyLong_Check(args[2])) {
+ _PyArg_BadArgument("crc32_combine", "argument 3", "int", args[2]);
+ goto exit;
+ }
+ len2 = args[2];
+ _return_value = zlib_crc32_combine_impl(module, crc1, crc2, len2);
+ if ((_return_value == (unsigned int)-1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromUnsignedLong((unsigned long)_return_value);
+
+exit:
+ return return_value;
+}
+
#ifndef ZLIB_COMPRESS_COPY_METHODDEF
#define ZLIB_COMPRESS_COPY_METHODDEF
#endif /* !defined(ZLIB_COMPRESS_COPY_METHODDEF) */
@@ -1121,4 +1239,4 @@ exit:
#ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF
#define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF
#endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */
-/*[clinic end generated code: output=33938c7613a8c1c7 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=3f7692eb3b5d5a0c input=a9049054013a1b77]*/
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index d49ce794d88..73bea8172c7 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -6,7 +6,6 @@
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_runtime.h" // _Py_ID()
#include "pycore_signal.h" // Py_NSIG
-#include "pycore_sysmodule.h" // _PySys_GetRequiredAttr()
#include "pycore_time.h" // _PyTime_FromSecondsObject()
#include "pycore_traceback.h" // _Py_DumpTracebackThreads
#ifdef HAVE_UNISTD_H
@@ -98,7 +97,7 @@ faulthandler_get_fileno(PyObject **file_ptr)
PyObject *file = *file_ptr;
if (file == NULL || file == Py_None) {
- file = _PySys_GetRequiredAttr(&_Py_ID(stderr));
+ file = PySys_GetAttr(&_Py_ID(stderr));
if (file == NULL) {
return -1;
}
@@ -1069,18 +1068,6 @@ faulthandler_suppress_crash_report(void)
#endif
}
-static PyObject* _Py_NO_SANITIZE_UNDEFINED
-faulthandler_read_null(PyObject *self, PyObject *args)
-{
- volatile int *x;
- volatile int y;
-
- faulthandler_suppress_crash_report();
- x = NULL;
- y = *x;
- return PyLong_FromLong(y);
-
-}
static void
faulthandler_raise_sigsegv(void)
@@ -1158,23 +1145,12 @@ faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject* _Py_NO_SANITIZE_UNDEFINED
+static PyObject*
faulthandler_sigfpe(PyObject *self, PyObject *Py_UNUSED(dummy))
{
faulthandler_suppress_crash_report();
-
- /* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
- PowerPC. Use volatile to disable compile-time optimizations. */
- volatile int x = 1, y = 0, z;
- z = x / y;
-
- /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
- raise it manually. */
raise(SIGFPE);
-
- /* This line is never reached, but we pretend to make something with z
- to silence a compiler warning. */
- return PyLong_FromLong(z);
+ Py_UNREACHABLE();
}
static PyObject *
@@ -1316,10 +1292,6 @@ static PyMethodDef module_methods[] = {
"Unregister the handler of the signal "
"'signum' registered by register().")},
#endif
- {"_read_null", faulthandler_read_null, METH_NOARGS,
- PyDoc_STR("_read_null($module, /)\n--\n\n"
- "Read from NULL, raise "
- "a SIGSEGV or SIGBUS signal depending on the platform.")},
{"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
PyDoc_STR("_sigsegv($module, release_gil=False, /)\n--\n\n"
"Raise a SIGSEGV signal.")},
diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c
index 220ee9ecdff..90363b9dca3 100644
--- a/Modules/fcntlmodule.c
+++ b/Modules/fcntlmodule.c
@@ -93,29 +93,54 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
return NULL;
}
Py_ssize_t len = view.len;
- if (len > FCNTL_BUFSZ) {
- PyErr_SetString(PyExc_ValueError,
- "fcntl argument 3 is too long");
+ if (len <= FCNTL_BUFSZ) {
+ memcpy(buf, view.buf, len);
+ memcpy(buf + len, guard, GUARDSZ);
PyBuffer_Release(&view);
- return NULL;
- }
- memcpy(buf, view.buf, len);
- memcpy(buf + len, guard, GUARDSZ);
- PyBuffer_Release(&view);
- do {
- Py_BEGIN_ALLOW_THREADS
- ret = fcntl(fd, code, buf);
- Py_END_ALLOW_THREADS
- } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
- if (ret < 0) {
- return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcntl(fd, code, buf);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (ret < 0) {
+ return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
+ }
+ if (memcmp(buf + len, guard, GUARDSZ) != 0) {
+ PyErr_SetString(PyExc_SystemError, "buffer overflow");
+ return NULL;
+ }
+ return PyBytes_FromStringAndSize(buf, len);
}
- if (memcmp(buf + len, guard, GUARDSZ) != 0) {
- PyErr_SetString(PyExc_SystemError, "buffer overflow");
- return NULL;
+ else {
+ PyObject *result = PyBytes_FromStringAndSize(NULL, len);
+ if (result == NULL) {
+ PyBuffer_Release(&view);
+ return NULL;
+ }
+ char *ptr = PyBytes_AsString(result);
+ memcpy(ptr, view.buf, len);
+ PyBuffer_Release(&view);
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcntl(fd, code, ptr);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (ret < 0) {
+ if (!async_err) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ }
+ Py_DECREF(result);
+ return NULL;
+ }
+ if (ptr[len] != '\0') {
+ PyErr_SetString(PyExc_SystemError, "buffer overflow");
+ Py_DECREF(result);
+ return NULL;
+ }
+ return result;
}
- return PyBytes_FromStringAndSize(buf, len);
#undef FCNTL_BUFSZ
}
PyErr_Format(PyExc_TypeError,
@@ -251,29 +276,54 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
return NULL;
}
Py_ssize_t len = view.len;
- if (len > IOCTL_BUFSZ) {
- PyErr_SetString(PyExc_ValueError,
- "ioctl argument 3 is too long");
+ if (len <= IOCTL_BUFSZ) {
+ memcpy(buf, view.buf, len);
+ memcpy(buf + len, guard, GUARDSZ);
PyBuffer_Release(&view);
- return NULL;
- }
- memcpy(buf, view.buf, len);
- memcpy(buf + len, guard, GUARDSZ);
- PyBuffer_Release(&view);
- do {
- Py_BEGIN_ALLOW_THREADS
- ret = ioctl(fd, code, buf);
- Py_END_ALLOW_THREADS
- } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
- if (ret < 0) {
- return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = ioctl(fd, code, buf);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (ret < 0) {
+ return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
+ }
+ if (memcmp(buf + len, guard, GUARDSZ) != 0) {
+ PyErr_SetString(PyExc_SystemError, "buffer overflow");
+ return NULL;
+ }
+ return PyBytes_FromStringAndSize(buf, len);
}
- if (memcmp(buf + len, guard, GUARDSZ) != 0) {
- PyErr_SetString(PyExc_SystemError, "buffer overflow");
- return NULL;
+ else {
+ PyObject *result = PyBytes_FromStringAndSize(NULL, len);
+ if (result == NULL) {
+ PyBuffer_Release(&view);
+ return NULL;
+ }
+ char *ptr = PyBytes_AsString(result);
+ memcpy(ptr, view.buf, len);
+ PyBuffer_Release(&view);
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = ioctl(fd, code, ptr);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (ret < 0) {
+ if (!async_err) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ }
+ Py_DECREF(result);
+ return NULL;
+ }
+ if (ptr[len] != '\0') {
+ PyErr_SetString(PyExc_SystemError, "buffer overflow");
+ Py_DECREF(result);
+ return NULL;
+ }
+ return result;
}
- return PyBytes_FromStringAndSize(buf, len);
#undef IOCTL_BUFSZ
}
PyErr_Format(PyExc_TypeError,
diff --git a/Modules/hashlib.h b/Modules/hashlib.h
index 7105e68af7b..9a7e72f34a7 100644
--- a/Modules/hashlib.h
+++ b/Modules/hashlib.h
@@ -34,45 +34,114 @@
/*
* Helper code to synchronize access to the hash object when the GIL is
- * released around a CPU consuming hashlib operation. All code paths that
- * access a mutable part of obj must be enclosed in an ENTER_HASHLIB /
- * LEAVE_HASHLIB block or explicitly acquire and release the lock inside
- * a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for
- * an operation.
+ * released around a CPU consuming hashlib operation.
*
- * These only drop the GIL if the lock acquisition itself is likely to
- * block. Thus the non-blocking acquire gating the GIL release for a
- * blocking lock acquisition. The intent of these macros is to surround
- * the assumed always "fast" operations that you aren't releasing the
- * GIL around. Otherwise use code similar to what you see in hash
- * function update() methods.
+ * Code accessing a mutable part of the hash object must be enclosed in
+ * an HASHLIB_{ACQUIRE,RELEASE}_LOCK block or explicitly acquire and release
+ * the mutex inside a Py_BEGIN_ALLOW_THREADS -- Py_END_ALLOW_THREADS block if
+ * they wish to release the GIL for an operation.
*/
-#include "pythread.h"
-#define ENTER_HASHLIB(obj) \
- if ((obj)->use_mutex) { \
- PyMutex_Lock(&(obj)->mutex); \
- }
-#define LEAVE_HASHLIB(obj) \
- if ((obj)->use_mutex) { \
- PyMutex_Unlock(&(obj)->mutex); \
- }
+#define HASHLIB_OBJECT_HEAD \
+ PyObject_HEAD \
+ /* Guard against race conditions during incremental update(). */ \
+ PyMutex mutex;
-#ifdef Py_GIL_DISABLED
-#define HASHLIB_INIT_MUTEX(obj) \
- do { \
- (obj)->mutex = (PyMutex){0}; \
- (obj)->use_mutex = true; \
+#define HASHLIB_INIT_MUTEX(OBJ) \
+ do { \
+ (OBJ)->mutex = (PyMutex){0}; \
} while (0)
-#else
-#define HASHLIB_INIT_MUTEX(obj) \
- do { \
- (obj)->mutex = (PyMutex){0}; \
- (obj)->use_mutex = false; \
+
+#define HASHLIB_ACQUIRE_LOCK(OBJ) PyMutex_Lock(&(OBJ)->mutex)
+#define HASHLIB_RELEASE_LOCK(OBJ) PyMutex_Unlock(&(OBJ)->mutex)
+
+/*
+ * Message length above which the GIL is to be released
+ * when performing hashing operations.
+ */
+#define HASHLIB_GIL_MINSIZE 2048
+
+// Macros for executing code while conditionally holding the GIL.
+//
+// These only drop the GIL if the lock acquisition itself is likely to
+// block. Thus the non-blocking acquire gating the GIL release for a
+// blocking lock acquisition. The intent of these macros is to surround
+// the assumed always "fast" operations that you aren't releasing the
+// GIL around.
+
+/*
+ * Execute a suite of C statements 'STATEMENTS'.
+ *
+ * The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold.
+ */
+#define HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(SIZE, STATEMENTS) \
+ do { \
+ if ((SIZE) > HASHLIB_GIL_MINSIZE) { \
+ Py_BEGIN_ALLOW_THREADS \
+ STATEMENTS; \
+ Py_END_ALLOW_THREADS \
+ } \
+ else { \
+ STATEMENTS; \
+ } \
} while (0)
-#endif
-/* TODO(gpshead): We should make this a module or class attribute
- * to allow the user to optimize based on the platform they're using. */
-#define HASHLIB_GIL_MINSIZE 2048
+/*
+ * Lock 'OBJ' and execute a suite of C statements 'STATEMENTS'.
+ *
+ * The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold.
+ */
+#define HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(OBJ, SIZE, STATEMENTS) \
+ do { \
+ if ((SIZE) > HASHLIB_GIL_MINSIZE) { \
+ Py_BEGIN_ALLOW_THREADS \
+ HASHLIB_ACQUIRE_LOCK(OBJ); \
+ STATEMENTS; \
+ HASHLIB_RELEASE_LOCK(OBJ); \
+ Py_END_ALLOW_THREADS \
+ } \
+ else { \
+ HASHLIB_ACQUIRE_LOCK(OBJ); \
+ STATEMENTS; \
+ HASHLIB_RELEASE_LOCK(OBJ); \
+ } \
+ } while (0)
+static inline int
+_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)
+{
+ if (data != NULL && string == NULL) {
+ // called as H(data) or H(data=...)
+ *res = data;
+ return 1;
+ }
+ else if (data == NULL && string != NULL) {
+ // called as H(string=...)
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "the 'string' keyword parameter is deprecated since "
+ "Python 3.15 and slated for removal in Python 3.19; "
+ "use the 'data' keyword parameter or pass the data "
+ "to hash as a positional argument instead", 1) < 0)
+ {
+ *res = NULL;
+ return -1;
+ }
+ *res = string;
+ return 1;
+ }
+ else if (data == NULL && string == NULL) {
+ // fast path when no data is given
+ assert(!PyErr_Occurred());
+ *res = NULL;
+ return 0;
+ }
+ else {
+ // called as H(data=..., string)
+ *res = NULL;
+ PyErr_SetString(PyExc_TypeError,
+ "'data' and 'string' are mutually exclusive "
+ "and support for 'string' keyword parameter "
+ "is slated for removal in a future version.");
+ return -1;
+ }
+}
diff --git a/Modules/hmacmodule.c b/Modules/hmacmodule.c
index c7b49d4dee3..95e400231bb 100644
--- a/Modules/hmacmodule.c
+++ b/Modules/hmacmodule.c
@@ -31,14 +31,15 @@
#endif
#if defined(__APPLE__) && defined(__arm64__)
-# undef HACL_CAN_COMPILE_SIMD128
-# undef HACL_CAN_COMPILE_SIMD256
+# undef _Py_HACL_CAN_COMPILE_VEC128
+# undef _Py_HACL_CAN_COMPILE_VEC256
#endif
-// Small mismatch between the variable names Python defines as part of configure
-// at the ones HACL* expects to be set in order to enable those headers.
-#define HACL_CAN_COMPILE_VEC128 HACL_CAN_COMPILE_SIMD128
-#define HACL_CAN_COMPILE_VEC256 HACL_CAN_COMPILE_SIMD256
+// HACL* expects HACL_CAN_COMPILE_VEC* macros to be set in order to enable
+// the corresponding SIMD instructions so we need to "forward" the values
+// we just deduced above.
+#define HACL_CAN_COMPILE_VEC128 _Py_HACL_CAN_COMPILE_VEC128
+#define HACL_CAN_COMPILE_VEC256 _Py_HACL_CAN_COMPILE_VEC256
#include "_hacl/Hacl_HMAC.h"
#include "_hacl/Hacl_Streaming_HMAC.h" // Hacl_Agile_Hash_* identifiers
@@ -216,105 +217,6 @@ typedef struct py_hmac_hacl_api {
#endif
/*
- * Call the HACL* HMAC-HASH update function on the given data.
- *
- * The magnitude of 'LEN' is not checked and thus 'LEN' must be
- * safely convertible to a uint32_t value.
- */
-#define Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, LEN) \
- Hacl_Streaming_HMAC_update(HACL_STATE, BUF, (uint32_t)(LEN))
-
-/*
- * Call the HACL* HMAC-HASH update function on the given data.
- *
- * On DEBUG builds, the 'ERRACTION' statements are executed if
- * the update() call returned a non-successful HACL* exit code.
- *
- * The buffer 'BUF' and its length 'LEN' are left untouched.
- *
- * The formal signature of this macro is:
- *
- * (HACL_HMAC_state *, uint8_t *, uint32_t, PyObject *, (C statements))
- */
-#ifndef NDEBUG
-#define Py_HMAC_HACL_UPDATE_ONCE( \
- HACL_STATE, BUF, LEN, \
- ALGORITHM, ERRACTION \
-) \
- do { \
- Py_CHECK_HACL_UINT32_T_LENGTH(LEN); \
- hacl_errno_t code = Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, LEN); \
- if (_hacl_convert_errno(code, (ALGORITHM)) < 0) { \
- ERRACTION; \
- } \
- } while (0)
-#else
-#define Py_HMAC_HACL_UPDATE_ONCE( \
- HACL_STATE, BUF, LEN, \
- _ALGORITHM, _ERRACTION \
-) \
- do { \
- (void)Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, (LEN)); \
- } while (0)
-#endif
-
-/*
- * Repetivively call the HACL* HMAC-HASH update function on the given
- * data until the buffer length 'LEN' is strictly less than UINT32_MAX.
- *
- * On builds with PY_SSIZE_T_MAX <= UINT32_MAX, this is a no-op.
- *
- * The buffer 'BUF' (resp. 'LEN') is advanced (resp. decremented)
- * by UINT32_MAX after each update. On DEBUG builds, each update()
- * call is verified and the 'ERRACTION' statements are executed if
- * a non-successful HACL* exit code is being returned.
- *
- * In particular, 'BUF' and 'LEN' must be variable names and not
- * expressions on their own.
- *
- * The formal signature of this macro is:
- *
- * (HACL_HMAC_state *, uint8_t *, C integer, PyObject *, (C statements))
- */
-#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
-#define Py_HMAC_HACL_UPDATE_LOOP( \
- HACL_STATE, BUF, LEN, \
- ALGORITHM, ERRACTION \
-) \
- do { \
- while ((Py_ssize_t)LEN > UINT32_MAX_AS_SSIZE_T) { \
- Py_HMAC_HACL_UPDATE_ONCE(HACL_STATE, BUF, UINT32_MAX, \
- ALGORITHM, ERRACTION); \
- BUF += UINT32_MAX; \
- LEN -= UINT32_MAX; \
- } \
- } while (0)
-#else
-#define Py_HMAC_HACL_UPDATE_LOOP( \
- HACL_STATE, BUF, LEN, \
- _ALGORITHM, _ERRACTION \
-)
-#endif
-
-/*
- * Perform the HMAC-HASH update() operation in a streaming fashion.
- *
- * The formal signature of this macro is:
- *
- * (HACL_HMAC_state *, uint8_t *, C integer, PyObject *, (C statements))
- */
-#define Py_HMAC_HACL_UPDATE( \
- HACL_STATE, BUF, LEN, \
- ALGORITHM, ERRACTION \
-) \
- do { \
- Py_HMAC_HACL_UPDATE_LOOP(HACL_STATE, BUF, LEN, \
- ALGORITHM, ERRACTION); \
- Py_HMAC_HACL_UPDATE_ONCE(HACL_STATE, BUF, LEN, \
- ALGORITHM, ERRACTION); \
- } while (0)
-
-/*
* HMAC underlying hash function static information.
*/
typedef struct py_hmac_hinfo {
@@ -382,11 +284,7 @@ get_hmacmodule_state_by_cls(PyTypeObject *cls)
typedef Hacl_Streaming_HMAC_agile_state HACL_HMAC_state;
typedef struct HMACObject {
- PyObject_HEAD
-
- bool use_mutex;
- PyMutex mutex;
-
+ HASHLIB_OBJECT_HEAD
// Hash function information
PyObject *name; // rendered name (exact unicode object)
HMAC_Hash_Kind kind; // can be used for runtime dispatch (must be known)
@@ -464,7 +362,7 @@ narrow_hmac_hash_kind(hmacmodule_state *state, HMAC_Hash_Kind kind)
{
switch (kind) {
case Py_hmac_kind_hmac_blake2s_32: {
-#if HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
if (state->can_run_simd128) {
return Py_hmac_kind_hmac_vectorized_blake2s_32;
}
@@ -472,7 +370,7 @@ narrow_hmac_hash_kind(hmacmodule_state *state, HMAC_Hash_Kind kind)
return kind;
}
case Py_hmac_kind_hmac_blake2b_32: {
-#if HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
if (state->can_run_simd256) {
return Py_hmac_kind_hmac_vectorized_blake2b_32;
}
@@ -491,38 +389,40 @@ narrow_hmac_hash_kind(hmacmodule_state *state, HMAC_Hash_Kind kind)
* Otherwise, this sets an appropriate exception and returns -1.
*/
static int
-_hacl_convert_errno(hacl_errno_t code, PyObject *algorithm)
+_hacl_convert_errno(hacl_errno_t code)
{
+ assert(PyGILState_GetThisThreadState() != NULL);
+ if (code == Hacl_Streaming_Types_Success) {
+ return 0;
+ }
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
switch (code) {
- case Hacl_Streaming_Types_Success: {
- return 0;
- }
case Hacl_Streaming_Types_InvalidAlgorithm: {
- // only makes sense if an algorithm is known at call time
- assert(algorithm != NULL);
- assert(PyUnicode_CheckExact(algorithm));
- PyErr_Format(PyExc_ValueError, "invalid algorithm: %U", algorithm);
- return -1;
+ PyErr_SetString(PyExc_ValueError, "invalid HACL* algorithm");
+ break;
}
case Hacl_Streaming_Types_InvalidLength: {
PyErr_SetString(PyExc_ValueError, "invalid length");
- return -1;
+ break;
}
case Hacl_Streaming_Types_MaximumLengthExceeded: {
PyErr_SetString(PyExc_OverflowError, "maximum length exceeded");
- return -1;
+ break;
}
case Hacl_Streaming_Types_OutOfMemory: {
PyErr_NoMemory();
- return -1;
+ break;
}
default: {
PyErr_Format(PyExc_RuntimeError,
- "HACL* internal routine failed with error code: %d",
+ "HACL* internal routine failed with error code: %u",
code);
- return -1;
+ break;
}
}
+ PyGILState_Release(gstate);
+ return -1;
}
/*
@@ -536,7 +436,7 @@ _hacl_hmac_state_new(HMAC_Hash_Kind kind, uint8_t *key, uint32_t len)
assert(kind != Py_hmac_kind_hash_unknown);
HACL_HMAC_state *state = NULL;
hacl_errno_t retcode = Hacl_Streaming_HMAC_malloc_(kind, key, len, &state);
- if (_hacl_convert_errno(retcode, NULL) < 0) {
+ if (_hacl_convert_errno(retcode) < 0) {
assert(state == NULL);
return NULL;
}
@@ -554,6 +454,51 @@ _hacl_hmac_state_free(HACL_HMAC_state *state)
}
}
+/*
+ * Call the HACL* HMAC-HASH update function on the given data.
+ *
+ * On DEBUG builds, the update() call is verified.
+ *
+ * Return 0 on success; otherwise, set an exception and return -1 on failure.
+*/
+static int
+_hacl_hmac_state_update_once(HACL_HMAC_state *state,
+ uint8_t *buf, uint32_t len)
+{
+#ifndef NDEBUG
+ hacl_errno_t code = Hacl_Streaming_HMAC_update(state, buf, len);
+ return _hacl_convert_errno(code);
+#else
+ (void)Hacl_Streaming_HMAC_update(state, buf, len);
+ return 0;
+#endif
+}
+
+/*
+ * Perform the HMAC-HASH update() operation in a streaming fashion.
+ *
+ * On DEBUG builds, each update() call is verified.
+ *
+ * Return 0 on success; otherwise, set an exception and return -1 on failure.
+ */
+static int
+_hacl_hmac_state_update(HACL_HMAC_state *state, uint8_t *buf, Py_ssize_t len)
+{
+ assert(len >= 0);
+#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
+ while (len > UINT32_MAX_AS_SSIZE_T) {
+ if (_hacl_hmac_state_update_once(state, buf, UINT32_MAX) < 0) {
+ assert(PyErr_Occurred());
+ return -1;
+ }
+ buf += UINT32_MAX;
+ len -= UINT32_MAX;
+ }
+#endif
+ Py_CHECK_HACL_UINT32_T_LENGTH(len);
+ return _hacl_hmac_state_update_once(state, buf, (uint32_t)len);
+}
+
/* Static information used to construct the hash table. */
static const py_hmac_hinfo py_hmac_static_hinfo[] = {
#define Py_HMAC_HINFO_HACL_API(HACL_HID) \
@@ -784,45 +729,6 @@ hmac_new_initial_state(HMACObject *self, uint8_t *key, Py_ssize_t len)
return self->state == NULL ? -1 : 0;
}
-/*
- * Feed initial data.
- *
- * This function MUST only be called by the HMAC object constructor
- * and after hmac_set_hinfo() and hmac_new_initial_state() have been
- * called, lest the behaviour is undefined.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static int
-hmac_feed_initial_data(HMACObject *self, uint8_t *msg, Py_ssize_t len)
-{
- assert(self->name != NULL);
- assert(self->state != NULL);
- if (len == 0) {
- // do nothing if the buffer is empty
- return 0;
- }
-
- if (len < HASHLIB_GIL_MINSIZE) {
- Py_HMAC_HACL_UPDATE(self->state, msg, len, self->name, return -1);
- return 0;
- }
-
- int res = 0;
- Py_BEGIN_ALLOW_THREADS
- Py_HMAC_HACL_UPDATE(self->state, msg, len, self->name, goto error);
- goto done;
-#ifndef NDEBUG
-error:
- res = -1;
-#else
- Py_UNREACHABLE();
-#endif
-done:
- Py_END_ALLOW_THREADS
- return res;
-}
-
/*[clinic input]
_hmac.new
@@ -869,7 +775,12 @@ _hmac_new_impl(PyObject *module, PyObject *keyobj, PyObject *msgobj,
if (msgobj != NULL && msgobj != Py_None) {
Py_buffer msg;
GET_BUFFER_VIEW_OR_ERROR(msgobj, &msg, goto error);
- rc = hmac_feed_initial_data(self, msg.buf, msg.len);
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ msg.len,
+ rc = _hacl_hmac_state_update(self->state, msg.buf, msg.len)
+ );
PyBuffer_Release(&msg);
#ifndef NDEBUG
if (rc < 0) {
@@ -946,12 +857,12 @@ _hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls)
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
/* copy hash information */
hmac_copy_hinfo(copy, self);
/* copy internal state */
int rc = hmac_copy_state(copy, self);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(copy);
@@ -963,78 +874,6 @@ _hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls)
return (PyObject *)copy;
}
-/*
- * Update the HMAC object with the given buffer.
- *
- * This unconditionally acquires the lock on the HMAC object.
- *
- * On DEBUG builds, each update() call is verified.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static int
-hmac_update_state_with_lock(HMACObject *self, uint8_t *buf, Py_ssize_t len)
-{
- int res = 0;
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex); // unconditionally acquire a lock
- Py_HMAC_HACL_UPDATE(self->state, buf, len, self->name, goto error);
- goto done;
-#ifndef NDEBUG
-error:
- res = -1;
-#else
- Py_UNREACHABLE();
-#endif
-done:
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- return res;
-}
-
-/*
- * Update the HMAC object with the given buffer.
- *
- * This conditionally acquires the lock on the HMAC object.
- *
- * On DEBUG builds, each update() call is verified.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static int
-hmac_update_state_cond_lock(HMACObject *self, uint8_t *buf, Py_ssize_t len)
-{
- ENTER_HASHLIB(self); // conditionally acquire a lock
- Py_HMAC_HACL_UPDATE(self->state, buf, len, self->name, goto error);
- LEAVE_HASHLIB(self);
- return 0;
-
-#ifndef NDEBUG
-error:
- LEAVE_HASHLIB(self);
- return -1;
-#else
- Py_UNREACHABLE();
-#endif
-}
-
-/*
- * Update the internal HMAC state with the given buffer.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static inline int
-hmac_update_state(HMACObject *self, uint8_t *buf, Py_ssize_t len)
-{
- assert(buf != 0);
- assert(len >= 0);
- return len == 0
- ? 0 /* nothing to do */
- : len < HASHLIB_GIL_MINSIZE
- ? hmac_update_state_cond_lock(self, buf, len)
- : hmac_update_state_with_lock(self, buf, len);
-}
-
/*[clinic input]
_hmac.HMAC.update
@@ -1047,9 +886,13 @@ static PyObject *
_hmac_HMAC_update_impl(HMACObject *self, PyObject *msgobj)
/*[clinic end generated code: output=962134ada5e55985 input=7c0ea830efb03367]*/
{
+ int rc = 0;
Py_buffer msg;
GET_BUFFER_VIEW_OR_ERROUT(msgobj, &msg);
- int rc = hmac_update_state(self, msg.buf, msg.len);
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, msg.len,
+ rc = _hacl_hmac_state_update(self->state, msg.buf, msg.len)
+ );
PyBuffer_Release(&msg);
return rc < 0 ? NULL : Py_None;
}
@@ -1065,18 +908,18 @@ _hmac_HMAC_update_impl(HMACObject *self, PyObject *msgobj)
* Note: this function may raise a MemoryError.
*/
static int
-hmac_digest_compute_cond_lock(HMACObject *self, uint8_t *digest)
+hmac_digest_compute_locked(HMACObject *self, uint8_t *digest)
{
assert(digest != NULL);
hacl_errno_t rc;
- ENTER_HASHLIB(self); // conditionally acquire a lock
+ HASHLIB_ACQUIRE_LOCK(self);
rc = Hacl_Streaming_HMAC_digest(self->state, digest, self->digest_size);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
assert(
rc == Hacl_Streaming_Types_Success ||
rc == Hacl_Streaming_Types_OutOfMemory
);
- return _hacl_convert_errno(rc, NULL);
+ return _hacl_convert_errno(rc);
}
/*[clinic input]
@@ -1093,7 +936,7 @@ _hmac_HMAC_digest_impl(HMACObject *self)
{
assert(self->digest_size <= Py_hmac_hash_max_digest_size);
uint8_t digest[Py_hmac_hash_max_digest_size];
- if (hmac_digest_compute_cond_lock(self, digest) < 0) {
+ if (hmac_digest_compute_locked(self, digest) < 0) {
return NULL;
}
return PyBytes_FromStringAndSize((const char *)digest, self->digest_size);
@@ -1116,7 +959,7 @@ _hmac_HMAC_hexdigest_impl(HMACObject *self)
{
assert(self->digest_size <= Py_hmac_hash_max_digest_size);
uint8_t digest[Py_hmac_hash_max_digest_size];
- if (hmac_digest_compute_cond_lock(self, digest) < 0) {
+ if (hmac_digest_compute_locked(self, digest) < 0) {
return NULL;
}
return _Py_strhex((const char *)digest, self->digest_size);
@@ -1715,11 +1558,11 @@ hmacmodule_init_cpu_features(hmacmodule_state *state)
__cpuid_count(1, 0, eax1, ebx1, ecx1, edx1);
__cpuid_count(7, 0, eax7, ebx7, ecx7, edx7);
#elif defined(_M_X64)
- int info1[4] = { 0 };
+ int info1[4] = {0};
__cpuidex(info1, 1, 0);
eax1 = info1[0], ebx1 = info1[1], ecx1 = info1[2], edx1 = info1[3];
- int info7[4] = { 0 };
+ int info7[4] = {0};
__cpuidex(info7, 7, 0);
eax7 = info7[0], ebx7 = info7[1], ecx7 = info7[2], edx7 = info7[3];
#endif
@@ -1759,7 +1602,7 @@ hmacmodule_init_cpu_features(hmacmodule_state *state)
#undef ECX_SSE3
#undef EBX_AVX2
-#if HACL_CAN_COMPILE_SIMD128
+#if _Py_HACL_CAN_COMPILE_VEC128
// TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection
state->can_run_simd128 = sse && sse2 && sse3 && sse41 && sse42 && cmov;
#else
@@ -1769,7 +1612,7 @@ hmacmodule_init_cpu_features(hmacmodule_state *state)
state->can_run_simd128 = false;
#endif
-#if HACL_CAN_COMPILE_SIMD256
+#if _Py_HACL_CAN_COMPILE_VEC256
// TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection
state->can_run_simd256 = state->can_run_simd128 && avx && avx2;
#else
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 943c1e8607b..cc1a5580015 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -1124,7 +1124,6 @@ typedef struct {
PyObject *it;
PyObject *saved;
Py_ssize_t index;
- int firstpass;
} cycleobject;
#define cycleobject_CAST(op) ((cycleobject *)(op))
@@ -1165,8 +1164,7 @@ itertools_cycle_impl(PyTypeObject *type, PyObject *iterable)
}
lz->it = it;
lz->saved = saved;
- lz->index = 0;
- lz->firstpass = 0;
+ lz->index = -1;
return (PyObject *)lz;
}
@@ -1199,11 +1197,11 @@ cycle_next(PyObject *op)
cycleobject *lz = cycleobject_CAST(op);
PyObject *item;
- if (lz->it != NULL) {
+ Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(lz->index);
+
+ if (index < 0) {
item = PyIter_Next(lz->it);
if (item != NULL) {
- if (lz->firstpass)
- return item;
if (PyList_Append(lz->saved, item)) {
Py_DECREF(item);
return NULL;
@@ -1213,15 +1211,22 @@ cycle_next(PyObject *op)
/* Note: StopIteration is already cleared by PyIter_Next() */
if (PyErr_Occurred())
return NULL;
+ index = 0;
+ FT_ATOMIC_STORE_SSIZE_RELAXED(lz->index, 0);
+#ifndef Py_GIL_DISABLED
Py_CLEAR(lz->it);
+#endif
}
if (PyList_GET_SIZE(lz->saved) == 0)
return NULL;
- item = PyList_GET_ITEM(lz->saved, lz->index);
- lz->index++;
- if (lz->index >= PyList_GET_SIZE(lz->saved))
- lz->index = 0;
- return Py_NewRef(item);
+ item = PyList_GetItemRef(lz->saved, index);
+ assert(item);
+ index++;
+ if (index >= PyList_GET_SIZE(lz->saved)) {
+ index = 0;
+ }
+ FT_ATOMIC_STORE_SSIZE_RELAXED(lz->index, index);
+ return item;
}
static PyType_Slot cycle_slots[] = {
@@ -1875,8 +1880,8 @@ chain_traverse(PyObject *op, visitproc visit, void *arg)
return 0;
}
-static PyObject *
-chain_next(PyObject *op)
+static inline PyObject *
+chain_next_lock_held(PyObject *op)
{
chainobject *lz = chainobject_CAST(op);
PyObject *item;
@@ -1914,6 +1919,16 @@ chain_next(PyObject *op)
return NULL;
}
+static PyObject *
+chain_next(PyObject *op)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = chain_next_lock_held(op);
+ Py_END_CRITICAL_SECTION()
+ return result;
+}
+
PyDoc_STRVAR(chain_doc,
"chain(*iterables)\n\
--\n\
@@ -2081,7 +2096,7 @@ product_traverse(PyObject *op, visitproc visit, void *arg)
}
static PyObject *
-product_next(PyObject *op)
+product_next_lock_held(PyObject *op)
{
productobject *lz = productobject_CAST(op);
PyObject *pool;
@@ -2167,6 +2182,16 @@ empty:
return NULL;
}
+static PyObject *
+product_next(PyObject *op)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = product_next_lock_held(op);
+ Py_END_CRITICAL_SECTION()
+ return result;
+}
+
static PyMethodDef product_methods[] = {
{"__sizeof__", product_sizeof, METH_NOARGS, sizeof_doc},
{NULL, NULL} /* sentinel */
@@ -2314,7 +2339,7 @@ combinations_traverse(PyObject *op, visitproc visit, void *arg)
}
static PyObject *
-combinations_next(PyObject *op)
+combinations_next_lock_held(PyObject *op)
{
combinationsobject *co = combinationsobject_CAST(op);
PyObject *elem;
@@ -2399,6 +2424,16 @@ empty:
return NULL;
}
+static PyObject *
+combinations_next(PyObject *op)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = combinations_next_lock_held(op);
+ Py_END_CRITICAL_SECTION()
+ return result;
+}
+
static PyMethodDef combinations_methods[] = {
{"__sizeof__", combinations_sizeof, METH_NOARGS, sizeof_doc},
{NULL, NULL} /* sentinel */
diff --git a/Modules/main.c b/Modules/main.c
index ea1239ecc57..74e48c94732 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -128,7 +128,7 @@ pymain_get_importer(const wchar_t *filename, PyObject **importer_p, int *exitcod
{
PyObject *sys_path0 = NULL, *importer;
- sys_path0 = PyUnicode_FromWideChar(filename, wcslen(filename));
+ sys_path0 = PyUnicode_FromWideChar(filename, -1);
if (sys_path0 == NULL) {
goto error;
}
@@ -269,13 +269,14 @@ error:
static int
-pymain_start_pyrepl_no_main(void)
+pymain_start_pyrepl(int pythonstartup)
{
int res = 0;
PyObject *console = NULL;
PyObject *empty_tuple = NULL;
PyObject *kwargs = NULL;
PyObject *console_result = NULL;
+ PyObject *main_module = NULL;
PyObject *pyrepl = PyImport_ImportModule("_pyrepl.main");
if (pyrepl == NULL) {
@@ -299,7 +300,13 @@ pymain_start_pyrepl_no_main(void)
res = pymain_exit_err_print();
goto done;
}
- if (!PyDict_SetItemString(kwargs, "pythonstartup", _PyLong_GetOne())) {
+ main_module = PyImport_AddModuleRef("__main__");
+ if (main_module == NULL) {
+ res = pymain_exit_err_print();
+ goto done;
+ }
+ if (!PyDict_SetItemString(kwargs, "mainmodule", main_module)
+ && !PyDict_SetItemString(kwargs, "pythonstartup", pythonstartup ? Py_True : Py_False)) {
console_result = PyObject_Call(console, empty_tuple, kwargs);
if (console_result == NULL) {
res = pymain_exit_err_print();
@@ -311,6 +318,7 @@ done:
Py_XDECREF(empty_tuple);
Py_XDECREF(console);
Py_XDECREF(pyrepl);
+ Py_XDECREF(main_module);
return res;
}
@@ -328,7 +336,7 @@ pymain_run_module(const wchar_t *modname, int set_argv0)
fprintf(stderr, "Could not import runpy._run_module_as_main\n");
return pymain_exit_err_print();
}
- module = PyUnicode_FromWideChar(modname, wcslen(modname));
+ module = PyUnicode_FromWideChar(modname, -1);
if (module == NULL) {
fprintf(stderr, "Could not convert module name to unicode\n");
Py_DECREF(runmodule);
@@ -439,7 +447,7 @@ pymain_run_startup(PyConfig *config, int *exitcode)
if (env == NULL || env[0] == L'\0') {
return 0;
}
- startup = PyUnicode_FromWideChar(env, wcslen(env));
+ startup = PyUnicode_FromWideChar(env, -1);
if (startup == NULL) {
goto error;
}
@@ -489,16 +497,13 @@ error:
static int
pymain_run_interactive_hook(int *exitcode)
{
- PyObject *hook = PyImport_ImportModuleAttrString("sys",
- "__interactivehook__");
- if (hook == NULL) {
- if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
- // no sys.__interactivehook__ attribute
- PyErr_Clear();
- return 0;
- }
+ PyObject *hook;
+ if (PySys_GetOptionalAttrString("__interactivehook__", &hook) < 0) {
goto error;
}
+ if (hook == NULL) {
+ return 0;
+ }
if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
goto error;
@@ -562,7 +567,7 @@ pymain_run_stdin(PyConfig *config)
int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
return (run != 0);
}
- return pymain_run_module(L"_pyrepl", 0);
+ return pymain_start_pyrepl(0);
}
@@ -595,7 +600,7 @@ pymain_repl(PyConfig *config, int *exitcode)
*exitcode = (run != 0);
return;
}
- int run = pymain_start_pyrepl_no_main();
+ int run = pymain_start_pyrepl(1);
*exitcode = (run != 0);
return;
}
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 11d9b7418a2..033de0b2907 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -1233,6 +1233,23 @@ FUNC2(remainder, m_remainder,
"Return x - n*y where n*y is the closest integer multiple of y.\n"
"In the case where x is exactly halfway between two multiples of\n"
"y, the nearest even value of n is used. The result is always exact.")
+
+/*[clinic input]
+math.signbit
+
+ x: double
+ /
+
+Return True if the sign of x is negative and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_signbit_impl(PyObject *module, double x)
+/*[clinic end generated code: output=20c5f20156a9b871 input=3d3493fbcb5bdb3e]*/
+{
+ return PyBool_FromLong(signbit(x));
+}
+
FUNC1D(sin, sin, 0,
"sin($module, x, /)\n--\n\n"
"Return the sine of x (measured in radians).",
@@ -2008,13 +2025,11 @@ math.factorial
/
Find n!.
-
-Raise a ValueError if x is negative or non-integral.
[clinic start generated code]*/
static PyObject *
math_factorial(PyObject *module, PyObject *arg)
-/*[clinic end generated code: output=6686f26fae00e9ca input=713fb771677e8c31]*/
+/*[clinic end generated code: output=6686f26fae00e9ca input=366cc321df3d4773]*/
{
long x, two_valuation;
int overflow;
@@ -2163,6 +2178,27 @@ math_ldexp_impl(PyObject *module, double x, PyObject *i)
} else {
errno = 0;
r = ldexp(x, (int)exp);
+#ifdef _MSC_VER
+ if (DBL_MIN > r && r > -DBL_MIN) {
+ /* Denormal (or zero) results can be incorrectly rounded here (rather,
+ truncated). Fixed in newer versions of the C runtime, included
+ with Windows 11. */
+ int original_exp;
+ frexp(x, &original_exp);
+ if (original_exp > DBL_MIN_EXP) {
+ /* Shift down to the smallest normal binade. No bits lost. */
+ int shift = DBL_MIN_EXP - original_exp;
+ x = ldexp(x, shift);
+ exp -= shift;
+ }
+ /* Multiplying by 2**exp finishes the job, and the HW will round as
+ appropriate. Note: if exp < -DBL_MANT_DIG, all of x is shifted
+ to be < 0.5ULP of smallest denorm, so should be thrown away. If
+ exp is so very negative that ldexp underflows to 0, that's fine;
+ no need to check in advance. */
+ r = x*ldexp(1.0, (int)exp);
+ }
+#endif
if (isinf(r))
errno = ERANGE;
}
@@ -3100,6 +3136,44 @@ math_isfinite_impl(PyObject *module, double x)
/*[clinic input]
+math.isnormal
+
+ x: double
+ /
+
+Return True if x is normal, and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_isnormal_impl(PyObject *module, double x)
+/*[clinic end generated code: output=c7b302b5b89c3541 input=fdaa00c58aa7bc17]*/
+{
+ return PyBool_FromLong(isnormal(x));
+}
+
+
+/*[clinic input]
+math.issubnormal
+
+ x: double
+ /
+
+Return True if x is subnormal, and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_issubnormal_impl(PyObject *module, double x)
+/*[clinic end generated code: output=4e76ac98ddcae761 input=9a20aba7107d0d95]*/
+{
+#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+ return PyBool_FromLong(issubnormal(x));
+#else
+ return PyBool_FromLong(isfinite(x) && x && !isnormal(x));
+#endif
+}
+
+
+/*[clinic input]
math.isnan
x: double
@@ -4126,6 +4200,8 @@ static PyMethodDef math_methods[] = {
MATH_HYPOT_METHODDEF
MATH_ISCLOSE_METHODDEF
MATH_ISFINITE_METHODDEF
+ MATH_ISNORMAL_METHODDEF
+ MATH_ISSUBNORMAL_METHODDEF
MATH_ISINF_METHODDEF
MATH_ISNAN_METHODDEF
MATH_ISQRT_METHODDEF
@@ -4140,6 +4216,7 @@ static PyMethodDef math_methods[] = {
MATH_POW_METHODDEF
MATH_RADIANS_METHODDEF
{"remainder", _PyCFunction_CAST(math_remainder), METH_FASTCALL, math_remainder_doc},
+ MATH_SIGNBIT_METHODDEF
{"sin", math_sin, METH_O, math_sin_doc},
{"sinh", math_sinh, METH_O, math_sinh_doc},
{"sqrt", math_sqrt, METH_O, math_sqrt_doc},
diff --git a/Modules/md5module.c b/Modules/md5module.c
index c36eb41d4d2..8b6dd4a8195 100644
--- a/Modules/md5module.c
+++ b/Modules/md5module.c
@@ -8,6 +8,7 @@
Andrew Kuchling (amk@amk.ca)
Greg Stein (gstein@lyra.org)
Trevor Perrin (trevp@trevp.net)
+ Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
Licensed to PSF under a Contributor Agreement.
@@ -21,34 +22,27 @@
#endif
#include "Python.h"
+#include "pycore_strhex.h" // _Py_strhex()
+
#include "hashlib.h"
-/*[clinic input]
-module _md5
-class MD5Type "MD5object *" "&PyType_Type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6e5261719957a912]*/
+#include "_hacl/Hacl_Hash_MD5.h"
/* The MD5 block size and message digest sizes, in bytes */
#define MD5_BLOCKSIZE 64
#define MD5_DIGESTSIZE 16
-#include "_hacl/Hacl_Hash_MD5.h"
-
+// --- Module objects ---------------------------------------------------------
typedef struct {
- PyObject_HEAD
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
+ HASHLIB_OBJECT_HEAD
Hacl_Hash_MD5_state_t *hash_state;
} MD5object;
#define _MD5object_CAST(op) ((MD5object *)(op))
-#include "clinic/md5module.c.h"
-
+// --- Module state -----------------------------------------------------------
typedef struct {
PyTypeObject* md5_type;
@@ -62,6 +56,18 @@ md5_get_state(PyObject *module)
return (MD5State *)state;
}
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _md5
+class MD5Type "MD5object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6e5261719957a912]*/
+
+#include "clinic/md5module.c.h"
+
+// --- MD5 object interface ---------------------------------------------------
+
static MD5object *
newMD5object(MD5State * st)
{
@@ -116,11 +122,11 @@ MD5Type_copy_impl(MD5object *self, PyTypeObject *cls)
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
newobj->hash_state = Hacl_Hash_MD5_copy(self->hash_state);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (newobj->hash_state == NULL) {
- Py_DECREF(self);
+ Py_DECREF(newobj);
return PyErr_NoMemory();
}
return (PyObject *)newobj;
@@ -136,10 +142,10 @@ static PyObject *
MD5Type_digest_impl(MD5object *self)
/*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/
{
- unsigned char digest[MD5_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ uint8_t digest[MD5_DIGESTSIZE];
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_MD5_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE);
}
@@ -153,20 +159,11 @@ static PyObject *
MD5Type_hexdigest_impl(MD5object *self)
/*[clinic end generated code: output=17badced1f3ac932 input=b60b19de644798dd]*/
{
- unsigned char digest[MD5_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ uint8_t digest[MD5_DIGESTSIZE];
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_MD5_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
-
- const char *hexdigits = "0123456789abcdef";
- char digest_hex[MD5_DIGESTSIZE * 2];
- char *str = digest_hex;
- for (size_t i=0; i < MD5_DIGESTSIZE; i++) {
- unsigned char byte = digest[i];
- *str++ = hexdigits[byte >> 4];
- *str++ = hexdigits[byte & 0x0f];
- }
- return PyUnicode_FromStringAndSize(digest_hex, sizeof(digest_hex));
+ HASHLIB_RELEASE_LOCK(self);
+ return _Py_strhex((const char *)digest, MD5_DIGESTSIZE);
}
static void
@@ -177,6 +174,7 @@ update(Hacl_Hash_MD5_state_t *state, uint8_t *buf, Py_ssize_t len)
* take more than 1 billion years to overflow the maximum admissible length
* for MD5 (2^61 - 1).
*/
+ assert(len >= 0);
#if PY_SSIZE_T_MAX > UINT32_MAX
while (len > UINT32_MAX) {
(void)Hacl_Hash_MD5_update(state, buf, UINT32_MAX);
@@ -202,22 +200,11 @@ MD5Type_update_impl(MD5object *self, PyObject *obj)
/*[clinic end generated code: output=b0fed9a7ce7ad253 input=6e1efcd9ecf17032]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- update(self->hash_state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update(self->hash_state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update(self->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -276,17 +263,24 @@ static PyType_Spec md5_type_spec = {
/*[clinic input]
_md5.md5
- string: object(c_default="NULL") = b''
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string as string_obj: object(c_default="NULL") = None
Return a new MD5 hash object; optionally initialized with a string.
[clinic start generated code]*/
static PyObject *
-_md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity)
-/*[clinic end generated code: output=587071f76254a4ac input=7a144a1905636985]*/
+_md5_md5_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj)
+/*[clinic end generated code: output=d45e187d3d16f3a8 input=7ea5c5366dbb44bf]*/
{
+ PyObject *string;
+ if (_Py_hashlib_data_argument(&string, data, string_obj) < 0) {
+ return NULL;
+ }
+
MD5object *new;
Py_buffer buf;
@@ -312,16 +306,12 @@ _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity)
}
if (string) {
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- update(new->hash_state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update(new->hash_state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ update(new->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index 6a385562845..142ff1a2131 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -25,6 +25,7 @@
#include <Python.h>
#include "pycore_bytesobject.h" // _PyBytes_Find()
#include "pycore_fileutils.h" // _Py_stat_struct
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#ifndef MS_WINDOWS
@@ -163,8 +164,7 @@ mmap_object_dealloc(PyObject *op)
Py_END_ALLOW_THREADS
#endif /* UNIX */
- if (m_obj->weakreflist != NULL)
- PyObject_ClearWeakRefs(op);
+ FT_CLEAR_WEAKREFS(op, m_obj->weakreflist);
tp->tp_free(m_obj);
Py_DECREF(tp);
@@ -290,6 +290,24 @@ filter_page_exception_method(mmap_object *self, EXCEPTION_POINTERS *ptrs,
}
return EXCEPTION_CONTINUE_SEARCH;
}
+
+static void
+_PyErr_SetFromNTSTATUS(ULONG status)
+{
+#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
+ PyErr_SetFromWindowsErr(LsaNtStatusToWinError((NTSTATUS)status));
+#else
+ if (status & 0x80000000) {
+ // HRESULT-shaped codes are supported by PyErr_SetFromWindowsErr
+ PyErr_SetFromWindowsErr((int)status);
+ }
+ else {
+ // No mapping for NTSTATUS values, so just return it for diagnostic purposes
+ // If we provide it as winerror it could incorrectly change the type of the exception.
+ PyErr_Format(PyExc_OSError, "Operating system error NTSTATUS=0x%08lX", status);
+ }
+#endif
+}
#endif
#if defined(MS_WINDOWS) && !defined(DONT_USE_SEH)
@@ -303,9 +321,7 @@ do { \
assert(record.ExceptionCode == EXCEPTION_IN_PAGE_ERROR || \
record.ExceptionCode == EXCEPTION_ACCESS_VIOLATION); \
if (record.ExceptionCode == EXCEPTION_IN_PAGE_ERROR) { \
- NTSTATUS status = (NTSTATUS) record.ExceptionInformation[2]; \
- ULONG code = LsaNtStatusToWinError(status); \
- PyErr_SetFromWindowsErr(code); \
+ _PyErr_SetFromNTSTATUS((ULONG)record.ExceptionInformation[2]); \
} \
else if (record.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { \
PyErr_SetFromWindowsErr(ERROR_NOACCESS); \
@@ -332,9 +348,7 @@ do { \
assert(record.ExceptionCode == EXCEPTION_IN_PAGE_ERROR || \
record.ExceptionCode == EXCEPTION_ACCESS_VIOLATION); \
if (record.ExceptionCode == EXCEPTION_IN_PAGE_ERROR) { \
- NTSTATUS status = (NTSTATUS) record.ExceptionInformation[2]; \
- ULONG code = LsaNtStatusToWinError(status); \
- PyErr_SetFromWindowsErr(code); \
+ _PyErr_SetFromNTSTATUS((ULONG)record.ExceptionInformation[2]); \
} \
else if (record.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { \
PyErr_SetFromWindowsErr(ERROR_NOACCESS); \
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 04c3b9e987a..b570f81b7cf 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -573,7 +573,11 @@ extern char *ctermid_r(char *);
# define HAVE_FACCESSAT_RUNTIME 1
# define HAVE_FCHMODAT_RUNTIME 1
# define HAVE_FCHOWNAT_RUNTIME 1
+#ifdef __wasi__
+# define HAVE_LINKAT_RUNTIME 0
+# else
# define HAVE_LINKAT_RUNTIME 1
+# endif
# define HAVE_FDOPENDIR_RUNTIME 1
# define HAVE_MKDIRAT_RUNTIME 1
# define HAVE_RENAMEAT_RUNTIME 1
@@ -681,7 +685,8 @@ static void
reset_remotedebug_data(PyThreadState *tstate)
{
tstate->remote_debugger_support.debugger_pending_call = 0;
- memset(tstate->remote_debugger_support.debugger_script_path, 0, MAX_SCRIPT_PATH_SIZE);
+ memset(tstate->remote_debugger_support.debugger_script_path, 0,
+ Py_MAX_SCRIPT_PATH_SIZE);
}
@@ -1778,7 +1783,7 @@ convertenviron(void)
return NULL;
}
#ifdef MS_WINDOWS
- v = PyUnicode_FromWideChar(p+1, wcslen(p+1));
+ v = PyUnicode_FromWideChar(p+1, -1);
#else
v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
#endif
@@ -4203,7 +4208,7 @@ posix_getcwd(int use_bytes)
terminating \0. If the buffer is too small, len includes
the space needed for the terminator. */
if (len >= Py_ARRAY_LENGTH(wbuf)) {
- if (len <= PY_SSIZE_T_MAX / sizeof(wchar_t)) {
+ if ((Py_ssize_t)len <= PY_SSIZE_T_MAX / sizeof(wchar_t)) {
wbuf2 = PyMem_RawMalloc(len * sizeof(wchar_t));
}
else {
@@ -4346,7 +4351,7 @@ os.link
*
src_dir_fd : dir_fd = None
dst_dir_fd : dir_fd = None
- follow_symlinks: bool = True
+ follow_symlinks: bool(c_default="-1", py_default="(os.name != 'nt')") = PLACEHOLDER
Create a hard link to a file.
@@ -4364,31 +4369,46 @@ src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your
static PyObject *
os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
int dst_dir_fd, int follow_symlinks)
-/*[clinic end generated code: output=7f00f6007fd5269a input=b0095ebbcbaa7e04]*/
+/*[clinic end generated code: output=7f00f6007fd5269a input=1d5e602d115fed7b]*/
{
#ifdef MS_WINDOWS
BOOL result = FALSE;
#else
int result;
#endif
-#if defined(HAVE_LINKAT)
- int linkat_unavailable = 0;
-#endif
-#ifndef HAVE_LINKAT
- if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) {
- argument_unavailable_error("link", "src_dir_fd and dst_dir_fd");
- return NULL;
+#ifdef HAVE_LINKAT
+ if (HAVE_LINKAT_RUNTIME) {
+ if (follow_symlinks < 0) {
+ follow_symlinks = 1;
+ }
}
+ else
#endif
-
-#ifndef MS_WINDOWS
- if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
- PyErr_SetString(PyExc_NotImplementedError,
- "link: src and dst must be the same type");
- return NULL;
- }
+ {
+ if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) {
+ argument_unavailable_error("link", "src_dir_fd and dst_dir_fd");
+ return NULL;
+ }
+/* See issue 85527: link() on Linux works like linkat without AT_SYMLINK_FOLLOW,
+ but on Mac it works like linkat *with* AT_SYMLINK_FOLLOW. */
+#if defined(MS_WINDOWS) || defined(__linux__)
+ if (follow_symlinks == 1) {
+ argument_unavailable_error("link", "follow_symlinks=True");
+ return NULL;
+ }
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || (defined(__sun) && defined(__SVR4))
+ if (follow_symlinks == 0) {
+ argument_unavailable_error("link", "follow_symlinks=False");
+ return NULL;
+ }
+#else
+ if (follow_symlinks >= 0) {
+ argument_unavailable_error("link", "follow_symlinks");
+ return NULL;
+ }
#endif
+ }
if (PySys_Audit("os.link", "OOii", src->object, dst->object,
src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
@@ -4406,44 +4426,18 @@ os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
#else
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_LINKAT
- if ((src_dir_fd != DEFAULT_DIR_FD) ||
- (dst_dir_fd != DEFAULT_DIR_FD) ||
- (!follow_symlinks)) {
-
- if (HAVE_LINKAT_RUNTIME) {
-
- result = linkat(src_dir_fd, src->narrow,
- dst_dir_fd, dst->narrow,
- follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
-
- }
-#ifdef __APPLE__
- else {
- if (src_dir_fd == DEFAULT_DIR_FD && dst_dir_fd == DEFAULT_DIR_FD) {
- /* See issue 41355: This matches the behaviour of !HAVE_LINKAT */
- result = link(src->narrow, dst->narrow);
- } else {
- linkat_unavailable = 1;
- }
- }
-#endif
+ if (HAVE_LINKAT_RUNTIME) {
+ result = linkat(src_dir_fd, src->narrow,
+ dst_dir_fd, dst->narrow,
+ follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
}
else
-#endif /* HAVE_LINKAT */
+#endif
+ {
+ /* linkat not available */
result = link(src->narrow, dst->narrow);
- Py_END_ALLOW_THREADS
-
-#ifdef HAVE_LINKAT
- if (linkat_unavailable) {
- /* Either or both dir_fd arguments were specified */
- if (src_dir_fd != DEFAULT_DIR_FD) {
- argument_unavailable_error("link", "src_dir_fd");
- } else {
- argument_unavailable_error("link", "dst_dir_fd");
- }
- return NULL;
}
-#endif
+ Py_END_ALLOW_THREADS
if (result)
return path_error2(src, dst);
@@ -4705,7 +4699,7 @@ os_listdir_impl(PyObject *module, path_t *path)
}
-#ifdef MS_WINDOWS
+#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
/*[clinic input]
os.listdrives
@@ -4754,6 +4748,10 @@ os_listdrives_impl(PyObject *module)
return result;
}
+#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */
+
+#if defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)
+
/*[clinic input]
os.listvolumes
@@ -4815,6 +4813,9 @@ os_listvolumes_impl(PyObject *module)
return result;
}
+#endif /* MS_WINDOWS_APP || MS_WINDOWS_SYSTEM */
+
+#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
/*[clinic input]
os.listmounts
@@ -4895,6 +4896,9 @@ exit:
return result;
}
+#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */
+
+#ifdef MS_WINDOWS
/*[clinic input]
os._path_isdevdrive
@@ -5049,7 +5053,7 @@ os__getfullpathname_impl(PyObject *module, path_t *path)
return PyErr_NoMemory();
}
- PyObject *str = PyUnicode_FromWideChar(abspath, wcslen(abspath));
+ PyObject *str = PyUnicode_FromWideChar(abspath, -1);
PyMem_RawFree(abspath);
if (str == NULL) {
return NULL;
@@ -5165,7 +5169,7 @@ os__findfirstfile_impl(PyObject *module, path_t *path)
}
wRealFileName = wFileData.cFileName;
- result = PyUnicode_FromWideChar(wRealFileName, wcslen(wRealFileName));
+ result = PyUnicode_FromWideChar(wRealFileName, -1);
FindClose(hFindFile);
return result;
}
@@ -5209,7 +5213,7 @@ os__getvolumepathname_impl(PyObject *module, path_t *path)
result = win32_error_object("_getvolumepathname", path->object);
goto exit;
}
- result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath));
+ result = PyUnicode_FromWideChar(mountpath, -1);
if (PyBytes_Check(path->object))
Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
@@ -5733,6 +5737,9 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
+ // For API sets that don't support these APIs, we have no choice
+ // but to silently create a directory with default ACL.
+#if defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)
if (mode == 0700 /* 0o700 */) {
ULONG sdSize;
pSecAttr = &secAttr;
@@ -5748,6 +5755,7 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
error = GetLastError();
}
}
+#endif
if (!error) {
result = CreateDirectoryW(path->wide, pSecAttr);
if (secAttr.lpSecurityDescriptor &&
@@ -5935,12 +5943,6 @@ internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is
return path_error2(src, dst);
#else
- if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
- PyErr_Format(PyExc_ValueError,
- "%s: src and dst must be the same type", function_name);
- return NULL;
- }
-
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_RENAMEAT
if (dir_fd_specified) {
@@ -8819,14 +8821,14 @@ os_ptsname_impl(PyObject *module, int fd)
#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX)
#ifdef HAVE_PTY_H
#include <pty.h>
-#ifdef HAVE_UTMP_H
-#include <utmp.h>
-#endif /* HAVE_UTMP_H */
#elif defined(HAVE_LIBUTIL_H)
#include <libutil.h>
#elif defined(HAVE_UTIL_H)
#include <util.h>
#endif /* HAVE_PTY_H */
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif /* HAVE_UTMP_H */
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
@@ -9561,6 +9563,24 @@ os_getlogin_impl(PyObject *module)
}
else
result = PyErr_SetFromWindowsErr(GetLastError());
+#elif defined (HAVE_GETLOGIN_R)
+# if defined (HAVE_MAXLOGNAME)
+ char name[MAXLOGNAME + 1];
+# elif defined (HAVE_UT_NAMESIZE)
+ char name[UT_NAMESIZE + 1];
+# else
+ char name[256];
+# endif
+ int err = getlogin_r(name, sizeof(name));
+ if (err) {
+ int old_errno = errno;
+ errno = -err;
+ posix_error();
+ errno = old_errno;
+ }
+ else {
+ result = PyUnicode_DecodeFSDefault(name);
+ }
#else
char *name;
int old_errno = errno;
@@ -10613,12 +10633,6 @@ os_symlink_impl(PyObject *module, path_t *src, path_t *dst,
#else
- if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
- PyErr_SetString(PyExc_ValueError,
- "symlink: src and dst must be the same type");
- return NULL;
- }
-
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_SYMLINKAT
if (dir_fd != DEFAULT_DIR_FD) {
@@ -16884,12 +16898,16 @@ static PyObject *
os__supports_virtual_terminal_impl(PyObject *module)
/*[clinic end generated code: output=bd0556a6d9d99fe6 input=0752c98e5d321542]*/
{
+#ifdef HAVE_WINDOWS_CONSOLE_IO
DWORD mode = 0;
HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
if (!GetConsoleMode(handle, &mode)) {
Py_RETURN_FALSE;
}
return PyBool_FromLong(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+#else
+ Py_RETURN_FALSE;
+#endif /* HAVE_WINDOWS_CONSOLE_IO */
}
#endif
diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c
index 2240e2078b2..c5a8cead19a 100644
--- a/Modules/pwdmodule.c
+++ b/Modules/pwdmodule.c
@@ -301,18 +301,33 @@ pwd_getpwall_impl(PyObject *module)
struct passwd *p;
if ((d = PyList_New(0)) == NULL)
return NULL;
+
+#ifdef Py_GIL_DISABLED
+ static PyMutex getpwall_mutex = {0};
+ PyMutex_Lock(&getpwall_mutex);
+#endif
+ int failure = 0;
+ PyObject *v = NULL;
setpwent();
while ((p = getpwent()) != NULL) {
- PyObject *v = mkpwent(module, p);
+ v = mkpwent(module, p);
if (v == NULL || PyList_Append(d, v) != 0) {
- Py_XDECREF(v);
- Py_DECREF(d);
- endpwent();
- return NULL;
+ /* NOTE: cannot dec-ref here, while holding the mutex. */
+ failure = 1;
+ goto done;
}
Py_DECREF(v);
}
+
+done:
endpwent();
+#ifdef Py_GIL_DISABLED
+ PyMutex_Unlock(&getpwall_mutex);
+#endif
+ if (failure) {
+ Py_XDECREF(v);
+ Py_CLEAR(d);
+ }
return d;
}
#endif
diff --git a/Modules/sha1module.c b/Modules/sha1module.c
index f4a00cdb422..faa9dcccc57 100644
--- a/Modules/sha1module.c
+++ b/Modules/sha1module.c
@@ -8,13 +8,13 @@
Andrew Kuchling (amk@amk.ca)
Greg Stein (gstein@lyra.org)
Trevor Perrin (trevp@trevp.net)
+ Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
Licensed to PSF under a Contributor Agreement.
*/
-/* SHA1 objects */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
@@ -24,32 +24,23 @@
#include "pycore_strhex.h" // _Py_strhex()
#include "pycore_typeobject.h" // _PyType_GetModuleState()
-/*[clinic input]
-module _sha1
-class SHA1Type "SHA1object *" "&PyType_Type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3dc9a20d1becb759]*/
+#include "_hacl/Hacl_Hash_SHA1.h"
/* The SHA1 block size and message digest sizes, in bytes */
#define SHA1_BLOCKSIZE 64
#define SHA1_DIGESTSIZE 20
-#include "_hacl/Hacl_Hash_SHA1.h"
+// --- Module objects ---------------------------------------------------------
typedef struct {
- PyObject_HEAD
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
- PyThread_type_lock lock;
+ HASHLIB_OBJECT_HEAD
Hacl_Hash_SHA1_state_t *hash_state;
} SHA1object;
#define _SHA1object_CAST(op) ((SHA1object *)(op))
-#include "clinic/sha1module.c.h"
-
+// --- Module state -----------------------------------------------------------
typedef struct {
PyTypeObject* sha1_type;
@@ -63,6 +54,18 @@ sha1_get_state(PyObject *module)
return (SHA1State *)state;
}
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _sha1
+class SHA1Type "SHA1object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3dc9a20d1becb759]*/
+
+#include "clinic/sha1module.c.h"
+
+// --- SHA-1 object interface configuration -----------------------------------
+
static SHA1object *
newSHA1object(SHA1State *st)
{
@@ -121,9 +124,9 @@ SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls)
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
newobj->hash_state = Hacl_Hash_SHA1_copy(self->hash_state);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (newobj->hash_state == NULL) {
Py_DECREF(newobj);
return PyErr_NoMemory();
@@ -142,9 +145,9 @@ SHA1Type_digest_impl(SHA1object *self)
/*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA1_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE);
}
@@ -159,9 +162,9 @@ SHA1Type_hexdigest_impl(SHA1object *self)
/*[clinic end generated code: output=4161fd71e68c6659 input=97691055c0c74ab0]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA1_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, SHA1_DIGESTSIZE);
}
@@ -198,22 +201,11 @@ SHA1Type_update_impl(SHA1object *self, PyObject *obj)
/*[clinic end generated code: output=cdc8e0e106dbec5f input=aad8e07812edbba3]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- update(self->hash_state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update(self->hash_state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update(self->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -272,19 +264,25 @@ static PyType_Spec sha1_type_spec = {
/*[clinic input]
_sha1.sha1
- string: object(c_default="NULL") = b''
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string as string_obj: object(c_default="NULL") = None
Return a new SHA1 hash object; optionally initialized with a string.
[clinic start generated code]*/
static PyObject *
-_sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity)
-/*[clinic end generated code: output=6f8b3af05126e18e input=bd54b68e2bf36a8a]*/
+_sha1_sha1_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj)
+/*[clinic end generated code: output=0d453775924f88a7 input=807f25264e0ac656]*/
{
SHA1object *new;
Py_buffer buf;
+ PyObject *string;
+ if (_Py_hashlib_data_argument(&string, data, string_obj) < 0) {
+ return NULL;
+ }
if (string) {
GET_BUFFER_VIEW_OR_ERROUT(string, &buf);
@@ -308,16 +306,12 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity)
return PyErr_NoMemory();
}
if (string) {
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- update(new->hash_state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update(new->hash_state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ update(new->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
diff --git a/Modules/sha2module.c b/Modules/sha2module.c
index e88d7cb2d45..36300ba899f 100644
--- a/Modules/sha2module.c
+++ b/Modules/sha2module.c
@@ -9,32 +9,25 @@
Greg Stein (gstein@lyra.org)
Trevor Perrin (trevp@trevp.net)
Jonathan Protzenko (jonathan@protzenko.fr)
+ Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
Licensed to PSF under a Contributor Agreement.
*/
-/* SHA objects */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
-#include "pycore_bitutils.h" // _Py_bswap32()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "pycore_strhex.h" // _Py_strhex()
#include "hashlib.h"
-/*[clinic input]
-module _sha2
-class SHA256Type "SHA256object *" "&PyType_Type"
-class SHA512Type "SHA512object *" "&PyType_Type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b5315a7b611c9afc]*/
-
+#include "_hacl/Hacl_Hash_SHA2.h"
/* The SHA block sizes and maximum message digest sizes, in bytes */
@@ -43,34 +36,26 @@ class SHA512Type "SHA512object *" "&PyType_Type"
#define SHA512_BLOCKSIZE 128
#define SHA512_DIGESTSIZE 64
-/* Our SHA2 implementations defer to the HACL* verified library. */
-
-#include "_hacl/Hacl_Hash_SHA2.h"
+// --- Module objects ---------------------------------------------------------
// TODO: Get rid of int digestsize in favor of Hacl state info?
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
int digestsize;
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
Hacl_Hash_SHA2_state_t_256 *state;
} SHA256object;
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
int digestsize;
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
Hacl_Hash_SHA2_state_t_512 *state;
} SHA512object;
#define _SHA256object_CAST(op) ((SHA256object *)(op))
#define _SHA512object_CAST(op) ((SHA512object *)(op))
-#include "clinic/sha2module.c.h"
+// --- Module state -----------------------------------------------------------
/* We shall use run-time type information in the remainder of this module to
* tell apart SHA2-224 and SHA2-256 */
@@ -89,6 +74,19 @@ sha2_get_state(PyObject *module)
return (sha2_state *)state;
}
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _sha2
+class SHA256Type "SHA256object *" "&PyType_Type"
+class SHA512Type "SHA512object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b5315a7b611c9afc]*/
+
+#include "clinic/sha2module.c.h"
+
+// --- SHA-2 object interface -------------------------------------------------
+
static int
SHA256copy(SHA256object *src, SHA256object *dest)
{
@@ -272,9 +270,9 @@ SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls)
}
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
rc = SHA256copy(self, newobj);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(newobj);
return NULL;
@@ -309,9 +307,9 @@ SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls)
}
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
rc = SHA512copy(self, newobj);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(newobj);
return NULL;
@@ -331,11 +329,11 @@ SHA256Type_digest_impl(SHA256object *self)
{
uint8_t digest[SHA256_DIGESTSIZE];
assert(self->digestsize <= SHA256_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
// HACL* performs copies under the hood so that self->state remains valid
// after this call.
Hacl_Hash_SHA2_digest_256(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, self->digestsize);
}
@@ -351,11 +349,11 @@ SHA512Type_digest_impl(SHA512object *self)
{
uint8_t digest[SHA512_DIGESTSIZE];
assert(self->digestsize <= SHA512_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
// HACL* performs copies under the hood so that self->state remains valid
// after this call.
Hacl_Hash_SHA2_digest_512(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, self->digestsize);
}
@@ -371,9 +369,9 @@ SHA256Type_hexdigest_impl(SHA256object *self)
{
uint8_t digest[SHA256_DIGESTSIZE];
assert(self->digestsize <= SHA256_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA2_digest_256(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, self->digestsize);
}
@@ -389,9 +387,9 @@ SHA512Type_hexdigest_impl(SHA512object *self)
{
uint8_t digest[SHA512_DIGESTSIZE];
assert(self->digestsize <= SHA512_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA2_digest_512(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, self->digestsize);
}
@@ -409,22 +407,11 @@ SHA256Type_update_impl(SHA256object *self, PyObject *obj)
/*[clinic end generated code: output=dc58a580cf8905a5 input=b2d449d5b30f0f5a]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- update_256(self->state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update_256(self->state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update_256(self->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -443,22 +430,11 @@ SHA512Type_update_impl(SHA512object *self, PyObject *obj)
/*[clinic end generated code: output=9af211766c0b7365 input=ded2b46656566283]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- update_512(self->state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update_512(self->state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update_512(self->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -594,18 +570,24 @@ static PyType_Spec sha512_type_spec = {
/*[clinic input]
_sha2.sha256
- string: object(c_default="NULL") = b''
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string as string_obj: object(c_default="NULL") = None
Return a new SHA-256 hash object; optionally initialized with a string.
[clinic start generated code]*/
static PyObject *
-_sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity)
-/*[clinic end generated code: output=243c9dd289931f87 input=6249da1de607280a]*/
+_sha2_sha256_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj)
+/*[clinic end generated code: output=49828a7bcd418f45 input=9ce1d70e669abc14]*/
{
Py_buffer buf;
+ PyObject *string;
+ if (_Py_hashlib_data_argument(&string, data, string_obj) < 0) {
+ return NULL;
+ }
if (string) {
GET_BUFFER_VIEW_OR_ERROUT(string, &buf);
@@ -632,16 +614,12 @@ _sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity)
return PyErr_NoMemory();
}
if (string) {
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- update_256(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_256(new->state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ update_256(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -651,18 +629,25 @@ _sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity)
/*[clinic input]
_sha2.sha224
- string: object(c_default="NULL") = b''
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string as string_obj: object(c_default="NULL") = None
Return a new SHA-224 hash object; optionally initialized with a string.
[clinic start generated code]*/
static PyObject *
-_sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity)
-/*[clinic end generated code: output=68191f232e4a3843 input=c42bcba47fd7d2b7]*/
+_sha2_sha224_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj)
+/*[clinic end generated code: output=2163cb03b6cf6157 input=612f7682a889bc2a]*/
{
Py_buffer buf;
+ PyObject *string;
+ if (_Py_hashlib_data_argument(&string, data, string_obj) < 0) {
+ return NULL;
+ }
+
if (string) {
GET_BUFFER_VIEW_OR_ERROUT(string, &buf);
}
@@ -687,16 +672,12 @@ _sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity)
return PyErr_NoMemory();
}
if (string) {
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- update_256(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_256(new->state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ update_256(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -706,19 +687,25 @@ _sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity)
/*[clinic input]
_sha2.sha512
- string: object(c_default="NULL") = b''
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string as string_obj: object(c_default="NULL") = None
Return a new SHA-512 hash object; optionally initialized with a string.
[clinic start generated code]*/
static PyObject *
-_sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity)
-/*[clinic end generated code: output=d55c8996eca214d7 input=0576ae2a6ebfad25]*/
+_sha2_sha512_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj)
+/*[clinic end generated code: output=cc3fcfce001a4538 input=19c9f2c06d59563a]*/
{
SHA512object *new;
Py_buffer buf;
+ PyObject *string;
+ if (_Py_hashlib_data_argument(&string, data, string_obj) < 0) {
+ return NULL;
+ }
sha2_state *state = sha2_get_state(module);
@@ -744,16 +731,12 @@ _sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity)
return PyErr_NoMemory();
}
if (string) {
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- update_512(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_512(new->state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ update_512(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -763,19 +746,25 @@ _sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity)
/*[clinic input]
_sha2.sha384
- string: object(c_default="NULL") = b''
+ data: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string as string_obj: object(c_default="NULL") = None
Return a new SHA-384 hash object; optionally initialized with a string.
[clinic start generated code]*/
static PyObject *
-_sha2_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity)
-/*[clinic end generated code: output=b29a0d81d51d1368 input=4e9199d8de0d2f9b]*/
+_sha2_sha384_impl(PyObject *module, PyObject *data, int usedforsecurity,
+ PyObject *string_obj)
+/*[clinic end generated code: output=b6e3db593b5a0330 input=9fd50c942ad9e0bf]*/
{
SHA512object *new;
Py_buffer buf;
+ PyObject *string;
+ if (_Py_hashlib_data_argument(&string, data, string_obj) < 0) {
+ return NULL;
+ }
sha2_state *state = sha2_get_state(module);
@@ -801,16 +790,12 @@ _sha2_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity)
return PyErr_NoMemory();
}
if (string) {
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- update_512(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_512(new->state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ update_512(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
diff --git a/Modules/sha3module.c b/Modules/sha3module.c
index a7edf5c66a1..5764556bb68 100644
--- a/Modules/sha3module.c
+++ b/Modules/sha3module.c
@@ -9,6 +9,7 @@
* Greg Stein (gstein@lyra.org)
* Trevor Perrin (trevp@trevp.net)
* Gregory P. Smith (greg@krypto.org)
+ * Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
*
* Copyright (C) 2012-2022 Christian Heimes (christian@python.org)
* Licensed to PSF under a Contributor Agreement.
@@ -24,8 +25,23 @@
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "hashlib.h"
+#include "_hacl/Hacl_Hash_SHA3.h"
+
+/*
+ * Assert that 'LEN' can be safely casted to uint32_t.
+ *
+ * The 'LEN' parameter should be convertible to Py_ssize_t.
+ */
+#if !defined(NDEBUG) && (PY_SSIZE_T_MAX > UINT32_MAX)
+#define CHECK_HACL_UINT32_T_LENGTH(LEN) assert((LEN) < (Py_ssize_t)UINT32_MAX)
+#else
+#define CHECK_HACL_UINT32_T_LENGTH(LEN)
+#endif
+
#define SHA3_MAX_DIGESTSIZE 64 /* 64 Bytes (512 Bits) for 224 to 512 */
+// --- Module state -----------------------------------------------------------
+
typedef struct {
PyTypeObject *sha3_224_type;
PyTypeObject *sha3_256_type;
@@ -43,33 +59,34 @@ sha3_get_state(PyObject *module)
return (SHA3State *)state;
}
-/*[clinic input]
-module _sha3
-class _sha3.sha3_224 "SHA3object *" "&SHA3_224typ"
-class _sha3.sha3_256 "SHA3object *" "&SHA3_256typ"
-class _sha3.sha3_384 "SHA3object *" "&SHA3_384typ"
-class _sha3.sha3_512 "SHA3object *" "&SHA3_512typ"
-class _sha3.shake_128 "SHA3object *" "&SHAKE128type"
-class _sha3.shake_256 "SHA3object *" "&SHAKE256type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b8a53680f370285a]*/
+// --- Module objects ---------------------------------------------------------
/* The structure for storing SHA3 info */
-#include "_hacl/Hacl_Hash_SHA3.h"
-
typedef struct {
- PyObject_HEAD
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
+ HASHLIB_OBJECT_HEAD
Hacl_Hash_SHA3_state_t *hash_state;
} SHA3object;
#define _SHA3object_CAST(op) ((SHA3object *)(op))
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _sha3
+class _sha3.sha3_224 "SHA3object *" "&PyType_Type"
+class _sha3.sha3_256 "SHA3object *" "&PyType_Type"
+class _sha3.sha3_384 "SHA3object *" "&PyType_Type"
+class _sha3.sha3_512 "SHA3object *" "&PyType_Type"
+class _sha3.shake_128 "SHA3object *" "&PyType_Type"
+class _sha3.shake_256 "SHA3object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ccd22550c7fb99bf]*/
+
#include "clinic/sha3module.c.h"
+// --- SHA-3 object interface -------------------------------------------------
+
static SHA3object *
newSHA3object(PyTypeObject *type)
{
@@ -105,18 +122,25 @@ sha3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *buf, Py_ssize_t len)
/*[clinic input]
@classmethod
_sha3.sha3_224.__new__ as py_sha3_new
- data: object(c_default="NULL") = b''
- /
+
+ data as data_obj: object(c_default="NULL") = b''
*
usedforsecurity: bool = True
+ string: object(c_default="NULL") = None
Return a new SHA3 hash object.
[clinic start generated code]*/
static PyObject *
-py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity)
-/*[clinic end generated code: output=90409addc5d5e8b0 input=637e5f8f6a93982a]*/
+py_sha3_new_impl(PyTypeObject *type, PyObject *data_obj, int usedforsecurity,
+ PyObject *string)
+/*[clinic end generated code: output=dcec1eca20395f2a input=c106e0b4e2d67d58]*/
{
+ PyObject *data;
+ if (_Py_hashlib_data_argument(&data, data_obj, string) < 0) {
+ return NULL;
+ }
+
Py_buffer buf = {NULL, NULL};
SHA3State *state = _PyType_GetModuleState(type);
SHA3object *self = newSHA3object(type);
@@ -156,16 +180,12 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity)
if (data) {
GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- sha3_update(self->hash_state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- sha3_update(self->hash_state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ sha3_update(self->hash_state, buf.buf, buf.len)
+ );
}
PyBuffer_Release(&buf);
@@ -219,21 +239,22 @@ SHA3_traverse(PyObject *self, visitproc visit, void *arg)
/*[clinic input]
_sha3.sha3_224.copy
+ cls: defining_class
+
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
-_sha3_sha3_224_copy_impl(SHA3object *self)
-/*[clinic end generated code: output=6c537411ecdcda4c input=93a44aaebea51ba8]*/
+_sha3_sha3_224_copy_impl(SHA3object *self, PyTypeObject *cls)
+/*[clinic end generated code: output=13958b44c244013e input=7134b4dc0a2fbcac]*/
{
SHA3object *newobj;
-
- if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) {
+ if ((newobj = newSHA3object(cls)) == NULL) {
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
newobj->hash_state = Hacl_Hash_SHA3_copy(self->hash_state);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (newobj->hash_state == NULL) {
Py_DECREF(newobj);
return PyErr_NoMemory();
@@ -255,9 +276,9 @@ _sha3_sha3_224_digest_impl(SHA3object *self)
unsigned char digest[SHA3_MAX_DIGESTSIZE];
// This function errors out if the algorithm is SHAKE. Here, we know this
// not to be the case, and therefore do not perform error checking.
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
(void)Hacl_Hash_SHA3_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest,
Hacl_Hash_SHA3_hash_len(self->hash_state));
}
@@ -274,9 +295,9 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self)
/*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/
{
unsigned char digest[SHA3_MAX_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
(void)Hacl_Hash_SHA3_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest,
Hacl_Hash_SHA3_hash_len(self->hash_state));
}
@@ -296,22 +317,11 @@ _sha3_sha3_224_update_impl(SHA3object *self, PyObject *data)
/*[clinic end generated code: output=390b7abf7c9795a5 input=a887f54dcc4ae227]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- sha3_update(self->hash_state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- sha3_update(self->hash_state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ sha3_update(self->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -465,71 +475,94 @@ SHA3_TYPE_SPEC(sha3_384_spec, "sha3_384", sha3_384_slots);
SHA3_TYPE_SLOTS(sha3_512_slots, sha3_512__doc__, SHA3_methods, SHA3_getseters);
SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots);
-static PyObject *
-_SHAKE_digest(PyObject *op, unsigned long digestlen, int hex)
+static int
+sha3_shake_check_digest_length(Py_ssize_t length)
{
- unsigned char *digest = NULL;
- PyObject *result = NULL;
- SHA3object *self = _SHA3object_CAST(op);
-
- if (digestlen >= (1 << 29)) {
- PyErr_SetString(PyExc_ValueError, "length is too large");
- return NULL;
- }
- digest = (unsigned char*)PyMem_Malloc(digestlen);
- if (digest == NULL) {
- return PyErr_NoMemory();
- }
-
- /* Get the raw (binary) digest value. The HACL functions errors out if:
- * - the algorithm is not shake -- not the case here
- * - the output length is zero -- we follow the existing behavior and return
- * an empty digest, without raising an error */
- if (digestlen > 0) {
- (void)Hacl_Hash_SHA3_squeeze(self->hash_state, digest, digestlen);
- }
- if (hex) {
- result = _Py_strhex((const char *)digest, digestlen);
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative digest length");
+ return -1;
}
- else {
- result = PyBytes_FromStringAndSize((const char *)digest, digestlen);
+ if ((size_t)length >= (1 << 29)) {
+ /*
+ * Raise OverflowError to match the semantics of OpenSSL SHAKE
+ * when the digest length exceeds the range of a 'Py_ssize_t';
+ * the exception message will however be different in this case.
+ */
+ PyErr_SetString(PyExc_OverflowError, "digest length is too large");
+ return -1;
}
- PyMem_Free(digest);
- return result;
+ return 0;
}
/*[clinic input]
_sha3.shake_128.digest
- length: unsigned_long
- /
+ length: Py_ssize_t
Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length)
-/*[clinic end generated code: output=2313605e2f87bb8f input=418ef6a36d2e6082]*/
+_sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length)
+/*[clinic end generated code: output=6c53fb71a6cff0a0 input=be03ade4b31dd54c]*/
{
- return _SHAKE_digest((PyObject *)self, length, 0);
+ if (sha3_shake_check_digest_length(length) < 0) {
+ return NULL;
+ }
+
+ /*
+ * Hacl_Hash_SHA3_squeeze() fails if the algorithm is not SHAKE,
+ * or if the length is 0. In the latter case, we follow OpenSSL's
+ * behavior and return an empty digest, without raising an error.
+ */
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+
+ CHECK_HACL_UINT32_T_LENGTH(length);
+ PyObject *digest = PyBytes_FromStringAndSize(NULL, length);
+ uint8_t *buffer = (uint8_t *)PyBytes_AS_STRING(digest);
+ HASHLIB_ACQUIRE_LOCK(self);
+ (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length);
+ HASHLIB_RELEASE_LOCK(self);
+ return digest;
}
/*[clinic input]
_sha3.shake_128.hexdigest
- length: unsigned_long
- /
+ length: Py_ssize_t
Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
-_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length)
-/*[clinic end generated code: output=bf8e2f1e490944a8 input=69fb29b0926ae321]*/
+_sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length)
+/*[clinic end generated code: output=a27412d404f64512 input=0d84d05d7a8ccd37]*/
{
- return _SHAKE_digest((PyObject *)self, length, 1);
+ if (sha3_shake_check_digest_length(length) < 0) {
+ return NULL;
+ }
+
+ /* See _sha3_shake_128_digest_impl() for the fast path rationale. */
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
+ }
+
+ CHECK_HACL_UINT32_T_LENGTH(length);
+ uint8_t *buffer = PyMem_Malloc(length);
+ if (buffer == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ HASHLIB_ACQUIRE_LOCK(self);
+ (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length);
+ HASHLIB_RELEASE_LOCK(self);
+ PyObject *digest = _Py_strhex((const char *)buffer, length);
+ PyMem_Free(buffer);
+ return digest;
}
static PyObject *
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 47958379263..f3ad01854de 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -111,7 +111,6 @@ Local naming conventions:
#include "pycore_moduleobject.h" // _PyModule_GetState
#include "pycore_time.h" // _PyTime_AsMilliseconds()
#include "pycore_pystate.h" // _Py_AssertHoldsTstate()
-#include "pycore_pyatomic_ft_wrappers.h"
#ifdef _Py_MEMORY_SANITIZER
# include <sanitizer/msan_interface.h>
@@ -565,7 +564,6 @@ static int sock_cloexec_works = -1;
static inline void
set_sock_fd(PySocketSockObject *s, SOCKET_T fd)
{
-#ifdef Py_GIL_DISABLED
#if SIZEOF_SOCKET_T == SIZEOF_INT
_Py_atomic_store_int_relaxed((int *)&s->sock_fd, (int)fd);
#elif SIZEOF_SOCKET_T == SIZEOF_LONG
@@ -575,15 +573,11 @@ set_sock_fd(PySocketSockObject *s, SOCKET_T fd)
#else
#error "Unsupported SIZEOF_SOCKET_T"
#endif
-#else
- s->sock_fd = fd;
-#endif
}
static inline SOCKET_T
get_sock_fd(PySocketSockObject *s)
{
-#ifdef Py_GIL_DISABLED
#if SIZEOF_SOCKET_T == SIZEOF_INT
return (SOCKET_T)_Py_atomic_load_int_relaxed((int *)&s->sock_fd);
#elif SIZEOF_SOCKET_T == SIZEOF_LONG
@@ -593,9 +587,6 @@ get_sock_fd(PySocketSockObject *s)
#else
#error "Unsupported SIZEOF_SOCKET_T"
#endif
-#else
- return s->sock_fd;
-#endif
}
#define _PySocketSockObject_CAST(op) ((PySocketSockObject *)(op))
@@ -638,33 +629,22 @@ _PyLong_##NAME##_Converter(PyObject *obj, void *ptr) \
return 1; \
}
-UNSIGNED_INT_CONVERTER(UInt16, uint16_t)
-UNSIGNED_INT_CONVERTER(UInt32, uint32_t)
-
#if defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS)
# ifdef MS_WINDOWS
UNSIGNED_INT_CONVERTER(NetIfindex, NET_IFINDEX)
# else
- UNSIGNED_INT_CONVERTER(NetIfindex, unsigned int)
+# define _PyLong_NetIfindex_Converter _PyLong_UnsignedInt_Converter
# define NET_IFINDEX unsigned int
# endif
#endif // defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS)
/*[python input]
-class uint16_converter(CConverter):
- type = "uint16_t"
- converter = '_PyLong_UInt16_Converter'
-
-class uint32_converter(CConverter):
- type = "uint32_t"
- converter = '_PyLong_UInt32_Converter'
-
class NET_IFINDEX_converter(CConverter):
type = "NET_IFINDEX"
converter = '_PyLong_NetIfindex_Converter'
[python start generated code]*/
-/*[python end generated code: output=da39a3ee5e6b4b0d input=3de2e4a03fbf83b8]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=1cf809c40a407c34]*/
/*[clinic input]
module _socket
@@ -736,12 +716,6 @@ select_error(void)
# define SOCK_INPROGRESS_ERR EINPROGRESS
#endif
-#ifdef _MSC_VER
-# define SUPPRESS_DEPRECATED_CALL __pragma(warning(suppress: 4996))
-#else
-# define SUPPRESS_DEPRECATED_CALL
-#endif
-
/* Convenience function to raise an error according to errno
and return a NULL pointer from a function. */
@@ -3386,7 +3360,7 @@ sock_setsockopt(PyObject *self, PyObject *args)
&level, &optname, &flag)) {
#ifdef MS_WINDOWS
if (optname == SIO_TCP_SET_ACK_FREQUENCY) {
- int dummy;
+ DWORD dummy;
res = WSAIoctl(get_sock_fd(s), SIO_TCP_SET_ACK_FREQUENCY, &flag,
sizeof(flag), NULL, 0, &dummy, NULL, NULL);
if (res >= 0) {
@@ -4618,55 +4592,62 @@ sock_send_impl(PySocketSockObject *s, void *data)
return (ctx->result >= 0);
}
-/* s.send(data [,flags]) method */
+/*[clinic input]
+_socket.socket.send
+ self as s: self(type="PySocketSockObject *")
+ data as pbuf: Py_buffer
+ flags: int = 0
+ /
+
+Send a data string to the socket.
+
+For the optional flags argument, see the Unix manual.
+Return the number of bytes sent; this may be less than len(data) if the network is busy.
+[clinic start generated code]*/
static PyObject *
-sock_send(PyObject *self, PyObject *args)
-{
- PySocketSockObject *s = _PySocketSockObject_CAST(self);
+_socket_socket_send_impl(PySocketSockObject *s, Py_buffer *pbuf, int flags)
+/*[clinic end generated code: output=3ddf83f17d0c875b input=befe7d7790ccb035]*/
- int flags = 0;
- Py_buffer pbuf;
+{
struct sock_send ctx;
- if (!PyArg_ParseTuple(args, "y*|i:send", &pbuf, &flags))
- return NULL;
-
if (!IS_SELECTABLE(s)) {
- PyBuffer_Release(&pbuf);
return select_error();
}
- ctx.buf = pbuf.buf;
- ctx.len = pbuf.len;
+ ctx.buf = pbuf->buf;
+ ctx.len = pbuf->len;
ctx.flags = flags;
if (sock_call(s, 1, sock_send_impl, &ctx) < 0) {
- PyBuffer_Release(&pbuf);
return NULL;
}
- PyBuffer_Release(&pbuf);
return PyLong_FromSsize_t(ctx.result);
}
-PyDoc_STRVAR(send_doc,
-"send(data[, flags]) -> count\n\
-\n\
-Send a data string to the socket. For the optional flags\n\
-argument, see the Unix manual. Return the number of bytes\n\
-sent; this may be less than len(data) if the network is busy.");
+/*[clinic input]
+_socket.socket.sendall
+ self as s: self(type="PySocketSockObject *")
+ data as pbuf: Py_buffer
+ flags: int = 0
+ /
-/* s.sendall(data [,flags]) method */
+Send a data string to the socket.
+
+For the optional flags argument, see the Unix manual.
+This calls send() repeatedly until all data is sent.
+If an error occurs, it's impossible to tell how much data has been sent.
+[clinic start generated code]*/
static PyObject *
-sock_sendall(PyObject *self, PyObject *args)
-{
- PySocketSockObject *s = _PySocketSockObject_CAST(self);
+_socket_socket_sendall_impl(PySocketSockObject *s, Py_buffer *pbuf,
+ int flags)
+/*[clinic end generated code: output=ec92861424d3faa8 input=732b15b9ca64dce6]*/
+{
char *buf;
Py_ssize_t len, n;
- int flags = 0;
- Py_buffer pbuf;
struct sock_send ctx;
int has_timeout = (s->sock_timeout > 0);
PyTime_t timeout = s->sock_timeout;
@@ -4674,13 +4655,10 @@ sock_sendall(PyObject *self, PyObject *args)
int deadline_initialized = 0;
PyObject *res = NULL;
- if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
- return NULL;
- buf = pbuf.buf;
- len = pbuf.len;
+ buf = pbuf->buf;
+ len = pbuf->len;
if (!IS_SELECTABLE(s)) {
- PyBuffer_Release(&pbuf);
return select_error();
}
@@ -4718,23 +4696,13 @@ sock_sendall(PyObject *self, PyObject *args)
if (PyErr_CheckSignals())
goto done;
} while (len > 0);
- PyBuffer_Release(&pbuf);
res = Py_NewRef(Py_None);
done:
- PyBuffer_Release(&pbuf);
return res;
}
-PyDoc_STRVAR(sendall_doc,
-"sendall(data[, flags])\n\
-\n\
-Send a data string to the socket. For the optional flags\n\
-argument, see the Unix manual. This calls send() repeatedly\n\
-until all data is sent. If an error occurs, it's impossible\n\
-to tell how much data has been sent.");
-
#ifdef HAVE_SENDTO
struct sock_sendto {
@@ -4884,10 +4852,8 @@ sock_sendmsg_iovec(PySocketSockObject *s, PyObject *data_arg,
}
}
for (; ndatabufs < ndataparts; ndatabufs++) {
- if (!PyArg_Parse(PySequence_Fast_GET_ITEM(data_fast, ndatabufs),
- "y*;sendmsg() argument 1 must be an iterable of "
- "bytes-like objects",
- &databufs[ndatabufs]))
+ if (PyObject_GetBuffer(PySequence_Fast_GET_ITEM(data_fast, ndatabufs),
+ &databufs[ndatabufs], PyBUF_SIMPLE) < 0)
goto finally;
iovs[ndatabufs].iov_base = databufs[ndatabufs].buf;
iovs[ndatabufs].iov_len = databufs[ndatabufs].len;
@@ -4909,13 +4875,39 @@ sock_sendmsg_impl(PySocketSockObject *s, void *data)
return (ctx->result >= 0);
}
-/* s.sendmsg(buffers[, ancdata[, flags[, address]]]) method */
+/*[clinic input]
+_socket.socket.sendmsg
+ self as s: self(type="PySocketSockObject *")
+ buffers as data_arg: object
+ ancdata as cmsg_arg: object = NULL
+ flags: int = 0
+ address as addr_arg: object = NULL
+ /
+
+Send normal and ancillary data to the socket.
+
+It gathering the non-ancillary data from a series of buffers
+and concatenating it into a single message.
+The buffers argument specifies the non-ancillary
+data as an iterable of bytes-like objects (e.g. bytes objects).
+The ancdata argument specifies the ancillary data (control messages)
+as an iterable of zero or more tuples (cmsg_level, cmsg_type,
+cmsg_data), where cmsg_level and cmsg_type are integers specifying the
+protocol level and protocol-specific type respectively, and cmsg_data
+is a bytes-like object holding the associated data. The flags
+argument defaults to 0 and has the same meaning as for send(). If
+address is supplied and not None, it sets a destination address for
+the message. The return value is the number of bytes of non-ancillary
+data sent.
+[clinic start generated code]*/
static PyObject *
-sock_sendmsg(PyObject *self, PyObject *args)
-{
- PySocketSockObject *s = _PySocketSockObject_CAST(self);
+_socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg,
+ PyObject *cmsg_arg, int flags,
+ PyObject *addr_arg)
+/*[clinic end generated code: output=3b4cb1110644ce39 input=479c13d90bd2f88b]*/
+{
Py_ssize_t i, ndatabufs = 0, ncmsgs, ncmsgbufs = 0;
Py_buffer *databufs = NULL;
sock_addr_t addrbuf;
@@ -4927,16 +4919,10 @@ sock_sendmsg(PyObject *self, PyObject *args)
} *cmsgs = NULL;
void *controlbuf = NULL;
size_t controllen, controllen_last;
- int addrlen, flags = 0;
- PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL,
- *cmsg_fast = NULL, *retval = NULL;
+ int addrlen;
+ PyObject *cmsg_fast = NULL, *retval = NULL;
struct sock_sendmsg ctx;
- if (!PyArg_ParseTuple(args, "O|OiO:sendmsg",
- &data_arg, &cmsg_arg, &flags, &addr_arg)) {
- return NULL;
- }
-
memset(&msg, 0, sizeof(msg));
/* Parse destination address. */
@@ -5098,22 +5084,6 @@ finally:
return retval;
}
-PyDoc_STRVAR(sendmsg_doc,
-"sendmsg(buffers[, ancdata[, flags[, address]]]) -> count\n\
-\n\
-Send normal and ancillary data to the socket, gathering the\n\
-non-ancillary data from a series of buffers and concatenating it into\n\
-a single message. The buffers argument specifies the non-ancillary\n\
-data as an iterable of bytes-like objects (e.g. bytes objects).\n\
-The ancdata argument specifies the ancillary data (control messages)\n\
-as an iterable of zero or more tuples (cmsg_level, cmsg_type,\n\
-cmsg_data), where cmsg_level and cmsg_type are integers specifying the\n\
-protocol level and protocol-specific type respectively, and cmsg_data\n\
-is a bytes-like object holding the associated data. The flags\n\
-argument defaults to 0 and has the same meaning as for send(). If\n\
-address is supplied and not None, it sets a destination address for\n\
-the message. The return value is the number of bytes of non-ancillary\n\
-data sent.");
#endif /* CMSG_LEN */
#ifdef HAVE_SOCKADDR_ALG
@@ -5450,8 +5420,8 @@ static PyMethodDef sock_methods[] = {
recvfrom_into_doc
},
#endif
- {"send", sock_send, METH_VARARGS, send_doc},
- {"sendall", sock_sendall, METH_VARARGS, sendall_doc},
+ _SOCKET_SOCKET_SEND_METHODDEF
+ _SOCKET_SOCKET_SENDALL_METHODDEF
#ifdef HAVE_SENDTO
{"sendto", sock_sendto, METH_VARARGS, sendto_doc},
#endif
@@ -5471,7 +5441,7 @@ static PyMethodDef sock_methods[] = {
#ifdef CMSG_LEN
{"recvmsg", sock_recvmsg, METH_VARARGS, recvmsg_doc},
{"recvmsg_into", sock_recvmsg_into, METH_VARARGS, recvmsg_into_doc},
- {"sendmsg", sock_sendmsg, METH_VARARGS, sendmsg_doc},
+ _SOCKET_SOCKET_SENDMSG_METHODDEF
#endif
#ifdef HAVE_SOCKADDR_ALG
{
@@ -6215,8 +6185,10 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(netdb_lock, 1);
#endif
- SUPPRESS_DEPRECATED_CALL
+ _Py_COMP_DIAG_PUSH
+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
h = gethostbyname(name);
+ _Py_COMP_DIAG_POP
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
/* Some C libraries would require addr.__ss_family instead of
@@ -6320,8 +6292,10 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(netdb_lock, 1);
#endif
- SUPPRESS_DEPRECATED_CALL
+ _Py_COMP_DIAG_PUSH
+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
h = gethostbyaddr(ap, al, af);
+ _Py_COMP_DIAG_POP
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr), af);
@@ -6738,8 +6712,10 @@ _socket_inet_aton_impl(PyObject *module, const char *ip_addr)
packed_addr = INADDR_BROADCAST;
} else {
- SUPPRESS_DEPRECATED_CALL
+ _Py_COMP_DIAG_PUSH
+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
packed_addr = inet_addr(ip_addr);
+ _Py_COMP_DIAG_POP
if (packed_addr == INADDR_NONE) { /* invalid address */
PyErr_SetString(PyExc_OSError,
@@ -6782,8 +6758,10 @@ _socket_inet_ntoa_impl(PyObject *module, Py_buffer *packed_ip)
memcpy(&packed_addr, packed_ip->buf, packed_ip->len);
PyBuffer_Release(packed_ip);
- SUPPRESS_DEPRECATED_CALL
+ _Py_COMP_DIAG_PUSH
+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
return PyUnicode_FromString(inet_ntoa(packed_addr));
+ _Py_COMP_DIAG_POP
}
#endif // HAVE_INET_NTOA
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
index 63624d511c3..200b2b8c7d8 100644
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -259,7 +259,7 @@ typedef int SOCKET_T;
#endif
// AF_HYPERV is only supported on Windows
-#if defined(AF_HYPERV) && defined(MS_WINDOWS)
+#if defined(AF_HYPERV) && (defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM))
# define HAVE_AF_HYPERV
#endif
diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c
index 9c54af51402..ab20fff1509 100644
--- a/Modules/syslogmodule.c
+++ b/Modules/syslogmodule.c
@@ -56,7 +56,6 @@ Revision history:
#include "Python.h"
#include "osdefs.h" // SEP
-#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString()
#include <syslog.h>
@@ -92,7 +91,7 @@ syslog_get_argv(void)
Py_ssize_t slash;
PyObject *argv;
- if (_PySys_GetOptionalAttrString("argv", &argv) <= 0) {
+ if (PySys_GetOptionalAttrString("argv", &argv) <= 0) {
return NULL;
}
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 1bfbf3f6a0b..3271d87ddc2 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -187,7 +187,7 @@ time_clockid_converter(PyObject *obj, clockid_t *p)
{
#ifdef _AIX
long long clk_id = PyLong_AsLongLong(obj);
-#elif defined(__DragonFly__)
+#elif defined(__DragonFly__) || defined(__CYGWIN__)
long clk_id = PyLong_AsLong(obj);
#else
int clk_id = PyLong_AsInt(obj);
diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c
index 26ac35734fb..0480fb08498 100644
--- a/Modules/xxlimited.c
+++ b/Modules/xxlimited.c
@@ -424,6 +424,13 @@ xx_clear(PyObject *module)
return 0;
}
+static void
+xx_free(void *module)
+{
+ // allow xx_modexec to omit calling xx_clear on error
+ (void)xx_clear((PyObject *)module);
+}
+
static struct PyModuleDef xxmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "xxlimited",
@@ -433,9 +440,7 @@ static struct PyModuleDef xxmodule = {
.m_slots = xx_slots,
.m_traverse = xx_traverse,
.m_clear = xx_clear,
- /* m_free is not necessary here: xx_clear clears all references,
- * and the module state is deallocated along with the module.
- */
+ .m_free = xx_free,
};
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
index d4b4b91697c..f7009364644 100644
--- a/Modules/zlibmodule.c
+++ b/Modules/zlibmodule.c
@@ -17,6 +17,16 @@
#error "At least zlib version 1.2.2.1 is required"
#endif
+#if (SIZEOF_OFF_T == SIZEOF_SIZE_T)
+# define convert_to_z_off_t PyLong_AsSsize_t
+#elif (SIZEOF_OFF_T == SIZEOF_LONG_LONG)
+# define convert_to_z_off_t PyLong_AsLongLong
+#elif (SIZEOF_OFF_T == SIZEOF_LONG)
+# define convert_to_z_off_t PyLong_AsLong
+#else
+# error off_t does not match either size_t, long, or long long!
+#endif
+
// Blocks output buffer wrappers
#include "pycore_blocks_output_buffer.h"
@@ -1877,6 +1887,44 @@ zlib_adler32_impl(PyObject *module, Py_buffer *data, unsigned int value)
}
/*[clinic input]
+zlib.adler32_combine -> unsigned_int
+
+ adler1: unsigned_int(bitwise=True)
+ Adler-32 checksum for sequence A
+
+ adler2: unsigned_int(bitwise=True)
+ Adler-32 checksum for sequence B
+
+ len2: object(subclass_of='&PyLong_Type')
+ Length of sequence B
+ /
+
+Combine two Adler-32 checksums into one.
+
+Given the Adler-32 checksum 'adler1' of a sequence A and the
+Adler-32 checksum 'adler2' of a sequence B of length 'len2',
+return the Adler-32 checksum of A and B concatenated.
+[clinic start generated code]*/
+
+static unsigned int
+zlib_adler32_combine_impl(PyObject *module, unsigned int adler1,
+ unsigned int adler2, PyObject *len2)
+/*[clinic end generated code: output=61842cefb16afb1b input=51bb045c95130c6f]*/
+{
+#if defined(Z_WANT64)
+ z_off64_t len = convert_to_z_off_t(len2);
+#else
+ z_off_t len = convert_to_z_off_t(len2);
+#endif
+ if (PyErr_Occurred()) {
+ return (unsigned int)-1;
+ }
+ return adler32_combine(adler1, adler2, len);
+}
+
+
+
+/*[clinic input]
zlib.crc32 -> unsigned_int
data: Py_buffer
@@ -1923,13 +1971,50 @@ zlib_crc32_impl(PyObject *module, Py_buffer *data, unsigned int value)
return value;
}
+/*[clinic input]
+zlib.crc32_combine -> unsigned_int
+
+ crc1: unsigned_int(bitwise=True)
+ CRC-32 checksum for sequence A
+
+ crc2: unsigned_int(bitwise=True)
+ CRC-32 checksum for sequence B
+
+ len2: object(subclass_of='&PyLong_Type')
+ Length of sequence B
+ /
+
+Combine two CRC-32 checksums into one.
+
+Given the CRC-32 checksum 'crc1' of a sequence A and the
+CRC-32 checksum 'crc2' of a sequence B of length 'len2',
+return the CRC-32 checksum of A and B concatenated.
+[clinic start generated code]*/
+
+static unsigned int
+zlib_crc32_combine_impl(PyObject *module, unsigned int crc1,
+ unsigned int crc2, PyObject *len2)
+/*[clinic end generated code: output=c4def907c602e6eb input=9c8a065d9040dc66]*/
+{
+#if defined(Z_WANT64)
+ z_off64_t len = convert_to_z_off_t(len2);
+#else
+ z_off_t len = convert_to_z_off_t(len2);
+#endif
+ if (PyErr_Occurred()) {
+ return (unsigned int)-1;
+ }
+ return crc32_combine(crc1, crc2, len);
+}
static PyMethodDef zlib_methods[] =
{
ZLIB_ADLER32_METHODDEF
+ ZLIB_ADLER32_COMBINE_METHODDEF
ZLIB_COMPRESS_METHODDEF
ZLIB_COMPRESSOBJ_METHODDEF
ZLIB_CRC32_METHODDEF
+ ZLIB_CRC32_COMBINE_METHODDEF
ZLIB_DECOMPRESS_METHODDEF
ZLIB_DECOMPRESSOBJ_METHODDEF
{NULL, NULL}
@@ -1981,14 +2066,17 @@ static PyType_Spec ZlibDecompressor_type_spec = {
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
.slots = ZlibDecompressor_type_slots,
};
+
PyDoc_STRVAR(zlib_module_documentation,
"The functions in this module allow compression and decompression using the\n"
"zlib library, which is based on GNU zip.\n"
"\n"
"adler32(string[, start]) -- Compute an Adler-32 checksum.\n"
+"adler32_combine(adler1, adler2, len2, /) -- Combine two Adler-32 checksums.\n"
"compress(data[, level]) -- Compress data, with compression level 0-9 or -1.\n"
"compressobj([level[, ...]]) -- Return a compressor object.\n"
"crc32(string[, start]) -- Compute a CRC-32 checksum.\n"
+"crc32_combine(crc1, crc2, len2, /) -- Combine two CRC-32 checksums.\n"
"decompress(string,[wbits],[bufsize]) -- Decompresses a compressed string.\n"
"decompressobj([wbits[, zdict]]) -- Return a decompressor object.\n"
"\n"