sed-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[INSTALLED 4/4] sed: improve integer overflow checking


From: Paul Eggert
Subject: [INSTALLED 4/4] sed: improve integer overflow checking
Date: Mon, 19 Dec 2022 12:49:01 -0800

Fix some some longstanding but unlikely integer overflows.
Internally, 'sed' now more often prefers signed integer arithmetic,
which can be checked automatically via 'gcc -fsanitize=undefined'.
* basicdefs.h (countT): Remove.  All uses replaced
with a more-specific signed type, e.g., idx_t.
Similarly, change uses of types like size_t to
signed types like idx_t when appropriate.
(REALLOC): Remove; no longer used.  We now use xpalloc
because that detects integer overflow in size calculations.
Also, we no longer use XCALLOC since the code never relies
on the storage being zero, and leaving it uninitialized is
more likely to catch errors when debugging implementations
are used.  We use XNMALLOC instead, or xpalloc.
* bootstrap.conf (gnulib_modules): Add stdckdint, strtoimax.
* lib/.gitignore, m4/.gitignore: Update for new Gnulib modules.
* sed/compile.c: Include stdckdint.h.
(VECTOR_ALLOC_INCREMENT): Remove; no longer used.
(in_integer): Return maximal value if integer overflow.
All callers changed to expect this.
(next_cmd_entry): Use xpalloc instead of reallocating by hand,
which might suffer integer overflow.
(normalize_text): Don’t rely on system-defined conversion
of out-of-range size_t to int.
(next_cmd_entry): Arg is now pointer, not pointer-to-pointer.
All uses changed.
* sed/debug.c (debug_print_function): Don’t attempt to
fwrite a null pointer with a zero size.
* sed/execute.c: Include <stdckdint.h>, "minmax.h".
(resize_line): LEN arg is now increment, not total length,
to avoid overflow when calculating total length.
All uses changed.  Do not assume lb->alloc * 2 cannot overflow.
(resize_line, line_copy): Use xpalloc instead of doing realloc by
hand, which might suffer integer overflow.
(str_append_modified): Do not add n to to->length until
after it's known this cannot overflow.
(read_file_line): Don’t assume ssize_t fits in long.
(get_backup_file_name): Don’t assume string length fits in int.
Do not assume PTR-1+1 works; behavior is undefined if PTR
is at buffer start.  Check for integer overflow in buffer
size calculation.
(read_pattern_space): Check for line number overflow.
(match_address_p): Check for address overflow.
(debug_print_line): Omit unnecessary test for in->active being null.
(execute_program): Check for Q overflow.
* sed/regexp.c: Include <stdckdint.h>.
(match_regex): Don’t assume TYPE_MAXIMUM (regoff_t) == INT_MAX.
* sed/sed.c: Include inttypes.h, for strtoimax.
(main): Use strtoimax, not atoi.
* sed/utils.c (init_buffer): Use xmalloc and xpalloc
instead of guessing sizes ourselves, and unnecessarily
initializing.
(resize_buffer): Remove; all callers changed to use xpalloc.
(free_buffer): Don’t call free (NULL), since we already
test whether the pointer is null.
---
 NEWS           |   6 ++
 basicdefs.h    |   5 +-
 bootstrap.conf |   2 +
 lib/.gitignore |   3 +
 m4/.gitignore  |   2 +
 sed/compile.c  |  82 +++++++++++------------
 sed/debug.c    |  21 +++---
 sed/execute.c  | 174 +++++++++++++++++++++++++------------------------
 sed/regexp.c   |  25 ++++---
 sed/sed.c      |   9 +--
 sed/sed.h      |  28 ++++----
 sed/utils.c    |  66 +++++++------------
 sed/utils.h    |  17 ++---
 13 files changed, 214 insertions(+), 226 deletions(-)

diff --git a/NEWS b/NEWS
index a2e5334..33b5657 100644
--- a/NEWS
+++ b/NEWS
@@ -2,10 +2,16 @@ GNU sed NEWS                                    -*- outline 
-*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
   'sed --follow-symlinks -i' no longer mishandles an operand that is a
   short symbolic link to a long symbolic link to a file.
   [bug introduced in sed 4.9]
 
+  Fix some some longstanding but unlikely integer overflows.
+  Internally, 'sed' now more often prefers signed integer arithmetic,
+  which can be checked automatically via 'gcc -fsanitize=undefined'.
+
 
 * Noteworthy changes in release 4.9 (2022-11-06) [stable]
 
diff --git a/basicdefs.h b/basicdefs.h
index df759fc..db109a3 100644
--- a/basicdefs.h
+++ b/basicdefs.h
@@ -26,13 +26,10 @@
 #include <gettext.h>
 #define _(String) gettext(String)
 
-/* type countT is used to keep track of line numbers, etc. */
-typedef unsigned long countT;
-
+#include "idx.h"
 #include "xalloc.h"
 
 /* some basic definitions to avoid undue promulgating of  ugliness */
-#define REALLOC(x,n,t)  ((t *)xnrealloc((void *)(x),(n),sizeof(t)))
 #define MEMDUP(x,n,t)   ((t *)xmemdup((x),(n)*sizeof(t)))
 #define OB_MALLOC(o,n,t) ((t *)(void *)obstack_alloc(o,(n)*sizeof(t)))
 
diff --git a/bootstrap.conf b/bootstrap.conf
index d491028..8db6f04 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -59,7 +59,9 @@ selinux-h
 ssize_t
 stat-macros
 stdbool
+stdckdint
 strerror
+strtoimax
 strverscmp
 unlocked-io
 update-copyright
diff --git a/lib/.gitignore b/lib/.gitignore
index a3d90da..7dcd492 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -196,6 +196,9 @@
 /string.h
 /string.in.h
 /stripslash.c
+/strtoimax.c
+/strtol.c
+/strtoll.c
 /strverscmp.c
 /sys/
 /sys_random.in.h
diff --git a/m4/.gitignore b/m4/.gitignore
index e9d24cf..6263329 100644
--- a/m4/.gitignore
+++ b/m4/.gitignore
@@ -182,6 +182,8 @@
 /strerror.m4
 /strerror_r.m4
 /string_h.m4
+/strtoimax.m4
+/strtoll.m4
 /strverscmp.m4
 /symlink.m4
 /sys_ioctl_h.m4
diff --git a/sed/compile.c b/sed/compile.c
index 79b6390..579f5bd 100644
--- a/sed/compile.c
+++ b/sed/compile.c
@@ -17,6 +17,7 @@
 /* compile.c: translate sed source into internal form */
 
 #include "sed.h"
+#include <stdckdint.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
@@ -27,7 +28,6 @@
 #include "xalloc.h"
 
 #define YMAP_LENGTH            256 /*XXX shouldn't this be (UCHAR_MAX+1)?*/
-#define VECTOR_ALLOC_INCREMENT 40
 
 /* let's not confuse text editors that have only dumb bracket-matching... */
 #define OPEN_BRACKET   '['
@@ -57,16 +57,16 @@ struct error_info {
   const char *name;
 
   /* This is the number of the current script line that we're compiling. */
-  countT line;
+  intmax_t line;
 
   /* This is the index of the "-e" expressions on the command line. */
-  countT string_expr_count;
+  int string_expr_count;
 };
 
 
 /* Label structure used to resolve GOTO's, labels, and block beginnings. */
 struct sed_label {
-  countT v_index;              /* index of vector element being referenced */
+  idx_t v_index;               /* index of vector element being referenced */
   char *name;                  /* NUL-terminated name of the label */
   struct error_info err_info;  /* track where `{}' blocks start */
   struct sed_label *next;      /* linked list (stack) */
@@ -118,13 +118,13 @@ static _Noreturn void 
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0)
 vbad_prog (char const *why, va_list ap)
 {
   if (cur_input.name)
-    fprintf (stderr, _("%s: file %s line %lu: "), program_name,
-             cur_input.name, (unsigned long) cur_input.line);
+    fprintf (stderr, _("%s: file %s line %jd: "), program_name,
+             cur_input.name, cur_input.line);
   else
-    fprintf (stderr, _("%s: -e expression #%lu, char %lu: "),
+    fprintf (stderr, _("%s: -e expression #%d, char %td: "),
              program_name,
-             (unsigned long)cur_input.string_expr_count,
-             (unsigned long)(prog.cur-prog.base));
+             cur_input.string_expr_count,
+             prog.cur - prog.base);
 
   vfprintf (stderr, why, ap);
   fputc ('\n', stderr);
@@ -215,15 +215,17 @@ read_end_of_cmd (void)
     bad_prog ("extra characters after command");
 }
 
-/* Read an integer value from the program.  */
-static countT
+/* Read an unsigned integer value from the program.  Return the value,
+   or INTMAX_MAX on overflow.  */
+static intmax_t
 in_integer (int ch)
 {
-  countT num = 0;
+  intmax_t num = 0;
 
   while (ISDIGIT (ch))
     {
-      num = num * 10 + ch - '0';
+      if (ckd_mul (&num, num, 10) || ckd_add (&num, num, ch - '0'))
+        num = INTMAX_MAX;
       ch = inchar ();
     }
   savchar (ch);
@@ -352,17 +354,12 @@ get_openfile (struct output **file_ptrs, const char 
*mode, int fail)
 }
 
 static struct sed_cmd *
-next_cmd_entry (struct vector **vectorp)
+next_cmd_entry (struct vector *v)
 {
   struct sed_cmd *cmd;
-  struct vector *v;
 
-  v = *vectorp;
   if (v->v_length == v->v_allocated)
-    {
-      v->v_allocated += VECTOR_ALLOC_INCREMENT;
-      v->v = REALLOC (v->v, v->v_allocated, struct sed_cmd);
-    }
+    v->v = xpalloc (v->v, &v->v_allocated, 1, -1, sizeof *v->v);
 
   cmd = v->v + v->v_length;
   cmd->a1 = NULL;
@@ -371,7 +368,6 @@ next_cmd_entry (struct vector **vectorp)
   cmd->addr_bang = false;
   cmd->cmd = '\0';     /* something invalid, to catch bugs early */
 
-  *vectorp  = v;
   return cmd;
 }
 
@@ -607,7 +603,7 @@ read_label (void)
    compilation is complete, or a reference created by a `{' to be
    backpatched when the corresponding `}' is found.  */
 static struct sed_label *
-setup_label (struct sed_label *list, countT idx, char *name,
+setup_label (struct sed_label *list, idx_t idx, char *name,
              const struct error_info *err_info)
 {
   struct sed_label *ret = OB_MALLOC (&obs, 1, struct sed_label);
@@ -638,7 +634,7 @@ release_label (struct sed_label *list_head)
 }
 
 static struct replacement *
-new_replacement (char *text, size_t length, enum replacement_types type)
+new_replacement (char *text, idx_t length, enum replacement_types type)
 {
   struct replacement *r = OB_MALLOC (&obs, 1, struct replacement);
 
@@ -652,7 +648,7 @@ new_replacement (char *text, size_t length, enum 
replacement_types type)
 }
 
 static void
-setup_replacement (struct subst *sub, const char *text, size_t length)
+setup_replacement (struct subst *sub, const char *text, idx_t length)
 {
   char *base;
   char *p;
@@ -676,7 +672,7 @@ setup_replacement (struct subst *sub, const char *text, 
size_t length)
         {
           /* Preceding the backslash may be some literal text: */
           tail = tail->next =
-            new_replacement (base, (size_t)(p - base), repl_type);
+            new_replacement (base, p - base, repl_type);
 
           repl_type = save_type;
 
@@ -738,7 +734,7 @@ setup_replacement (struct subst *sub, const char *text, 
size_t length)
         {
           /* Preceding the ampersand may be some literal text: */
           tail = tail->next =
-            new_replacement (base, (size_t)(p - base), repl_type);
+            new_replacement (base, p - base, repl_type);
 
           repl_type = save_type;
           tail->subst_id = 0;
@@ -748,7 +744,7 @@ setup_replacement (struct subst *sub, const char *text, 
size_t length)
   /* There may be some trailing literal text: */
   if (base < text_end)
     tail = tail->next =
-      new_replacement (base, (size_t)(text_end - base), repl_type);
+      new_replacement (base, text_end - base, repl_type);
 
   tail->next = NULL;
   sub->replacement = root.next;
@@ -815,7 +811,7 @@ compile_address (struct addr *addr, int ch)
 {
   addr->addr_type = ADDR_IS_NULL;
   addr->addr_step = 0;
-  addr->addr_number = ~(countT)0;  /* extremely unlikely to ever match */
+  addr->addr_number = -1;  /* cannot match */
   addr->addr_regex = NULL;
 
   if (ch == '/' || ch == '\\')
@@ -863,7 +859,7 @@ compile_address (struct addr *addr, int ch)
         }
       else
         {
-          countT step = in_integer (in_nonblank ());
+          idx_t step = in_integer (in_nonblank ());
           if (step > 0)
             {
               addr->addr_step = step;
@@ -902,7 +898,7 @@ compile_program (struct vector *vector)
 
   if (!vector)
     {
-      vector = XCALLOC (1, struct vector);
+      vector = XNMALLOC (1, struct vector);
       vector->v = NULL;
       vector->v_allocated = 0;
       vector->v_length = 0;
@@ -921,7 +917,7 @@ compile_program (struct vector *vector)
       if (ch == EOF)
         break;
 
-      cur_cmd = next_cmd_entry (&vector);
+      cur_cmd = next_cmd_entry (vector);
       if (compile_address (&a, ch))
         {
           if (a.addr_type == ADDR_IS_STEP
@@ -1173,7 +1169,7 @@ compile_program (struct vector *vector)
 
         case 'y':
           {
-            size_t len, dest_len;
+            idx_t len, dest_len;
             int slash;
             struct buffer *b2;
             char *src_buf, *dest_buf;
@@ -1191,8 +1187,8 @@ compile_program (struct vector *vector)
 
             if (mb_cur_max > 1)
               {
-                size_t i, j, idx, src_char_num;
-                size_t *src_lens = XCALLOC (len, size_t);
+                idx_t i, j, idx, src_char_num;
+                idx_t *src_lens = XNMALLOC (len, idx_t);
                 char **trans_pairs;
                 size_t mbclen;
                 mbstate_t cur_stat = { 0, };
@@ -1218,7 +1214,7 @@ compile_program (struct vector *vector)
                      src(i) : pointer to i-th source character.
                      dest(i) : pointer to i-th destination character.
                      NULL : terminator */
-                trans_pairs = XCALLOC (2 * src_char_num + 1, char*);
+                trans_pairs = XNMALLOC (2 * src_char_num + 1, char *);
                 cur_cmd->x.translatemb = trans_pairs;
                 for (i = 0; i < src_char_num; i++)
                   {
@@ -1226,7 +1222,7 @@ compile_program (struct vector *vector)
                       bad_prog ("strings for `y' command are different 
lengths");
 
                     /* Set the i-th source character.  */
-                    trans_pairs[2 * i] = XCALLOC (src_lens[i] + 1, char);
+                    trans_pairs[2 * i] = XNMALLOC (src_lens[i] + 1, char);
                     memcpy (trans_pairs[2 * i], src_buf, src_lens[i]);
                     trans_pairs[2 * i][src_lens[i]] = '\0';
                     src_buf += src_lens[i]; /* Forward to next character.  */
@@ -1240,7 +1236,7 @@ compile_program (struct vector *vector)
                       mbclen = 1;
 
                     /* Set the i-th destination character.  */
-                    trans_pairs[2 * i + 1] = XCALLOC (mbclen + 1, char);
+                    trans_pairs[2 * i + 1] = XNMALLOC (mbclen + 1, char);
                     memcpy (trans_pairs[2 * i + 1], dest_buf + idx, mbclen);
                     trans_pairs[2 * i + 1][mbclen] = '\0';
                     idx += mbclen; /* Forward to next character.  */
@@ -1294,8 +1290,8 @@ compile_program (struct vector *vector)
 }
 
 /* deal with \X escapes */
-size_t
-normalize_text (char *buf, size_t len, enum text_types buftype)
+idx_t
+normalize_text (char *buf, idx_t len, enum text_types buftype)
 {
   const char *bufend = buf + len;
   char *p = buf;
@@ -1311,7 +1307,7 @@ normalize_text (char *buf, size_t len, enum text_types 
buftype)
      respectively within these three types of subexpressions.  */
   int bracket_state = 0;
 
-  int mbclen;
+  size_t mbclen;
   mbstate_t cur_stat = { 0, };
 
   while (p < bufend)
@@ -1419,16 +1415,16 @@ convert:
 
       *q++ = *p++;
     }
-    return (size_t)(q - buf);
+    return q - buf;
 }
 
 
 /* `str' is a string (from the command line) that contains a sed command.
    Compile the command, and add it to the end of `cur_program'. */
 struct vector *
-compile_string (struct vector *cur_program, char *str, size_t len)
+compile_string (struct vector *cur_program, char *str, idx_t len)
 {
-  static countT string_expr_count = 0;
+  static int string_expr_count;
   struct vector *ret;
 
   prog.file = NULL;
diff --git a/sed/debug.c b/sed/debug.c
index 24d6d95..78a470a 100644
--- a/sed/debug.c
+++ b/sed/debug.c
@@ -70,7 +70,7 @@ debug_print_char (char c)
 }
 
 static void
-debug_print_regex_pattern (const char *pat, size_t len)
+debug_print_regex_pattern (const char *pat, idx_t len)
 {
   const char *p = pat;
   while (len--)
@@ -132,16 +132,16 @@ debug_print_addr (const struct addr *a)
       debug_print_regex_flags (a->addr_regex, true);
       break;
     case ADDR_IS_NUM:
-      printf ("%lu", a->addr_number);
+      printf ("%jd", a->addr_number);
       break;
     case ADDR_IS_NUM_MOD:
-      printf ("%lu~%lu", a->addr_number, a->addr_step);
+      printf ("%jd~%jd", a->addr_number, a->addr_step);
       break;
     case ADDR_IS_STEP:
-      printf ("+%lu", a->addr_step);
+      printf ("+%jd", a->addr_step);
       break;
     case ADDR_IS_STEP_MOD:
-      printf ("~%lu", a->addr_step);
+      printf ("~%jd", a->addr_step);
       break;
     case ADDR_IS_LAST:
       putchar ('$');
@@ -223,7 +223,7 @@ debug_print_subst (const struct subst *s)
   if (s->print)
     putchar ('p');
   if (s->numb)
-    printf ("%lu", s->numb);
+    printf ("%jd", s->numb);
   if (s->outf)
     {
       putchar ('w');
@@ -234,7 +234,7 @@ debug_print_subst (const struct subst *s)
 static void
 debug_print_translation (const struct sed_cmd *sc)
 {
-  unsigned int i;
+  idx_t i;
 
   if (mb_cur_max > 1)
     {
@@ -318,7 +318,8 @@ debug_print_function (const struct vector *program, const 
struct sed_cmd *sc)
 
     case 'e':
       putchar (' ');
-      fwrite (sc->x.cmd_txt.text, 1, sc->x.cmd_txt.text_length, stdout);
+      if (sc->x.cmd_txt.text_length)
+        fwrite (sc->x.cmd_txt.text, 1, sc->x.cmd_txt.text_length, stdout);
       break;
 
     case 'F':
@@ -343,7 +344,7 @@ debug_print_function (const struct vector *program, const 
struct sed_cmd *sc)
     case 'q':
     case 'Q':
       if (sc->x.int_arg != -1)
-        printf (" %d", sc->x.int_arg);
+        printf (" %jd", sc->x.int_arg);
       break;
 
     case 'n':
@@ -449,7 +450,7 @@ debug_print_program (const struct vector *program)
 
   block_level = 1;
   puts ("SED PROGRAM:");
-  for (size_t i = 0; i < program->v_length; ++i)
+  for (idx_t i = 0; i < program->v_length; i++)
     debug_print_command (program, &program->v[i]);
   block_level = 0;
 }
diff --git a/sed/execute.c b/sed/execute.c
index 529ae47..b20c4ea 100644
--- a/sed/execute.c
+++ b/sed/execute.c
@@ -19,6 +19,7 @@
 
 #include "sed.h"
 
+#include <stdckdint.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <ctype.h>
@@ -34,6 +35,7 @@
 #include <selinux/context.h>
 #include "acl.h"
 #include "ignore-value.h"
+#include "minmax.h"
 #include "progname.h"
 #include "xalloc.h"
 
@@ -46,8 +48,10 @@
 struct line {
   char *text;          /* Pointer to line allocated by malloc. */
   char *active;                /* Pointer to non-consumed part of text. */
-  size_t length;       /* Length of text (or active, if used). */
-  size_t alloc;                /* Allocated space for active. */
+  idx_t length;                /* Length of text (or active, if used). */
+  idx_t alloc;         /* Allocated space for active. */
+                       /* 0 <= LENGTH <= ALLOC, and the malloc
+                          size is ACTIVE - TEXT + ALLOC + DFA_SLOP.  */
   bool chomped;                /* Was a trailing newline dropped? */
   mbstate_t mbstate;
 };
@@ -59,7 +63,7 @@ struct line {
 struct append_queue {
   const char *fname;
   char *text;
-  size_t textlen;
+  idx_t textlen;
   struct append_queue *next;
   bool free;
 };
@@ -73,10 +77,10 @@ struct input {
   char **file_list;
 
   /* Count of files we failed to open. */
-  countT bad_count;
+  intmax_t bad_count;
 
   /* Current input line number (over all files).  */
-  countT line_number;
+  intmax_t line_number;
 
   /* True if we'll reset line numbers and addresses before
      starting to process the next (possibly the first) file.  */
@@ -123,45 +127,41 @@ static struct line buffer;
 static struct append_queue *append_head = NULL;
 static struct append_queue *append_tail = NULL;
 
-/* increase a struct line's length, making some attempt at
+/* Prepare to increase LB's length by LEN, making some attempt at
    keeping realloc() calls under control by padding for future growth.  */
 static void
-resize_line (struct line *lb, size_t len)
+resize_line (struct line *lb, idx_t len)
 {
-  int inactive;
+  idx_t inactive;
   inactive = lb->active - lb->text;
 
   /* If the inactive part has got to more than two thirds of the buffer,
    * remove it. */
-  if (inactive > lb->alloc * 2)
+  if (lb->alloc < inactive >> 1)
     {
       memmove (lb->text, lb->active, lb->length);
-      lb->alloc += lb->active - lb->text;
+      lb->alloc += inactive;
       lb->active = lb->text;
       inactive = 0;
-
-      if (lb->alloc > len)
+      if (len <= lb->alloc - lb->length)
         return;
     }
 
-  lb->alloc *= 2;
-  if (lb->alloc < len)
-    lb->alloc = len;
-  if (lb->alloc < INITIAL_BUFFER_SIZE)
-    lb->alloc = INITIAL_BUFFER_SIZE;
-
-  lb->text = REALLOC (lb->text, inactive + lb->alloc + DFA_SLOP, char);
+  /* Grow the line.  */
+  idx_t n_incr_min = len - (lb->alloc - lb->length);
+  lb->alloc += inactive + DFA_SLOP;
+  lb->text = xpalloc (lb->text, &lb->alloc, n_incr_min, -1, 1);
+  lb->alloc -= inactive + DFA_SLOP;
   lb->active = lb->text + inactive;
 }
 
 /* Append LENGTH bytes from STRING to the line, TO.  */
 static void
-str_append (struct line *to, const char *string, size_t length)
+str_append (struct line *to, const char *string, idx_t length)
 {
-  size_t new_length = to->length + length;
-
-  if (to->alloc < new_length)
-    resize_line (to, new_length);
+  if (to->alloc - to->length < length)
+    resize_line (to, length);
+  idx_t new_length = to->length + length;
   memcpy (to->active + to->length, string, length);
   to->length = new_length;
 
@@ -187,7 +187,7 @@ str_append (struct line *to, const char *string, size_t 
length)
 }
 
 static void
-str_append_modified (struct line *to, const char *string, size_t length,
+str_append_modified (struct line *to, const char *string, idx_t length,
                      enum replacement_types type)
 {
   mbstate_t from_stat;
@@ -199,7 +199,7 @@ str_append_modified (struct line *to, const char *string, 
size_t length,
     }
 
   if (to->alloc - to->length < length * mb_cur_max)
-    resize_line (to, to->length + length * mb_cur_max);
+    resize_line (to, length * mb_cur_max);
 
   memcpy (&from_stat, &to->mbstate, sizeof (mbstate_t));
   while (length)
@@ -246,13 +246,13 @@ str_append_modified (struct line *to, const char *string, 
size_t length,
             {
               /* Copy the new wide character to the end of the string. */
               n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
-              to->length += n;
               if (n == (size_t) -1 || n == (size_t) -2)
                 {
                   fprintf (stderr,
                            _("case conversion produced an invalid character"));
                   abort ();
                 }
+              to->length += n;
               str_append (to, string, length);
               return;
             }
@@ -264,21 +264,21 @@ str_append_modified (struct line *to, const char *string, 
size_t length,
 
       /* Copy the new wide character to the end of the string. */
       n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
-      to->length += n;
       if (n == -1 || n == -2)
         {
           fprintf (stderr, _("case conversion produced an invalid character"));
           abort ();
         }
+      to->length += n;
     }
 }
 
 /* Initialize a "struct line" buffer.  Copy multibyte state from `state'
    if not null.  */
 static void
-line_init (struct line *buf, struct line *state, size_t initial_size)
+line_init (struct line *buf, struct line *state, idx_t initial_size)
 {
-  buf->text = XCALLOC (initial_size + DFA_SLOP, char);
+  buf->text = XNMALLOC (initial_size + DFA_SLOP, char);
   buf->active = buf->text;
   buf->alloc = initial_size;
   buf->length = 0;
@@ -318,15 +318,12 @@ line_copy (struct line *from, struct line *to, int state)
 
   if (to->alloc < from->length)
     {
-      to->alloc *= 2;
-      if (to->alloc < from->length)
-        to->alloc = from->length;
-      if (to->alloc < INITIAL_BUFFER_SIZE)
-        to->alloc = INITIAL_BUFFER_SIZE;
-      /* Use free()+MALLOC() instead of REALLOC() to
-         avoid unnecessary copying of old text. */
+      /* Use free+xpalloc to avoid unnecessary copying of old text.  */
+      idx_t n_incr_min = from->length - to->alloc;
       free (to->text);
-      to->text = XCALLOC (to->alloc + DFA_SLOP, char);
+      to->alloc += DFA_SLOP;
+      to->text = xpalloc (NULL, &to->alloc, n_incr_min, -1, 1);
+      to->alloc -= DFA_SLOP;
     }
 
   to->active = to->text;
@@ -385,7 +382,7 @@ read_file_line (struct input *input)
   static char *b;
   static size_t blen;
 
-  long result = ck_getdelim (&b, &blen, buffer_delimiter, input->fp);
+  ssize_t result = ck_getdelim (&b, &blen, buffer_delimiter, input->fp);
   if (result <= 0)
     return false;
 
@@ -417,7 +414,7 @@ flush_output (FILE *fp)
 }
 
 static void
-output_line (const char *text, size_t length, int nl, struct output *outf)
+output_line (const char *text, idx_t length, int nl, struct output *outf)
 {
   if (!text)
     return;
@@ -436,7 +433,7 @@ output_line (const char *text, size_t length, int nl, 
struct output *outf)
 static struct append_queue *
 next_append_slot (void)
 {
-  struct append_queue *n = XCALLOC (1, struct append_queue);
+  struct append_queue *n = XNMALLOC (1, struct append_queue);
 
   n->fname = NULL;
   n->text = NULL;
@@ -471,7 +468,7 @@ static void
 print_file (const char* infname, FILE* outf)
 {
   char buf[FREAD_BUFFER_SIZE];
-  size_t cnt;
+  idx_t cnt;
   FILE *fp;
 
   /* "If _fname_ does not exist or cannot be read, it shall
@@ -511,18 +508,21 @@ static char *
 get_backup_file_name (const char *name)
 {
   char *old_asterisk, *asterisk, *backup, *p;
-  int name_length = strlen (name), backup_length = strlen (in_place_extension);
 
   /* Compute the length of the backup file */
-  for (asterisk = in_place_extension - 1, old_asterisk = asterisk + 1;
+  idx_t asterisks = 0;
+  for (old_asterisk = in_place_extension;
        (asterisk = strchr (old_asterisk, '*'));
        old_asterisk = asterisk + 1)
-    backup_length += name_length - 1;
-
-  p = backup = xmalloc (backup_length + 1);
+    asterisks++;
+  ptrdiff_t name_length = strlen (name), backup_size;
+  if (ckd_mul (&backup_size, asterisks, name_length - 1)
+      || ckd_add (&backup_size, backup_size, strlen (in_place_extension) + 1))
+    xalloc_die ();
+  p = backup = ximalloc (backup_size);
 
   /* Each iteration gobbles up to an asterisk */
-  for (asterisk = in_place_extension - 1, old_asterisk = asterisk + 1;
+  for (old_asterisk = in_place_extension;
        (asterisk = strchr (old_asterisk, '*'));
        old_asterisk = asterisk + 1)
     {
@@ -742,6 +742,12 @@ read_pattern_space (struct input *input, struct vector 
*the_program, int append)
     }
 
   ++input->line_number;
+
+  /* Do not allow a line number equal to INTMAX_MAX, as that represents
+     overflow in address specs.  */
+  if (input->line_number == INTMAX_MAX)
+    bad_prog ("line number overflow");
+
   return true;
 }
 
@@ -866,11 +872,15 @@ match_address_p (struct sed_cmd *cmd, struct input *input)
           return (input->line_number <= cmd->a2->addr_number
                   || match_an_address_p (cmd->a1, input));
         case ADDR_IS_STEP:
-          cmd->a2->addr_number = input->line_number + cmd->a2->addr_step;
+          if (ckd_add (&cmd->a2->addr_number,
+                       input->line_number, cmd->a2->addr_step))
+            cmd->a2->addr_number = INTMAX_MAX;
           return true;
         case ADDR_IS_STEP_MOD:
-          cmd->a2->addr_number = input->line_number + cmd->a2->addr_step
-                                 - (input->line_number%cmd->a2->addr_step);
+          if (ckd_add (&cmd->a2->addr_number, input->line_number,
+                       (cmd->a2->addr_step
+                        - (input->line_number % cmd->a2->addr_step))))
+            cmd->a2->addr_number = INTMAX_MAX;
           return true;
         default:
           break;
@@ -900,11 +910,11 @@ match_address_p (struct sed_cmd *cmd, struct input *input)
 }
 
 static void
-do_list (int line_len)
+do_list (intmax_t line_len)
 {
   unsigned char *p = (unsigned char *)line.active;
-  countT len = line.length;
-  countT width = 0;
+  idx_t len = line.length;
+  idx_t width = 0;
   FILE *fp = output_file.fp;
 
   output_missing_newline (&output_file);
@@ -944,8 +954,8 @@ do_list (int line_len)
               break;
             }
       }
-      size_t olen = o - obuf;
-      if (width+olen >= line_len && line_len > 0) {
+      idx_t olen = o - obuf;
+      if (0 < line_len && line_len - olen <= width) {
           ck_fwrite ("\\", 1, 1, fp);
           ck_fwrite (&buffer_delimiter, 1, 1, fp);
           width = 0;
@@ -994,7 +1004,7 @@ static void append_replacement (struct line *buf, struct 
replacement *p,
 
           else if (regs->end[i] != regs->start[i])
             str_append_modified (buf, line.active + regs->start[i],
-                                 (size_t)(regs->end[i] - regs->start[i]),
+                                 regs->end[i] - regs->start[i],
                                  curr_type);
         }
     }
@@ -1003,9 +1013,9 @@ static void append_replacement (struct line *buf, struct 
replacement *p,
 static void
 do_subst (struct subst *sub)
 {
-  size_t start = 0;    /* where to start scan for (next) match in LINE */
-  size_t last_end = 0;  /* where did the last successful match end in LINE */
-  countT count = 0;    /* number of matches found */
+  idx_t start = 0;     /* where to start scan for (next) match in LINE */
+  idx_t last_end = 0;  /* where did the last successful match end in LINE */
+  idx_t count = 0;     /* number of matches found */
   bool again = true;
 
   static struct re_registers regs;
@@ -1063,8 +1073,8 @@ do_subst (struct subst *sub)
 
   do
     {
-      size_t offset = regs.start[0];
-      size_t matched = regs.end[0] - regs.start[0];
+      idx_t offset = regs.start[0];
+      idx_t matched = regs.end[0] - regs.start[0];
 
       /* Copy stuff to the left of this match into the output string. */
       if (start < offset)
@@ -1183,11 +1193,11 @@ do_subst (struct subst *sub)
 static void
 translate_mb (char *const *trans)
 {
-  size_t idx; /* index in the input line.  */
+  idx_t idx; /* index in the input line.  */
   mbstate_t mbstate = { 0, };
   for (idx = 0; idx < line.length;)
     {
-      unsigned int i;
+      idx_t i;
       size_t mbclen = MBRLEN (line.active + idx,
                               line.length - idx, &mbstate);
       /* An invalid sequence, or a truncated multibyte
@@ -1202,18 +1212,13 @@ translate_mb (char *const *trans)
             {
               bool move_remain_buffer = false;
               const char *tr = trans[2*i+1];
-              size_t trans_len = *tr == '\0' ? 1 : strlen (tr);
+              idx_t trans_len = *tr == '\0' ? 1 : strlen (tr);
 
               if (mbclen < trans_len)
                 {
-                  size_t new_len = (line.length + 1
-                                    + trans_len - mbclen);
-                  /* We must extend the line buffer.  */
-                  if (line.alloc < new_len)
-                    {
-                      /* And we must resize the buffer.  */
-                      resize_line (&line, new_len);
-                    }
+                  idx_t len = trans_len + 1 - mbclen;
+                  if (line.alloc - line.length < len)
+                    resize_line (&line, len);
                   move_remain_buffer = true;
                 }
               else if (mbclen > trans_len)
@@ -1221,14 +1226,14 @@ translate_mb (char *const *trans)
                   /* We must truncate the line buffer.  */
                   move_remain_buffer = true;
                 }
-              size_t prev_idx = idx;
+              idx_t prev_idx = idx;
               if (move_remain_buffer)
                 {
                   /* Move the remaining with \0.  */
                   char const *move_from = (line.active + idx + mbclen);
                   char *move_to = line.active + idx + trans_len;
-                  size_t move_len = line.length + 1 - idx - mbclen;
-                  size_t move_offset = trans_len - mbclen;
+                  idx_t move_len = line.length + 1 - idx - mbclen;
+                  idx_t move_offset = trans_len - mbclen;
                   memmove (move_to, move_from, move_len);
                   line.length += move_offset;
                   idx += move_offset;
@@ -1253,7 +1258,7 @@ debug_print_input (const struct input *input)
 {
   bool is_stdin = (input->fp && fileno (input->fp) == 0);
 
-  printf ("INPUT:   '%s' line %lu\n",
+  printf ("INPUT:   '%s' line %jd\n",
           is_stdin?"STDIN":input->in_file_name,
           input->line_number);
 }
@@ -1261,8 +1266,8 @@ debug_print_input (const struct input *input)
 static void
 debug_print_line (struct line *ln)
 {
-  const char *src = ln->active ? ln->active : ln->text;
-  size_t l = ln->length;
+  const char *src = ln->active;
+  idx_t l = ln->length;
   const char *p = src;
 
   fputs ( (ln == &hold) ? "HOLD:    ":"PATTERN: ", stdout);
@@ -1349,7 +1354,7 @@ execute_program (struct vector *vec, struct input *input)
               panic (_("`e' command not supported"));
 #else
               FILE *pipe_fp;
-              size_t cmd_length = cur_cmd->x.cmd_txt.text_length;
+              idx_t cmd_length = cur_cmd->x.cmd_txt.text_length;
               line_reset (&s_accum, NULL);
 
               if (!cmd_length)
@@ -1369,7 +1374,7 @@ execute_program (struct vector *vec, struct input *input)
 
               {
                 char buf[4096];
-                size_t n;
+                idx_t n;
                 while (!feof (pipe_fp))
                   if ((n = fread (buf, sizeof (char), 4096, pipe_fp)) > 0)
                     {
@@ -1504,7 +1509,7 @@ execute_program (struct vector *vec, struct input *input)
               FALLTHROUGH;
 
             case 'Q':
-              return cur_cmd->x.int_arg == -1 ? 0 : cur_cmd->x.int_arg;
+              return MAX (0, MIN (cur_cmd->x.int_arg, INT_MAX));
 
             case 'r':
               if (cur_cmd->x.readcmd.fname)
@@ -1527,7 +1532,7 @@ execute_program (struct vector *vec, struct input *input)
                   struct append_queue *aq;
                   size_t buflen;
                   char *text = NULL;
-                  size_t result;
+                  ssize_t result;
 
                   result = ck_getdelim (&text, &buflen, buffer_delimiter,
                                         cur_cmd->x.inf->fp);
@@ -1620,8 +1625,7 @@ execute_program (struct vector *vec, struct input *input)
 
             case '=':
               output_missing_newline (&output_file);
-              fprintf (output_file.fp, "%lu%c",
-                       (unsigned long)input->line_number,
+              fprintf (output_file.fp, "%jd%c", input->line_number,
                        buffer_delimiter);
               flush_output (output_file.fp);
              break;
diff --git a/sed/regexp.c b/sed/regexp.c
index a80b2f6..88fa9b6 100644
--- a/sed/regexp.c
+++ b/sed/regexp.c
@@ -19,6 +19,7 @@
 #include <ctype.h>
 #include <limits.h>
 #include <string.h>
+#include <stdckdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -130,7 +131,7 @@ struct regex *
 compile_regex (struct buffer *b, int flags, int needed_sub)
 {
   struct regex *new_regex;
-  size_t re_len;
+  idx_t re_len;
 
   /* // matches the last RE */
   if (size_buffer (b) == 0)
@@ -153,15 +154,13 @@ compile_regex (struct buffer *b, int flags, int 
needed_sub)
 }
 
 int
-match_regex (struct regex *regex, char *buf, size_t buflen,
-            size_t buf_start_offset, struct re_registers *regarray,
+match_regex (struct regex *regex, char *buf, idx_t buflen,
+            idx_t buf_start_offset, struct re_registers *regarray,
             int regsize)
 {
   int ret;
   static struct regex *regex_last;
 
-  /* printf ("Matching from %d/%d\n", buf_start_offset, buflen); */
-
   /* Keep track of the last regexp matched. */
   if (!regex)
     {
@@ -172,9 +171,9 @@ match_regex (struct regex *regex, char *buf, size_t buflen,
   else
     regex_last = regex;
 
-  /* gnulib's re_search uses signed-int as length */
-  if (buflen >= INT_MAX)
-    panic (_("regex input buffer length larger than INT_MAX"));
+  regoff_t buflen_regoff;
+  if (ckd_add (&buflen_regoff, buflen, 0))
+    panic (_("regex input buffer length overflow"));
 
   if (regex->pattern.no_sub && regsize)
     {
@@ -196,7 +195,7 @@ match_regex (struct regex *regex, char *buf, size_t buflen,
   /* Optimized handling for '^' and '$' patterns */
   if (regex->begline || regex->endline)
     {
-      size_t offset;
+      idx_t offset;
 
       if (regex->endline)
         {
@@ -239,12 +238,12 @@ match_regex (struct regex *regex, char *buf, size_t 
buflen,
 
       if (regsize)
         {
-          size_t i;
+          idx_t i;
 
           if (!regarray->start)
             {
-              regarray->start = XCALLOC (1, regoff_t);
-              regarray->end = XCALLOC (1, regoff_t);
+              regarray->start = XNMALLOC (1, regoff_t);
+              regarray->end = XNMALLOC (1, regoff_t);
               regarray->num_regs = 1;
             }
 
@@ -311,7 +310,7 @@ match_regex (struct regex *regex, char *buf, size_t buflen,
 
           if (ret > -1)
             {
-              size_t i;
+              idx_t i;
 
               ret += beg - buf;
 
diff --git a/sed/sed.c b/sed/sed.c
index af83065..b2811f8 100644
--- a/sed/sed.c
+++ b/sed/sed.c
@@ -18,6 +18,7 @@
 #include "sed.h"
 
 
+#include <inttypes.h>
 #include <limits.h>
 #include <stdio.h>
 #include <string.h>
@@ -80,7 +81,7 @@ bool binary_mode = false;
 enum posixicity_types posixicity;
 
 /* How long should the `l' command's output line be? */
-countT lcmd_out_line_len = 70;
+intmax_t lcmd_out_line_len = 70;
 
 /* The complete compiled SED program that we are going to run: */
 static struct vector *the_program = NULL;
@@ -253,7 +254,7 @@ main (int argc, char **argv)
    */
   if (cols)
     {
-      countT t = atoi (cols);
+      intmax_t t = strtoimax (cols, NULL, 10);
       if (t > 1)
         lcmd_out_line_len = t-1;
     }
@@ -292,7 +293,7 @@ main (int argc, char **argv)
 
           else
             {
-              in_place_extension = XCALLOC (strlen (optarg) + 2, char);
+              in_place_extension = XNMALLOC (strlen (optarg) + 2, char);
               in_place_extension[0] = '*';
               strcpy (in_place_extension + 1, optarg);
             }
@@ -300,7 +301,7 @@ main (int argc, char **argv)
           break;
 
         case 'l':
-          lcmd_out_line_len = atoi (optarg);
+          lcmd_out_line_len = strtoimax (optarg, NULL, 10);
           break;
 
         case 'p':
diff --git a/sed/sed.h b/sed/sed.h
index 8be9955..64ef7ed 100644
--- a/sed/sed.h
+++ b/sed/sed.h
@@ -27,8 +27,8 @@
 /* Struct vector is used to describe a compiled sed program. */
 struct vector {
   struct sed_cmd *v;   /* a dynamically allocated array */
-  size_t v_allocated;  /* ... number of slots allocated */
-  size_t v_length;     /* ... number of slots in use */
+  idx_t v_allocated;   /* ... number of slots allocated */
+  idx_t v_length;      /* ... number of slots in use */
 };
 
 /* This structure tracks files used by sed so that they may all be
@@ -44,13 +44,13 @@ struct output {
 
 struct text_buf {
   char *text;
-  size_t text_length;
+  idx_t text_length;
 };
 
 struct regex {
   regex_t pattern;
   int flags;
-  size_t sz;
+  idx_t sz;
   struct dfa *dfa;
   bool begline;
   bool endline;
@@ -107,15 +107,15 @@ enum addr_types {
 
 struct addr {
   enum addr_types addr_type;
-  countT addr_number;
-  countT addr_step;
+  intmax_t addr_number;
+  intmax_t addr_step;
   struct regex *addr_regex;
 };
 
 
 struct replacement {
   char *prefix;
-  size_t prefix_length;
+  idx_t prefix_length;
   int subst_id;
   enum replacement_types repl_type;
   struct replacement *next;
@@ -124,7 +124,7 @@ struct replacement {
 struct subst {
   struct regex *regx;
   struct replacement *replacement;
-  countT numb;         /* if >0, only substitute for match number "numb" */
+  intmax_t numb;       /* if >0, only substitute for match number "numb" */
   struct output *outf; /* 'w' option given */
   unsigned global : 1; /* 'g' option given */
   unsigned print : 2;  /* 'p' option given (before/after eval) */
@@ -157,10 +157,10 @@ struct sed_cmd {
     struct text_buf cmd_txt;
 
     /* This is used for the l, q and Q commands. */
-    int int_arg;
+    intmax_t int_arg;
 
     /* This is used for the {}, b, and t commands. */
-    countT jump_index;
+    idx_t jump_index;
 
     /* This is used for the r command. */
     struct readcmd readcmd;
@@ -189,8 +189,8 @@ _Noreturn void bad_prog (char const *why, ...)
   _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2);
 _Noreturn void bad_prog_notranslate (char const *why, ...)
   _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2);
-size_t normalize_text (char *text, size_t len, enum text_types buftype);
-struct vector *compile_string (struct vector *, char *str, size_t len);
+idx_t normalize_text (char *text, idx_t len, enum text_types buftype);
+struct vector *compile_string (struct vector *, char *str, idx_t len);
 struct vector *compile_file (struct vector *, const char *cmdfile);
 void check_final_program (struct vector *);
 void rewind_read_files (void);
@@ -198,7 +198,7 @@ void finish_program (struct vector *);
 
 struct regex *compile_regex (struct buffer *b, int flags, int needed_sub);
 int match_regex (struct regex *regex,
-                 char *buf, size_t buflen, size_t buf_start_offset,
+                 char *buf, idx_t buflen, idx_t buf_start_offset,
                  struct re_registers *regarray, int regsize);
 #ifdef lint
 void release_regex (struct regex *);
@@ -239,7 +239,7 @@ extern bool follow_symlinks;
 extern enum posixicity_types posixicity;
 
 /* How long should the `l' command's output line be? */
-extern countT lcmd_out_line_len;
+extern idx_t lcmd_out_line_len;
 
 /* How do we edit files in-place? (we don't if NULL) */
 extern char *in_place_extension;
diff --git a/sed/utils.c b/sed/utils.c
index 19d6554..7dce6ca 100644
--- a/sed/utils.c
+++ b/sed/utils.c
@@ -226,19 +226,19 @@ ck_mkstemp (char **p_filename, const char *tmpdir,
 
 /* Panic on failing fwrite */
 void
-ck_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream)
+ck_fwrite (const void *ptr, idx_t size, idx_t nmemb, FILE *stream)
 {
   clearerr (stream);
   if (size && fwrite (ptr, size, nmemb, stream) != nmemb)
-    panic (ngettext ("couldn't write %llu item to %s: %s",
-                   "couldn't write %llu items to %s: %s", nmemb),
-          (unsigned long long) nmemb, utils_fp_name (stream),
+    panic (ngettext ("couldn't write %jd item to %s: %s",
+                     "couldn't write %jd items to %s: %s", nmemb),
+          nmemb, utils_fp_name (stream),
           strerror (errno));
 }
 
 /* Panic on failing fread */
-size_t
-ck_fread (void *ptr, size_t size, size_t nmemb, FILE *stream)
+idx_t
+ck_fread (void *ptr, idx_t size, idx_t nmemb, FILE *stream)
 {
   clearerr (stream);
   if (size && (nmemb=fread (ptr, size, nmemb, stream)) <= 0 && ferror (stream))
@@ -247,7 +247,7 @@ ck_fread (void *ptr, size_t size, size_t nmemb, FILE 
*stream)
   return nmemb;
 }
 
-size_t
+ssize_t
 ck_getdelim (char **text, size_t *buflen, char delim, FILE *stream)
 {
   ssize_t result;
@@ -421,20 +421,17 @@ nor do we care, as long as it doesn't mind being aligned 
by malloc. */
 
 struct buffer
   {
-    size_t allocated;
-    size_t length;
+    idx_t allocated;
+    idx_t length;
     char *b;
   };
 
-#define MIN_ALLOCATE 50
-
 struct buffer *
 init_buffer (void)
 {
-  struct buffer *b = XCALLOC (1, struct buffer);
-  b->b = XCALLOC (MIN_ALLOCATE, char);
-  b->allocated = MIN_ALLOCATE;
-  b->length = 0;
+  struct buffer *b = XNMALLOC (1, struct buffer);
+  b->allocated = b->length = 0;
+  b->b = xpalloc (NULL, &b->allocated, 1, -1, 1);
   return b;
 }
 
@@ -444,38 +441,19 @@ get_buffer (struct buffer const *b)
   return b->b;
 }
 
-size_t
+idx_t
 size_buffer (struct buffer const *b)
 {
   return b->length;
 }
 
-static void
-resize_buffer (struct buffer *b, size_t newlen)
-{
-  char *try = NULL;
-  size_t alen = b->allocated;
-
-  if (newlen <= alen)
-    return;
-  alen *= 2;
-  if (newlen < alen)
-    try = realloc (b->b, alen);        /* Note: *not* the REALLOC() macro! */
-  if (!try)
-    {
-      alen = newlen;
-      try = REALLOC (b->b, alen, char);
-    }
-  b->allocated = alen;
-  b->b = try;
-}
-
 char *
-add_buffer (struct buffer *b, const char *p, size_t n)
+add_buffer (struct buffer *b, const char *p, idx_t n)
 {
   char *result;
-  if (b->allocated - b->length < n)
-    resize_buffer (b, b->length+n);
+  idx_t avail = b->allocated - b->length;
+  if (avail < n)
+    b->b = xpalloc (b->b, &b->allocated, n - avail, -1, 1);
   result = memcpy (b->b + b->length, p, n);
   b->length += n;
   return result;
@@ -493,8 +471,8 @@ add1_buffer (struct buffer *b, int c)
   if (c != EOF)
     {
       char *result;
-      if (b->allocated - b->length < 1)
-        resize_buffer (b, b->length+1);
+      if (b->length == b->allocated)
+        b->b = xpalloc (b->b, &b->allocated, 1, -1, 1);
       result = b->b + b->length++;
       *result = c;
       return result;
@@ -507,6 +485,8 @@ void
 free_buffer (struct buffer *b)
 {
   if (b)
-    free (b->b);
-  free (b);
+    {
+      free (b->b);
+      free (b);
+    }
 }
diff --git a/sed/utils.h b/sed/utils.h
index cac8a05..1713307 100644
--- a/sed/utils.h
+++ b/sed/utils.h
@@ -31,26 +31,23 @@ _Noreturn void panic (const char *str, ...)
 
 FILE *ck_fopen (const char *name, const char *mode, int fail);
 FILE *ck_fdopen (int fd, const char *name, const char *mode, int fail);
-void ck_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream);
-size_t ck_fread (void *ptr, size_t size, size_t nmemb, FILE *stream);
+void ck_fwrite (const void *ptr, idx_t size, idx_t nmemb, FILE *stream);
+idx_t ck_fread (void *ptr, idx_t size, idx_t nmemb, FILE *stream);
 void ck_fflush (FILE *stream);
 void ck_fclose (FILE *stream);
 const char *follow_symlink (const char *path);
-size_t ck_getdelim (char **text, size_t *buflen, char buffer_delimiter,
-                    FILE *stream);
+ssize_t ck_getdelim (char **text, size_t *buflen, char buffer_delimiter,
+                     FILE *stream);
 FILE * ck_mkstemp (char **p_filename, const char *tmpdir, const char *base,
                    const char *mode) _GL_ARG_NONNULL ((1, 2, 3, 4));
 void ck_rename (const char *from, const char *to);
 
-void *ck_malloc (size_t size);
-void *ck_realloc (void *ptr, size_t size);
-
 void cancel_cleanup (void);
 void remove_cleanup_file (void);
 
-struct buffer *init_buffer (void);
+struct buffer *init_buffer (void) _GL_ATTRIBUTE_MALLOC;
 char *get_buffer (struct buffer const *b) _GL_ATTRIBUTE_PURE;
-size_t size_buffer (struct buffer const *b) _GL_ATTRIBUTE_PURE;
-char *add_buffer (struct buffer *b, const char *p, size_t n);
+idx_t size_buffer (struct buffer const *b) _GL_ATTRIBUTE_PURE;
+char *add_buffer (struct buffer *b, const char *p, idx_t n);
 char *add1_buffer (struct buffer *b, int ch);
 void free_buffer (struct buffer *b);
-- 
2.38.1






reply via email to

[Prev in Thread] Current Thread [Next in Thread]