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

Alan Modra amodra@gmail.com
Wed Aug 26 13:47:40 GMT 2020


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.

diff --git a/gas/symbols.c b/gas/symbols.c
index 67ac801295..d6080886be 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;

-- 
Alan Modra
Australia Development Lab, IBM


More information about the Binutils mailing list