Bug #1515471: string.replace() accepts character buffers again.
Pass the char* and size around rather than PyObject's.
diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py
index 236c529..73447ad 100644
--- a/Lib/test/string_tests.py
+++ b/Lib/test/string_tests.py
@@ -147,8 +147,8 @@
                 else:
                     r2, rem = len(i)+1, 0
                 if rem or r1 != r2:
-                    self.assertEqual(rem, 0)
-                    self.assertEqual(r1, r2)
+                    self.assertEqual(rem, 0, '%s != 0 for %s' % (rem, i))
+                    self.assertEqual(r1, r2, '%s != %s for %s' % (r1, r2, i))
 
     def test_find(self):
         self.checkequal(0, 'abcdefghiabc', 'find', 'abc')
@@ -636,6 +636,11 @@
         EQ("bobobXbobob", "bobobobXbobobob", "replace", "bobob", "bob")
         EQ("BOBOBOB", "BOBOBOB", "replace", "bob", "bobby")
 
+        ba = buffer('a')
+        bb = buffer('b')
+        EQ("bbc", "abc", "replace", ba, bb)
+        EQ("aac", "abc", "replace", bb, ba)
+
         #
         self.checkequal('one@two!three!', 'one!two!three!', 'replace', '!', '@', 1)
         self.checkequal('onetwothree', 'one!two!three!', 'replace', '!', '')
diff --git a/Misc/NEWS b/Misc/NEWS
index dac1129..76b76de 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,8 @@
 Core and builtins
 -----------------
 
+- Bug #1515471: string.replace() accepts character buffers again.
+
 - Add PyErr_WarnEx() so C code can pass the stacklevel to warnings.warn().
   This provides the proper warning for struct.pack().
   PyErr_Warn() is now deprecated in favor of PyErr_WarnEx().
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 92477ee..3f8d2a7 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -2464,11 +2464,11 @@
 }
 
 Py_LOCAL_INLINE(Py_ssize_t)
-countchar(char *target, int target_len, char c, Py_ssize_t maxcount)
+countchar(const char *target, int target_len, char c, Py_ssize_t maxcount)
 {
 	Py_ssize_t count=0;
-	char *start=target;
-	char *end=target+target_len;
+	const char *start=target;
+	const char *end=target+target_len;
 
 	while ( (start=findchar(start, end-start, c)) != NULL ) {
 		count++;
@@ -2480,8 +2480,8 @@
 }
 
 Py_LOCAL(Py_ssize_t)
-findstring(char *target, Py_ssize_t target_len,
-	   char *pattern, Py_ssize_t pattern_len,
+findstring(const char *target, Py_ssize_t target_len,
+	   const char *pattern, Py_ssize_t pattern_len,
 	   Py_ssize_t start,
 	   Py_ssize_t end,
 	   int direction)
@@ -2518,8 +2518,8 @@
 }
 
 Py_LOCAL_INLINE(Py_ssize_t)
-countstring(char *target, Py_ssize_t target_len,
-	    char *pattern, Py_ssize_t pattern_len,
+countstring(const char *target, Py_ssize_t target_len,
+	    const char *pattern, Py_ssize_t pattern_len,
 	    Py_ssize_t start,
 	    Py_ssize_t end,
 	    int direction, Py_ssize_t maxcount)
@@ -2572,16 +2572,15 @@
 /* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
 Py_LOCAL(PyStringObject *)
 replace_interleave(PyStringObject *self,
-		   PyStringObject *to,
+		   const char *to_s, Py_ssize_t to_len,
 		   Py_ssize_t maxcount)
 {
-	char *self_s, *to_s, *result_s;
-	Py_ssize_t self_len, to_len, result_len;
+	char *self_s, *result_s;
+	Py_ssize_t self_len, result_len;
 	Py_ssize_t count, i, product;
 	PyStringObject *result;
 
 	self_len = PyString_GET_SIZE(self);
-	to_len = PyString_GET_SIZE(to);
 	
 	/* 1 at the end plus 1 after every character */
 	count = self_len+1;
@@ -2608,8 +2607,6 @@
 		return NULL;
 
 	self_s = PyString_AS_STRING(self);
-	to_s = PyString_AS_STRING(to);
-	to_len = PyString_GET_SIZE(to);
 	result_s = PyString_AS_STRING(result);
 
 	/* TODO: special case single character, which doesn't need memcpy */
@@ -2677,18 +2674,17 @@
 /* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
 
 Py_LOCAL(PyStringObject *)
-replace_delete_substring(PyStringObject *self, PyStringObject *from,
+replace_delete_substring(PyStringObject *self,
+			 const char *from_s, Py_ssize_t from_len,
 			 Py_ssize_t maxcount) {
-	char *self_s, *from_s, *result_s;
+	char *self_s, *result_s;
 	char *start, *next, *end;
-	Py_ssize_t self_len, from_len, result_len;
+	Py_ssize_t self_len, result_len;
 	Py_ssize_t count, offset;
 	PyStringObject *result;
 
 	self_len = PyString_GET_SIZE(self);
 	self_s = PyString_AS_STRING(self);
-	from_len = PyString_GET_SIZE(from);
-	from_s = PyString_AS_STRING(from);
 
 	count = countstring(self_s, self_len,
 			    from_s, from_len,
@@ -2776,24 +2772,20 @@
 /* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
 Py_LOCAL(PyStringObject *)
 replace_substring_in_place(PyStringObject *self,
-			   PyStringObject *from,
-			   PyStringObject *to,
+			   const char *from_s, Py_ssize_t from_len,
+			   const char *to_s, Py_ssize_t to_len,
 			   Py_ssize_t maxcount)
 {
 	char *result_s, *start, *end;
-	char *self_s, *from_s, *to_s;
-	Py_ssize_t self_len, from_len, offset;
+	char *self_s;
+	Py_ssize_t self_len, offset;
 	PyStringObject *result;
 	
 	/* The result string will be the same size */
 	
 	self_s = PyString_AS_STRING(self);
 	self_len = PyString_GET_SIZE(self);
-	
-	from_s = PyString_AS_STRING(from);
-	from_len = PyString_GET_SIZE(from);
-	to_s = PyString_AS_STRING(to);
-	
+
 	offset = findstring(self_s, self_len,
 			    from_s, from_len,
 			    0, self_len, FORWARD);
@@ -2810,7 +2802,6 @@
 	result_s = PyString_AS_STRING(result);
 	Py_MEMCPY(result_s, self_s, self_len);
 
-	
 	/* change everything in-place, starting with this one */
 	start =  result_s + offset;
 	Py_MEMCPY(start, to_s, from_len);
@@ -2834,12 +2825,12 @@
 Py_LOCAL(PyStringObject *)
 replace_single_character(PyStringObject *self,
 			 char from_c,
-			 PyStringObject *to,
+			 const char *to_s, Py_ssize_t to_len,
 			 Py_ssize_t maxcount)
 {
-	char *self_s, *to_s, *result_s;
+	char *self_s, *result_s;
 	char *start, *next, *end;
-	Py_ssize_t self_len, to_len, result_len;
+	Py_ssize_t self_len, result_len;
 	Py_ssize_t count, product;
 	PyStringObject *result;
 	
@@ -2852,10 +2843,7 @@
 		/* no matches, return unchanged */
 		return return_self(self);
 	}
-	
-	to_s = PyString_AS_STRING(to);
-	to_len = PyString_GET_SIZE(to);
-	
+
 	/* use the difference between current and new, hence the "-1" */
 	/*   result_len = self_len + count * (to_len-1)  */
 	product = count * (to_len-1);
@@ -2904,20 +2892,18 @@
 /* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
 Py_LOCAL(PyStringObject *)
 replace_substring(PyStringObject *self,
-		  PyStringObject *from,
-		  PyStringObject *to,
+		  const char *from_s, Py_ssize_t from_len,
+		  const char *to_s, Py_ssize_t to_len,
 		  Py_ssize_t maxcount) {
-	char *self_s, *from_s, *to_s, *result_s;
+	char *self_s, *result_s;
 	char *start, *next, *end;
-	Py_ssize_t self_len, from_len, to_len, result_len;
+	Py_ssize_t self_len, result_len;
 	Py_ssize_t count, offset, product;
 	PyStringObject *result;
 	
 	self_s = PyString_AS_STRING(self);
 	self_len = PyString_GET_SIZE(self);
-	from_s = PyString_AS_STRING(from);
-	from_len = PyString_GET_SIZE(from);
-	
+
 	count = countstring(self_s, self_len,
 			    from_s, from_len,
 			    0, self_len, FORWARD, maxcount);
@@ -2925,10 +2911,7 @@
 		/* no matches, return unchanged */
 		return return_self(self);
 	}
-	
-	to_s = PyString_AS_STRING(to);
-	to_len = PyString_GET_SIZE(to);
-	
+
 	/* Check for overflow */
 	/*    result_len = self_len + count * (to_len-from_len) */
 	product = count * (to_len-from_len);
@@ -2979,22 +2962,17 @@
 
 Py_LOCAL(PyStringObject *)
 replace(PyStringObject *self,
-	PyStringObject *from,
-	PyStringObject *to,
+	const char *from_s, Py_ssize_t from_len,
+	const char *to_s, Py_ssize_t to_len,
 	Py_ssize_t maxcount)
 {
-	Py_ssize_t from_len, to_len;
-	
 	if (maxcount < 0) {
 		maxcount = PY_SSIZE_T_MAX;
 	} else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) {
 		/* nothing to do; return the original string */
 		return return_self(self);
 	}
-	
-	from_len = PyString_GET_SIZE(from);
-	to_len = PyString_GET_SIZE(to);
-	
+
 	if (maxcount == 0 ||
 	    (from_len == 0 && to_len == 0)) {
 		/* nothing to do; return the original string */
@@ -3007,7 +2985,7 @@
 		/* insert the 'to' string everywhere.   */
 		/*    >>> "Python".replace("", ".")     */
 		/*    '.P.y.t.h.o.n.'                   */
-		return replace_interleave(self, to, maxcount);
+		return replace_interleave(self, to_s, to_len, maxcount);
 	}
 
 	/* Except for "".replace("", "A") == "A" there is no way beyond this */
@@ -3021,9 +2999,9 @@
 		/* delete all occurances of 'from' string */
 		if (from_len == 1) {
 			return replace_delete_single_character(
-				self, PyString_AS_STRING(from)[0], maxcount);
+				self, from_s[0], maxcount);
 		} else {
-			return replace_delete_substring(self, from, maxcount);
+			return replace_delete_substring(self, from_s, from_len, maxcount);
 		}
 	}
 
@@ -3033,22 +3011,22 @@
 		if (from_len == 1) {
 			return replace_single_character_in_place(
 				self,
-				PyString_AS_STRING(from)[0],
-				PyString_AS_STRING(to)[0],
+				from_s[0],
+				to_s[0],
 				maxcount);
 		} else {
 			return replace_substring_in_place(
-				self, from, to, maxcount);
+				self, from_s, from_len, to_s, to_len, maxcount);
 		}
 	}
 
 	/* Otherwise use the more generic algorithms */
 	if (from_len == 1) {
-		return replace_single_character(self, PyString_AS_STRING(from)[0],
-						to, maxcount);
+		return replace_single_character(self, from_s[0],
+						to_s, to_len, maxcount);
 	} else {
 		/* len('from')>=2, len('to')>=1 */
-		return replace_substring(self, from, to, maxcount);
+		return replace_substring(self, from_s, from_len, to_s, to_len, maxcount);
 	}
 }
 
@@ -3064,37 +3042,39 @@
 {
 	Py_ssize_t count = -1;
 	PyObject *from, *to;
-	const char *tmp_s;
-	Py_ssize_t tmp_len;
+	const char *from_s, *to_s;
+	Py_ssize_t from_len, to_len;
 
 	if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
 		return NULL;
 
 	if (PyString_Check(from)) {
-	  /* Can this be made a '!check' after the Unicode check? */
+		from_s = PyString_AS_STRING(from);
+		from_len = PyString_GET_SIZE(from);
 	}
 #ifdef Py_USING_UNICODE
 	if (PyUnicode_Check(from))
 		return PyUnicode_Replace((PyObject *)self,
 					 from, to, count);
 #endif
-	else if (PyObject_AsCharBuffer(from, &tmp_s, &tmp_len))
+	else if (PyObject_AsCharBuffer(from, &from_s, &from_len))
 		return NULL;
 
 	if (PyString_Check(to)) {
-	  /* Can this be made a '!check' after the Unicode check? */
+		to_s = PyString_AS_STRING(to);
+		to_len = PyString_GET_SIZE(to);
 	}
 #ifdef Py_USING_UNICODE
 	else if (PyUnicode_Check(to))
 		return PyUnicode_Replace((PyObject *)self,
 					 from, to, count);
 #endif
-	else if (PyObject_AsCharBuffer(to, &tmp_s, &tmp_len))
+	else if (PyObject_AsCharBuffer(to, &to_s, &to_len))
 		return NULL;
 
 	return (PyObject *)replace((PyStringObject *) self,
-				   (PyStringObject *) from,
-				   (PyStringObject *) to, count);
+				   from_s, from_len,
+				   to_s, to_len, count);
 }
 
 /** End DALKE **/