From dadc7f231f524b08a2d6497d55e702ef418c0b60 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 22 Aug 2021 13:54:04 -0700 Subject: [PATCH] diff: avoid sprintf %s sprintf fails if the result contains more than INT_MAX bytes, so rework the code to avoid usage of sprintf %s where the string might be longer than that. * bootstrap.conf (gnulib_modules): Remove xvasprintf. * src/diff.c (specify_style): * src/util.c (begin_output): Rewrite to avoid sprintf %s. * src/util.c: Do not include xvasprintf.h. (concat): Remove, as it uses sprintf %s. All uses rewritten. --- bootstrap.conf | 1 - src/diff.c | 72 ++++++++++++++++++++++++++++++++++++++------------ src/diff.h | 3 --- src/util.c | 20 ++++++-------- 4 files changed, 63 insertions(+), 33 deletions(-) diff --git a/bootstrap.conf b/bootstrap.conf index b3c39e6..6560e9a 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -93,7 +93,6 @@ xmalloca xreadlink xstdopen xstrtoimax -xvasprintf ' # Additional xgettext options to use. Use "\\\newline" to break lines. diff --git a/src/diff.c b/src/diff.c index 7eafbdd..36cc76a 100644 --- a/src/diff.c +++ b/src/diff.c @@ -378,21 +378,55 @@ main (int argc, char **argv) case 'D': specify_style (OUTPUT_IFDEF); { - static char const C_ifdef_group_formats[] = - "%%=%c#ifndef %s\n%%<#endif /* ! %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n"; - char *b = xmalloc (sizeof C_ifdef_group_formats - + 7 * strlen (optarg) - 14 /* 7*"%s" */ - - 8 /* 5*"%%" + 3*"%c" */); - sprintf (b, C_ifdef_group_formats, - 0, - optarg, optarg, 0, - optarg, optarg, 0, - optarg, optarg, optarg); - for (i = 0; i < sizeof group_format / sizeof group_format[0]; i++) - { - specify_value (&group_format[i], b, "-D"); - b += strlen (b) + 1; - } + static char const C_ifdef_group_formats[] + = (/* UNCHANGED */ + "%=" + "\0" + + /* OLD */ + "#ifndef @\n" + "%<" + "#endif /* ! @ */\n" + "\0" + + /* NEW */ + "#ifdef @\n" + "%>" + "#endif /* @ */\n" + "\0" + + /* CHANGED */ + "#ifndef @\n" + "%<" + "#else /* @ */\n" + "%>" + "#endif /* @ */\n"); + + char *b = xmalloc (sizeof C_ifdef_group_formats + + 7 * strlen (optarg) - 7 /* 7*"@" */); + char *base = b; + int changes = 0; + + for (i = 0; i < sizeof sizeof C_ifdef_group_formats; i++) + { + char ch = C_ifdef_group_formats[i]; + switch (ch) + { + default: + *b++ = ch; + break; + + case '@': + b = stpcpy (b, optarg); + break; + + case '\0': + *b++ = ch; + specify_value (&group_format[changes++], base, "-D"); + base = b; + break; + } + } } break; @@ -749,8 +783,12 @@ main (int argc, char **argv) if (!group_format[UNCHANGED]) group_format[UNCHANGED] = "%="; if (!group_format[CHANGED]) - group_format[CHANGED] = concat (group_format[OLD], - group_format[NEW], ""); + { + char *p = xmalloc (strlen (group_format[OLD]) + + strlen (group_format[NEW]) + 1); + group_format[CHANGED] = p; + strcpy (stpcpy (p, group_format[OLD]), group_format[NEW]); + } } no_diff_means_no_output = diff --git a/src/diff.h b/src/diff.h index 227ca6a..03f00a6 100644 --- a/src/diff.h +++ b/src/diff.h @@ -382,9 +382,6 @@ extern void print_sdiff_script (struct change *); /* util.c */ extern char const change_letter[4]; extern char const pr_program[]; -extern char *concat (char const *, char const *, char const *) - _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE - _GL_ATTRIBUTE_RETURNS_NONNULL; extern bool lines_differ (char const *, char const *) _GL_ATTRIBUTE_PURE; extern lin translate_line_number (struct file_data const *, lin); extern struct change *find_change (struct change *); diff --git a/src/util.c b/src/util.c index a8b2fb1..dd6d3bf 100644 --- a/src/util.c +++ b/src/util.c @@ -25,7 +25,6 @@ #include #include #include -#include "xvasprintf.h" #include /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is @@ -843,7 +842,14 @@ begin_output (void) of the pathnames, and it requires two spaces after "diff" if there are no options. These requirements are silly and do not match historical practice. */ - name = xasprintf ("diff%s %s %s", switch_string, names[0], names[1]); + name = xmalloc (sizeof "diff" + strlen (switch_string) + + 1 + strlen (names[0]) + 1 + strlen (names[1])); + char *p = stpcpy (name, "diff"); + p = stpcpy (p, switch_string); + *p++ = ' '; + p = stpcpy (p, names[0]); + *p++ = ' '; + strcpy (p, names[1]); if (paginate) { @@ -1536,16 +1542,6 @@ analyze_hunk (struct change *hunk, return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED); } -/* Concatenate three strings, returning a newly malloc'd string. */ - -char * -concat (char const *s1, char const *s2, char const *s3) -{ - char *new = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1); - sprintf (new, "%s%s%s", s1, s2, s3); - return new; -} - #ifdef DEBUG void debug_script (struct change *sp)