aboutsummaryrefslogtreecommitdiffhomepage
path: root/compiler/asserts.go
diff options
context:
space:
mode:
authorJaden Weiss <[email protected]>2020-03-28 12:35:19 -0400
committerGitHub <[email protected]>2020-03-28 17:35:19 +0100
commit5cc130bb6ea92882cce391c4251159dc2effd95f (patch)
treec88573940ef57c1c013e63f129240bec0dbad64c /compiler/asserts.go
parent91d1a23b14fd95fb8bdcf306007a2c47d87c32a7 (diff)
downloadtinygo-5cc130bb6ea92882cce391c4251159dc2effd95f.tar.gz
tinygo-5cc130bb6ea92882cce391c4251159dc2effd95f.zip
compiler: implement spec-compliant shifts
Previously, the compiler used LLVM's shift instructions directly, which have UB whenever the shifts are large or negative. This commit adds runtime checks for negative shifts, and handles oversized shifts.
Diffstat (limited to 'compiler/asserts.go')
-rw-r--r--compiler/asserts.go13
1 files changed, 13 insertions, 0 deletions
diff --git a/compiler/asserts.go b/compiler/asserts.go
index f1ae259ea..e8b53f7d4 100644
--- a/compiler/asserts.go
+++ b/compiler/asserts.go
@@ -186,6 +186,19 @@ func (b *builder) createNilCheck(inst ssa.Value, ptr llvm.Value, blockPrefix str
b.createRuntimeAssert(isnil, blockPrefix, "nilPanic")
}
+// createNegativeShiftCheck creates an assertion that panics if the given shift value is negative.
+// This function assumes that the shift value is signed.
+func (b *builder) createNegativeShiftCheck(shift llvm.Value) {
+ if b.fn.IsNoBounds() {
+ // Function disabled bounds checking - skip shift check.
+ return
+ }
+
+ // isNegative = shift < 0
+ isNegative := b.CreateICmp(llvm.IntSLT, shift, llvm.ConstInt(shift.Type(), 0, false), "")
+ b.createRuntimeAssert(isNegative, "shift", "negativeShiftPanic")
+}
+
// createRuntimeAssert is a common function to create a new branch on an assert
// bool, calling an assert func if the assert value is true (1).
func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string) {