In pkg/kubeletclient/kubeletclient.go, when a new resource name is first seen, getDevicePluginResources stores the slice directly without copying:
resourceMap[dev.ResourceName] = &types.ResourceInfo{DeviceIDs: dev.DeviceIds}
dev.DeviceIds is a slice backed by the same underlying array as the data in rc.resources (the cached kubelet API response). When GetPodResourceMap subsequently calls types.SortDeviceIDs(resourceMap), the in-place sort.Strings call mutates that backing array, silently reordering the data stored in rc.resources.
Impact
- A read-only operation (
GetPodResourceMap) has a hidden write side-effect on cached state.
- Under concurrent
GetPodResourceMap calls, this is a data race on the shared backing array.
Fix
Copy the slice when inserting into resourceMap:
// in getDevicePluginResources
resourceMap[dev.ResourceName] = &types.ResourceInfo{
DeviceIDs: append([]string(nil), dev.DeviceIds...),
}
The same pattern should be verified in getDRAResources, though deviceIDs there is built locally so it is not aliased.
In
pkg/kubeletclient/kubeletclient.go, when a new resource name is first seen,getDevicePluginResourcesstores the slice directly without copying:dev.DeviceIdsis a slice backed by the same underlying array as the data inrc.resources(the cached kubelet API response). WhenGetPodResourceMapsubsequently callstypes.SortDeviceIDs(resourceMap), the in-placesort.Stringscall mutates that backing array, silently reordering the data stored inrc.resources.Impact
GetPodResourceMap) has a hidden write side-effect on cached state.GetPodResourceMapcalls, this is a data race on the shared backing array.Fix
Copy the slice when inserting into
resourceMap:The same pattern should be verified in
getDRAResources, thoughdeviceIDsthere is built locally so it is not aliased.