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
--- 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;