From f41935d53ff6271e8c2a9022f41b99ccee9b634b Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 15 Sep 2016 13:45:06 +0200 Subject: Allow range sized arrays --- prog/mutation.go | 18 ++++++++++++++---- prog/rand.go | 11 +++++++++-- sys/README.md | 2 +- sys/align.go | 2 +- sys/decl.go | 20 +++++++++++++------- sysgen/sysgen.go | 28 +++++++++++++++------------- 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 b359748ea..859113474 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 a447948bc..a87b51d91 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 { -- cgit mrf-deployment