commit 4f72acfd428621296c28f3aedd6aa329e39c53c0
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Dec 22 06:01:10 2011 -0500
cpychecker: implement PyObject_CallFunctionObjArgs and PyObject_CallMethodObjArgs
Implement PyObject_CallFunctionObjArgs and PyObject_CallMethodObjArgs, with
type-checking of varargs, and a test for NULL-termination of the varargs
libcpychecker/refcounts.py | 55 +++++++-
.../PyObject_CallFunctionObjArgs/correct/input.c | 43 +++++
.../PyObject_CallFunctionObjArgs/correct/script.py | 22 +++
.../correct/stdout.txt | 51 ++++++
.../PyObject_CallFunctionObjArgs/incorrect/input.c | 44 ++++++
.../incorrect/script.py | 22 +++
.../incorrect/stderr.txt | 8 +
.../incorrect/stdout.txt | 41 +++++
.../PyObject_CallMethodObjArgs/correct/input.c | 50 ++++++
.../PyObject_CallMethodObjArgs/correct/script.py | 22 +++
.../PyObject_CallMethodObjArgs/correct/stdout.txt | 163 ++++++++++++++++++++
.../PyObject_CallMethodObjArgs/incorrect/input.c | 56 +++++++
.../PyObject_CallMethodObjArgs/incorrect/script.py | 22 +++
.../incorrect/stderr.txt | 7 +
.../incorrect/stdout.txt | 163 ++++++++++++++++++++
15 files changed, 768 insertions(+), 1 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 8cb6c58..d89f47d 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -1841,10 +1841,50 @@ class CPython(Facet):
prototype=('PyObject *\n'
'PyObject_Call(PyObject *func, PyObject *arg,
PyObject *kw)'))
# "func" and "args" must not be NULL, but "kw" can
be:
- self.state.raise_any_null_ptr_func_arg(stmt, 0, v_o)
+ self.state.raise_any_null_ptr_func_arg(stmt, 0, v_o,
+ why='looks up func->ob_type')
self.state.raise_any_null_ptr_func_arg(stmt, 1, v_args)
return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+ def _check_objargs(self, stmt, fnmeta, args, base_idx):
+ """
+ Object/abstract.c: objargs_mktuple(va_list va)
+ expects a NULL-terminated list of PyObject*
+ """
+ check_isinstance(fnmeta, FnMeta)
+
+ # must be PyObject* (or NULL):
+ for i, v_arg in enumerate(args):
+ if v_arg.is_null_ptr():
+ continue
+ if not type_is_pyobjptr_subclass(v_arg.gcctype):
+ loc = v_arg.loc
+ if not loc:
+ loc = stmt.loc
+ gcc.error(loc,
+ ('argument %i had type %s but was expecting a PyObject* (or
subclass)'
+ % (i + base_idx + 1, v_arg.gcctype)))
+
+ # check NULL-termination:
+ if not args or not args[-1].is_null_ptr():
+ gcc.error(stmt.loc,
+ ('arguments to %s were not NULL-terminated'
+ % fnmeta.name))
+
+ def impl_PyObject_CallFunctionObjArgs(self, stmt, v_callable, *args):
+ fnmeta = FnMeta(name='PyObject_CallFunctionObjArgs',
+
docurl='http://docs.python.org/c-api/object.html#PyObject_CallFunctio...;,
+ prototype='PyObject* PyObject_CallFunctionObjArgs(PyObject
*callable, ...)',
+ defined_in='Objects/abstract.c',
+ notes='args must be NULL-terminated')
+
+ # "callable" can be NULL
+
+ # Check args:
+ self._check_objargs(stmt, fnmeta, args, 1)
+
+ return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+
def impl_PyObject_CallMethod(self, stmt, v_o, v_name, v_format, *args):
fnmeta = FnMeta(name='PyObject_CallMethod',
docurl='http://docs.python.org/c-api/object.html#PyObject_CallMethod';,
@@ -1869,6 +1909,19 @@ class CPython(Facet):
v_o, v_name, v_format,
args, with_size_t=True)
+ def impl_PyObject_CallMethodObjArgs(self, stmt, v_o, v_name, *args):
+ fnmeta = FnMeta(name='PyObject_CallMethodObjArgs',
+
docurl='http://docs.python.org/c-api/object.html#PyObject_CallMethodO...;,
+ defined_in='Objects/abstract.c',
+ prototype='PyObject* PyObject_CallMethodObjArgs(PyObject *o,
PyObject *name, ..., NULL)')
+
+ # "callable" and "name" can be NULL
+
+ # Check args:
+ self._check_objargs(stmt, fnmeta, args, 2)
+
+ return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+
def impl_PyObject_GenericGetAttr(self, stmt, v_o, v_name):
fnmeta = FnMeta(name='PyObject_GenericGetAttr',
docurl='http://docs.python.org/c-api/object.html#PyObject_GenericGetA...;,
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c
new file mode 100644
index 0000000..6653064
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c
@@ -0,0 +1,43 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm(a)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 PyObject_CallFunctionObjArgs
+*/
+
+struct FooObject {
+ PyObject_HEAD
+ int i;
+};
+
+PyObject *
+test(PyObject *callable, PyObject *a, struct FooObject *b)
+{
+ return PyObject_CallFunctionObjArgs(callable, a, b, NULL);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/script.py
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)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/PyObject_CallFunctionObjArgs/correct/stdout.txt
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/stdout.txt
new file mode 100644
index 0000000..999d104
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/stdout.txt
@@ -0,0 +1,51 @@
+Trace 0:
+ Transitions:
+ 'when PyObject_CallFunctionObjArgs() succeeds'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=34), region=RegionOnHeap('new ref from call to PyObject_CallFunctionObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=34)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to
PyObject_CallFunctionObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=34)) from tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/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/PyObject_CallFunctionObjArgs/correct/input.c',
line=34), region=Region('PyTypeObject for new ref from call to
PyObject_CallFunctionObjArgs'))
+ Region("region-for-arg-gcc.ParmDecl('callable')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ str(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=32),
region=Region("region-for-type-of-arg-gcc.ParmDecl('callable')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ Exception:
+ (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c:33
+
+Trace 1:
+ Transitions:
+ 'when PyObject_CallFunctionObjArgs() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=34), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c:34
+ Region("region-for-arg-gcc.ParmDecl('callable')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ str(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=32),
region=Region("region-for-type-of-arg-gcc.ParmDecl('callable')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/correct/input.c:34
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c
new file mode 100644
index 0000000..abb5dad
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c
@@ -0,0 +1,44 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm(a)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 detection of bogus types/lack of NULL termination in a call to
+ PyObject_CallFunctionObjArgs
+*/
+
+PyObject *
+test(PyObject *self, PyObject *args)
+{
+ /* BUG: these types are completely wrong:
+ the function expects a NULL-terminated sequence of (PyObject*)
+ */
+ return PyObject_CallFunctionObjArgs(self, "method_name",
+ "(s, s, s, s)",
+ "fee", "fi", "fo",
"fum");
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/script.py
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)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/PyObject_CallFunctionObjArgs/incorrect/stderr.txt
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/stderr.txt
new file mode 100644
index 0000000..297b881
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/stderr.txt
@@ -0,0 +1,8 @@
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c: In function
'test':
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
argument 2 had type char[12] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
argument 3 had type char[13] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
argument 4 had type char[4] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
argument 5 had type char[3] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
argument 6 had type char[3] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
argument 7 had type char[4] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33:5: error:
arguments to PyObject_CallFunctionObjArgs were not NULL-terminated
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/stdout.txt
b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/stdout.txt
new file mode 100644
index 0000000..2ee8a13
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/stdout.txt
@@ -0,0 +1,41 @@
+Trace 0:
+ Transitions:
+ 'when PyObject_CallFunctionObjArgs() succeeds'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=33), region=RegionOnHeap('new ref from call to PyObject_CallFunctionObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=33)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to
PyObject_CallFunctionObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=33)) from
tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/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/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=33), region=Region('PyTypeObject for new ref from call to
PyObject_CallFunctionObjArgs'))
+ 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/PyObject_CallFunctionObjArgs/incorrect/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/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:29
+
+Trace 1:
+ Transitions:
+ 'when PyObject_CallFunctionObjArgs() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=33), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/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/PyObject_CallFunctionObjArgs/incorrect/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/PyObject_CallFunctionObjArgs/incorrect/input.c',
line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallFunctionObjArgs/incorrect/input.c:33
diff --git a/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c
new file mode 100644
index 0000000..4757f4d
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c
@@ -0,0 +1,50 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm(a)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 PyObject_CallMethodObjArgs
+*/
+
+struct FooObject {
+ PyObject_HEAD
+ int i;
+};
+
+PyObject *
+test(PyObject *obj, PyObject *a, struct FooObject *b)
+{
+ PyObject *name = PyString_FromString("some_method");
+ PyObject *result;
+ if (!name) {
+ return NULL;
+ }
+ result = PyObject_CallMethodObjArgs(obj, name, a, b, NULL);
+ Py_DECREF(name);
+ return result;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/script.py
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)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/PyObject_CallMethodObjArgs/correct/stdout.txt
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/stdout.txt
new file mode 100644
index 0000000..f41484c
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/stdout.txt
@@ -0,0 +1,163 @@
+Trace 0:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() succeeds'
+ 'when taking True path'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39), region=RegionOnHeap('new ref from call to PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to
PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39)) from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:39
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39), region=Region('PyTypeObject for new ref from call to
PyObject_CallMethodObjArgs'))
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=34))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=34), region=RegionForGlobal(gcc.VarDecl('PyString_Type')))
+ Exception:
+ (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:33
+
+Trace 1:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() succeeds'
+ 'when taking False path'
+ 'calling tp_dealloc on PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39), region=RegionOnHeap('new ref from call to PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to
PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39)) from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:39
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39), region=Region('PyTypeObject for new ref from call to
PyObject_CallMethodObjArgs'))
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=34))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:33
+
+Trace 2:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() fails'
+ 'when taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:39
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=34))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=34), region=RegionForGlobal(gcc.VarDecl('PyString_Type')))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:39
+
+Trace 3:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() fails'
+ 'when taking False path'
+ 'calling tp_dealloc on PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=39), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:39
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=34))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:39
+
+Trace 4:
+ Transitions:
+ 'when PyString_FromString() fails'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=37), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:37
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c',
line=32), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/correct/input.c:34
diff --git a/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c
new file mode 100644
index 0000000..5e098fe
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c
@@ -0,0 +1,56 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm(a)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 detection of bogus types/lack of NULL termination in a call to
+ PyObject_CallMethodObjArgs
+*/
+
+struct FooObject {
+ PyObject_HEAD
+ int i;
+};
+
+PyObject *
+test(PyObject *obj, PyObject *a, struct FooObject *b)
+{
+ PyObject *name = PyString_FromString("some_method");
+ PyObject *result;
+ if (!name) {
+ return NULL;
+ }
+ /* BUG: these types are completely wrong:
+ the function expects a NULL-terminated sequence of (PyObject*)
+ */
+ result = PyObject_CallMethodObjArgs(obj, name,
+ "(s, s, s, s)",
+ "fee", "fi", "fo",
"fum");
+ Py_DECREF(name);
+ return result;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/script.py
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)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/PyObject_CallMethodObjArgs/incorrect/stderr.txt
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/stderr.txt
new file mode 100644
index 0000000..7d1bcb0
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/stderr.txt
@@ -0,0 +1,7 @@
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c: In function
'test':
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43:12: error:
argument 3 had type char[13] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43:12: error:
argument 4 had type char[4] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43:12: error:
argument 5 had type char[3] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43:12: error:
argument 6 had type char[3] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43:12: error:
argument 7 had type char[4] * but was expecting a PyObject* (or subclass)
+tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43:12: error:
arguments to PyObject_CallMethodObjArgs were not NULL-terminated
diff --git a/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/stdout.txt
b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/stdout.txt
new file mode 100644
index 0000000..bd302b8
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/stdout.txt
@@ -0,0 +1,163 @@
+Trace 0:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() succeeds'
+ 'when taking True path'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43), region=RegionOnHeap('new ref from call to PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to
PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43)) from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43), region=Region('PyTypeObject for new ref from call to
PyObject_CallMethodObjArgs'))
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=35))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=35), region=RegionForGlobal(gcc.VarDecl('PyString_Type')))
+ Exception:
+ (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:34
+
+Trace 1:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() succeeds'
+ 'when taking False path'
+ 'calling tp_dealloc on PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43), region=RegionOnHeap('new ref from call to PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to
PyObject_CallMethodObjArgs',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43)) from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43), region=Region('PyTypeObject for new ref from call to
PyObject_CallMethodObjArgs'))
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=35))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:34
+
+Trace 2:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() fails'
+ 'when taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=35))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=35), region=RegionForGlobal(gcc.VarDecl('PyString_Type')))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43
+
+Trace 3:
+ Transitions:
+ 'when PyString_FromString() succeeds'
+ 'taking False path'
+ 'when PyObject_CallMethodObjArgs() fails'
+ 'when taking False path'
+ 'calling tp_dealloc on PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=43), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35:
+ repr(): RegionOnHeap('PyStringObject',
gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=35))
+ str(): PyStringObject allocated at
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:43
+
+Trace 4:
+ Transitions:
+ 'when PyString_FromString() fails'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=38), value=0)
+ str(): (struct PyObject *)0 from
tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:38
+ Region("region-for-arg-gcc.ParmDecl('obj')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ str(): Region("region-for-arg-gcc.ParmDecl('obj')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Region("region-for-arg-gcc.ParmDecl('a')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('a')")
+ str(): Region("region-for-arg-gcc.ParmDecl('a')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Region("region-for-arg-gcc.ParmDecl('b')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('b')")
+ str(): Region("region-for-arg-gcc.ParmDecl('b')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *',
loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c',
line=33), region=Region("region-for-type-of-arg-gcc.ParmDecl('b')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError'))
from tests/cpychecker/refcounts/PyObject_CallMethodObjArgs/incorrect/input.c:35