[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-python-plugin-commits
Subject: [gcc-python-plugin] cpychecker: improved handling of unknown functions that return a PyObject * subc
From: dmalcolm () fedoraproject ! org (dmalcolm)
Date: 2012-02-28 20:15:23
Message-ID: 20120228201524.10D5A158E () lists ! fedorahosted ! org
[Download RAW message or body]
commit ef9cdb8bb9af87e6b4b310ffd152b0dbc280ceba
Author: David Malcolm <dmalcolm at redhat.com>
Date: Tue Feb 28 15:14:02 2012 -0500
cpychecker: improved handling of unknown functions that return a PyObject * \
subclass In 90d237c02bb8fe6bd7b40aa6c2420652c87ce906 unknown functions that return
a PyObject* are assumed to return either a new reference, or return NULL
setting an exception.
Generalize this for functions returning PyObject subclasses.
Fixes a false warning for psycopg:
psycopg/connection_type.c: In function ‘psyco_conn_tpc_begin':
psycopg/connection_type.c:228:1: warning: returning (PyObject*)NULL without \
setting an exception
libcpychecker/absinterp.py | 10 ++-
.../refcounts/unrecognized_function4/input.c | 51 +++++++++++++
.../refcounts/unrecognized_function4/script.py | 22 ++++++
.../refcounts/unrecognized_function4/stdout.txt | 79 ++++++++++++++++++++
4 files changed, 158 insertions(+), 4 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index a7295d7..d7ecb89 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -211,8 +211,9 @@ class AbstractValue(object):
check_isinstance(stmt, gcc.GimpleCall)
returntype = stmt.fn.type.dereference.type
- if str(returntype) == 'struct PyObject *':
- log('Invocation of function pointer returning PyObject *')
+ from libcpychecker.refcounts import type_is_pyobjptr_subclass
+ if type_is_pyobjptr_subclass(returntype):
+ log('Invocation of function pointer returning PyObject * (or subclass)')
# Assume that all such functions either:
# - return a new reference, or
# - return NULL and set an exception (e.g. MemoryError)
@@ -2212,8 +2213,9 @@ class State(object):
raise NotImplementedError('not yet implemented: %s' % fnname)
# Unknown function returning (PyObject*):
- if str(stmt.fn.operand.type.type) == 'struct PyObject *':
- log('Invocation of unknown function returning PyObject *: %r' % \
fnname) + from libcpychecker.refcounts import type_is_pyobjptr_subclass
+ if type_is_pyobjptr_subclass(stmt.fn.operand.type.type):
+ log('Invocation of unknown function returning PyObject * (or \
subclass): %r' % fnname)
fnmeta = FnMeta(name=fnname)
diff --git a/tests/cpychecker/refcounts/unrecognized_function4/input.c \
b/tests/cpychecker/refcounts/unrecognized_function4/input.c new file mode 100644
index 0000000..e691582
--- /dev/null
+++ b/tests/cpychecker/refcounts/unrecognized_function4/input.c
@@ -0,0 +1,51 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm at redhat.com>
+ Copyright 2012 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>
+
+/*
+ Ensure that the checker can cope with calls to a function that it doesn't
+ recognize that returns a PyObject subclass:
+*/
+typedef struct FooObject {
+ PyObject_HEAD
+ int i;
+} FooObject;
+
+extern FooObject *make_foo(int i);
+
+PyObject *
+test(PyObject *self, PyObject *args)
+{
+ FooObject *f = make_foo(42);
+ if (NULL == f) {
+ return NULL; /* we assume an exception was set by make_foo() */
+ }
+ Py_DECREF(f);
+
+ Py_RETURN_NONE;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/unrecognized_function4/script.py \
b/tests/cpychecker/refcounts/unrecognized_function4/script.py new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/unrecognized_function4/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm at 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/unrecognized_function4/stdout.txt \
b/tests/cpychecker/refcounts/unrecognized_function4/stdout.txt new file mode 100644
index 0000000..c6479c7
--- /dev/null
+++ b/tests/cpychecker/refcounts/unrecognized_function4/stdout.txt
@@ -0,0 +1,79 @@
+Trace 0:
+ Transitions:
+ 'when make_foo() succeeds'
+ 'taking False path'
+ 'when taking True path'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', \
loc=gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
line=42), region=RegionForGlobal(gcc.VarDecl('_Py_NoneStruct'))) + str(): (struct \
PyObject *)&RegionForGlobal(gcc.VarDecl('_Py_NoneStruct')) from \
tests/cpychecker/refcounts/unrecognized_function4/input.c:42 + 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/unrecognized_function4/input.c', \
line=34), 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/unrecognized_function4/input.c', \
> line=34), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ new ref from (unknown) make_foo allocated at \
tests/cpychecker/refcounts/unrecognized_function4/input.c:36: + repr(): \
RegionOnHeap('new ref from (unknown) make_foo', \
gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
line=36)) + str(): new ref from (unknown) make_foo allocated at \
tests/cpychecker/refcounts/unrecognized_function4/input.c:36 + r->ob_refcnt: refs: \
0 + N where N >= 0 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', \
loc=gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
line=36), region=Region('PyTypeObject for new ref from (unknown) make_foo')) + \
Exception: + (struct PyObject *)0 from \
tests/cpychecker/refcounts/unrecognized_function4/input.c:35 +
+Trace 1:
+ Transitions:
+ 'when make_foo() succeeds'
+ 'taking False path'
+ 'when taking False path'
+ 'calling tp_dealloc on new ref from (unknown) make_foo allocated at \
tests/cpychecker/refcounts/unrecognized_function4/input.c:36' + 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', \
loc=gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
line=42), region=RegionForGlobal(gcc.VarDecl('_Py_NoneStruct'))) + str(): (struct \
PyObject *)&RegionForGlobal(gcc.VarDecl('_Py_NoneStruct')) from \
tests/cpychecker/refcounts/unrecognized_function4/input.c:42 + 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/unrecognized_function4/input.c', \
line=34), 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/unrecognized_function4/input.c', \
> line=34), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ new ref from (unknown) make_foo allocated at \
tests/cpychecker/refcounts/unrecognized_function4/input.c:36: + repr(): \
RegionOnHeap('new ref from (unknown) make_foo', \
gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
line=36)) + str(): new ref from (unknown) make_foo allocated at \
tests/cpychecker/refcounts/unrecognized_function4/input.c:36 + r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)0 from \
tests/cpychecker/refcounts/unrecognized_function4/input.c:35 +
+Trace 2:
+ Transitions:
+ 'when make_foo() fails'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', \
loc=gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
line=38), value=0) + str(): (struct PyObject *)0 from \
tests/cpychecker/refcounts/unrecognized_function4/input.c:38 + \
Region("region-for-arg-gcc.ParmDecl('self')"): + repr(): \
Region("region-for-arg-gcc.ParmDecl('self')") + str(): \
Region("region-for-arg-gcc.ParmDecl('self')") + r->ob_refcnt: refs: 0 + N where N \
>= 1 + r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', \
> loc=gcc.Location(file='tests/cpychecker/refcounts/unrecognized_function4/input.c', \
> line=34), 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/unrecognized_function4/input.c', \
line=34), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')")) + Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from \
tests/cpychecker/refcounts/unrecognized_function4/input.c:36
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic