From eb4b7bad336481a34b2db01cbea809de726f9698 Mon Sep 17 00:00:00 2001
From: Tim Peters <tim.peters@gmail.com>
Date: Fri, 7 Dec 2001 00:37:39 +0000
Subject: audioop_ratecv() again:  settle for a sloppier upper bound that's
 less obnoxious to compute and easier to explain.  No compromise on safety.

---
 Modules/audioop.c | 53 +++++++++++++++++++----------------------------------
 1 file changed, 19 insertions(+), 34 deletions(-)

diff --git a/Modules/audioop.c b/Modules/audioop.c
index d23ee2a..d9a398f 100644
--- a/Modules/audioop.c
+++ b/Modules/audioop.c
@@ -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);
 
-- 
cgit v0.12

