ubsan: cris: signed integer overflow

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.
This commit is contained in:
Alan Modra 2019-12-10 23:22:10 +10:30
parent 0ef562a4b5
commit c202f69e51
2 changed files with 21 additions and 19 deletions

View 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.

View 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: