From 3b7b9766119b8d19eec2d73d40968fd662b60aa6 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 24 Feb 2014 21:56:21 -0800 Subject: [PATCH 2/2] diff, sdiff: minor integer overflow fixes * src/context.c (find_hunk): Simplify, now that 2 * context + 1 cannot overflow. * src/diff.c (main): * src/sdiff.c (interact): Don't rely on undefined behavior on signed integer overflow. * src/diff.c (main): Don't let contexts exceed CONTEXT_MAX. * src/system.h (CONTEXT_MAX): New macro. --- src/context.c | 6 +++--- src/diff.c | 15 ++++++++------- src/sdiff.c | 10 ++++++---- src/system.h | 5 +++++ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/context.c b/src/context.c index 42f1eed..32053d1 100644 --- a/src/context.c +++ b/src/context.c @@ -403,10 +403,10 @@ find_hunk (struct change *start) lin thresh; /* Threshold distance is CONTEXT if the second change is ignorable, - 2 * CONTEXT + 1 otherwise. Watch out for integer overflow. */ - lin non_ignorable_threshold = - (LIN_MAX - 1) / 2 < context ? LIN_MAX : 2 * context + 1; + 2 * CONTEXT + 1 otherwise. Integer overflow can't happen, due + to CONTEXT_LIM. */ lin ignorable_threshold = context; + lin non_ignorable_threshold = 2 * context + 1; do { diff --git a/src/diff.c b/src/diff.c index 50d0365..c6ba5f6 100644 --- a/src/diff.c +++ b/src/diff.c @@ -304,11 +304,12 @@ main (int argc, char **argv) case '7': case '8': case '9': - if (! ISDIGIT (prev)) - ocontext = c - '0'; - else if (LIN_MAX / 10 < ocontext - || ((ocontext = 10 * ocontext + c - '0') < 0)) - ocontext = LIN_MAX; + ocontext = (! ISDIGIT (prev) + ? c - '0' + : (ocontext - (c - '0' <= CONTEXT_MAX % 10) + < CONTEXT_MAX / 10) + ? 10 * ocontext + (c - '0') + : CONTEXT_MAX); break; case 'a': @@ -337,8 +338,8 @@ main (int argc, char **argv) numval = strtoumax (optarg, &numend, 10); if (*numend) try_help ("invalid context length '%s'", optarg); - if (LIN_MAX < numval) - numval = LIN_MAX; + if (CONTEXT_MAX < numval) + numval = CONTEXT_MAX; } else numval = 3; diff --git a/src/sdiff.c b/src/sdiff.c index e7bc657..329fa52 100644 --- a/src/sdiff.c +++ b/src/sdiff.c @@ -1099,12 +1099,14 @@ interact (struct line_filter *diff, uintmax_t val; lin llen, rlen, lenmax; errno = 0; - llen = val = strtoumax (diff_help + 1, &numend, 10); - if (llen < 0 || llen != val || errno || *numend != ',') + val = strtoumax (diff_help + 1, &numend, 10); + if (LIN_MAX < val || errno || *numend != ',') fatal (diff_help); - rlen = val = strtoumax (numend + 1, &numend, 10); - if (rlen < 0 || rlen != val || errno || *numend) + llen = val; + val = strtoumax (numend + 1, &numend, 10); + if (LIN_MAX < val || errno || *numend) fatal (diff_help); + rlen = val; lenmax = MAX (llen, rlen); diff --git a/src/system.h b/src/system.h index f39fff0..1f81a72 100644 --- a/src/system.h +++ b/src/system.h @@ -135,6 +135,11 @@ typedef ptrdiff_t lin; verify (TYPE_SIGNED (lin)); verify (sizeof (ptrdiff_t) <= sizeof (lin)); verify (sizeof (lin) <= sizeof (long int)); + +/* Limit so that 2 * CONTEXT + 1 does not overflow. */ + +#define CONTEXT_MAX ((LIN_MAX - 1) / 2) + /* This section contains POSIX-compliant defaults for macros that are meant to be overridden by hand in config.h as needed. */ -- 1.8.5.3