Table of Contents

Class MemoryPatch

Namespace
CStructSharp.Memory
Assembly
CStructSharp.dll

A prepared, immutable write: the logical range to change and the physical fragments, with expected and replacement bytes, that realize it.

public sealed class MemoryPatch
Inheritance
MemoryPatch
Inherited Members

Remarks

A patch separates deciding what to write from writing it. Planning (Create(MemoryRegion, ReadOnlySpan<byte>, MemoryAccessContext?, byte[]?), or PlanUpdate(MemoryRegion, string, string, object?, MemoryAccessContext?) which calls it) resolves every known mapping layer into the final physical fragments, records each fragment's current bytes and its source's generation, and stages the replacement bytes. Nothing is modified. An editor can show those fragments to a user before Commit(MemoryAccessContext?) performs the writes.

Two safety rules follow from the design. Physical overlap between fragments is rejected, so a logical edit cannot write the same file bytes twice through aliased mappings. And commit re-validates every fragment (writable source, unchanged generation, unchanged expected bytes) before its first write, so a patch prepared against an image that has since changed fails with StaleSource rather than corrupting it.

What a patch cannot promise is atomicity. Arbitrary sources share no transaction or lock, so a later fragment can fail after earlier ones succeeded, and the failing write may be partial. Commit(MemoryAccessContext?) reports that state precisely through MemoryPatchCommitException and never claims rollback. When the original must survive, commit into an OverlayMemorySource.

Properties

Fragments

Gets the physical fragments in logical order; concatenating their replacements reproduces the logical replacement.

public IReadOnlyList<MemoryPatchFragment> Fragments { get; }

Property Value

IReadOnlyList<MemoryPatchFragment>

LogicalRegion

Gets the logical range the patch changes, before mapping layers were resolved.

public MemoryRegion LogicalRegion { get; }

Property Value

MemoryRegion

Methods

Commit(MemoryAccessContext?)

Re-validates every fragment, then writes them in order; a failure during writing reports what completed and what is uncertain.

public void Commit(MemoryAccessContext? context = null)

Parameters

context MemoryAccessContext

Shared operation budget and cancellation, or null to create a default budget.

Remarks

Validation runs over all fragments before any write, so a patch that is entirely stale fails without touching the image. Each fragment must have a source that implements IWritableMemorySource, a generation equal to the one captured at planning, and current bytes equal to its expected bytes. The generation is checked both before and after the comparison read, so a change during that read is caught.

No lock spans arbitrary sources, so a mutation between validation and writing remains possible. If a write throws, the exception is wrapped in MemoryPatchCommitException with the byte count of the fragments confirmed before it and the index of the fragment whose completion is uncertain. Do not retry automatically or assume the original bytes were restored. Passing the planning context here shares one budget across planning and commit; a fresh context starts a new one.

Exceptions

NotSupportedException

A fragment's source does not implement IWritableMemorySource.

MemoryAccessException

Pre-write validation found unavailable bytes, a stale source, or an exhausted budget.

OperationCanceledException

Cancellation was observed before the write phase.

MemoryPatchCommitException

A fragment write failed; earlier writes completed and the failing one may be partial.

Create(MemoryRegion, ReadOnlySpan<byte>, MemoryAccessContext?, byte[]?)

Plans a byte-for-byte replacement of a region, flattening mappings and snapshotting each fragment's current bytes and generation.

public static MemoryPatch Create(MemoryRegion region, ReadOnlySpan<byte> replacement, MemoryAccessContext? context = null, byte[]? expected = null)

Parameters

region MemoryRegion

Finite caller-owned region to replace.

replacement ReadOnlySpan<byte>

New bytes, exactly region.Length of them.

context MemoryAccessContext

Shared operation budget and cancellation, or null to create a default budget.

expected byte[]

Bytes the caller believes the region currently holds, or null to skip that check.

Returns

MemoryPatch

An immutable patch describing the fragments and their bytes.

Remarks

The replacement must be exactly as long as the region. When expected is supplied, each fragment's current bytes are also compared with it, so a caller can assert that the bytes it read earlier are still there. Planning does not require a writable source: previewing an edit against a read-only capture is valid, and the writable check is deferred to Commit(MemoryAccessContext?).

Exceptions

ArgumentNullException

region is null.

ArgumentException

replacement or expected is not exactly region.Length bytes long.

CStructWriteException

Aliased mappings make two fragments cover the same physical bytes.

MemoryAccessException

The current bytes are unavailable, differ from expected, changed while being read, or exceed the budget.

OperationCanceledException

The context's token was cancelled.