summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2004-09-18 19:17:10 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2004-09-18 19:17:10 (GMT)
commita3ec92940dc1dda1f91d654e08b7bba36bc2300d (patch)
tree34583eaed6324aad39f4233f0f144285bab5bf82
parent2994c047afba0aed2193c6cc688808335ae956ce (diff)
downloadtcl-a3ec92940dc1dda1f91d654e08b7bba36bc2300d.zip
tcl-a3ec92940dc1dda1f91d654e08b7bba36bc2300d.tar.gz
tcl-a3ec92940dc1dda1f91d654e08b7bba36bc2300d.tar.bz2
Make sure large shifts shift for real. [Bug 868467]
-rw-r--r--ChangeLog5
-rw-r--r--generic/tclExecute.c83
-rw-r--r--tests/expr.test13
3 files changed, 93 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index c2f5a8a..7298a82 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2004-09-18 Donal K. Fellows <donal.k.fellows@man.ac.uk>
+
+ * generic/tclExecute.c (TEBC-INST_LSHIFT,INST_RSHIFT): Ensure that
+ large shifts end up shifting correctly. [Bug 868467]
+
2004-09-15 Daniel Steffen <das@users.sourceforge.net>
* tests/load.test (load-2.3): adopted fix for failure on darwin
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index b0a94fe..ef4f379 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclExecute.c,v 1.94.2.8 2004/09/10 15:30:02 msofer Exp $
+ * RCS: @(#) $Id: tclExecute.c,v 1.94.2.9 2004/09/18 19:17:12 dkf Exp $
*/
#include "tclInt.h"
@@ -3058,11 +3058,42 @@ TclExecuteByteCode(interp, codePtr)
#ifdef TCL_COMPILE_DEBUG
w2 = Tcl_LongAsWide(i2);
#endif /* TCL_COMPILE_DEBUG */
- wResult = w << i2;
+ wResult = w;
+ /*
+ * Shift in steps when the shift gets large to prevent
+ * annoying compiler/processor bugs. [Bug 868467]
+ */
+ if (i2 >= 64) {
+ wResult = Tcl_LongAsWide(0);
+ } else if (i2 > 60) {
+ wResult = w << 30;
+ wResult <<= 30;
+ wResult <<= i2-60;
+ } else if (i2 > 30) {
+ wResult = w << 30;
+ wResult <<= i2-30;
+ } else {
+ wResult = w << i2;
+ }
doWide = 1;
break;
}
- iResult = i << i2;
+ /*
+ * Shift in steps when the shift gets large to prevent
+ * annoying compiler/processor bugs. [Bug 868467]
+ */
+ if (i2 >= 64) {
+ iResult = 0;
+ } else if (i2 > 60) {
+ iResult = i << 30;
+ iResult <<= 30;
+ iResult <<= i2-60;
+ } else if (i2 > 30) {
+ iResult = i << 30;
+ iResult <<= i2-30;
+ } else {
+ iResult = i << i2;
+ }
break;
case INST_RSHIFT:
/*
@@ -3079,17 +3110,55 @@ TclExecuteByteCode(interp, codePtr)
w2 = Tcl_LongAsWide(i2);
#endif /* TCL_COMPILE_DEBUG */
if (w < 0) {
- wResult = ~((~w) >> i2);
+ wResult = ~w;
+ } else {
+ wResult = w;
+ }
+ /*
+ * Shift in steps when the shift gets large to prevent
+ * annoying compiler/processor bugs. [Bug 868467]
+ */
+ if (i2 >= 64) {
+ wResult = Tcl_LongAsWide(0);
+ } else if (i2 > 60) {
+ wResult >>= 30;
+ wResult >>= 30;
+ wResult >>= i2-60;
+ } else if (i2 > 30) {
+ wResult >>= 30;
+ wResult >>= i2-30;
} else {
- wResult = w >> i2;
+ wResult >>= i2;
+ }
+ if (w < 0) {
+ wResult = ~wResult;
}
doWide = 1;
break;
}
if (i < 0) {
- iResult = ~((~i) >> i2);
+ iResult = ~i;
+ } else {
+ iResult = i;
+ }
+ /*
+ * Shift in steps when the shift gets large to prevent
+ * annoying compiler/processor bugs. [Bug 868467]
+ */
+ if (i2 >= 64) {
+ iResult = 0;
+ } else if (i2 > 60) {
+ iResult >>= 30;
+ iResult >>= 30;
+ iResult >>= i2-60;
+ } else if (i2 > 30) {
+ iResult >>= 30;
+ iResult >>= i2-30;
} else {
- iResult = i >> i2;
+ iResult >>= i2;
+ }
+ if (i < 0) {
+ iResult = ~iResult;
}
break;
case INST_BITOR:
diff --git a/tests/expr.test b/tests/expr.test
index 6ef1c41..b4b6917 100644
--- a/tests/expr.test
+++ b/tests/expr.test
@@ -10,7 +10,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: expr.test,v 1.17.2.1 2003/03/27 13:49:22 dkf Exp $
+# RCS: @(#) $Id: expr.test,v 1.17.2.2 2004/09/18 19:17:13 dkf Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest
@@ -806,6 +806,17 @@ test expr-22.8 {non-numeric floats} nonPortable {
list [catch {expr {1 / Inf}} msg] $msg
} {1 {can't use infinite floating-point value as operand of "/"}}
+# Some compilers get this wrong; ensure that we work around it correctly
+test expr-24.1 {expr edge cases; shifting} {expr int(5)>>31} 0
+test expr-24.2 {expr edge cases; shifting} {expr int(5)>>63} 0
+test expr-24.3 {expr edge cases; shifting} {expr wide(5)>>31} 0
+test expr-24.4 {expr edge cases; shifting} {expr wide(5)>>63} 0
+test expr-24.5 {expr edge cases; shifting} nonPortable {expr int(5)<<31} 0
+test expr-24.6 {expr edge cases; shifting} {expr int(5)<<63} 0
+test expr-24.7 {expr edge cases; shifting} {expr wide(5)<<31} 10737418240
+test expr-24.8 {expr edge cases; shifting} nonPortable {expr wide(5)<<63} -9223372036854775808
+test expr-24.9 {expr edge cases; shifting} {expr 5>>32} 0
+
# cleanup
if {[info exists a]} {
unset a