commit a5398f7e9f77a3beaecfe8b4a9c926f3d467b5d3 Author: David Malcolm dmalcolm@redhat.com Date: Fri Sep 2 18:21:45 2011 -0400
cpychecker: implement PyStructSequence_New
libcpychecker/refcounts.py | 30 ++++++++ .../refcounts/PyStructSequence/correct/input.c | 75 ++++++++++++++++++++ .../refcounts/PyStructSequence/correct/script.py | 22 ++++++ .../refcounts/PyStructSequence/correct/stdout.txt | 55 ++++++++++++++ 4 files changed, 182 insertions(+), 0 deletions(-) --- diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py index bba1644..5d15477 100644 --- a/libcpychecker/refcounts.py +++ b/libcpychecker/refcounts.py @@ -1216,6 +1216,36 @@ class MyState(State): return [t_success, t_failure]
######################################################################## + # PyStructSequence_* + ######################################################################## + def impl_PyStructSequence_New(self, stmt): + # Declared in structseq.h as: + # PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); + # + # Implemented in Objects/structseq.c + + # From our perspective, this is very similar to _PyObject_New + assert isinstance(stmt, gcc.GimpleCall) + assert isinstance(stmt.fn.operand, gcc.FunctionDecl) + + tp_rvalue = self.eval_rvalue(stmt.args[0], stmt.loc) + + # Success case: allocation and assignment: + s_success, nonnull = self.mkstate_new_ref(stmt, 'PyStructSequence_New') + # ...and set up ob_type on the result object: + ob_type = s_success.make_field_region(nonnull, 'ob_type') + s_success.value_for_region[ob_type] = tp_rvalue + t_success = Transition(self, + s_success, + 'PyStructSequence_New() succeeds') + # Failure case: + t_failure = self.mktrans_assignment(stmt.lhs, + ConcreteValue(stmt.lhs.type, stmt.loc, 0), + 'PyStructSequence_New() fails') + t_failure.dest.set_exception('PyExc_MemoryError') + return [t_success, t_failure] + + ######################################################################## # PyTuple_* ######################################################################## def impl_PyTuple_New(self, stmt): diff --git a/tests/cpychecker/refcounts/PyStructSequence/correct/input.c b/tests/cpychecker/refcounts/PyStructSequence/correct/input.c new file mode 100644 index 0000000..7ed7778 --- /dev/null +++ b/tests/cpychecker/refcounts/PyStructSequence/correct/input.c @@ -0,0 +1,75 @@ +/* + Copyright 2011 David Malcolm dmalcolm@redhat.com + Copyright 2011 Red Hat, Inc. + + This is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + http://www.gnu.org/licenses/. +*/ + +/* + Test of correct reference-handling in usage of the PyStructSequence API +*/ + +#include <Python.h> +#include <structseq.h> /* not pulled in by Python.h */ + +static struct PyStructSequence_Field coord_fields[] = { + {"x", NULL}, + {"y", NULL}, + {0} +}; + +static struct PyStructSequence_Desc coord_desc = { + "Coord", /* name */ + NULL, /* doc */ + coord_fields, + 2 +}; + +PyTypeObject CoordType; + +PyObject * +test(PyObject *self, PyObject *args) +{ + /* + FWIW, this assumes that we called: + PyStructSequence_InitType(&CoordType, &coord_desc); + when initializing the module: + */ + PyObject *obj = PyStructSequence_New(&CoordType); + if (!obj) { + return NULL; + } + + /* + These PyInt_ calls can't fail; the SET_ITEM macros steal the new ref + they give us, so this is correct: + */ + PyStructSequence_SET_ITEM(obj, 0, PyInt_FromLong(0)); + PyStructSequence_SET_ITEM(obj, 1, PyInt_FromLong(0)); + return obj; +} + +static PyMethodDef test_methods[] = { + {"test_method", test, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +/* + PEP-7 +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/tests/cpychecker/refcounts/PyStructSequence/correct/script.py b/tests/cpychecker/refcounts/PyStructSequence/correct/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyStructSequence/correct/script.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2011 David Malcolm dmalcolm@redhat.com +# Copyright 2011 Red Hat, Inc. +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# http://www.gnu.org/licenses/. + +from libcpychecker import main +main(verify_refcounting=True, + dump_traces=True, + show_traces=False) diff --git a/tests/cpychecker/refcounts/PyStructSequence/correct/stdout.txt b/tests/cpychecker/refcounts/PyStructSequence/correct/stdout.txt new file mode 100644 index 0000000..cc91edf --- /dev/null +++ b/tests/cpychecker/refcounts/PyStructSequence/correct/stdout.txt @@ -0,0 +1,55 @@ +Trace 0: + Transitions: + 'PyStructSequence_New() succeeds' + 'taking False path' + 'PyInt_FromLong() succeeds' + 'PyInt_FromLong() succeeds' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=50), region=RegionOnHeap('PyStructSequence_New', gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=50))) + str(): (struct PyObject *)&RegionOnHeap('PyStructSequence_New', gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=50)) from tests/cpychecker/refcounts/PyStructSequence/correct/input.c:50 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=50), region=RegionForGlobal(gcc.VarDecl('CoordType'))) + Region("region-for-arg-gcc.ParmDecl('self')"): + repr(): Region("region-for-arg-gcc.ParmDecl('self')") + str(): Region("region-for-arg-gcc.ParmDecl('self')") + r->ob_refcnt: refs: 0 + N where N >= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=43), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')")) + Region("region-for-arg-gcc.ParmDecl('args')"): + repr(): Region("region-for-arg-gcc.ParmDecl('args')") + str(): Region("region-for-arg-gcc.ParmDecl('args')") + r->ob_refcnt: refs: 0 + N where N >= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=43), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyIntObject allocated at tests/cpychecker/refcounts/PyStructSequence/correct/input.c:59: + repr(): RegionOnHeap('PyIntObject', gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=59)) + str(): PyIntObject allocated at tests/cpychecker/refcounts/PyStructSequence/correct/input.c:59 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=59), region=RegionForGlobal(gcc.VarDecl('PyInt_Type'))) + PyIntObject allocated at tests/cpychecker/refcounts/PyStructSequence/correct/input.c:60: + repr(): RegionOnHeap('PyIntObject', gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=60)) + str(): PyIntObject allocated at tests/cpychecker/refcounts/PyStructSequence/correct/input.c:60 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=60), region=RegionForGlobal(gcc.VarDecl('PyInt_Type'))) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyStructSequence/correct/input.c:44 + +Trace 1: + Transitions: + 'PyStructSequence_New() fails' + 'taking True path' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=52), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyStructSequence/correct/input.c:52 + Region("region-for-arg-gcc.ParmDecl('self')"): + repr(): Region("region-for-arg-gcc.ParmDecl('self')") + str(): Region("region-for-arg-gcc.ParmDecl('self')") + r->ob_refcnt: refs: 0 + N where N >= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=43), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')")) + Region("region-for-arg-gcc.ParmDecl('args')"): + repr(): Region("region-for-arg-gcc.ParmDecl('args')") + str(): Region("region-for-arg-gcc.ParmDecl('args')") + r->ob_refcnt: refs: 0 + N where N >= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyStructSequence/correct/input.c', line=43), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
gcc-python-plugin-commits@lists.stg.fedorahosted.org