]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
Avoid strtoul
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 8 Aug 2024 00:03:22 +0000 (17:03 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 15 Aug 2024 06:25:45 +0000 (23:25 -0700)
This is part of the general trend to prefer signed integer types,
to allow better runtime checking with -fsanitize=undefined etc.
* gnulib.modules: Remove strtoul.  Add xstrtoimax.
* src/checkpoint.c (checkpoint, format_checkpoint_string):
* src/system.c (sys_exec_checkpoint_script):
* src/tar.c (checkpoint_option):
Use intmax_t, not unsigned, for checkpoint numbers.
All uses changed.
* src/checkpoint.c (checkpoint_compile_action): Don’t assume
time_t == unsigned long.  Treat overflows as TYPE_MAXIMUM (time_t),
essentially infinity.
* src/tar.c (tar_sparse_major, tar_sparse_minor):
* src/tar.h (struct tar_stat_info):
Use intmax_t, not unsigned, for sparse major and minor.
All uses changed.
* src/tar.c (parse_opt):
Don’t mishandle multiple specifications of sparse major and minor.
* src/transform.c (struct transform):
Use idx_t, not unsigned, for match_number.  All uses changed.
(parse_transform_expr): Don’t mishandle large match numbers
by wrapping them around.

gnulib.modules
src/checkpoint.c
src/common.h
src/system.c
src/tar.c
src/tar.h
src/transform.c
src/xheader.c

index cbcde2fb3c3fd74d3884e96cd5a3ff908f04b41e..dc826b437bc83d8c06ae4c8b9ca41d35f8accd2e 100644 (file)
@@ -108,7 +108,6 @@ strerror
 strnlen
 strtoimax
 strtol
-strtoul
 strtoumax
 symlinkat
 sys_stat
@@ -123,6 +122,7 @@ xalignalloc
 xalloc
 xalloc-die
 xgetcwd
+xstrtoimax
 xstrtoumax
 xvasprintf
 year2038-recommended
index 00079ec219e07f145eb5df6d96d08ced512e679a..28e4c22a92a5e56ba98c39c7925246d582ea7fc0 100644 (file)
@@ -50,7 +50,7 @@ struct checkpoint_action
 };
 
 /* Checkpointing counter */
-static unsigned checkpoint;
+static intmax_t checkpoint;
 
 /* List of checkpoint actions */
 static struct checkpoint_action *checkpoint_action, *checkpoint_action_tail;
@@ -128,9 +128,10 @@ checkpoint_compile_action (const char *str)
   else if (strncmp (str, "sleep=", 6) == 0)
     {
       char *p;
-      time_t n = strtoul (str+6, &p, 10);
-      if (*p)
+      intmax_t sleepsec = strtoimax (str + 6, &p, 10);
+      if (*p || sleepsec < 0)
        FATAL_ERROR ((0, 0, _("%s: not a valid timeout"), str));
+      time_t n = ckd_add (&n, sleepsec, 0) ? TYPE_MAXIMUM (time_t) : n;
       act = alloc_action (cop_sleep);
       act->v.time = n;
     }
@@ -231,7 +232,7 @@ static const char *def_format =
 static int
 format_checkpoint_string (FILE *fp, size_t len,
                          const char *input, bool do_write,
-                         unsigned cpn)
+                         intmax_t cpn)
 {
   const char *opstr = do_write ? gettext ("write") : gettext ("read");
   const char *ip;
@@ -279,7 +280,7 @@ format_checkpoint_string (FILE *fp, size_t len,
              break;
 
            case 'u':
-             len += fprintf (fp, "%u", cpn);
+             len += fprintf (fp, "%jd", cpn);
              break;
 
            case 's':
index e81a46319de50b4607711c373b8dd3d5b9d83ea3..135e6f3e3f25a1822b7a8a1246ff036c52ff56fa 100644 (file)
@@ -129,7 +129,7 @@ extern enum backup_type backup_type;
 
 extern bool block_number_option;
 
-extern unsigned checkpoint_option;
+extern intmax_t checkpoint_option;
 #define DEFAULT_CHECKPOINT 10
 
 /* Specified name of compression program, or "gzip" as implied by -z.  */
@@ -288,8 +288,7 @@ extern size_t strip_name_components;
 extern bool show_omitted_dirs_option;
 
 extern bool sparse_option;
-extern unsigned tar_sparse_major;
-extern unsigned tar_sparse_minor;
+extern intmax_t tar_sparse_major, tar_sparse_minor;
 
 enum hole_detection_method
   {
@@ -941,7 +940,7 @@ void sys_wait_command (void);
 int sys_exec_info_script (const char **archive_name, int volume_number);
 void sys_exec_checkpoint_script (const char *script_name,
                                 const char *archive_name,
-                                int checkpoint_number);
+                                intmax_t checkpoint_number);
 bool mtioseek (bool count_files, off_t count);
 int sys_exec_setmtime_script (const char *script_name,
                              int dirfd,
index 2b73afbf997d369759d3304ef8b58da8b2198636..3ec4e993b2ffc5f51698ed8f383caae1875220a8 100644 (file)
@@ -896,7 +896,7 @@ sys_exec_info_script (const char **archive_name, int volume_number)
 void
 sys_exec_checkpoint_script (const char *script_name,
                            const char *archive_name,
-                           int checkpoint_number)
+                           intmax_t checkpoint_number)
 {
   pid_t pid = xfork ();
 
@@ -919,8 +919,8 @@ sys_exec_checkpoint_script (const char *script_name,
   /* Child */
   setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
   setenv ("TAR_ARCHIVE", archive_name, 1);
-  char intbuf[INT_BUFSIZE_BOUND (int)];
-  sprintf (intbuf, "%d", checkpoint_number);
+  char intbuf[INT_BUFSIZE_BOUND (intmax_t)];
+  sprintf (intbuf, "%jd", checkpoint_number);
   setenv ("TAR_CHECKPOINT", intbuf, 1);
   sprintf (intbuf, "%d", blocking_factor);
   setenv ("TAR_BLOCKING_FACTOR", intbuf, 1);
index 4cb074687acc7c68b1e64587ad8c14f12a394353..595ec8b7eb43796c36ebb1f36a4a07f845080b87 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -44,7 +44,7 @@ enum atime_preserve atime_preserve_option;
 bool backup_option;
 enum backup_type backup_type;
 bool block_number_option;
-unsigned checkpoint_option;
+intmax_t checkpoint_option;
 const char *use_compress_program_option;
 bool dereference_option;
 bool hard_dereference_option;
@@ -90,8 +90,8 @@ int xattrs_option;
 size_t strip_name_components;
 bool show_omitted_dirs_option;
 bool sparse_option;
-unsigned tar_sparse_major;
-unsigned tar_sparse_minor;
+intmax_t tar_sparse_major;
+intmax_t tar_sparse_minor;
 enum hole_detection_method hole_detection;
 bool starting_file_option;
 tarlong tape_length_option;
@@ -1831,15 +1831,27 @@ parse_opt (int key, char *arg, struct argp_state *state)
       sparse_option = true;
       {
        char *p;
-       tar_sparse_major = strtoul (arg, &p, 10);
-       if (*p)
+       bool ok;
+       switch (xstrtoimax (arg, &p, 10, &tar_sparse_major, ""))
          {
-           if (*p != '.')
-             USAGE_ERROR ((0, 0, _("Invalid sparse version value")));
-           tar_sparse_minor = strtoul (p + 1, &p, 10);
-           if (*p)
-             USAGE_ERROR ((0, 0, _("Invalid sparse version value")));
+         case LONGINT_OK:
+           tar_sparse_minor = 0;
+           ok = 0 <= tar_sparse_major;
+           break;
+
+         case LONGINT_INVALID_SUFFIX_CHAR:
+           ok = (*p == '.'
+                 && (xstrtoimax (p + 1, nullptr, 10, &tar_sparse_minor, "")
+                     == LONGINT_OK)
+                 && 0 <= tar_sparse_minor && 0 <= tar_sparse_major);
+           break;
+
+         default:
+           ok = false;
+           break;
          }
+       if (!ok)
+         USAGE_ERROR ((0, 0, _("Invalid sparse version value")));
       }
       break;
 
@@ -1936,10 +1948,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
              checkpoint_compile_action (".");
              arg++;
            }
-         checkpoint_option = strtoul (arg, &p, 0);
-         if (*p)
+         checkpoint_option = strtoimax (arg, &p, 0);
+         if (*p || checkpoint_option <= 0)
            FATAL_ERROR ((0, 0,
-                         _("--checkpoint value is not an integer")));
+                         _("invalid --checkpoint value")));
        }
       else
        checkpoint_option = DEFAULT_CHECKPOINT;
index c5b39547967ff3cc3acfff604c4f4ff213f1a7e9..f53ef3e7294c6b01b3da91ed31fb5b7f40c19e73 100644 (file)
--- a/src/tar.h
+++ b/src/tar.h
@@ -325,8 +325,8 @@ struct tar_stat_info
   bool   is_sparse;         /* Is the file sparse */
 
   /* For sparse files: */
-  unsigned sparse_major;
-  unsigned sparse_minor;
+  intmax_t sparse_major;
+  intmax_t sparse_minor;
   size_t sparse_map_avail;  /* Index to the first unused element in
                               sparse_map array. Zero if the file is
                               not sparse */
index f9947193fe33df45818613072798d6a6bc45ee67..2fc97b31f807b93d38d21f0c590a8a4195962621 100644 (file)
@@ -62,7 +62,7 @@ struct transform
   struct transform *next;
   enum transform_type transform_type;
   int flags;
-  unsigned match_number;
+  idx_t match_number;
   regex_t regex;
   /* Compiled replacement expression */
   struct replace_segm *repl_head, *repl_tail;
@@ -248,8 +248,14 @@ parse_transform_expr (const char *expr)
 
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
-       tf->match_number = strtoul (p, (char**) &p, 0);
-       p--;
+       {
+         char *endp;
+         intmax_t match_number = strtoimax (p, &endp, 10);
+         assume (0 <= match_number);
+         if (ckd_add (&tf->match_number, match_number, 0))
+           tf->match_number = IDX_MAX;
+         p = endp - 1;
+       }
        break;
 
       default:
@@ -290,17 +296,19 @@ parse_transform_expr (const char *expr)
     {
       if (*cur == '\\')
        {
-         size_t n;
-
          add_literal_segment (tf, beg, cur);
          switch (*++cur)
            {
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
-             n = strtoul (cur, &cur, 10);
-             if (n > tf->regex.re_nsub)
-               USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
-             add_backref_segment (tf, n);
+             {
+               intmax_t n = strtoimax (cur, &cur, 10);
+               assume (0 <= n);
+               if (tf->regex.re_nsub < n)
+                 USAGE_ERROR ((0, 0, _("Invalid transform replacement:"
+                                       " back reference out of range")));
+               add_backref_segment (tf, n);
+             }
              break;
 
            case '\\':
index cf37e2d982a32545963adbf726db4df79e2ece64..b306accdd7c34b69e6d153402135c94056ce6a41 100644 (file)
@@ -1673,7 +1673,7 @@ sparse_major_decoder (struct tar_stat_info *st,
                      MAYBE_UNUSED size_t size)
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
+  if (decode_num (&u, arg, INTMAX_MAX, keyword))
     st->sparse_major = u;
 }
 
@@ -1691,7 +1691,7 @@ sparse_minor_decoder (struct tar_stat_info *st,
                      MAYBE_UNUSED size_t size)
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
+  if (decode_num (&u, arg, INTMAX_MAX, keyword))
     st->sparse_minor = u;
 }