aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorPaul Chaignon <paul.chaignon@gmail.com>2023-10-06 20:02:41 +0200
committerAleksandr Nogikh <nogikh@google.com>2023-10-09 10:22:31 +0000
commitf5ee62f7ee98f53dced33b767e59f47b35017568 (patch)
treee3a79d0d20645b7834fe5e44d91d43200c503e0b /prog
parent77f31e1f821f48a72259fdbd9d285d1ce16956f5 (diff)
prog: fix missing required input resources
While reviewing the changes introduced by previous commits, Aleksandr noticed a bug in the logic to compute all required input resources of a given syscall (function getInputResources). This commit fixes the bug. That function has an optimization to avoid walking structs and unions twice. That optimization however fails to consider the direction and optional bit. For example, if a struct is first encountered with DirOut (== output resource), it will never be analyzed again and will not be included in getInputResources' returned values. That same struct could however be included elsewhere with DirIn. The exact same issue affects the optional bit since optional resources are now also skipped by getInputResources. One approach to fix this is to only consider a struct or union as 'seen' if it was seen with the same direction and optional bit. This commit implements that approach. Fixes: 852e3d2eae98 ("sys: support recursive structs") Reported-by: Aleksandr Nogikh <nogikh@google.com> Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
Diffstat (limited to 'prog')
-rw-r--r--prog/types.go30
1 files changed, 25 insertions, 5 deletions
diff --git a/prog/types.go b/prog/types.go
index 45136f079..cbba259c9 100644
--- a/prog/types.go
+++ b/prog/types.go
@@ -704,10 +704,20 @@ func ForeachCallType(meta *Syscall, f func(t Type, ctx *TypeCtx)) {
}
func foreachTypeImpl(meta *Syscall, preorder bool, f func(t Type, ctx *TypeCtx)) {
+ // We need seen to be keyed by the type, the direction, and the optionality
+ // bit. Even if the first time we see a type it is optional or DirOut, it
+ // could be required or DirIn on another path. So to ensure that the
+ // information we report to the caller is correct, we need to visit both
+ // occurrences.
+ type seenKey struct {
+ t Type
+ d Dir
+ o bool
+ }
// Note: we specifically don't create seen in ForeachType.
// It would prune recursion more (across syscalls), but lots of users need to
// visit each struct per-syscall (e.g. prio, used resources).
- seen := make(map[Type]bool)
+ seen := make(map[seenKey]bool)
var rec func(*Type, Dir, bool)
rec = func(ptr *Type, dir Dir, optional bool) {
if _, ref := (*ptr).(Ref); !ref {
@@ -726,18 +736,28 @@ func foreachTypeImpl(meta *Syscall, preorder bool, f func(t Type, ctx *TypeCtx))
case *ArrayType:
rec(&a.Elem, dir, optional)
case *StructType:
- if seen[a] {
+ key := seenKey{
+ t: a,
+ d: dir,
+ o: optional,
+ }
+ if seen[key] {
break // prune recursion via pointers to structs/unions
}
- seen[a] = true
+ seen[key] = true
for i, f := range a.Fields {
rec(&a.Fields[i].Type, f.Dir(dir), optional)
}
case *UnionType:
- if seen[a] {
+ key := seenKey{
+ t: a,
+ d: dir,
+ o: optional,
+ }
+ if seen[key] {
break // prune recursion via pointers to structs/unions
}
- seen[a] = true
+ seen[key] = true
for i, f := range a.Fields {
rec(&a.Fields[i].Type, f.Dir(dir), optional)
}