Merge pull request #346 from visualfc/checkindex

ssa: index/indexAddr check range
This commit is contained in:
xushiwei
2024-06-18 18:52:19 +08:00
committed by GitHub
14 changed files with 694 additions and 406 deletions

View File

@@ -125,34 +125,107 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
if debugInstr {
log.Printf("IndexAddr %v, %v\n", x.impl, idx.impl)
}
idx = b.checkIndex(idx)
prog := b.Prog
telem := prog.Index(x.Type)
pt := prog.Pointer(telem)
switch x.raw.Type.Underlying().(type) {
switch t := x.raw.Type.Underlying().(type) {
case *types.Slice:
ptr := b.SliceData(x)
max := b.SliceLen(x)
idx = b.checkIndex(idx, max)
indices := []llvm.Value{idx.impl}
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt}
case *types.Pointer:
ar := t.Elem().Underlying().(*types.Array)
max := prog.IntVal(uint64(ar.Len()), prog.Int())
idx = b.checkIndex(idx, max)
}
// case *types.Pointer:
indices := []llvm.Value{idx.impl}
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, x.impl, indices), pt}
}
// check index >= 0 and size to uint
func (b Builder) checkIndex(idx Expr) Expr {
prog := b.Prog
if needsNegativeCheck(idx) {
zero := llvm.ConstInt(idx.ll, 0, false)
check := Expr{llvm.CreateICmp(b.impl, llvm.IntSLT, idx.impl, zero), prog.Bool()}
b.InlineCall(b.Pkg.rtFunc("AssertIndexRange"), check)
func isConstantInt(x Expr) (v int64, ok bool) {
if rv := x.impl.IsAConstantInt(); !rv.IsNil() {
v = rv.SExtValue()
ok = true
}
return
}
func isConstantUint(x Expr) (v uint64, ok bool) {
if rv := x.impl.IsAConstantInt(); !rv.IsNil() {
v = rv.ZExtValue()
ok = true
}
return
}
func checkRange(idx Expr, max Expr) (checkMin, checkMax bool) {
if idx.kind == vkSigned {
if v, ok := isConstantInt(idx); ok {
if v < 0 {
checkMin = true
}
if m, ok := isConstantInt(max); ok {
if v >= m {
checkMax = true
}
} else {
checkMax = true
}
} else {
checkMin = true
checkMax = true
}
} else {
if v, ok := isConstantUint(idx); ok {
if m, ok := isConstantUint(max); ok {
if v >= m {
checkMax = true
}
} else {
checkMax = true
}
} else {
checkMax = true
}
}
return
}
// check index >= 0 && index < max and size to uint
func (b Builder) checkIndex(idx Expr, max Expr) Expr {
prog := b.Prog
// check range
checkMin, checkMax := checkRange(idx, max)
// fit size
var typ Type
if idx.kind == vkSigned {
typ = prog.Int()
} else {
typ = prog.Uint()
}
typ := prog.Uint()
if prog.SizeOf(idx.Type) < prog.SizeOf(typ) {
idx.Type = typ
idx.impl = castUintptr(b, idx.impl, typ)
}
// check range expr
var check Expr
if checkMin {
zero := llvm.ConstInt(idx.ll, 0, false)
check = Expr{llvm.CreateICmp(b.impl, llvm.IntSLT, idx.impl, zero), prog.Bool()}
}
if checkMax {
r := Expr{llvm.CreateICmp(b.impl, llvm.IntSGE, idx.impl, max.impl), prog.Bool()}
if check.IsNil() {
check = r
} else {
check = Expr{b.impl.CreateOr(r.impl, check.impl, ""), prog.Bool()}
}
}
if !check.IsNil() {
b.InlineCall(b.Pkg.rtFunc("AssertIndexRange"), check)
}
return idx
}
@@ -170,6 +243,7 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) (Expr, bool)) Expr {
prog := b.Prog
var telem Type
var ptr Expr
var max Expr
var zero bool
switch t := x.raw.Type.Underlying().(type) {
case *types.Basic:
@@ -178,6 +252,7 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) (Expr, bool)) Expr {
}
telem = prog.rawType(types.Typ[types.Byte])
ptr = b.StringData(x)
max = b.StringLen(x)
case *types.Array:
telem = prog.Index(x.Type)
if addr != nil {
@@ -190,9 +265,9 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) (Expr, bool)) Expr {
*/
panic("unreachable")
}
max = prog.IntVal(uint64(t.Len()), prog.Int())
}
// TODO check range
idx = b.checkIndex(idx)
idx = b.checkIndex(idx, max)
if zero {
return Expr{llvm.ConstNull(telem.ll), telem}
}