HybridCache: tags parsing issue breaks remove by tags behavior
Description
I see Cache backend data rejected: ParseFault. warning when calling GetOrCreateAsync without providing tags. I'm passing a key that i had previously added with 2 or more tags. I'm using Redis as a backend cache.
Reproduction Steps
using Microsoft.Extensions.Caching.Hybrid;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = "127.0.0.1:6379"; });
builder.Services.AddHybridCache();
var app = builder.Build();
app.MapGet("/tags", async (HybridCache hybridCache) =>
{
string[] tags = ["tag1", "tag2"];
return await hybridCache.GetOrCreateAsync("key", _ => ValueTask.FromResult("data"), tags: tags);
});
app.MapGet("/no-tags", async (HybridCache hybridCache) =>
{
return await hybridCache.GetOrCreateAsync("key", _ => ValueTask.FromResult("data"));
});
app.Run();
- Run app and send GET request on
/tags. - Re-run app and send GET request on
/no-tags.
Expected behavior
No warning is shown
Actual behavior
I get this warning:
Cache backend data rejected: ParseFault.
System.ArgumentException: Destination array was not long enough. Check the destination index, length, and the array's lower bounds. (Parameter 'destinationArray')
at System.Array.CopyImpl(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length)
at System.Array.CopyTo(Array array, Int32 index)
at Microsoft.Extensions.Caching.Hybrid.Internal.HybridCachePayload.TryParse(ArraySegment`1 source, String key, TagSet knownTags, DefaultHybridCache cache, ArraySegment`1& payload, TimeSpan& remainingTime, PayloadFlags& flags, UInt16& entropy, TagSet& pendingTags, Exception& fault)
Regression?
No response
Known Workarounds
No response
Configuration
.NET SDK:
Version: 9.0.110
Commit: cecf5898ba
Workload version: 9.0.100-manifests.d96a6bf8
MSBuild version: 17.12.44+db5c766a7
Runtime Environment:
OS Name: Windows
OS Version: 10.0.26100
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\9.0.110\
.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.
Host:
Version: 9.0.9
Architecture: x64
Commit: 893c2ebbd4
.NET SDKs installed:
9.0.101 [C:\Program Files\dotnet\sdk]
9.0.110 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 9.0.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 9.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 9.0.9 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Packages:
Microsoft.Extensions.Caching.Hybrid 9.9.0
Microsoft.Extensions.Caching.StackExchangeRedis 9.0.9
Other information
The problem seems to occur here https://github.com/dotnet/extensions/blob/c4e57fb1e6b8403a527ea3cd737f1146dcbc1f31/src/Libraries/Microsoft.Extensions.Caching.Hybrid/Internal/HybridCachePayload.cs#L278-L281 pendingTagBuffer size is increased, and later in default case https://github.com/dotnet/extensions/blob/c4e57fb1e6b8403a527ea3cd737f1146dcbc1f31/src/Libraries/Microsoft.Extensions.Caching.Hybrid/Internal/HybridCachePayload.cs#L310-L314 CopyTo fails because final array length is less than pendingTagBuffer