diff options
author | Alan Modra <amodra@gmail.com> | 2020-08-26 17:39:58 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2020-08-26 23:23:44 +0930 |
commit | d8d6da137d7ececcd0e10c575aa187bb8c9b24e0 (patch) | |
tree | f57f56b1a46cb23bcdbbbbd50cc3c914d0d4cfa9 /gas/symbols.c | |
parent | b2f386b99caeab72eae26ca5bc9024421de145d9 (diff) | |
download | gdb-d8d6da137d7ececcd0e10c575aa187bb8c9b24e0.zip gdb-d8d6da137d7ececcd0e10c575aa187bb8c9b24e0.tar.gz gdb-d8d6da137d7ececcd0e10c575aa187bb8c9b24e0.tar.bz2 |
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.
Diffstat (limited to 'gas/symbols.c')
-rw-r--r-- | gas/symbols.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/gas/symbols.c b/gas/symbols.c index 67ac801..d608088 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -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; |