]> granicus.if.org Git - python/commitdiff
audioop_ratecv() again: settle for a sloppier upper bound that's less
authorTim Peters <tim.peters@gmail.com>
Fri, 7 Dec 2001 00:37:39 +0000 (00:37 +0000)
committerTim Peters <tim.peters@gmail.com>
Fri, 7 Dec 2001 00:37:39 +0000 (00:37 +0000)
obnoxious to compute and easier to explain.  No compromise on safety.

Modules/audioop.c

index d23ee2aafc9ba8125252b96a6eb94ffca07c7412..d9a398fc0bfa2272e3a5a136a7df8b96ee1bba9c 100644 (file)
@@ -2,7 +2,6 @@
 /* audioopmodule - Module to detect peak values in arrays */
 
 #include "Python.h"
-#include <math.h>
 
 #if SIZEOF_INT == 4
 typedef int Py_Int32;
@@ -981,46 +980,32 @@ audioop_ratecv(PyObject *self, PyObject *args)
                /* There are len input frames, so we need (mathematically)
                   ceiling(len*outrate/inrate) output frames, and each frame
                   requires bytes_per_frame bytes.  Computing this
-                  without spurious overflow is the challenge. */
-               int ceiling;   /* the number of output frames, eventually */
+                  without spurious overflow is the challenge; we can
+                  settle for a reasonable upper bound, though. */
+               int ceiling;   /* the number of output frames */
                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;
-               }
+               /* Now len = q * inrate + r exactly (with r = len % inrate),
+                  and this is less than q * inrate + inrate = (q+1)*inrate.
+                  So a reasonable upper bound on len*outrate/inrate is
+                  ((q+1)*inrate)*outrate/inrate =
+                  (q+1)*outrate.
+               */
+               ceiling = (q+1) * outrate;
                nbytes = ceiling * bytes_per_frame;
-               if (nbytes / bytes_per_frame != ceiling) {
+               /* See whether anything overflowed; if not, get the space. */
+               if (q+1 < 0 ||
+                   ceiling / outrate != q+1 ||
+                   nbytes / bytes_per_frame != ceiling)
+                       str = NULL;
+               else
+                       str = PyString_FromStringAndSize(NULL, nbytes);
+
+               if (str == NULL) {
                        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);