Getting started writing a GIMPLE analysis plugin

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Is there some simple example plugin which contains a simple GIMPLE analysis pass which doesn't change anything? I have written something very much like the warn_unused_result pass, iterating over gimple_body(current_function_decl), and the compiler crashes much later in the compilation process.

The gcc-python plugin (which is much more complex) seems to work in my GCC installation, but it's not clear to me what I'm doing differently, so that my own plugin registration doesn't work.

Here's the backtrace I eventually get when I call gimple_call_fndecl on a GIMPLE_CALL statement from my pass:

==1089== Invalid read of size 4
==1089== at 0x657F60: dom_info_available_p(cdi_direction) (dominance.c:1479)
==1089==    by 0x985F98: cleanup_tree_cfg() (tree-cfgcleanup.c:674)
==1089==    by 0x86543A: execute_function_todo(void*) (passes.c:1756)
==1089== by 0x8659E6: do_per_function(void (*)(void*), void*) (passes.c:1646)
==1089==    by 0x865B92: execute_todo(unsigned int) (passes.c:1834)
==1089==    by 0x868C41: execute_one_pass(opt_pass*) (passes.c:2180)
==1089==    by 0x868EEE: execute_pass_list(opt_pass*) (passes.c:2212)
==1089== by 0x61AA58: cgraph_analyze_function(cgraph_node*) (cgraphunit.c:663)
==1089==    by 0x61D3F5: cgraph_analyze_functions() (cgraphunit.c:937)
==1089==    by 0x61E6DD: finalize_compilation_unit() (cgraphunit.c:2080)
==1089==    by 0x4F31C6: c_write_global_declarations() (c-decl.c:10116)
==1089==    by 0x9603E2: compile_file() (toplev.c:560)

If I call gimple_call_fndecl on the same statements, I get this instead:

==1699== Invalid read of size 8
==1699==    at 0x979391: verify_gimple_in_cfg(function*) (tree-cfg.c:4544)
==1699==    by 0x865562: execute_function_todo(void*) (passes.c:1801)
==1699== by 0x8659E6: do_per_function(void (*)(void*), void*) (passes.c:1646)
==1699==    by 0x865B92: execute_todo(unsigned int) (passes.c:1834)
==1699==    by 0x868C41: execute_one_pass(opt_pass*) (passes.c:2180)
==1699==    by 0x868EEE: execute_pass_list(opt_pass*) (passes.c:2212)
==1699== by 0x61AA58: cgraph_analyze_function(cgraph_node*) (cgraphunit.c:663)
==1699==    by 0x61D3F5: cgraph_analyze_functions() (cgraphunit.c:937)
==1699==    by 0x61E6DD: finalize_compilation_unit() (cgraphunit.c:2080)
==1699==    by 0x4F31C6: c_write_global_declarations() (c-decl.c:10116)
==1699==    by 0x9603E2: compile_file() (toplev.c:560)
==1699==    by 0x961F67: toplev_main(int, char**) (toplev.c:1863)
==1699==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

This happens with GCC 4.7.0 from Fedora 17, and with GCC 4.8 trunk. I tried to compile the latter with --enable-checking=all, but I don't get any illuminating results, either. For GCC 4.7, it doesn't matter if I compile the plugin in C or C++ mode.

Any idea what might be the cause?

I've attached the plugin source code for reference.

--
Florian Weimer / Red Hat Product Security Team
#include <gmp.h>

#include <gcc-plugin.h>
#include <plugin-version.h>
#include <tree-pass.h>
#include <gimple.h>
#include <langhooks.h>

int plugin_is_GPL_compatible;

static const char *
check_banned_function(tree fdecl)
{
  static const char *const banned[] = {
    "readdir_r",
    "getwd",
    "gets",
    NULL,
  };
  const char *fname = lang_hooks.decl_printable_name(fdecl, 1);
  for (const char *const *p = banned; *p; ++p) {
    if (strcmp(fname, *p) == 0) {
      return fname;
    }
  }
  return NULL;
}
  
static void
do_banned_functions(gimple_seq seq)
{
  for (gimple_stmt_iterator i = gsi_start(seq);
       !gsi_end_p(i); gsi_next(&i)) {
    gimple g = gsi_stmt (i);

    switch (gimple_code(g))
      {
      case GIMPLE_BIND:
	do_banned_functions(gimple_bind_body (g));
	break;
      case GIMPLE_TRY:
	do_banned_functions(gimple_try_eval (g));
	do_banned_functions(gimple_try_cleanup (g));
	break;
      case GIMPLE_CATCH:
	do_banned_functions(gimple_catch_handler (g));
	break;
      case GIMPLE_EH_FILTER:
	do_banned_functions(gimple_eh_filter_failure (g));
	break;

      case GIMPLE_CALL:
        if (!gimple_call_internal_p(g)) {
	  tree fdecl = gimple_call_fndecl(g);
	  const char *bad_fn = check_banned_function(fdecl);
	  if (bad_fn) {
	    expanded_location loc = expand_location(gimple_location(g));
	    const char *current =
	      lang_hooks.decl_printable_name (current_function_decl, 2);
	    fprintf(stderr, "%s:%d:%d: function %s calls banned function %s\n",
		    loc.file, loc.line, loc.column, current, bad_fn);
	  }
	}
	break;

      default:
	break;
      }
  }
}

static unsigned
banned_functions_execute()
{
  do_banned_functions(gimple_body(current_function_decl));
}

static struct opt_pass banned_functions_pass = {
  /* .type = */ GIMPLE_PASS,
  /* .name = */ "banned-functions",
  /* .gate = */ 0,
  /* .execute = */ &banned_functions_execute,
};

static struct register_pass_info banned_functions_register = {
  /* .pass = */ &banned_functions_pass,
  /* .reference_pass_name = */ "*warn_unused_result",
  /* .ref_pass_instance_number = */ 1,
  /* .pos_op = */  PASS_POS_INSERT_AFTER
};

int
plugin_init(struct plugin_name_args *plugin_info,
	    struct plugin_gcc_version *version)
{
  if (!plugin_default_version_check (version, &gcc_version))
    return 1;
  plugin_info->version = PLUGIN_VERSION;
  plugin_info->help = "plugin help";

  register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
		    &banned_functions_register);
  return 0;
}

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux