]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Streamer: Fix out of range memory access of machine mode
authorPan Li <pan2.li@intel.com>
Wed, 21 Jun 2023 07:58:24 +0000 (15:58 +0800)
committerThomas Schwinge <thomas@codesourcery.com>
Tue, 4 Jul 2023 12:10:54 +0000 (14:10 +0200)
We extend the machine mode from 8 to 16 bits already. But there still
one placing missing from the streamer. It has one hard coded array
for the machine code like size 256.

In the lto pass, we memset the array by MAX_MACHINE_MODE count but the
value of the MAX_MACHINE_MODE will grow as more and more modes are
added. While the machine mode array in tree-streamer still leave 256 as is.

Then, when the MAX_MACHINE_MODE is greater than 256, the memset of
lto_output_init_mode_table will touch the memory out of range unexpected.

This patch would like to take the MAX_MACHINE_MODE as the size of the
array in streamer, to make sure there is no potential unexpected
memory access in future. Meanwhile, this patch also adjust some place
which has MAX_MACHINE_MODE <= 256 assumption.

Care is taken that for offload compilation, we interpret the stream-in
data in terms of the host 'MAX_MACHINE_MODE' ('file_data->mode_bits'),
which very likely is different from the offload device
'MAX_MACHINE_MODE'.

gcc/
* lto-streamer-in.cc (lto_input_mode_table): Stream in the mode
bits for machine mode table.
* lto-streamer-out.cc (lto_write_mode_table): Stream out the
HOST machine mode bits.
* lto-streamer.h (struct lto_file_decl_data): New fields mode_bits.
* tree-streamer.cc (streamer_mode_table): Take MAX_MACHINE_MODE
as the table size.
* tree-streamer.h (streamer_mode_table): Ditto.
(bp_pack_machine_mode): Take 1 << ceil_log2 (MAX_MACHINE_MODE)
as the packing limit.
(bp_unpack_machine_mode): Ditto with 'file_data->mode_bits'.
gcc/lto/
* lto-common.cc (lto_file_finalize) [!ACCEL_COMPILER]: Initialize
'file_data->mode_bits'.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-authored-by: Thomas Schwinge <thomas@codesourcery.com>
gcc/lto-streamer-in.cc
gcc/lto-streamer-out.cc
gcc/lto-streamer.h
gcc/lto/lto-common.cc
gcc/tree-streamer.cc
gcc/tree-streamer.h

index 6e8bc9516a69f7e5c26017fa352ec0fbb462d725..1876e1967ec04bb07f5aa37a3d053950b904e1a6 100644 (file)
@@ -1985,8 +1985,6 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
     internal_error ("cannot read LTO mode table from %s",
                    file_data->file_name);
 
-  unsigned char *table = ggc_cleared_vec_alloc<unsigned char> (1 << 8);
-  file_data->mode_table = table;
   const struct lto_simple_header_with_strings *header
     = (const struct lto_simple_header_with_strings *) data;
   int string_offset;
@@ -1998,16 +1996,22 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
                                header->string_size, vNULL);
   bitpack_d bp = streamer_read_bitpack (&ib);
 
+  unsigned mode_bits = bp_unpack_value (&bp, 5);
+  unsigned char *table = ggc_cleared_vec_alloc<unsigned char> (1 << mode_bits);
+
+  file_data->mode_table = table;
+  file_data->mode_bits = mode_bits;
+
   table[VOIDmode] = VOIDmode;
   table[BLKmode] = BLKmode;
   unsigned int m;
-  while ((m = bp_unpack_value (&bp, 8)) != VOIDmode)
+  while ((m = bp_unpack_value (&bp, mode_bits)) != VOIDmode)
     {
       enum mode_class mclass
        = bp_unpack_enum (&bp, mode_class, MAX_MODE_CLASS);
       poly_uint16 size = bp_unpack_poly_value (&bp, 16);
       poly_uint16 prec = bp_unpack_poly_value (&bp, 16);
-      machine_mode inner = (machine_mode) bp_unpack_value (&bp, 8);
+      machine_mode inner = (machine_mode) bp_unpack_value (&bp, mode_bits);
       poly_uint16 nunits = bp_unpack_poly_value (&bp, 16);
       unsigned int ibit = 0, fbit = 0;
       unsigned int real_fmt_len = 0;
index 3432dd434e2379e97286774f6a183dc4f2d4931c..5ffa89540220ba6d4d3810b438d91f692fd96e80 100644 (file)
@@ -3196,6 +3196,11 @@ lto_write_mode_table (void)
        if (inner_m != m)
          streamer_mode_table[(int) inner_m] = 1;
       }
+
+  /* Pack the mode_bits value within 5 bits (up to 31) in the beginning.  */
+  unsigned mode_bits = ceil_log2 (MAX_MACHINE_MODE);
+  bp_pack_value (&bp, mode_bits, 5);
+
   /* First stream modes that have GET_MODE_INNER (m) == m,
      so that we can refer to them afterwards.  */
   for (int pass = 0; pass < 2; pass++)
@@ -3205,11 +3210,11 @@ lto_write_mode_table (void)
          machine_mode m = (machine_mode) i;
          if ((GET_MODE_INNER (m) == m) ^ (pass == 0))
            continue;
-         bp_pack_value (&bp, m, 8);
+         bp_pack_value (&bp, m, mode_bits);
          bp_pack_enum (&bp, mode_class, MAX_MODE_CLASS, GET_MODE_CLASS (m));
          bp_pack_poly_value (&bp, GET_MODE_SIZE (m), 16);
          bp_pack_poly_value (&bp, GET_MODE_PRECISION (m), 16);
-         bp_pack_value (&bp, GET_MODE_INNER (m), 8);
+         bp_pack_value (&bp, GET_MODE_INNER (m), mode_bits);
          bp_pack_poly_value (&bp, GET_MODE_NUNITS (m), 16);
          switch (GET_MODE_CLASS (m))
            {
@@ -3229,7 +3234,7 @@ lto_write_mode_table (void)
            }
          bp_pack_string (ob, &bp, GET_MODE_NAME (m), true);
        }
-  bp_pack_value (&bp, VOIDmode, 8);
+  bp_pack_value (&bp, VOIDmode, mode_bits);
 
   streamer_write_bitpack (&bp);
 
index 2913b808bdece92374a073e4c228bcd01e70a982..0556b34c837bdf12a09ea080ab715e707a8603d3 100644 (file)
@@ -604,6 +604,8 @@ struct GTY(()) lto_file_decl_data
   int order_base;
 
   int unit_base;
+
+  unsigned mode_bits;
 };
 
 typedef struct lto_file_decl_data *lto_file_decl_data_ptr;
index cdb37c86b466fe4a0bd75a9f3ba117b8aaafeb28..703e665b698fd678566928389c1dc72eb4d135cc 100644 (file)
@@ -2278,6 +2278,7 @@ lto_file_finalize (struct lto_file_decl_data *file_data, lto_file *file,
   lto_input_mode_table (file_data);
 #else
   file_data->mode_table = lto_mode_identity_table;
+  file_data->mode_bits = ceil_log2 (MAX_MACHINE_MODE);
 #endif
 
   data = lto_get_summary_section_data (file_data, LTO_section_decls, &len);
index ed65a7692e3f88fdab783ca6587ebd2cf4d35dd2..a28ef9c7920e7729cca8aaf0822c702995d29880 100644 (file)
@@ -35,7 +35,7 @@ along with GCC; see the file COPYING3.  If not see
    During streaming in, we translate the on the disk mode using this
    table.  For normal LTO it is set to identity, for ACCEL_COMPILER
    depending on the mode_table content.  */
-unsigned char streamer_mode_table[1 << 8];
+unsigned char streamer_mode_table[MAX_MACHINE_MODE];
 
 /* Check that all the TS_* structures handled by the streamer_write_* and
    streamer_read_* routines are exactly ALL the structures defined in
index 6d565acbbc252858163ded2ee8ac88b5ca75068c..ff49d1ba637aaaedd01b46b8cebc26067f2db6c6 100644 (file)
@@ -75,7 +75,7 @@ void streamer_write_tree_body (struct output_block *, tree);
 void streamer_write_integer_cst (struct output_block *, tree);
 
 /* In tree-streamer.cc.  */
-extern unsigned char streamer_mode_table[1 << 8];
+extern unsigned char streamer_mode_table[MAX_MACHINE_MODE];
 void streamer_check_handled_ts_structures (void);
 bool streamer_tree_cache_insert (struct streamer_tree_cache_d *, tree,
                                 hashval_t, unsigned *);
@@ -108,14 +108,16 @@ inline void
 bp_pack_machine_mode (struct bitpack_d *bp, machine_mode mode)
 {
   streamer_mode_table[mode] = 1;
-  bp_pack_enum (bp, machine_mode, 1 << 8, mode);
+  int last = 1 << ceil_log2 (MAX_MACHINE_MODE);
+  bp_pack_enum (bp, machine_mode, last, mode);
 }
 
 inline machine_mode
 bp_unpack_machine_mode (struct bitpack_d *bp)
 {
   lto_input_block *ib = (class lto_input_block *) bp->stream;
-  unsigned ix = bp_unpack_enum (bp, machine_mode, 1 << 8);
+  int last = 1 << ib->file_data->mode_bits;
+  unsigned ix = bp_unpack_enum (bp, machine_mode, last);
   return (machine_mode) ib->file_data->mode_table[ix];
 }