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