[gcc-python-plugin] cpychecker: implement PyMapping_Size
by David Hugh Malcolm
commit d7115d8472ed8ac8f8288fd997f6e70941ae4e31
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Dec 22 16:07:36 2011 -0500
cpychecker: implement PyMapping_Size
libcpychecker/refcounts.py | 23 ++++++++++++
.../refcounts/PyMapping_Size/basic/input.c | 38 ++++++++++++++++++++
.../refcounts/PyMapping_Size/basic/script.py | 22 +++++++++++
.../refcounts/PyMapping_Size/basic/stdout.txt | 29 +++++++++++++++
4 files changed, 112 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 9df2635..78e9660 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -1674,6 +1674,29 @@ class CPython(Facet):
return [t_success, t_failure]
########################################################################
+ # PyMapping_*
+ ########################################################################
+
+ def impl_PyMapping_Size(self, stmt, v_o):
+ fnmeta = FnMeta(name='PyMapping_Size',
+ docurl='http://docs.python.org/c-api/mapping.html#PyMapping_Size',
+ prototype='Py_ssize_t PyMapping_Size(PyObject *o)',
+ defined_in='Objects/abstract.c',
+ notes='Can cope with NULL (sets exception)')
+ t_success = self.state.mktrans_assignment(stmt.lhs,
+ UnknownValue.make(stmt.lhs.type,
+ stmt.loc),
+ fnmeta.desc_when_call_succeeds())
+ t_failure = self.state.mktrans_assignment(stmt.lhs,
+ ConcreteValue(stmt.lhs.type,
+ stmt.loc,
+ -1),
+ fnmeta.desc_when_call_fails())
+ t_failure.dest.cpython.set_exception('PyExc_TypeError',
+ stmt.loc)
+ return [t_success, t_failure]
+
+ ########################################################################
# PyMem_*
########################################################################
def impl_PyMem_Free(self, stmt, v_ptr):
diff --git a/tests/cpychecker/refcounts/PyMapping_Size/basic/input.c b/tests/cpychecker/refcounts/PyMapping_Size/basic/input.c
new file mode 100644
index 0000000..7de2e0c
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyMapping_Size/basic/input.c
@@ -0,0 +1,38 @@
+/*
+ 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>
+
+/*
+ Basic test coverage for our handler for PyMapping_Size
+*/
+
+Py_ssize_t
+test(PyObject *obj)
+{
+ return PyMapping_Size(obj);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyMapping_Size/basic/script.py b/tests/cpychecker/refcounts/PyMapping_Size/basic/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyMapping_Size/basic/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/PyMapping_Size/basic/stdout.txt b/tests/cpychecker/refcounts/PyMapping_Size/basic/stdout.txt
new file mode 100644
index 0000000..871895f
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyMapping_Size/basic/stdout.txt
@@ -0,0 +1,29 @@
+Trace 0:
+ Transitions:
+ 'when PyMapping_Size() succeeds'
+ 'returning'
+ Return value:
+ repr(): WithinRange(gcctype='Py_ssize_t', loc=gcc.Location(file='tests/cpychecker/refcounts/PyMapping_Size/basic/input.c', line=29), minvalue=-0x8000000000000000, maxvalue=0x7fffffffffffffff)
+ str(): (Py_ssize_t)val [-0x8000000000000000 <= val <= 0x7fffffffffffffff] from tests/cpychecker/refcounts/PyMapping_Size/basic/input.c:29
+ 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/PyMapping_Size/basic/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/PyMapping_Size/basic/input.c:28
+
+Trace 1:
+ Transitions:
+ 'when PyMapping_Size() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='Py_ssize_t', loc=gcc.Location(file='tests/cpychecker/refcounts/PyMapping_Size/basic/input.c', line=29), value=-1)
+ str(): (Py_ssize_t)-1 from tests/cpychecker/refcounts/PyMapping_Size/basic/input.c:29
+ 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/PyMapping_Size/basic/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_TypeError')) from tests/cpychecker/refcounts/PyMapping_Size/basic/input.c:29
12 years, 5 months
[gcc-python-plugin] cpychecker: implement PyCapsule_GetPointer
by David Hugh Malcolm
commit f294898c1dc429e838c1c3e79eff57431a8239a4
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Dec 22 15:48:04 2011 -0500
cpychecker: implement PyCapsule_GetPointer
libcpychecker/absinterp.py | 3 ++
libcpychecker/refcounts.py | 24 ++++++++++++-
.../refcounts/PyCapsule_GetPointer/basic/input.c | 38 ++++++++++++++++++++
.../refcounts/PyCapsule_GetPointer/basic/script.py | 22 +++++++++++
.../PyCapsule_GetPointer/basic/stdout.txt | 29 +++++++++++++++
5 files changed, 115 insertions(+), 1 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index 5d69442..acc87ed 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -826,6 +826,9 @@ class UninitializedData(AbstractValue):
def extract_from_parent(self, region, gcctype, loc):
return UninitializedData(gcctype, self.loc)
+def make_null_ptr(gcctype, loc):
+ return ConcreteValue(gcctype, loc, 0)
+
############################################################################
# Various kinds of predicted error:
############################################################################
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 4bb4f7f..9df2635 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -98,7 +98,7 @@ def stmt_is_return_of_objptr(stmt):
return True
def make_null_pyobject_ptr(stmt):
- return ConcreteValue(get_PyObjectPtr(), stmt.loc, 0)
+ return make_null_ptr(get_PyObjectPtr(), stmt.loc)
class RefcountValue(AbstractValue):
"""
@@ -960,6 +960,28 @@ class CPython(Facet):
fnmeta.desc_when_call_returns_value('0 (false)'))]
########################################################################
+ # PyCapsule_*
+ ########################################################################
+
+ def impl_PyCapsule_GetPointer(self, stmt, v_capsule, v_name):
+ fnmeta = FnMeta(name='PyCapsule_GetPointer',
+ docurl='http://docs.python.org/c-api/capsule.html#PyCapsule_GetPointer',
+ prototype='void* PyCapsule_GetPointer(PyObject *capsule, const char *name)',
+ defined_in='Objects/capsule.c')
+ # either returns NULL, setting an exception, or returns non-NULL
+ t_success = self.state.mktrans_assignment(stmt.lhs,
+ UnknownValue.make(stmt.lhs.type,
+ stmt.loc),
+ fnmeta.desc_when_call_succeeds())
+ t_failure = self.state.mktrans_assignment(stmt.lhs,
+ make_null_ptr(stmt.lhs.type,
+ stmt.loc),
+ fnmeta.desc_when_call_fails())
+ t_failure.dest.cpython.set_exception('PyExc_ValueError',
+ stmt.loc)
+ return [t_success, t_failure]
+
+ ########################################################################
# PyCObject_*
########################################################################
diff --git a/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c b/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c
new file mode 100644
index 0000000..4868143
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c
@@ -0,0 +1,38 @@
+/*
+ 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>
+
+/*
+ Basic test coverage for our handler for PyCapsule_GetPointer
+*/
+
+void*
+test(PyObject *capsule, const char *name)
+{
+ return PyCapsule_GetPointer(capsule, name);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/script.py b/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/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/PyCapsule_GetPointer/basic/stdout.txt b/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/stdout.txt
new file mode 100644
index 0000000..81cee3f
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/stdout.txt
@@ -0,0 +1,29 @@
+Trace 0:
+ Transitions:
+ 'when PyCapsule_GetPointer() succeeds'
+ 'returning'
+ Return value:
+ repr(): UnknownValue(gcctype=<gcc.PointerType object at 0xdeadbeef>, loc=gcc.Location(file='tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c', line=29))
+ str(): unknown void * from tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c:29
+ Region("region-for-arg-gcc.ParmDecl('capsule')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('capsule')")
+ str(): Region("region-for-arg-gcc.ParmDecl('capsule')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('capsule')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c:28
+
+Trace 1:
+ Transitions:
+ 'when PyCapsule_GetPointer() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='void *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c', line=29), value=0)
+ str(): (void *)0 from tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c:29
+ Region("region-for-arg-gcc.ParmDecl('capsule')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('capsule')")
+ str(): Region("region-for-arg-gcc.ParmDecl('capsule')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('capsule')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_ValueError')) from tests/cpychecker/refcounts/PyCapsule_GetPointer/basic/input.c:29
12 years, 5 months
[gcc-python-plugin] cpychecker: implement PyEval_CallObjectWithKeywords
by David Hugh Malcolm
commit 42c3630ff19a27c63909a87507c913122181a689
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Dec 22 15:16:14 2011 -0500
cpychecker: implement PyEval_CallObjectWithKeywords
libcpychecker/refcounts.py | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index b144ce0..4bb4f7f 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -1276,6 +1276,18 @@ class CPython(Facet):
########################################################################
# PyEval_InitThreads()
########################################################################
+
+ def impl_PyEval_CallObjectWithKeywords(self, stmt, v_func, v_arg, v_kw):
+ fnmeta = FnMeta(name='PyEval_CallObjectWithKeywords',
+ prototype=('PyObject *\n'
+ 'PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)'),
+ defined_in='Python/ceval.c')
+ self.state.raise_any_null_ptr_func_arg(stmt, 0, v_func,
+ why='looks up func->ob_type within inner call to PyObject_Call()')
+ # arg and kw can each be NULL, though
+
+ return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+
def impl_PyEval_InitThreads(self, stmt):
fnmeta = FnMeta(name='PyEval_InitThreads',
docurl='http://docs.python.org/c-api/init.html#PyEval_InitThreads')
12 years, 5 months
[gcc-python-plugin] cpychecker: implement PyObject_CallFunction
by David Hugh Malcolm
commit abae8018ad3be4a41d610f94f7cda18e0154cf07
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Dec 22 07:07:32 2011 -0500
cpychecker: implement PyObject_CallFunction
libcpychecker/refcounts.py | 32 ++++++++++++++--
.../PyObject_CallFunction/correct/input.c | 40 ++++++++++++++++++++
.../PyObject_CallFunction/correct/script.py | 22 +++++++++++
.../PyObject_CallFunction/correct/stdout.txt | 31 +++++++++++++++
4 files changed, 121 insertions(+), 4 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index d89f47d..b144ce0 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -1769,9 +1769,13 @@ class CPython(Facet):
# PyObject_*
########################################################################
def _handle_PyObject_CallMethod(self, stmt, fnmeta,
- v_o, v_name, v_fmt, v_varargs, with_size_t):
+ v_o, v_fmt, v_varargs, with_size_t):
+ """
+ For functions in Objects/abstract.c that use Py_VaBuildValue or
+ _Py_VaBuildValue_SizeT, then use call_function_tail
+ (e.g. handles PyObject_CallFunction also)
+ """
check_isinstance(v_o, AbstractValue)
- check_isinstance(v_name, AbstractValue)
check_isinstance(v_fmt, AbstractValue)
check_isinstance(v_varargs, tuple) # of AbstractValue
check_isinstance(with_size_t, bool)
@@ -1846,6 +1850,26 @@ class CPython(Facet):
self.state.raise_any_null_ptr_func_arg(stmt, 1, v_args)
return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+ def impl_PyObject_CallFunction(self, stmt, v_callable, v_format, *args):
+ fnmeta = FnMeta(name='PyObject_CallFunction',
+ docurl='http://docs.python.org/c-api/object.html#PyObject_CallFunction',
+ defined_in='Objects/abstract.c',
+ prototype='PyObject* PyObject_CallFunction(PyObject *callable, char *format, ...)')
+ # callable can be NULL
+
+ return self._handle_PyObject_CallMethod(stmt, fnmeta,
+ v_callable, v_format,
+ args, with_size_t=False)
+
+ def impl__PyObject_CallFunction_SizeT(self, stmt, v_callable, v_format, *args):
+ fnmeta = FnMeta(name='_PyObject_CallFunction_SizeT',
+ docurl='http://docs.python.org/c-api/object.html#PyObject_CallFunction',
+ defined_in='Objects/abstract.c',
+ prototype='PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, char *format, ...)')
+ return self._handle_PyObject_CallMethod(stmt, fnmeta,
+ v_callable, v_format,
+ args, with_size_t=True)
+
def _check_objargs(self, stmt, fnmeta, args, base_idx):
"""
Object/abstract.c: objargs_mktuple(va_list va)
@@ -1892,7 +1916,7 @@ class CPython(Facet):
prototype=('PyObject *\n'
'PyObject_CallMethod(PyObject *o, char *name, char *format, ...)'))
return self._handle_PyObject_CallMethod(stmt, fnmeta,
- v_o, v_name, v_format,
+ v_o, v_format,
args, with_size_t=False)
def impl__PyObject_CallMethod_SizeT(self, stmt, v_o, v_name, v_format, *args):
@@ -1906,7 +1930,7 @@ class CPython(Facet):
# PyObject *
# _PyObject_CallMethod_SizeT(PyObject *o, char *name, char *format, ...)
return self._handle_PyObject_CallMethod(stmt, fnmeta,
- v_o, v_name, v_format,
+ v_o, v_format,
args, with_size_t=True)
def impl_PyObject_CallMethodObjArgs(self, stmt, v_o, v_name, *args):
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c b/tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c
new file mode 100644
index 0000000..e7a6288
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c
@@ -0,0 +1,40 @@
+/*
+ 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_CallFunction
+*/
+
+PyObject *
+test(PyObject *callable, int i)
+{
+ return PyObject_CallFunction(callable,
+ "(s, s, s, s, i)",
+ "fee", "fi", "fo", "fum", i);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyObject_CallFunction/correct/script.py b/tests/cpychecker/refcounts/PyObject_CallFunction/correct/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunction/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_CallFunction/correct/stdout.txt b/tests/cpychecker/refcounts/PyObject_CallFunction/correct/stdout.txt
new file mode 100644
index 0000000..21ecb9e
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallFunction/correct/stdout.txt
@@ -0,0 +1,31 @@
+Trace 0:
+ Transitions:
+ 'when PyObject_CallFunction() succeeds'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c', line=29), region=RegionOnHeap('new ref from call to PyObject_CallFunction', gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c', line=29)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to PyObject_CallFunction', gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c', line=29)) from tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c:29
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c', line=29), region=Region('PyTypeObject for new ref from call to PyObject_CallFunction'))
+ 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_CallFunction/correct/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('callable')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c:28
+
+Trace 1:
+ Transitions:
+ 'when PyObject_CallFunction() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c', line=29), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c:29
+ 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_CallFunction/correct/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('callable')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/PyObject_CallFunction/correct/input.c:29
12 years, 5 months
[gcc-python-plugin] cpychecker: fix casting of pointer to a non-pointer value
by David Hugh Malcolm
commit 8748cee98b56e1096384312bdfb3322909e221df
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Dec 22 06:48:25 2011 -0500
cpychecker: fix casting of pointer to a non-pointer value
Fix casting of pointer to a non-pointer value
Fixes a traceback seen when running the checker against rpm, in
python/header-py.c:hdr_hash
libcpychecker/absinterp.py | 8 ++++
.../absinterp/casts/pyobjectptr-to-long/input.c | 38 ++++++++++++++++++++
.../absinterp/casts/pyobjectptr-to-long/script.py | 22 +++++++++++
.../absinterp/casts/pyobjectptr-to-long/stdout.txt | 13 +++++++
4 files changed, 81 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index 5de228f..5d69442 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -763,6 +763,14 @@ class PointerToRegion(AbstractValue):
def impl_is_ge(self, rhs):
return None
+ def eval_unary_op(self, exprcode, gcctype, loc):
+ if exprcode == gcc.ConvertExpr:
+ # Casting of this non-NULL pointer to another type:
+ return UnknownValue.make(gcctype, loc)
+
+ # Defer to base class:
+ AbstractValue.eval_unary_op(self, exprcode, gcctype, loc)
+
class DeallocatedMemory(AbstractValue):
"""
A 'poisoned' r-value: this memory has been deallocated, so the r-value
diff --git a/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/input.c b/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/input.c
new file mode 100644
index 0000000..c7e02d0
--- /dev/null
+++ b/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/input.c
@@ -0,0 +1,38 @@
+/*
+ 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 casting from a PyObject* to a long
+*/
+
+long
+test(PyObject *obj)
+{
+ return (long)obj;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/script.py b/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/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/absinterp/casts/pyobjectptr-to-long/stdout.txt b/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/stdout.txt
new file mode 100644
index 0000000..3b20277
--- /dev/null
+++ b/tests/cpychecker/absinterp/casts/pyobjectptr-to-long/stdout.txt
@@ -0,0 +1,13 @@
+Trace 0:
+ Transitions:
+ 'returning'
+ Return value:
+ repr(): WithinRange(gcctype='long int', loc=gcc.Location(file='tests/cpychecker/absinterp/casts/pyobjectptr-to-long/input.c', line=29), minvalue=-0x8000000000000000, maxvalue=0x7fffffffffffffff)
+ str(): (long int)val [-0x8000000000000000 <= val <= 0x7fffffffffffffff] from tests/cpychecker/absinterp/casts/pyobjectptr-to-long/input.c:29
+ 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/absinterp/casts/pyobjectptr-to-long/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('obj')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/casts/pyobjectptr-to-long/input.c:28
12 years, 5 months
[gcc-python-plugin] cpychecker: implement PyObject_CallFunctionObjArgs and PyObject_CallMethodObjArgs
by David Hugh Malcolm
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_CallFunctionObjArgs',
+ 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_CallMethodObjArgs',
+ 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_GenericGetAttr',
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
12 years, 5 months
[gcc-python-plugin] cpychecker: add bulletproofing to refcount modifications
by David Hugh Malcolm
commit eeb4d89f6686864e84f085a971f328a44524f305
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Dec 21 22:41:14 2011 -0500
cpychecker: add bulletproofing to refcount modifications
In many cases, PyObject* values are initialized by the checker to have
an ob_refcnt, but it's possible for CPython.change_refcount() to
encounter a PyObject* for which the ob_refcnt is unknown.
This patch makes it treat such a case as a borrowed reference, rather
than failing with a traceback.
Fixes a traceback seen when running the checker on rpm's python bindings
in python/header-py.c:hdr_reduce where we don't know the ob_refcnt of
Py_TYPE(s) in:
Py_BuildValue("O(O)", Py_TYPE(s), blob);
libcpychecker/refcounts.py | 5 ++-
.../refcounts/Py_BuildValue/Py_TYPE/input.c | 39 ++++++++++++++++++++
.../refcounts/Py_BuildValue/Py_TYPE/script.py | 22 +++++++++++
.../refcounts/Py_BuildValue/Py_TYPE/stdout.txt | 31 ++++++++++++++++
4 files changed, 95 insertions(+), 2 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index c0f7a0a..8cb6c58 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -304,8 +304,9 @@ class CPython(Facet):
oldvalue = self.state.get_store(ob_refcnt, None, loc) # FIXME: gcctype
check_isinstance(oldvalue, AbstractValue)
log('oldvalue: %r', oldvalue)
- #if isinstance(oldvalue, UnknownValue):
- # self.raise_split_value(oldvalue, loc)
+ # If we never had a ob_refcnt, treat it as a borrowed reference:
+ if isinstance(oldvalue, UnknownValue):
+ oldvalue = RefcountValue.borrowed_ref()
check_isinstance(oldvalue, RefcountValue)
newvalue = fn(oldvalue)
log('newvalue: %r', newvalue)
diff --git a/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c b/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c
new file mode 100644
index 0000000..9b8d6e9
--- /dev/null
+++ b/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c
@@ -0,0 +1,39 @@
+/*
+ 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>
+
+/*
+ Verify that Py_BuildValue("O") can cope with a PyObject* for which the
+ ob_refcnt is unknown. This happens with PyTypeObject instances.
+*/
+
+PyObject *
+test(PyObject *a)
+{
+ return Py_BuildValue("O", Py_TYPE(a));
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/script.py b/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/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/Py_BuildValue/Py_TYPE/stdout.txt b/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/stdout.txt
new file mode 100644
index 0000000..5583c34
--- /dev/null
+++ b/tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/stdout.txt
@@ -0,0 +1,31 @@
+Trace 0:
+ Transitions:
+ 'when Py_BuildValue() succeeds'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c', line=30), region=RegionOnHeap('new ref from call to Py_BuildValue', gcc.Location(file='tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c', line=30)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to Py_BuildValue', gcc.Location(file='tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c', line=30)) from tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c:30
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c', line=30), region=Region('PyTypeObject for new ref from call to Py_BuildValue'))
+ 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/Py_BuildValue/Py_TYPE/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c:29
+
+Trace 1:
+ Transitions:
+ 'when Py_BuildValue() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c', line=30), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c:30
+ 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/Py_BuildValue/Py_TYPE/input.c', line=28), region=Region("region-for-type-of-arg-gcc.ParmDecl('a')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/Py_BuildValue/Py_TYPE/input.c:30
12 years, 5 months
[gcc-python-plugin] cpychecker: add (disabled) code to profile the refcount checker
by David Hugh Malcolm
commit e5ac16759ca4bd2637708ad6ba9fa363cc0cc283
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Dec 21 22:31:27 2011 -0500
cpychecker: add (disabled) code to profile the refcount checker
libcpychecker/__init__.py | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
---
diff --git a/libcpychecker/__init__.py b/libcpychecker/__init__.py
index be2834f..a2267ef 100644
--- a/libcpychecker/__init__.py
+++ b/libcpychecker/__init__.py
@@ -48,8 +48,25 @@ class CpyCheckerGimplePass(gcc.GimplePass):
# The refcount code is too buggy for now to be on by default:
if self.verify_refcounting:
- check_refcounts(fun, self.dump_traces, self.show_traces,
- self.show_possible_null_derefs)
+ if 0:
+ # Profiled version:
+ import cProfile
+ prof_filename = '%s.%s.refcount-profile' % (gcc.get_dump_base_name(),
+ fun.decl.name)
+ cProfile.runctx('self._check_refcounts(fun)',
+ globals(), locals(),
+ filename=prof_filename)
+ import pstats
+ prof = pstats.Stats(prof_filename)
+ prof.sort_stats('cumulative').print_stats(20)
+ else:
+ # Normal mode (without profiler):
+ self._check_refcounts(fun)
+
+ def _check_refcounts(self, fun):
+ check_refcounts(fun, self.dump_traces, self.show_traces,
+ self.show_possible_null_derefs)
+
class CpyCheckerIpaPass(gcc.SimpleIpaPass):
"""
12 years, 5 months
[gcc-python-plugin] cpychecker: optimize Trace.get_all_var_region_pairs()
by David Hugh Malcolm
commit 429306595b1733b0f3f732c26ae216b463a807e6
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Dec 21 17:03:02 2011 -0500
cpychecker: optimize Trace.get_all_var_region_pairs()
Running 9c2b81d2abf89c238c785fcf189e101067549eb1 (plus local changes) on
rpm's python/rpmmodule.c showed a big slowdown analyzing that code's
"initModule" function.
Analysis with the profiler showed a big spike in
Trace.get_all_var_region_pairs()
as called by get_description_for_region()
Changing it to use a set (rather than a list) removes the slowdown, presumably
due to avoiding the cost of "in" on a list inside the loop, changing it from
O(N^2) to O(N), where N is the number of items.
For reference, here's the old profile:
Wed Dec 21 16:17:18 2011 .libs/rpmmodule.c.initModule.refcount-profile
5491244 function calls (5490966 primitive calls) in 29.004 seconds
Ordered by: cumulative time
List reduced from 159 to 20 due to restriction <20>
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 29.004 29.004 <string>:2(<module>)
1 0.040 0.040 29.004 29.004 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/refcounts.py:2747(check_refcounts)
113 0.004 0.000 27.433 0.243 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:2540(get_description_for_region)
113 24.435 0.216 27.277 0.241 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:2488(get_all_var_region_pairs)
25429 1.683 0.000 2.770 0.000 /usr/lib64/python2.7/_abcoll.py:368(items)
257/1 0.007 0.000 1.506 1.506 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:2624(iter_traces)
248 0.001 0.000 1.374 0.006 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:1816(get_transitions)
247 0.002 0.000 1.368 0.006 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:1830(_get_transitions_for_stmt)
179 0.005 0.000 1.274 0.007 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:1941(_get_transitions_for_GimpleCall)
161 0.002 0.000 1.138 0.007 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/refcounts.py:1743(impl_PyModule_AddIntConstant)
3784073 1.123 0.000 1.123 0.000 /usr/lib64/python2.7/collections.py:97(__iter__)
175 0.002 0.000 0.901 0.005 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/refcounts.py:358(set_exception)
175 0.313 0.002 0.498 0.003 /home/david/coding/gcc-python/gcc-python/fixing-rpm/gccutils.py:49(get_global_vardecl_by_name)
184 0.271 0.001 0.412 0.002 /home/david/coding/gcc-python/gcc-python/fixing-rpm/gccutils.py:34(get_global_typedef)
176 0.001 0.000 0.393 0.002 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/types.py:59(get_PyObjectPtr)
481 0.003 0.000 0.384 0.001 /home/david/coding/gcc-python/gcc-python/fixing-rpm/libcpychecker/absinterp.py:1244(copy)
962 0.004 0.000 0.374 0.000 /usr/lib64/python2.7/collections.py:178(copy)
964 0.009 0.000 0.371 0.000 /usr/lib64/python2.7/collections.py:58(__init__)
1303416 0.359 0.000 0.361 0.000 {isinstance}
964 0.104 0.000 0.359 0.000 /usr/lib64/python2.7/_abcoll.py:483(update)
libcpychecker/absinterp.py | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index 678e4b7..5de228f 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -2475,15 +2475,14 @@ class Trace(object):
def get_all_var_region_pairs(self):
"""
- Get the list of all (LHS,region) pairs in region_for_var within all of
+ Get the set of all (LHS,region) pairs in region_for_var within all of
the states in this trace, without duplicates
"""
- result = []
+ result = set()
for s_iter in self.states:
for var_iter, r_iter in s_iter.region_for_var.items():
pair = (var_iter, r_iter)
- if pair not in result:
- result.append(pair)
+ result.add(pair)
return result
def var_points_unambiguously_to(self, r_srcptr, r_dstptr):
12 years, 5 months
[gcc-python-plugin] cpychecker: handle PyArg_Parse code "O&" in reference-count checker
by David Hugh Malcolm
commit a0c8d9de5878546f7d79b0a3cabc0befac96fe19
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Mon Dec 19 21:27:47 2011 -0500
cpychecker: handle PyArg_Parse code "O&" in reference-count checker
libcpychecker/refcounts.py | 11 +++++-
.../PyArg_ParseTuple/correct_converter/input.c | 42 +++++++++++++++++++
.../PyArg_ParseTuple/correct_converter/script.py | 22 ++++++++++
.../PyArg_ParseTuple/correct_converter/stdout.txt | 43 ++++++++++++++++++++
4 files changed, 117 insertions(+), 1 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 5b0f28b..2139a00 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -30,7 +30,8 @@ from libcpychecker.attributes import fnnames_returning_borrowed_refs, \
stolen_refs_by_fnname
from libcpychecker.diagnostics import Reporter, Annotator, Note
from libcpychecker.PyArg_ParseTuple import PyArgParseFmt, FormatStringError, \
- TypeCheckCheckerType, TypeCheckResultType
+ TypeCheckCheckerType, TypeCheckResultType, \
+ ConverterCallbackType, ConverterResultType
from libcpychecker.Py_BuildValue import PyBuildValueFmt, ObjectFormatUnit, \
CodeSO, CodeN
from libcpychecker.types import is_py3k, is_debug_build, get_PyObjectPtr
@@ -667,6 +668,14 @@ class CPython(Facet):
self.make_sane_object(stmt, 'object from arg "O!"',
RefcountValue.borrowed_ref()))
+ if unit.code == 'O&':
+ # Assume for now that conversion succeeds
+ if isinstance(exptype, ConverterCallbackType):
+ # This is read from, not written to:
+ return None
+ if isinstance(exptype, ConverterResultType):
+ return UnknownValue.make(exptype.type, stmt.loc)
+
# Unknown value:
check_isinstance(exptype, gcc.PointerType)
return UnknownValue.make(exptype.dereference, stmt.loc)
diff --git a/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c b/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c
new file mode 100644
index 0000000..5cbdd4b
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c
@@ -0,0 +1,42 @@
+/*
+ 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>
+
+/* Adapted from Python's Objects/listobject.c:listindex */
+PyObject *
+correct_usage_of_converter(PyObject *self, PyObject *args)
+{
+ Py_ssize_t start, stop;
+ if (!PyArg_ParseTuple(args, "O&O&",
+ _PyEval_SliceIndex, &start,
+ _PyEval_SliceIndex, &stop)) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/script.py b/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/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/PyArg_ParseTuple/correct_converter/stdout.txt b/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/stdout.txt
new file mode 100644
index 0000000..221c584
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/stdout.txt
@@ -0,0 +1,43 @@
+Trace 0:
+ Transitions:
+ 'when PyArg_ParseTuple() succeeds'
+ 'taking False path'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c', line=33), region=RegionForGlobal(gcc.VarDecl('_Py_NoneStruct')))
+ str(): (struct PyObject *)&RegionForGlobal(gcc.VarDecl('_Py_NoneStruct')) from tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c:33
+ r->ob_refcnt: refs: 1 + N where N >= 1
+ r->ob_type: None
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c', line=24), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c', line=24), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c:25
+
+Trace 1:
+ Transitions:
+ 'when PyArg_ParseTuple() fails'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c', line=30), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c:30
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c', line=24), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c', line=24), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_TypeError')) from tests/cpychecker/refcounts/PyArg_ParseTuple/correct_converter/input.c:27
12 years, 5 months