diff options
| author | Paul Chaignon <paul.chaignon@gmail.com> | 2023-10-06 20:02:41 +0200 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2023-10-09 10:22:31 +0000 |
| commit | f5ee62f7ee98f53dced33b767e59f47b35017568 (patch) | |
| tree | e3a79d0d20645b7834fe5e44d91d43200c503e0b /prog | |
| parent | 77f31e1f821f48a72259fdbd9d285d1ce16956f5 (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.go | 30 |
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) } |
