PR26448 UBSAN: symbols.c:1586 left shift of negative value

Besides avoiding the UB, this also makes right shifts inside
expression symbols unsigned, consistent with the way gas evaluates
expressions in source.

	PR 26448
	* symbols.c: Include limits.h.
	(resolve_symbol_value <O_left_shift, O_right_shift>): Do an
	unsigned shift.  Warn if shift count larger than valueT size.
This commit is contained in:
Alan Modra 2020-08-26 17:39:58 +09:30
parent b2f386b99c
commit d8d6da137d
2 changed files with 26 additions and 2 deletions

View File

@ -1,3 +1,10 @@
2020-08-26 Alan Modra <amodra@gmail.com>
PR 26448
* symbols.c: Include limits.h.
(resolve_symbol_value <O_left_shift, O_right_shift>): Do an
unsigned shift. Warn if shift count larger than valueT size.
2020-08-26 Alan Modra <amodra@gmail.com>
PR 26447

View File

@ -26,6 +26,13 @@
#include "subsegs.h"
#include "write.h"
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
struct symbol_flags
{
/* Whether the symbol is a local_symbol. */
@ -1559,14 +1566,24 @@ resolve_symbol_value (symbolS *symp)
right = 1;
}
if ((op == O_left_shift || op == O_right_shift)
&& (valueT) right >= sizeof (valueT) * CHAR_BIT)
{
as_warn_value_out_of_range (_("shift count"), right, 0,
sizeof (valueT) * CHAR_BIT - 1,
NULL, 0);
left = right = 0;
}
switch (symp->x->value.X_op)
{
case O_multiply: left *= right; break;
case O_divide: left /= right; break;
case O_modulus: left %= right; break;
case O_left_shift: left <<= right; break;
case O_right_shift: left >>= right; break;
case O_left_shift:
left = (valueT) left << (valueT) right; break;
case O_right_shift:
left = (valueT) left >> (valueT) right; break;
case O_bit_inclusive_or: left |= right; break;
case O_bit_or_not: left |= ~right; break;
case O_bit_exclusive_or: left ^= right; break;