cext: use modern buffer protocol in patches()
authorGregory Szorc <gregory.szorc@gmail.com>
Tue, 02 Oct 2018 13:13:03 -0700
changeset 39992 77492c10a35b
parent 39991 a91398dc73ab
child 39993 ec3c06a1c554
cext: use modern buffer protocol in patches() PyObject_AsCharBuffer() is part of the "Old Buffer Protocol," which has been deprecated for years. Let's port away from it. PyBuffer_GetBuffer() must be paired with PyBuffer_Release(), hence the added "goto cleanup" in a failure case. We don't bump the extension version because the API has not changed. Differential Revision: https://phab.mercurial-scm.org/D4840
mercurial/cext/mpatch.c
--- a/mercurial/cext/mpatch.c	Mon Oct 01 14:44:27 2018 -0400
+++ b/mercurial/cext/mpatch.c	Tue Oct 02 13:13:03 2018 -0700
@@ -72,10 +72,10 @@
 {
 	PyObject *text, *bins, *result;
 	struct mpatch_flist *patch;
-	const char *in;
+	Py_buffer buffer;
 	int r = 0;
 	char *out;
-	Py_ssize_t len, outlen, inlen;
+	Py_ssize_t len, outlen;
 
 	if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
 		return NULL;
@@ -87,17 +87,19 @@
 		return text;
 	}
 
-	if (PyObject_AsCharBuffer(text, &in, &inlen))
+	if (PyObject_GetBuffer(text, &buffer, PyBUF_CONTIG_RO)) {
 		return NULL;
+	}
 
 	patch = mpatch_fold(bins, cpygetitem, 0, len);
 	if (!patch) { /* error already set or memory error */
 		if (!PyErr_Occurred())
 			PyErr_NoMemory();
-		return NULL;
+		result = NULL;
+		goto cleanup;
 	}
 
-	outlen = mpatch_calcsize(inlen, patch);
+	outlen = mpatch_calcsize(buffer.len, patch);
 	if (outlen < 0) {
 		r = (int)outlen;
 		result = NULL;
@@ -112,7 +114,7 @@
 	/* clang-format off */
 	{
 		Py_BEGIN_ALLOW_THREADS
-		r = mpatch_apply(out, in, inlen, patch);
+		r = mpatch_apply(out, buffer.buf, buffer.len, patch);
 		Py_END_ALLOW_THREADS
 	}
 	/* clang-format on */
@@ -122,6 +124,7 @@
 	}
 cleanup:
 	mpatch_lfree(patch);
+	PyBuffer_Release(&buffer);
 	if (!result && !PyErr_Occurred())
 		setpyerr(r);
 	return result;