mirror of
https://github.com/reactos/syzkaller.git
synced 2025-03-03 17:17:39 +00:00
pkg/compiler: support negative integers
Currently we have to use 0xffffffffffffffff to represent -1, and we can't express e.g. -20:20 int range. Support negative consts to fix both problems.
This commit is contained in:
parent
f25e577041
commit
710eefe85a
@ -78,7 +78,8 @@ flagname = "\"" literal "\"" ["," "\"" literal "\""]*
|
||||
|
||||
## Ints
|
||||
|
||||
`int8`, `int16`, `int32` and `int64` denote an integer of the corresponding size. `intptr` denotes a pointer-sized integer, i.e. C `long` type.
|
||||
`int8`, `int16`, `int32` and `int64` denote an integer of the corresponding size.
|
||||
`intptr` denotes a pointer-sized integer, i.e. C `long` type.
|
||||
|
||||
By appending `be` suffix (e.g. `int16be`) integers become big-endian.
|
||||
|
||||
@ -260,7 +261,7 @@ hex literals, as `'`-surrounded char literals, or as symbolic constants
|
||||
extracted from kernel headers or defined by `define` directives. For example:
|
||||
|
||||
```
|
||||
foo(a const[10])
|
||||
foo(a const[10], b const[-10])
|
||||
foo(a const[0xabcd])
|
||||
foo(a int8['a':'z'])
|
||||
foo(a const[PATH_MAX])
|
||||
|
@ -169,19 +169,20 @@ func (n *String) Info() (Pos, string, string) {
|
||||
return n.Pos, tok2str[tokString], ""
|
||||
}
|
||||
|
||||
type intFmt int
|
||||
type IntFmt int
|
||||
|
||||
const (
|
||||
intFmtDec intFmt = iota
|
||||
intFmtHex
|
||||
intFmtChar
|
||||
IntFmtDec IntFmt = iota
|
||||
IntFmtNeg
|
||||
IntFmtHex
|
||||
IntFmtChar
|
||||
)
|
||||
|
||||
type Int struct {
|
||||
Pos Pos
|
||||
// Only one of Value, Ident, CExpr is filled.
|
||||
Value uint64
|
||||
valueFmt intFmt
|
||||
ValueFmt IntFmt
|
||||
Ident string
|
||||
CExpr string
|
||||
}
|
||||
@ -194,7 +195,7 @@ type Type struct {
|
||||
Pos Pos
|
||||
// Only one of Value, Ident, String is filled.
|
||||
Value uint64
|
||||
valueFmt intFmt
|
||||
ValueFmt IntFmt
|
||||
Ident string
|
||||
String string
|
||||
HasString bool
|
||||
@ -202,7 +203,7 @@ type Type struct {
|
||||
HasColon bool
|
||||
Pos2 Pos
|
||||
Value2 uint64
|
||||
value2Fmt intFmt
|
||||
Value2Fmt IntFmt
|
||||
Ident2 string
|
||||
Args []*Type
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ func (n *Int) Clone() Node {
|
||||
return &Int{
|
||||
Pos: n.Pos,
|
||||
Value: n.Value,
|
||||
valueFmt: n.valueFmt,
|
||||
ValueFmt: n.ValueFmt,
|
||||
Ident: n.Ident,
|
||||
CExpr: n.CExpr,
|
||||
}
|
||||
@ -179,14 +179,14 @@ func (n *Type) Clone() Node {
|
||||
return &Type{
|
||||
Pos: n.Pos,
|
||||
Value: n.Value,
|
||||
valueFmt: n.valueFmt,
|
||||
ValueFmt: n.ValueFmt,
|
||||
Ident: n.Ident,
|
||||
String: n.String,
|
||||
HasString: n.HasString,
|
||||
HasColon: n.HasColon,
|
||||
Pos2: n.Pos2,
|
||||
Value2: n.Value2,
|
||||
value2Fmt: n.value2Fmt,
|
||||
Value2Fmt: n.Value2Fmt,
|
||||
Ident2: n.Ident2,
|
||||
Args: args,
|
||||
}
|
||||
|
@ -35,6 +35,21 @@ func SerializeNode(n Node) string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func FormatInt(v uint64, format IntFmt) string {
|
||||
switch format {
|
||||
case IntFmtDec:
|
||||
return fmt.Sprint(v)
|
||||
case IntFmtNeg:
|
||||
return fmt.Sprint(int64(v))
|
||||
case IntFmtHex:
|
||||
return fmt.Sprintf("0x%x", v)
|
||||
case IntFmtChar:
|
||||
return fmt.Sprintf("'%c'", v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown int format %v", format))
|
||||
}
|
||||
}
|
||||
|
||||
type serializer interface {
|
||||
serialize(w io.Writer)
|
||||
}
|
||||
@ -159,14 +174,14 @@ func fmtType(t *Type) string {
|
||||
case t.HasString:
|
||||
v = fmt.Sprintf("\"%v\"", t.String)
|
||||
default:
|
||||
v = fmtIntValue(t.Value, t.valueFmt)
|
||||
v = FormatInt(t.Value, t.ValueFmt)
|
||||
}
|
||||
if t.HasColon {
|
||||
switch {
|
||||
case t.Ident2 != "":
|
||||
v += fmt.Sprintf(":%v", t.Ident2)
|
||||
default:
|
||||
v += fmt.Sprintf(":%v", fmtIntValue(t.Value2, t.value2Fmt))
|
||||
v += fmt.Sprintf(":%v", FormatInt(t.Value2, t.Value2Fmt))
|
||||
}
|
||||
}
|
||||
v += fmtTypeList(t.Args)
|
||||
@ -206,20 +221,7 @@ func fmtInt(i *Int) string {
|
||||
case i.CExpr != "":
|
||||
return fmt.Sprintf("%v", i.CExpr)
|
||||
default:
|
||||
return fmtIntValue(i.Value, i.valueFmt)
|
||||
}
|
||||
}
|
||||
|
||||
func fmtIntValue(v uint64, format intFmt) string {
|
||||
switch format {
|
||||
case intFmtDec:
|
||||
return fmt.Sprint(v)
|
||||
case intFmtHex:
|
||||
return fmt.Sprintf("0x%x", v)
|
||||
case intFmtChar:
|
||||
return fmt.Sprintf("'%c'", v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown int format %v", format))
|
||||
return FormatInt(i.Value, i.ValueFmt)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,7 +413,7 @@ func (p *parser) parseType() *Type {
|
||||
switch p.tok {
|
||||
case tokInt:
|
||||
allowColon = true
|
||||
arg.Value, arg.valueFmt = p.parseIntValue()
|
||||
arg.Value, arg.ValueFmt = p.parseIntValue()
|
||||
case tokIdent:
|
||||
allowColon = true
|
||||
arg.Ident = p.lit
|
||||
@ -429,7 +429,7 @@ func (p *parser) parseType() *Type {
|
||||
arg.Pos2 = p.pos
|
||||
switch p.tok {
|
||||
case tokInt:
|
||||
arg.Value2, arg.value2Fmt = p.parseIntValue()
|
||||
arg.Value2, arg.Value2Fmt = p.parseIntValue()
|
||||
case tokIdent:
|
||||
arg.Ident2 = p.lit
|
||||
default:
|
||||
@ -479,7 +479,7 @@ func (p *parser) parseInt() *Int {
|
||||
}
|
||||
switch p.tok {
|
||||
case tokInt:
|
||||
i.Value, i.valueFmt = p.parseIntValue()
|
||||
i.Value, i.ValueFmt = p.parseIntValue()
|
||||
case tokIdent:
|
||||
i.Ident = p.lit
|
||||
default:
|
||||
@ -489,16 +489,19 @@ func (p *parser) parseInt() *Int {
|
||||
return i
|
||||
}
|
||||
|
||||
func (p *parser) parseIntValue() (uint64, intFmt) {
|
||||
func (p *parser) parseIntValue() (uint64, IntFmt) {
|
||||
if p.lit[0] == '\'' {
|
||||
return uint64(p.lit[1]), intFmtChar
|
||||
return uint64(p.lit[1]), IntFmtChar
|
||||
}
|
||||
if v, err := strconv.ParseUint(p.lit, 10, 64); err == nil {
|
||||
return v, intFmtDec
|
||||
return v, IntFmtDec
|
||||
}
|
||||
if v, err := strconv.ParseInt(p.lit, 10, 64); err == nil {
|
||||
return uint64(v), IntFmtNeg
|
||||
}
|
||||
if len(p.lit) > 2 && p.lit[0] == '0' && p.lit[1] == 'x' {
|
||||
if v, err := strconv.ParseUint(p.lit[2:], 16, 64); err == nil {
|
||||
return v, intFmtHex
|
||||
return v, IntFmtHex
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("scanner returned bad integer %q", p.lit))
|
||||
|
@ -150,7 +150,7 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
|
||||
case s.ch == '"' || s.ch == '<':
|
||||
tok = tokString
|
||||
lit = s.scanStr(pos)
|
||||
case s.ch >= '0' && s.ch <= '9':
|
||||
case s.ch >= '0' && s.ch <= '9' || s.ch == '-':
|
||||
tok = tokInt
|
||||
lit = s.scanInt(pos)
|
||||
case s.ch == '\'':
|
||||
@ -211,25 +211,26 @@ func (s *scanner) scanStr(pos Pos) string {
|
||||
func (s *scanner) scanInt(pos Pos) string {
|
||||
for s.ch >= '0' && s.ch <= '9' ||
|
||||
s.ch >= 'a' && s.ch <= 'f' ||
|
||||
s.ch >= 'A' && s.ch <= 'F' || s.ch == 'x' {
|
||||
s.ch >= 'A' && s.ch <= 'F' ||
|
||||
s.ch == 'x' || s.ch == '-' {
|
||||
s.next()
|
||||
}
|
||||
lit := string(s.data[pos.Off:s.off])
|
||||
bad := false
|
||||
if _, err := strconv.ParseUint(lit, 10, 64); err != nil {
|
||||
if len(lit) > 2 && lit[0] == '0' && lit[1] == 'x' {
|
||||
if _, err := strconv.ParseUint(lit[2:], 16, 64); err != nil {
|
||||
bad = true
|
||||
}
|
||||
} else {
|
||||
bad = true
|
||||
if _, err := strconv.ParseUint(lit, 10, 64); err == nil {
|
||||
return lit
|
||||
}
|
||||
if len(lit) > 1 && lit[0] == '-' {
|
||||
if _, err := strconv.ParseInt(lit, 10, 64); err == nil {
|
||||
return lit
|
||||
}
|
||||
}
|
||||
if bad {
|
||||
s.Error(pos, fmt.Sprintf("bad integer %q", lit))
|
||||
lit = "0"
|
||||
if len(lit) > 2 && lit[0] == '0' && lit[1] == 'x' {
|
||||
if _, err := strconv.ParseUint(lit[2:], 16, 64); err == nil {
|
||||
return lit
|
||||
}
|
||||
}
|
||||
return lit
|
||||
s.Error(pos, fmt.Sprintf("bad integer %q", lit))
|
||||
return "0"
|
||||
}
|
||||
|
||||
func (s *scanner) scanChar(pos Pos) string {
|
||||
|
1
pkg/ast/testdata/all.txt
vendored
1
pkg/ast/testdata/all.txt
vendored
@ -12,6 +12,7 @@ int_flags = 0, "foo" ### unexpected string, expecting int, identifier
|
||||
int_flags2 = ' ### char literal is not terminated
|
||||
int_flags3 = 'a ### char literal is not terminated
|
||||
int_flags3 = 'a, 1 ### char literal is not terminated
|
||||
int_flags4 = 1, -2- ### bad integer "-2-"
|
||||
|
||||
str_flags0 = "foo", "bar"
|
||||
str_flags1 = "non terminated ### string literal is not terminated
|
||||
|
6
pkg/compiler/testdata/all.txt
vendored
6
pkg/compiler/testdata/all.txt
vendored
@ -7,7 +7,9 @@ foo$2(a ptr[out, array[int32]])
|
||||
foo$3(a union_arg)
|
||||
foo$4() r0
|
||||
foo$5(a int8['a':'z'])
|
||||
foo$6(a ptr[in, strings])
|
||||
foo$6(a int8[-20:-10])
|
||||
foo$7(a int8[-20:20])
|
||||
foo$8(a ptr[in, strings])
|
||||
|
||||
resource r0[intptr]
|
||||
|
||||
@ -38,7 +40,7 @@ strings {
|
||||
|
||||
string_flags1 = "foo", "barbaz"
|
||||
string_flags2 = ""
|
||||
int_flags = 0, 1
|
||||
int_flags = 0, 1, 0xabc, 'x', -11
|
||||
_ = 1, 2
|
||||
_ = C1, C2
|
||||
|
||||
|
1
pkg/compiler/testdata/errors.txt
vendored
1
pkg/compiler/testdata/errors.txt
vendored
@ -329,4 +329,5 @@ foo$fmt4(a ptr[in, fmt[dec, int8:3]]) ### unexpected ':', only struct fields ca
|
||||
|
||||
struct$fmt0 {
|
||||
f0 fmt[dec, int8:3] ### unexpected ':', only struct fields can be bitfields
|
||||
f1 int32:-1 ### bitfield of size 18446744073709551615 is too large for base type of size 32
|
||||
}
|
||||
|
5
pkg/compiler/testdata/errors2.txt
vendored
5
pkg/compiler/testdata/errors2.txt
vendored
@ -217,6 +217,11 @@ foo$507(a ptr[in, array[int32, 0:0]]) ### arrays of size 0 are not supported
|
||||
foo$508(a ptr[in, string["foo", 3]]) ### string value "foo\x00" exceeds buffer length 3
|
||||
foo$509(a int8['b':'a']) ### bad int range [98:97]
|
||||
foo$510(a type500)
|
||||
foo$511(a int32[-10:-20]) ### bad int range [18446744073709551606:18446744073709551596]
|
||||
foo$512(a ptr[in, array[int8, -2:-1]]) ### bad size range [18446744073709551614:18446744073709551615]
|
||||
foo$513(a ptr[in, array[int8, -2:2]]) ### bad size range [18446744073709551614:2]
|
||||
foo$514(a vma[-2:2]) ### bad size range [18446744073709551614:2]
|
||||
foo$515(a ptr[in, proc[1, -10, int64]]) ### values starting from 1 with step 18446744073709551606 overflow base type for 32 procs
|
||||
|
||||
type type500 proc[C1, 8, int8] ### values starting from 1 with step 8 overflow base type for 32 procs
|
||||
type type501 int8 ### unused type type501
|
||||
|
@ -68,7 +68,7 @@ var typeInt = &typeDesc{
|
||||
AllowColon: true,
|
||||
ResourceBase: true,
|
||||
OptArgs: 1,
|
||||
Args: []namedArg{{Name: "range", Type: typeArgRange}},
|
||||
Args: []namedArg{{Name: "range", Type: typeArgIntRange}},
|
||||
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
|
||||
typeArgBase.Type.Check(comp, t)
|
||||
},
|
||||
@ -128,7 +128,7 @@ var typeArray = &typeDesc{
|
||||
CanBeTypedef: true,
|
||||
CantBeOpt: true,
|
||||
OptArgs: 1,
|
||||
Args: []namedArg{{Name: "type", Type: typeArgType}, {Name: "size", Type: typeArgRange}},
|
||||
Args: []namedArg{{Name: "type", Type: typeArgType}, {Name: "size", Type: typeArgSizeRange}},
|
||||
CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
|
||||
if len(args) > 1 && args[1].Value == 0 && args[1].Value2 == 0 {
|
||||
comp.error(args[1].Pos, "arrays of size 0 are not supported")
|
||||
@ -290,7 +290,7 @@ var typeVMA = &typeDesc{
|
||||
Names: []string{"vma"},
|
||||
CanBeArgRet: canBeArg,
|
||||
OptArgs: 1,
|
||||
Args: []namedArg{{Name: "size range", Type: typeArgRange}},
|
||||
Args: []namedArg{{Name: "size range", Type: typeArgSizeRange}},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
begin, end := uint64(0), uint64(0)
|
||||
if len(args) > 0 {
|
||||
@ -367,14 +367,16 @@ var typeProc = &typeDesc{
|
||||
return
|
||||
}
|
||||
size := base.TypeSize * 8
|
||||
if size != 64 {
|
||||
const maxPids = 32 // executor knows about this constant (MAX_PIDS)
|
||||
if start >= 1<<size {
|
||||
comp.error(args[0].Pos, "values starting from %v overflow base type", start)
|
||||
} else if start+maxPids*perProc > 1<<size {
|
||||
comp.error(args[0].Pos, "values starting from %v with step %v overflow base type for %v procs",
|
||||
start, perProc, maxPids)
|
||||
}
|
||||
max := uint64(1) << size
|
||||
if size == 64 {
|
||||
max = ^uint64(0)
|
||||
}
|
||||
const maxPids = 32 // executor knows about this constant (MAX_PIDS)
|
||||
if start >= max {
|
||||
comp.error(args[0].Pos, "values starting from %v overflow base type", start)
|
||||
} else if perProc > (max-start)/maxPids {
|
||||
comp.error(args[0].Pos, "values starting from %v with step %v overflow base type for %v procs",
|
||||
start, perProc, maxPids)
|
||||
}
|
||||
},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
@ -763,15 +765,31 @@ var typeArgInt = &typeArg{
|
||||
Kind: kindInt,
|
||||
}
|
||||
|
||||
var typeArgRange = &typeArg{
|
||||
var typeArgIntRange = &typeArg{
|
||||
Kind: kindInt,
|
||||
AllowColon: true,
|
||||
CheckConsts: func(comp *compiler, t *ast.Type) {
|
||||
if !t.HasColon {
|
||||
t.Value2 = t.Value
|
||||
t.Value2Fmt = t.ValueFmt
|
||||
}
|
||||
if t.Value2-t.Value > 1<<64-1<<32 {
|
||||
comp.error(t.Pos, "bad int range [%v:%v]", t.Value, t.Value2)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Size of array and vma's.
|
||||
var typeArgSizeRange = &typeArg{
|
||||
Kind: kindInt,
|
||||
AllowColon: true,
|
||||
CheckConsts: func(comp *compiler, t *ast.Type) {
|
||||
if !t.HasColon {
|
||||
t.Value2 = t.Value
|
||||
}
|
||||
if t.Value > t.Value2 {
|
||||
comp.error(t.Pos, "bad int range [%v:%v]", t.Value, t.Value2)
|
||||
const maxVal = 1e6
|
||||
if t.Value > t.Value2 || t.Value > maxVal || t.Value2 > maxVal {
|
||||
comp.error(t.Pos, "bad size range [%v:%v]", t.Value, t.Value2)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user