@@ -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)
@@ -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 ();