Avoid strtoul
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
38
src/tar.c
38
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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 '\\':
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user