[Python-checkins] CVS: python/dist/src/Modules audioop.c,1.44,1.45
Tim Peters
tim_one@users.sourceforge.net
Tue, 04 Dec 2001 22:05:09 -0800
Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv23575/python/Modules
Modified Files:
audioop.c
Log Message:
SF bug 482574: audioop.ratecv crashes.
Bugfix candidate.
A numerically naive computation of output buffer size caused crashes
and spurious MemoryErrors for reasonable arguments.
audioop_ratecv(): Avoid spurious overflow by careful reworking of the
buffer size computations, triggering MemoryError if and only if the
final buffer size can't be represented in a C int (although
PyString_FromStringAndSize may legitimately raise MemoryError even if
it does fit in a C int). All reasonable arguments should work as
intended now, and all unreasonable arguments should be cuaght.
Index: audioop.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/audioop.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -C2 -d -r1.44 -r1.45
*** audioop.c 2000/09/01 23:29:26 1.44
--- audioop.c 2001/12/05 06:05:07 1.45
***************
*** 3,6 ****
--- 3,7 ----
#include "Python.h"
+ #include <math.h>
#if SIZEOF_INT == 4
***************
*** 903,906 ****
--- 904,908 ----
int chan, d, *prev_i, *cur_i, cur_o;
PyObject *state, *samps, *str, *rv = NULL;
+ int size_times_nchannels;
weightA = 1;
***************
*** 937,941 ****
prev_i = (int *) malloc(nchannels * sizeof(int));
cur_i = (int *) malloc(nchannels * sizeof(int));
- len /= size * nchannels; /* # of frames */
if (prev_i == NULL || cur_i == NULL) {
(void) PyErr_NoMemory();
--- 939,942 ----
***************
*** 943,951 ****
}
if (state == Py_None) {
d = -outrate;
for (chan = 0; chan < nchannels; chan++)
prev_i[chan] = cur_i[chan] = 0;
! } else {
if (!PyArg_ParseTuple(state,
"iO!;audioop.ratecv: illegal state argument",
--- 944,964 ----
}
+ size_times_nchannels = size * nchannels;
+ if (size_times_nchannels / nchannels != size) {
+ /* This overflow test is rigorously correct because
+ both multiplicands are >= 1. Use the argument names
+ from the docs for the error msg. */
+ PyErr_SetString(PyExc_OverflowError,
+ "width * nchannels too big for a C int");
+ goto exit;
+ }
+ len /= size_times_nchannels; /* # of frames */
+
if (state == Py_None) {
d = -outrate;
for (chan = 0; chan < nchannels; chan++)
prev_i[chan] = cur_i[chan] = 0;
! }
! else {
if (!PyArg_ParseTuple(state,
"iO!;audioop.ratecv: illegal state argument",
***************
*** 963,970 ****
}
}
! str = PyString_FromStringAndSize(
! NULL, size * nchannels * (len * outrate + inrate - 1) / inrate);
! if (str == NULL)
! goto exit;
ncp = PyString_AsString(str);
--- 976,1026 ----
}
}
!
! /* str <- Space for the output buffer. */
! {
! /* There are len input frames, so we need (mathematically)
! ceiling(len*outrate/inrate) output frames, and each frame
! requires size_times_nchannels bytes. Computing this
! without spurious overflow is the challenge. */
! int ceiling; /* the number of output frames, eventually */
! int nbytes; /* the number of output bytes needed */
! int q = len / inrate;
! int r = len - q * inrate;
! /* Now len = q * inrate + r exactly, so
! len*outrate/inrate =
! (q*inrate+r)*outrate/inrate =
! (q*inrate*outrate + r*outrate)/inrate =
! q*outrate + r*outrate/inrate exactly.
! q*outrate is an exact integer, so the ceiling we're after is
! q*outrate + ceiling(r*outrate/inrate). */
! ceiling = q * outrate;
! if (ceiling / outrate != q) {
! PyErr_SetString(PyExc_MemoryError,
! "not enough memory for output buffer");
! goto exit;
! }
! /* Since r = len % inrate, in particular r < inrate. So
! r * outrate / inrate = (r / inrate) * outrate < outrate,
! so ceiling(r * outrate / inrate) <= outrate: the final
! result fits in an int -- it can't overflow. */
! assert(r < inrate);
! q = (int)ceil((double)r * (double)outrate / (double)inrate);
! assert(q <= outrate);
! ceiling += q;
! if (ceiling < 0) {
! PyErr_SetString(PyExc_MemoryError,
! "not enough memory for output buffer");
! goto exit;
! }
! nbytes = ceiling * size_times_nchannels;
! if (nbytes / size_times_nchannels != ceiling) {
! PyErr_SetString(PyExc_MemoryError,
! "not enough memory for output buffer");
! goto exit;
! }
! str = PyString_FromStringAndSize(NULL, nbytes);
! if (str == NULL)
! goto exit;
! }
ncp = PyString_AsString(str);