commit 8abed6e97c9a35532939d5f0f102aeeb6068cde6
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Mar 30 17:15:03 2012 -0400
cpychecker: in C++ code, "this" can't be NULL
docs/tree.rst | 8 ++++
generate-tree-c.py | 19 +++++----
libcpychecker/absinterp.py | 5 ++-
tests/cpychecker/refcounts/cplusplus/this/input.cc | 45 ++++++++++++++++++++
.../cpychecker/refcounts/cplusplus/this/script.py | 22 ++++++++++
.../cpychecker/refcounts/cplusplus/this/stdout.txt | 8 ++++
6 files changed, 98 insertions(+), 9 deletions(-)
---
diff --git a/docs/tree.rst b/docs/tree.rst
index 5edae87..d54131a 100644
--- a/docs/tree.rst
+++ b/docs/tree.rst
@@ -217,6 +217,14 @@ Declarations
The :py:class:`gcc.Location` for this declaration
+ .. py:attribute:: is_artifical
+
+ (bool) Is this declaration a compiler-generated entity, rather than
+ one provided by the user?
+
+ An example of such an "artifical" declaration occurs within the
+ arguments of C++ methods: the initial `this` argument is a
+ compiler-generated :py:class:`gcc.ParmDecl`.
.. py:class:: gcc.FieldDecl
diff --git a/generate-tree-c.py b/generate-tree-c.py
index 54ffdc6..457b2de 100644
--- a/generate-tree-c.py
+++ b/generate-tree-c.py
@@ -149,6 +149,14 @@ def generate_intermediate_tree_classes():
tp_getset = getsettable.identifier,
tp_methods = methods.identifier)
+ def add_simple_getter(name, c_expression, doc):
+ getsettable.add_gsdef(name,
+ cu.add_simple_getter('gcc_%s_get_%s' %
(localname, name),
+ 'PyGccTree',
+ c_expression),
+ None,
+ doc)
+
if localname == 'Declaration':
cu.add_defn("""
PyObject *
@@ -175,16 +183,11 @@ gcc_Declaration_get_location(struct PyGccTree *self, void *closure)
'gcc_Declaration_get_location',
None,
'The gcc.Location for this declaration')
+ add_simple_getter('is_artificial',
+ 'PyBool_FromLong(DECL_ARTIFICIAL(self->t))',
+ "Is this a compiler-generated entity?")
pytype.tp_repr = '(reprfunc)gcc_Declaration_repr'
- def add_simple_getter(name, c_expression, doc):
- getsettable.add_gsdef(name,
- cu.add_simple_getter('gcc_%s_get_%s' %
(localname, name),
- 'PyGccTree',
- c_expression),
- None,
- doc)
-
if localname == 'Type':
add_simple_getter('name',
'gcc_python_make_wrapper_tree(TYPE_NAME(self->t))',
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index 35c4103..97e5d7f 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -1916,9 +1916,12 @@ class State(object):
nonnull_args = get_nonnull_arguments(fun.decl.type)
for idx, parm in enumerate(fun.decl.arguments):
+ def parm_is_this():
+ if idx == 0 and parm.is_artificial and parm.name == 'this':
+ return True
region = RegionForLocal(parm, stack)
self.region_for_var[parm] = region
- if idx in nonnull_args:
+ if idx in nonnull_args or parm_is_this():
# Make a non-NULL ptr:
other = Region('region-for-arg-%r' % parm, None)
self.region_for_var[other] = other
diff --git a/tests/cpychecker/refcounts/cplusplus/this/input.cc
b/tests/cpychecker/refcounts/cplusplus/this/input.cc
new file mode 100644
index 0000000..788af9f
--- /dev/null
+++ b/tests/cpychecker/refcounts/cplusplus/this/input.cc
@@ -0,0 +1,45 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <
http://www.gnu.org/licenses/>.
+*/
+
+
+/* Verify that the checker can handle "this" in C++ code */
+#include <Python.h>
+
+class Foo
+{
+ int x;
+
+public:
+ int
+ get_x();
+};
+
+int Foo::get_x()
+{
+ /* the checker should assume that "this" is non-NULL */
+ return this->x;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/cplusplus/this/script.py
b/tests/cpychecker/refcounts/cplusplus/this/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/cplusplus/this/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/cplusplus/this/stdout.txt
b/tests/cpychecker/refcounts/cplusplus/this/stdout.txt
new file mode 100644
index 0000000..9f488bd
--- /dev/null
+++ b/tests/cpychecker/refcounts/cplusplus/this/stdout.txt
@@ -0,0 +1,8 @@
+Trace 0:
+ Transitions:
+ 'returning'
+ Return value:
+ repr(): WithinRange(gcctype='int',
loc=gcc.Location(file='tests/cpychecker/refcounts/cplusplus/this/input.cc',
line=36), minvalue=-0x80000000, maxvalue=0x7fffffff)
+ str(): (int)val [-0x80000000 <= val <= 0x7fffffff] from
tests/cpychecker/refcounts/cplusplus/this/input.cc:36
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/cplusplus/this/input.cc:34