linemap_line_start: protect against location_t overflow (PR lto/88147)
authorDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 12 Feb 2019 01:09:31 +0000 (01:09 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 12 Feb 2019 01:09:31 +0000 (01:09 +0000)
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

gcc/ChangeLog
gcc/input.c
libcpp/ChangeLog
libcpp/line-map.c

index b08cd68d4aacde36d539ab628f1918c1b2ffa24d..33623ada53f5d6ea9893469482727cd6165db747 100644 (file)
@@ -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
index bf1ca660ade6648bb852835a66b2addd665b202e..c589d70c2bbe6c2edb5de120efbf3ac68323ba9b 100644 (file)
@@ -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
index ae05d6be9a6bc8f807bb8274693a229f79c2a3b0..8af9846d7fba3ec467c0710f88e29a5596d9d05c 100644 (file)
@@ -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
index ff679ed6fc33148313519a83b3d7292a4c5e09a2..0e30b4b2b391de6725341d38fe71278770b5e56b 100644 (file)
@@ -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 *>