aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--prog/expr.go13
-rw-r--r--prog/expr_test.go22
-rw-r--r--prog/rand.go8
-rw-r--r--sys/test/expressions.txt23
4 files changed, 56 insertions, 10 deletions
diff --git a/prog/expr.go b/prog/expr.go
index cfe6eb70b..e9446ab2c 100644
--- a/prog/expr.go
+++ b/prog/expr.go
@@ -67,11 +67,14 @@ func makeArgFinder(t *Target, c *Call, unionArg *UnionArg, parents parentStack)
}
func (r *randGen) patchConditionalFields(c *Call, s *state) (extra []*Call, changed bool) {
- if r.inPatchConditional {
- return nil, false
- }
- r.inPatchConditional = true
- defer func() { r.inPatchConditional = false }()
+ if r.patchConditionalDepth > 1 {
+ // Some nested patchConditionalFields() calls are fine as we could trigger a resource
+ // constructor via generateArg(). But since nested createResource() calls are prohibited,
+ // patchConditionalFields() should never be nested more than 2 times.
+ panic("third nested patchConditionalFields call")
+ }
+ r.patchConditionalDepth++
+ defer func() { r.patchConditionalDepth-- }()
var extraCalls []*Call
var anyPatched bool
diff --git a/prog/expr_test.go b/prog/expr_test.go
index aaae6a74a..74818ea55 100644
--- a/prog/expr_test.go
+++ b/prog/expr_test.go
@@ -280,3 +280,25 @@ func TestConditionalUnionFields(t *testing.T) {
assert.Greater(t, zeroU2, 0)
assert.Greater(t, nonzeroU2, 0)
}
+
+func TestNestedConditionalCall(t *testing.T) {
+ // Ensure that we reach different combinations of conditional fields.
+ target, rs, _ := initRandomTargetTest(t, "test", "64")
+ ct := target.DefaultChoiceTable()
+ r := newRand(target, rs)
+
+ for i := 0; i < 100; i++ {
+ for _, name := range []string{"test$conditional_struct_nested", "test$conditional_struct_nested2"} {
+ s := newState(target, ct, nil)
+ calls := r.generateParticularCall(s, target.SyscallMap[name])
+ p := &Prog{
+ Target: target,
+ Calls: calls,
+ }
+ err := p.checkConditions()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+}
diff --git a/prog/rand.go b/prog/rand.go
index b15871b8a..760f7a904 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -25,10 +25,10 @@ const (
type randGen struct {
*rand.Rand
- target *Target
- inGenerateResource bool
- inPatchConditional bool
- recDepth map[string]int
+ target *Target
+ inGenerateResource bool
+ patchConditionalDepth int
+ recDepth map[string]int
}
func newRand(target *Target, rs rand.Source) *randGen {
diff --git a/sys/test/expressions.txt b/sys/test/expressions.txt
index 1c1cfbca5..500bdec20 100644
--- a/sys/test/expressions.txt
+++ b/sys/test/expressions.txt
@@ -16,7 +16,28 @@ conditional_struct {
f2 int64 (if[value[mask] & FIELD_FLAG2])
} [packed]
-test$conditional_struct(a ptr[in, conditional_struct])
+resource some_res[int32]
+
+test$conditional_struct(a ptr[in, conditional_struct]) some_res
+
+# To generate this call, we need to recursively also generate a test$conditional_struct() call.
+
+needs_some_res {
+ switch int32
+ field some_res (if[value[switch] != 0])
+}
+
+resource some_res_nested[int32]
+test$conditional_struct_nested(a ptr[in, needs_some_res]) some_res_nested
+
+# .. and one more level.
+
+needs_some_res_nested {
+ switch int32
+ field some_res_nested (if[value[switch] != 0])
+}
+
+test$conditional_struct_nested2(a ptr[in, needs_some_res_nested])
parent_conditions {
mask int32