On Tue, Jan 26, 2016 at 03:06:43PM +0100, Richard Biener wrote: > I'm somewhat confused about that you drop -fsanitize options from > the LTO options section writing in lto-opts.c but then add code to > parse it from there in lto-wrapper.c. The code there also looks
Sorry, as I said to Bernd, that has been just thinko in the comment change, the code was doing what I meant to. > somewhat duplicated - why not just canonicalize any -fsanitize= > option coming in to the first in merge_and_complain > and special-case it in append_compiler_options again by say > > case OPT_fsanitize_: > obstack_ptr_grow (argv_obstack, "-fsanitize=shift"); It is certainly much easier to just propagate around a bool flag whether we need to add -fsanitize=shift after the linker options. The reason I haven't done that because I didn't want to pass around yet another argument, furthermore so specific to a particular option. But looking around, it seems we are already passing around pairs, the pointer to array of struct cl_decoded_option and pointer to the count of elements in that array. By sticking the two into a structure and adding the sanitize_undefined flag for now, if in the future we need to handle some other option similarly, we can just handle it in 3-4 spots and not everywhere among so many different functions. So, what do you think about the untested patch below (the test with -c -flto -fsanitize=undefined -flto -fno-sanitize=undefined passes)? The patch is large, because it changed many places from a pair of pointer and unsigned int (or a pair of pointer to pointer and pointer to unsigned int) to pointer to this new struct. 2016-01-26 Jakub Jelinek <ja...@redhat.com> PR lto/69254 * lto-opts.c (lto_write_options): Write also -f{,no-}sanitize= options. * lto-wrapper.c (struct lto_decoded_options): New type. (append_option, merge_and_complain, append_compiler_options, append_linker_options, append_offload_options, compile_offload_image, compile_images_for_offload_targets, find_and_merge_options): Pass around options in struct lto_decoded_options instead of struct cl_decoded_option pointer and count pair. (get_options_from_collect_gcc_options): Likewise. Parse -fsanitize= options and if in the end any ub sanitizers are enabled, set decoded_opts->sanitize_undefined to true. (run_gcc): Adjust callers of these functions. If fdecoded_options.sanitize_undefined is true, append -fsanitize=shift after the linker options. --- gcc/lto-opts.c.jj 2016-01-25 22:33:11.477029666 +0100 +++ gcc/lto-opts.c 2016-01-26 15:41:02.937040062 +0100 @@ -198,10 +198,13 @@ lto_write_options (void) /* Also drop all options that are handled by the driver as well, which includes things like -o and -v or -fhelp for example. - We do not need those. The only exception is -foffload option, if we - write it in offload_lto section. Also drop all diagnostic options. */ + We do not need those. The only exceptions are: + 1) -foffload option, if we write it in offload_lto section + 2) -f{,no-}sanitize= + Also drop all diagnostic options. */ if ((cl_options[option->opt_index].flags & (CL_DRIVER|CL_WARNING)) - && (!lto_stream_offload_p || option->opt_index != OPT_foffload_)) + && (!lto_stream_offload_p || option->opt_index != OPT_foffload_) + && option->opt_index != OPT_fsanitize_) continue; for (j = 0; j < option->canonical_option_num_elements; ++j) --- gcc/lto-wrapper.c.jj 2016-01-26 15:24:10.457845617 +0100 +++ gcc/lto-wrapper.c 2016-01-26 16:38:16.784303735 +0100 @@ -118,6 +118,16 @@ maybe_unlink (const char *file) /* Template of LTRANS dumpbase suffix. */ #define DUMPBASE_SUFFIX ".ltrans18446744073709551615" +/* Structure containing decoded options, number of them and auxiliary + state from the options handling. */ + +struct lto_decoded_options +{ + struct cl_decoded_option *opt; + unsigned int count; + bool sanitize_undefined; +}; + /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS environment according to LANG_MASK. */ @@ -125,13 +135,14 @@ static void get_options_from_collect_gcc_options (const char *collect_gcc, const char *collect_gcc_options, unsigned int lang_mask, - struct cl_decoded_option **decoded_options, - unsigned int *decoded_options_count) + struct lto_decoded_options *decoded_opts) { struct obstack argv_obstack; char *argv_storage; const char **argv; int j, k, argc; + unsigned int i; + int sanitize = 0; argv_storage = xstrdup (collect_gcc_options); obstack_init (&argv_obstack); @@ -166,9 +177,30 @@ get_options_from_collect_gcc_options (co argc = obstack_object_size (&argv_obstack) / sizeof (void *) - 1; argv = XOBFINISH (&argv_obstack, const char **); + memset (decoded_opts, 0, sizeof (*decoded_opts)); decode_cmdline_options_to_array (argc, (const char **)argv, lang_mask, - decoded_options, decoded_options_count); + &decoded_opts->opt, &decoded_opts->count); + + for (i = 0; i < decoded_opts->count; ++i) + { + struct cl_decoded_option *foption = &decoded_opts->opt[i]; + switch (foption->opt_index) + { + case OPT_fsanitize_: + sanitize = parse_sanitizer_options (foption->arg, input_location, + OPT_fsanitize_, sanitize, + foption->value, false); + break; + default: + break; + } + } + /* If DECODED_OPTS->OPT requested any ubsan sanitization, collect + that info for later handling. */ + if (sanitize & (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT)) + decoded_opts->sanitize_undefined = true; + obstack_free (&argv_obstack, NULL); } @@ -176,17 +208,16 @@ get_options_from_collect_gcc_options (co DECODED_OPTIONS_COUNT. */ static void -append_option (struct cl_decoded_option **decoded_options, - unsigned int *decoded_options_count, +append_option (struct lto_decoded_options *decoded_options, struct cl_decoded_option *option) { - ++*decoded_options_count; - *decoded_options + ++decoded_options->count; + decoded_options->opt = (struct cl_decoded_option *) - xrealloc (*decoded_options, - (*decoded_options_count + xrealloc (decoded_options->opt, + (decoded_options->count * sizeof (struct cl_decoded_option))); - memcpy (&(*decoded_options)[*decoded_options_count - 1], option, + memcpy (&decoded_options->opt[decoded_options->count - 1], option, sizeof (struct cl_decoded_option)); } @@ -194,13 +225,13 @@ append_option (struct cl_decoded_option ontop of DECODED_OPTIONS. */ static void -merge_and_complain (struct cl_decoded_option **decoded_options, - unsigned int *decoded_options_count, - struct cl_decoded_option *fdecoded_options, - unsigned int fdecoded_options_count) +merge_and_complain (struct lto_decoded_options *decoded_options, + struct lto_decoded_options *fdecoded_options) { unsigned int i, j; + decoded_options->sanitize_undefined |= fdecoded_options->sanitize_undefined; + /* ??? Merge options from files. Most cases can be handled by either unioning or intersecting (for example -fwrapv is a case for unioning, @@ -216,9 +247,9 @@ merge_and_complain (struct cl_decoded_op /* The following does what the old LTO option code did, union all target and a selected set of common options. */ - for (i = 0; i < fdecoded_options_count; ++i) + for (i = 0; i < fdecoded_options->count; ++i) { - struct cl_decoded_option *foption = &fdecoded_options[i]; + struct cl_decoded_option *foption = &fdecoded_options->opt[i]; switch (foption->opt_index) { case OPT_SPECIAL_unknown: @@ -248,27 +279,27 @@ merge_and_complain (struct cl_decoded_op setting per OPT code, we pick the first we encounter. ??? This doesn't make too much sense, but when it doesn't then we should complain. */ - for (j = 0; j < *decoded_options_count; ++j) - if ((*decoded_options)[j].opt_index == foption->opt_index) + for (j = 0; j < decoded_options->count; ++j) + if (decoded_options->opt[j].opt_index == foption->opt_index) break; - if (j == *decoded_options_count) - append_option (decoded_options, decoded_options_count, foption); + if (j == decoded_options->count) + append_option (decoded_options, foption); break; case OPT_ftrapv: case OPT_fstrict_overflow: case OPT_ffp_contract_: /* For selected options we can merge conservatively. */ - for (j = 0; j < *decoded_options_count; ++j) - if ((*decoded_options)[j].opt_index == foption->opt_index) + for (j = 0; j < decoded_options->count; ++j) + if (decoded_options->opt[j].opt_index == foption->opt_index) break; - if (j == *decoded_options_count) - append_option (decoded_options, decoded_options_count, foption); + if (j == decoded_options->count) + append_option (decoded_options, foption); /* FP_CONTRACT_OFF < FP_CONTRACT_ON < FP_CONTRACT_FAST, -fno-trapv < -ftrapv, -fno-strict-overflow < -fstrict-overflow */ - else if (foption->value < (*decoded_options)[j].value) - (*decoded_options)[j] = *foption; + else if (foption->value < decoded_options->opt[j].value) + decoded_options->opt[j] = *foption; break; case OPT_fmath_errno: @@ -280,38 +311,38 @@ merge_and_complain (struct cl_decoded_op case OPT_fcilkplus: case OPT_fcheck_pointer_bounds: /* For selected options we can merge conservatively. */ - for (j = 0; j < *decoded_options_count; ++j) - if ((*decoded_options)[j].opt_index == foption->opt_index) + for (j = 0; j < decoded_options->count; ++j) + if (decoded_options->opt[j].opt_index == foption->opt_index) break; - if (j == *decoded_options_count) - append_option (decoded_options, decoded_options_count, foption); + if (j == decoded_options->count) + append_option (decoded_options, foption); /* -fmath-errno > -fno-math-errno, -fsigned-zeros > -fno-signed-zeros, -ftrapping-math -> -fno-trapping-math, -fwrapv > -fno-wrapv. */ - else if (foption->value > (*decoded_options)[j].value) - (*decoded_options)[j] = *foption; + else if (foption->value > decoded_options->opt[j].value) + decoded_options->opt[j] = *foption; break; case OPT_freg_struct_return: case OPT_fpcc_struct_return: case OPT_fshort_double: - for (j = 0; j < *decoded_options_count; ++j) - if ((*decoded_options)[j].opt_index == foption->opt_index) + for (j = 0; j < decoded_options->count; ++j) + if (decoded_options->opt[j].opt_index == foption->opt_index) break; - if (j == *decoded_options_count) + if (j == decoded_options->count) fatal_error (input_location, "Option %s not used consistently in all LTO input" " files", foption->orig_option_with_args_text); break; case OPT_foffload_abi_: - for (j = 0; j < *decoded_options_count; ++j) - if ((*decoded_options)[j].opt_index == foption->opt_index) + for (j = 0; j < decoded_options->count; ++j) + if (decoded_options->opt[j].opt_index == foption->opt_index) break; - if (j == *decoded_options_count) - append_option (decoded_options, decoded_options_count, foption); - else if (foption->value != (*decoded_options)[j].value) + if (j == decoded_options->count) + append_option (decoded_options, foption); + else if (foption->value != decoded_options->opt[j].value) fatal_error (input_location, "Option %s not used consistently in all LTO input" " files", foption->orig_option_with_args_text); @@ -321,15 +352,15 @@ merge_and_complain (struct cl_decoded_op case OPT_Ofast: case OPT_Og: case OPT_Os: - for (j = 0; j < *decoded_options_count; ++j) - if ((*decoded_options)[j].opt_index == OPT_O - || (*decoded_options)[j].opt_index == OPT_Ofast - || (*decoded_options)[j].opt_index == OPT_Og - || (*decoded_options)[j].opt_index == OPT_Os) + for (j = 0; j < decoded_options->count; ++j) + if (decoded_options->opt[j].opt_index == OPT_O + || decoded_options->opt[j].opt_index == OPT_Ofast + || decoded_options->opt[j].opt_index == OPT_Og + || decoded_options->opt[j].opt_index == OPT_Os) break; - if (j == *decoded_options_count) - append_option (decoded_options, decoded_options_count, foption); - else if ((*decoded_options)[j].opt_index == foption->opt_index + if (j == decoded_options->count) + append_option (decoded_options, foption); + else if (decoded_options->opt[j].opt_index == foption->opt_index && foption->opt_index != OPT_O) /* Exact same options get merged. */ ; @@ -359,13 +390,13 @@ merge_and_complain (struct cl_decoded_op default: gcc_unreachable (); } - switch ((*decoded_options)[j].opt_index) + switch (decoded_options->opt[j].opt_index) { case OPT_O: - if ((*decoded_options)[j].arg[0] == '\0') + if (decoded_options->opt[j].arg[0] == '\0') level = MAX (level, 1); else - level = MAX (level, atoi ((*decoded_options)[j].arg)); + level = MAX (level, atoi (decoded_options->opt[j].arg)); break; case OPT_Ofast: level = MAX (level, 3); @@ -379,17 +410,17 @@ merge_and_complain (struct cl_decoded_op default: gcc_unreachable (); } - (*decoded_options)[j].opt_index = OPT_O; + decoded_options->opt[j].opt_index = OPT_O; char *tem; tem = xasprintf ("-O%d", level); - (*decoded_options)[j].arg = &tem[2]; - (*decoded_options)[j].canonical_option[0] = tem; - (*decoded_options)[j].value = 1; + decoded_options->opt[j].arg = &tem[2]; + decoded_options->opt[j].canonical_option[0] = tem; + decoded_options->opt[j].value = 1; } break; case OPT_foffload_: - append_option (decoded_options, decoded_options_count, foption); + append_option (decoded_options, foption); break; } } @@ -459,13 +490,13 @@ parse_env_var (const char *str, char *** /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK. */ static void -append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts, - unsigned int count) +append_compiler_options (obstack *argv_obstack, + struct lto_decoded_options *opts) { /* Append compiler driver arguments as far as they were merged. */ - for (unsigned int j = 1; j < count; ++j) + for (unsigned int j = 1; j < opts->count; ++j) { - struct cl_decoded_option *option = &opts[j]; + struct cl_decoded_option *option = &opts->opt[j]; /* File options have been properly filtered by lto-opts.c. */ switch (option->opt_index) @@ -531,14 +562,13 @@ append_compiler_options (obstack *argv_o /* Append linker options OPTS to ARGV_OBSTACK. */ static void -append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts, - unsigned int count) +append_linker_options (obstack *argv_obstack, struct lto_decoded_options *opts) { /* Append linker driver arguments. Compiler options from the linker driver arguments will override / merge with those from the compiler. */ - for (unsigned int j = 1; j < count; ++j) + for (unsigned int j = 1; j < opts->count; ++j) { - struct cl_decoded_option *option = &opts[j]; + struct cl_decoded_option *option = &opts->opt[j]; /* Do not pass on frontend specific flags not suitable for lto. */ if (!(cl_options[option->opt_index].flags @@ -584,15 +614,14 @@ append_linker_options (obstack *argv_obs static void append_offload_options (obstack *argv_obstack, const char *target, - struct cl_decoded_option *options, - unsigned int options_count) + struct lto_decoded_options *options) { - for (unsigned i = 0; i < options_count; i++) + for (unsigned i = 0; i < options->count; i++) { const char *cur, *next, *opts; char **argv; unsigned argc; - struct cl_decoded_option *option = &options[i]; + struct cl_decoded_option *option = &options->opt[i]; if (option->opt_index != OPT_foffload_) continue; @@ -664,10 +693,8 @@ access_check (const char *name, int mode static char * compile_offload_image (const char *target, const char *compiler_path, unsigned in_argc, char *in_argv[], - struct cl_decoded_option *compiler_opts, - unsigned int compiler_opt_count, - struct cl_decoded_option *linker_opts, - unsigned int linker_opt_count) + struct lto_decoded_options *compiler_opts, + struct lto_decoded_options *linker_opts) { char *filename = NULL; char **argv; @@ -708,15 +735,12 @@ compile_offload_image (const char *targe obstack_ptr_grow (&argv_obstack, in_argv[i]); /* Append options from offload_lto sections. */ - append_compiler_options (&argv_obstack, compiler_opts, - compiler_opt_count); + append_compiler_options (&argv_obstack, compiler_opts); /* Append options specified by -foffload last. In case of conflicting options we expect offload compiler to choose the latest. */ - append_offload_options (&argv_obstack, target, compiler_opts, - compiler_opt_count); - append_offload_options (&argv_obstack, target, linker_opts, - linker_opt_count); + append_offload_options (&argv_obstack, target, compiler_opts); + append_offload_options (&argv_obstack, target, linker_opts); obstack_ptr_grow (&argv_obstack, NULL); argv = XOBFINISH (&argv_obstack, char **); @@ -736,10 +760,8 @@ compile_offload_image (const char *targe static void compile_images_for_offload_targets (unsigned in_argc, char *in_argv[], - struct cl_decoded_option *compiler_opts, - unsigned int compiler_opt_count, - struct cl_decoded_option *linker_opts, - unsigned int linker_opt_count) + struct lto_decoded_options *compiler_opts, + struct lto_decoded_options *linker_opts) { char **names = NULL; const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV); @@ -764,8 +786,7 @@ compile_images_for_offload_targets (unsi offload_names[next_name_entry] = compile_offload_image (names[i], compiler_path, in_argc, in_argv, - compiler_opts, compiler_opt_count, - linker_opts, linker_opt_count); + compiler_opts, linker_opts); if (!offload_names[next_name_entry]) fatal_error (input_location, "problem with building target image for %s\n", names[i]); @@ -837,23 +858,20 @@ find_offloadbeginend (void) } /* A subroutine of run_gcc. Examine the open file FD for lto sections with - name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS - and OPT_COUNT. Return true if we found a matchingn section, false - otherwise. COLLECT_GCC holds the value of the environment variable with - the same name. */ + name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS. + Return true if we found a matchingn section, false otherwise. COLLECT_GCC + holds the value of the environment variable with the same name. */ static bool find_and_merge_options (int fd, off_t file_offset, const char *prefix, - struct cl_decoded_option **opts, - unsigned int *opt_count, const char *collect_gcc) + struct lto_decoded_options *opts, + const char *collect_gcc) { off_t offset, length; char *data; char *fopts; const char *errmsg; int err; - struct cl_decoded_option *fdecoded_options = *opts; - unsigned int fdecoded_options_count = *opt_count; simple_object_read *sobj; sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO", @@ -877,21 +895,14 @@ find_and_merge_options (int fd, off_t fi fopts = data; do { - struct cl_decoded_option *f2decoded_options; - unsigned int f2decoded_options_count; + struct lto_decoded_options fdecoded_options; get_options_from_collect_gcc_options (collect_gcc, fopts, CL_LANG_ALL, - &f2decoded_options, - &f2decoded_options_count); - if (!fdecoded_options) - { - fdecoded_options = f2decoded_options; - fdecoded_options_count = f2decoded_options_count; - } + &fdecoded_options); + if (opts->opt == NULL) + *opts = fdecoded_options; else - merge_and_complain (&fdecoded_options, - &fdecoded_options_count, - f2decoded_options, f2decoded_options_count); + merge_and_complain (opts, &fdecoded_options); fopts += strlen (fopts) + 1; } @@ -899,8 +910,6 @@ find_and_merge_options (int fd, off_t fi free (data); simple_object_release_read (sobj); - *opts = fdecoded_options; - *opt_count = fdecoded_options_count; return true; } @@ -918,12 +927,9 @@ run_gcc (unsigned argc, char *argv[]) int parallel = 0; int jobserver = 0; bool no_partition = false; - struct cl_decoded_option *fdecoded_options = NULL; - struct cl_decoded_option *offload_fdecoded_options = NULL; - unsigned int fdecoded_options_count = 0; - unsigned int offload_fdecoded_options_count = 0; - struct cl_decoded_option *decoded_options; - unsigned int decoded_options_count; + struct lto_decoded_options fdecoded_options; + struct lto_decoded_options offload_fdecoded_options; + struct lto_decoded_options decoded_options; struct obstack argv_obstack; int new_head_argc; bool have_lto = false; @@ -931,6 +937,8 @@ run_gcc (unsigned argc, char *argv[]) unsigned lto_argc = 0, offload_argc = 0; char **lto_argv, **offload_argv; + memset (&fdecoded_options, 0, sizeof fdecoded_options); + memset (&offload_fdecoded_options, 0, sizeof offload_fdecoded_options); /* Get the driver and options. */ collect_gcc = getenv ("COLLECT_GCC"); if (!collect_gcc) @@ -942,8 +950,7 @@ run_gcc (unsigned argc, char *argv[]) "environment variable COLLECT_GCC_OPTIONS must be set"); get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options, CL_LANG_ALL, - &decoded_options, - &decoded_options_count); + &decoded_options); /* Allocate arrays for input object files with LTO or offload IL, and for possible preceding arguments. */ @@ -978,16 +985,14 @@ run_gcc (unsigned argc, char *argv[]) } if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX, - &fdecoded_options, &fdecoded_options_count, - collect_gcc)) + &fdecoded_options, collect_gcc)) { have_lto = true; lto_argv[lto_argc++] = argv[i]; } if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX, - &offload_fdecoded_options, - &offload_fdecoded_options_count, collect_gcc)) + &offload_fdecoded_options, collect_gcc)) { have_offload = true; offload_argv[offload_argc++] = argv[i]; @@ -1002,14 +1007,22 @@ run_gcc (unsigned argc, char *argv[]) obstack_ptr_grow (&argv_obstack, "-xlto"); obstack_ptr_grow (&argv_obstack, "-c"); - append_compiler_options (&argv_obstack, fdecoded_options, - fdecoded_options_count); - append_linker_options (&argv_obstack, decoded_options, decoded_options_count); + append_compiler_options (&argv_obstack, &fdecoded_options); + append_linker_options (&argv_obstack, &decoded_options); + /* If any of the TUs have enabled any undefined behavior sanitizer + options, make sure one of them is enabled in lto1, no matter what + the linker options say. It doesn't matter much which undefined + behavior sanitizer it is, as long as it is handled only in the FEs + or before IPA, and afterwards the instrumentation is present only + in the form of builtin functions. Adding this option makes sure + the builtins are initialized in lto1. */ + if (fdecoded_options.sanitize_undefined) + obstack_ptr_grow (&argv_obstack, "-fsanitize=shift"); /* Scan linker driver arguments for things that are of relevance to us. */ - for (j = 1; j < decoded_options_count; ++j) + for (j = 1; j < decoded_options.count; ++j) { - struct cl_decoded_option *option = &decoded_options[j]; + struct cl_decoded_option *option = &decoded_options.opt[j]; switch (option->opt_index) { case OPT_o: @@ -1092,10 +1105,8 @@ run_gcc (unsigned argc, char *argv[]) if (have_offload) { compile_images_for_offload_targets (offload_argc, offload_argv, - offload_fdecoded_options, - offload_fdecoded_options_count, - decoded_options, - decoded_options_count); + &offload_fdecoded_options, + &decoded_options); if (offload_names) { find_offloadbeginend (); Jakub