commit b3e293815bc7e5fb2c404365a5fb84155ff1e2f5 Author: David Malcolm dmalcolm@redhat.com Date: Fri Sep 2 13:25:11 2011 -0400
cpychecker: implement refcount tracking for PyArg_ParseTupleAndKeywords
libcpychecker/refcounts.py | 20 ++++++- .../PyArg_ParseTupleAndKeywords/correct_O/input.c | 58 ++++++++++++++++++++ .../correct_O/script.py | 22 ++++++++ .../correct_O/stdout.txt | 53 ++++++++++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) --- diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py index e90fd21..1e83a73 100644 --- a/libcpychecker/refcounts.py +++ b/libcpychecker/refcounts.py @@ -660,9 +660,9 @@ class MyState(State): return self.make_transitions_for_fncall(stmt, s_success, s_failure)
def impl_PyArg_ParseTuple(self, stmt): - # Decl: + # Declared in modsupport.h: # PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...) Py_FORMAT_PARSETUPLE(PyArg_ParseTuple, 2, 3); - # Also: + # Also, with #ifdef PY_SSIZE_T_CLEAN # #define PyArg_ParseTuple _PyArg_ParseTuple_SizeT
args = self.eval_stmt_args(stmt) @@ -671,6 +671,22 @@ class MyState(State): v_varargs = args[2:] return self._handle_PyArg_function(stmt, v_fmt, v_varargs, with_size_t=False)
+ def impl_PyArg_ParseTupleAndKeywords(self, stmt): + # Declared in modsupport.h: + # PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, + # const char *, char **, ...); + # + # Also, with #ifdef PY_SSIZE_T_CLEAN + # #define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT + + args = self.eval_stmt_args(stmt) + v_args = args[0] + v_kwargs = args[1] + v_fmt = args[2] + v_keywords = args[3] + v_varargs = args[4:] + return self._handle_PyArg_function(stmt, v_fmt, v_varargs, with_size_t=False) +
######################################################################## # PyDict_* diff --git a/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c b/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c new file mode 100644 index 0000000..eded3a5 --- /dev/null +++ b/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c @@ -0,0 +1,58 @@ +/* + 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/. +*/ + +#include <Python.h> + +/* + Test of correct reference-handling in a call to PyArg_ParseTupleAndKeywords + that uses the "O" format code +*/ + +PyObject * +test(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *obj; + char *keywords[] = {"object", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O:test", keywords, + &obj)) { + return NULL; + } + + /* + We now have a borrowed non-NULL ref to "obj". + + To correctly use it as the return value, we need to INCREF it: + */ + Py_INCREF(obj); + return obj; +} +static PyMethodDef test_methods[] = { + {"test_method", (PyCFunction)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/PyArg_ParseTupleAndKeywords/correct_O/script.py b/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/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/PyArg_ParseTupleAndKeywords/correct_O/stdout.txt b/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/stdout.txt new file mode 100644 index 0000000..47759d9 --- /dev/null +++ b/tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/stdout.txt @@ -0,0 +1,53 @@ +Trace 0: + Transitions: + 'PyArg_ParseTupleAndKeywords() succeeds' + 'taking False path' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=33), region=RegionOnHeap('object from arg "O"', gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=33))) + str(): (struct PyObject *)&RegionOnHeap('object from arg "O"', gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=33)) from tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c:33 + r->ob_refcnt: unknown Py_ssize_t from tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c:44 + r->ob_type: None + 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/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=28), 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/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Region("region-for-arg-gcc.ParmDecl('kwargs')"): + repr(): Region("region-for-arg-gcc.ParmDecl('kwargs')") + str(): Region("region-for-arg-gcc.ParmDecl('kwargs')") + r->ob_refcnt: refs: 0 + N where N >= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('kwargs')")) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c:29 + +Trace 1: + Transitions: + 'PyArg_ParseTupleAndKeywords() fails' + 'taking True path' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=36), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c:36 + 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/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=28), 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/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Region("region-for-arg-gcc.ParmDecl('kwargs')"): + repr(): Region("region-for-arg-gcc.ParmDecl('kwargs')") + str(): Region("region-for-arg-gcc.ParmDecl('kwargs')") + r->ob_refcnt: refs: 0 + N where N >= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('kwargs')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_TypeError'))
gcc-python-plugin-commits@lists.stg.fedorahosted.org