Commit 7ecc3eb9 by Dodji Seketeli Committed by Dodji Seketeli

PR preprocessor/58580 - preprocessor goes OOM with warning for zero literals

In this problem report, the compiler is fed a (bogus) translation unit
in which some literals contain bytes whose value is zero.  The
preprocessor detects that and proceeds to emit diagnostics for that
king of bogus literals.  But then when the diagnostics machinery
re-reads the input file again to display the bogus literals with a
caret, it attempts to calculate the length of each of the lines it got
using fgets.  The line length calculation is done using strlen.  But
that doesn't work well when the content of the line can have several
zero bytes.  The result is that the read_line never sees the end of
the line because strlen repeatedly reports that the line ends before
the end-of-line character; so read_line thinks its buffer for reading
the line is too small; it thus increases the buffer, leading to a huge
memory consumption and disaster.

Here is what this patch does.

location_get_source_line is modified to return the length of a source
line that can now contain bytes with zero value.
diagnostic_show_locus() is then modified to consider that a line can
have characters of value zero, and so just shows a white space when
instructed to display one of these characters.

Additionally location_get_source_line is modified to avoid re-reading
each and every line from the beginning of the file until it reaches
the line number N that it is instructed to get; this was leading to
annoying quadratic behaviour when reading adjacent lines near the end
of (big) files.  So a cache is now associated to the file opened in
text mode.  When the content of the file is read, that content is
stashed in the file cache.  That file cache is searched for line
delimiters.  A number of line positions are saved in the cache and a
number of file caches are kept in memory.  That way when
location_get_source_line is asked to read line N + 1, it just has to
start reading from line N that it has already read.

libcpp/ChangeLog:

	* include/line-map.h (linemap_get_file_highest_location): Declare
	new function.
	* line-map.c (linemap_get_file_highest_location): Define it.

gcc/ChangeLog:

	* input.h (location_get_source_line): Take an additional line_size
	parameter.
	(void diagnostics_file_cache_fini): Declare new function.
	* input.c (struct fcache): New type.
	(fcache_tab_size, fcache_buffer_size, fcache_line_record_size):
	New static constants.
	(diagnostic_file_cache_init, total_lines_num)
	(lookup_file_in_cache_tab, evicted_cache_tab_entry)
	(add_file_to_cache_tab, lookup_or_add_file_to_cache_tab)
	(needs_read, needs_grow, maybe_grow, read_data, maybe_read_data)
	(get_next_line, read_next_line, goto_next_line, read_line_num):
	New static function definitions.
	(diagnostic_file_cache_fini): New function.
	(location_get_source_line): Take an additional output line_len
	parameter.  Re-write using lookup_or_add_file_to_cache_tab and
	read_line_num.
	* diagnostic.c (diagnostic_finish): Call
	diagnostic_file_cache_fini.
	(adjust_line): Take an additional input parameter for the length
	of the line, rather than calculating it with strlen.
	(diagnostic_show_locus): Adjust the use of
	location_get_source_line and adjust_line with respect to their new
	signature.  While displaying a line now, do not stop at the first
	null byte.  Rather, display the zero byte as a space and keep
	going until we reach the size of the line.
	* Makefile.in: Add vec.o to OBJS-libcommon

gcc/testsuite/ChangeLog:

	* c-c++-common/cpp/warning-zero-in-literals-1.c: New test file.

Signed-off-by: Dodji Seketeli <dodji@seketeli.org>

From-SVN: r206957
parent 70473c63
2014-01-23 Dodji Seketeli <dodji@redhat.com>
PR preprocessor/58580
* input.h (location_get_source_line): Take an additional line_size
parameter.
(void diagnostics_file_cache_fini): Declare new function.
* input.c (struct fcache): New type.
(fcache_tab_size, fcache_buffer_size, fcache_line_record_size):
New static constants.
(diagnostic_file_cache_init, total_lines_num)
(lookup_file_in_cache_tab, evicted_cache_tab_entry)
(add_file_to_cache_tab, lookup_or_add_file_to_cache_tab)
(needs_read, needs_grow, maybe_grow, read_data, maybe_read_data)
(get_next_line, read_next_line, goto_next_line, read_line_num):
New static function definitions.
(diagnostic_file_cache_fini): New function.
(location_get_source_line): Take an additional output line_len
parameter. Re-write using lookup_or_add_file_to_cache_tab and
read_line_num.
* diagnostic.c (diagnostic_finish): Call
diagnostic_file_cache_fini.
(adjust_line): Take an additional input parameter for the length
of the line, rather than calculating it with strlen.
(diagnostic_show_locus): Adjust the use of
location_get_source_line and adjust_line with respect to their new
signature. While displaying a line now, do not stop at the first
null byte. Rather, display the zero byte as a space and keep
going until we reach the size of the line.
* Makefile.in: Add vec.o to OBJS-libcommon
2014-01-23 Kirill Yukhin <kirill.yukhin@intel.com>
* config/i386/avx512fintrin.h (_mm512_loadu_si512): Rename.
......
......@@ -1471,7 +1471,8 @@ OBJS = \
# Objects in libcommon.a, potentially used by all host binaries and with
# no target dependencies.
OBJS-libcommon = diagnostic.o diagnostic-color.o pretty-print.o intl.o input.o version.o
OBJS-libcommon = diagnostic.o diagnostic-color.o pretty-print.o intl.o \
vec.o input.o version.o
# Objects in libcommon-target.a, used by drivers and by the core
# compiler and containing target-dependent code.
......
......@@ -176,6 +176,8 @@ diagnostic_finish (diagnostic_context *context)
progname);
pp_newline_and_flush (context->printer);
}
diagnostic_file_cache_fini ();
}
/* Initialize DIAGNOSTIC, where the message MSG has already been
......@@ -259,12 +261,13 @@ diagnostic_build_prefix (diagnostic_context *context,
MAX_WIDTH by some margin, then adjust the start of the line such
that the COLUMN is smaller than MAX_WIDTH minus the margin. The
margin is either 10 characters or the difference between the column
and the length of the line, whatever is smaller. */
and the length of the line, whatever is smaller. The length of
LINE is given by LINE_WIDTH. */
static const char *
adjust_line (const char *line, int max_width, int *column_p)
adjust_line (const char *line, int line_width,
int max_width, int *column_p)
{
int right_margin = 10;
int line_width = strlen (line);
int column = *column_p;
right_margin = MIN (line_width - column, right_margin);
......@@ -284,6 +287,7 @@ diagnostic_show_locus (diagnostic_context * context,
const diagnostic_info *diagnostic)
{
const char *line;
int line_width;
char *buffer;
expanded_location s;
int max_width;
......@@ -297,22 +301,25 @@ diagnostic_show_locus (diagnostic_context * context,
context->last_location = diagnostic->location;
s = expand_location_to_spelling_point (diagnostic->location);
line = location_get_source_line (s);
line = location_get_source_line (s, &line_width);
if (line == NULL)
return;
max_width = context->caret_max_width;
line = adjust_line (line, max_width, &(s.column));
line = adjust_line (line, line_width, max_width, &(s.column));
pp_newline (context->printer);
saved_prefix = pp_get_prefix (context->printer);
pp_set_prefix (context->printer, NULL);
pp_space (context->printer);
while (max_width > 0 && *line != '\0')
while (max_width > 0 && line_width > 0)
{
char c = *line == '\t' ? ' ' : *line;
if (c == '\0')
c = ' ';
pp_character (context->printer, c);
max_width--;
line_width--;
line++;
}
pp_newline (context->printer);
......
......@@ -291,6 +291,7 @@ void default_diagnostic_starter (diagnostic_context *, diagnostic_info *);
void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
void diagnostic_set_caret_max_width (diagnostic_context *context, int value);
void diagnostic_file_cache_fini (void);
/* Pure text formatting support functions. */
extern char *file_name_as_prefix (diagnostic_context *, const char *);
......
......@@ -37,7 +37,8 @@ extern char builtins_location_check[(BUILTINS_LOCATION
< RESERVED_LOCATION_COUNT) ? 1 : -1];
extern expanded_location expand_location (source_location);
extern const char *location_get_source_line (expanded_location xloc);
extern const char *location_get_source_line (expanded_location xloc,
int *line_size);
extern expanded_location expand_location_to_spelling_point (source_location);
extern source_location expansion_point_location_if_in_system_header (source_location);
......@@ -62,4 +63,6 @@ extern location_t input_location;
void dump_line_table_statistics (void);
void diagnostics_file_cache_fini (void);
#endif
2014-01-23 Dodji Seketeli <dodji@redhat.com>
PR preprocessor/58580
* c-c++-common/cpp/warning-zero-in-literals-1.c: New test file.
2014-01-23 Kirill Yukhin <kirill.yukhin@intel.com>
* gcc.target/i386/avx512f-vmovdqu32-1.c: Fix intrinsic name.
......
2014-01-23 Dodji Seketeli <dodji@redhat.com>
PR PR preprocessor/58580
* include/line-map.h (linemap_get_file_highest_location): Declare
new function.
* line-map.c (linemap_get_file_highest_location): Define it.
2014-01-02 Richard Sandiford <rdsandiford@googlemail.com>
Update copyright years
......
......@@ -756,6 +756,14 @@ struct linemap_stats
long duplicated_macro_maps_locations_size;
};
/* Return the highest location emitted for a given file for which
there is a line map in SET. FILE_NAME is the file name to
consider. If the function returns TRUE, *LOC is set to the highest
location emitted for that file. */
bool linemap_get_file_highest_location (struct line_maps * set,
const char *file_name,
source_location *loc);
/* Compute and return statistics about the memory consumption of some
parts of the line table SET. */
void linemap_get_statistics (struct line_maps *, struct linemap_stats *);
......
......@@ -1502,6 +1502,46 @@ linemap_dump_location (struct line_maps *set,
path, from, l, c, s, (void*)map, e, loc, location);
}
/* Return the highest location emitted for a given file for which
there is a line map in SET. FILE_NAME is the file name to
consider. If the function returns TRUE, *LOC is set to the highest
location emitted for that file. */
bool
linemap_get_file_highest_location (struct line_maps *set,
const char *file_name,
source_location *loc)
{
/* If the set is empty or no ordinary map has been created then
there is no file to look for ... */
if (set == NULL || set->info_ordinary.used == 0)
return false;
/* Now look for the last ordinary map created for FILE_NAME. */
int i;
for (i = set->info_ordinary.used - 1; i >= 0; --i)
{
const char *fname = set->info_ordinary.maps[i].d.ordinary.to_file;
if (fname && !filename_cmp (fname, file_name))
break;
}
if (i < 0)
return false;
/* The highest location for a given map is either the starting
location of the next map minus one, or -- if the map is the
latest one -- the highest location of the set. */
source_location result;
if (i == (int) set->info_ordinary.used - 1)
result = set->highest_location;
else
result = set->info_ordinary.maps[i + 1].start_location - 1;
*loc = result;
return true;
}
/* Compute and return statistics about the memory consumption of some
parts of the line table SET. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment