From fcad8dd3e24286d10ee853f91be2ac21e3dc23c8 Mon Sep 17 00:00:00 2001 From: krangelov Date: Tue, 28 Sep 2021 11:13:45 +0200 Subject: [PATCH] no more space leaks --- src/runtime/python/ffi.c | 63 +++++++++++++++++++++++-------- src/runtime/python/pypgf.c | 6 +++ src/runtime/python/transactions.c | 9 ++++- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/runtime/python/ffi.c b/src/runtime/python/ffi.c index fb091875d..4cfc91083 100644 --- a/src/runtime/python/ffi.c +++ b/src/runtime/python/ffi.c @@ -122,12 +122,18 @@ PyList_AsPgfPrintContext(PyObject *pylist) PyErr_SetString(PyExc_TypeError, "variable argument in context must be a string"); return NULL; } - PgfText *input = PyUnicode_AsPgfText(item); - // TODO a better way to copy into this->name? - PgfPrintContext *this = (PgfPrintContext *)PyMem_RawMalloc(sizeof(PgfPrintContext *) + sizeof(PgfText) + input->size + 1); + if (PyUnicode_READY(item) != 0) { + return NULL; + } + + Py_ssize_t size; + const char *enc = PyUnicode_AsUTF8AndSize(item, &size); + + PgfPrintContext *this = (PgfPrintContext *)PyMem_RawMalloc(sizeof(PgfPrintContext) + size + 1); this->next = ctxt; - memcpy(&this->name, input, sizeof(PgfText)+input->size+1); + this->name.size = size; + memcpy(&this->name.text, enc, size+1); ctxt = this; } @@ -254,6 +260,7 @@ lint(PgfUnmarshaller *this, size_t size, uintmax_t *v) Py_DECREF(i); i = tmp; } + Py_DECREF(intShifter); if (PyErr_Occurred()) { return 0; } @@ -326,42 +333,61 @@ match_lit(PgfMarshaller *this, PgfUnmarshaller *u, PgfLiteral lit) PyObject *pyobj = (PyObject *)lit; if (PyLong_Check(pyobj)) { - PyObject *intShifter = PyLong_FromUnsignedLong(pow(10, floor(log10(ULONG_MAX)))); + PyObject *intShifter = PyLong_FromUnsignedLong(LINT_BASE); // determine size size_t size = 1; - PyObject *x = PyNumber_Absolute(PyNumber_Long(pyobj)); // make a copy, ignore sign + PyObject *x = PyNumber_Absolute(pyobj); // make a copy, ignore sign while (PyObject_RichCompareBool(x, intShifter, Py_GE) == 1) { size++; - x = PyNumber_FloorDivide(x, intShifter); + PyObject *tmp = PyNumber_FloorDivide(x, intShifter); + Py_DECREF(x); + x = tmp; } + Py_DECREF(x); // chop up into chunks, always positive - bool isPos = PyObject_RichCompareBool(pyobj, PyLong_FromLong(0), Py_GE) == 1; - x = PyNumber_Absolute(PyNumber_Long(pyobj)); // make a copy, ignore sign + PyObject *zero = PyLong_FromLong(0); + bool isPos = PyObject_RichCompareBool(pyobj, zero, Py_GE) == 1; + Py_DECREF(zero); + x = PyNumber_Absolute(pyobj); // make a copy, ignore sign uintmax_t *i = PyMem_RawMalloc(sizeof(uintmax_t)*size); // TODO when does this get freed? for (int n = size-1; n > 0; n--) { PyObject *rem = PyNumber_Remainder(x, intShifter); i[n] = PyLong_AsUnsignedLong(rem); - x = PyNumber_FloorDivide(x, intShifter); + Py_DECREF(rem); + PyObject *tmp = PyNumber_FloorDivide(x, intShifter); + Py_DECREF(x); + x = tmp; } + Py_DECREF(intShifter); + // first chunk, re-applying polarity if (isPos) i[0] = PyLong_AsLong(x); else - i[0] = PyLong_AsLong(PyNumber_Negative(x)); + i[0] = -PyLong_AsLong(x); + + Py_DECREF(x); if (PyErr_Occurred()) { return 0; } - return u->vtbl->lint(u, size, i); + + object res = u->vtbl->lint(u, size, i); + + PyMem_RawFree(i); + + return res; } else if (PyFloat_Check(pyobj)) { double d = PyFloat_AsDouble(pyobj); return u->vtbl->lflt(u, d); } else if (PyUnicode_Check(pyobj)) { PgfText *t = PyUnicode_AsPgfText(pyobj); - return u->vtbl->lstr(u, t); + object res = u->vtbl->lstr(u, t); + FreePgfText(t); + return res; } else { PyErr_SetString(PyExc_TypeError, "unable to match on literal"); return 0; @@ -376,7 +402,10 @@ match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr) if (PyObject_TypeCheck(pyobj, &pgf_ExprAbsType)) { ExprAbsObject *eabs = (ExprAbsObject *)expr; long bt = eabs->bind_type == Py_True ? 0 : 1; - return u->vtbl->eabs(u, bt, PyUnicode_AsPgfText(eabs->name), (PgfExpr) eabs->body); + PgfText *name = PyUnicode_AsPgfText(eabs->name); + object res = u->vtbl->eabs(u, bt, name, (PgfExpr) eabs->body); + FreePgfText(name); + return res; } else if (PyObject_TypeCheck(pyobj, &pgf_ExprAppType)) { ExprAppObject *eapp = (ExprAppObject *)expr; @@ -392,7 +421,10 @@ match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr) } else if (PyObject_TypeCheck(pyobj, &pgf_ExprFunType)) { ExprFunObject *efun = (ExprFunObject *)expr; - return u->vtbl->efun(u, PyUnicode_AsPgfText(efun->name)); + PgfText *name = PyUnicode_AsPgfText(efun->name); + object res = u->vtbl->efun(u, name); + FreePgfText(name); + return res; } else if (PyObject_TypeCheck(pyobj, &pgf_ExprVarType)) { ExprVarObject *evar = (ExprVarObject *)expr; @@ -442,6 +474,7 @@ match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty) free(hypos[i].cid); Py_DECREF(hypos[i].type); } + PyMem_Free(hypos); FreePgfText(cat); return res; diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 9c329b8b6..052fcff93 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -150,6 +150,12 @@ PGF_categoryContext(PGFObject *self, PyObject *args) PyObject *contexts = PyList_FromHypos(hypos, n_hypos); + for (size_t i = 0; i < n_hypos; i++) { + free(hypos[i].cid); + Py_DECREF((PyObject *)hypos[i].type); + } + free(hypos); + return contexts; } diff --git a/src/runtime/python/transactions.c b/src/runtime/python/transactions.c index 84a675da7..0c25b76ab 100644 --- a/src/runtime/python/transactions.c +++ b/src/runtime/python/transactions.c @@ -29,6 +29,7 @@ PGF_checkoutBranch(PGFObject *self, PyObject *args) return NULL; } + pgf_free_revision(self->db, self->revision); self->revision = rev; Py_RETURN_TRUE; @@ -198,8 +199,14 @@ Transaction_createCategory(TransactionObject *self, PyObject *args) PgfExn err; pgf_create_category(self->pgf->db, self->revision, catname, n_hypos, context, prob, &marshaller, &err); + FreePgfText(catname); - if (handleError(err) != PGF_EXN_NONE) { + for (Py_ssize_t i = 0; i < n_hypos; i++) { + FreePgfText(context[i].cid); + } + PyMem_Free(context); + + if (handleError(err) != PGF_EXN_NONE) { return NULL; }