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.
PyObject_HEAD
buf b;
PyObject *sub;
PyObject_HEAD
buf b;
PyObject *sub;
} buf_pyobj;
static PyTypeObject *rbuf_pytype, *wbuf_pytype;
} buf_pyobj;
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 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 --------------------------------------------------------*/
/*----- Exceptions --------------------------------------------------------*/
q = xmalloc(in.sz);
memcpy(q, in.p, in.sz);
me = (buf_pyobj *)ty->tp_alloc(ty, 0);
q = xmalloc(in.sz);
memcpy(q, in.p, in.sz);
me = (buf_pyobj *)ty->tp_alloc(ty, 0);
+ me->sub = 0; me->lk = 0;
buf_init(&me->b, q, in.sz);
end:
return ((PyObject *)me);
buf_init(&me->b, q, in.sz);
end:
return ((PyObject *)me);
static void buf_pydealloc(PyObject *me)
{
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)));
b = PyObject_NEW(buf_pyobj, rbuf_pytype); \
b->b = bb; \
b->sub = me; \
b = PyObject_NEW(buf_pyobj, rbuf_pytype); \
b->b = bb; \
b->sub = me; \
Py_INCREF(me); \
return ((PyObject *)b); \
end: \
Py_INCREF(me); \
return ((PyObject *)b); \
end: \
/*----- Write buffers -----------------------------------------------------*/
/*----- Write buffers -----------------------------------------------------*/
-static void ensure(PyObject *me, size_t n)
+static int ensure(PyObject *me, size_t n)
+ 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;
while (nn < want) nn <<= 1;
p = xrealloc(BBASE(b), nn, BSZ(b));
BCUR(b) = p + BLEN(b);
BLIM(b) = p + nn;
BBASE(b) = p;
}
static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
}
static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
goto end;
me = (buf_pyobj *)ty->tp_alloc(ty, 0);
p = xmalloc(n);
goto end;
me = (buf_pyobj *)ty->tp_alloc(ty, 0);
p = xmalloc(n);
+ me->sub = 0; me->lk = 0;
buf_init(&me->b, p, n);
end:
return ((PyObject *)me);
buf_init(&me->b, p, n);
end:
return ((PyObject *)me);
void *p;
size_t n;
if (!PyArg_ParseTuple(arg, "O&:zero", convszt, &n)) return (0);
void *p;
size_t n;
if (!PyArg_ParseTuple(arg, "O&:zero", convszt, &n)) return (0);
+ 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;
p = buf_get(BUF_B(me), n); assert(p && BOK(BUF_B(me)));
memset(p, 0, n);
RETURN_ME;
{
struct bin in;
if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0);
{
struct bin in;
if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0);
+ if (ensure(me, in.sz)) return (0);
buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));
RETURN_ME;
}
buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));
RETURN_ME;
}
{ \
uint##n i; \
if (!PyArg_ParseTuple(arg, "O&:putu" #w, convu##n, &i)) return (0); \
{ \
uint##n i; \
if (!PyArg_ParseTuple(arg, "O&:putu" #w, convu##n, &i)) return (0); \
+ if (ensure(me, SZ_##n)) return (0); \
buf_putu##w(BUF_B(me), i); assert(BOK(BUF_B(me))); \
RETURN_ME; \
}
buf_putu##w(BUF_B(me), i); assert(BOK(BUF_B(me))); \
RETURN_ME; \
}
struct bin in; \
if (!PyArg_ParseTuple(arg, "O&:putblk" #w, convbin, &in)) goto end; \
if (MASK##W && in.sz > MASK##W) VALERR("too large"); \
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: \
buf_putmem##w(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me))); \
RETURN_ME; \
end: \
{
mp *x = 0;
if (!PyArg_ParseTuple(arg, "O&:putmp", convmp, &x)) return (0);
{
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;
}
buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me)));
RETURN_ME;
}
{
mp *x = 0;
if (!PyArg_ParseTuple(arg, "O&:putgf", convgf, &x)) return (0);
{
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;
buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me)));
MP_DROP(x);
RETURN_ME;
{
ec pt = EC_INIT;
if (!PyArg_ParseTuple(arg, "O&:putecpt", convecpt, &pt)) return (0);
{
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;
buf_putec(BUF_B(me), &pt); assert(BOK(BUF_B(me)));
EC_DESTROY(&pt);
RETURN_ME;
if (!PyArg_ParseTuple(arg, "O!:putecptraw", ecptcurve_pytype, &ptobj))
return (0);
EC_OUT(ECPT_C(ptobj), &pt, ECPT_P(ptobj));
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;
ec_putraw(ECPT_C(ptobj), BUF_B(me), &pt); assert(BOK(BUF_B(me)));
EC_DESTROY(&pt);
RETURN_ME;
{
PyObject *geobj;
if (!PyArg_ParseTuple(arg, "O!:putge", ge_pytype, &geobj)) return (0);
{
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;
}
G_TOBUF(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me)));
RETURN_ME;
}
{
PyObject *geobj;
if (!PyArg_ParseTuple(arg, "O!:putgeraw", ge_pytype, &geobj)) return (0);
{
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;
}
G_TORAW(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me)));
RETURN_ME;
}