Skip to content

Commit e8dd2c6

Browse files
committed
prog: add concept of "special pointers"
Currently we only generate either valid user-space pointers or NULL. Extend NULL to a set of special pointers that we will use in programs. All targets now contain 3 special values: - NULL - 0xfffffffffffffff (invalid kernel pointer) - 0x999999999999999 (non-canonical address) Each target can add additional special pointers on top of this. Also generate NULL/special pointers for non-opt ptr's. This restriction was always too restrictive. We may want to generate them with very low probability, but we do want to generate them. Also change pointers to NULL/special during mutation (but still not in the opposite direction).
1 parent 6ba5fe3 commit e8dd2c6

File tree

13 files changed

+161
-67
lines changed

13 files changed

+161
-67
lines changed

prog/analysis.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (s *state) analyzeImpl(c *Call, resources bool) {
5757
switch a := arg.(type) {
5858
case *PointerArg:
5959
switch {
60-
case a.IsNull():
60+
case a.IsSpecial():
6161
case a.VmaSize != 0:
6262
s.va.noteAlloc(a.Address/s.target.PageSize, a.VmaSize/s.target.PageSize)
6363
default:
@@ -273,7 +273,7 @@ func extractArgSignal(arg Arg, callID, flags int, inf *CallInfo, resources map[*
273273
}
274274
case *PointerArg:
275275
flags <<= 1
276-
if a.IsNull() {
276+
if a.IsSpecial() {
277277
flags |= 1
278278
}
279279
}

prog/encoding.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ func (a *ConstArg) serialize(ctx *serializer) {
8585
}
8686

8787
func (a *PointerArg) serialize(ctx *serializer) {
88-
if a.IsNull() {
89-
ctx.printf("0x0")
88+
if a.IsSpecial() {
89+
ctx.printf("0x%x", a.Address)
9090
return
9191
}
9292
target := ctx.target
@@ -345,10 +345,8 @@ func (target *Target) parseArgInt(typ Type, p *parser) (Arg, error) {
345345
case *ResourceType:
346346
return MakeResultArg(typ, nil, v), nil
347347
case *PtrType, *VmaType:
348-
if typ.Optional() {
349-
return MakeNullPointerArg(typ), nil
350-
}
351-
return typ.makeDefaultArg(), nil
348+
index := -v % uint64(len(target.SpecialPointers))
349+
return MakeSpecialPointerArg(typ, index), nil
352350
default:
353351
eatExcessive(p, true)
354352
return typ.makeDefaultArg(), nil

prog/encoding_test.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"sort"
1313
"strings"
1414
"testing"
15+
16+
"github.com/google/go-cmp/cmp"
1517
)
1618

1719
func setToArray(s map[string]struct{}) []string {
@@ -160,7 +162,7 @@ func TestDeserialize(t *testing.T) {
160162
},
161163
{
162164
input: `test$excessive_fields1(0x0)`,
163-
output: `test$excessive_fields1(&(0x7f0000000000))`,
165+
output: `test$excessive_fields1(0x0)`,
164166
},
165167
{
166168
input: `test$excessive_fields1(r0)`,
@@ -206,6 +208,26 @@ func TestDeserialize(t *testing.T) {
206208
input: `test$excessive_fields1(&(0x7f0000000000)=0x0)`,
207209
output: `test$excessive_fields1(&(0x7f0000000000))`,
208210
},
211+
{
212+
input: `test$excessive_fields1(0x0)`,
213+
output: `test$excessive_fields1(0x0)`,
214+
},
215+
{
216+
input: `test$excessive_fields1(0xffffffffffffffff)`,
217+
output: `test$excessive_fields1(0xffffffffffffffff)`,
218+
},
219+
{
220+
input: `test$excessive_fields1(0xfffffffffffffffe)`,
221+
output: `test$excessive_fields1(0xfffffffffffffffe)`,
222+
},
223+
{
224+
input: `test$excessive_fields1(0xfffffffffffffffd)`,
225+
output: `test$excessive_fields1(0x0)`,
226+
},
227+
{
228+
input: `test$excessive_fields1(0xfffffffffffffffc)`,
229+
output: `test$excessive_fields1(0xffffffffffffffff)`,
230+
},
209231
}
210232
buf := make([]byte, ExecBufferSize)
211233
for _, test := range tests {
@@ -276,8 +298,18 @@ func TestSerializeDeserializeRandom(t *testing.T) {
276298
})
277299
ok, n0, n1 := testSerializeDeserialize(t, p0, data0, data1)
278300
if ok {
279-
t.Fatal("flaky?")
301+
t.Log("flaky?")
302+
}
303+
decoded0, err := target.DeserializeExec(data0[:n0])
304+
if err != nil {
305+
t.Fatal(err)
306+
}
307+
decoded1, err := target.DeserializeExec(data1[:n1])
308+
if err != nil {
309+
t.Fatal(err)
280310
}
311+
diff := cmp.Diff(decoded0, decoded1)
312+
t.Logf("decoded diff: %v", diff)
281313
t.Fatalf("was: %q\ngot: %q\nprogram:\n%s",
282314
data0[:n0], data1[:n1], p0.Serialize())
283315
}

prog/encodingexec.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,6 @@ func (w *execContext) serializeCall(c *Call) {
100100
w.writeCopyout(c)
101101
}
102102

103-
func (target *Target) PhysicalAddr(arg *PointerArg) uint64 {
104-
if arg.IsNull() {
105-
return 0
106-
}
107-
return target.DataOffset + arg.Address
108-
}
109-
110103
type execContext struct {
111104
target *Target
112105
buf []byte

prog/encodingexec_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,30 @@ func TestSerializeForExec(t *testing.T) {
403403
},
404404
nil,
405405
},
406+
{
407+
"test$excessive_fields1(0x0)",
408+
[]uint64{
409+
callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x0,
410+
execInstrEOF,
411+
},
412+
nil,
413+
},
414+
{
415+
"test$excessive_fields1(0xffffffffffffffff)",
416+
[]uint64{
417+
callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0xffffffffffffffff,
418+
execInstrEOF,
419+
},
420+
nil,
421+
},
422+
{
423+
"test$excessive_fields1(0xfffffffffffffffe)",
424+
[]uint64{
425+
callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x9999999999999999,
426+
execInstrEOF,
427+
},
428+
nil,
429+
},
406430
}
407431

408432
buf := make([]byte, ExecBufferSize)

prog/mutation.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,13 @@ func (t *ArrayType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*
308308

309309
func (t *PtrType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) {
310310
a := arg.(*PointerArg)
311+
if r.oneOf(1000) {
312+
removeArg(a.Res)
313+
index := r.rand(len(r.target.SpecialPointers))
314+
newArg := MakeSpecialPointerArg(t, index)
315+
replaceArg(arg, newArg)
316+
return
317+
}
311318
newArg := r.allocAddr(s, t, a.Res.Size(), a.Res)
312319
replaceArg(arg, newArg)
313320
return
@@ -401,7 +408,7 @@ func (ma *mutationArgs) collectArg(arg Arg, ctx *ArgCtx) {
401408
return // string const
402409
}
403410
case *PtrType:
404-
if arg.(*PointerArg).IsNull() {
411+
if arg.(*PointerArg).IsSpecial() {
405412
// TODO: we ought to mutate this, but we don't have code for this yet.
406413
return
407414
}

prog/prog.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,29 @@ func MakeVmaPointerArg(t Type, addr, size uint64) *PointerArg {
106106
}
107107
}
108108

109-
func MakeNullPointerArg(t Type) *PointerArg {
109+
func MakeSpecialPointerArg(t Type, index uint64) *PointerArg {
110+
if index >= maxSpecialPointers {
111+
panic("bad special pointer index")
112+
}
110113
return &PointerArg{
111114
ArgCommon: ArgCommon{typ: t},
115+
Address: -index,
112116
}
113117
}
114118

115119
func (arg *PointerArg) Size() uint64 {
116120
return arg.typ.Size()
117121
}
118122

119-
func (arg *PointerArg) IsNull() bool {
120-
return arg.Address == 0 && arg.VmaSize == 0 && arg.Res == nil
123+
func (arg *PointerArg) IsSpecial() bool {
124+
return arg.VmaSize == 0 && arg.Res == nil && -arg.Address < maxSpecialPointers
125+
}
126+
127+
func (target *Target) PhysicalAddr(arg *PointerArg) uint64 {
128+
if arg.IsSpecial() {
129+
return target.SpecialPointers[-arg.Address]
130+
}
131+
return target.DataOffset + arg.Address
121132
}
122133

123134
// Used for BufferType.
@@ -262,17 +273,12 @@ func (arg *ResultArg) Size() uint64 {
262273

263274
// Returns inner arg for pointer args.
264275
func InnerArg(arg Arg) Arg {
265-
if t, ok := arg.Type().(*PtrType); ok {
266-
if a, ok := arg.(*PointerArg); ok {
267-
if a.Res == nil {
268-
if !t.Optional() {
269-
panic(fmt.Sprintf("non-optional pointer is nil\narg: %+v\ntype: %+v", a, t))
270-
}
271-
return nil
272-
}
273-
return InnerArg(a.Res)
276+
if _, ok := arg.Type().(*PtrType); ok {
277+
res := arg.(*PointerArg).Res
278+
if res == nil {
279+
return nil
274280
}
275-
return nil // *ConstArg.
281+
return InnerArg(res)
276282
}
277283
return arg // Not a pointer.
278284
}

prog/rand.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A
515515
}
516516
}()
517517
if r.recDepth[name] >= 3 {
518-
return MakeNullPointerArg(typ), nil
518+
return MakeSpecialPointerArg(typ, 0), nil
519519
}
520520
}
521521
}
@@ -673,6 +673,10 @@ func (a *UnionType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
673673
}
674674

675675
func (a *PtrType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
676+
if r.oneOf(1000) {
677+
index := r.rand(len(r.target.SpecialPointers))
678+
return MakeSpecialPointerArg(a, index), nil
679+
}
676680
inner, calls := r.generateArg(s, a.Type)
677681
arg = r.allocAddr(s, a, inner.Size(), inner)
678682
return arg, calls

prog/target.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ type Target struct {
4444
// Used as fallback when string type does not have own dictionary.
4545
StringDictionary []string
4646

47+
// Additional special invalid pointer values besides NULL to use.
48+
SpecialPointers []uint64
49+
4750
// Filled by prog package:
4851
init sync.Once
4952
initArch func(target *Target)
@@ -55,6 +58,8 @@ type Target struct {
5558
any anyTypes
5659
}
5760

61+
const maxSpecialPointers = 16
62+
5863
var targets = make(map[string]*Target)
5964

6065
func RegisterTarget(target *Target, initArch func(target *Target)) {
@@ -101,6 +106,15 @@ func (target *Target) lazyInit() {
101106
target.initTarget()
102107
target.initArch(target)
103108
target.ConstMap = nil // currently used only by initArch
109+
// Give these 2 known addresses fixed positions and prepend target-specific ones at the end.
110+
target.SpecialPointers = append([]uint64{
111+
0x0000000000000000, // NULL pointer (keep this first because code uses special index=0 as NULL)
112+
0xffffffffffffffff, // unmapped kernel address (keep second because serialized value will match actual pointer value)
113+
0x9999999999999999, // non-canonical address
114+
}, target.SpecialPointers...)
115+
if len(target.SpecialPointers) > maxSpecialPointers {
116+
panic("too many special pointers")
117+
}
104118
}
105119

106120
func (target *Target) initTarget() {

prog/types.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,12 @@ func (t *VmaType) String() string {
321321
}
322322

323323
func (t *VmaType) makeDefaultArg() Arg {
324-
return MakeNullPointerArg(t)
324+
return MakeSpecialPointerArg(t, 0)
325325
}
326326

327327
func (t *VmaType) isDefaultArg(arg Arg) bool {
328-
return arg.(*PointerArg).IsNull()
328+
a := arg.(*PointerArg)
329+
return a.IsSpecial() && a.Address == 0
329330
}
330331

331332
type BufferKind int
@@ -450,17 +451,17 @@ func (t *PtrType) String() string {
450451

451452
func (t *PtrType) makeDefaultArg() Arg {
452453
if t.Optional() {
453-
return MakeNullPointerArg(t)
454+
return MakeSpecialPointerArg(t, 0)
454455
}
455456
return MakePointerArg(t, 0, t.Type.makeDefaultArg())
456457
}
457458

458459
func (t *PtrType) isDefaultArg(arg Arg) bool {
459460
a := arg.(*PointerArg)
460461
if t.Optional() {
461-
return a.IsNull()
462+
return a.IsSpecial() && a.Address == 0
462463
}
463-
return a.Address == 0 && isDefault(a.Res)
464+
return a.Address == 0 && a.Res != nil && isDefault(a.Res)
464465
}
465466

466467
type StructType struct {

0 commit comments

Comments
 (0)