summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@gcc.gnu.org>2019-02-12 01:09:31 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2019-02-12 01:09:31 +0000
commita4553534dfcccf992d30307a8bdbb5405ecd01f7 (patch)
treef67e59ffd6fb5cf560579cb0ca4c399c581cda40
parentf11bb3106f4232ea2c9a2bc754a7d929879ea746 (diff)
linemap_line_start: protect against location_t overflow (PR lto/88147)
PR lto/88147 reports an assertion failure due to a bogus location_t value when adding a line to a pre-existing line map, when there's a large difference between the two line numbers. For some "large differences", this leads to a location_t value that exceeds LINE_MAP_MAX_LOCATION, in which case linemap_line_start returns 0. This isn't ideal, but at least should lead to safe degradation of location information. However, if the difference is very large, it's possible for the line number offset (relative to the start of the map) to be sufficiently large that overflow occurs when left-shifted by the column-bits, and hence the check against the LINE_MAP_MAX_LOCATION limit fails, leading to a seemingly-valid location_t value, but encoding the wrong location. This triggers the assertion failure: linemap_assert (SOURCE_LINE (map, r) == to_line); The fix (thanks to Martin) is to check for overflow when determining whether to reuse an existing map, and to not reuse it if it would occur. gcc/ChangeLog: David Malcolm <dmalcolm@redhat.com> PR lto/88147 * input.c (selftest::test_line_offset_overflow): New selftest. (selftest::input_c_tests): Call it. libcpp/ChangeLog: Martin Liska <mliska@suse.cz> PR lto/88147 * line-map.c (linemap_line_start): Don't reuse the existing line map if the line offset is sufficiently large to cause overflow when computing location_t values. From-SVN: r268789
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/input.c30
-rw-r--r--libcpp/ChangeLog7
-rw-r--r--libcpp/line-map.c4
4 files changed, 47 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b08cd68d4aa..33623ada53f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2019-02-11 David Malcolm <dmalcolm@redhat.com>
+
+ PR lto/88147
+ * input.c (selftest::test_line_offset_overflow): New selftest.
+ (selftest::input_c_tests): Call it.
+
2019-02-11 Martin Sebor <msebor@redhat.com>
PR tree-optimization/88771
diff --git a/gcc/input.c b/gcc/input.c
index bf1ca660ade..c589d70c2bb 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -3557,6 +3557,34 @@ for_each_line_table_case (void (*testcase) (const line_table_case &))
ASSERT_EQ (num_cases_tested, 2 * 12);
}
+/* Verify that when presented with a consecutive pair of locations with
+ a very large line offset, we don't attempt to consolidate them into
+ a single ordinary linemap where the line offsets within the line map
+ would lead to overflow (PR lto/88147). */
+
+static void
+test_line_offset_overflow ()
+{
+ line_table_test ltt (line_table_case (5, 0));
+
+ linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+ linemap_line_start (line_table, 1, 100);
+ location_t loc_a = linemap_line_start (line_table, 2578, 255);
+ assert_loceq ("foo.c", 2578, 0, loc_a);
+
+ const line_map_ordinary *ordmap_a = LINEMAPS_LAST_ORDINARY_MAP (line_table);
+ ASSERT_EQ (ordmap_a->m_column_and_range_bits, 13);
+ ASSERT_EQ (ordmap_a->m_range_bits, 5);
+
+ location_t loc_b = linemap_line_start (line_table, 404198, 512);
+ assert_loceq ("foo.c", 404198, 0, loc_b);
+
+ /* We should have started a new linemap, rather than attempting to store
+ a very large line offset. */
+ const line_map_ordinary *ordmap_b = LINEMAPS_LAST_ORDINARY_MAP (line_table);
+ ASSERT_NE (ordmap_a, ordmap_b);
+}
+
/* Run all of the selftests within this file. */
void
@@ -3596,6 +3624,8 @@ input_c_tests ()
for_each_line_table_case (test_lexer_char_constants);
test_reading_source_line ();
+
+ test_line_offset_overflow ();
}
} // namespace selftest
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index ae05d6be9a6..8af9846d7fb 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,10 @@
+2019-02-11 Martin Liska <mliska@suse.cz>
+
+ PR lto/88147
+ * line-map.c (linemap_line_start): Don't reuse the existing line
+ map if the line offset is sufficiently large to cause overflow
+ when computing location_t values.
+
2019-01-26 Jakub Jelinek <jakub@redhat.com>
PR preprocessor/88974
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index ff679ed6fc3..0e30b4b2b39 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -742,6 +742,10 @@ linemap_line_start (struct line_maps *set, linenum_type to_line,
if (line_delta < 0
|| last_line != ORDINARY_MAP_STARTING_LINE_NUMBER (map)
|| SOURCE_COLUMN (map, highest) >= (1U << (column_bits - range_bits))
+ || ( /* We can't reuse the map if the line offset is sufficiently
+ large to cause overflow when computing location_t values. */
+ (to_line - ORDINARY_MAP_STARTING_LINE_NUMBER (map))
+ >= (1U << (CHAR_BIT * sizeof (linenum_type) - column_bits)))
|| range_bits < map->m_range_bits)
map = linemap_check_ordinary
(const_cast <line_map *>