This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Getting started writing a GIMPLE analysis plugin


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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]