summaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authordmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>2017-01-07 21:33:59 +0000
committerdmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>2017-01-07 21:33:59 +0000
commit732cf0365f0bb30432b8051ea7de3e38936cda97 (patch)
treed50cf2a1d95d451c655a244f774cbcdbb459d9df /libcpp
parent05d8c5f8ca3f9dfec96146a6adc2fafda536c121 (diff)
downloadgcc-732cf0365f0bb30432b8051ea7de3e38936cda97.tar.gz
Fix linemap corruption after very wide source lines (PR c++/72803)
PR c++/72803 describes an issue where a fix-it hint is to be emitted at column 512 of a 511-column source line, leading to an ICE. The root cause is a bug in linemap_line_start, when transitioning from lines >= 512 in width to narrow lines. The wide line in the reproducer has a line map with: m_column_and_range_bits = 15, m_range_bits = 5 giving 10 effective bits for representing columns, so that columns <= 1023 can be represented. When parsing the following line, linemap_line_start (..., ..., max_column_hint=0); is called. This leads to the "add_map" logic, due to this condition: || (max_column_hint <= 80 && effective_column_bits >= 10) i.e. the new line is sufficiently narrower than the old one to potentially use a new linemap (so as to conserve values within the location_t space). It then attempts to avoid allocating a new line map. Part of the logic to determine if we really need a new line map is this condition: SOURCE_COLUMN (map, highest) >= (1U << column_bits) The above condition is incorrect: we need to determine if the highest column we've handed out will fit within the proposed *effective* column bits, but "column_bits" here is the column plus the range bits, rather than just the column bits. Hence in this case linemap_line_start erroneously decides that we don't need a new line map, and updates the column bits within the existing line map, so any location_t values we've already handed out within it that are offset from the start by >= (1<<new_column_and_range_bits) effectively change meaning, leading to incorrect line&column information when decoding them, and various "interesting" ways for the linemap code to fail. The fix is to use the effective column bits in the above conditional. gcc/ChangeLog: PR c++/72803 * input.c (selftest::test_accessing_ordinary_linemaps): Verify that the transition from a max line width >= 1<<10 to narrower lines works correctly. gcc/testsuite/ChangeLog: PR c++/72803 * g++.dg/diagnostic/pr72803.C: New test case. libcpp/ChangeLog: PR c++/72803 * line-map.c (linemap_line_start): When determining if the highest column given out so far will fit into a proposed change to the current map, use the effective number of column bits, rather than the total number of column + range bits. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@244199 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog8
-rw-r--r--libcpp/line-map.c2
2 files changed, 9 insertions, 1 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index e9055bb92a4..082291d5648 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,11 @@
+2017-01-07 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/72803
+ * line-map.c (linemap_line_start): When determining if the highest
+ column given out so far will fit into a proposed change to the
+ current map, use the effective number of column bits, rather than
+ the total number of column + range bits.
+
2017-01-01 Jakub Jelinek <jakub@redhat.com>
Update copyright years.
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 77beaffd5bf..b410c00e367 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -752,7 +752,7 @@ linemap_line_start (struct line_maps *set, linenum_type to_line,
single line we can sometimes just increase its column_bits instead. */
if (line_delta < 0
|| last_line != ORDINARY_MAP_STARTING_LINE_NUMBER (map)
- || SOURCE_COLUMN (map, highest) >= (1U << column_bits)
+ || SOURCE_COLUMN (map, highest) >= (1U << (column_bits - range_bits))
|| range_bits < map->m_range_bits)
map = linemap_check_ordinary
(const_cast <line_map *>