From 12ae218bfe8c194786737220759cbb2e8e3e3a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanislav=20L=C3=A1zni=C4=8Dka?= Date: Thu, 15 Aug 2024 15:50:22 +0200 Subject: [PATCH] ensure tlsCacheKey is strictly comparable to avoid runtime panics --- .../k8s.io/client-go/transport/cache_go118.go | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/staging/src/k8s.io/client-go/transport/cache_go118.go b/staging/src/k8s.io/client-go/transport/cache_go118.go index d21d5137d4d..babdaf8b5ad 100644 --- a/staging/src/k8s.io/client-go/transport/cache_go118.go +++ b/staging/src/k8s.io/client-go/transport/cache_go118.go @@ -18,7 +18,29 @@ limitations under the License. package transport +// this is just to make the "unused" linter rule happy +var _ = isCacheKeyComparable[tlsCacheKey] + // assert at compile time that tlsCacheKey is comparable in a way that will never panic at runtime. -var _ = isComparable[tlsCacheKey] +// +// Golang 1.20 introduced an exception to type constraints that allows comparable, but not +// necessarily strictly comparable type arguments to satisfy the `comparable` type constraint, +// thus allowing interfaces to fulfil the `comparable` constraint. +// However, by definition, "A comparison of two interface values with identical +// dynamic types causes a run-time panic if that type is not comparable". +// +// We want to make sure that comparing two `tlsCacheKey` elements won't cause a +// runtime panic. In order to do that, we'll force the `tlsCacheKey` to be strictly +// comparable, thus making it impossible for it to contain interfaces. +// To assert strict comparability, we'll use another definition: "Type +// parameters are comparable if they are strictly comparable". +// Below, we first construct a type parameter from the `tlsCacheKey` type so that +// we can then push this type parameter to a comparable check, thus checking these +// are strictly comparable. +// +// Original suggestion from https://github.com/golang/go/issues/56548#issuecomment-1317673963 +func isCacheKeyComparable[K tlsCacheKey]() { + _ = isComparable[K] +} func isComparable[T comparable]() {}