CultCache: a record whose payload carries slots past its reader's, at any depth, is held read-only
The guard formatter counts each int-keyed object's slots into a thread-bound scope opened around the one payload decode; ToStoredDocument turns the finding into CultStoredDocument.UnreadSlots (explained only for depth-0 slots the catalog comparison reports ignored); HeldOwned refuses an unexplained mark whatever is declared; RefuseUndeclared throws the one refusal with UnreadSlots; CultCache.IsWritable asks the same predicate. Vectors: extra-slot-unit-arm, extra-slot-store.cc. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c371832736
commit
c55d34fb32
14 changed files with 642 additions and 30 deletions
|
|
@ -166,7 +166,7 @@ public static class CultDocumentMessagePackSerialization
|
|||
|
||||
private static (MessagePackSerializerOptions Options, IFormatterResolver[] Ahead) Compose(IFormatterResolver[] consumerResolvers)
|
||||
{
|
||||
// The guard goes first and wraps whatever formatter the rest of the composite would hand out, so a consumer
|
||||
// The guard goes first and wraps whatever formatter the rest of the composite would hand out (a union, or a concrete int-keyed object for its slot count), so a consumer
|
||||
// resolver still encodes an arm while the key check runs.
|
||||
var ahead = consumerResolvers.Append(CultDocumentResolver.Instance).Append(CultMathResolver.Instance).Append(CultMathExprResolver.Instance).ToArray();
|
||||
var inner = CompositeResolver.Create(ahead.Append(StandardResolver.Instance).ToArray());
|
||||
|
|
@ -214,6 +214,19 @@ public static class CultDocumentMessagePackSerialization
|
|||
?? throw new InvalidOperationException($"MessagePack returned null for Cult document type {type.FullName}.");
|
||||
}
|
||||
|
||||
// The same decode, with the slots it read past noted (CultSlotScope). Opened around the one decode and after the depth check,
|
||||
// so a payload past the nesting limit is refused, never marked.
|
||||
internal static CultDecoded DeserializeMarked(Type type, byte[] payload, CultDocumentRegistry registry)
|
||||
{
|
||||
if (registry == null) throw new ArgumentNullException(nameof(registry));
|
||||
registry.GetRequired(type);
|
||||
CultPayloadDepth.Check(payload, type, PayloadDirection.Read);
|
||||
using var scope = CultSlotScope.Open();
|
||||
var document = MessagePackSerializer.Deserialize(type, payload, OptionsForDocument(type))
|
||||
?? throw new InvalidOperationException($"MessagePack returned null for Cult document type {type.FullName}.");
|
||||
return new CultDecoded(document, scope.Finding());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces slots of a serialized document payload (a MessagePack array indexed by slot) with already-encoded member
|
||||
/// values, leaving every other slot byte for byte as it was. A slot past the end extends the array with nil.
|
||||
|
|
@ -823,4 +836,7 @@ public class SingleFileMessagePackBackingStore : SingleFileBackingStore
|
|||
{
|
||||
return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload, Registry);
|
||||
}
|
||||
|
||||
internal override CultDecoded DeserializeMarked(Type documentType, byte[] payload) =>
|
||||
CultDocumentMessagePackSerialization.DeserializeMarked(documentType, payload, Registry);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue