PR26448 UBSAN: symbols.c:1586 left shift of negative value
authorAlan Modra <amodra@gmail.com>
Wed, 26 Aug 2020 08:09:58 +0000 (17:39 +0930)
committerAlan Modra <amodra@gmail.com>
Wed, 26 Aug 2020 13:53:44 +0000 (23:23 +0930)
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.

gas/ChangeLog
gas/symbols.c

index cfa087ed6ac9c6ceeb7680df185b7273c6f7278f..c56b992685cb302e6f6d8797dfd2f2bc6d3b65a7 100644 (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
index 67ac801295875512fc3c214fa9f3d349146b881b..d6080886be8b27000d03621310776fd35e570762 100644 (file)
 #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;