commit 4d0fa8d022522637b748df983e91d58b1630c97f Author: David Malcolm dmalcolm@redhat.com Date: Fri Sep 2 17:15:18 2011 -0400
cpychecker: implement PyInt_FromLong
libcpychecker/refcounts.py | 26 +++++++++++ .../PyInt_FromLong/correct_large_int/input.c | 47 ++++++++++++++++++++ .../PyInt_FromLong/correct_large_int/script.py | 22 +++++++++ .../PyInt_FromLong/correct_large_int/stdout.txt | 41 +++++++++++++++++ .../PyInt_FromLong/correct_small_int/input.c | 44 ++++++++++++++++++ .../PyInt_FromLong/correct_small_int/script.py | 22 +++++++++ .../PyInt_FromLong/correct_small_int/stdout.txt | 21 +++++++++ 7 files changed, 223 insertions(+), 0 deletions(-) --- diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py index 6a36ab3..ad989ed 100644 --- a/libcpychecker/refcounts.py +++ b/libcpychecker/refcounts.py @@ -937,6 +937,32 @@ class MyState(State): return self.make_transitions_for_fncall(stmt, s_success, s_failure)
######################################################################## + # Py_Int* + ######################################################################## + def impl_PyInt_FromLong(self, stmt): + # Declared in intobject.h as: + # PyAPI_FUNC(PyObject *) PyInt_FromLong(long); + # Defined in Objects/intobject.c + # + # CPython2 shares objects for integers in the range: + # -5 <= ival < 257 + # within intobject.c's "small_ints" array and these are preallocated + # by _PyInt_Init(). Thus, for these values, we know that the call + # cannot fail + + args = self.eval_stmt_args(stmt) + v_ival = args[0] + + newobj, success, failure = self.impl_object_ctor(stmt, + 'PyIntObject', 'PyInt_Type') + if isinstance(v_ival, ConcreteValue): + if v_ival.value >= -5 and v_ival.value < 257: + # We know that failure isn't possible: + return [success] + + return [success, failure] + + ######################################################################## # PyList_* ######################################################################## def impl_PyList_Append(self, stmt): diff --git a/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c b/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c new file mode 100644 index 0000000..6c8d198 --- /dev/null +++ b/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c @@ -0,0 +1,47 @@ +/* + 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 PyInt_FromLong for the + case where the int is large +*/ + +PyObject * +test(PyObject *self, PyObject *args) +{ + /* + This call could fail, since we're outside the interval [-5..257) + 257 is the first value not to be in the "small_ints" array + */ + return PyInt_FromLong(257); +} +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/PyInt_FromLong/correct_large_int/script.py b/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/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/PyInt_FromLong/correct_large_int/stdout.txt b/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/stdout.txt new file mode 100644 index 0000000..9713530 --- /dev/null +++ b/tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/stdout.txt @@ -0,0 +1,41 @@ +Trace 0: + Transitions: + 'PyInt_FromLong() succeeds' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c', line=34), region=RegionOnHeap('PyIntObject', gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c', line=34))) + str(): (struct PyObject *)&RegionOnHeap('PyIntObject', gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c', line=34)) from tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c:34 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyInt_Type'))) + 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/PyInt_FromLong/correct_large_int/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/PyInt_FromLong/correct_large_int/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c:29 + +Trace 1: + Transitions: + 'PyInt_FromLong() fails' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c', line=34), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyInt_FromLong/correct_large_int/input.c:34 + 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/PyInt_FromLong/correct_large_int/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/PyInt_FromLong/correct_large_int/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) diff --git a/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c b/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c new file mode 100644 index 0000000..220041f --- /dev/null +++ b/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c @@ -0,0 +1,44 @@ +/* + 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 PyInt_FromLong for + the case where the int is small +*/ + +PyObject * +test(PyObject *self, PyObject *args) +{ + /* This call can't fail, since we're in the interval [-5..257) */ + return PyInt_FromLong(0); +} +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/PyInt_FromLong/correct_small_int/script.py b/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/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/PyInt_FromLong/correct_small_int/stdout.txt b/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/stdout.txt new file mode 100644 index 0000000..e43c122 --- /dev/null +++ b/tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/stdout.txt @@ -0,0 +1,21 @@ +Trace 0: + Transitions: + 'PyInt_FromLong() succeeds' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c', line=31), region=RegionOnHeap('PyIntObject', gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c', line=31))) + str(): (struct PyObject *)&RegionOnHeap('PyIntObject', gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c', line=31)) from tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c:31 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c', line=31), region=RegionForGlobal(gcc.VarDecl('PyInt_Type'))) + 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/PyInt_FromLong/correct_small_int/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/PyInt_FromLong/correct_small_int/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyInt_FromLong/correct_small_int/input.c:29
gcc-python-plugin-commits@lists.stg.fedorahosted.org