From bb105d7a4e6b96f6c93ace38821b3a27206c4b89 Mon Sep 17 00:00:00 2001 From: Etienne Perot Date: Mon, 12 Jun 2023 12:59:15 -0700 Subject: [PATCH] Unimplemented syscall counter: Pre-allocate 1-element slices of field values. This is necessary in order to avoid a heap allocation when calling `unimplementedSyscallCounter.Increment`. Prior to this CL, this code actually allocated a 1-element slice, because the `Increment` method takes in a variadic number of arguments. Somehow this had not tripped up the `+checkescape` check at submission time, but running `nogo` manually confirms the problem. This CL fixes it. PiperOrigin-RevId: 539737956 --- pkg/sentry/kernel/syscalls.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/sentry/kernel/syscalls.go b/pkg/sentry/kernel/syscalls.go index 4cdc5d385..c0582e67b 100644 --- a/pkg/sentry/kernel/syscalls.go +++ b/pkg/sentry/kernel/syscalls.go @@ -43,7 +43,7 @@ const ( // outOfRangeSyscallNumber is used to represent a syscall number that is out of the // range [0, maxSyscallNum] in monitoring. -var outOfRangeSyscallNumber = metric.FieldValue{"-1"} +var outOfRangeSyscallNumber = []*metric.FieldValue{&metric.FieldValue{"-1"}} // SyscallSupportLevel is a syscall support levels. type SyscallSupportLevel int @@ -359,7 +359,10 @@ var ( // unimplementedSyscallNumbers maps syscall numbers to their string representation. // Used such that incrementing unimplementedSyscallCounter does not require allocating memory. - unimplementedSyscallNumbers map[uintptr]*metric.FieldValue + // Each element in the mapped slices are of length 1, as there is only one field for the + // unimplemented syscall counter metric. Allocating a slice is necessary as it is passed as a + // variadic argument to the metric library. + unimplementedSyscallNumbers map[uintptr][]*metric.FieldValue // unimplementedSyscallCounter tracks the number of times each unimplemented syscall has been // called by the sandboxed application. @@ -392,13 +395,13 @@ func RegisterSyscallTable(s *SyscallTable) { allSyscallTables = append(allSyscallTables, s) unimplementedSyscallCounterInit.Do(func() { allowedValues := make([]*metric.FieldValue, maxSyscallNum+2) - unimplementedSyscallNumbers = make(map[uintptr]*metric.FieldValue, len(allowedValues)) + unimplementedSyscallNumbers = make(map[uintptr][]*metric.FieldValue, len(allowedValues)) for i := uintptr(0); i <= maxSyscallNum; i++ { s := &metric.FieldValue{strconv.Itoa(int(i))} allowedValues[i] = s - unimplementedSyscallNumbers[i] = s + unimplementedSyscallNumbers[i] = []*metric.FieldValue{s} } - allowedValues[len(allowedValues)-1] = &outOfRangeSyscallNumber + allowedValues[len(allowedValues)-1] = outOfRangeSyscallNumber[0] unimplementedSyscallCounter = metric.MustCreateNewUint64Metric("unimplemented_syscalls", true, "Number of times the application tried to call an unimplemented syscall, broken down by syscall number", metric.NewField("sysno", allowedValues...)) }) s.Init() @@ -501,7 +504,7 @@ type SyscallInfo struct { func IncrementUnimplementedSyscallCounter(sysno uintptr) { s, found := unimplementedSyscallNumbers[sysno] if !found { - s = &outOfRangeSyscallNumber + s = outOfRangeSyscallNumber } - unimplementedSyscallCounter.Increment(s) + unimplementedSyscallCounter.Increment(s...) }