From 1d460442e7cc36ea3ddebdd8746888afd7999307 Mon Sep 17 00:00:00 2001 Message-Id: <1d460442e7cc36ea3ddebdd8746888afd7999307.1717929746.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 22 Oct 2019 17:14:46 +0100 Subject: [PATCH] buffer.c: Add a lock count which pins a write-buffer's backing store. Organization: Straylight/Edgeware From: Mark Wooding Python 3's buffer protocol allows a long-term acquisition of a buffer's backing-store address. It would be Bad if one of our `WriteBuffer' objects were to reallocate its backing store while something still thought it had the old address, so keep track of how many times the buffer has been referenced in this way. Nothing actually makes use of this machinery yet, but its time will come. --- buffer.c | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/buffer.c b/buffer.c index 7a3bec7..5731c53 100644 --- a/buffer.c +++ b/buffer.c @@ -34,6 +34,7 @@ typedef struct buf_pyobj { PyObject_HEAD buf b; PyObject *sub; + unsigned lk; } buf_pyobj; static PyTypeObject *rbuf_pytype, *wbuf_pytype; @@ -41,6 +42,7 @@ static PyTypeObject *rbuf_pytype, *wbuf_pytype; #define WBUF_PYCHECK(o) PyObject_TypeCheck((o), wbuf_pytype) #define BUF_B(o) (&((buf_pyobj *)(o))->b) #define BUF_SUB(o) (((buf_pyobj *)(o))->sub) +#define BUF_LK(o) (((buf_pyobj *)(o))->lk) /*----- Exceptions --------------------------------------------------------*/ @@ -62,7 +64,7 @@ static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) q = xmalloc(in.sz); memcpy(q, in.p, in.sz); me = (buf_pyobj *)ty->tp_alloc(ty, 0); - me->sub = 0; + me->sub = 0; me->lk = 0; buf_init(&me->b, q, in.sz); end: return ((PyObject *)me); @@ -70,10 +72,9 @@ end: static void buf_pydealloc(PyObject *me) { - if (BUF_SUB(me)) - Py_DECREF(BUF_SUB(me)); - else - xfree(BBASE(BUF_B(me))); + assert(!BUF_LK(me)); + if (BUF_SUB(me)) Py_DECREF(BUF_SUB(me)); + else xfree(BBASE(BUF_B(me))); FREEOBJ(me); } @@ -140,6 +141,7 @@ BUF_DOSUFFIXES(RBMETH_GETBLK_) b = PyObject_NEW(buf_pyobj, rbuf_pytype); \ b->b = bb; \ b->sub = me; \ + b->lk = 0; \ Py_INCREF(me); \ return ((PyObject *)b); \ end: \ @@ -331,20 +333,27 @@ static const PyTypeObject rbuf_pytype_skel = { /*----- Write buffers -----------------------------------------------------*/ -static void ensure(PyObject *me, size_t n) +static int ensure(PyObject *me, size_t n) { buf *b = BUF_B(me); + size_t nn = BSZ(b); + octet *p; + size_t want = BLEN(b) + n; - if (BLEFT(b) < n) { - size_t nn = BSZ(b); - octet *p; - size_t want = BLEN(b) + n; + if (BLEFT(b) >= n) + return (0); + else if (BUF_LK(me)) + BUFERR("buffer locked"); + else { while (nn < want) nn <<= 1; p = xrealloc(BBASE(b), nn, BSZ(b)); BCUR(b) = p + BLEN(b); BLIM(b) = p + nn; BBASE(b) = p; + return (0); } +end: + return (-1); } static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) @@ -359,7 +368,7 @@ static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) goto end; me = (buf_pyobj *)ty->tp_alloc(ty, 0); p = xmalloc(n); - me->sub = 0; + me->sub = 0; me->lk = 0; buf_init(&me->b, p, n); end: return ((PyObject *)me); @@ -376,7 +385,7 @@ static PyObject *wbmeth_zero(PyObject *me, PyObject *arg) void *p; size_t n; if (!PyArg_ParseTuple(arg, "O&:zero", convszt, &n)) return (0); - ensure(me, n); + if (ensure(me, n)) return (0); p = buf_get(BUF_B(me), n); assert(p && BOK(BUF_B(me))); memset(p, 0, n); RETURN_ME; @@ -386,7 +395,7 @@ static PyObject *wbmeth_put(PyObject *me, PyObject *arg) { struct bin in; if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0); - ensure(me, in.sz); + if (ensure(me, in.sz)) return (0); buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me))); RETURN_ME; } @@ -396,7 +405,7 @@ static PyObject *wbmeth_put(PyObject *me, PyObject *arg) { \ uint##n i; \ if (!PyArg_ParseTuple(arg, "O&:putu" #w, convu##n, &i)) return (0); \ - ensure(me, SZ_##n); \ + if (ensure(me, SZ_##n)) return (0); \ buf_putu##w(BUF_B(me), i); assert(BOK(BUF_B(me))); \ RETURN_ME; \ } @@ -410,7 +419,7 @@ DOUINTCONV(WBMETH_PUTU_) struct bin in; \ if (!PyArg_ParseTuple(arg, "O&:putblk" #w, convbin, &in)) goto end; \ if (MASK##W && in.sz > MASK##W) VALERR("too large"); \ - ensure(me, in.sz + SZ_##n); \ + if (ensure(me, in.sz + SZ_##n)) return (0); \ buf_putmem##w(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me))); \ RETURN_ME; \ end: \ @@ -422,7 +431,7 @@ static PyObject *wbmeth_putmp(PyObject *me, PyObject *arg) { mp *x = 0; if (!PyArg_ParseTuple(arg, "O&:putmp", convmp, &x)) return (0); - ensure(me, mp_octets(x) + 2); + if (ensure(me, mp_octets(x) + 2)) return (0); buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me))); RETURN_ME; } @@ -431,7 +440,7 @@ static PyObject *wbmeth_putgf(PyObject *me, PyObject *arg) { mp *x = 0; if (!PyArg_ParseTuple(arg, "O&:putgf", convgf, &x)) return (0); - ensure(me, mp_octets(x) + 2); + if (ensure(me, mp_octets(x) + 2)) return (0); buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me))); MP_DROP(x); RETURN_ME; @@ -441,7 +450,8 @@ static PyObject *wbmeth_putecpt(PyObject *me, PyObject *arg) { ec pt = EC_INIT; if (!PyArg_ParseTuple(arg, "O&:putecpt", convecpt, &pt)) return (0); - ensure(me, EC_ATINF(&pt) ? 2 : 6 + mp_octets(pt.x) + mp_octets(pt.y)); + if (ensure(me, EC_ATINF(&pt) ? 2 : 6 + mp_octets(pt.x) + mp_octets(pt.y))) + return (0); buf_putec(BUF_B(me), &pt); assert(BOK(BUF_B(me))); EC_DESTROY(&pt); RETURN_ME; @@ -454,7 +464,7 @@ static PyObject *wbmeth_putecptraw(PyObject *me, PyObject *arg) if (!PyArg_ParseTuple(arg, "O!:putecptraw", ecptcurve_pytype, &ptobj)) return (0); EC_OUT(ECPT_C(ptobj), &pt, ECPT_P(ptobj)); - ensure(me, ECPT_C(ptobj)->f->noctets * 2 + 1); + if (ensure(me, ECPT_C(ptobj)->f->noctets * 2 + 1)) return (0); ec_putraw(ECPT_C(ptobj), BUF_B(me), &pt); assert(BOK(BUF_B(me))); EC_DESTROY(&pt); RETURN_ME; @@ -464,7 +474,7 @@ static PyObject *wbmeth_putge(PyObject *me, PyObject *arg) { PyObject *geobj; if (!PyArg_ParseTuple(arg, "O!:putge", ge_pytype, &geobj)) return (0); - ensure(me, GE_G(geobj)->noctets); + if (ensure(me, GE_G(geobj)->noctets)) return (0); G_TOBUF(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me))); RETURN_ME; } @@ -473,7 +483,7 @@ static PyObject *wbmeth_putgeraw(PyObject *me, PyObject *arg) { PyObject *geobj; if (!PyArg_ParseTuple(arg, "O!:putgeraw", ge_pytype, &geobj)) return (0); - ensure(me, GE_G(geobj)->noctets); + if (ensure(me, GE_G(geobj)->noctets)) return (0); G_TORAW(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me))); RETURN_ME; } -- [mdw]