commit 7922e98d5765221861bef8100f6b4dd69756c41b Author: David Malcolm dmalcolm@redhat.com Date: Sat Sep 3 09:35:29 2011 -0400
cpychecker: implement PyString_AsString
libcpychecker/refcounts.py | 57 ++++++++ .../refcounts/PyString_AsString/correct/input.c | 52 +++++++ .../refcounts/PyString_AsString/correct/script.py | 22 +++ .../refcounts/PyString_AsString/correct/stdout.txt | 142 ++++++++++++++++++++ .../refcounts/PyString_AsString/incorrect/input.c | 54 ++++++++ .../PyString_AsString/incorrect/script.py | 22 +++ .../PyString_AsString/incorrect/stderr.txt | 4 + .../PyString_AsString/incorrect/stdout.txt | 135 +++++++++++++++++++ .../refcounts/PyString_AsString/unknown/input.c | 48 +++++++ .../refcounts/PyString_AsString/unknown/script.py | 22 +++ .../refcounts/PyString_AsString/unknown/stdout.txt | 87 ++++++++++++ 11 files changed, 645 insertions(+), 0 deletions(-) --- diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py index 5d15477..f1d877e 100644 --- a/libcpychecker/refcounts.py +++ b/libcpychecker/refcounts.py @@ -565,6 +565,21 @@ class MyState(State): return [self.eval_rvalue(arg, stmt.loc) for arg in stmt.args]
+ def object_ptr_has_global_ob_type(self, v_object_ptr, vardecl_name): + """ + Boolean: do we know that the given PyObject* has an ob_type matching + the given global PyTypeObject (e.g. "PyString_Type") + """ + check_isinstance(v_object_ptr, AbstractValue) + check_isinstance(vardecl_name, str) + if isinstance(v_object_ptr, PointerToRegion): + v_ob_type = self.get_value_of_field_by_region(v_object_ptr.region, + 'ob_type') + if isinstance(v_ob_type, PointerToRegion): + if isinstance(v_ob_type.region, RegionForGlobal): + if v_ob_type.region.vardecl.name == vardecl_name: + return True + # Treat calls to various function prefixed with __cpychecker as special, # to help with debugging, and when writing selftests:
@@ -1195,6 +1210,48 @@ class MyState(State): ######################################################################## # PyString_* ######################################################################## + def impl_PyString_AsString(self, stmt): + # Declared in stringobject.h as: + # PyAPI_FUNC(char *) PyString_AsString(PyObject *); + # Implemented in Objects/stringobject.c + # + # http://docs.python.org/c-api/string.html#PyString_AsString + # + # With PyStringObject and their subclasses, it returns + # ((PyStringObject *)op) -> ob_sval + # With other classes, this call can fail + + v_op, = self.eval_stmt_args(stmt) + + # It will segfault if called with NULL, since it uses PyString_Check, + # which reads through the object's ob_type: + self.raise_any_null_ptr_func_arg(stmt, 0, v_op) + + returntype = stmt.fn.type.dereference.type + + if self.object_ptr_has_global_ob_type(v_op, 'PyString_Type'): + # We know it's a PyStringObject; the call will succeed: + # FIXME: cast: + r_ob_sval = self.make_field_region(v_op.region, 'ob_sval') + v_result = PointerToRegion(returntype, stmt.loc, r_ob_sval) + t_success = self.mktrans_assignment(stmt.lhs, + v_result, + 'PyString_AsString() returns ob_sval') + return [t_success] + + # We don't know if it's a PyStringObject (or subclass); the call could + # fail: + r_nonnull = self.make_heap_region('buffer from PyString_AsString()', stmt) + v_success = PointerToRegion(returntype, stmt.loc, r_nonnull) + t_success = self.mktrans_assignment(stmt.lhs, + v_success, + 'PyString_AsString() succeeds') + t_failure = self.mktrans_assignment(stmt.lhs, + ConcreteValue(returntype, stmt.loc, 0), + 'PyString_AsString() fails') + t_failure.dest.set_exception('PyExc_MemoryError') + return [t_success, t_failure] + def impl_PyString_FromFormat(self, stmt): # Declared in stringobject.h as: # PyAPI_FUNC(PyObject *) PyString_FromFormat(const char*, ...) diff --git a/tests/cpychecker/refcounts/PyString_AsString/correct/input.c b/tests/cpychecker/refcounts/PyString_AsString/correct/input.c new file mode 100644 index 0000000..d8d7a98 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/correct/input.c @@ -0,0 +1,52 @@ +/* + 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 call to PyString_AsString +*/ +PyObject * +test(PyObject *self, PyObject *args) +{ + PyObject *repr_args = NULL; + PyObject *result = NULL; + + repr_args = PyObject_Repr(args); + if (!repr_args) { + return NULL; + } + + result = PyString_FromFormat("test(args=%s)", + PyString_AsString(repr_args)); + Py_DECREF(repr_args); + return result; +} +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/PyString_AsString/correct/script.py b/tests/cpychecker/refcounts/PyString_AsString/correct/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/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/PyString_AsString/correct/stdout.txt b/tests/cpychecker/refcounts/PyString_AsString/correct/stdout.txt new file mode 100644 index 0000000..d6008b8 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/correct/stdout.txt @@ -0,0 +1,142 @@ +Trace 0: + Transitions: + 'PyObject_Repr() succeeds' + 'taking False path' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() succeeds' + 'taking True path' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36), region=RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36))) + str(): (struct PyObject *)&RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36)) from tests/cpychecker/refcounts/PyString_AsString/correct/input.c:36 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36), region=RegionForGlobal(gcc.VarDecl('PyString_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/PyString_AsString/correct/input.c', line=26), 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/PyString_AsString/correct/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31 + r->ob_refcnt: refs: 0 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=31), region=RegionForGlobal(gcc.VarDecl('PyString_Type'))) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/correct/input.c:27 + +Trace 1: + Transitions: + 'PyObject_Repr() succeeds' + 'taking False path' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() succeeds' + 'taking False path' + 'calling tp_dealloc on PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36), region=RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36))) + str(): (struct PyObject *)&RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36)) from tests/cpychecker/refcounts/PyString_AsString/correct/input.c:36 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36), region=RegionForGlobal(gcc.VarDecl('PyString_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/PyString_AsString/correct/input.c', line=26), 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/PyString_AsString/correct/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31 + r->ob_refcnt: None + r->ob_type: None + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/correct/input.c:27 + +Trace 2: + Transitions: + 'PyObject_Repr() succeeds' + 'taking False path' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() fails' + 'taking True path' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/correct/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/PyString_AsString/correct/input.c', line=26), 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/PyString_AsString/correct/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31 + r->ob_refcnt: refs: 0 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=31), region=RegionForGlobal(gcc.VarDecl('PyString_Type'))) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) + +Trace 3: + Transitions: + 'PyObject_Repr() succeeds' + 'taking False path' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() fails' + 'taking False path' + 'calling tp_dealloc on PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=36), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/correct/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/PyString_AsString/correct/input.c', line=26), 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/PyString_AsString/correct/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/correct/input.c:31 + r->ob_refcnt: None + r->ob_type: None + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) + +Trace 4: + Transitions: + 'PyObject_Repr() fails' + 'taking True path' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/correct/input.c', line=33), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/correct/input.c:33 + 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/PyString_AsString/correct/input.c', line=26), 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/PyString_AsString/correct/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) diff --git a/tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c b/tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c new file mode 100644 index 0000000..2b5a77b --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c @@ -0,0 +1,54 @@ +/* + 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 incorrect call to PyString_AsString +*/ +PyObject * +test(PyObject *self, PyObject *args) +{ + PyObject *repr_args = NULL; + PyObject *result = NULL; + + repr_args = PyObject_Repr(args); + /* + This code fails to check that the call to PyObject_Repr succeeded; + the checker ought to detect that a NULL ptr deref can happen inside + PyString_AsString: + */ + + result = PyString_FromFormat("test(args=%s)", + PyString_AsString(repr_args)); + Py_DECREF(repr_args); + return result; +} +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/PyString_AsString/incorrect/script.py b/tests/cpychecker/refcounts/PyString_AsString/incorrect/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/incorrect/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/PyString_AsString/incorrect/stderr.txt b/tests/cpychecker/refcounts/PyString_AsString/incorrect/stderr.txt new file mode 100644 index 0000000..d3d42d4 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/incorrect/stderr.txt @@ -0,0 +1,4 @@ +tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c: In function 'test': +tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38:33: error: calling PyString_AsString with NULL (gcc.VarDecl('repr_args')) as argument 0 at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38 +tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31:15: note: when PyObject_Repr() fails at: repr_args = PyObject_Repr(args); +tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:27:1: note: graphical error report for function 'test' written out to 'tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c.test-refcount-errors.html' diff --git a/tests/cpychecker/refcounts/PyString_AsString/incorrect/stdout.txt b/tests/cpychecker/refcounts/PyString_AsString/incorrect/stdout.txt new file mode 100644 index 0000000..47802a6 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/incorrect/stdout.txt @@ -0,0 +1,135 @@ +Trace 0: + Transitions: + 'PyObject_Repr() succeeds' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() succeeds' + 'taking True path' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38), region=RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38))) + str(): (struct PyObject *)&RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38)) from tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38), region=RegionForGlobal(gcc.VarDecl('PyString_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/PyString_AsString/incorrect/input.c', line=26), 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/PyString_AsString/incorrect/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31 + r->ob_refcnt: refs: 0 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=31), region=RegionForGlobal(gcc.VarDecl('PyString_Type'))) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:27 + +Trace 1: + Transitions: + 'PyObject_Repr() succeeds' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() succeeds' + 'taking False path' + 'calling tp_dealloc on PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38), region=RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38))) + str(): (struct PyObject *)&RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38)) from tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38), region=RegionForGlobal(gcc.VarDecl('PyString_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/PyString_AsString/incorrect/input.c', line=26), 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/PyString_AsString/incorrect/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31 + r->ob_refcnt: None + r->ob_type: None + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:27 + +Trace 2: + Transitions: + 'PyObject_Repr() succeeds' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() fails' + 'taking True path' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38 + 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/PyString_AsString/incorrect/input.c', line=26), 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/PyString_AsString/incorrect/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31 + r->ob_refcnt: refs: 0 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=31), region=RegionForGlobal(gcc.VarDecl('PyString_Type'))) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) + +Trace 3: + Transitions: + 'PyObject_Repr() succeeds' + 'PyString_AsString() returns ob_sval' + 'PyString_FromFormat() fails' + 'taking False path' + 'calling tp_dealloc on PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=38), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38 + 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/PyString_AsString/incorrect/input.c', line=26), 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/PyString_AsString/incorrect/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31: + repr(): RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c', line=31)) + str(): PyStringObject allocated at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:31 + r->ob_refcnt: None + r->ob_type: None + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) + +Trace 4: + Transitions: + 'PyObject_Repr() fails' + error: NullPtrArgument() + error: calling PyString_AsString with NULL (gcc.VarDecl('repr_args')) as argument 0 at tests/cpychecker/refcounts/PyString_AsString/incorrect/input.c:38 + 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/PyString_AsString/incorrect/input.c', line=26), 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/PyString_AsString/incorrect/input.c', line=26), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) diff --git a/tests/cpychecker/refcounts/PyString_AsString/unknown/input.c b/tests/cpychecker/refcounts/PyString_AsString/unknown/input.c new file mode 100644 index 0000000..02b4d0b --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/unknown/input.c @@ -0,0 +1,48 @@ +/* + 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 a call to PyString_AsString where we can't know whether or not + it's a PyStringObject +*/ +PyObject * +test(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + + /* (ultimately we ought to detect when PyString_FromFormat is passed + a NULL for a %s format code) */ + result = PyString_FromFormat("test(args=%s)", + PyString_AsString(args)); + return result; +} +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/PyString_AsString/unknown/script.py b/tests/cpychecker/refcounts/PyString_AsString/unknown/script.py new file mode 100644 index 0000000..fdd5ba3 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/unknown/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/PyString_AsString/unknown/stdout.txt b/tests/cpychecker/refcounts/PyString_AsString/unknown/stdout.txt new file mode 100644 index 0000000..a53fc53 --- /dev/null +++ b/tests/cpychecker/refcounts/PyString_AsString/unknown/stdout.txt @@ -0,0 +1,87 @@ +Trace 0: + Transitions: + 'PyString_AsString() succeeds' + 'PyString_FromFormat() succeeds' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33), region=RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33))) + str(): (struct PyObject *)&RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33)) from tests/cpychecker/refcounts/PyString_AsString/unknown/input.c:33 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33), region=RegionForGlobal(gcc.VarDecl('PyString_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/PyString_AsString/unknown/input.c', line=27), 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/PyString_AsString/unknown/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/unknown/input.c:28 + +Trace 1: + Transitions: + 'PyString_AsString() succeeds' + 'PyString_FromFormat() fails' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/unknown/input.c:33 + 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/PyString_AsString/unknown/input.c', line=27), 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/PyString_AsString/unknown/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) + +Trace 2: + Transitions: + 'PyString_AsString() fails' + 'PyString_FromFormat() succeeds' + 'returning' + Return value: + repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33), region=RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33))) + str(): (struct PyObject *)&RegionOnHeap('PyStringObject', gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33)) from tests/cpychecker/refcounts/PyString_AsString/unknown/input.c:33 + r->ob_refcnt: refs: 1 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33), region=RegionForGlobal(gcc.VarDecl('PyString_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/PyString_AsString/unknown/input.c', line=27), 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/PyString_AsString/unknown/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) + +Trace 3: + Transitions: + 'PyString_AsString() fails' + 'PyString_FromFormat() fails' + 'returning' + Return value: + repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyString_AsString/unknown/input.c', line=33), value=0) + str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyString_AsString/unknown/input.c:33 + 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/PyString_AsString/unknown/input.c', line=27), 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/PyString_AsString/unknown/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception: + RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
gcc-python-plugin-commits@lists.stg.fedorahosted.org