aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-11-17 11:03:15 +0100
committerDmitry Vyukov <dvyukov@google.com>2025-11-20 10:10:05 +0000
commit94d1e3f8b1838e8a04074464a957e979a5c5e36b (patch)
tree77a8c97b2dce7bb0dd1704d31eccc1b9c647a3ad /pkg
parent2cc4c24ac3c9f96891da39b75cc806a6696b3a12 (diff)
pkg/clangtool: allow final verification of output
Let tools verify that all source file names, line numbers, etc are valid/present. If there are any bogus entries, it's better to detect them early, than to crash/error much later when the info is used.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/clangtool/clangtool.go59
-rw-r--r--pkg/clangtool/tooltest/tooltest.go4
-rw-r--r--pkg/declextract/entity.go2
3 files changed, 61 insertions, 4 deletions
diff --git a/pkg/clangtool/clangtool.go b/pkg/clangtool/clangtool.go
index 9b9f9387d..4e3914cf8 100644
--- a/pkg/clangtool/clangtool.go
+++ b/pkg/clangtool/clangtool.go
@@ -34,7 +34,7 @@ type OutputDataPtr[T any] interface {
*T
Merge(*T)
SetSourceFile(string, func(filename string) string)
- SortAndDedup()
+ Finalize(*Verifier)
}
// Run runs the clang tool on all files in the compilation database
@@ -81,7 +81,15 @@ func Run[Output any, OutputPtr OutputDataPtr[Output]](cfg *Config) (OutputPtr, e
}
out.Merge(res.out)
}
- out.SortAndDedup()
+ // Finalize the output (sort, dedup, etc), and let the output verify
+ // that all source file names, line numbers, etc are valid/present.
+ // If there are any bogus entries, it's better to detect them early,
+ // than to crash/error much later when the info is used.
+ // Some of the source files (generated) may be in the obj dir.
+ srcDirs := []string{cfg.KernelSrc, cfg.KernelObj}
+ if err := Finalize(out, srcDirs); err != nil {
+ return nil, err
+ }
if cfg.CacheFile != "" {
osutil.MkdirAll(filepath.Dir(cfg.CacheFile))
data, err := json.MarshalIndent(out, "", "\t")
@@ -95,6 +103,53 @@ func Run[Output any, OutputPtr OutputDataPtr[Output]](cfg *Config) (OutputPtr, e
return out, nil
}
+func Finalize[Output any, OutputPtr OutputDataPtr[Output]](out OutputPtr, srcDirs []string) error {
+ v := &Verifier{
+ srcDirs: srcDirs,
+ fileCache: make(map[string]int),
+ }
+ out.Finalize(v)
+ if v.err.Len() == 0 {
+ return nil
+ }
+ return errors.New(v.err.String())
+}
+
+type Verifier struct {
+ srcDirs []string
+ fileCache map[string]int // file->line count (-1 is cached for missing files)
+ err strings.Builder
+}
+
+func (v *Verifier) Filename(file string) {
+ if _, ok := v.fileCache[file]; ok {
+ return
+ }
+ for _, srcDir := range v.srcDirs {
+ data, err := os.ReadFile(filepath.Join(srcDir, file))
+ if err != nil {
+ continue
+ }
+ v.fileCache[file] = len(bytes.Split(data, []byte{'\n'}))
+ return
+ }
+ v.fileCache[file] = -1
+ fmt.Fprintf(&v.err, "missing file: %v\n", file)
+}
+
+func (v *Verifier) LineRange(file string, start, end int) {
+ v.Filename(file)
+ lines, ok := v.fileCache[file]
+ if !ok || lines < 0 {
+ return
+ }
+ // Line numbers produced by clang are 1-based.
+ if start <= 0 || end < start || end > lines {
+ fmt.Fprintf(&v.err, "bad line range [%v-%v] for file %v with %v lines\n",
+ start, end, file, lines)
+ }
+}
+
func runTool[Output any, OutputPtr OutputDataPtr[Output]](cfg *Config, dbFile, file string) (OutputPtr, error) {
relFile := strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(filepath.Clean(file),
cfg.KernelSrc), cfg.KernelObj), "/")
diff --git a/pkg/clangtool/tooltest/tooltest.go b/pkg/clangtool/tooltest/tooltest.go
index 14681946b..b9457e32d 100644
--- a/pkg/clangtool/tooltest/tooltest.go
+++ b/pkg/clangtool/tooltest/tooltest.go
@@ -48,7 +48,9 @@ func LoadOutput[Output any, OutputPtr clangtool.OutputDataPtr[Output]](t *testin
}
out.Merge(tmp)
})
- out.SortAndDedup()
+ if err := clangtool.Finalize(out, []string{"testdata"}); err != nil {
+ t.Fatal(err)
+ }
return out
}
diff --git a/pkg/declextract/entity.go b/pkg/declextract/entity.go
index bd8f143d1..3b5e13a6d 100644
--- a/pkg/declextract/entity.go
+++ b/pkg/declextract/entity.go
@@ -241,7 +241,7 @@ func (out *Output) Merge(other *Output) {
out.NetlinkPolicies = append(out.NetlinkPolicies, other.NetlinkPolicies...)
}
-func (out *Output) SortAndDedup() {
+func (out *Output) Finalize(v *clangtool.Verifier) {
out.Functions = clangtool.SortAndDedupSlice(out.Functions)
out.Consts = clangtool.SortAndDedupSlice(out.Consts)
out.Enums = clangtool.SortAndDedupSlice(out.Enums)