[gcc-python-plugin] docs: Fix the line-number range of the example input
by David Hugh Malcolm
commit e8ef32c00548fcf3e11958295afb7ed22f42ded8
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Sep 29 16:31:18 2011 -0400
docs: Fix the line-number range of the example input
docs/working-with-c.rst | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/docs/working-with-c.rst b/docs/working-with-c.rst
index 7e7e5e7..f966789 100644
--- a/docs/working-with-c.rst
+++ b/docs/working-with-c.rst
@@ -66,7 +66,7 @@ The Python code for this is:
Given this sample C source file:
.. literalinclude:: ../tests/examples/spelling-checker/input.c
- :lines: 19-26
+ :lines: 19-29
:language: c
these warnings are emitted on stderr:
12 years, 7 months
[gcc-python-plugin] docs: Use the correct example input
by David Hugh Malcolm
commit d4607102df90d69ff1d1aeccf8d6fe760f196c94
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Sep 29 16:22:03 2011 -0400
docs: Use the correct example input
docs/working-with-c.rst | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/docs/working-with-c.rst b/docs/working-with-c.rst
index ae4ba7b..7e7e5e7 100644
--- a/docs/working-with-c.rst
+++ b/docs/working-with-c.rst
@@ -65,7 +65,7 @@ The Python code for this is:
Given this sample C source file:
- .. literalinclude:: ../tests/examples/hello-world/input.c
+ .. literalinclude:: ../tests/examples/spelling-checker/input.c
:lines: 19-26
:language: c
12 years, 7 months
[gcc-python-plugin] add spell-checking example to docs
by David Hugh Malcolm
commit ddec8fe123dc108f360e92a969a53e362b42e87e
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Sep 29 16:01:31 2011 -0400
add spell-checking example to docs
docs/working-with-c.rst | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+), 0 deletions(-)
---
diff --git a/docs/working-with-c.rst b/docs/working-with-c.rst
index eb8251e..ae4ba7b 100644
--- a/docs/working-with-c.rst
+++ b/docs/working-with-c.rst
@@ -46,3 +46,29 @@ Here's the expected output:
Notice how the call to `printf` has already been optimized into a call
to `__builtin_puts`.
+
+
+Spell-checking string constants within source code
+--------------------------------------------------
+
+This example add a spell-checker pass to GCC: all string constants are run through the "enchant" spelling-checker:
+
+ .. code-block:: bash
+
+ $ ./gcc-with-python tests/examples/spelling-checker/script.py input.c
+
+The Python code for this is:
+
+ .. literalinclude:: ../tests/examples/spelling-checker/script.py
+ :lines: 18-
+ :language: python
+
+Given this sample C source file:
+
+ .. literalinclude:: ../tests/examples/hello-world/input.c
+ :lines: 19-26
+ :language: c
+
+these warnings are emitted on stderr:
+
+ .. literalinclude:: ../tests/examples/spelling-checker/stderr.txt
12 years, 7 months
[gcc-python-plugin] add spell-checking example
by David Hugh Malcolm
commit a8920575d372ef9a38779604d60d211921086893
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Sep 29 15:51:45 2011 -0400
add spell-checking example
run-test-suite.py | 5 +++
tests/examples/spelling-checker/input.c | 37 ++++++++++++++++++++
tests/examples/spelling-checker/script.py | 51 ++++++++++++++++++++++++++++
tests/examples/spelling-checker/stderr.txt | 13 +++++++
4 files changed, 106 insertions(+), 0 deletions(-)
---
diff --git a/run-test-suite.py b/run-test-suite.py
index b50bbce..ae7857e 100644
--- a/run-test-suite.py
+++ b/run-test-suite.py
@@ -189,6 +189,11 @@ def run_test(testdir):
# don't treat the stderr output as leading to an expected failure:
expsuccess = True
+ if testdir == 'tests/examples/spelling-checker':
+ # This test case emits warnings on stderr;
+ # don't treat the stderr output as leading to an expected failure:
+ expsuccess = True
+
# Check exit code:
if expsuccess:
# Expect a successful exit:
diff --git a/tests/examples/spelling-checker/input.c b/tests/examples/spelling-checker/input.c
new file mode 100644
index 0000000..7123c32
--- /dev/null
+++ b/tests/examples/spelling-checker/input.c
@@ -0,0 +1,37 @@
+/*
+ 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 <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ const char *p = argc ? "correctly spelled" : "not so korectly speled";
+
+ printf("The quick brown fox jumps over the lazy dog\n");
+
+ printf("Ths s n xmple f spllng mstke\n");
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/examples/spelling-checker/script.py b/tests/examples/spelling-checker/script.py
new file mode 100644
index 0000000..fbc6347
--- /dev/null
+++ b/tests/examples/spelling-checker/script.py
@@ -0,0 +1,51 @@
+# -*- 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/>.
+
+import gcc
+
+# Use the Python bindings to the "enchant" spellchecker:
+import enchant
+spellingdict = enchant.Dict("en_US")
+
+class SpellcheckingPass(gcc.GimplePass):
+ def execute(self, fun):
+ # This is called per-function during compilation:
+ for bb in fun.cfg.basic_blocks:
+ if bb.gimple:
+ for stmt in bb.gimple:
+ stmt.walk_tree(self.spellcheck_node, stmt.loc)
+
+ def spellcheck_node(self, node, loc):
+ # Spellcheck any textual constants found within the node:
+ if isinstance(node, gcc.StringCst):
+ words = node.constant.split()
+ for word in words:
+ if not spellingdict.check(word):
+ # Warn about the spelling error (controlling the warning
+ # with the -Wall command-line option):
+ if gcc.warning(loc,
+ gcc.Option('-Wall'),
+ 'Possibly misspelt word in string constant: %r' % word):
+ # and, if the warning was not suppressed at the command line, emit
+ # suggested respellings:
+ suggestions = spellingdict.suggest(word)
+ if suggestions:
+ gcc.inform(loc, 'Suggested respellings: %r' % ', '.join(suggestions))
+
+ps = SpellcheckingPass(name='spellchecker')
+ps.register_after('cfg')
diff --git a/tests/examples/spelling-checker/stderr.txt b/tests/examples/spelling-checker/stderr.txt
new file mode 100644
index 0000000..be9185a
--- /dev/null
+++ b/tests/examples/spelling-checker/stderr.txt
@@ -0,0 +1,13 @@
+tests/examples/spelling-checker/input.c: In function 'main':
+tests/examples/spelling-checker/input.c:24:48: warning: Possibly misspelt word in string constant: 'korectly' [-Wall]
+tests/examples/spelling-checker/input.c:24:48: note: Suggested respellings: 'correctly'
+tests/examples/spelling-checker/input.c:24:48: warning: Possibly misspelt word in string constant: 'speled' [-Wall]
+tests/examples/spelling-checker/input.c:24:48: note: Suggested respellings: 'speed, spieled, spelled, spewed, speckled, peeled, sped'
+tests/examples/spelling-checker/input.c:28:11: warning: Possibly misspelt word in string constant: 'Ths' [-Wall]
+tests/examples/spelling-checker/input.c:28:11: note: Suggested respellings: "Th, Th's, Ohs, Thu, TVs, T's, Th s, Ts, This, Thus, The, Tho, Tbs, Thy, Goths"
+tests/examples/spelling-checker/input.c:28:11: warning: Possibly misspelt word in string constant: 'xmple' [-Wall]
+tests/examples/spelling-checker/input.c:28:11: note: Suggested respellings: 'ample'
+tests/examples/spelling-checker/input.c:28:11: warning: Possibly misspelt word in string constant: 'spllng' [-Wall]
+tests/examples/spelling-checker/input.c:28:11: note: Suggested respellings: 'spelling'
+tests/examples/spelling-checker/input.c:28:11: warning: Possibly misspelt word in string constant: 'mstke' [-Wall]
+tests/examples/spelling-checker/input.c:28:11: note: Suggested respellings: 'mistake'
diff --git a/tests/examples/spelling-checker/stdout.txt b/tests/examples/spelling-checker/stdout.txt
new file mode 100644
index 0000000..e69de29
12 years, 7 months
[gcc-python-plugin] add a gcc.Gimple.walk_tree method
by David Hugh Malcolm
commit 0f987846ef9e059058673be4a32c5c26ae397e8a
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Sep 29 15:39:42 2011 -0400
add a gcc.Gimple.walk_tree method
docs/gimple.rst | 16 ++++
gcc-python-closure.c | 24 ++++--
gcc-python-closure.h | 3 +-
gcc-python-gimple.c | 78 ++++++++++++++++++++
gcc-python-wrappers.h | 3 +
gcc-python.c | 2 +-
generate-gimple-c.py | 8 ++
tests/plugin/gimple-walk-tree/dump-all/input.c | 55 ++++++++++++++
tests/plugin/gimple-walk-tree/dump-all/script.py | 36 +++++++++
tests/plugin/gimple-walk-tree/dump-all/stdout.txt | 70 ++++++++++++++++++
tests/plugin/gimple-walk-tree/exceptions/input.c | 55 ++++++++++++++
tests/plugin/gimple-walk-tree/exceptions/script.py | 36 +++++++++
.../plugin/gimple-walk-tree/exceptions/stderr.txt | 16 ++++
.../plugin/gimple-walk-tree/exceptions/stdout.txt | 4 +
tests/plugin/gimple-walk-tree/find-one/input.c | 55 ++++++++++++++
tests/plugin/gimple-walk-tree/find-one/script.py | 40 ++++++++++
tests/plugin/gimple-walk-tree/find-one/stdout.txt | 22 ++++++
17 files changed, 512 insertions(+), 11 deletions(-)
---
diff --git a/docs/gimple.rst b/docs/gimple.rst
index 31776bd..e0c8ae5 100644
--- a/docs/gimple.rst
+++ b/docs/gimple.rst
@@ -68,6 +68,22 @@ TODO
which won't arbitrarily change each time.
+ .. py:method:: walk_tree(callback, *args, **kwargs)
+
+ Visit all :py:class:`gcc.Tree` nodes associated with this
+ statement, potentially more than once each. This will visit both the
+ left-hand-side and right-hand-side operands of the statement (if any),
+ and recursively visit any of their child nodes.
+
+ For each node, the callback is invoked, supplying the node, and any
+ extra positional and keyword arguments passed to `walk_tree`::
+
+ callback(node, *args, **kwargs)
+
+ If the callback returns a true value, the traversal stops, and that
+ `gcc.Tree` is the result of the call to `walk_tree`. Otherwise, the
+ traversal continues, and `walk_tree` eventually returns `None`.
+
.. py:class:: gcc.GimpleAssign
Subclass of :py:class:`gcc.Gimple`: an assignment of an expression to an l-value
diff --git a/gcc-python-closure.c b/gcc-python-closure.c
index 0e975a1..c6f83dc 100644
--- a/gcc-python-closure.c
+++ b/gcc-python-closure.c
@@ -63,7 +63,7 @@ gcc_python_closure_new(PyObject *callback, PyObject *extraargs, PyObject *kwargs
}
PyObject *
-gcc_python_closure_make_args(struct callback_closure * closure, PyObject *wrapped_gcc_data)
+gcc_python_closure_make_args(struct callback_closure * closure, int add_cfun, PyObject *wrapped_gcc_data)
{
PyObject *args = NULL;
PyObject *cfun_obj = NULL;
@@ -76,26 +76,32 @@ gcc_python_closure_make_args(struct callback_closure * closure, PyObject *wrappe
if (wrapped_gcc_data) {
/*
- Equivalent to:
+ Equivalent to either:
args = (gcc_data, cfun, ) + extraargs
+ or:
+ args = (gcc_data, ) + extraargs
*/
- args = PyTuple_New(2 + PyTuple_Size(closure->extraargs));
+ args = PyTuple_New((add_cfun ? 2 : 1) + PyTuple_Size(closure->extraargs));
if (!args) {
goto error;
}
- cfun_obj = gcc_python_make_wrapper_function(cfun);
- if (!cfun_obj) {
- goto error;
- }
+ if (add_cfun) {
+ cfun_obj = gcc_python_make_wrapper_function(cfun);
+ if (!cfun_obj) {
+ goto error;
+ }
+ }
PyTuple_SetItem(args, 0, wrapped_gcc_data);
- PyTuple_SetItem(args, 1, cfun_obj);
+ if (add_cfun) {
+ PyTuple_SetItem(args, 1, cfun_obj);
+ }
Py_INCREF(wrapped_gcc_data);
for (i = 0; i < PyTuple_Size(closure->extraargs); i++) {
PyObject *item = PyTuple_GetItem(closure->extraargs, i);
- PyTuple_SetItem(args, i + 2, item);
+ PyTuple_SetItem(args, i + (add_cfun ? 2 : 1), item);
Py_INCREF(item);
}
diff --git a/gcc-python-closure.h b/gcc-python-closure.h
index 2297998..99dc170 100644
--- a/gcc-python-closure.h
+++ b/gcc-python-closure.h
@@ -31,7 +31,8 @@ struct callback_closure *
gcc_python_closure_new(PyObject *callback, PyObject *extraargs, PyObject *kwargs);
PyObject *
-gcc_python_closure_make_args(struct callback_closure * closure, PyObject *wrapped_gcc_data);
+gcc_python_closure_make_args(struct callback_closure * closure,
+ int add_cfun, PyObject *wrapped_gcc_data);
/*
PEP-7
diff --git a/gcc-python-gimple.c b/gcc-python-gimple.c
index f5b739f..7baec2b 100644
--- a/gcc-python-gimple.c
+++ b/gcc-python-gimple.c
@@ -21,6 +21,7 @@
#include "gcc-python.h"
#include "gcc-python-wrappers.h"
#include "gcc-python-compat.h"
+#include "gcc-python-closure.h"
#include "gimple.h"
#include "tree-flow.h"
#include "tree-flow-inline.h"
@@ -62,6 +63,83 @@ gcc_Gimple_str(struct PyGccGimple * self)
return do_pretty_print(self, 0, 0);
}
+static tree
+gimple_walk_tree_callback(tree *tree_ptr, int *walk_subtrees, void *data)
+{
+ struct walk_stmt_info *wi = (struct walk_stmt_info*)data;
+ struct callback_closure *closure = (struct callback_closure *)wi->info;
+ PyObject *tree_obj = NULL;
+ PyObject *args = NULL;
+ PyObject *result = NULL;
+
+ assert(closure);
+ assert(*tree_ptr);
+ tree_obj = gcc_python_make_wrapper_tree(*tree_ptr);
+ if (!tree_obj) {
+ goto error;
+ }
+
+ args = gcc_python_closure_make_args(closure, 0, tree_obj);
+ if (!args) {
+ goto error;
+ }
+
+ /* Invoke the python callback: */
+ result = PyObject_Call(closure->callback, args, closure->kwargs);
+ if (!result) {
+ goto error;
+ }
+
+ if (PyObject_IsTrue(result)) {
+ Py_DECREF(result);
+ return *tree_ptr;
+ } else {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ error:
+ /* On an exception, terminate the traversal: */
+ *walk_subtrees = 0;
+ Py_XDECREF(tree_obj);
+ Py_XDECREF(args);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject *
+gcc_Gimple_walk_tree(struct PyGccGimple * self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *callback;
+ PyObject *extraargs = NULL;
+ struct callback_closure *closure;
+ tree result;
+ struct walk_stmt_info wi;
+
+ callback = PyTuple_GetItem(args, 0);
+ extraargs = PyTuple_GetSlice(args, 1, PyTuple_Size(args));
+
+ closure = gcc_python_closure_new(callback, extraargs, kwargs);
+ if (!closure) {
+ return NULL;
+ }
+
+ memset(&wi, 0, sizeof(wi));
+ wi.info = closure;
+
+ result = walk_gimple_op (self->stmt,
+ gimple_walk_tree_callback,
+ &wi);
+ Py_DECREF(closure);
+
+ /* Propagate exceptions: */
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+
+ return gcc_python_make_wrapper_tree(result);
+}
+
PyObject *
gcc_Gimple_get_rhs(struct PyGccGimple *self, void *closure)
{
diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h
index a9ca28f..b67320a 100644
--- a/gcc-python-wrappers.h
+++ b/gcc-python-wrappers.h
@@ -142,6 +142,9 @@ PyObject *
gcc_Gimple_str(struct PyGccGimple * self);
PyObject *
+gcc_Gimple_walk_tree(struct PyGccGimple * self, PyObject *args, PyObject *kwargs);
+
+PyObject *
gcc_Gimple_get_rhs(struct PyGccGimple *self, void *closure);
PyObject *
diff --git a/gcc-python.c b/gcc-python.c
index f6c5f5f..69b5b49 100644
--- a/gcc-python.c
+++ b/gcc-python.c
@@ -172,7 +172,7 @@ gcc_python_finish_invoking_callback(PyGILState_STATE gstate,
input_location = cfun->function_start_locus;
}
- args = gcc_python_closure_make_args(closure, wrapped_gcc_data);
+ args = gcc_python_closure_make_args(closure, 1, wrapped_gcc_data);
if (!args) {
goto cleanup;
}
diff --git a/generate-gimple-c.py b/generate-gimple-c.py
index 8e475ae..960915b 100644
--- a/generate-gimple-c.py
+++ b/generate-gimple-c.py
@@ -225,6 +225,14 @@ gcc_Gimple_get_block(struct PyGccGimple *self, void *closure)
tp_repr = '(reprfunc)gcc_Gimple_repr',
tp_str = '(reprfunc)gcc_Gimple_str',
)
+ methods = PyMethodTable('gcc_Gimple_methods', [])
+ methods.add_method('walk_tree',
+ '(PyCFunction)gcc_Gimple_walk_tree',
+ 'METH_VARARGS | METH_KEYWORDS',
+ "Visit all gcc.Tree nodes associated with this statement")
+ cu.add_defn(methods.c_defn())
+ pytype.tp_methods = methods.identifier
+
cu.add_defn(pytype.c_defn())
modinit_preinit += pytype.c_invoke_type_ready()
modinit_postinit += pytype.c_invoke_add_to_module()
diff --git a/tests/plugin/gimple-walk-tree/dump-all/input.c b/tests/plugin/gimple-walk-tree/dump-all/input.c
new file mode 100644
index 0000000..ca4b30f
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/dump-all/input.c
@@ -0,0 +1,55 @@
+/*
+ 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/>.
+*/
+
+/*
+ Trivial example code to be compiled, for testing purposes
+ */
+
+#include <stdio.h>
+
+int
+helper_function(void)
+{
+ printf("I am a helper function\n");
+ return 42;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ printf("argc: %i\n", argc);
+
+ for (i = 0; i < argc; i++) {
+ printf("argv[%i]: %s\n", argv[i]);
+ }
+
+ helper_function();
+
+ return 0;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/gimple-walk-tree/dump-all/script.py b/tests/plugin/gimple-walk-tree/dump-all/script.py
new file mode 100644
index 0000000..ec4fdb9
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/dump-all/script.py
@@ -0,0 +1,36 @@
+# -*- 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/>.
+
+# Selftest for gcc.Gimple.walk_tree
+import gcc
+
+class DumpTreeNodesPass(gcc.GimplePass):
+ def execute(self, fun):
+ # This is called per-function during compilation:
+ print('fun: %s' % fun)
+ for bb in fun.cfg.basic_blocks:
+ if bb.gimple:
+ for stmt in bb.gimple:
+ print(' stmt: %s' % stmt)
+ stmt.walk_tree(self.dump_node, stmt.loc)
+
+ def dump_node(self, node, loc):
+ print(' node: %r (%s)' % (node, node))
+
+ps = DumpTreeNodesPass(name='dump-tree-nodes')
+ps.register_after('cfg')
diff --git a/tests/plugin/gimple-walk-tree/dump-all/stdout.txt b/tests/plugin/gimple-walk-tree/dump-all/stdout.txt
new file mode 100644
index 0000000..8a474dd
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/dump-all/stdout.txt
@@ -0,0 +1,70 @@
+fun: gcc.Function('main')
+ stmt: D.3258 = (const char * restrict) &"argc: %i\n"[0];
+ node: <gcc.AddrExpr object at 0xdeadbeef> (&"argc: %i\n"[0])
+ node: <gcc.ArrayRef object at 0xdeadbeef> ("argc: %i\n"[0])
+ node: gcc.StringCst('argc: %i\n') ("argc: %i\n")
+ node: gcc.IntegerCst(0) (0)
+ node: gcc.VarDecl(3258) (gcc.VarDecl(3258))
+ stmt: printf (D.3258, argc);
+ node: <gcc.AddrExpr object at 0xdeadbeef> (printf)
+ node: gcc.FunctionDecl('printf') (gcc.FunctionDecl('printf'))
+ node: gcc.VarDecl(3258) (gcc.VarDecl(3258))
+ node: gcc.ParmDecl('argc') (gcc.ParmDecl('argc'))
+ stmt: i = 0;
+ node: gcc.IntegerCst(0) (0)
+ node: gcc.VarDecl('i') (gcc.VarDecl('i'))
+ stmt: D.3259 = (long unsigned int) i;
+ node: gcc.VarDecl('i') (gcc.VarDecl('i'))
+ node: gcc.VarDecl(3259) (gcc.VarDecl(3259))
+ stmt: D.3260 = D.3259 * 8;
+ node: gcc.VarDecl(3259) (gcc.VarDecl(3259))
+ node: gcc.IntegerCst(8) (8)
+ node: gcc.VarDecl(3260) (gcc.VarDecl(3260))
+ stmt: D.3261 = argv + D.3260;
+ node: gcc.ParmDecl('argv') (gcc.ParmDecl('argv'))
+ node: gcc.VarDecl(3260) (gcc.VarDecl(3260))
+ node: gcc.VarDecl(3261) (gcc.VarDecl(3261))
+ stmt: D.3262 = *D.3261;
+ node: <gcc.MemRef object at 0xdeadbeef> (*D.3261)
+ node: gcc.VarDecl(3261) (gcc.VarDecl(3261))
+ node: gcc.IntegerCst(0) (0B)
+ node: gcc.VarDecl(3262) (gcc.VarDecl(3262))
+ stmt: D.3263 = (const char * restrict) &"argv[%i]: %s\n"[0];
+ node: <gcc.AddrExpr object at 0xdeadbeef> (&"argv[%i]: %s\n"[0])
+ node: <gcc.ArrayRef object at 0xdeadbeef> ("argv[%i]: %s\n"[0])
+ node: gcc.StringCst('argv[%i]: %s\n') ("argv[%i]: %s\n")
+ node: gcc.IntegerCst(0) (0)
+ node: gcc.VarDecl(3263) (gcc.VarDecl(3263))
+ stmt: printf (D.3263, D.3262);
+ node: <gcc.AddrExpr object at 0xdeadbeef> (printf)
+ node: gcc.FunctionDecl('printf') (gcc.FunctionDecl('printf'))
+ node: gcc.VarDecl(3263) (gcc.VarDecl(3263))
+ node: gcc.VarDecl(3262) (gcc.VarDecl(3262))
+ stmt: i = i + 1;
+ node: gcc.VarDecl('i') (gcc.VarDecl('i'))
+ node: gcc.IntegerCst(1) (1)
+ node: gcc.VarDecl('i') (gcc.VarDecl('i'))
+ stmt: if (i < argc)
+ node: gcc.VarDecl('i') (gcc.VarDecl('i'))
+ node: gcc.ParmDecl('argc') (gcc.ParmDecl('argc'))
+ stmt: helper_function ();
+ node: <gcc.AddrExpr object at 0xdeadbeef> (helper_function)
+ node: gcc.FunctionDecl('helper_function') (gcc.FunctionDecl('helper_function'))
+ stmt: D.3264 = 0;
+ node: gcc.IntegerCst(0) (0)
+ node: gcc.VarDecl(3264) (gcc.VarDecl(3264))
+ stmt: return D.3264;
+ node: gcc.VarDecl(3264) (gcc.VarDecl(3264))
+fun: gcc.Function('helper_function')
+ stmt: __builtin_puts (&"I am a helper function"[0]);
+ node: <gcc.AddrExpr object at 0xdeadbeef> (__builtin_puts)
+ node: gcc.FunctionDecl('__builtin_puts') (gcc.FunctionDecl('__builtin_puts'))
+ node: <gcc.AddrExpr object at 0xdeadbeef> (&"I am a helper function"[0])
+ node: <gcc.ArrayRef object at 0xdeadbeef> ("I am a helper function"[0])
+ node: gcc.StringCst('I am a helper function') ("I am a helper function")
+ node: gcc.IntegerCst(0) (0)
+ stmt: D.3266 = 42;
+ node: gcc.IntegerCst(42) (42)
+ node: gcc.VarDecl(3266) (gcc.VarDecl(3266))
+ stmt: return D.3266;
+ node: gcc.VarDecl(3266) (gcc.VarDecl(3266))
diff --git a/tests/plugin/gimple-walk-tree/exceptions/input.c b/tests/plugin/gimple-walk-tree/exceptions/input.c
new file mode 100644
index 0000000..ca4b30f
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/exceptions/input.c
@@ -0,0 +1,55 @@
+/*
+ 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/>.
+*/
+
+/*
+ Trivial example code to be compiled, for testing purposes
+ */
+
+#include <stdio.h>
+
+int
+helper_function(void)
+{
+ printf("I am a helper function\n");
+ return 42;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ printf("argc: %i\n", argc);
+
+ for (i = 0; i < argc; i++) {
+ printf("argv[%i]: %s\n", argv[i]);
+ }
+
+ helper_function();
+
+ return 0;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/gimple-walk-tree/exceptions/script.py b/tests/plugin/gimple-walk-tree/exceptions/script.py
new file mode 100644
index 0000000..ea20388
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/exceptions/script.py
@@ -0,0 +1,36 @@
+# -*- 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/>.
+
+# Selftest for gcc.Gimple.walk_tree
+import gcc
+
+class WalkTreeNodesPass(gcc.GimplePass):
+ def execute(self, fun):
+ # This is called per-function during compilation:
+ print('fun: %s' % fun)
+ for bb in fun.cfg.basic_blocks:
+ if bb.gimple:
+ for stmt in bb.gimple:
+ print(' stmt: %s' % stmt)
+ stmt.walk_tree(self.dump_node, stmt.loc)
+
+ def dump_node(self, node, loc):
+ raise RuntimeError('this is a test error')
+
+ps = WalkTreeNodesPass(name='walk-tree-nodes')
+ps.register_after('cfg')
diff --git a/tests/plugin/gimple-walk-tree/exceptions/stderr.txt b/tests/plugin/gimple-walk-tree/exceptions/stderr.txt
new file mode 100644
index 0000000..36c1cd1
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/exceptions/stderr.txt
@@ -0,0 +1,16 @@
+tests/plugin/gimple-walk-tree/exceptions/input.c: In function 'main':
+tests/plugin/gimple-walk-tree/exceptions/input.c:35:1: error: Unhandled Python exception raised calling 'execute' method
+Traceback (most recent call last):
+ File "tests/plugin/gimple-walk-tree/exceptions/script.py", line 30, in execute
+ stmt.walk_tree(self.dump_node, stmt.loc)
+ File "tests/plugin/gimple-walk-tree/exceptions/script.py", line 33, in dump_node
+ raise RuntimeError('this is a test error')
+RuntimeError: this is a test error
+tests/plugin/gimple-walk-tree/exceptions/input.c: In function 'helper_function':
+tests/plugin/gimple-walk-tree/exceptions/input.c:28:1: error: Unhandled Python exception raised calling 'execute' method
+Traceback (most recent call last):
+ File "tests/plugin/gimple-walk-tree/exceptions/script.py", line 30, in execute
+ stmt.walk_tree(self.dump_node, stmt.loc)
+ File "tests/plugin/gimple-walk-tree/exceptions/script.py", line 33, in dump_node
+ raise RuntimeError('this is a test error')
+RuntimeError: this is a test error
diff --git a/tests/plugin/gimple-walk-tree/exceptions/stdout.txt b/tests/plugin/gimple-walk-tree/exceptions/stdout.txt
new file mode 100644
index 0000000..c4ee227
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/exceptions/stdout.txt
@@ -0,0 +1,4 @@
+fun: gcc.Function('main')
+ stmt: D.3258 = (const char * restrict) &"argc: %i\n"[0];
+fun: gcc.Function('helper_function')
+ stmt: __builtin_puts (&"I am a helper function"[0]);
diff --git a/tests/plugin/gimple-walk-tree/find-one/input.c b/tests/plugin/gimple-walk-tree/find-one/input.c
new file mode 100644
index 0000000..ca4b30f
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/find-one/input.c
@@ -0,0 +1,55 @@
+/*
+ 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/>.
+*/
+
+/*
+ Trivial example code to be compiled, for testing purposes
+ */
+
+#include <stdio.h>
+
+int
+helper_function(void)
+{
+ printf("I am a helper function\n");
+ return 42;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ printf("argc: %i\n", argc);
+
+ for (i = 0; i < argc; i++) {
+ printf("argv[%i]: %s\n", argv[i]);
+ }
+
+ helper_function();
+
+ return 0;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/gimple-walk-tree/find-one/script.py b/tests/plugin/gimple-walk-tree/find-one/script.py
new file mode 100644
index 0000000..bf2a0f5
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/find-one/script.py
@@ -0,0 +1,40 @@
+# -*- 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/>.
+
+# Selftest for gcc.Gimple.walk_tree
+import gcc
+
+class FindTreeNodesPass(gcc.GimplePass):
+ def execute(self, fun):
+ # This is called per-function during compilation:
+ print('fun: %s' % fun)
+ for bb in fun.cfg.basic_blocks:
+ if bb.gimple:
+ for stmt in bb.gimple:
+ print(' stmt: %s' % stmt)
+ node = stmt.walk_tree(self.find_node)
+ if node:
+ print(' node: %r (%s)' % (node, node))
+
+ def find_node(self, node):
+ # Locate the first string constant in each statement:
+ if isinstance(node, gcc.StringCst):
+ return True
+
+ps = FindTreeNodesPass(name='find-tree-nodes')
+ps.register_after('cfg')
diff --git a/tests/plugin/gimple-walk-tree/find-one/stdout.txt b/tests/plugin/gimple-walk-tree/find-one/stdout.txt
new file mode 100644
index 0000000..5f924e4
--- /dev/null
+++ b/tests/plugin/gimple-walk-tree/find-one/stdout.txt
@@ -0,0 +1,22 @@
+fun: gcc.Function('main')
+ stmt: D.3258 = (const char * restrict) &"argc: %i\n"[0];
+ node: gcc.StringCst('argc: %i\n') ("argc: %i\n")
+ stmt: printf (D.3258, argc);
+ stmt: i = 0;
+ stmt: D.3259 = (long unsigned int) i;
+ stmt: D.3260 = D.3259 * 8;
+ stmt: D.3261 = argv + D.3260;
+ stmt: D.3262 = *D.3261;
+ stmt: D.3263 = (const char * restrict) &"argv[%i]: %s\n"[0];
+ node: gcc.StringCst('argv[%i]: %s\n') ("argv[%i]: %s\n")
+ stmt: printf (D.3263, D.3262);
+ stmt: i = i + 1;
+ stmt: if (i < argc)
+ stmt: helper_function ();
+ stmt: D.3264 = 0;
+ stmt: return D.3264;
+fun: gcc.Function('helper_function')
+ stmt: __builtin_puts (&"I am a helper function"[0]);
+ node: gcc.StringCst('I am a helper function') ("I am a helper function")
+ stmt: D.3266 = 42;
+ stmt: return D.3266;
12 years, 7 months
[gcc-python-plugin] cpychecker: cope with gimple that uses a gcc.ResultDecl
by David Hugh Malcolm
commit 1e226e4d6c76a300bbdded7e056cb463f7a8b011
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Sep 27 16:24:14 2011 -0400
cpychecker: cope with gimple that uses a gcc.ResultDecl
libcpychecker/absinterp.py | 12 +++-
tests/cpychecker/absinterp/result-decl/input.c | 57 +++++++++++++++++++++
tests/cpychecker/absinterp/result-decl/script.py | 22 ++++++++
tests/cpychecker/absinterp/result-decl/stdout.txt | 8 +++
4 files changed, 96 insertions(+), 3 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index ec18149..6df46b6 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -688,7 +688,7 @@ class State:
log('eval_lvalue: %r %s', expr, expr)
if loc:
check_isinstance(loc, gcc.Location)
- if isinstance(expr, (gcc.VarDecl, gcc.ParmDecl)):
+ if isinstance(expr, (gcc.VarDecl, gcc.ParmDecl, gcc.ResultDecl)):
region = self.var_region(expr)
check_isinstance(region, Region)
return region
@@ -732,7 +732,7 @@ class State:
return expr
if isinstance(expr, gcc.IntegerCst):
return ConcreteValue(expr.type, loc, expr.constant)
- if isinstance(expr, (gcc.VarDecl, gcc.ParmDecl)):
+ if isinstance(expr, (gcc.VarDecl, gcc.ParmDecl, gcc.ResultDecl)):
region = self.var_region(expr)
check_isinstance(region, Region)
value = self.get_store(region, expr.type, loc)
@@ -795,7 +795,7 @@ class State:
self.value_for_region[dest_region] = value
def var_region(self, var):
- check_isinstance(var, (gcc.VarDecl, gcc.ParmDecl))
+ check_isinstance(var, (gcc.VarDecl, gcc.ParmDecl, gcc.ResultDecl))
if var not in self.region_for_var:
# Presumably a reference to a global variable:
log('adding region for global var: %r', var)
@@ -1000,6 +1000,12 @@ class State:
region = RegionOnStack('region for %r' % local, stack)
self.region_for_var[local] = region
self.value_for_region[region] = UninitializedData(local.type, fun.start)
+ # Region for the gcc.ResultDecl, if any:
+ if fun.decl.result:
+ result = fun.decl.result
+ region = RegionOnStack('region for %s' % result, stack)
+ self.region_for_var[result] = region
+ self.value_for_region[region] = UninitializedData(result.type, fun.start)
self.verify()
def mktrans_assignment(self, lhs, rhs, desc):
diff --git a/tests/cpychecker/absinterp/result-decl/input.c b/tests/cpychecker/absinterp/result-decl/input.c
new file mode 100644
index 0000000..395a4eb
--- /dev/null
+++ b/tests/cpychecker/absinterp/result-decl/input.c
@@ -0,0 +1,57 @@
+/*
+ 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 returning a struct containing pointers, which seems
+ to gimple containing an assignment to a gcc.ResultDecl;
+ in the pretty-printed gimple it looks like:
+ assign to fields of a tmp value
+ <returnval> = tmp
+ return <returnval>
+ (this seems to only happen if there are 3 or more fields, and at least two
+ are pointers; not sure of exact conditions)
+*/
+
+struct foo {
+ void *x;
+ void *y;
+ int z;
+};
+
+struct foo
+test(void *x, void *y, int z)
+{
+ struct foo result;
+
+ result.x = x;
+ result.y = y;
+ result.z = z;
+
+ return result;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/result-decl/script.py b/tests/cpychecker/absinterp/result-decl/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/absinterp/result-decl/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/result-decl/stdout.txt b/tests/cpychecker/absinterp/result-decl/stdout.txt
new file mode 100644
index 0000000..312b5e0
--- /dev/null
+++ b/tests/cpychecker/absinterp/result-decl/stdout.txt
@@ -0,0 +1,8 @@
+Trace 0:
+ Transitions:
+ 'returning'
+ Return value:
+ repr(): UninitializedData(gcctype='struct foo', loc=gcc.Location(file='tests/cpychecker/absinterp/result-decl/input.c', line=41))
+ str(): uninitialized data at tests/cpychecker/absinterp/result-decl/input.c:41
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/result-decl/input.c:41
12 years, 7 months
[gcc-python-plugin] cpychecker: optionally log each function being analyzed
by David Hugh Malcolm
commit 89cf7e37d9da4ba04b0a7269c7e84d18f4342a38
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Mon Sep 26 19:36:15 2011 -0400
cpychecker: optionally log each function being analyzed
libcpychecker/refcounts.py | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 06caac2..14dba91 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -1741,6 +1741,9 @@ def check_refcounts(fun, dump_traces=False, show_traces=False,
log('check_refcounts(%r, %r, %r)', fun, dump_traces, show_traces)
+ if 0:
+ gcc.inform(fun.start, 'Analyzing reference-counting with %s' % fun.decl.name)
+
check_isinstance(fun, gcc.Function)
if show_traces:
12 years, 7 months
[gcc-python-plugin] cpychecker: assume that function pointers returning PyObject* work like constructors
by David Hugh Malcolm
commit c24bedaed207837d233c2df9c011309fc63b6af6
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Mon Sep 26 19:29:42 2011 -0400
cpychecker: assume that function pointers returning PyObject* work like constructors
Assume that a call through a function pointer that returns PyObject* either
gives a new ref, or returns NULL and sets an exception
Update some of the function call machinery to avoid the need for the function
to have a name
libcpychecker/absinterp.py | 18 +-
libcpychecker/refcounts.py | 8 +-
.../refcounts/object_from_callback/input.c | 80 +++
.../refcounts/object_from_callback/script.py | 22 +
.../refcounts/object_from_callback/stdout.txt | 626 ++++++++++++++++++++
5 files changed, 747 insertions(+), 7 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index 4e8d66f..b6ea626 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -72,6 +72,14 @@ class AbstractValue:
check_isinstance(state, State)
check_isinstance(stmt, gcc.GimpleCall)
returntype = stmt.fn.type.dereference.type
+
+ if str(returntype) == 'struct PyObject *':
+ log('Invocation of function pointer returning PyObject *')
+ # Assume that all such functions either:
+ # - return a new reference, or
+ # - return NULL and set an exception (e.g. MemoryError)
+ return state.cpython.make_transitions_for_new_ref_or_fail(stmt,
+ 'new ref from call through function pointer')
return [state.mktrans_assignment(stmt.lhs,
UnknownValue(returntype, stmt.loc),
'calling %s' % self)]
@@ -1166,10 +1174,14 @@ class State:
check_isinstance(s_success, State)
check_isinstance(s_failure, State)
- fnname = stmt.fn.operand.name
+ if hasattr(stmt.fn, 'operand'):
+ fnname = stmt.fn.operand.name
+ return [Transition(self, s_success, '%s() succeeds' % fnname),
+ Transition(self, s_failure, '%s() fails' % fnname)]
+ else:
+ return [Transition(self, s_success, 'call succeeds'),
+ Transition(self, s_failure, 'call fails')]
- return [Transition(self, s_success, '%s() succeeds' % fnname),
- Transition(self, s_failure, '%s() fails' % fnname)]
def eval_stmt_args(self, stmt):
check_isinstance(stmt, gcc.GimpleCall)
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 5132e7f..06caac2 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -444,7 +444,7 @@ class CPython(Facet):
stmt.loc)
return newstate
- def mkstate_exception(self, stmt, fnname):
+ def mkstate_exception(self, stmt):
"""Make a new State, giving NULL and some exception"""
if stmt.lhs:
value = ConcreteValue(stmt.lhs.type, stmt.loc, 0)
@@ -465,11 +465,11 @@ class CPython(Facet):
Optionally, a name for the new object can be supplied; otherwise
a sane default will be used.
"""
- fnname = stmt.fn.operand.name
if objname is None:
+ fnname = stmt.fn.operand.name
objname = 'new ref from call to %s' % fnname
s_success, nonnull = self.mkstate_new_ref(stmt, objname)
- s_failure = self.mkstate_exception(stmt, fnname)
+ s_failure = self.mkstate_exception(stmt)
return self.state.make_transitions_for_fncall(stmt, s_success, s_failure)
def object_ptr_has_global_ob_type(self, v_object_ptr, vardecl_name):
@@ -909,7 +909,7 @@ class CPython(Facet):
# #define Py_InitModule4 Py_InitModule4TraceRefs_64
# #define Py_InitModule4 Py_InitModule4TraceRefs
s_success = self.mkstate_borrowed_ref(stmt, 'output from Py_InitModule4')
- s_failure = self.mkstate_exception(stmt, 'Py_InitModule4')
+ s_failure = self.mkstate_exception(stmt)
return self.state.make_transitions_for_fncall(stmt, s_success, s_failure)
########################################################################
diff --git a/tests/cpychecker/refcounts/object_from_callback/input.c b/tests/cpychecker/refcounts/object_from_callback/input.c
new file mode 100644
index 0000000..830ecb5
--- /dev/null
+++ b/tests/cpychecker/refcounts/object_from_callback/input.c
@@ -0,0 +1,80 @@
+/*
+ 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 when dealing with a callback that
+ constructs an object
+*/
+
+PyObject *
+test(PyObject *(*ctor)(void))
+{
+ PyObject *dict = NULL;
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+
+ dict = PyDict_New();
+ if (!dict) {
+ goto error;
+ }
+
+ key = PyLong_FromLong(500);
+ if (!key) {
+ goto error;
+ }
+
+ /*
+ Invoke the callback; the checker will assume that it follows normal
+ object ownership rules:
+ */
+ value = (*ctor)();
+ if (!value) {
+ /* should have set an exception */
+ goto error;
+ }
+
+ if (-1 == PyDict_SetItem(dict, key, value)) {
+ goto error;
+ }
+ /*
+ The successful call added refs on both "key" and "value", owned by the
+ dictionary.
+ We must now drop our references on them:
+ */
+ Py_DECREF(key);
+ Py_DECREF(value);
+
+ return dict;
+
+ error:
+ Py_XDECREF(dict);
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ return NULL;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/object_from_callback/script.py b/tests/cpychecker/refcounts/object_from_callback/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/stdout.txt b/tests/cpychecker/refcounts/object_from_callback/stdout.txt
new file mode 100644
index 0000000..a7ed67d
--- /dev/null
+++ b/tests/cpychecker/refcounts/object_from_callback/stdout.txt
@@ -0,0 +1,626 @@
+Trace 0:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() succeeds'
+ 'taking False path'
+ 'taking True path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34), region=RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)))
+ str(): (struct PyObject *)&RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)) from tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48), region=Region('PyTypeObject for new ref from call through function pointer'))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:29
+
+Trace 1:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() succeeds'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'calling tp_dealloc on new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34), region=RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)))
+ str(): (struct PyObject *)&RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)) from tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:29
+
+Trace 2:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() succeeds'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34), region=RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)))
+ str(): (struct PyObject *)&RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)) from tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48), region=Region('PyTypeObject for new ref from call through function pointer'))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:29
+
+Trace 3:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() succeeds'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking False path'
+ 'calling tp_dealloc on new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34), region=RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)))
+ str(): (struct PyObject *)&RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34)) from tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:29
+
+Trace 4:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48), region=Region('PyTypeObject for new ref from call through function pointer'))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 5:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 6:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking False path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48), region=Region('PyTypeObject for new ref from call through function pointer'))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 7:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 8:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48), region=Region('PyTypeObject for new ref from call through function pointer'))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 9:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 10:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking False path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48), region=Region('PyTypeObject for new ref from call through function pointer'))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 11:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call succeeds'
+ 'taking False path'
+ 'PyDict_SetItem() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48:
+ repr(): RegionOnHeap('new ref from call through function pointer', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=48))
+ str(): new ref from call through function pointer allocated at tests/cpychecker/refcounts/object_from_callback/input.c:48
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:54
+
+Trace 12:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:48
+
+Trace 13:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:48
+
+Trace 14:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking False path'
+ 'taking True path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: refs: 0 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39), region=RegionForGlobal(gcc.VarDecl('PyLong_Type')))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:48
+
+Trace 15:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() succeeds'
+ 'taking False path'
+ 'call fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39:
+ repr(): RegionOnHeap('PyLongObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=39))
+ str(): PyLongObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:39
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:48
+
+Trace 16:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking True path'
+ 'taking True path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/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/object_from_callback/input.c', line=34), region=RegionForGlobal(gcc.VarDecl('PyDict_Type')))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:39
+
+Trace 17:
+ Transitions:
+ 'PyDict_New() succeeds'
+ 'taking False path'
+ 'PyLong_FromLong() fails'
+ 'taking True path'
+ 'taking False path'
+ 'taking False path'
+ 'calling tp_dealloc on PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34'
+ 'taking True path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34:
+ repr(): RegionOnHeap('PyDictObject', gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=34))
+ str(): PyDictObject allocated at tests/cpychecker/refcounts/object_from_callback/input.c:34
+ r->ob_refcnt: None
+ r->ob_type: None
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:39
+
+Trace 18:
+ Transitions:
+ 'PyDict_New() fails'
+ 'taking True path'
+ 'taking True path'
+ 'taking True path'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/object_from_callback/input.c', line=71), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/object_from_callback/input.c:71
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/object_from_callback/input.c:34
12 years, 7 months
[gcc-python-plugin] cpychecker: use check_isinstance rather than "assert isinstance"
by David Hugh Malcolm
commit 41eb9662b12ec9dde727030034dae72f701524b6
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Mon Sep 26 18:57:58 2011 -0400
cpychecker: use check_isinstance rather than "assert isinstance"
libcpychecker/absinterp.py | 2 +-
libcpychecker/refcounts.py | 14 +++++++-------
2 files changed, 8 insertions(+), 8 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index cc15003..4e8d66f 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -1172,7 +1172,7 @@ class State:
Transition(self, s_failure, '%s() fails' % fnname)]
def eval_stmt_args(self, stmt):
- assert isinstance(stmt, gcc.GimpleCall)
+ check_isinstance(stmt, gcc.GimpleCall)
return [self.eval_rvalue(arg, stmt.loc)
for arg in stmt.args]
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index da0c2bb..5132e7f 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -261,13 +261,13 @@ class CPython(Facet):
check_isinstance(pyobjectptr, PointerToRegion)
ob_refcnt = self.state.make_field_region(pyobjectptr.region,
'ob_refcnt')
- assert isinstance(ob_refcnt, Region)
+ check_isinstance(ob_refcnt, Region)
oldvalue = self.state.get_store(ob_refcnt, None, loc) # FIXME: gcctype
- assert isinstance(oldvalue, AbstractValue)
+ check_isinstance(oldvalue, AbstractValue)
log('oldvalue: %r', oldvalue)
#if isinstance(oldvalue, UnknownValue):
# self.raise_split_value(oldvalue, loc)
- assert isinstance(oldvalue, RefcountValue)
+ check_isinstance(oldvalue, RefcountValue)
newvalue = fn(oldvalue)
log('newvalue: %r', newvalue)
self.state.value_for_region[ob_refcnt] = newvalue
@@ -1250,8 +1250,8 @@ class CPython(Facet):
# Definition is in Objects/object.c
#
# Return value: New reference.
- assert isinstance(stmt, gcc.GimpleCall)
- assert isinstance(stmt.fn.operand, gcc.FunctionDecl)
+ check_isinstance(stmt, gcc.GimpleCall)
+ check_isinstance(stmt.fn.operand, gcc.FunctionDecl)
# Success case: allocation and assignment:
s_success, nonnull = self.mkstate_new_ref(stmt, '_PyObject_New')
@@ -1414,8 +1414,8 @@ class CPython(Facet):
# Implemented in Objects/structseq.c
# From our perspective, this is very similar to _PyObject_New
- assert isinstance(stmt, gcc.GimpleCall)
- assert isinstance(stmt.fn.operand, gcc.FunctionDecl)
+ check_isinstance(stmt, gcc.GimpleCall)
+ check_isinstance(stmt.fn.operand, gcc.FunctionDecl)
# Success case: allocation and assignment:
s_success, nonnull = self.mkstate_new_ref(stmt, 'PyStructSequence_New')
12 years, 7 months
[gcc-python-plugin] cpychecker: remove reference to RefcountValue from absinterp
by David Hugh Malcolm
commit 192a9c19765de83504eab58c1c769dad84602d8d
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Mon Sep 26 18:47:41 2011 -0400
cpychecker: remove reference to RefcountValue from absinterp
The absinterp core implemented comparisons between abstract values by
explicitly listing all of the cases, including those involving the
RefcountValue class.
Replace this with method calls: an AbstractValue.is_lt method, which calls
out to class-specific implementations of impl_is_lt and impl_is_ge, thus
allowing us to remove a reference to RefcountValue from the core simulator
libcpychecker/absinterp.py | 79 ++++++++++++++++++++++++++++++++++++++-----
libcpychecker/refcounts.py | 13 +++++++
2 files changed, 82 insertions(+), 10 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index af32f4b..cc15003 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -38,6 +38,10 @@ from libcpychecker.types import *
# the prefix "r_" means a Region
# the prefix "f_" means a Facet
+############################################################################
+# Various kinds of r-value:
+############################################################################
+
class AbstractValue:
def __init__(self, gcctype, loc):
if gcctype:
@@ -81,6 +85,36 @@ class AbstractValue:
"""
raise NotImplementedError("is_equal for %s" % self)
+ def is_lt(self, rhs):
+ """
+ "lt" = "less-than"
+ Return a boolean, or None (meaning we don't know)
+ """
+ # First try "less-than":
+ lt_result = self.impl_is_lt(rhs)
+ if lt_result is not None:
+ return lt_result
+ # We don't know; try the other way around:
+ ge_result = rhs.impl_is_ge(self)
+ if ge_result is not None:
+ return not ge_result
+ # We don't know:
+ return None
+
+ def impl_is_lt(self, rhs):
+ """
+ "lt" = "less-than"
+ Return a boolean, or None (meaning we don't know)
+ """
+ raise NotImplementedError("impl_is_lt for %s" % self)
+
+ def impl_is_ge(self, rhs):
+ """
+ "ge" = "greater-than-or-equal"
+ Return a boolean, or None (meaning we don't know)
+ """
+ raise NotImplementedError("impl_is_ge for %s" % self)
+
class UnknownValue(AbstractValue):
"""
A value that we know nothing about
@@ -103,6 +137,12 @@ class UnknownValue(AbstractValue):
def is_equal(self, rhs):
return None
+ def impl_is_lt(self, rhs):
+ return None
+
+ def impl_is_ge(self, rhs):
+ return None
+
class ConcreteValue(AbstractValue):
"""
A known, specific value (e.g. 0)
@@ -161,6 +201,18 @@ class ConcreteValue(AbstractValue):
return self.value == rhs.value
return None
+ def impl_is_lt(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing concrete values: %s %s', self, rhs)
+ return self.value < rhs.value
+ return None
+
+ def impl_is_ge(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing concrete values: %s %s', self, rhs)
+ return self.value >= rhs.value
+ return None
+
class PointerToRegion(AbstractValue):
"""A non-NULL pointer value, pointing at a specific Region"""
def __init__(self, gcctype, loc, region):
@@ -189,6 +241,12 @@ class PointerToRegion(AbstractValue):
# We don't know:
return None
+ def impl_is_lt(self, rhs):
+ return None
+
+ def impl_is_ge(self, rhs):
+ return None
+
class DeallocatedMemory(AbstractValue):
def __str__(self):
if self.loc:
@@ -207,6 +265,16 @@ class UninitializedData(AbstractValue):
# We don't know:
return None
+ def impl_is_lt(self, rhs):
+ return None
+
+ def impl_is_ge(self, rhs):
+ return None
+
+############################################################################
+# Various kinds of predicted error:
+############################################################################
+
class PredictedError(Exception):
pass
@@ -1252,16 +1320,7 @@ class State:
# "less-than"
check_isinstance(lhs, AbstractValue)
check_isinstance(rhs, AbstractValue)
- if isinstance(rhs, ConcreteValue):
- if isinstance(lhs, ConcreteValue):
- log('comparing concrete values: %s %s', lhs, rhs)
- return lhs.value < rhs.value
- if isinstance(lhs, RefcountValue):
- log('comparing refcount value %s with concrete value: %s', lhs, rhs)
- if lhs.get_min_value() >= rhs.value:
- return False
- # We don't know:
- return None
+ return lhs.is_lt(rhs)
def is_le(lhs, rhs):
# "less-than-or-equal"
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 57307d8..da0c2bb 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -154,6 +154,19 @@ class RefcountValue(AbstractValue):
# (Equality is thus not possible for this case)
return False
+ def impl_is_lt(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing refcount value %s with concrete value: %s', lhs, rhs)
+ if self.get_min_value() >= rhs.value:
+ return False
+
+ def impl_is_ge(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing refcount value %s with concrete value: %s', lhs, rhs)
+ if self.get_min_value() >= rhs.value:
+ return True
+
+
class GenericTpDealloc(AbstractValue):
"""
A function pointer that points to a "typical" tp_dealloc callback
12 years, 7 months