From: Mark Wooding Date: Tue, 22 Oct 2019 16:14:46 +0000 (+0100) Subject: buffer.c: Add a lock count which pins a write-buffer's backing store. X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/commitdiff_plain/1d460442e7cc36ea3ddebdd8746888afd7999307?ds=sidebyside buffer.c: Add a lock count which pins a write-buffer's backing store. 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. --- 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; }