From d26a81efedbb7efec8aaef4bb4e01f354fe6a681 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 29 Apr 2013 14:46:07 -0400 Subject: [PATCH 1/8] gcc_register_root_tab expects a NULL-terminated list of ggc_root_tab It appears that gcc_register_root_tab has always expected a NULL-terminated table of ggc_root_tab, and we were never NULL-terminating this, so it happened to only ever work by chance. Found when debugging segfaults seen on ARM in all of tests/plugin/gc (https://bugzilla.redhat.com/show_bug.cgi?id=864314); upon applying this patch, all of the tests/plugin/gc go from segfaulting to passing --- gcc-python-wrapper.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gcc-python-wrapper.c b/gcc-python-wrapper.c index fb6f87a0..951a04bf 100644 --- a/gcc-python-wrapper.c +++ b/gcc-python-wrapper.c @@ -316,13 +316,16 @@ my_walker(void *arg ATTRIBUTE_UNUSED) } } -static struct ggc_root_tab myroot = { (char*)"", 1, 1, my_walker, NULL }; +static struct ggc_root_tab myroottab[] = { + { (char*)"", 1, 1, my_walker, NULL }, + { NULL, } +}; void PyGcc_wrapper_init(void) { /* Register our GC root-walking callback: */ - ggc_register_root_tab(&myroot); + ggc_register_root_tab(myroottab); PyType_Ready(&PyGccWrapperMeta_TypeObj); } From 2f208bbd41d8ec6f1988f8b66fbdfc48175543b8 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 29 Apr 2013 15:14:52 -0400 Subject: [PATCH 2/8] use -fsigned-char when running selftests --- run-test-suite.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/run-test-suite.py b/run-test-suite.py index 8f2c544a..aedb203c 100644 --- a/run-test-suite.py +++ b/run-test-suite.py @@ -310,6 +310,10 @@ def run_test(testdir): args += ['-fplugin=%s' % os.path.abspath('%s.so' % PLUGIN_NAME), '-fplugin-arg-%s-script=%s' % (PLUGIN_NAME, script_py)] + # Force the signedness of char so that the tests have consistent + # behavior across all archs: + args += ['-fsigned-char'] + # Special-case: add the python include dir (for this runtime) if the C code # uses Python.h: def uses_python_headers(): From 42a1bbd136179b42a9e57ea5746f2f80447b8455 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 1 May 2013 13:47:54 -0400 Subject: [PATCH 3/8] tests/examples/find-global-state: don't report const arrays --- tests/examples/find-global-state/input.c | 8 ++++++++ tests/examples/find-global-state/script.py | 12 +++++++++++- tests/examples/find-global-state/stderr.txt | 6 +++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/examples/find-global-state/input.c b/tests/examples/find-global-state/input.c index 98799538..774f9cda 100644 --- a/tests/examples/find-global-state/input.c +++ b/tests/examples/find-global-state/input.c @@ -17,6 +17,8 @@ . */ +#include + static int a_global; struct { @@ -39,3 +41,9 @@ int test2(int j) i += j; return j * i; } + +int test3(int k) +{ + /* We should *not* report about __FUNCTION__ here: */ + printf("%s:%i:%s\n", __FILE__, __LINE__, __FUNCTION__); +} diff --git a/tests/examples/find-global-state/script.py b/tests/examples/find-global-state/script.py index 24b474a6..af9c42dc 100644 --- a/tests/examples/find-global-state/script.py +++ b/tests/examples/find-global-state/script.py @@ -21,9 +21,19 @@ def on_pass_execution(p, fn): if p.name == '*free_lang_data': for var in gcc.get_variables(): + type_ = var.decl.type + + # Don't bother warning about an array of const e.g. + # const char [] + if isinstance(type_, gcc.ArrayType): + item_type = type_.dereference + if hasattr(item_type, 'const'): + if item_type.const: + continue + gcc.inform(var.decl.location, 'global state "%s %s" defined here' - % (var.decl.type, var.decl)) + % (type_, var.decl)) gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, on_pass_execution) diff --git a/tests/examples/find-global-state/stderr.txt b/tests/examples/find-global-state/stderr.txt index c8cea812..bbbe8be0 100644 --- a/tests/examples/find-global-state/stderr.txt +++ b/tests/examples/find-global-state/stderr.txt @@ -1,6 +1,6 @@ -tests/examples/find-global-state/input.c:38:14: note: global state "int i" defined here -tests/examples/find-global-state/input.c:24:3: note: global state "struct +tests/examples/find-global-state/input.c:40:14: note: global state "int i" defined here +tests/examples/find-global-state/input.c:26:3: note: global state "struct { int i; } bar" defined here -tests/examples/find-global-state/input.c:20:12: note: global state "int a_global" defined here +tests/examples/find-global-state/input.c:22:12: note: global state "int a_global" defined here From 32607d44aaf703586c752e44bd1c0dbefb7e331d Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 1 May 2013 13:53:44 -0400 Subject: [PATCH 4/8] tests/examples/find-global-state: clarify the example by renaming variables --- tests/examples/find-global-state/input.c | 10 +++++----- tests/examples/find-global-state/stderr.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/examples/find-global-state/input.c b/tests/examples/find-global-state/input.c index 774f9cda..8b09a3eb 100644 --- a/tests/examples/find-global-state/input.c +++ b/tests/examples/find-global-state/input.c @@ -22,7 +22,7 @@ static int a_global; struct { - int i; + int f; } bar; extern int foo; @@ -35,11 +35,11 @@ int test(int j) return i + 1; } -int test2(int j) +int test2(int p) { - static int i = 0; - i += j; - return j * i; + static int q = 0; + q += p; + return p * q; } int test3(int k) diff --git a/tests/examples/find-global-state/stderr.txt b/tests/examples/find-global-state/stderr.txt index bbbe8be0..e3189fa5 100644 --- a/tests/examples/find-global-state/stderr.txt +++ b/tests/examples/find-global-state/stderr.txt @@ -1,6 +1,6 @@ -tests/examples/find-global-state/input.c:40:14: note: global state "int i" defined here +tests/examples/find-global-state/input.c:40:14: note: global state "int q" defined here tests/examples/find-global-state/input.c:26:3: note: global state "struct { - int i; + int f; } bar" defined here tests/examples/find-global-state/input.c:22:12: note: global state "int a_global" defined here From c4a6546b8c3b1591a3f9b63873530536be9c49d3 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 1 May 2013 14:51:08 -0400 Subject: [PATCH 5/8] tests/examples/find-global-state: report on uses of global state, rather than just decls --- docs/working-with-c.rst | 2 +- tests/examples/find-global-state/input.c | 10 ++++ tests/examples/find-global-state/script.py | 53 +++++++++++++++++++-- tests/examples/find-global-state/stderr.txt | 9 ++-- 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/docs/working-with-c.rst b/docs/working-with-c.rst index 73d66c20..c4665c71 100644 --- a/docs/working-with-c.rst +++ b/docs/working-with-c.rst @@ -76,7 +76,7 @@ these warnings are emitted on stderr: Finding global variables ------------------------ -This example adds a pass that warns about global variables: +This example adds a pass that warns about uses of global variables: .. code-block:: bash diff --git a/tests/examples/find-global-state/input.c b/tests/examples/find-global-state/input.c index 8b09a3eb..e26cfe67 100644 --- a/tests/examples/find-global-state/input.c +++ b/tests/examples/find-global-state/input.c @@ -47,3 +47,13 @@ int test3(int k) /* We should *not* report about __FUNCTION__ here: */ printf("%s:%i:%s\n", __FILE__, __LINE__, __FUNCTION__); } + +int test4() +{ + return foo; +} + +int test6() +{ + return bar.f; +} diff --git a/tests/examples/find-global-state/script.py b/tests/examples/find-global-state/script.py index af9c42dc..0ee52e9a 100644 --- a/tests/examples/find-global-state/script.py +++ b/tests/examples/find-global-state/script.py @@ -18,8 +18,13 @@ import gcc from gccutils import get_src_for_loc -def on_pass_execution(p, fn): - if p.name == '*free_lang_data': +DEBUG=0 + +class StateFinder: + def __init__(self): + # Locate all declarations of variables holding "global" state: + self.global_decls = set() + for var in gcc.get_variables(): type_ = var.decl.type @@ -30,10 +35,48 @@ def on_pass_execution(p, fn): if hasattr(item_type, 'const'): if item_type.const: continue + self.global_decls.add(var.decl) + if DEBUG: + print('self.global_decls: %r' % self.global_decls) + + self.state_users = set() + + def find_state_users(self, node, loc): + if isinstance(node, gcc.VarDecl): + if node in self.global_decls: + # store the state users for later replay, so that + # we can eliminate duplicates + # e.g. two references to "q" in "q += p" + # and replay in source-location order: + self.state_users.add( (loc, node) ) + + def flush(self): + # Emit warnings, sorted by source location: + for loc, node in sorted(self.state_users, + key=lambda pair:pair[0]): + gcc.inform(loc, + 'use of global state "%s %s" here' + % (node.type, node)) + +def on_pass_execution(p, fn): + if p.name == '*free_lang_data': + sf = StateFinder() + + # Locate uses of such variables: + for node in gcc.get_callgraph_nodes(): + fun = node.decl.function + if fun: + cfg = fun.cfg + if cfg: + for bb in cfg.basic_blocks: + stmts = bb.gimple + if stmts: + for stmt in stmts: + stmt.walk_tree(sf.find_state_users, + stmt.loc) - gcc.inform(var.decl.location, - 'global state "%s %s" defined here' - % (type_, var.decl)) + # Flush the data that was found: + sf.flush() gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, on_pass_execution) diff --git a/tests/examples/find-global-state/stderr.txt b/tests/examples/find-global-state/stderr.txt index e3189fa5..8a24a156 100644 --- a/tests/examples/find-global-state/stderr.txt +++ b/tests/examples/find-global-state/stderr.txt @@ -1,6 +1,7 @@ -tests/examples/find-global-state/input.c:40:14: note: global state "int q" defined here -tests/examples/find-global-state/input.c:26:3: note: global state "struct +tests/examples/find-global-state/input.c:41:nn: note: use of global state "int q" here +tests/examples/find-global-state/input.c:42:nn: note: use of global state "int q" here +tests/examples/find-global-state/input.c:53:nn: note: use of global state "int foo" here +tests/examples/find-global-state/input.c:58:nn: note: use of global state "struct { int f; -} bar" defined here -tests/examples/find-global-state/input.c:22:12: note: global state "int a_global" defined here +} bar" here From c908e41e2334e273f1a746dc50f350fe5867286e Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 1 May 2013 15:42:11 -0400 Subject: [PATCH 6/8] don't warn about const structs --- generate-tree-c.py | 4 +++ tests/examples/find-global-state/input.c | 11 ++++++++ tests/examples/find-global-state/script.py | 31 +++++++++++++++++----- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/generate-tree-c.py b/generate-tree-c.py index 65df19c5..cd43a2e3 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -388,6 +388,10 @@ def add_complex_getter(name, doc): add_simple_getter('%s_equivalent' % qual, 'PyGccTree_New(gcc_private_make_tree(build_qualified_type(self->t.inner, TYPE_QUAL_%s)))' % qual.upper(), 'The gcc.Type for the %s version of this type' % qual) + if tree_type.SYM == 'RECORD_TYPE': + add_simple_getter('const', + 'PyBool_FromLong(TYPE_READONLY(self->t.inner))', + "Boolean: does this type have the 'const' modifier?") if tree_type.SYM == 'INTEGER_TYPE': add_simple_getter('unsigned', diff --git a/tests/examples/find-global-state/input.c b/tests/examples/find-global-state/input.c index e26cfe67..ed0781d2 100644 --- a/tests/examples/find-global-state/input.c +++ b/tests/examples/find-global-state/input.c @@ -57,3 +57,14 @@ int test6() { return bar.f; } + +struct banana { + int f; +}; + +const struct banana a_banana; + +int test7() +{ + return a_banana.f; +} diff --git a/tests/examples/find-global-state/script.py b/tests/examples/find-global-state/script.py index 0ee52e9a..83778e0a 100644 --- a/tests/examples/find-global-state/script.py +++ b/tests/examples/find-global-state/script.py @@ -20,6 +20,22 @@ DEBUG=0 +def is_const(type_): + if DEBUG: + type_.debug() + + if hasattr(type_, 'const'): + if type_.const: + return True + + # Don't bother warning about an array of const e.g. + # const char [] + if isinstance(type_, gcc.ArrayType): + item_type = type_.dereference + if is_const(item_type): + return True + + class StateFinder: def __init__(self): # Locate all declarations of variables holding "global" state: @@ -28,13 +44,14 @@ def __init__(self): for var in gcc.get_variables(): type_ = var.decl.type - # Don't bother warning about an array of const e.g. - # const char [] - if isinstance(type_, gcc.ArrayType): - item_type = type_.dereference - if hasattr(item_type, 'const'): - if item_type.const: - continue + if DEBUG: + print('var.decl: %r' % var.decl) + print(type_) + + # Don't bother warning about const data: + if is_const(type_): + continue + self.global_decls.add(var.decl) if DEBUG: print('self.global_decls: %r' % self.global_decls) From 510c9278fa31bee9a3bde30ff35d1873e2ad8695 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 1 May 2013 16:58:10 -0400 Subject: [PATCH 7/8] document gcc.Variable --- docs/basics.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/basics.rst b/docs/basics.rst index a3787fe8..6883c121 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -442,6 +442,15 @@ Global data access Get all variables in this compilation unit as a list of :py:class:`gcc.Variable` +.. py:class:: gcc.Variable + + Wrapper around GCC's `struct varpool_node`, representing a variable in + the code being compiled. + + .. py:attribute:: decl + + The declaration of this variable, as a :py:class:`gcc.Tree` + .. py:function:: gccutils.get_variables_as_dict() Get a dictionary of all variables, where the keys are the variable names From 2c6b863a22337646e3ae94c558d525624ef6034c Mon Sep 17 00:00:00 2001 From: Valentin Haenel Date: Sat, 11 May 2013 11:41:16 +0200 Subject: [PATCH 8/8] fix mixing tabs and spaces --- gcc-with-cpychecker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc-with-cpychecker b/gcc-with-cpychecker index ae397e85..1dbb8bf9 100755 --- a/gcc-with-cpychecker +++ b/gcc-with-cpychecker @@ -78,7 +78,7 @@ cmd = 'from libcpychecker import main; main(**{%s})' % dictstr # when setting CC=gcc-with-cpychecker) args = ['gcc', ('-fplugin=%s' % PLUGIN), - ('-fplugin-arg-python-command=%s' % cmd)] + ('-fplugin-arg-python-command=%s' % cmd)] args += other_args # (the args we didn't consume) # Beware of quoting: if the command is quoted within the Popen call, then