aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-09-19 19:42:00 +0200
committerGitHub <noreply@github.com>2016-09-19 19:42:00 +0200
commitd18f8aa3669db8a7c2a9d235aa720bce8041f329 (patch)
tree56195536ec22d1414e7614403dc2757d9d76d4ca
parent0c97d70213a4fbc6d8d57626c18b603f2a281047 (diff)
parentf41935d53ff6271e8c2a9022f41b99ccee9b634b (diff)
Merge pull request #73 from xairy/ranged_arrays
Allow range sized arrays
-rw-r--r--prog/mutation.go18
-rw-r--r--prog/rand.go11
-rw-r--r--sys/README.md2
-rw-r--r--sys/align.go2
-rw-r--r--sys/decl.go20
-rw-r--r--sysgen/sysgen.go28
6 files changed, 53 insertions, 28 deletions
diff --git a/prog/mutation.go b/prog/mutation.go
index a00f64e43..a428d27cd 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -102,9 +102,19 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
filename := r.filename(s)
arg.Data = []byte(filename)
case sys.ArrayType:
- count := r.rand(6)
- if count == uintptr(len(arg.Inner)) {
- count++
+ count := uintptr(0)
+ switch a.Kind {
+ case sys.ArrayRandLen:
+ for count == uintptr(len(arg.Inner)) {
+ count = r.rand(6)
+ }
+ case sys.ArrayRangeLen:
+ if a.RangeBegin == a.RangeEnd {
+ panic("trying to mutate fixed length array")
+ }
+ for count == uintptr(len(arg.Inner)) {
+ count = r.randRange(int(a.RangeBegin), int(a.RangeEnd))
+ }
}
if count > uintptr(len(arg.Inner)) {
var calls []*Call
@@ -344,7 +354,7 @@ func mutationArgs(c *Call) (args, bases []*Arg, parents []*[]*Arg) {
// These special structs are mutated as a whole.
case sys.ArrayType:
// Don't mutate fixed-size arrays.
- if typ.Len != 0 {
+ if typ.Kind == sys.ArrayRangeLen && typ.RangeBegin == typ.RangeEnd {
return
}
case sys.LenType:
diff --git a/prog/rand.go b/prog/rand.go
index 97033b434..26063b626 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -26,6 +26,10 @@ func (r *randGen) rand(n int) uintptr {
return uintptr(r.Intn(n))
}
+func (r *randGen) randRange(begin int, end int) uintptr {
+ return uintptr(begin + r.Intn(end-begin+1))
+}
+
func (r *randGen) bin() bool {
return r.Intn(2) == 0
}
@@ -770,9 +774,12 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir, sizes map[stri
filename := r.filename(s)
return dataArg([]byte(filename)), nil, nil
case sys.ArrayType:
- count := a.Len
- if count == 0 {
+ count := uintptr(0)
+ switch a.Kind {
+ case sys.ArrayRandLen:
count = r.rand(6)
+ case sys.ArrayRangeLen:
+ count = r.randRange(int(a.RangeBegin), int(a.RangeEnd))
}
sz := constArg(count)
var inner []*Arg
diff --git a/sys/README.md b/sys/README.md
index 46c0a1a59..1355ad4f8 100644
--- a/sys/README.md
+++ b/sys/README.md
@@ -45,7 +45,7 @@ rest of the type-options are type-specific:
"ptr": a pointer to an object, type-options:
type of the object; direction (in/out/inout)
"array": a variable/fixed-length array, type-options:
- type of elements, optional size for fixed-length arrays
+ type of elements, optional size (fixed "5", or ranged "5:10", boundaries inclusive)
"intN"/"intptr": an integer without a particular meaning, type-options:
range of values (e.g. "5:10", or "-100:200", optional)
```
diff --git a/sys/align.go b/sys/align.go
index 5e67f6175..4c91c28be 100644
--- a/sys/align.go
+++ b/sys/align.go
@@ -64,7 +64,7 @@ func addAlignment(t *StructType) Type {
}
off += f.Size()
fields = append(fields, f)
- if at, ok := f.(ArrayType); ok && at.Len == 0 {
+ if at, ok := f.(ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
varLen = true
}
if varLen && i != len(t.Fields)-1 {
diff --git a/sys/decl.go b/sys/decl.go
index a9f9d1ad3..2cc8f22e5 100644
--- a/sys/decl.go
+++ b/sys/decl.go
@@ -236,21 +236,27 @@ func (t FilenameType) Align() uintptr {
return 1
}
+type ArrayKind int
+
+const (
+ ArrayRandLen ArrayKind = iota
+ ArrayRangeLen
+)
+
type ArrayType struct {
TypeCommon
- Type Type
- Len uintptr // 0 if variable-length, unused for now
+ Type Type
+ Kind ArrayKind
+ RangeBegin uintptr
+ RangeEnd uintptr
}
func (t ArrayType) Size() uintptr {
- if t.Len == 0 {
- return 0 // for trailing embed arrays
- }
- return t.Len * t.Type.Size()
+ panic("should not be called")
}
func (t ArrayType) Align() uintptr {
- return t.Type.Align()
+ panic("should not be called")
}
type PtrType struct {
diff --git a/sysgen/sysgen.go b/sysgen/sysgen.go
index 6d6a75bdc..e7a0fae00 100644
--- a/sysgen/sysgen.go
+++ b/sysgen/sysgen.go
@@ -490,21 +490,23 @@ func generateArg(
opt = false
fmt.Fprintf(out, "PtrType{%v, Dir: DirIn, Type: FilenameType{%v}}", commonHdr, common())
case "array":
- want := 1
- if len(a) == 2 {
- want = 2
- }
- if len(a) != want {
- failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
- }
- sz := "0"
- if len(a) == 2 {
- sz = a[1]
- if v, ok := consts[sz]; ok {
- sz = fmt.Sprint(v)
+ switch len(a) {
+ case 1:
+ fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], desc, consts))
+ case 2:
+ var begin, end uintptr
+ sz := a[1]
+ if _, err := fmt.Sscanf(sz, "%d:%d", &begin, &end); err != nil {
+ if v, ok := consts[sz]; ok {
+ sz = fmt.Sprint(v)
+ }
+ fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], desc, consts), sz, sz)
+ } else {
+ fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], desc, consts), begin, end)
}
+ default:
+ failf("wrong number of arguments for %v arg %v, want 1 or 2, got %v", typ, name, len(a))
}
- fmt.Fprintf(out, "ArrayType{%v, Type: %v, Len: %v}", common(), generateType(a[0], desc, consts), sz)
case "ptr":
canBeArg = true
if want := 2; len(a) != want {