bug-coreutils
[Top][All Lists]
Advanced

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

cut.c patch for unsigned overflow problems with sizes, etc.


From: Paul Eggert
Subject: cut.c patch for unsigned overflow problems with sizes, etc.
Date: 06 Nov 2003 00:14:39 -0800
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3

I went through cut.c and found some problems on hosts where size_t is
wider than int.  While I was at it, I fixed the widths of all the
integer types that I could find.  Here's a proposed patch.

2003-11-05  Paul Eggert  <address@hidden>

        Fix 'cut' problems with size_t overflow and unsigned int.
        More generally, resize integer variables to fit use more precisely.
        * m4/jm-macros.m4 (jm_CHECK_ALL_TYPES): Check for uintptr_t.
        * src/cut.c (ADD_RANGE_PAIR): Remove unnecessary parens.
        (struct range_pair): Make members to be of type size_t, not unsigned.
        (max_range_endpoint, eol_range_start): Now size_t, not unsigned.
        (suppress_non_delimited, output_delimiter_specified,
        have_read_stdin, print_kth, set_fields): Now bool, nt int.
        (delim): Now unsigned char, not int.
        (mark_printable_field, is_printable_field, is_range_start_index,
        set_fields, set_fields, cut_bytes, cut_fields):
        Use size_t, not unsigned, for field and byte counts.
        (hash_int): Use uintptr_t, not unsigned, for pointers converted
        to integers.  This squeezes more info out of them.
        (set_fields, cut_bytes, cut_fields, main):
        Use bool, not int, for booleans.
        (set_fields): Allocate zeroed byte array with xzalloc, not xcalloc.

Index: m4/jm-macros.m4
===================================================================
RCS file: /cvsroot/coreutils/coreutils/m4/jm-macros.m4,v
retrieving revision 1.180
diff -p -u -r1.180 jm-macros.m4
--- m4/jm-macros.m4     5 Oct 2003 11:42:11 -0000       1.180
+++ m4/jm-macros.m4     6 Nov 2003 08:03:50 -0000
@@ -256,7 +256,8 @@ AC_DEFUN([jm_CHECK_ALL_TYPES],
   AC_REQUIRE([AC_TYPE_SIGNAL])
   AC_REQUIRE([AC_TYPE_SIZE_T])
   AC_REQUIRE([AC_TYPE_UID_T])
-  AC_CHECK_TYPE(ino_t, unsigned long)
+  AC_CHECK_TYPE(ino_t, unsigned long int)
+  AC_CHECK_TYPE(uintptr_t, size_t)
 
   gt_TYPE_SSIZE_T
 
Index: src/cut.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/cut.c,v
retrieving revision 1.107
diff -p -u -r1.107 cut.c
--- src/cut.c   4 Nov 2003 06:28:01 -0000       1.107
+++ src/cut.c   6 Nov 2003 08:03:52 -0000
@@ -58,7 +58,7 @@
     {                                                                  \
       if (n_rp >= n_rp_allocated)                                      \
        {                                                               \
-         (rp) = x2nrealloc (rp, &n_rp_allocated, sizeof (*(rp)));      \
+         (rp) = x2nrealloc (rp, &n_rp_allocated, sizeof *(rp));        \
        }                                                               \
       rp[n_rp].lo = (low);                                             \
       rp[n_rp].hi = (high);                                            \
@@ -68,8 +68,8 @@
 
 struct range_pair
   {
-    unsigned int lo;
-    unsigned int hi;
+    size_t lo;
+    size_t hi;
   };
 
 /* This buffer is used to support the semantics of the -s option
@@ -88,11 +88,11 @@ static size_t field_1_bufsize;
    or degenerate range specification;  this doesn't include the starting
    index of right-open-ended ranges.  For example, with either range spec
    `2-5,9-', `2-3,5,9-' this variable would be set to 5.  */
-static unsigned int max_range_endpoint;
+static size_t max_range_endpoint;
 
 /* If nonzero, this is the index of the first field in a range that goes
    to end of line. */
-static unsigned int eol_range_start;
+static size_t eol_range_start;
 
 /* This is a bit vector.
    In byte mode, which bytes to output.
@@ -120,16 +120,16 @@ char *program_name;
 
 static enum operating_mode operating_mode;
 
-/* If nonzero do not output lines containing no delimeter characters.
+/* If true do not output lines containing no delimeter characters.
    Otherwise, all such lines are printed.  This option is valid only
    with field mode.  */
-static int suppress_non_delimited;
+static bool suppress_non_delimited;
 
 /* The delimeter character for field mode. */
-static int delim;
+static unsigned char delim;
 
-/* Nonzero if the --output-delimiter=STRING option was specified.  */
-static int output_delimiter_specified;
+/* True if the --output-delimiter=STRING option was specified.  */
+static bool output_delimiter_specified;
 
 /* The length of output_delimiter_string.  */
 static size_t output_delimiter_length;
@@ -138,8 +138,8 @@ static size_t output_delimiter_length;
    string consisting of the input delimiter.  */
 static char *output_delimiter_string;
 
-/* Nonzero if we have ever read standard input. */
-static int have_read_stdin;
+/* True if we have ever read standard input. */
+static bool have_read_stdin;
 
 #define HT_RANGE_START_INDEX_INITIAL_CAPACITY 31
 
@@ -225,14 +225,14 @@ With no FILE, or when FILE is -, read st
 }
 
 static inline void
-mark_printable_field (unsigned int i)
+mark_printable_field (size_t i)
 {
   size_t n = i / CHAR_BIT;
   printable_field[n] |= (1 << (i % CHAR_BIT));
 }
 
 static inline bool
-is_printable_field (unsigned int i)
+is_printable_field (size_t i)
 {
   size_t n = i / CHAR_BIT;
   return (printable_field[n] >> (i % CHAR_BIT)) & 1;
@@ -241,8 +241,8 @@ is_printable_field (unsigned int i)
 static size_t
 hash_int (const void *x, size_t tablesize)
 {
-  unsigned int y = (unsigned int) x;
-  return (y % tablesize);
+  uintptr_t y = (uintptr_t) x;
+  return y % tablesize;
 }
 
 static bool
@@ -252,34 +252,34 @@ hash_compare_ints (void const *x, void c
 }
 
 static bool
-is_range_start_index (int i)
+is_range_start_index (size_t i)
 {
   return hash_lookup (range_start_ht, (void *) i) ? true : false;
 }
 
 /* Return nonzero if the K'th field or byte is printable.
    When returning nonzero, if RANGE_START is non-NULL,
-   set *RANGE_START to nonzero if K is the beginning of a range, and
-   set *RANGE_START to zero if K is not the beginning of a range.  */
+   set *RANGE_START to true if K is the beginning of a range, and to
+   false otherwise.  */
 
-static int
-print_kth (unsigned int k, int *range_start)
+static bool
+print_kth (size_t k, bool *range_start)
 {
   if (0 < eol_range_start && eol_range_start <= k)
     {
       if (range_start)
        *range_start = (k == eol_range_start);
-      return 1;
+      return true;
     }
 
   if (k <= max_range_endpoint && is_printable_field (k))
     {
       if (range_start)
        *range_start = is_range_start_index (k);
-      return 1;
+      return true;
     }
 
-  return 0;
+  return false;
 }
 
 /* Given the list of field or byte range specifications FIELDSTR, set
@@ -288,8 +288,8 @@ print_kth (unsigned int k, int *range_st
    to its starting index.  FIELDSTR should be composed of one or more
    numbers or ranges of numbers, separated by blanks or commas.
    Incomplete ranges may be given: `-m' means `1-m'; `n-' means `n'
-   through end of line.  Return nonzero if FIELDSTR contains at least
-   one field specification, zero otherwise.  */
+   through end of line.  Return true if FIELDSTR contains at least
+   one field specification, false otherwise.  */
 
 /* FIXME-someday:  What if the user wants to cut out the 1,000,000-th
    field of some huge input file?  This function shouldn't have to
@@ -301,19 +301,19 @@ print_kth (unsigned int k, int *range_st
    too many are selected, then resort to using the range-pairs (the
    `rp' array) directly.  */
 
-static int
+static bool
 set_fields (const char *fieldstr)
 {
-  unsigned int initial = 1;    /* Value of first number in a range.  */
-  unsigned int value = 0;      /* If nonzero, a number being accumulated.  */
-  int dash_found = 0;          /* Nonzero if a '-' is found in this field.  */
-  int field_found = 0;         /* Non-zero if at least one field spec
+  size_t initial = 1;          /* Value of first number in a range.  */
+  size_t value = 0;            /* If nonzero, a number being accumulated.  */
+  bool dash_found = false;     /* True if a '-' is found in this field.  */
+  bool field_found = false;    /* True if at least one field spec
                                   has been processed.  */
 
   struct range_pair *rp = NULL;
-  unsigned int n_rp = 0;
-  unsigned int n_rp_allocated = 0;
-  unsigned int i;
+  size_t n_rp = 0;
+  size_t n_rp_allocated = 0;
+  size_t i;
   bool in_digits = false;
 
   /* Collect and store in RP the range end points.
@@ -327,7 +327,7 @@ set_fields (const char *fieldstr)
          /* Starting a range. */
          if (dash_found)
            FATAL_ERROR (_("invalid byte or field list"));
-         dash_found++;
+         dash_found = true;
          fieldstr++;
 
          if (value)
@@ -344,7 +344,7 @@ set_fields (const char *fieldstr)
          /* Ending the string, or this field/byte sublist. */
          if (dash_found)
            {
-             dash_found = 0;
+             dash_found = false;
 
              /* A range.  Possibilites: -n, m-n, n-.
                 In any case, `initial' contains the start of the range. */
@@ -352,7 +352,7 @@ set_fields (const char *fieldstr)
                {
                  /* `n-'.  From `initial' to end of line. */
                  eol_range_start = initial;
-                 field_found = 1;
+                 field_found = true;
                }
              else
                {
@@ -384,14 +384,14 @@ set_fields (const char *fieldstr)
                            }
 
                          /* In any case, some fields were selected. */
-                         field_found = 1;
+                         field_found = true;
                        }
                    }
                  else
                    {
                      /* There is no range going to end of line. */
                      ADD_RANGE_PAIR (rp, initial, value);
-                     field_found = 1;
+                     field_found = true;
                    }
                  value = 0;
                }
@@ -401,7 +401,7 @@ set_fields (const char *fieldstr)
              /* A simple field number, not a range. */
              ADD_RANGE_PAIR (rp, value, value);
              value = 0;
-             field_found = 1;
+             field_found = true;
            }
 
          if (*fieldstr == '\0')
@@ -413,7 +413,7 @@ set_fields (const char *fieldstr)
        }
       else if (ISDIGIT (*fieldstr))
        {
-         unsigned int new_v;
+         size_t new_v;
          /* Record beginning of digit string, in case we have to
             complain about it.  */
          static char const *num_start;
@@ -423,7 +423,7 @@ set_fields (const char *fieldstr)
 
          /* Detect overflow.  */
          new_v = 10 * value + *fieldstr - '0';
-         if (UINT_MAX / 10 < value || new_v < value * 10)
+         if (SIZE_MAX / 10 < value || new_v < value * 10)
            {
              /* In case the user specified -c4294967296-22,
                 complain only about the first number.  */
@@ -458,13 +458,12 @@ set_fields (const char *fieldstr)
      the field numbers corresponding to all finite ranges
      (i.e. `2-6' or `-4', but not `5-') in FIELDSTR.  */
 
-  printable_field = xcalloc (max_range_endpoint / CHAR_BIT + 1,
-                            sizeof *printable_field);
+  printable_field = xzalloc (max_range_endpoint / CHAR_BIT + 1);
 
   /* Set the array entries corresponding to integers in the ranges of RP.  */
   for (i = 0; i < n_rp; i++)
     {
-      unsigned int j;
+      size_t j;
       for (j = rp[i].lo; j <= rp[i].hi; j++)
        {
          mark_printable_field (j);
@@ -476,7 +475,7 @@ set_fields (const char *fieldstr)
       /* Record the range-start indices.  */
       for (i = 0; i < n_rp; i++)
        {
-         unsigned int j = rp[i].lo;
+         size_t j;
          for (j = rp[i].lo; j <= rp[i].hi; j++)
            {
              if (0 < j && is_printable_field (j)
@@ -490,7 +489,7 @@ set_fields (const char *fieldstr)
                      /* Insertion failed due to lack of memory.  */
                      xalloc_die ();
                    }
-                 assert ((unsigned int) ent_from_table == j);
+                 assert ((size_t) ent_from_table == j);
                }
            }
        }
@@ -506,13 +505,13 @@ set_fields (const char *fieldstr)
 static void
 cut_bytes (FILE *stream)
 {
-  unsigned int byte_idx;       /* Number of bytes in the line so far. */
+  size_t byte_idx;     /* Number of bytes in the line so far. */
   /* Whether to begin printing delimiters between ranges for the current line.
      Set after we've begun printing data corresponding to the first range.  */
-  int print_delimiter;
+  bool print_delimiter;
 
   byte_idx = 0;
-  print_delimiter = 0;
+  print_delimiter = false;
   while (1)
     {
       register int c;          /* Each character from the file. */
@@ -523,7 +522,7 @@ cut_bytes (FILE *stream)
        {
          putchar ('\n');
          byte_idx = 0;
-         print_delimiter = 0;
+         print_delimiter = false;
        }
       else if (c == EOF)
        {
@@ -533,8 +532,8 @@ cut_bytes (FILE *stream)
        }
       else
        {
-         int range_start;
-         int *rs = output_delimiter_specified ? &range_start : NULL;
+         bool range_start;
+         bool *rs = output_delimiter_specified ? &range_start : NULL;
          if (print_kth (++byte_idx, rs))
            {
              if (rs && *rs && print_delimiter)
@@ -542,7 +541,7 @@ cut_bytes (FILE *stream)
                  fwrite (output_delimiter_string, sizeof (char),
                          output_delimiter_length, stdout);
                }
-             print_delimiter = 1;
+             print_delimiter = true;
              putchar (c);
            }
        }
@@ -555,12 +554,9 @@ static void
 cut_fields (FILE *stream)
 {
   int c;
-  unsigned int field_idx;
-  int found_any_selected_field;
-  int buffer_first_field;
-
-  found_any_selected_field = 0;
-  field_idx = 1;
+  size_t field_idx = 1;
+  bool found_any_selected_field = false;
+  bool buffer_first_field;
 
   c = getc (stream);
   if (c == EOF)
@@ -617,7 +613,7 @@ cut_fields (FILE *stream)
            {
              /* Print the field, but not the trailing delimiter.  */
              fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout);
-             found_any_selected_field = 1;
+             found_any_selected_field = true;
            }
          ++field_idx;
        }
@@ -631,7 +627,7 @@ cut_fields (FILE *stream)
                  fwrite (output_delimiter_string, sizeof (char),
                          output_delimiter_length, stdout);
                }
-             found_any_selected_field = 1;
+             found_any_selected_field = true;
 
              while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
                {
@@ -667,7 +663,7 @@ cut_fields (FILE *stream)
          if (c == EOF)
            break;
          field_idx = 1;
-         found_any_selected_field = 0;
+         found_any_selected_field = false;
        }
     }
 }
@@ -691,7 +687,7 @@ cut_file (char *file)
 
   if (STREQ (file, "-"))
     {
-      have_read_stdin = 1;
+      have_read_stdin = true;
       stream = stdin;
     }
   else
@@ -725,7 +721,7 @@ int
 main (int argc, char **argv)
 {
   int optc, exit_status = 0;
-  int delim_specified = 0;
+  bool delim_specified = false;
   char *spec_list_string IF_LINT(= NULL);
 
   initialize_main (&argc, &argv);
@@ -739,10 +735,10 @@ main (int argc, char **argv)
   operating_mode = undefined_mode;
 
   /* By default, all non-delimited lines are printed.  */
-  suppress_non_delimited = 0;
+  suppress_non_delimited = false;
 
   delim = '\0';
-  have_read_stdin = 0;
+  have_read_stdin = false;
 
   while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1)
     {
@@ -773,12 +769,12 @@ main (int argc, char **argv)
          /* Interpret -d '' to mean `use the NUL byte as the delimiter.'  */
          if (optarg[0] != '\0' && optarg[1] != '\0')
            FATAL_ERROR (_("the delimiter must be a single character"));
-         delim = (unsigned char) optarg[0];
-         delim_specified = 1;
+         delim = optarg[0];
+         delim_specified = true;
          break;
 
        case OUTPUT_DELIMITER_OPTION:
-         output_delimiter_specified = 1;
+         output_delimiter_specified = true;
          /* Interpret --output-delimiter='' to mean
             `use the NUL byte as the delimiter.'  */
          output_delimiter_length = (optarg[0] == '\0'
@@ -790,7 +786,7 @@ main (int argc, char **argv)
          break;
 
        case 's':
-         suppress_non_delimited = 1;
+         suppress_non_delimited = true;
          break;
 
        case_GETOPT_HELP_CHAR;
@@ -823,7 +819,7 @@ main (int argc, char **argv)
 
     }
 
-  if (set_fields (spec_list_string) == 0)
+  if (! set_fields (spec_list_string))
     {
       if (operating_mode == field_mode)
        FATAL_ERROR (_("missing list of fields"));




reply via email to

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