aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2014-01-23 09:13:08 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2014-01-23 10:13:08 +0100
commit7ecc3eb9e6c61a3f1408a55e22eefa5fd3d08e79 (patch)
treea52b9945d8fde28d7ed83dbdff9f6abfe49d325b /libcpp
parent70473c6346babec51a0c488cb6e6d4e0a8194ac0 (diff)
downloadgcc-7ecc3eb9e6c61a3f1408a55e22eefa5fd3d08e79.zip
gcc-7ecc3eb9e6c61a3f1408a55e22eefa5fd3d08e79.tar.gz
gcc-7ecc3eb9e6c61a3f1408a55e22eefa5fd3d08e79.tar.bz2
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
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog7
-rw-r--r--libcpp/include/line-map.h8
-rw-r--r--libcpp/line-map.c40
3 files changed, 55 insertions, 0 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 669b0cc..9051282 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,10 @@
+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
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 996eae5..9886314 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -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 *);
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 052072a..7c7facb 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -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. */