From d0405298b24db0e2a6b2abfdc8c7e5ebbe49d1a0 Mon Sep 17 00:00:00 2001 From: Hrutvik Kanabar Date: Tue, 25 Oct 2022 10:13:51 +0000 Subject: prog, pkg/compiler: add `BufferCompressed` buffer type & `compressed_image` builtin Create the `BufferCompressed` kind of `BufferType`, which will be used to represent compressed data. Create the corresponding `compressed_image` syzlang builtin, which is backed by `BufferCompressed`. For now, no syscalls use this feature - this will be introduced in future commits. We have to be careful to decompress the data before mutating, and re-compress before storing. We make sure that any deserialised `BufferCompressed` data is valid too. `BufferCompressed` arguments are mutated using a generic heatmap. In future, we could add variants of `BufferCompressed` or populate the `BufferType` sub-kind, using it to choose different kinds of heatmap for different uncompressed data formats. Various operations on compressed data must be forbidden, so we check for `BufferCompressed` in key places. We also have to ensure `compressed_image` can only be used in syscalls that are marked `no_{generate,minimize}`. Therefore, we add a generic compiler check which allows type descriptions to require attributes on the syscalls which use them. --- pkg/compiler/check.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'pkg/compiler/check.go') diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 402e9a84e..4b2dd1330 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -341,8 +341,48 @@ func (comp *compiler) checkAttributeValues() { comp.error(f.Pos, "%v type must not be used as output", f.Type.Ident) } } + case *ast.Call: + attrNames := make(map[string]bool) + descAttrs := comp.parseAttrs(callAttrs, n, n.Attrs) + for desc := range descAttrs { + attrNames[prog.CppName(desc.Name)] = true + } + + checked := make(map[string]bool) + for _, a := range n.Args { + comp.checkRequiredCallAttrs(n, attrNames, a.Type, checked) + } + } + } +} + +func (comp *compiler) checkRequiredCallAttrs(call *ast.Call, callAttrNames map[string]bool, + t *ast.Type, checked map[string]bool) { + desc := comp.getTypeDesc(t) + for attr := range desc.RequiresCallAttrs { + if !callAttrNames[attr] { + comp.error(call.Pos, "call %v refers to type %v and so must be marked %s", call.Name.Name, t.Ident, attr) } } + + if desc == typeStruct { + s := comp.structs[t.Ident] + // Prune recursion, can happen even on correct tree via opt pointers. + if checked[s.Name.Name] { + return + } + checked[s.Name.Name] = true + fields := s.Fields + for _, fld := range fields { + comp.checkRequiredCallAttrs(call, callAttrNames, fld.Type, checked) + } + } else if desc == typeArray { + typ := t.Args[0] + comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked) + } else if desc == typePtr { + typ := t.Args[1] + comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked) + } } func (comp *compiler) checkLenTargets() { -- cgit mrf-deployment