aboutsummaryrefslogtreecommitdiff
path: root/gas/symbols.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2020-08-26 17:39:58 +0930
committerAlan Modra <amodra@gmail.com>2020-08-26 23:23:44 +0930
commitd8d6da137d7ececcd0e10c575aa187bb8c9b24e0 (patch)
treef57f56b1a46cb23bcdbbbbd50cc3c914d0d4cfa9 /gas/symbols.c
parentb2f386b99caeab72eae26ca5bc9024421de145d9 (diff)
downloadgdb-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.c21
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;