func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, calls []*Call) { if r.inCreateResource { special := res.SpecialValues() return constArg(special[r.Intn(len(special))]), nil } r.inCreateResource = true defer func() { r.inCreateResource = false }() sk := res.Subkind if r.oneOf(50) { // Spoof resource subkind. all := res.SubKinds() sk = all[r.Intn(len(all))] } // Find calls that produce the necessary resources. metas0 := sys.ResourceConstructors(res.Kind, sk) // TODO: reduce priority of ResAny ctors if we have sk ctors. var metas []*sys.Call for _, meta := range metas0 { if s.ct == nil || s.ct.run[meta.ID] == nil { continue } metas = append(metas, meta) } if len(metas) == 0 { return constArg(res.Default()), nil } // Now we have a set of candidate calls that can create the necessary resource. for i := 0; i < 1e3; i++ { // Generate one of them. meta := metas[r.Intn(len(metas))] calls := r.generateParticularCall(s, meta) //assignTypeAndDir(calls[len(calls)-1]) s1 := newState(s.ct) s1.analyze(calls[len(calls)-1]) // Now see if we have what we want. var allres []*Arg for sk1, ress := range s1.resources[res.Kind] { if sk1 == sys.ResAny || sk == sys.ResAny || sk1 == sk { allres = append(allres, ress...) } } if len(allres) != 0 { // Bingo! arg := resultArg(allres[r.Intn(len(allres))]) return arg, calls } switch meta.Name { case "getgroups": // Returns groups in an array. default: panic(fmt.Sprintf("unexpected call failed to create a resource %v/%v: %v", res.Kind, sk, meta.Name)) } // Discard unsuccessful calls. for _, c := range calls { foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) { if arg.Kind == ArgResult { delete(arg.Res.Uses, arg) } }) } } // Generally we can loop several times, e.g. when we choose a call that returns // the resource in an array, but then generateArg generated that array of zero length. // But we must succeed eventually. panic("failed to create a resource") }
func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, calls []*Call) { if r.inCreateResource { special := res.SpecialValues() return constArg(special[r.Intn(len(special))]), nil } r.inCreateResource = true defer func() { r.inCreateResource = false }() kind := res.Desc.Name if r.oneOf(100) { // Spoof resource subkind. var all []string for kind1 := range sys.Resources { if sys.IsCompatibleResource(res.Desc.Kind[0], kind1) { all = append(all, kind1) } } kind = all[r.Intn(len(all))] } // Find calls that produce the necessary resources. metas0 := sys.ResourceConstructors(kind) // TODO: reduce priority of less specialized ctors. var metas []*sys.Call for _, meta := range metas0 { if s.ct == nil || s.ct.run[meta.ID] == nil { continue } metas = append(metas, meta) } if len(metas) == 0 { return constArg(res.Default()), nil } // Now we have a set of candidate calls that can create the necessary resource. for i := 0; i < 1e3; i++ { // Generate one of them. meta := metas[r.Intn(len(metas))] calls := r.generateParticularCall(s, meta) s1 := newState(s.ct) s1.analyze(calls[len(calls)-1]) // Now see if we have what we want. var allres []*Arg for kind1, res1 := range s1.resources { if sys.IsCompatibleResource(kind, kind1) { allres = append(allres, res1...) } } if len(allres) != 0 { // Bingo! arg := resultArg(allres[r.Intn(len(allres))]) return arg, calls } switch meta.Name { // Return resources in a variable-length array (length can be 0). case "getgroups", "ioctl$DRM_IOCTL_RES_CTX": default: panic(fmt.Sprintf("unexpected call failed to create a resource %v: %v", kind, meta.Name)) } // Discard unsuccessful calls. for _, c := range calls { foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) { if arg.Kind == ArgResult { delete(arg.Res.Uses, arg) } }) } } // Generally we can loop several times, e.g. when we choose a call that returns // the resource in an array, but then generateArg generated that array of zero length. // But we must succeed eventually. panic("failed to create a resource") }
func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, calls []*Call) { if r.createDepth > 2 { special := res.SpecialValues() return constArg(special[r.Intn(len(special))]), nil } r.createDepth++ defer func() { r.createDepth-- }() sk := res.Subkind if r.oneOf(50) { // Spoof resource subkind. all := res.SubKinds() sk = all[r.Intn(len(all))] } // Find calls that produce the necessary resources. var metas []*sys.Call // Recurse into arguments to see if there is an out/inout arg of necessary type. var checkArg func(typ sys.Type, dir ArgDir) bool checkArg = func(typ sys.Type, dir ArgDir) bool { if resarg, ok := typ.(sys.ResourceType); ok && dir != DirIn && resarg.Kind == res.Kind && (resarg.Subkind == sk || resarg.Subkind == sys.ResAny || sk == sys.ResAny) { return true } switch typ1 := typ.(type) { case sys.ArrayType: if checkArg(typ1.Type, dir) { return true } case sys.StructType: for _, fld := range typ1.Fields { if checkArg(fld, dir) { return true } } case sys.PtrType: if checkArg(typ1.Type, ArgDir(typ1.Dir)) { return true } } return false } for i, meta := range sys.Calls { if s.ct == nil || s.ct.run[i] == nil { continue } ok := false for _, arg := range meta.Args { if checkArg(arg, DirIn) { ok = true break } } if !ok && meta.Ret != nil && checkArg(meta.Ret, DirOut) { ok = true } if ok { metas = append(metas, meta) } } if len(metas) == 0 { return constArg(res.Default()), nil } // Now we have a set of candidate calls that can create the necessary resource. for i := 0; i < 1e3; i++ { // Generate one of them. meta := metas[r.Intn(len(metas))] calls := r.generateParticularCall(s, meta) assignTypeAndDir(calls[len(calls)-1]) s1 := newState(s.ct) s1.analyze(calls[len(calls)-1]) // Now see if we have what we want. var allres []*Arg for sk1, ress := range s1.resources[res.Kind] { if sk1 == sys.ResAny || sk == sys.ResAny || sk1 == sk { allres = append(allres, ress...) } } if len(allres) != 0 { // Bingo! arg := resultArg(allres[r.Intn(len(allres))]) return arg, calls } switch meta.Name { case "getgroups": // Returns groups in an array. default: panic(fmt.Sprintf("unexpected call failed to create a resource %v/%v: %v", res.Kind, sk, meta.Name)) } // Discard unsuccessful calls. for _, c := range calls { foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) { if arg.Kind == ArgResult { delete(arg.Res.Uses, arg) } }) } } // Generally we can loop several times, e.g. when we choose a call that returns // the resource in an array, but then generateArg generated that array of zero length. // But we must succeed eventually. panic("failed to create a resource") }