Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 Aug 2014 22:36:42 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r270029 - in head/bin/sh: . tests/expansion
Message-ID:  <201408152236.s7FMagUJ043433@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Fri Aug 15 22:36:41 2014
New Revision: 270029
URL: http://svnweb.freebsd.org/changeset/base/270029

Log:
  sh: Mask off shift distance (<< and >>) in arithmetic.
  
  In C, shift distances equal to or larger than the number of bits in the
  operand result in undefined behaviour. As part of eliminating undefined
  behaviour in arithmetic, mask off the distance like Java and JavaScript
  specify and C on x86 usually does.
  
  Assumption: conversion from unsigned to signed retains the two's complement
  bits.
  Assumption: uintmax_t has no padding bits.

Added:
  head/bin/sh/tests/expansion/arith14.0   (contents, props changed)
Modified:
  head/bin/sh/arith_yacc.c
  head/bin/sh/tests/expansion/Makefile

Modified: head/bin/sh/arith_yacc.c
==============================================================================
--- head/bin/sh/arith_yacc.c	Fri Aug 15 21:35:31 2014	(r270028)
+++ head/bin/sh/arith_yacc.c	Fri Aug 15 22:36:41 2014	(r270029)
@@ -139,9 +139,10 @@ static arith_t do_binop(int op, arith_t 
 	case ARITH_SUB:
 		return (uintmax_t)a - (uintmax_t)b;
 	case ARITH_LSHIFT:
-		return (uintmax_t)a << b;
+		return (uintmax_t)a <<
+		    ((uintmax_t)b & (sizeof(uintmax_t) * CHAR_BIT - 1));
 	case ARITH_RSHIFT:
-		return a >> b;
+		return a >> ((uintmax_t)b & (sizeof(uintmax_t) * CHAR_BIT - 1));
 	case ARITH_LT:
 		return a < b;
 	case ARITH_LE:

Modified: head/bin/sh/tests/expansion/Makefile
==============================================================================
--- head/bin/sh/tests/expansion/Makefile	Fri Aug 15 21:35:31 2014	(r270028)
+++ head/bin/sh/tests/expansion/Makefile	Fri Aug 15 22:36:41 2014	(r270029)
@@ -20,6 +20,7 @@ FILES+=		arith10.0
 FILES+=		arith11.0
 FILES+=		arith12.0
 FILES+=		arith13.0
+FILES+=		arith14.0
 FILES+=		assign1.0
 FILES+=		cmdsubst1.0
 FILES+=		cmdsubst2.0

Added: head/bin/sh/tests/expansion/arith14.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/expansion/arith14.0	Fri Aug 15 22:36:41 2014	(r270029)
@@ -0,0 +1,40 @@
+# $FreeBSD$
+# Check that <</>> use the low bits of the shift count.
+
+if [ $((1<<16<<16)) = 0 ]; then
+	width=32
+elif [ $((1<<32<<32)) = 0 ]; then
+	width=64
+elif [ $((1<<64<<64)) = 0 ]; then
+	width=128
+elif [ $((1<<64>>64)) = 1 ]; then
+	# Integers are wider than 128 bits; assume arbitrary precision.
+	# Nothing to test here.
+	exit 0
+else
+	echo "Cannot determine integer width"
+	exit 2
+fi
+
+twowidth=$((width * 2))
+j=43 k=$((1 << (width - 2))) r=0
+
+i=0
+while [ $i -lt $twowidth ]; do
+	if [ "$((j << i))" != "$((j << (i + width)))" ]; then
+		echo "Problem with $j << $i"
+		r=2
+	fi
+	i=$((i + 1))
+done
+
+i=0
+while [ $i -lt $twowidth ]; do
+	if [ "$((k >> i))" != "$((k >> (i + width)))" ]; then
+		echo "Problem with $k >> $i"
+		r=2
+	fi
+	i=$((i + 1))
+done
+
+exit $r



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408152236.s7FMagUJ043433>