Skip to content

fix mixing tabs and spaces #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/working-with-c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 5 additions & 2 deletions gcc-python-wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion gcc-with-cpychecker
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions generate-tree-c.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
4 changes: 4 additions & 0 deletions run-test-suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
39 changes: 34 additions & 5 deletions tests/examples/find-global-state/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
<http://www.gnu.org/licenses/>.
*/

#include <stdio.h>

static int a_global;

struct {
int i;
int f;
} bar;

extern int foo;
Expand All @@ -33,9 +35,36 @@ int test(int j)
return i + 1;
}

int test2(int j)
int test2(int p)
{
static int q = 0;
q += p;
return p * q;
}

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;
}

struct banana {
int f;
};

const struct banana a_banana;

int test7()
{
static int i = 0;
i += j;
return j * i;
return a_banana.f;
}
78 changes: 74 additions & 4 deletions tests/examples/find-global-state/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,82 @@
import gcc
from gccutils import get_src_for_loc

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:
self.global_decls = set()

for var in gcc.get_variables():
type_ = var.decl.type

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)

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':
for var in gcc.get_variables():
gcc.inform(var.decl.location,
'global state "%s %s" defined here'
% (var.decl.type, var.decl))
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)

# Flush the data that was found:
sf.flush()

gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION,
on_pass_execution)
11 changes: 6 additions & 5 deletions tests/examples/find-global-state/stderr.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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: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 i;
} bar" defined here
tests/examples/find-global-state/input.c:20:12: note: global state "int a_global" defined here
int f;
} bar" here