mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-24 03:49:45 +00:00
pkg/compiler: support non-zero-terminated strings
Add stringnoz type.
This commit is contained in:
parent
c77c36d5fa
commit
3661e26e74
@ -39,6 +39,9 @@ rest of the type-options are type-specific:
|
||||
either a string value in quotes for constant strings (e.g. "foo"),
|
||||
or a reference to string flags,
|
||||
optionally followed by a buffer size (string values will be padded with \x00 to that size)
|
||||
"stringnoz": a non-zero-terminated memory buffer (no pointer indirection implied), type-options:
|
||||
either a string value in quotes for constant strings (e.g. "foo"),
|
||||
or a reference to string flags,
|
||||
"filename": a file/link/dir name, no pointer indirection implied, in most cases you want `ptr[in, filename]`
|
||||
"fileoff": offset within a file
|
||||
"len": length of another field (for array it is number of elements), type-options:
|
||||
|
11
pkg/compiler/testdata/all.txt
vendored
11
pkg/compiler/testdata/all.txt
vendored
@ -5,6 +5,17 @@ foo$0(a int8)
|
||||
foo$1(a int8[C1:C2])
|
||||
foo$2() ptr[out, array[int32]]
|
||||
|
||||
strings {
|
||||
f1 string
|
||||
f2 string["foo"]
|
||||
f3 string["foo", 10]
|
||||
f4 string[string_flags, 10]
|
||||
f5 stringnoz
|
||||
f6 stringnoz["foo"]
|
||||
} [packed]
|
||||
|
||||
string_flags = "foo", "barbaz"
|
||||
|
||||
# Proc type.
|
||||
|
||||
proc_struct1 {
|
||||
|
6
pkg/compiler/testdata/errors.txt
vendored
6
pkg/compiler/testdata/errors.txt
vendored
@ -111,6 +111,8 @@ foo$53(a proc[20, 10, opt])
|
||||
foo$54(a ptr[in, string["foo", C1]])
|
||||
foo$55(a int8[opt[int8]]) ### opt can't have arguments
|
||||
foo$56(a void) ### void can't be syscall argument
|
||||
foo$57(a ptr[in, stringnoz["foo", 10]]) ### fixed-size string can't be non-zero-terminated
|
||||
foo$58(a ptr[in, stringnoz[sf2, 10]]) ### fixed-size string can't be non-zero-terminated
|
||||
|
||||
opt { ### struct uses reserved name opt
|
||||
f1 int32
|
||||
@ -188,8 +190,8 @@ typestruct {
|
||||
}
|
||||
|
||||
type type0 int8
|
||||
type type0 int8 ### type type0 redeclared, previously declared as type alias at errors.txt:190:6
|
||||
resource type0[int32] ### type type0 redeclared, previously declared as type alias at errors.txt:190:6
|
||||
type type0 int8 ### type type0 redeclared, previously declared as type alias at errors.txt:192:6
|
||||
resource type0[int32] ### type type0 redeclared, previously declared as type alias at errors.txt:192:6
|
||||
type0 = 0, 1
|
||||
type type1 type1 ### type instantiation loop: type1 -> type1
|
||||
type type2 int8:4 ### unexpected ':', only struct fields can be bitfields
|
||||
|
@ -441,19 +441,20 @@ var typeBuffer = &typeDesc{
|
||||
}
|
||||
|
||||
var typeString = &typeDesc{
|
||||
Names: []string{"string"},
|
||||
Names: []string{"string", "stringnoz"},
|
||||
CanBeTypedef: true,
|
||||
OptArgs: 2,
|
||||
Args: []namedArg{{"literal or flags", typeArgStringFlags}, {"size", typeArgInt}},
|
||||
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
|
||||
if t.Ident == "stringnoz" && len(args) > 1 {
|
||||
comp.error(args[0].Pos, "fixed-size string can't be non-zero-terminated")
|
||||
}
|
||||
},
|
||||
CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
|
||||
if len(args) > 1 {
|
||||
size := args[1].Value
|
||||
vals := []string{args[0].String}
|
||||
if args[0].Ident != "" {
|
||||
vals = genStrArray(comp.strFlags[args[0].Ident].Values)
|
||||
}
|
||||
vals := comp.genStrings(t, args)
|
||||
for _, s := range vals {
|
||||
s += "\x00"
|
||||
if uint64(len(s)) > size {
|
||||
comp.error(args[0].Pos, "string value %q exceeds buffer length %v",
|
||||
s, size)
|
||||
@ -462,52 +463,67 @@ var typeString = &typeDesc{
|
||||
}
|
||||
},
|
||||
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
|
||||
return comp.stringSize(args) == 0
|
||||
return comp.stringSize(t, args) == 0
|
||||
},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
subkind := ""
|
||||
var vals []string
|
||||
if len(args) > 0 {
|
||||
if args[0].String != "" {
|
||||
vals = append(vals, args[0].String)
|
||||
} else {
|
||||
subkind = args[0].Ident
|
||||
vals = genStrArray(comp.strFlags[subkind].Values)
|
||||
}
|
||||
if len(args) > 0 && args[0].Ident != "" {
|
||||
subkind = args[0].Ident
|
||||
}
|
||||
var size uint64
|
||||
if len(args) > 1 {
|
||||
size = args[1].Value
|
||||
}
|
||||
for i, s := range vals {
|
||||
s += "\x00"
|
||||
for uint64(len(s)) < size {
|
||||
s += "\x00"
|
||||
}
|
||||
vals[i] = s
|
||||
}
|
||||
base.TypeSize = comp.stringSize(args)
|
||||
vals := comp.genStrings(t, args)
|
||||
base.TypeSize = comp.stringSize(t, args)
|
||||
return &prog.BufferType{
|
||||
TypeCommon: base.TypeCommon,
|
||||
Kind: prog.BufferString,
|
||||
SubKind: subkind,
|
||||
Values: vals,
|
||||
NoZ: t.Ident == "stringnoz",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string {
|
||||
var vals []string
|
||||
if len(args) > 0 {
|
||||
if args[0].String != "" {
|
||||
vals = append(vals, args[0].String)
|
||||
} else {
|
||||
vals = genStrArray(comp.strFlags[args[0].Ident].Values)
|
||||
}
|
||||
}
|
||||
if t.Ident == "stringnoz" {
|
||||
return vals
|
||||
}
|
||||
var size uint64
|
||||
if len(args) > 1 {
|
||||
size = args[1].Value
|
||||
}
|
||||
for i, s := range vals {
|
||||
s += "\x00"
|
||||
for uint64(len(s)) < size {
|
||||
s += "\x00"
|
||||
}
|
||||
vals[i] = s
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
// stringSize returns static string size, or 0 if it is variable length.
|
||||
func (comp *compiler) stringSize(args []*ast.Type) uint64 {
|
||||
func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return 0 // a random string
|
||||
case 1:
|
||||
var z uint64
|
||||
if t.Ident == "string" {
|
||||
z = 1
|
||||
}
|
||||
if args[0].String != "" {
|
||||
return uint64(len(args[0].String)) + 1 // string constant
|
||||
return uint64(len(args[0].String)) + z // string constant
|
||||
}
|
||||
var size uint64
|
||||
for _, s := range comp.strFlags[args[0].Ident].Values {
|
||||
s1 := uint64(len(s.Value)) + 1
|
||||
s1 := uint64(len(s.Value)) + z
|
||||
if size != 0 && size != s1 {
|
||||
return 0 // strings of different lengths
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
|
||||
}
|
||||
a.data = mutateData(r, data, minLen, maxLen)
|
||||
} else {
|
||||
a.data = r.randString(s, t.Values, t.Dir())
|
||||
a.data = r.randString(s, t)
|
||||
}
|
||||
case BufferFilename:
|
||||
a.data = []byte(r.filename(s))
|
||||
|
21
prog/rand.go
21
prog/rand.go
@ -182,22 +182,13 @@ func (r *randGen) filename(s *state) string {
|
||||
return files[r.Intn(len(files))]
|
||||
}
|
||||
|
||||
func (r *randGen) randString(s *state, vals []string, dir Dir) []byte {
|
||||
data := r.randStringImpl(s, vals)
|
||||
if dir == DirOut {
|
||||
for i := range data {
|
||||
data[i] = 0
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (r *randGen) randStringImpl(s *state, vals []string) []byte {
|
||||
if len(vals) != 0 {
|
||||
return []byte(vals[r.Intn(len(vals))])
|
||||
func (r *randGen) randString(s *state, t *BufferType) []byte {
|
||||
if len(t.Values) != 0 {
|
||||
return []byte(t.Values[r.Intn(len(t.Values))])
|
||||
}
|
||||
if len(s.strings) != 0 && r.bin() {
|
||||
// Return an existing string.
|
||||
// TODO(dvyukov): make s.strings indexed by string SubKind.
|
||||
strings := make([]string, 0, len(s.strings))
|
||||
for s := range s.strings {
|
||||
strings = append(strings, s)
|
||||
@ -220,7 +211,7 @@ func (r *randGen) randStringImpl(s *state, vals []string) []byte {
|
||||
buf.Write([]byte{byte(r.Intn(256))})
|
||||
}
|
||||
}
|
||||
if !r.oneOf(100) {
|
||||
if r.oneOf(100) == t.NoZ {
|
||||
buf.Write([]byte{0})
|
||||
}
|
||||
return buf.Bytes()
|
||||
@ -602,7 +593,7 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
|
||||
}
|
||||
return MakeDataArg(a, data), nil
|
||||
case BufferString:
|
||||
data := r.randString(s, a.Values, a.Dir())
|
||||
data := r.randString(s, a)
|
||||
if a.Dir() == DirOut {
|
||||
return MakeOutDataArg(a, uint64(len(data))), nil
|
||||
}
|
||||
|
@ -227,6 +227,7 @@ type BufferType struct {
|
||||
Text TextKind // for BufferText
|
||||
SubKind string
|
||||
Values []string // possible values for BufferString kind
|
||||
NoZ bool // non-zero terminated BufferString
|
||||
}
|
||||
|
||||
type ArrayKind int
|
||||
|
Loading…
Reference in New Issue
Block a user