ubsan: cris: signed integer overflow
authorAlan Modra <amodra@gmail.com>
Tue, 10 Dec 2019 12:52:10 +0000 (23:22 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 11 Dec 2019 01:08:24 +0000 (11:38 +1030)
This was the following in print_with_operands
case 4:
  number
    = buffer[2] + buffer[3] * 256 + buffer[4] * 65536
    + buffer[5] * 0x1000000;
and buffer[5] * 0x1000000 can indeed overflow.  So to fix this we need
to use unsigned arithmetic where overflow semantics are specified.
But number is a long, and the expression is int which will be sign
extended to long.  If we make the expression unsigned it will be zero
extended.  So make number an int32_t and rearrange a little for some
of the places that need fixing.

* cris-dis.c (print_with_operands): Avoid signed integer
overflow when collecting bytes of a 32-bit integer.

opcodes/ChangeLog
opcodes/cris-dis.c

index 57212f843baa4a034b3c11e810e1d6f1e42351bc..6b76f158c952f54e32afc212f47f6ca997ed2fb8 100644 (file)
@@ -1,3 +1,8 @@
+2019-12-11  Alan Modra  <amodra@gmail.com>
+
+       * cris-dis.c (print_with_operands): Avoid signed integer
+       overflow when collecting bytes of a 32-bit integer.
+
 2019-12-11  Alan Modra  <amodra@gmail.com>
 
        * cr16-dis.c (EXTRACT, SBM): Rewrite.
index 793549d26dc203efc097a955562ade27a507410b..c501ba002c66e9846d0e99c4fc1e0b861052a34c 100644 (file)
@@ -850,9 +850,8 @@ print_with_operands (const struct cris_opcode *opcodep,
       case 'n':
        {
          /* Like N but pc-relative to the start of the insn.  */
-         unsigned long number
-           = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
-              + buffer[5] * 0x1000000 + addr);
+         int32_t number = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+                           + buffer[5] * 0x1000000u);
 
          /* Finish off and output previous formatted bytes.  */
          *tp = 0;
@@ -860,14 +859,14 @@ print_with_operands (const struct cris_opcode *opcodep,
            (*info->fprintf_func) (info->stream, "%s", temp);
          tp = temp;
 
-         (*info->print_address_func) ((bfd_vma) number, info);
+         (*info->print_address_func) (addr + number, info);
        }
        break;
 
       case 'u':
        {
          /* Like n but the offset is bits <3:0> in the instruction.  */
-         unsigned long number = (buffer[0] & 0xf) * 2 + addr;
+         unsigned int number = (buffer[0] & 0xf) * 2;
 
          /* Finish off and output previous formatted bytes.  */
          *tp = 0;
@@ -875,7 +874,7 @@ print_with_operands (const struct cris_opcode *opcodep,
            (*info->fprintf_func) (info->stream, "%s", temp);
          tp = temp;
 
-         (*info->print_address_func) ((bfd_vma) number, info);
+         (*info->print_address_func) (addr + number, info);
        }
        break;
 
@@ -889,7 +888,7 @@ print_with_operands (const struct cris_opcode *opcodep,
          {
            /* We're looking at [pc+], i.e. we need to output an immediate
               number, where the size can depend on different things.  */
-           long number;
+           int32_t number;
            int signedp
              = ((*cs == 'z' && (insn & 0x20))
                 || opcodep->match == BDAP_QUICK_OPCODE);
@@ -940,9 +939,8 @@ print_with_operands (const struct cris_opcode *opcodep,
                break;
 
              case 4:
-               number
-                 = buffer[2] + buffer[3] * 256 + buffer[4] * 65536
-                 + buffer[5] * 0x1000000;
+               number = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+                         + buffer[5] * 0x1000000u);
                break;
 
              default:
@@ -1042,10 +1040,10 @@ print_with_operands (const struct cris_opcode *opcodep,
                      {
                        /* It's [pc+].  This cannot possibly be anything
                           but an address.  */
-                       unsigned long number
-                         = prefix_buffer[2] + prefix_buffer[3] * 256
-                         + prefix_buffer[4] * 65536
-                         + prefix_buffer[5] * 0x1000000;
+                       int32_t number = (prefix_buffer[2]
+                                         + prefix_buffer[3] * 256
+                                         + prefix_buffer[4] * 65536
+                                         + prefix_buffer[5] * 0x1000000u);
 
                        info->target = (bfd_vma) number;
 
@@ -1131,7 +1129,7 @@ print_with_operands (const struct cris_opcode *opcodep,
 
                    if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
                      {
-                       long number;
+                       int32_t number;
                        unsigned int nbytes;
 
                        /* It's a value.  Get its size.  */
@@ -1157,10 +1155,9 @@ print_with_operands (const struct cris_opcode *opcodep,
                            break;
 
                          case 4:
-                           number
-                             = prefix_buffer[2] + prefix_buffer[3] * 256
-                             + prefix_buffer[4] * 65536
-                             + prefix_buffer[5] * 0x1000000;
+                           number = (prefix_buffer[2] + prefix_buffer[3] * 256
+                                     + prefix_buffer[4] * 65536
+                                     + prefix_buffer[5] * 0x1000000u);
                            break;
 
                          default: