bpo-31862: Port binascii to PEP 489 multiphase initialization (GH-4108)

This commit is contained in:
Marcel Plch 2019-05-22 13:51:26 +02:00 committed by Petr Viktorin
parent 77aa396bb9
commit 33e71e01e9
3 changed files with 118 additions and 34 deletions

View File

@ -473,6 +473,19 @@ class SubinterpreterTest(unittest.TestCase):
self.assertNotEqual(pickle.load(f), id(sys.modules)) self.assertNotEqual(pickle.load(f), id(sys.modules))
self.assertNotEqual(pickle.load(f), id(builtins)) self.assertNotEqual(pickle.load(f), id(builtins))
def test_mutate_exception(self):
"""
Exceptions saved in global module state get shared between
individual module instances. This test checks whether or not
a change in one interpreter's module gets reflected into the
other ones.
"""
import binascii
support.run_in_subinterp("import binascii; binascii.Error.foobar = 'foobar'")
self.assertFalse(hasattr(binascii.Error, "foobar"))
class TestThreadState(unittest.TestCase): class TestThreadState(unittest.TestCase):

View File

@ -0,0 +1,2 @@
Port binascii to PEP 489 multiphase initialization.
Patch by Marcel Plch.

View File

@ -61,8 +61,10 @@
#include "zlib.h" #include "zlib.h"
#endif #endif
static PyObject *Error; typedef struct binascii_state {
static PyObject *Incomplete; PyObject *Error;
PyObject *Incomplete;
} binascii_state;
/* /*
** hqx lookup table, ascii->binary. ** hqx lookup table, ascii->binary.
@ -263,6 +265,7 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
unsigned int leftchar = 0; unsigned int leftchar = 0;
PyObject *rv; PyObject *rv;
Py_ssize_t ascii_len, bin_len; Py_ssize_t ascii_len, bin_len;
binascii_state *state;
ascii_data = data->buf; ascii_data = data->buf;
ascii_len = data->len; ascii_len = data->len;
@ -294,7 +297,11 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
** '`' as zero instead of space. ** '`' as zero instead of space.
*/ */
if ( this_ch < ' ' || this_ch > (' ' + 64)) { if ( this_ch < ' ' || this_ch > (' ' + 64)) {
PyErr_SetString(Error, "Illegal char"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "Illegal char");
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
@ -322,7 +329,11 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
/* Extra '`' may be written as padding in some cases */ /* Extra '`' may be written as padding in some cases */
if ( this_ch != ' ' && this_ch != ' '+64 && if ( this_ch != ' ' && this_ch != ' '+64 &&
this_ch != '\n' && this_ch != '\r' ) { this_ch != '\n' && this_ch != '\r' ) {
PyErr_SetString(Error, "Trailing garbage"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "Trailing garbage");
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
@ -350,6 +361,7 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
int leftbits = 0; int leftbits = 0;
unsigned char this_ch; unsigned char this_ch;
unsigned int leftchar = 0; unsigned int leftchar = 0;
binascii_state *state;
Py_ssize_t bin_len, out_len; Py_ssize_t bin_len, out_len;
_PyBytesWriter writer; _PyBytesWriter writer;
@ -358,7 +370,11 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
bin_len = data->len; bin_len = data->len;
if ( bin_len > 45 ) { if ( bin_len > 45 ) {
/* The 45 is a limit that appears in all uuencode's */ /* The 45 is a limit that appears in all uuencode's */
PyErr_SetString(Error, "At most 45 bytes at once"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "At most 45 bytes at once");
return NULL; return NULL;
} }
@ -445,6 +461,7 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data)
Py_ssize_t ascii_len, bin_len; Py_ssize_t ascii_len, bin_len;
int quad_pos = 0; int quad_pos = 0;
_PyBytesWriter writer; _PyBytesWriter writer;
binascii_state *state;
ascii_data = data->buf; ascii_data = data->buf;
ascii_len = data->len; ascii_len = data->len;
@ -512,19 +529,23 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data)
} }
if (leftbits != 0) { if (leftbits != 0) {
state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
if (leftbits == 6) { if (leftbits == 6) {
/* /*
** There is exactly one extra valid, non-padding, base64 character. ** There is exactly one extra valid, non-padding, base64 character.
** This is an invalid length, as there is no possible input that ** This is an invalid length, as there is no possible input that
** could encoded into such a base64 string. ** could encoded into such a base64 string.
*/ */
PyErr_Format(Error, PyErr_Format(state->Error,
"Invalid base64-encoded string: " "Invalid base64-encoded string: "
"number of data characters (%zd) cannot be 1 more " "number of data characters (%zd) cannot be 1 more "
"than a multiple of 4", "than a multiple of 4",
(bin_data - bin_data_start) / 3 * 4 + 1); (bin_data - bin_data_start) / 3 * 4 + 1);
} else { } else {
PyErr_SetString(Error, "Incorrect padding"); PyErr_SetString(state->Error, "Incorrect padding");
} }
_PyBytesWriter_Dealloc(&writer); _PyBytesWriter_Dealloc(&writer);
return NULL; return NULL;
@ -556,6 +577,7 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline)
unsigned int leftchar = 0; unsigned int leftchar = 0;
Py_ssize_t bin_len, out_len; Py_ssize_t bin_len, out_len;
_PyBytesWriter writer; _PyBytesWriter writer;
binascii_state *state;
bin_data = data->buf; bin_data = data->buf;
bin_len = data->len; bin_len = data->len;
@ -564,7 +586,11 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline)
assert(bin_len >= 0); assert(bin_len >= 0);
if ( bin_len > BASE64_MAXBIN ) { if ( bin_len > BASE64_MAXBIN ) {
PyErr_SetString(Error, "Too much data for base64 line"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "Too much data for base64 line");
return NULL; return NULL;
} }
@ -626,6 +652,7 @@ binascii_a2b_hqx_impl(PyObject *module, Py_buffer *data)
Py_ssize_t len; Py_ssize_t len;
int done = 0; int done = 0;
_PyBytesWriter writer; _PyBytesWriter writer;
binascii_state *state;
ascii_data = data->buf; ascii_data = data->buf;
len = data->len; len = data->len;
@ -649,7 +676,11 @@ binascii_a2b_hqx_impl(PyObject *module, Py_buffer *data)
if ( this_ch == SKIP ) if ( this_ch == SKIP )
continue; continue;
if ( this_ch == FAIL ) { if ( this_ch == FAIL ) {
PyErr_SetString(Error, "Illegal char"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "Illegal char");
_PyBytesWriter_Dealloc(&writer); _PyBytesWriter_Dealloc(&writer);
return NULL; return NULL;
} }
@ -670,7 +701,11 @@ binascii_a2b_hqx_impl(PyObject *module, Py_buffer *data)
} }
if ( leftbits && !done ) { if ( leftbits && !done ) {
PyErr_SetString(Incomplete, state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Incomplete,
"String has incomplete number of bytes"); "String has incomplete number of bytes");
_PyBytesWriter_Dealloc(&writer); _PyBytesWriter_Dealloc(&writer);
return NULL; return NULL;
@ -822,6 +857,7 @@ binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data)
in_data = data->buf; in_data = data->buf;
in_len = data->len; in_len = data->len;
_PyBytesWriter_Init(&writer); _PyBytesWriter_Init(&writer);
binascii_state *state;
assert(in_len >= 0); assert(in_len >= 0);
@ -846,7 +882,11 @@ binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data)
#define INBYTE(b) \ #define INBYTE(b) \
do { \ do { \
if ( --in_len < 0 ) { \ if ( --in_len < 0 ) { \
PyErr_SetString(Incomplete, ""); \ state = PyModule_GetState(module); \
if (state == NULL) { \
return NULL; \
} \
PyErr_SetString(state->Incomplete, ""); \
goto error; \ goto error; \
} \ } \
b = *in_data++; \ b = *in_data++; \
@ -868,7 +908,11 @@ binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data)
/* Note Error, not Incomplete (which is at the end /* Note Error, not Incomplete (which is at the end
** of the string only). This is a programmer error. ** of the string only). This is a programmer error.
*/ */
PyErr_SetString(Error, "Orphaned RLE code at start"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "Orphaned RLE code at start");
goto error; goto error;
} }
*out_data++ = RUNCHAR; *out_data++ = RUNCHAR;
@ -1166,6 +1210,7 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
PyObject *retval; PyObject *retval;
char* retbuf; char* retbuf;
Py_ssize_t i, j; Py_ssize_t i, j;
binascii_state *state;
argbuf = hexstr->buf; argbuf = hexstr->buf;
arglen = hexstr->len; arglen = hexstr->len;
@ -1177,7 +1222,11 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
* raise an exception. * raise an exception.
*/ */
if (arglen % 2) { if (arglen % 2) {
PyErr_SetString(Error, "Odd-length string"); state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error, "Odd-length string");
return NULL; return NULL;
} }
@ -1190,7 +1239,11 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])]; unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])];
unsigned int bot = _PyLong_DigitValue[Py_CHARMASK(argbuf[i+1])]; unsigned int bot = _PyLong_DigitValue[Py_CHARMASK(argbuf[i+1])];
if (top >= 16 || bot >= 16) { if (top >= 16 || bot >= 16) {
PyErr_SetString(Error, state = PyModule_GetState(module);
if (state == NULL) {
return NULL;
}
PyErr_SetString(state->Error,
"Non-hexadecimal digit found"); "Non-hexadecimal digit found");
goto finally; goto finally;
} }
@ -1545,14 +1598,47 @@ static struct PyMethodDef binascii_module_methods[] = {
/* Initialization function for the module (*must* be called PyInit_binascii) */ /* Initialization function for the module (*must* be called PyInit_binascii) */
PyDoc_STRVAR(doc_binascii, "Conversion between binary data and ASCII"); PyDoc_STRVAR(doc_binascii, "Conversion between binary data and ASCII");
static int
binascii_exec(PyObject *m) {
int result;
binascii_state *state = PyModule_GetState(m);
if (state == NULL) {
return -1;
}
state->Error = PyErr_NewException("binascii.Error", PyExc_ValueError, NULL);
if (state->Error == NULL) {
return -1;
}
result = PyModule_AddObject(m, "Error", state->Error);
if (result == -1) {
return -1;
}
state->Incomplete = PyErr_NewException("binascii.Incomplete", NULL, NULL);
if (state->Incomplete == NULL) {
return -1;
}
result = PyModule_AddObject(m, "Incomplete", state->Incomplete);
if (result == -1) {
return -1;
}
return 0;
}
static PyModuleDef_Slot binascii_slots[] = {
{Py_mod_exec, binascii_exec},
{0, NULL}
};
static struct PyModuleDef binasciimodule = { static struct PyModuleDef binasciimodule = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"binascii", "binascii",
doc_binascii, doc_binascii,
-1, sizeof(binascii_state),
binascii_module_methods, binascii_module_methods,
NULL, binascii_slots,
NULL, NULL,
NULL, NULL,
NULL NULL
@ -1561,22 +1647,5 @@ static struct PyModuleDef binasciimodule = {
PyMODINIT_FUNC PyMODINIT_FUNC
PyInit_binascii(void) PyInit_binascii(void)
{ {
PyObject *m, *d; return PyModuleDef_Init(&binasciimodule);
/* Create the module and add the functions */
m = PyModule_Create(&binasciimodule);
if (m == NULL)
return NULL;
d = PyModule_GetDict(m);
Error = PyErr_NewException("binascii.Error", PyExc_ValueError, NULL);
PyDict_SetItemString(d, "Error", Error);
Incomplete = PyErr_NewException("binascii.Incomplete", NULL, NULL);
PyDict_SetItemString(d, "Incomplete", Incomplete);
if (PyErr_Occurred()) {
Py_DECREF(m);
m = NULL;
}
return m;
} }