-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
bpo-1635741: Port audioop extension module to multiphase initialization(PEP 489) #18608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
42b2a61
981bac9
b776cb1
8434b61
1a1b56e
cfa67a7
5364b74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Port audioop extension module to multiphase initialization (:pep:`489`). |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -375,15 +375,22 @@ static PyModuleDef audioopmodule; | |
|
||
typedef struct { | ||
PyObject *AudioopError; | ||
} _audioopstate; | ||
} audioop_state; | ||
|
||
#define _audioopstate(o) ((_audioopstate *)PyModule_GetState(o)) | ||
static inline audioop_state * | ||
get_audioop_state(PyObject *module) | ||
{ | ||
void *state = PyModule_GetState(module); | ||
assert(state != NULL); | ||
return (audioop_state *)state; | ||
} | ||
|
||
static int | ||
audioop_check_size(PyObject *module, int size) | ||
{ | ||
if (size < 1 || size > 4) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Size should be 1, 2, 3 or 4"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Size should be 1, 2, 3 or 4"); | ||
return 0; | ||
} | ||
else | ||
|
@@ -396,7 +403,8 @@ audioop_check_parameters(PyObject *module, Py_ssize_t len, int size) | |
if (!audioop_check_size(module, size)) | ||
return 0; | ||
if (len % size != 0) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "not a whole number of frames"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"not a whole number of frames"); | ||
return 0; | ||
} | ||
return 1; | ||
|
@@ -428,7 +436,8 @@ audioop_getsample_impl(PyObject *module, Py_buffer *fragment, int width, | |
if (!audioop_check_parameters(module, fragment->len, width)) | ||
return NULL; | ||
if (index < 0 || index >= fragment->len/width) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Index out of range"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Index out of range"); | ||
return NULL; | ||
} | ||
val = GETRAWSAMPLE(width, fragment->buf, index*width); | ||
|
@@ -619,7 +628,8 @@ audioop_findfit_impl(PyObject *module, Py_buffer *fragment, | |
double sum_ri_2, sum_aij_2, sum_aij_ri, result, best_result, factor; | ||
|
||
if (fragment->len & 1 || reference->len & 1) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Strings should be even-sized"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Strings should be even-sized"); | ||
return NULL; | ||
} | ||
cp1 = (const int16_t *)fragment->buf; | ||
|
@@ -628,7 +638,8 @@ audioop_findfit_impl(PyObject *module, Py_buffer *fragment, | |
len2 = reference->len >> 1; | ||
|
||
if (len1 < len2) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "First sample should be longer"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"First sample should be longer"); | ||
return NULL; | ||
} | ||
sum_ri_2 = _sum2(cp2, cp2, len2); | ||
|
@@ -686,11 +697,13 @@ audioop_findfactor_impl(PyObject *module, Py_buffer *fragment, | |
double sum_ri_2, sum_aij_ri, result; | ||
|
||
if (fragment->len & 1 || reference->len & 1) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Strings should be even-sized"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Strings should be even-sized"); | ||
return NULL; | ||
} | ||
if (fragment->len != reference->len) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Samples should be same size"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Samples should be same size"); | ||
return NULL; | ||
} | ||
cp1 = (const int16_t *)fragment->buf; | ||
|
@@ -730,14 +743,16 @@ audioop_findmax_impl(PyObject *module, Py_buffer *fragment, | |
double result, best_result; | ||
|
||
if (fragment->len & 1) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Strings should be even-sized"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Strings should be even-sized"); | ||
return NULL; | ||
} | ||
cp1 = (const int16_t *)fragment->buf; | ||
len1 = fragment->len >> 1; | ||
|
||
if (length < 0 || len1 < length) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Input sample should be longer"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Input sample should be longer"); | ||
return NULL; | ||
} | ||
|
||
|
@@ -969,7 +984,8 @@ audioop_tomono_impl(PyObject *module, Py_buffer *fragment, int width, | |
if (!audioop_check_parameters(module, len, width)) | ||
return NULL; | ||
if (((len / width) & 1) != 0) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "not a whole number of frames"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"not a whole number of frames"); | ||
return NULL; | ||
} | ||
|
||
|
@@ -1064,7 +1080,8 @@ audioop_add_impl(PyObject *module, Py_buffer *fragment1, | |
if (!audioop_check_parameters(module, fragment1->len, width)) | ||
return NULL; | ||
if (fragment1->len != fragment2->len) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "Lengths should be the same"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"Lengths should be the same"); | ||
return NULL; | ||
} | ||
|
||
|
@@ -1310,7 +1327,8 @@ audioop_ratecv_impl(PyObject *module, Py_buffer *fragment, int width, | |
if (!audioop_check_size(module, width)) | ||
return NULL; | ||
if (nchannels < 1) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "# of channels should be >= 1"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"# of channels should be >= 1"); | ||
return NULL; | ||
} | ||
if (width > INT_MAX / nchannels) { | ||
|
@@ -1323,17 +1341,19 @@ audioop_ratecv_impl(PyObject *module, Py_buffer *fragment, int width, | |
} | ||
bytes_per_frame = width * nchannels; | ||
if (weightA < 1 || weightB < 0) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"weightA should be >= 1, weightB should be >= 0"); | ||
return NULL; | ||
} | ||
assert(fragment->len >= 0); | ||
if (fragment->len % bytes_per_frame != 0) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "not a whole number of frames"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"not a whole number of frames"); | ||
return NULL; | ||
} | ||
if (inrate <= 0 || outrate <= 0) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, "sampling rate not > 0"); | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"sampling rate not > 0"); | ||
return NULL; | ||
} | ||
/* divide inrate and outrate by their greatest common divisor */ | ||
|
@@ -1374,7 +1394,7 @@ audioop_ratecv_impl(PyObject *module, Py_buffer *fragment, int width, | |
&d, &PyTuple_Type, &samps)) | ||
goto exit; | ||
if (PyTuple_Size(samps) != nchannels) { | ||
PyErr_SetString(_audioopstate(module)->AudioopError, | ||
PyErr_SetString(get_audioop_state(module)->AudioopError, | ||
"illegal state argument"); | ||
goto exit; | ||
} | ||
|
@@ -1903,31 +1923,61 @@ static PyMethodDef audioop_methods[] = { | |
}; | ||
|
||
static int | ||
audioop_traverse(PyObject *m, visitproc visit, void *arg) { | ||
_audioopstate *state = _audioopstate(m); | ||
if (state != NULL) | ||
audioop_traverse(PyObject *module, visitproc visit, void *arg) | ||
{ | ||
audioop_state *state = (audioop_state *)PyModule_GetState(module); | ||
if (state) { | ||
Py_VISIT(state->AudioopError); | ||
} | ||
return 0; | ||
} | ||
|
||
static int | ||
audioop_clear(PyObject *m) { | ||
_audioopstate *state = _audioopstate(m); | ||
if (state != NULL) | ||
audioop_clear(PyObject *module) | ||
{ | ||
audioop_state *state = (audioop_state *)PyModule_GetState(module); | ||
if (state) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it really possible that state can be NULL when this function is called? module_clear() doesn't touch module->md_state value. Only module_dealloc() calls PyMem_FREE(m->md_state). But audioop_clear() must not be called on a deallocated module object. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to see this question answered before approving the PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the docs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth us to change this logic as victor said? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I created https://bugs.python.org/issue39824 to propose to change the Python behavior, so modules would not have to handle md_state=NULL anymore. |
||
Py_CLEAR(state->AudioopError); | ||
} | ||
return 0; | ||
} | ||
|
||
static void | ||
audioop_free(void *m) { | ||
audioop_clear((PyObject *)m); | ||
audioop_free(void *module) { | ||
audioop_clear((PyObject *)module); | ||
} | ||
|
||
static int | ||
audioop_exec(PyObject* module) | ||
{ | ||
audioop_state *state = get_audioop_state(module); | ||
|
||
state->AudioopError = PyErr_NewException("audioop.error", NULL, NULL); | ||
if (state->AudioopError == NULL) { | ||
return -1; | ||
} | ||
|
||
Py_INCREF(state->AudioopError); | ||
if (PyModule_AddObject(module, "error", state->AudioopError) < 0) { | ||
Py_DECREF(state->AudioopError); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static PyModuleDef_Slot audioop_slots[] = { | ||
{Py_mod_exec, audioop_exec}, | ||
{0, NULL} | ||
}; | ||
|
||
static struct PyModuleDef audioopmodule = { | ||
PyModuleDef_HEAD_INIT, | ||
"audioop", | ||
NULL, | ||
sizeof(_audioopstate), | ||
sizeof(audioop_state), | ||
audioop_methods, | ||
NULL, | ||
audioop_slots, | ||
audioop_traverse, | ||
audioop_clear, | ||
audioop_free | ||
|
@@ -1936,14 +1986,5 @@ static struct PyModuleDef audioopmodule = { | |
PyMODINIT_FUNC | ||
PyInit_audioop(void) | ||
{ | ||
PyObject *m = PyModule_Create(&audioopmodule); | ||
if (m == NULL) | ||
return NULL; | ||
PyObject *AudioopError = PyErr_NewException("audioop.error", NULL, NULL); | ||
if (AudioopError == NULL) | ||
return NULL; | ||
Py_INCREF(AudioopError); | ||
PyModule_AddObject(m, "error", AudioopError); | ||
_audioopstate(m)->AudioopError = AudioopError; | ||
return m; | ||
return PyModuleDef_Init(&audioopmodule); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really possible that state can be NULL when this function is called?