[gcc-python-plugin] C++ support
by David Hugh Malcolm
commit 2bb77306c37bb03a616c2554cfbf25dc02640b43
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Nov 30 16:34:37 2011 -0500
C++ support
Add "fullname" attribute to gcc.FunctionDecl, but only when the plugin is
invoked from the C++ frontend (cc1plus), gracefully handling the case when
we're invoked from other language frontends.
Add "is_public", "is_private", "is_protected", "is_static" boolean attributes
to gcc.FunctionDecl
Add "argument_types" attribute to gcc.MethodType
docs/tree.rst | 56 +++
gcc-python-tree.c | 42 ++
gcc-python-wrappers.h | 6 +
generate-tree-c.py | 25 ++-
tests/examples/cplusplus/classes/input.cc | 89 +++++
tests/examples/cplusplus/classes/script.py | 63 ++++
tests/examples/cplusplus/classes/stdout.txt | 391 ++++++++++++++++++++
.../language-specific-errors/fullname/input.c | 31 ++
.../language-specific-errors/fullname/script.py | 32 ++
.../language-specific-errors/fullname/stderr.txt | 6 +
.../language-specific-errors/fullname/stdout.txt | 2 +
11 files changed, 741 insertions(+), 2 deletions(-)
---
diff --git a/docs/tree.rst b/docs/tree.rst
index b766853..919c3e9 100644
--- a/docs/tree.rst
+++ b/docs/tree.rst
@@ -216,11 +216,55 @@ Declarations
The :py:class:`gcc.ResultDecl` representing the return value of this
function
+ .. py:attribute:: fullname
+
+ .. note:: This attribute is only usable with C++ code. Attempting to use
+ it from another language will lead to a `RuntimeError` exception.
+
+ (string) The "full name" of this function, including the scope, return
+ type and default arguments.
+
+ For example, given this code:
+
+ .. code-block:: c++
+
+ namespace Example {
+ struct Coord {
+ int x;
+ int y;
+ };
+
+ class Widget {
+ public:
+ void set_location(const struct Coord& coord);
+ };
+ };
+
+ `set_location`'s fullname is::
+
+ 'void Example::Widget::set_location(const Example::Coord&)'
+
.. py:attribute:: callgraph_node
The :py:class:`gcc.CallgraphNode` for this function declaration, or
`None`
+ .. py:attribute:: is_public
+
+ (bool) For C++: is this declaration "public"
+
+ .. py:attribute:: is_private
+
+ (bool) For C++: is this declaration "private"
+
+ .. py:attribute:: is_protected
+
+ (bool) For C++: is this declaration "protected"
+
+ .. py:attribute:: is_static
+
+ (bool) For C++: is this declaration "static"
+
.. py:class:: gcc.VarDecl
A subclass of :py:class:`gcc.Declaration` indicating the declaration of a
@@ -416,6 +460,18 @@ Additional attributes for various :py:class:`gcc.Type` subclasses:
* the attribute is present, with a list of 1-based argument indices
(Note that the result is still 0-based)
+.. py:class:: gcc.MethodType
+
+ Subclass of :py:class:`gcc.Type` representing the type of a given method.
+ Similar to :py:class:`gcc.FunctionType`
+
+ The `type` attribute holds the return type.
+
+ .. py:attribute:: argument_types
+
+ A tuple of :py:class:`gcc.Type` instances, representing the function's
+ argument types
+
Constants
---------
diff --git a/gcc-python-tree.c b/gcc-python-tree.c
index 625938e..3ba3b4c 100644
--- a/gcc-python-tree.c
+++ b/gcc-python-tree.c
@@ -23,6 +23,8 @@
#include "gcc-python-compat.h"
#include "gimple.h"
+#include "cp/cp-tree.h" /* for TFF_* for use by gcc_FunctionDecl_get_fullname */
+
//#include "rtl.h"
/*
"struct rtx_def" is declarted within rtl.h, c.f:
@@ -154,6 +156,41 @@ error:
}
PyObject *
+gcc_FunctionDecl_get_fullname(struct PyGccTree *self, void *closure)
+{
+ /*
+ Unfortunately, decl_as_string() is only available from the C++
+ frontend: cc1plus (it's defined in gcc/cp/error.c).
+
+ See http://gcc.gnu.org/ml/gcc/2011-11/msg00504.html
+
+ Hence we try to dynamically load the symbol, which will be already
+ present if we were loaded by cc1plus (for C++), and not be found
+ otherwise
+
+ Declared in cp/cp-tree.h as:
+ extern const char *decl_as_string (tree, int);
+ */
+
+ const char *(*decl_as_string)(tree, int);
+ const char *str;
+
+ decl_as_string = dlsym(RTLD_DEFAULT, "decl_as_string");
+
+ if (NULL == decl_as_string) {
+ return PyErr_Format(PyExc_RuntimeError,
+ "attribute 'fullname' is only available when compiling C++ code");
+ }
+
+ str = decl_as_string(self->t,
+ TFF_DECL_SPECIFIERS
+ |TFF_RETURN_TYPE
+ |TFF_FUNCTION_DEFAULT_ARGUMENTS
+ |TFF_EXCEPTION_SPECIFICATION);
+ return gcc_python_string_from_string(str);
+}
+
+PyObject *
gcc_IdentifierNode_repr(struct PyGccTree * self)
{
if (IDENTIFIER_POINTER(self->t)) {
@@ -297,6 +334,11 @@ gcc_FunctionType_get_argument_types(struct PyGccTree * self, void *closure)
return NULL;
}
+PyObject *
+gcc_MethodType_get_argument_types(struct PyGccTree * self,void *closure)
+{
+ return gcc_FunctionType_get_argument_types(self, closure);
+}
PyObject *
gcc_Constructor_get_elements(PyObject *self, void *closure)
diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h
index fc3bf8e..b1f3986 100644
--- a/gcc-python-wrappers.h
+++ b/gcc-python-wrappers.h
@@ -109,6 +109,9 @@ PyObject *
gcc_Declaration_repr(struct PyGccTree * self);
PyObject *
+gcc_FunctionDecl_get_fullname(struct PyGccTree *self, void *closure);
+
+PyObject *
gcc_IdentifierNode_repr(struct PyGccTree * self);
PyObject *
@@ -130,6 +133,9 @@ PyObject *
gcc_IntegerConstant_repr(struct PyGccTree * self);
PyObject *
+gcc_MethodType_get_argument_types(struct PyGccTree * self,void *closure);
+
+PyObject *
gcc_StringConstant_repr(struct PyGccTree * self);
PyObject *
diff --git a/generate-tree-c.py b/generate-tree-c.py
index 079bb1b..923b801 100644
--- a/generate-tree-c.py
+++ b/generate-tree-c.py
@@ -63,7 +63,10 @@ gcc_Tree_get_addr(struct PyGccTree *self, void *closure)
PyGetSetDef('addr', 'gcc_Tree_get_addr', None,
'The address of the underlying GCC object in memory'),
PyGetSetDef('str_no_uid', 'gcc_Tree_get_str_no_uid', None,
- 'A string representation of this object, like str(), but without including any internal UID')])
+ 'A string representation of this object, like str(), but without including any internal UID')],
+ identifier_prefix='gcc_Tree',
+ typename='PyGccTree')
+
cu.add_defn(getsettable.c_defn())
pytype = PyTypeObject(identifier = 'gcc_TreeType',
@@ -298,7 +301,9 @@ def generate_tree_code_classes():
cc = tree_type.camel_cased_string()
- getsettable = PyGetSetDefTable('gcc_%s_getset_table' % cc, [])
+ getsettable = PyGetSetDefTable('gcc_%s_getset_table' % cc, [],
+ identifier_prefix='gcc_%s' % cc,
+ typename='PyGccTree')
tp_as_number = None
tp_repr = None
@@ -462,7 +467,17 @@ def generate_tree_code_classes():
None,
"A tuple of gcc.Type instances, representing the argument types of this function type")
+ if tree_type.SYM == 'METHOD_TYPE':
+ getsettable.add_gsdef('argument_types',
+ 'gcc_MethodType_get_argument_types',
+ None,
+ "A tuple of gcc.Type instances, representing the argument types of this method type")
+
if tree_type.SYM == 'FUNCTION_DECL':
+ getsettable.add_gsdef('fullname',
+ 'gcc_FunctionDecl_get_fullname',
+ None,
+ 'C++ only: the full name of this function declaration')
add_simple_getter('function',
'gcc_python_make_wrapper_function(DECL_STRUCT_FUNCTION(self->t))',
'The gcc.Function (or None) for this declaration')
@@ -476,6 +491,12 @@ def generate_tree_code_classes():
'gcc_python_make_wrapper_cgraph_node(cgraph_get_node(self->t))',
'The gcc.CallgraphNode for this function declaration, or None')
+ for attr in ('public', 'private', 'protected', 'static'):
+ getsettable.add_simple_getter(cu,
+ 'is_%s' % attr,
+ 'PyBool_FromLong(TREE_%s(self->t))' % attr.upper(),
+ None)
+
if tree_type.SYM == 'SSA_NAME':
# c.f. "struct GTY(()) tree_ssa_name":
add_simple_getter('var',
diff --git a/tests/examples/cplusplus/classes/input.cc b/tests/examples/cplusplus/classes/input.cc
new file mode 100644
index 0000000..10032a0
--- /dev/null
+++ b/tests/examples/cplusplus/classes/input.cc
@@ -0,0 +1,89 @@
+/*
+ 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/>.
+*/
+
+/* Examples of various aspects of C++ syntax */
+namespace Example {
+ struct Coord {
+ int x;
+ int y;
+ };
+
+ class Widget {
+ protected:
+ Widget() {
+ }
+ public:
+ virtual ~Widget() {
+ }
+
+ /* Example of a pure virtual method */
+ virtual int get_width() = 0;
+
+ /* Reference: */
+ void set_location(const struct Coord& coord);
+
+ private:
+ struct Coord m_location;
+ };
+
+ class Dialog : public Widget {
+ public:
+ Dialog(): Widget() {
+ }
+
+ ~Dialog() {}
+
+ int get_width() { return 400; }
+ };
+};
+
+/* Example of a method definition, outside of the body of the class */
+void Example::Widget::set_location(const struct Coord& coord)
+{
+ this->m_location = coord;
+}
+
+/* Examples of overloaded functions: */
+void foo()
+{
+}
+
+void foo(const char *str)
+{
+}
+
+void foo(const Example::Coord& coord)
+{
+ /* Example of a call to a non-virtual method: */
+ Example::Widget *dlg = new Example::Dialog();
+ dlg->set_location(coord);
+ delete dlg;
+
+}
+
+
+
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/examples/cplusplus/classes/script.py b/tests/examples/cplusplus/classes/script.py
new file mode 100644
index 0000000..2071b95
--- /dev/null
+++ b/tests/examples/cplusplus/classes/script.py
@@ -0,0 +1,63 @@
+# -*- 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
+
+class TestPass(gcc.GimplePass):
+ def execute(self, fn):
+ print('fn: %r' % fn)
+ print(' fn.decl.name: %r' % fn.decl.name)
+ print(' fn.decl.fullname: %r' % fn.decl.fullname)
+ print(' str(fn.decl): %s' % fn.decl)
+ print(' type(fn): %r' % type(fn))
+ print(' type(fn.decl): %r' % type(fn.decl))
+ print(' type(fn.decl.type): %r' % type(fn.decl.type))
+
+ for attr in ('public', 'private', 'protected', 'static'):
+ print(' fn.decl.is_%s: %r' % (attr, getattr(fn.decl, 'is_%s' % attr)))
+
+ #fn.decl.debug()
+
+ # fn.decl is an instance of gcc.FunctionDecl:
+ print(' return type: %r' % str(fn.decl.type.type))
+ # fn.decl.type is an instance of gcc.MethodType for the methods:
+ print(' argument types: %r' % [str(t) for t in fn.decl.type.argument_types])
+
+ assert isinstance(fn.cfg, gcc.Cfg) # None for some early passes
+ assert fn.cfg.basic_blocks[0] == fn.cfg.entry
+ assert fn.cfg.basic_blocks[1] == fn.cfg.exit
+ for blockidx, bb in enumerate(fn.cfg.basic_blocks):
+ if bb.gimple:
+ print(' block %i' % blockidx)
+ for i,stmt in enumerate(bb.gimple):
+ print(' gimple[%i]:' % i)
+ print(' str(stmt): %r' % str(stmt))
+ print(' repr(stmt): %r' % repr(stmt))
+ if isinstance(stmt, gcc.GimpleCall):
+ print(' type(stmt.fn): %r' % type(stmt.fn))
+ print(' str(stmt.fn): %r' % str(stmt.fn))
+ print(' stmt.fn: %r' % stmt.fn)
+ if isinstance(stmt.fn, gcc.AddrExpr):
+ print(' stmt.fn.operand: %r' % stmt.fn.operand)
+ print(' stmt.fn.operand.fullname: %r' % stmt.fn.operand.fullname)
+ for i, arg in enumerate(stmt.args):
+ print(' str(stmt.args[%i]): %r' % (i, str(stmt.args[i])))
+ print(' str(stmt.lhs): %s' % str(stmt.lhs))
+
+test_pass = TestPass(name='test-pass')
+test_pass.register_after('cfg')
diff --git a/tests/examples/cplusplus/classes/stdout.txt b/tests/examples/cplusplus/classes/stdout.txt
new file mode 100644
index 0000000..f1cbdde
--- /dev/null
+++ b/tests/examples/cplusplus/classes/stdout.txt
@@ -0,0 +1,391 @@
+fn: gcc.Function('__base_dtor ')
+ fn.decl.name: '__base_dtor '
+ fn.decl.fullname: 'Example::Widget::~Widget()'
+ str(fn.decl): gcc.FunctionDecl('__base_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->_vptr.Widget = &_ZTVN7Example6WidgetE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'D.nnnnn = 0 & 1;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'D.nnnnn = (bool) D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'if (D.nnnnn != 0)'
+ repr(stmt): 'gcc.GimpleCond()'
+ block 4
+ gimple[0]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 5
+ gimple[0]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__base_dtor ')
+ fn.decl.name: '__base_dtor '
+ fn.decl.fullname: 'Example::Dialog::~Dialog()'
+ str(fn.decl): gcc.FunctionDecl('__base_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->D.nnnnn._vptr.Widget = &_ZTVN7Example6DialogE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'Example::Widget::~Widget (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__base_dtor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__base_dtor ')
+ stmt.fn.operand.fullname: 'Example::Widget::~Widget()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'D.nnnnn = 0 & 1;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'D.nnnnn = (bool) D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'if (D.nnnnn != 0)'
+ repr(stmt): 'gcc.GimpleCond()'
+ block 4
+ gimple[0]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 5
+ gimple[0]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
+ fn.decl.fullname: 'void foo(const Example::Coord&)'
+ str(fn.decl): gcc.FunctionDecl('foo')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.FunctionType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['const struct Coord &']
+ block 2
+ gimple[0]:
+ str(stmt): 'D.nnnnn = operator new (16);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator new'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator new')
+ stmt.fn.operand.fullname: 'void* operator new(long unsigned int) throw (std::bad_alloc)'
+ str(stmt.args[0]): '16'
+ str(stmt.lhs): gcc.VarDecl(nnnn)
+ gimple[1]:
+ str(stmt): 'dlg.0 = D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'Example::Dialog::Dialog (dlg.0);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__comp_ctor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__comp_ctor ')
+ stmt.fn.operand.fullname: 'Example::Dialog::Dialog()'
+ str(stmt.args[0]): "gcc.VarDecl('dlg.0')"
+ str(stmt.lhs): None
+ gimple[3]:
+ str(stmt): 'dlg = dlg.0;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[4]:
+ str(stmt): 'Example::Widget::set_location (dlg, coord);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'set_location'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('set_location')
+ stmt.fn.operand.fullname: 'void Example::Widget::set_location(const Example::Coord&)'
+ str(stmt.args[0]): "gcc.VarDecl('dlg')"
+ str(stmt.args[1]): "gcc.ParmDecl('coord')"
+ str(stmt.lhs): None
+ gimple[5]:
+ str(stmt): 'if (dlg != 0B)'
+ repr(stmt): 'gcc.GimpleCond()'
+ block 3
+ gimple[0]:
+ str(stmt): 'D.nnnnn = dlg->_vptr.Widget;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'D.nnnnn = D.nnnnn + 8;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'D.nnnnn = *D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'OBJ_TYPE_REF(D.nnnnn;dlg->1) (dlg);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.ObjTypeRef'>
+ str(stmt.fn): 'OBJ_TYPE_REF(D.nnnnn;dlg->1)'
+ stmt.fn: <gcc.ObjTypeRef object at 0xdeadbeef>
+ str(stmt.args[0]): "gcc.VarDecl('dlg')"
+ str(stmt.lhs): None
+ block 4
+ gimple[0]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__base_ctor ')
+ fn.decl.name: '__base_ctor '
+ fn.decl.fullname: 'Example::Dialog::Dialog()'
+ str(fn.decl): gcc.FunctionDecl('__base_ctor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'D.nnnnn = &this->D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'Example::Widget::Widget (D.nnnnn);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__base_ctor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__base_ctor ')
+ stmt.fn.operand.fullname: 'Example::Widget::Widget()'
+ str(stmt.args[0]): 'gcc.VarDecl(nnnn)'
+ str(stmt.lhs): None
+ gimple[2]:
+ str(stmt): 'this->D.nnnnn._vptr.Widget = &_ZTVN7Example6DialogE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__base_ctor ')
+ fn.decl.name: '__base_ctor '
+ fn.decl.fullname: 'Example::Widget::Widget()'
+ str(fn.decl): gcc.FunctionDecl('__base_ctor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: True
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->_vptr.Widget = &_ZTVN7Example6WidgetE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
+ fn.decl.fullname: 'void foo(const char*)'
+ str(fn.decl): gcc.FunctionDecl('foo')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.FunctionType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['const char *']
+ block 2
+ gimple[0]:
+ str(stmt): 'GIMPLE_NOP'
+ repr(stmt): 'gcc.GimpleNop()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
+ fn.decl.fullname: 'void foo()'
+ str(fn.decl): gcc.FunctionDecl('foo')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.FunctionType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: []
+ block 2
+ gimple[0]:
+ str(stmt): 'GIMPLE_NOP'
+ repr(stmt): 'gcc.GimpleNop()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('set_location')
+ fn.decl.name: 'set_location'
+ fn.decl.fullname: 'void Example::Widget::set_location(const Example::Coord&)'
+ str(fn.decl): gcc.FunctionDecl('set_location')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *', 'const struct Coord &']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->m_location = *coord;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('get_width')
+ fn.decl.name: 'get_width'
+ fn.decl.fullname: 'virtual int Example::Dialog::get_width()'
+ str(fn.decl): gcc.FunctionDecl('get_width')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'int'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'D.nnnnn = 400;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'return D.nnnnn;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__deleting_dtor ')
+ fn.decl.name: '__deleting_dtor '
+ fn.decl.fullname: 'virtual Example::Dialog::~Dialog()'
+ str(fn.decl): gcc.FunctionDecl('__deleting_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'Example::Dialog::~Dialog (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__comp_dtor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__comp_dtor ')
+ stmt.fn.operand.fullname: 'virtual Example::Dialog::~Dialog()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ gimple[2]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__deleting_dtor ')
+ fn.decl.name: '__deleting_dtor '
+ fn.decl.fullname: 'virtual Example::Widget::~Widget()'
+ str(fn.decl): gcc.FunctionDecl('__deleting_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *']
+ block 2
+ gimple[0]:
+ str(stmt): 'Example::Widget::~Widget (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__comp_dtor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__comp_dtor ')
+ stmt.fn.operand.fullname: 'virtual Example::Widget::~Widget()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ gimple[2]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
diff --git a/tests/plugin/language-specific-errors/fullname/input.c b/tests/plugin/language-specific-errors/fullname/input.c
new file mode 100644
index 0000000..5fc1a4d
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/input.c
@@ -0,0 +1,31 @@
+/*
+ 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/>.
+*/
+
+void foo(int x, int y)
+{
+}
+
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/language-specific-errors/fullname/script.py b/tests/plugin/language-specific-errors/fullname/script.py
new file mode 100644
index 0000000..9a65f84
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/script.py
@@ -0,0 +1,32 @@
+# -*- 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/>.
+
+# Verify that an attempt to use the "fullname" attribute outside of C++
+# is gracefully handled
+
+import gcc
+
+class TestPass(gcc.GimplePass):
+ def execute(self, fn):
+ print('fn: %r' % fn)
+ print(' fn.decl.name: %r' % fn.decl.name)
+ # This ought to raise a RuntimeError
+ print(' fn.decl.fullname: %r' % fn.decl.fullname)
+
+test_pass = TestPass(name='test-pass')
+test_pass.register_after('cfg')
diff --git a/tests/plugin/language-specific-errors/fullname/stderr.txt b/tests/plugin/language-specific-errors/fullname/stderr.txt
new file mode 100644
index 0000000..455762f
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/stderr.txt
@@ -0,0 +1,6 @@
+tests/plugin/language-specific-errors/fullname/input.c: In function 'foo':
+tests/plugin/language-specific-errors/fullname/input.c:21:1: error: Unhandled Python exception raised calling 'execute' method
+Traceback (most recent call last):
+ File "tests/plugin/language-specific-errors/fullname/script.py", line 29, in execute
+ print(' fn.decl.fullname: %r' % fn.decl.fullname)
+RuntimeError: attribute 'fullname' is only available when compiling C++ code
diff --git a/tests/plugin/language-specific-errors/fullname/stdout.txt b/tests/plugin/language-specific-errors/fullname/stdout.txt
new file mode 100644
index 0000000..f315c93
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/stdout.txt
@@ -0,0 +1,2 @@
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
12 years, 5 months
[gcc-python-plugin] docs: add more cross-references
by David Hugh Malcolm
commit f2a03656b1e75586221031fb04cb6ad7726be965
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Nov 30 14:22:40 2011 -0500
docs: add more cross-references
docs/tree.rst | 27 +++++++++++++++------------
1 files changed, 15 insertions(+), 12 deletions(-)
---
diff --git a/docs/tree.rst b/docs/tree.rst
index 9f834b4..b766853 100644
--- a/docs/tree.rst
+++ b/docs/tree.rst
@@ -286,13 +286,14 @@ Types
`sizeof()` this type, as an `int`, or raising `TypeError` for those
types which don't have a well-defined size
- The standard C types are accessible via class methods of gcc.Type.
+ The standard C types are accessible via class methods of :py:class:`gcc.Type`.
They are only created by GCC after plugins are loaded, and so they're
only visible during callbacks, not during the initial run of the code.
(yes, having them as class methods is slightly clumsy).
- Each of the following returns a `gcc.Type` instance representing the given
- type (or None at startup before any passes, when the types don't yet exist)
+ Each of the following returns a :py:class:`gcc.Type` instance representing
+ the given type (or None at startup before any passes, when the types don't
+ yet exist)
============================= =====================
Class method C Type
@@ -321,7 +322,7 @@ Types
.. py:class:: gcc.IntegerType
- Subclass of gcc.Type, adding a few properties:
+ Subclass of :py:class:`gcc.Type`, adding a few properties:
.. py:attribute:: unsigned
@@ -341,7 +342,7 @@ Types
.. py:class:: gcc.FloatType
- Subclass of gcc.Type representing C's `float` and `double` types
+ Subclass of :py:class:`gcc.Type` representing C's `float` and `double` types
.. py:attribute:: precision
@@ -354,9 +355,9 @@ Types
.. py:attribute:: dereference
- The gcc.Type that this type points to
+ The :py:class:`gcc.Type` that this type points to
-Additional attributes for various gcc.Type subclasses:
+Additional attributes for various :py:class:`gcc.Type` subclasses:
.. py:attribute:: const
@@ -364,7 +365,7 @@ Additional attributes for various gcc.Type subclasses:
.. py:attribute:: const_equivalent
- The gcc.Type for the `const` version of this type
+ The :py:class:`gcc.Type` for the `const` version of this type
.. py:attribute:: volatile
@@ -372,7 +373,7 @@ Additional attributes for various gcc.Type subclasses:
.. py:attribute:: volatile_equivalent
- The gcc.Type for the `volatile` version of this type
+ The :py:class:`gcc.Type` for the `volatile` version of this type
.. py:attribute:: restrict
@@ -380,13 +381,15 @@ Additional attributes for various gcc.Type subclasses:
.. py:attribute:: restrict_equivalent
- The gcc.Type for the `restrict` version of this type
+ The :py:class:`gcc.Type` for the `restrict` version of this type
.. py:class:: gcc.FunctionType
- Subclass of gcc.Type representing the type of a given function (or or a
- typedef to a function type, e.g. for callbacks).
+ Subclass of :py:class:`gcc.Type` representing the type of a given function
+ (or or a typedef to a function type, e.g. for callbacks).
+
+ See also :py:class:`gcc.FunctionType`
The `type` attribute holds the return type.
12 years, 5 months
[gcc-python-plugin] run-test-suite.py: support test cases for source languages other than C
by David Hugh Malcolm
commit 22f707d215a39ba4f1c3945dba0091e045f9488b
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Nov 30 13:36:20 2011 -0500
run-test-suite.py: support test cases for source languages other than C
run-test-suite.py | 20 +++++++++++++++-----
1 files changed, 15 insertions(+), 5 deletions(-)
---
diff --git a/run-test-suite.py b/run-test-suite.py
index 98bf748..6ff3cca 100644
--- a/run-test-suite.py
+++ b/run-test-suite.py
@@ -19,8 +19,8 @@
# subdirectory containing a "script.py" is regarded as a test case.
#
# A test consists of:
-# input.c: C source code to be compiled
-# script.py: a Python script to be run by GCC during said compilation
+# input.c/cc: C/C++ source code to be compiled
+# script.py: a Python script to be run by GCC during said compilation
# stdout.txt: (optional) the expected stdout from GCC (empty if not present)
# stderr.txt: (optional) as per stdout.txt
# getopts.py: (optional) if present, stdout from this script is
@@ -162,10 +162,20 @@ class UnexpectedOutput(CompilationError):
return self.stream.diff(self.label)
+def get_source_file(testdir):
+ # Locate the source file within the test directory,
+ # trying various different suffixes (by programming language)
+ suffixes = ['.c', '.cc', '.java', '.f', '.f90']
+ for suffix in suffixes:
+ inputfile = os.path.join(testdir, 'input%s' % suffix)
+ if os.path.exists(inputfile):
+ return inputfile
+ raise RuntimeError('Source file not found')
+
def run_test(testdir):
# Compile each 'input.c', using 'script.py'
# Assume success and empty stdout; compare against expected stderr, or empty if file not present
- c_input = os.path.join(testdir, 'input.c')
+ inputfile = get_source_file(testdir)
outfile = os.path.join(testdir, 'output.o')
script_py = os.path.join(testdir, 'script.py')
out = TestStream(os.path.join(testdir, 'stdout.txt'))
@@ -183,7 +193,7 @@ def run_test(testdir):
# Special-case: add the python include dir (for this runtime) if the C code
# uses Python.h:
- with open(c_input, 'r') as f:
+ with open(inputfile, 'r') as f:
code = f.read()
if '#include <Python.h>' in code:
args += ['-I' + get_python_inc()]
@@ -203,7 +213,7 @@ def run_test(testdir):
args += opts_out.split()
# and the source file goes at the end:
- args += [c_input]
+ args += [inputfile]
# Invoke the compiler:
p = Popen(args, env=env, stdout=PIPE, stderr=PIPE)
12 years, 5 months
[gcc-python-plugin] cpychecker: Py_BuildValue("O") can accept a ptr to any PyObject subclass
by David Hugh Malcolm
commit d4f4f42264c02f87ec6b1772d79bbe4a2ace99e9
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Nov 30 10:51:30 2011 -0500
cpychecker: Py_BuildValue("O") can accept a ptr to any PyObject subclass
The checker for Py_BuildValue("O") (and "S" and "N") was being too strict,
requiring a (PyObject*). Although it's not explicitly documented, it's
clear that these can also accept pointers to any PyObject subclass.
Fixes a false positive seen when running cpychecker on coverage-3.5.1b1.tar.gz,
in which coverage/tracer.c:Tracer_trace passes a PyFrameObject* as an argument
to such a call.
libcpychecker/Py_BuildValue.py | 11 ++++-
.../Py_BuildValue/code_O/subclass/input.c | 47 ++++++++++++++++++++
.../Py_BuildValue/code_O/subclass/script.py | 19 ++++++++
3 files changed, 76 insertions(+), 1 deletions(-)
---
diff --git a/libcpychecker/Py_BuildValue.py b/libcpychecker/Py_BuildValue.py
index 79afcd3..8d5289f 100644
--- a/libcpychecker/Py_BuildValue.py
+++ b/libcpychecker/Py_BuildValue.py
@@ -76,12 +76,21 @@ def _type_of_simple_arg(arg):
elif arg == 'K':
return get_PY_LONG_LONG().unsigned_equivalent
+class AnyPyObjectPtr(AwkwardType):
+ """
+ For use when we expect PyObject*, or any subclass
+ """
+ def is_compatible(self, actual_type, actual_arg):
+ # We expect a pointer to a PyObject*, or any subclass:
+ from libcpychecker.refcounts import type_is_pyobjptr_subclass
+ return type_is_pyobjptr_subclass(actual_type)
+
class ObjectFormatUnit(FormatUnit):
"""
Base class for Py_BuildValue format codes that expect a PyObject*
"""
def get_expected_types(self):
- return [get_PyObject().pointer]
+ return [AnyPyObjectPtr()]
class CodeSO(ObjectFormatUnit):
"""
diff --git a/tests/cpychecker/Py_BuildValue/code_O/subclass/input.c b/tests/cpychecker/Py_BuildValue/code_O/subclass/input.c
new file mode 100644
index 0000000..b93a32c
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_O/subclass/input.c
@@ -0,0 +1,47 @@
+/*
+ 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>
+
+/* Example of a PyObject subclass */
+struct SomeObject {
+ PyObject_HEAD
+ int some_field;
+};
+
+/* Instance of the PyObject subclass */
+struct SomeObject *global_instance;
+
+PyObject *
+test(PyObject *self, PyObject *args)
+{
+ /*
+ Although "O" expects a (PyObject*), a subclass should be acceptable
+ also:
+ */
+ return Py_BuildValue("O", global_instance);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_O/subclass/script.py b/tests/cpychecker/Py_BuildValue/code_O/subclass/script.py
new file mode 100644
index 0000000..e120c53
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_O/subclass/script.py
@@ -0,0 +1,19 @@
+# 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()
12 years, 5 months
[gcc-python-plugin] add release notes for 0.7
by David Hugh Malcolm
commit e12a34997261a74755e62e1f61139a2f0f95b77c
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Nov 29 16:52:21 2011 -0500
add release notes for 0.7
docs/0.7.rst | 278 ++++++++++++++++++++++++++++++++++++++++++++++++
docs/index.rst | 1 +
docs/release-notes.rst | 23 ++++
3 files changed, 302 insertions(+), 0 deletions(-)
---
diff --git a/docs/0.7.rst b/docs/0.7.rst
new file mode 100644
index 0000000..4fbac8d
--- /dev/null
+++ b/docs/0.7.rst
@@ -0,0 +1,278 @@
+0.7
+~~~
+
+This is a major update to the GCC Python plugin.
+
+The main example script, cpychecker, has seen numerous improvements, and has
+now detected many reference-counting bugs in real-world CPython extension code.
+The usability and signal:noise ratio is greatly improved over previous releases.
+
+Changes to the GCC Python Plugin
+================================
+
+It's now possible to create custom GCC attributes from Python, allowing you to
+add custom high-level annotation to a C API, and to write scripts that will
+verify these properties. It's also possible to inject preprocessor macros
+from Python. Taken together, this allows code like this:
+
+ .. literalinclude:: ../tests/examples/attributes-with-macros/input.c
+ :lines: 22-45
+ :language: c
+
+Other improvements:
+
+ * gcc's debug dump facilities are now exposed via a Python API
+
+ * it's now possible to run Python commands in GCC (rather than scripts) using
+ -fplugin-arg-python-command
+
+ * improvements to the "source location" when reporting on an unhandled
+ Python exception. Amongst other tweaks, it's now possible for a script to
+ override this, which the cpychecker uses, so that if it can't handle a
+ particular line of C code, the GCC error report gives that location before
+ reporting the Python traceback (making debugging much easier).
+
+ * "switch" statements are now properly wrapped at the Python level
+ (gcc.GimpleSwitch)
+
+ * C bitfields are now wrapped at the Python level
+
+ * gcc.Type instances now have a "sizeof" attribute, and an "attributes"
+ attribute.
+
+ * added a gcc.Gimple.walk_tree method, to make it easy to visit all nodes
+ relating to a statement
+
+ * added a new example: spell-checking all string literals in code
+
+Improvements to "cpychecker"
+============================
+
+The "libcpychecker" Python code is a large example of using the plugin: it
+extends GCC with code that tries to detect various bugs in CPython extension
+modules.
+
+The cpychecker analyzes the paths that can be followed through a C function,
+and verifies various properties, including reference-count handling.
+
+As of this release, the pass has found many reference-counting bugs in
+real-world code. You can see a list of the bugs that it has detected at:
+
+http://gcc-python-plugin.readthedocs.org/en/latest/success.html
+
+The checker is now *almost* capable of fully handling the C code within the
+gcc python plugin itself.
+
+The checker has also been reorganized to (I hope) make it easy to add checking
+for other libraries and APIs.
+
+Major rewrite of reference-count tracking
+-----------------------------------------
+
+I've rewritten the internals of how reference counts are tracked: the code now
+makes a distinction betweeen all of the reference that can be analysed within a
+single function, versus all of the other references that may exist in the rest
+of the program.
+
+This allows us to know for an object e.g. that the function doesn't directly
+own any references, but that the reference count is still > 0 (a "borrowed
+reference"), as compared to the case where the function owns a reference, but
+we don't know of any in the rest of the program (this is typical when receiving
+a "new reference" e.g. from a function call to a constructor).
+
+Within the reference-count checker, we now look for memory locations that
+store references to objects. If those locations not on the stack, then the
+references they store are now assumed to legally count towards the ob_refcnt
+that the function "owns". This is needed in order to correctly handle e.g.
+the PyList_SET_ITEM() macro, which directly writes to the list's ob_item field,
+"stealing" a reference: we can detect these references, and count them towards
+the ob_refcnt value.
+
+The checker can now detect types that look like PyObject subclasses at the C
+level (by looking at the top-most fields), and uses this information in various
+places.
+
+The checker now exposes custom GCC attributes allowing you to mark APIs that
+have non-standard reference-handling behavior:
+
+.. code-block:: c
+
+ PyObject *foo(void)
+ CPYCHECKER_RETURNS_BORROWED_REF;
+
+ extern void bar(int i, PyObject *obj, int j, PyObject *other)
+ CPYCHECKER_STEALS_REFERENCE_TO_ARG(2)
+ CPYCHECKER_STEALS_REFERENCE_TO_ARG(4);
+
+It also exposes an attribute allowing you to the run-time and compile-time
+type information for a Python extension class:
+
+.. code-block:: c
+
+ /* Define some PyObject subclass, as both a struct and a typedef */
+ struct OurObjectStruct {
+ PyObject_HEAD
+ /* other fields */
+ };
+ typedef struct OurObjectStruct OurExtensionObject;
+
+ /*
+ Declare the PyTypeObject, using the custom attribute to associate it with
+ the typedef above:
+ */
+ extern PyTypeObject UserDefinedExtension_Type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF("OurExtensionObject");
+
+Function calls with NULL-pointer arguments
+------------------------------------------
+The checker knows about various CPython API hooks that will crash on NULL
+pointer arguments, and will emit warnings when it can determine a path through
+the code that will lead to a definite call with a NULL value.
+
+
+Dereferences of uninitialized pointers
+--------------------------------------
+The checker will now complain about paths through a function for which it can
+prove that an uninitialized pointer will be dereferenced.
+
+
+Error-reporting improvements
+----------------------------
+
+The error-reporting machinery can generate HTML reports: see e.g.:
+http://readthedocs.org/docs/gcc-python-plugin/en/latest/cpychecker.html#reference-count-checking
+and http://dmalcolm.livejournal.com/6560.html
+
+The checker can now annotate its HTML (and textual) reports with information
+showing how some pertinent aspect of the program's state changes during a
+particular path through a function.
+
+For example, when reporting on reference-counting errors, the HTML report
+showing the flow through the function will now display all changes to an object's
+ob_refcnt, together with all changes to what the value ought to be (e.g. due to
+pointers being stored to persistent memory locations):
+
+ .. figure:: sample-html-error-report.png
+ :alt: screenshot of the HTML report
+
+Similarly, when reporting on exception-handling errors, it now displays the
+"history" of changes to the thread-local exception state.
+
+There's also a debug mode which dumps _everything_ that changes within the
+report, which is helpful for debugging the checker itself.
+
+The error report will attempt to use the most representative name for a leaked
+object, using a variable name or a C expression fragment as appropriate.
+
+The checker will attempt to combine duplicate error reports, so that it will
+only emit one error for all of the various traces of execution that exhibit a
+particular reference-counting bug.
+
+Finally, when writing out an HTML report, the path to the HTML is now noted
+within gcc's regular stderr messages.
+
+
+Signal:noise ratio improvements
+-------------------------------
+
+To suppress various false-positives that I commonly ran into on real code, the
+checker now makes certain assumptions:
+
+ * When encountering an unknown function that returns a PyObject*, the
+ checker assumes that it will either return a new reference to a sane
+ object (with a sane ob_type), or return NULL and set the thread-local
+ exception state.
+
+ * The checker assumes that a PyObject* argument to a function is non-NULL
+ and has a >0 refcount, and has a sane ob_type (e.g. with a sane refcount
+ and tp_dealloc)
+
+ * When dereferencing a pointer that it has no knowledge about (e.g. a
+ pointer field in a structure), the checker now assumes that it's
+ non-NULL, unless it knows that NULL is a definite possibility i.e. it
+ optimistically assumes that you know what you're doing (this could be
+ turned into a command-line option). Note that for the cases where we
+ know that the pointer can _definitely_ be NULL, an error will still be
+ reported (e.g. when considering the various possible return values for a
+ function known to be able to return NULL).
+
+Coverage of the CPython API
+---------------------------
+
+I've gone through much of the CPython API, "teaching" the checker about the
+reference-count semantics of each API call (and which calls will crash if fed a
+NULL pointer). This involves writing a simple fragment of Python code for
+each function, which describes the various different affects that the call can
+have on the internal state within the callee.
+
+This release adds support for calls to the following:
+ * _PyObject_New
+ * Py_{Initialize|Finalize}
+ * Py_InitModule4
+ * PyArg_ParseTuple[AndKeywords], and the PY_SSIZE_T_CLEAN variants (only
+ partial coverage so far: "O", "O!" should work though)
+ * PyArg_UnpackTuple
+ * PyBool_FromLong
+ * Py_BuildValue and the PY_SSIZE_T_CLEAN variant (only partial coverage so
+ far)
+ * PyDict_{GetItem,GetItemString,New,SetItem,SetItemString}
+ * PyErr_{Format,NoMemory,Occurred,Print,PrintEx,SetFromErrno[WithFilename],
+ SetObject,SetString}
+ * PyEval_InitThreads
+ * PyGILState_{Ensure,Release}
+ * PyImport_{AppendInittab,ImportModule}
+ * PyInt_{AsLong,FromLong}
+ * PyList_Append
+ * PyLong_{FromString,FromVoidPtr}
+ * PyMem_{Malloc,Free}
+ * PyModule_Add{IntConstant,Object,StringConstant}
+ * PyObject_{Call,CallMethod,HasAttrString,IsTrue,Repr,Str}
+ * PyRun_{SimpleFileExFlags,SimpleStringFlags}
+ * PySequence_GetItem
+ * PyString_{AsString,FromFormat,FromString,FromStringAndSize}
+ * PyStructSequence_{InitType,New}
+ * PySys_SetObject
+ * PyTuple_{New,SetItem,Size}
+ * PyType_{IsSubtype,Ready}
+
+I've been targetting those API entrypoints that I use myself in the plugin;
+this is one area which is particularly amenable to patching, for anyone who
+wants to get involved. I've also added a (disabled) hook that complains
+about Python API entrypoints that weren't explicitly handled, to make it easy
+to find gaps in our coverage of the CPython API.
+
+
+Other user-visible improvments
+------------------------------
+
+ * There's now a "gcc-with-cpychecker" harness, to make it easier to invoke
+ GCC with the cpychecker code from e.g. Makefiles
+
+ * The checker now respects `__attribute((nonnull))` on function arguments
+ when detecting NULL pointers
+
+ * Handle functions that don't return (e.g. "exit")
+
+ * Number the unknown heap regions, to clarify things when there's more than
+ one
+
+Internal improvements
+---------------------
+
+ * The cpychecker now has some protection against combinatorial explosion
+ for functions that have very large numbers of possible routes through
+ them. For such functions, the checker will emit a note on stderr and
+ not attempt to find reference-counting bugs in the function.
+
+ * The cpychecker is now done as a custom pass (rather than by wiring up a
+ callback associated with every pass)
+
+ * I've tuned the logging within the checker, eliminating some CPU/memory
+ consumption issues seen when analysing complicated C code. In particular,
+ the log message arguments are now only expanded when logging is enabled
+ (previously this was happening all the time).
+
+ * Lots of other internal improvements and bug fixes (e.g. handling of arrays
+ vs pointers, static vs auto local variables, add missing handlers for
+ various kinds of C expression, lots of work on improving the readability of
+ error messages)
diff --git a/docs/index.rst b/docs/index.rst
index 685e490..affa112 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -40,6 +40,7 @@ Contents:
cpychecker.rst
success.rst
misc.rst
+ release-notes.rst
This document describes the Python plugin I've written for GCC. In theory the
plugin allows you to write Python scripts that can run inside GCC as it
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
new file mode 100644
index 0000000..3822838
--- /dev/null
+++ b/docs/release-notes.rst
@@ -0,0 +1,23 @@
+.. 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/>.
+
+Release Notes
+=============
+
+.. toctree::
+
+ 0.7.rst
12 years, 5 months
[gcc-python-plugin] Created tag v0.7
by David Hugh Malcolm
The unsigned tag 'v0.7' was created.
Tagger: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Nov 29 16:33:34 2011 -0500
0.7
Changes since the last tag 'v0.6':
David Malcolm (254):
Bump specfile to 0.6
Expose gcc's debug dump facilities from the Python API
Expose dump_base_name to Python, and use it in libcpychecker when writing logs
Add some more files output by the selftests to .gitignore
Add note on stderr when refcount checker writes out a graphical error report
Add support for specifying Python commands via -fplugin-arg-python-command
Add "gcc-with-cpychecker" harness
Ignore Ctrl-C within gcc-with-cpychecker
Rewrite the cpychecker as a custom pass, rather than a callback associated with every pass
Fix bogus format string within gcc_Pass_get_by_name
Add some simple debug logging to the plugin's startup
Consolidate exception handling within the plugin
Try to use a better source location when an unhandled Python exception occurs
cpychecker: fix the handling of "return;" in void-returning functions
Remove exact pointer addresses from repr() when running test suite
libcpychecker: Improvements to handling of globals and of pointers
Rework split-value handling to remove code duplication
Number the unknown heap regions, to clarify things when there's more than one
Make UnknownValue.__repr__ more robust
Add selftests for writing through NULL; support reading from params
Work on exposing attributes on types
Update gcc.Type.attributes to return a dictionary, rather than a gcc.TreeList
cpychecker: respect __attribute((nonnull)) when detecting NULL pointers
Add stray file omitted from 3c705025a705de0945a4d9dc90891e90b6d4c46a
Work on libcpychecker towards handling strdup-like routines
Improve error reporting for unhandled exceptions
libcpychecker: use gcc.set_location() to get better exception locations when unexpected errors occur
libcpychecker: Handle functions that don't return (e.g. "exit")
libcpychecker: cope with string constants
cpychecker: support Py_InitModule4
Work towards handling switch statements
cpychecker: support switch statements
cpychecker: Implement detect of PyObject* subclasses
python 3 fix
libcpychecker: cope with nested structures
libcpychecker: implement the "O!" format code for the PyArg_Parse entrypoints
run-test-suite.py: add support for regenerating the "gold" outputs
update expected stdout.txt containing pointers, reflecting the regeneration within run-test-suite.py
libcpychecker: assume that PyObject* function arguments are non-NULL and sane
fix stray syntax error
Makefile: add "release" target, to help me make releases
cpychecker: Add selftest for a simple getter
run-test-suite.py: fix typo
cpychecker: rewrite State.assign in terms of State.eval_lvalue
Improve error messages within type checking
Show both the str() and the repr() when a type error occurs
Add "sizeof" attribute to gcc.Type
gcc_python_int_from_double_int: use PyIntObject instances where possible
Make gcc.Type.sizeof be an int, rather than a gcc.IntegerCst
cpychecker: support accessing arrays via pointers
cpychecker: show the history of all changes to an object's ob_refcnt when reporting a refcount error
cpychecker: revamp of reference-count checking
make the logging be less verbose
cpychecker: in log() calls, only expand the message arguments when logging is enabled
cpychecker: improve handling of conditionals; add testcase support functions
cpychecker: add hook for rendering detailed debug dump of all traces in HTML form
cpychecker: implement PyList_Append
Add HTML debug dump files to .gitignore
cpychecker: implement _PyObject_New
cpychecker: fix handling of writes through unknown pointer values
cpychecker: fix exception when leaking a reference in a function with "void" return type
cpychecker: assume unknown functions returning (PyObject*) either return a new ref, or NULL+exception
cpychecker: bulletproof against function calls where the return value is not captured
cpychecker: simplify MyState.impl_object_ctor in terms of MyState.make_new_ref
cpychecker: when assuming a PyObject* is sane, also assume it has a sane ob_type
cpychecker: fix an exception that occurred when C code discarded a (PyObject*) value
cpychecker: show exception status in debug dumps
cpychecker: introduce a naming convention to try to stop confusion between State and Transition
cpychecker: add (disabled) hook that complains about Python API entrypoints that weren't explicitly handled
cpychecker: implement PyErr_SetString
cpychecker: implement PyDict_GetItemString
cpychecker: display history of thread-local exception state when reporting on exception-handling errors
cpychecker: implement PyErr_Print/PrintEx
run the selftests in alphabetical order
cpychecker: implement PyLong_FromString, PyObject_Str, PyString_FromString
cpychecker: alphabetize the various API implementations
cpychecker: refinements to handling of NULL pointers
cpychecker: simplification of State.get_field_region
cpychecker: support more array/pointer operations
cpychecker: implement PyErr_Format
cpychecker: implement multiplication of ConcreteValue pairs
cpychecker: implement PyDict_SetItemString
cpychecker: implement PyDict_SetItem
cpychecker: detect various NULL pointer arguments to API calls that will crash with them
cpychecker: complain about deferences of uninitialized pointers
cpychecker: when handling PyArg_ParseTuple in the refcount checker, write back (unknown) values to the output regions
cpychecker: when PyArg_ParseTuple with "O" succeeds, a sane non-NULL PyObject* is written back
cpychecker: implement refcount tracking for PyArg_ParseTupleAndKeywords
cpychecker: implement refcount tracking for the PY_SSIZE_T_CLEAN variants of PyArg_ParseTuple and PyArg_ParseTupleAndKeywords
cpychecker: handle PyArg_ParseTuple with "O!" in the refcount checker
cpychecker: implement PyBool_FromLong
cpychecker: implement PyDict_New
cpychecker: implement PyErr_NoMemory
cpychecker: implement PyErr_SetFromErrno[WithFilename]
cpychecker: implement PyTuple_New
cpychecker: make PyDict_New set the ob_type of the new object to &PyDict_Type
cpychecker: implement PyObject_Repr
cpychecker: implement PyObject_IsTrue
cpychecker: implement PyModule_Add{IntConstant|Object|StringConstant}
cpychecker: implement PyString_FromFormat
cpychecker: implement PyInt_FromLong
libcpychecker: implement PyLong_FromVoidPtr
cpychecker: implement PyType_Ready
cpychecker: implement PyType_IsSubtype
cpychecker: update selftest to reflect better implementation of PyString_FromFormat
cpychecker: implement PyStructSequence_New
cpychecker: implement PyString_AsString
cpychecker: implement PySys_SetObject
cpychecker: initial implementation of PyMem_Malloc and PyMem_Free
cpychecker: initial implementation of Py_Finalize
cpychecker: implement PyImport_AppendInittab
cpychecker: implement Py_Initialize
cpychecker: implement PyRun_SimpleFileExFlags and PyRun_SimpleStringFlags
cpychecker: bulletproof impl_object_ctor against invocations that don't capture the return value
cpychecker: implement PyEval_InitThreads
cpychecker: implement PyImport_ImportModule
cpychecker: implement PyStructSequence_InitType
cpychecker: remove a couple of long-redundant disabled selftests
cpychecker: start generalizing PyArg_ParseTuple code to handle other format string APIs
cpychecker: remove stray line from previous commit
cpychecker: initial implementation of PyGILState_{Ensure|Release}
docs: add note about pygments dependency
specfile: add pygments to build-time requirements
cpychecker: add initial implementation of type conversions (aka casts)
cpychecker: fix subtraction
cpychecker: implement division
cpychecker: reorganize the directory structure of the PyList_SET_ITEM selftests
cpychecker: add selftests for the PyTuple_SET_ITEM macro
cpychecker: implement PyTuple_Size
cpychecker: implement PyObject_HasAttrString
cpychecker: implement PyDict_GetItem
cpychecker: implement bitwise and, or, xor
cpychecker: handle more jumps through function pointers
cpychecker: implement PyString_FromStringAndSize; add detection of NULL argument to PyString_FromString
cpychecker: bulletproof against combinatorial explosion
cpychecker: implement bit-shifting operations
cpychecker: fix set_exception method
cpychecker: implement PyErr_Occurred and PyInt_AsLong
cpychecker: remove dead code ("owned_refs" field of MyState)
cpychecker: internal reorganization, introducing Facet classes
cpychecker: evaluate arguments before invoking an "impl_" method
cpychecker: rename impl_object_ctor method
cpychecker: rename arguments to impl_ functions
cpychecker: further renaming to reflect name convention
cpychecker: improve detection of uninitialized data
cpychecker: PyList_SetItem: warn if the list is NULL
cpychecker: remove reference to RefcountValue from absinterp
cpychecker: use check_isinstance rather than "assert isinstance"
cpychecker: assume that function pointers returning PyObject* work like constructors
cpychecker: optionally log each function being analyzed
cpychecker: implement PyTuple_SetItem
cpychecker: cope with gimple that uses a gcc.ResultDecl
cpychecker: improve the descriptions of state transitions
add a gcc.Gimple.walk_tree method
add spell-checking example
add spell-checking example to docs
docs: Use the correct example input
docs: Fix the line-number range of the example input
run-test-suite.py: remove exact numbers from declarations
cpychecker: RefcountAnnotator now takes a description of the object being tracked
cpychecker: add RegionForLocal class
cpychecker: use variables names where possible when reporting refcount errors
cpychecker: begin implementing Py_BuildValue
cpychecker: add missing file
cpychecker: implement more of Py_BuildValue
cpychecker: remove C code fragment
improvements to gcc.GimpleCond
assume that gcc's plugin headers don't flatten the c-family directory
cpychecker: initial implementation of PyObject_CallMethod
cpychecker: support code that doesn't include Python's headers
cpychecker: handle function pointer variables
cpychecker: fixup debug code to support non-python sources
add "static" boolean property to gcc.VarDecl
cpychecker: handle functions that write back values through pointer arguments
cpychecker: implement gcc.TruthAndExpr and gcc.TruthOrExpr
cpychecker: work on unary and binary expressions
cpychecker: implement gcc.MaxExpr and gcc.MinExpr
cpychecker: ignore gcc.GimplePredict
cpychecker: fix (disabled) invocation of cfg_to_dot
cpychecker: fix copy-and-paste errors in error handling
cpychecker: split out heart of ConcreteValue.eval_binop() into a new eval_binop() function
cpychecker: fix up some impl_ functions with incorrect names
cpychecker: introduce WithinRange subclass of AbstractValue
cpychecker: add logging to eval_binop()
cpychecker: implement PyErr_SetObject
cpychecker: check for uninitialized arguments for all function calls, not just those going through facets
cpychecker: implement PyArg_UnpackTuple
cpychecker: implement PySequence_GetItem
cpychecker: implement gcc.ConvertExpr for WithinRange instances
cpychecker: fix some operations on WithinRange instances
expose fields of gcc.BitFieldRef (operand, num_bits, position)
cpychecker: handle reads from bitfields
cpychecker: implement gcc.ConvertExpr for ConcreteValue instances
docs: Start adding a "Success Stories" page
docs: add another gdb success story
cpychecker: reworking of l-values and r-values
cpychecker: implement WithinRange.extract_from_parent
cpychecker: add a way to show CPU usage for each function being analyzed
cpychecker: allow WithinRange to take one or more values as input, in any order
cpychecker: implement __cpychecker_dump_all() debug function
cpychecker: fix false warning about uninitialized data for arrays on the stack
cpychecker: handle gcc.Constructor()
cpychecker: handle void*
cpychecker: add __slots__ to all important classes
cpychecker: fix PyGILState_Ensure
cpychecker: fix typechecking of Py_BuildValue with code "s"
cpychecker: make gcc-with-cpychecker run the refcount-checking code
cpychecker: allow the checker to run on an SSA representation
add support for creating custom attributes from Python
docs: fix description of syntax of __attribute__(())
track which event we're within when a callback fires
add gcc.define_macro()
cpychecker: add a custom "cpychecker_returns_borrowed_ref" attribute
cpychecker: revamp of the documentation
cpychecker: fix wording in docs
cpychecker: further fixes to wording in docs
docs: start addding bugs found in the plugin itself to the success stories
docs: add another bug found in gdb
cpychecker: add cpychecker_steals_reference_to_arg(n) attribute
use gcc-with-cpychecker's attributes on ourselves
cpychecker: fix impl_PyErr_SetFromErrnoWithFilename
cpychecker: Py_BuildValue("s") expects a (char*)
cpychecker: fix handling of loops
python 3 fixes: use six.integer_types rather than exposing 'int' and 'long'
python 3 fix: explicitly use floor division when calculating offset within an array
python 3 fix: use items() rather than iteritems()
cpychecker: python 3 fixes: don't attempt to implement APIs not in Python 3
python 3 fixes: fix up some paths and repr() strings in actual vs expected output
python 3 fixes: exclude some selftests when building against Python 3
python 3 fix: remove an unnecessary usage of the PyString API
remove "is_py3k()" conditionals on methods
docs: add gdb success story for http://sourceware.org/ml/gdb/2011-11/msg00002.html
docs: markup all usage of PyObject* in the text
cpychecker: use 1-based argument indices when warning about NULL function arguments
cpychecker: implement PyObject_Call
cpychecker: provide a way to associate run-time and compile-time type information
use cpychecker's custom attribute to associate run-time and compile-time type information
cpychecker: add buffering of gcc diagnostics within Report instances
cpychecker: de-duplicate error reports
docs: add more information on dependencies and building
docs: add more detail on building the plugin
docs: revamp the cross-references
minor reworking of module initialization
Fix constness of msgid within gcc_python_permerror()
fix reference leaks when assembling lists of wrapped objects
fix various reference leaks found by cpychecker
add __attribute__((nonnull)) in a few places
docs: add recent fixes to self to the Success Stories
fix cleanup of gcc_Gimple_walk_tree
cpychecker: fix typos
remove stray assertion
disable various tests when building against a debug build of Python
disable various tests when building on 32-bit
make test suite's handling of function pointer types more robust
Tom Tromey (1):
bug in gcc_python_closure_new_generic
12 years, 5 months
[gcc-python-plugin] make test suite's handling of function pointer types more robust
by David Hugh Malcolm
commit 2b991551ed11256b14ce447dbef8222efd612d82
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Nov 29 16:32:13 2011 -0500
make test suite's handling of function pointer types more robust
Don't depend on a precise (and arbitrary) numeric ID for function types
Makes tests/cpychecker/absinterp/function-pointers more robust
run-test-suite.py | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
---
diff --git a/run-test-suite.py b/run-test-suite.py
index fa51c37..98bf748 100644
--- a/run-test-suite.py
+++ b/run-test-suite.py
@@ -98,6 +98,10 @@ class TestStream:
line = re.sub('VarDecl\(([0-9]+)\)', 'VarDecl(nnnn)', line)
line = re.sub('LabelDecl\(([0-9]+)\)', 'LabelDecl(nnnn)', line)
+ # Remove exact numbers from types
+ # (e.g. from "int (*<T513>) (int)" to "int (*<Tnnn>) (int)"):
+ line = re.sub('<T([0-9]+)>', '<Tnnn>', line)
+
# Remove exact path to Python header file and line number
# e.g.
# unknown struct PyObject * from /usr/include/python2.7/pyerrors.h:135
12 years, 5 months
[gcc-python-plugin] disable various tests when building on 32-bit
by David Hugh Malcolm
commit 24684a638fbccfe99c0cc2b973159556ed15a3d8
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Nov 29 16:20:26 2011 -0500
disable various tests when building on 32-bit
run-test-suite.py | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
---
diff --git a/run-test-suite.py b/run-test-suite.py
index 9851211..fa51c37 100644
--- a/run-test-suite.py
+++ b/run-test-suite.py
@@ -293,6 +293,17 @@ if six.MAXSIZE == 0x7fffffff:
# mismatch:
exclude_test('tests/cpychecker/PyArg_ParseTuple/incorrect_converters')
+ # The expected output for the following tests assumes a 64-bit build:
+ exclude_test('tests/cpychecker/absinterp/casts/pointer-to-long')
+ exclude_test('tests/cpychecker/refcounts/PyArg_ParseTuple/correct_O')
+ exclude_test('tests/cpychecker/refcounts/PyArg_ParseTupleAndKeywords/correct_O')
+ exclude_test('tests/cpychecker/refcounts/PyInt_AsLong/correct_cast')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_New/correct')
+ exclude_test('tests/cpychecker/refcounts/module_handling')
+ exclude_test('tests/plugin/constants')
+ exclude_test('tests/plugin/gimple-walk-tree/dump-all')
+ exclude_test('tests/plugin/gimple-walk-tree/find-one')
+
# Certain tests don't work for Python 3:
if six.PY3:
# The PyInt_ API doesn't exist anymore in Python 3:
@@ -346,6 +357,9 @@ if hasattr(sys, 'gettotalrefcount'):
exclude_test('tests/cpychecker/refcounts/use_after_dealloc')
exclude_test('tests/examples/spelling-checker')
+# This test is unreliable, due to differences in the dictionary:
+exclude_test('tests/examples/spelling-checker')
+
num_passes = 0
failed_tests = []
for testdir in sorted(testdirs):
12 years, 5 months
[gcc-python-plugin] disable various tests when building against a debug build of Python
by David Hugh Malcolm
commit 881f1656bf390c81c94ee1e9769400e15b74b6fa
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Nov 29 15:49:13 2011 -0500
disable various tests when building against a debug build of Python
run-test-suite.py | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
---
diff --git a/run-test-suite.py b/run-test-suite.py
index da6b728..9851211 100644
--- a/run-test-suite.py
+++ b/run-test-suite.py
@@ -314,6 +314,37 @@ if six.PY3:
# this test for Python 2:
exclude_test('tests/cpychecker/refcounts/module_handling')
+# Certain tests don't work for debug builds of Python:
+if hasattr(sys, 'gettotalrefcount'):
+ exclude_test('tests/cpychecker/refcounts/PyDict_SetItem/correct')
+ exclude_test('tests/cpychecker/refcounts/PyDict_SetItem/incorrect')
+ exclude_test('tests/cpychecker/refcounts/PyDict_SetItemString/correct')
+ exclude_test('tests/cpychecker/refcounts/PyDict_SetItemString/incorrect')
+ exclude_test('tests/cpychecker/refcounts/PyList_Append/correct')
+ exclude_test('tests/cpychecker/refcounts/PyList_Append/incorrect')
+ exclude_test('tests/cpychecker/refcounts/PyList_Append/incorrect-loop')
+ exclude_test('tests/cpychecker/refcounts/PyList_SET_ITEM_macro/correct')
+ exclude_test('tests/cpychecker/refcounts/PyList_SET_ITEM_macro/correct_multiple')
+ exclude_test('tests/cpychecker/refcounts/PyList_SET_ITEM_macro/incorrect_multiple')
+ exclude_test('tests/cpychecker/refcounts/PyString_AsString/correct')
+ exclude_test('tests/cpychecker/refcounts/PyString_AsString/incorrect')
+ exclude_test('tests/cpychecker/refcounts/PySys_SetObject/correct')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_SET_ITEM_macro/correct')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_SET_ITEM_macro/correct_multiple')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_SET_ITEM_macro/incorrect_multiple')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_SetItem/correct')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_SetItem/correct_multiple')
+ exclude_test('tests/cpychecker/refcounts/PyTuple_SetItem/incorrect_multiple')
+ exclude_test('tests/cpychecker/refcounts/Py_BuildValue/correct-code-N')
+ exclude_test('tests/cpychecker/refcounts/Py_BuildValue/correct-code-O')
+ exclude_test('tests/cpychecker/refcounts/correct_decref')
+ exclude_test('tests/cpychecker/refcounts/loop_n_times')
+ exclude_test('tests/cpychecker/refcounts/module_handling')
+ exclude_test('tests/cpychecker/refcounts/object_from_callback')
+ exclude_test('tests/cpychecker/refcounts/returning_dead_object')
+ exclude_test('tests/cpychecker/refcounts/unrecognized_function2')
+ exclude_test('tests/cpychecker/refcounts/use_after_dealloc')
+ exclude_test('tests/examples/spelling-checker')
num_passes = 0
failed_tests = []
12 years, 5 months
[gcc-python-plugin] remove stray assertion
by David Hugh Malcolm
commit 4d84b980cc195c7e840014ed332077e542480cf3
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Nov 29 15:48:22 2011 -0500
remove stray assertion
For some reason, this worked OK on a regular build, but showed
as an error on a debug build
gcc-python.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
---
diff --git a/gcc-python.c b/gcc-python.c
index 49f5dfd..8417d70 100644
--- a/gcc-python.c
+++ b/gcc-python.c
@@ -252,7 +252,6 @@ gcc_python_callback_for_PLUGIN_ATTRIBUTES(void *gcc_data, void *user_data)
PyGILState_STATE gstate;
//printf("%s:%i:(%p, %p)\n", __FILE__, __LINE__, gcc_data, user_data);
- assert(pass);
gstate = PyGILState_Ensure();
12 years, 5 months