aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-01-23 11:05:51 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-01-23 11:05:51 +0100
commit14d1e424b6a582d021c73c88e1f0c5f0962ecc9d (patch)
tree0fdc71b6e0de2576ae330f145a51f9c016ad81a2 /pkg
parentde3e24c4b6cd0136618ce74eb025a15d4834c082 (diff)
pkg/compiler: allow use of empty strings
This comes up in several contexts in netfilter.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/ast/ast.go9
-rw-r--r--pkg/ast/clone.go1
-rw-r--r--pkg/ast/format.go2
-rw-r--r--pkg/ast/parser.go1
-rw-r--r--pkg/ast/scanner.go6
-rw-r--r--pkg/ast/testdata/all.txt4
-rw-r--r--pkg/compiler/check.go2
-rw-r--r--pkg/compiler/testdata/all.txt11
-rw-r--r--pkg/compiler/types.go24
9 files changed, 36 insertions, 24 deletions
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go
index 08703ba33..f7d5b8b32 100644
--- a/pkg/ast/ast.go
+++ b/pkg/ast/ast.go
@@ -185,10 +185,11 @@ func (n *Int) Info() (Pos, string, string) {
type Type struct {
Pos Pos
// Only one of Value, Ident, String is filled.
- Value uint64
- ValueHex bool
- Ident string
- String string
+ Value uint64
+ ValueHex bool
+ Ident string
+ String string
+ HasString bool
// Part after COLON (for ranges and bitfields).
HasColon bool
Pos2 Pos
diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go
index b915c1f33..b754b7650 100644
--- a/pkg/ast/clone.go
+++ b/pkg/ast/clone.go
@@ -182,6 +182,7 @@ func (n *Type) Clone() Node {
ValueHex: n.ValueHex,
Ident: n.Ident,
String: n.String,
+ HasString: n.HasString,
HasColon: n.HasColon,
Pos2: n.Pos2,
Value2: n.Value2,
diff --git a/pkg/ast/format.go b/pkg/ast/format.go
index c1dd3a624..a7e0f568f 100644
--- a/pkg/ast/format.go
+++ b/pkg/ast/format.go
@@ -152,7 +152,7 @@ func fmtType(t *Type) string {
switch {
case t.Ident != "":
v = t.Ident
- case t.String != "":
+ case t.HasString:
v = fmt.Sprintf("\"%v\"", t.String)
default:
v = fmtIntValue(t.Value, t.ValueHex)
diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go
index bd5650ad5..a7cfdbf02 100644
--- a/pkg/ast/parser.go
+++ b/pkg/ast/parser.go
@@ -419,6 +419,7 @@ func (p *parser) parseType() *Type {
arg.Ident = p.lit
case tokString:
arg.String = p.lit
+ arg.HasString = true
default:
p.expect(tokInt, tokIdent, tokString)
}
diff --git a/pkg/ast/scanner.go b/pkg/ast/scanner.go
index bd2171506..5ad5e5808 100644
--- a/pkg/ast/scanner.go
+++ b/pkg/ast/scanner.go
@@ -177,12 +177,6 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
break
}
}
- if lit == "" {
- // Currently unsupported because with the current Type representation
- // it would not be possible to understand if it is an empty string
- // or a 0 integer.
- s.Error(pos, "empty string literals are not supported")
- }
s.next()
case s.ch >= '0' && s.ch <= '9':
tok = tokInt
diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt
index d4452b34f..ede11a88a 100644
--- a/pkg/ast/testdata/all.txt
+++ b/pkg/ast/testdata/all.txt
@@ -25,10 +25,10 @@ define FOO `bar ### C expression is not terminated
foo(x int32[1:2:3, opt]) ### unexpected ':', expecting ']'
s0 {
- f0 string[""] ### empty string literals are not supported
+ f0 string[""]
}
-sf0 = "", "1" ### empty string literals are not supported
+sf0 = "", "1"
include <linux/foo.h>
include "linux/foo.h"
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 5d741effc..eb2a13e19 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -802,7 +802,7 @@ func checkTypeKind(t *ast.Type, kind int) (unexpected string, expect string, ok
switch {
case kind == kindAny:
ok = true
- case t.String != "":
+ case t.HasString:
ok = kind == kindString
if !ok {
unexpected = fmt.Sprintf("string %q", t.String)
diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt
index 088e119ef..88e45dba4 100644
--- a/pkg/compiler/testdata/all.txt
+++ b/pkg/compiler/testdata/all.txt
@@ -9,12 +9,19 @@ strings {
f1 string
f2 string["foo"]
f3 string["foo", 10]
- f4 string[string_flags, 10]
+ f4 string[string_flags1, 10]
f5 stringnoz
f6 stringnoz["foo"]
+ f7 string[""]
+ f8 string["", 10]
+ f9 stringnoz[""]
+ f11 stringnoz[string_flags1]
+ f12 string[string_flags2]
+ f13 stringnoz[string_flags2]
} [packed]
-string_flags = "foo", "barbaz"
+string_flags1 = "foo", "barbaz"
+string_flags2 = ""
# Proc type.
diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go
index abfbc86fc..847849f2e 100644
--- a/pkg/compiler/types.go
+++ b/pkg/compiler/types.go
@@ -463,6 +463,9 @@ var typeString = &typeDesc{
}
},
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
+ return comp.stringSize(t, args) == varlenString
+ },
+ ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
return comp.stringSize(t, args) == 0
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
@@ -472,6 +475,9 @@ var typeString = &typeDesc{
}
vals := comp.genStrings(t, args)
base.TypeSize = comp.stringSize(t, args)
+ if base.TypeSize == varlenString {
+ base.TypeSize = 0
+ }
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: prog.BufferString,
@@ -485,7 +491,7 @@ var typeString = &typeDesc{
func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string {
var vals []string
if len(args) > 0 {
- if args[0].String != "" {
+ if args[0].HasString {
vals = append(vals, args[0].String)
} else {
vals = genStrArray(comp.strFlags[args[0].Ident].Values)
@@ -508,24 +514,26 @@ func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string {
return vals
}
-// stringSize returns static string size, or 0 if it is variable length.
+const varlenString = ^uint64(0)
+
+// stringSize returns static string size, or varlenString if it is variable length.
func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 {
switch len(args) {
case 0:
- return 0 // a random string
+ return varlenString // a random string
case 1:
var z uint64
if t.Ident == "string" {
z = 1
}
- if args[0].String != "" {
+ if args[0].HasString {
return uint64(len(args[0].String)) + z // string constant
}
- var size uint64
+ size := varlenString
for _, s := range comp.strFlags[args[0].Ident].Values {
s1 := uint64(len(s.Value)) + z
- if size != 0 && size != s1 {
- return 0 // strings of different lengths
+ if size != varlenString && size != s1 {
+ return varlenString // strings of different lengths
}
size = s1
}
@@ -539,7 +547,7 @@ func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 {
var typeArgStringFlags = &typeArg{
Check: func(comp *compiler, t *ast.Type) {
- if t.String == "" && t.Ident == "" {
+ if !t.HasString && t.Ident == "" {
comp.error(t.Pos, "unexpected int %v, string arg must be a string literal or string flags", t.Value)
return
}