From 200a8e1a38d11c112a460e026663e8301b201d85 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 20 Feb 2019 20:07:20 +0000 Subject: Fix ICE with #line directive (PR c/89410) PR c/89410 reports various issues with #line directives with very large numbers; one of them is an ICE inside diagnostic-show-locus.c when emitting a diagnostic at line 0xffffffff. The issue is that the arithmetic in layout::calculate_line_spans to determine if two line spans are sufficiently close to consolidate was using the unsigned 32-bit linenum_type, which was overflowing when comparing the line for the expanded location with those of the location range (all on line 0xffffffff), leading to it erroneously adding two spans for the same line, leading to an assertion failure. This patch fixes the ICE by generalizing the use of long long in line-map.h's comparison function for linenum_type into a new linenum_arith_t typedef, and using it here. Doing so uncovered a second problem: the loop to print the lines within the line_span for this case is infinite: looping from 0xfffffff upwards, overflowing to 0, and then never becoming greater than 0xfffffff. The patch fixes this by using linenum_arith_t there also. gcc/ChangeLog: PR c/89410 * diagnostic-show-locus.c (layout::calculate_line_spans): Use linenum_arith_t when determining if two adjacent line spans are close enough to merge. (diagnostic_show_locus): Use linenum_arith_t when iterating over lines within each line_span. gcc/testsuite/ChangeLog: PR c/89410 * gcc.dg/pr89410-1.c: New test. * gcc.dg/pr89410-2.c: New test. libcpp/ChangeLog: PR c/89410 * include/line-map.h (linenum_arith_t): New typedef. (compare): Use it. From-SVN: r269050 --- libcpp/ChangeLog | 6 ++++++ libcpp/include/line-map.h | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'libcpp') diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index fa2fa7d..355b4cb 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,9 @@ +2019-02-20 David Malcolm + + PR c/89410 + * include/line-map.h (linenum_arith_t): New typedef. + (compare): Use it. + 2019-02-18 Martin Liska PR c++/89383 diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index a6eb87c..6c77c28 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -49,13 +49,16 @@ along with this program; see the file COPYING3. If not see /* The type of line numbers. */ typedef unsigned int linenum_type; +/* A type for doing arithmetic on line numbers. */ +typedef long long linenum_arith_t; + /* A function for for use by qsort for comparing line numbers. */ inline int compare (linenum_type lhs, linenum_type rhs) { - /* Avoid truncation issues by using long long for the comparison, + /* Avoid truncation issues by using linenum_arith_t for the comparison, and only consider the sign of the result. */ - long long diff = (long long)lhs - (long long)rhs; + linenum_arith_t diff = (linenum_arith_t)lhs - (linenum_arith_t)rhs; if (diff) return diff > 0 ? 1 : -1; return 0; -- cgit v1.1