Update to kube v1.17

Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
Humble Chirammal
2020-01-14 16:08:55 +05:30
committed by mergify[bot]
parent 327fcd1b1b
commit 3af1e26d7c
1710 changed files with 289562 additions and 168638 deletions

View File

@ -0,0 +1,73 @@
package vrp
import (
"fmt"
"honnef.co/go/tools/ssa"
)
type ChannelInterval struct {
Size IntInterval
}
func (c ChannelInterval) Union(other Range) Range {
i, ok := other.(ChannelInterval)
if !ok {
i = ChannelInterval{EmptyIntInterval}
}
if c.Size.Empty() || !c.Size.IsKnown() {
return i
}
if i.Size.Empty() || !i.Size.IsKnown() {
return c
}
return ChannelInterval{
Size: c.Size.Union(i.Size).(IntInterval),
}
}
func (c ChannelInterval) String() string {
return c.Size.String()
}
func (c ChannelInterval) IsKnown() bool {
return c.Size.IsKnown()
}
type MakeChannelConstraint struct {
aConstraint
Buffer ssa.Value
}
type ChannelChangeTypeConstraint struct {
aConstraint
X ssa.Value
}
func NewMakeChannelConstraint(buffer, y ssa.Value) Constraint {
return &MakeChannelConstraint{NewConstraint(y), buffer}
}
func NewChannelChangeTypeConstraint(x, y ssa.Value) Constraint {
return &ChannelChangeTypeConstraint{NewConstraint(y), x}
}
func (c *MakeChannelConstraint) Operands() []ssa.Value { return []ssa.Value{c.Buffer} }
func (c *ChannelChangeTypeConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
func (c *MakeChannelConstraint) String() string {
return fmt.Sprintf("%s = make(chan, %s)", c.Y().Name(), c.Buffer.Name())
}
func (c *ChannelChangeTypeConstraint) String() string {
return fmt.Sprintf("%s = changetype(%s)", c.Y().Name(), c.X.Name())
}
func (c *MakeChannelConstraint) Eval(g *Graph) Range {
i, ok := g.Range(c.Buffer).(IntInterval)
if !ok {
return ChannelInterval{NewIntInterval(NewZ(0), PInfinity)}
}
if i.Lower.Sign() == -1 {
i.Lower = NewZ(0)
}
return ChannelInterval{i}
}
func (c *ChannelChangeTypeConstraint) Eval(g *Graph) Range { return g.Range(c.X) }

View File

@ -0,0 +1,476 @@
package vrp
import (
"fmt"
"go/token"
"go/types"
"math/big"
"honnef.co/go/tools/ssa"
)
type Zs []Z
func (zs Zs) Len() int {
return len(zs)
}
func (zs Zs) Less(i int, j int) bool {
return zs[i].Cmp(zs[j]) == -1
}
func (zs Zs) Swap(i int, j int) {
zs[i], zs[j] = zs[j], zs[i]
}
type Z struct {
infinity int8
integer *big.Int
}
func NewZ(n int64) Z {
return NewBigZ(big.NewInt(n))
}
func NewBigZ(n *big.Int) Z {
return Z{integer: n}
}
func (z1 Z) Infinite() bool {
return z1.infinity != 0
}
func (z1 Z) Add(z2 Z) Z {
if z2.Sign() == -1 {
return z1.Sub(z2.Negate())
}
if z1 == NInfinity {
return NInfinity
}
if z1 == PInfinity {
return PInfinity
}
if z2 == PInfinity {
return PInfinity
}
if !z1.Infinite() && !z2.Infinite() {
n := &big.Int{}
n.Add(z1.integer, z2.integer)
return NewBigZ(n)
}
panic(fmt.Sprintf("%s + %s is not defined", z1, z2))
}
func (z1 Z) Sub(z2 Z) Z {
if z2.Sign() == -1 {
return z1.Add(z2.Negate())
}
if !z1.Infinite() && !z2.Infinite() {
n := &big.Int{}
n.Sub(z1.integer, z2.integer)
return NewBigZ(n)
}
if z1 != PInfinity && z2 == PInfinity {
return NInfinity
}
if z1.Infinite() && !z2.Infinite() {
return Z{infinity: z1.infinity}
}
if z1 == PInfinity && z2 == PInfinity {
return PInfinity
}
panic(fmt.Sprintf("%s - %s is not defined", z1, z2))
}
func (z1 Z) Mul(z2 Z) Z {
if (z1.integer != nil && z1.integer.Sign() == 0) ||
(z2.integer != nil && z2.integer.Sign() == 0) {
return NewBigZ(&big.Int{})
}
if z1.infinity != 0 || z2.infinity != 0 {
return Z{infinity: int8(z1.Sign() * z2.Sign())}
}
n := &big.Int{}
n.Mul(z1.integer, z2.integer)
return NewBigZ(n)
}
func (z1 Z) Negate() Z {
if z1.infinity == 1 {
return NInfinity
}
if z1.infinity == -1 {
return PInfinity
}
n := &big.Int{}
n.Neg(z1.integer)
return NewBigZ(n)
}
func (z1 Z) Sign() int {
if z1.infinity != 0 {
return int(z1.infinity)
}
return z1.integer.Sign()
}
func (z1 Z) String() string {
if z1 == NInfinity {
return "-∞"
}
if z1 == PInfinity {
return "∞"
}
return fmt.Sprintf("%d", z1.integer)
}
func (z1 Z) Cmp(z2 Z) int {
if z1.infinity == z2.infinity && z1.infinity != 0 {
return 0
}
if z1 == PInfinity {
return 1
}
if z1 == NInfinity {
return -1
}
if z2 == NInfinity {
return 1
}
if z2 == PInfinity {
return -1
}
return z1.integer.Cmp(z2.integer)
}
func MaxZ(zs ...Z) Z {
if len(zs) == 0 {
panic("Max called with no arguments")
}
if len(zs) == 1 {
return zs[0]
}
ret := zs[0]
for _, z := range zs[1:] {
if z.Cmp(ret) == 1 {
ret = z
}
}
return ret
}
func MinZ(zs ...Z) Z {
if len(zs) == 0 {
panic("Min called with no arguments")
}
if len(zs) == 1 {
return zs[0]
}
ret := zs[0]
for _, z := range zs[1:] {
if z.Cmp(ret) == -1 {
ret = z
}
}
return ret
}
var NInfinity = Z{infinity: -1}
var PInfinity = Z{infinity: 1}
var EmptyIntInterval = IntInterval{true, PInfinity, NInfinity}
func InfinityFor(v ssa.Value) IntInterval {
if b, ok := v.Type().Underlying().(*types.Basic); ok {
if (b.Info() & types.IsUnsigned) != 0 {
return NewIntInterval(NewZ(0), PInfinity)
}
}
return NewIntInterval(NInfinity, PInfinity)
}
type IntInterval struct {
known bool
Lower Z
Upper Z
}
func NewIntInterval(l, u Z) IntInterval {
if u.Cmp(l) == -1 {
return EmptyIntInterval
}
return IntInterval{known: true, Lower: l, Upper: u}
}
func (i IntInterval) IsKnown() bool {
return i.known
}
func (i IntInterval) Empty() bool {
return i.Lower == PInfinity && i.Upper == NInfinity
}
func (i IntInterval) IsMaxRange() bool {
return i.Lower == NInfinity && i.Upper == PInfinity
}
func (i1 IntInterval) Intersection(i2 IntInterval) IntInterval {
if !i1.IsKnown() {
return i2
}
if !i2.IsKnown() {
return i1
}
if i1.Empty() || i2.Empty() {
return EmptyIntInterval
}
i3 := NewIntInterval(MaxZ(i1.Lower, i2.Lower), MinZ(i1.Upper, i2.Upper))
if i3.Lower.Cmp(i3.Upper) == 1 {
return EmptyIntInterval
}
return i3
}
func (i1 IntInterval) Union(other Range) Range {
i2, ok := other.(IntInterval)
if !ok {
i2 = EmptyIntInterval
}
if i1.Empty() || !i1.IsKnown() {
return i2
}
if i2.Empty() || !i2.IsKnown() {
return i1
}
return NewIntInterval(MinZ(i1.Lower, i2.Lower), MaxZ(i1.Upper, i2.Upper))
}
func (i1 IntInterval) Add(i2 IntInterval) IntInterval {
if i1.Empty() || i2.Empty() {
return EmptyIntInterval
}
l1, u1, l2, u2 := i1.Lower, i1.Upper, i2.Lower, i2.Upper
return NewIntInterval(l1.Add(l2), u1.Add(u2))
}
func (i1 IntInterval) Sub(i2 IntInterval) IntInterval {
if i1.Empty() || i2.Empty() {
return EmptyIntInterval
}
l1, u1, l2, u2 := i1.Lower, i1.Upper, i2.Lower, i2.Upper
return NewIntInterval(l1.Sub(u2), u1.Sub(l2))
}
func (i1 IntInterval) Mul(i2 IntInterval) IntInterval {
if i1.Empty() || i2.Empty() {
return EmptyIntInterval
}
x1, x2 := i1.Lower, i1.Upper
y1, y2 := i2.Lower, i2.Upper
return NewIntInterval(
MinZ(x1.Mul(y1), x1.Mul(y2), x2.Mul(y1), x2.Mul(y2)),
MaxZ(x1.Mul(y1), x1.Mul(y2), x2.Mul(y1), x2.Mul(y2)),
)
}
func (i1 IntInterval) String() string {
if !i1.IsKnown() {
return "[⊥, ⊥]"
}
if i1.Empty() {
return "{}"
}
return fmt.Sprintf("[%s, %s]", i1.Lower, i1.Upper)
}
type IntArithmeticConstraint struct {
aConstraint
A ssa.Value
B ssa.Value
Op token.Token
Fn func(IntInterval, IntInterval) IntInterval
}
type IntAddConstraint struct{ *IntArithmeticConstraint }
type IntSubConstraint struct{ *IntArithmeticConstraint }
type IntMulConstraint struct{ *IntArithmeticConstraint }
type IntConversionConstraint struct {
aConstraint
X ssa.Value
}
type IntIntersectionConstraint struct {
aConstraint
ranges Ranges
A ssa.Value
B ssa.Value
Op token.Token
I IntInterval
resolved bool
}
type IntIntervalConstraint struct {
aConstraint
I IntInterval
}
func NewIntArithmeticConstraint(a, b, y ssa.Value, op token.Token, fn func(IntInterval, IntInterval) IntInterval) *IntArithmeticConstraint {
return &IntArithmeticConstraint{NewConstraint(y), a, b, op, fn}
}
func NewIntAddConstraint(a, b, y ssa.Value) Constraint {
return &IntAddConstraint{NewIntArithmeticConstraint(a, b, y, token.ADD, IntInterval.Add)}
}
func NewIntSubConstraint(a, b, y ssa.Value) Constraint {
return &IntSubConstraint{NewIntArithmeticConstraint(a, b, y, token.SUB, IntInterval.Sub)}
}
func NewIntMulConstraint(a, b, y ssa.Value) Constraint {
return &IntMulConstraint{NewIntArithmeticConstraint(a, b, y, token.MUL, IntInterval.Mul)}
}
func NewIntConversionConstraint(x, y ssa.Value) Constraint {
return &IntConversionConstraint{NewConstraint(y), x}
}
func NewIntIntersectionConstraint(a, b ssa.Value, op token.Token, ranges Ranges, y ssa.Value) Constraint {
return &IntIntersectionConstraint{
aConstraint: NewConstraint(y),
ranges: ranges,
A: a,
B: b,
Op: op,
}
}
func NewIntIntervalConstraint(i IntInterval, y ssa.Value) Constraint {
return &IntIntervalConstraint{NewConstraint(y), i}
}
func (c *IntArithmeticConstraint) Operands() []ssa.Value { return []ssa.Value{c.A, c.B} }
func (c *IntConversionConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
func (c *IntIntersectionConstraint) Operands() []ssa.Value { return []ssa.Value{c.A} }
func (s *IntIntervalConstraint) Operands() []ssa.Value { return nil }
func (c *IntArithmeticConstraint) String() string {
return fmt.Sprintf("%s = %s %s %s", c.Y().Name(), c.A.Name(), c.Op, c.B.Name())
}
func (c *IntConversionConstraint) String() string {
return fmt.Sprintf("%s = %s(%s)", c.Y().Name(), c.Y().Type(), c.X.Name())
}
func (c *IntIntersectionConstraint) String() string {
return fmt.Sprintf("%s = %s %s %s (%t branch)", c.Y().Name(), c.A.Name(), c.Op, c.B.Name(), c.Y().(*ssa.Sigma).Branch)
}
func (c *IntIntervalConstraint) String() string { return fmt.Sprintf("%s = %s", c.Y().Name(), c.I) }
func (c *IntArithmeticConstraint) Eval(g *Graph) Range {
i1, i2 := g.Range(c.A).(IntInterval), g.Range(c.B).(IntInterval)
if !i1.IsKnown() || !i2.IsKnown() {
return IntInterval{}
}
return c.Fn(i1, i2)
}
func (c *IntConversionConstraint) Eval(g *Graph) Range {
s := &types.StdSizes{
// XXX is it okay to assume the largest word size, or do we
// need to be platform specific?
WordSize: 8,
MaxAlign: 1,
}
fromI := g.Range(c.X).(IntInterval)
toI := g.Range(c.Y()).(IntInterval)
fromT := c.X.Type().Underlying().(*types.Basic)
toT := c.Y().Type().Underlying().(*types.Basic)
fromB := s.Sizeof(c.X.Type())
toB := s.Sizeof(c.Y().Type())
if !fromI.IsKnown() {
return toI
}
if !toI.IsKnown() {
return fromI
}
// uint<N> -> sint/uint<M>, M > N: [max(0, l1), min(2**N-1, u2)]
if (fromT.Info()&types.IsUnsigned != 0) &&
toB > fromB {
n := big.NewInt(1)
n.Lsh(n, uint(fromB*8))
n.Sub(n, big.NewInt(1))
return NewIntInterval(
MaxZ(NewZ(0), fromI.Lower),
MinZ(NewBigZ(n), toI.Upper),
)
}
// sint<N> -> sint<M>, M > N; [max(-∞, l1), min(2**N-1, u2)]
if (fromT.Info()&types.IsUnsigned == 0) &&
(toT.Info()&types.IsUnsigned == 0) &&
toB > fromB {
n := big.NewInt(1)
n.Lsh(n, uint(fromB*8))
n.Sub(n, big.NewInt(1))
return NewIntInterval(
MaxZ(NInfinity, fromI.Lower),
MinZ(NewBigZ(n), toI.Upper),
)
}
return fromI
}
func (c *IntIntersectionConstraint) Eval(g *Graph) Range {
xi := g.Range(c.A).(IntInterval)
if !xi.IsKnown() {
return c.I
}
return xi.Intersection(c.I)
}
func (c *IntIntervalConstraint) Eval(*Graph) Range { return c.I }
func (c *IntIntersectionConstraint) Futures() []ssa.Value {
return []ssa.Value{c.B}
}
func (c *IntIntersectionConstraint) Resolve() {
r, ok := c.ranges[c.B].(IntInterval)
if !ok {
c.I = InfinityFor(c.Y())
return
}
switch c.Op {
case token.EQL:
c.I = r
case token.GTR:
c.I = NewIntInterval(r.Lower.Add(NewZ(1)), PInfinity)
case token.GEQ:
c.I = NewIntInterval(r.Lower, PInfinity)
case token.LSS:
// TODO(dh): do we need 0 instead of NInfinity for uints?
c.I = NewIntInterval(NInfinity, r.Upper.Sub(NewZ(1)))
case token.LEQ:
c.I = NewIntInterval(NInfinity, r.Upper)
case token.NEQ:
c.I = InfinityFor(c.Y())
default:
panic("unsupported op " + c.Op.String())
}
}
func (c *IntIntersectionConstraint) IsKnown() bool {
return c.I.IsKnown()
}
func (c *IntIntersectionConstraint) MarkUnresolved() {
c.resolved = false
}
func (c *IntIntersectionConstraint) MarkResolved() {
c.resolved = true
}
func (c *IntIntersectionConstraint) IsResolved() bool {
return c.resolved
}

View File

@ -0,0 +1,273 @@
package vrp
// TODO(dh): most of the constraints have implementations identical to
// that of strings. Consider reusing them.
import (
"fmt"
"go/types"
"honnef.co/go/tools/ssa"
)
type SliceInterval struct {
Length IntInterval
}
func (s SliceInterval) Union(other Range) Range {
i, ok := other.(SliceInterval)
if !ok {
i = SliceInterval{EmptyIntInterval}
}
if s.Length.Empty() || !s.Length.IsKnown() {
return i
}
if i.Length.Empty() || !i.Length.IsKnown() {
return s
}
return SliceInterval{
Length: s.Length.Union(i.Length).(IntInterval),
}
}
func (s SliceInterval) String() string { return s.Length.String() }
func (s SliceInterval) IsKnown() bool { return s.Length.IsKnown() }
type SliceAppendConstraint struct {
aConstraint
A ssa.Value
B ssa.Value
}
type SliceSliceConstraint struct {
aConstraint
X ssa.Value
Lower ssa.Value
Upper ssa.Value
}
type ArraySliceConstraint struct {
aConstraint
X ssa.Value
Lower ssa.Value
Upper ssa.Value
}
type SliceIntersectionConstraint struct {
aConstraint
X ssa.Value
I IntInterval
}
type SliceLengthConstraint struct {
aConstraint
X ssa.Value
}
type MakeSliceConstraint struct {
aConstraint
Size ssa.Value
}
type SliceIntervalConstraint struct {
aConstraint
I IntInterval
}
func NewSliceAppendConstraint(a, b, y ssa.Value) Constraint {
return &SliceAppendConstraint{NewConstraint(y), a, b}
}
func NewSliceSliceConstraint(x, lower, upper, y ssa.Value) Constraint {
return &SliceSliceConstraint{NewConstraint(y), x, lower, upper}
}
func NewArraySliceConstraint(x, lower, upper, y ssa.Value) Constraint {
return &ArraySliceConstraint{NewConstraint(y), x, lower, upper}
}
func NewSliceIntersectionConstraint(x ssa.Value, i IntInterval, y ssa.Value) Constraint {
return &SliceIntersectionConstraint{NewConstraint(y), x, i}
}
func NewSliceLengthConstraint(x, y ssa.Value) Constraint {
return &SliceLengthConstraint{NewConstraint(y), x}
}
func NewMakeSliceConstraint(size, y ssa.Value) Constraint {
return &MakeSliceConstraint{NewConstraint(y), size}
}
func NewSliceIntervalConstraint(i IntInterval, y ssa.Value) Constraint {
return &SliceIntervalConstraint{NewConstraint(y), i}
}
func (c *SliceAppendConstraint) Operands() []ssa.Value { return []ssa.Value{c.A, c.B} }
func (c *SliceSliceConstraint) Operands() []ssa.Value {
ops := []ssa.Value{c.X}
if c.Lower != nil {
ops = append(ops, c.Lower)
}
if c.Upper != nil {
ops = append(ops, c.Upper)
}
return ops
}
func (c *ArraySliceConstraint) Operands() []ssa.Value {
ops := []ssa.Value{c.X}
if c.Lower != nil {
ops = append(ops, c.Lower)
}
if c.Upper != nil {
ops = append(ops, c.Upper)
}
return ops
}
func (c *SliceIntersectionConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
func (c *SliceLengthConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
func (c *MakeSliceConstraint) Operands() []ssa.Value { return []ssa.Value{c.Size} }
func (s *SliceIntervalConstraint) Operands() []ssa.Value { return nil }
func (c *SliceAppendConstraint) String() string {
return fmt.Sprintf("%s = append(%s, %s)", c.Y().Name(), c.A.Name(), c.B.Name())
}
func (c *SliceSliceConstraint) String() string {
var lname, uname string
if c.Lower != nil {
lname = c.Lower.Name()
}
if c.Upper != nil {
uname = c.Upper.Name()
}
return fmt.Sprintf("%s[%s:%s]", c.X.Name(), lname, uname)
}
func (c *ArraySliceConstraint) String() string {
var lname, uname string
if c.Lower != nil {
lname = c.Lower.Name()
}
if c.Upper != nil {
uname = c.Upper.Name()
}
return fmt.Sprintf("%s[%s:%s]", c.X.Name(), lname, uname)
}
func (c *SliceIntersectionConstraint) String() string {
return fmt.Sprintf("%s = %s.%t ⊓ %s", c.Y().Name(), c.X.Name(), c.Y().(*ssa.Sigma).Branch, c.I)
}
func (c *SliceLengthConstraint) String() string {
return fmt.Sprintf("%s = len(%s)", c.Y().Name(), c.X.Name())
}
func (c *MakeSliceConstraint) String() string {
return fmt.Sprintf("%s = make(slice, %s)", c.Y().Name(), c.Size.Name())
}
func (c *SliceIntervalConstraint) String() string { return fmt.Sprintf("%s = %s", c.Y().Name(), c.I) }
func (c *SliceAppendConstraint) Eval(g *Graph) Range {
l1 := g.Range(c.A).(SliceInterval).Length
var l2 IntInterval
switch r := g.Range(c.B).(type) {
case SliceInterval:
l2 = r.Length
case StringInterval:
l2 = r.Length
default:
return SliceInterval{}
}
if !l1.IsKnown() || !l2.IsKnown() {
return SliceInterval{}
}
return SliceInterval{
Length: l1.Add(l2),
}
}
func (c *SliceSliceConstraint) Eval(g *Graph) Range {
lr := NewIntInterval(NewZ(0), NewZ(0))
if c.Lower != nil {
lr = g.Range(c.Lower).(IntInterval)
}
ur := g.Range(c.X).(SliceInterval).Length
if c.Upper != nil {
ur = g.Range(c.Upper).(IntInterval)
}
if !lr.IsKnown() || !ur.IsKnown() {
return SliceInterval{}
}
ls := []Z{
ur.Lower.Sub(lr.Lower),
ur.Upper.Sub(lr.Lower),
ur.Lower.Sub(lr.Upper),
ur.Upper.Sub(lr.Upper),
}
// TODO(dh): if we don't truncate lengths to 0 we might be able to
// easily detect slices with high < low. we'd need to treat -∞
// specially, though.
for i, l := range ls {
if l.Sign() == -1 {
ls[i] = NewZ(0)
}
}
return SliceInterval{
Length: NewIntInterval(MinZ(ls...), MaxZ(ls...)),
}
}
func (c *ArraySliceConstraint) Eval(g *Graph) Range {
lr := NewIntInterval(NewZ(0), NewZ(0))
if c.Lower != nil {
lr = g.Range(c.Lower).(IntInterval)
}
var l int64
switch typ := c.X.Type().(type) {
case *types.Array:
l = typ.Len()
case *types.Pointer:
l = typ.Elem().(*types.Array).Len()
}
ur := NewIntInterval(NewZ(l), NewZ(l))
if c.Upper != nil {
ur = g.Range(c.Upper).(IntInterval)
}
if !lr.IsKnown() || !ur.IsKnown() {
return SliceInterval{}
}
ls := []Z{
ur.Lower.Sub(lr.Lower),
ur.Upper.Sub(lr.Lower),
ur.Lower.Sub(lr.Upper),
ur.Upper.Sub(lr.Upper),
}
// TODO(dh): if we don't truncate lengths to 0 we might be able to
// easily detect slices with high < low. we'd need to treat -∞
// specially, though.
for i, l := range ls {
if l.Sign() == -1 {
ls[i] = NewZ(0)
}
}
return SliceInterval{
Length: NewIntInterval(MinZ(ls...), MaxZ(ls...)),
}
}
func (c *SliceIntersectionConstraint) Eval(g *Graph) Range {
xi := g.Range(c.X).(SliceInterval)
if !xi.IsKnown() {
return c.I
}
return SliceInterval{
Length: xi.Length.Intersection(c.I),
}
}
func (c *SliceLengthConstraint) Eval(g *Graph) Range {
i := g.Range(c.X).(SliceInterval).Length
if !i.IsKnown() {
return NewIntInterval(NewZ(0), PInfinity)
}
return i
}
func (c *MakeSliceConstraint) Eval(g *Graph) Range {
i, ok := g.Range(c.Size).(IntInterval)
if !ok {
return SliceInterval{NewIntInterval(NewZ(0), PInfinity)}
}
if i.Lower.Sign() == -1 {
i.Lower = NewZ(0)
}
return SliceInterval{i}
}
func (c *SliceIntervalConstraint) Eval(*Graph) Range { return SliceInterval{c.I} }

View File

@ -0,0 +1,258 @@
package vrp
import (
"fmt"
"go/token"
"go/types"
"honnef.co/go/tools/ssa"
)
type StringInterval struct {
Length IntInterval
}
func (s StringInterval) Union(other Range) Range {
i, ok := other.(StringInterval)
if !ok {
i = StringInterval{EmptyIntInterval}
}
if s.Length.Empty() || !s.Length.IsKnown() {
return i
}
if i.Length.Empty() || !i.Length.IsKnown() {
return s
}
return StringInterval{
Length: s.Length.Union(i.Length).(IntInterval),
}
}
func (s StringInterval) String() string {
return s.Length.String()
}
func (s StringInterval) IsKnown() bool {
return s.Length.IsKnown()
}
type StringSliceConstraint struct {
aConstraint
X ssa.Value
Lower ssa.Value
Upper ssa.Value
}
type StringIntersectionConstraint struct {
aConstraint
ranges Ranges
A ssa.Value
B ssa.Value
Op token.Token
I IntInterval
resolved bool
}
type StringConcatConstraint struct {
aConstraint
A ssa.Value
B ssa.Value
}
type StringLengthConstraint struct {
aConstraint
X ssa.Value
}
type StringIntervalConstraint struct {
aConstraint
I IntInterval
}
func NewStringSliceConstraint(x, lower, upper, y ssa.Value) Constraint {
return &StringSliceConstraint{NewConstraint(y), x, lower, upper}
}
func NewStringIntersectionConstraint(a, b ssa.Value, op token.Token, ranges Ranges, y ssa.Value) Constraint {
return &StringIntersectionConstraint{
aConstraint: NewConstraint(y),
ranges: ranges,
A: a,
B: b,
Op: op,
}
}
func NewStringConcatConstraint(a, b, y ssa.Value) Constraint {
return &StringConcatConstraint{NewConstraint(y), a, b}
}
func NewStringLengthConstraint(x ssa.Value, y ssa.Value) Constraint {
return &StringLengthConstraint{NewConstraint(y), x}
}
func NewStringIntervalConstraint(i IntInterval, y ssa.Value) Constraint {
return &StringIntervalConstraint{NewConstraint(y), i}
}
func (c *StringSliceConstraint) Operands() []ssa.Value {
vs := []ssa.Value{c.X}
if c.Lower != nil {
vs = append(vs, c.Lower)
}
if c.Upper != nil {
vs = append(vs, c.Upper)
}
return vs
}
func (c *StringIntersectionConstraint) Operands() []ssa.Value { return []ssa.Value{c.A} }
func (c StringConcatConstraint) Operands() []ssa.Value { return []ssa.Value{c.A, c.B} }
func (c *StringLengthConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
func (s *StringIntervalConstraint) Operands() []ssa.Value { return nil }
func (c *StringSliceConstraint) String() string {
var lname, uname string
if c.Lower != nil {
lname = c.Lower.Name()
}
if c.Upper != nil {
uname = c.Upper.Name()
}
return fmt.Sprintf("%s[%s:%s]", c.X.Name(), lname, uname)
}
func (c *StringIntersectionConstraint) String() string {
return fmt.Sprintf("%s = %s %s %s (%t branch)", c.Y().Name(), c.A.Name(), c.Op, c.B.Name(), c.Y().(*ssa.Sigma).Branch)
}
func (c StringConcatConstraint) String() string {
return fmt.Sprintf("%s = %s + %s", c.Y().Name(), c.A.Name(), c.B.Name())
}
func (c *StringLengthConstraint) String() string {
return fmt.Sprintf("%s = len(%s)", c.Y().Name(), c.X.Name())
}
func (c *StringIntervalConstraint) String() string { return fmt.Sprintf("%s = %s", c.Y().Name(), c.I) }
func (c *StringSliceConstraint) Eval(g *Graph) Range {
lr := NewIntInterval(NewZ(0), NewZ(0))
if c.Lower != nil {
lr = g.Range(c.Lower).(IntInterval)
}
ur := g.Range(c.X).(StringInterval).Length
if c.Upper != nil {
ur = g.Range(c.Upper).(IntInterval)
}
if !lr.IsKnown() || !ur.IsKnown() {
return StringInterval{}
}
ls := []Z{
ur.Lower.Sub(lr.Lower),
ur.Upper.Sub(lr.Lower),
ur.Lower.Sub(lr.Upper),
ur.Upper.Sub(lr.Upper),
}
// TODO(dh): if we don't truncate lengths to 0 we might be able to
// easily detect slices with high < low. we'd need to treat -∞
// specially, though.
for i, l := range ls {
if l.Sign() == -1 {
ls[i] = NewZ(0)
}
}
return StringInterval{
Length: NewIntInterval(MinZ(ls...), MaxZ(ls...)),
}
}
func (c *StringIntersectionConstraint) Eval(g *Graph) Range {
var l IntInterval
switch r := g.Range(c.A).(type) {
case StringInterval:
l = r.Length
case IntInterval:
l = r
}
if !l.IsKnown() {
return StringInterval{c.I}
}
return StringInterval{
Length: l.Intersection(c.I),
}
}
func (c StringConcatConstraint) Eval(g *Graph) Range {
i1, i2 := g.Range(c.A).(StringInterval), g.Range(c.B).(StringInterval)
if !i1.Length.IsKnown() || !i2.Length.IsKnown() {
return StringInterval{}
}
return StringInterval{
Length: i1.Length.Add(i2.Length),
}
}
func (c *StringLengthConstraint) Eval(g *Graph) Range {
i := g.Range(c.X).(StringInterval).Length
if !i.IsKnown() {
return NewIntInterval(NewZ(0), PInfinity)
}
return i
}
func (c *StringIntervalConstraint) Eval(*Graph) Range { return StringInterval{c.I} }
func (c *StringIntersectionConstraint) Futures() []ssa.Value {
return []ssa.Value{c.B}
}
func (c *StringIntersectionConstraint) Resolve() {
if (c.A.Type().Underlying().(*types.Basic).Info() & types.IsString) != 0 {
// comparing two strings
r, ok := c.ranges[c.B].(StringInterval)
if !ok {
c.I = NewIntInterval(NewZ(0), PInfinity)
return
}
switch c.Op {
case token.EQL:
c.I = r.Length
case token.GTR, token.GEQ:
c.I = NewIntInterval(r.Length.Lower, PInfinity)
case token.LSS, token.LEQ:
c.I = NewIntInterval(NewZ(0), r.Length.Upper)
case token.NEQ:
default:
panic("unsupported op " + c.Op.String())
}
} else {
r, ok := c.ranges[c.B].(IntInterval)
if !ok {
c.I = NewIntInterval(NewZ(0), PInfinity)
return
}
// comparing two lengths
switch c.Op {
case token.EQL:
c.I = r
case token.GTR:
c.I = NewIntInterval(r.Lower.Add(NewZ(1)), PInfinity)
case token.GEQ:
c.I = NewIntInterval(r.Lower, PInfinity)
case token.LSS:
c.I = NewIntInterval(NInfinity, r.Upper.Sub(NewZ(1)))
case token.LEQ:
c.I = NewIntInterval(NInfinity, r.Upper)
case token.NEQ:
default:
panic("unsupported op " + c.Op.String())
}
}
}
func (c *StringIntersectionConstraint) IsKnown() bool {
return c.I.IsKnown()
}
func (c *StringIntersectionConstraint) MarkUnresolved() {
c.resolved = false
}
func (c *StringIntersectionConstraint) MarkResolved() {
c.resolved = true
}
func (c *StringIntersectionConstraint) IsResolved() bool {
return c.resolved
}

File diff suppressed because it is too large Load Diff