Install
$ agentstack add skill-jeremykuhne-agent-skills-il-copy-inspection ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Inspecting IL for struct copies
If overlay.md exists beside this file, read it before acting; it contains repository-specific bindings. This core remains usable without it.
A struct copy is invisible in C# source but concrete in IL. This skill reads a method's emitted bytecode to find where the compiler actually copies a value type - defensive copies, boxing, and by-value field/argument/return copies - and maps each back to a source line. It is the ground-truth, post-build complement to the predictive, in-IDE rules of a source-level defensive-copy analyzer.
The four layers (where this sits)
A struct copy can be reasoned about at four levels. Pick the layer that answers the question; they are complementary, not interchangeable.
| Layer | Artifact | Tool / skill | What it tells you | | ----- | -------- | ------------ | ----------------- | | Source | IOperation (pre-lowering) | roslyn-analyzers (defensive-copy rules) | A copy is predicted from C# rules, live in the IDE | | IL | compiled bytecode (post-lowering) | this skill (ildasm / ilspycmd / Cecil) | **A copy was emitted by the C# compiler** | | Asm | JIT machine code | framework-jit-optimization + DisassemblyDiagnoser | Whether the JIT kept the copy or elided it | | Runtime | ETW / wall-clock | performance-testing + filtrace | Whether the copy costs measurable time / allocation |
The IL layer is uniquely able to see copies the compiler synthesizes during lowering - async / iterator state-machine field hoisting, closures, thunks - which have no source operation and are therefore out of reach for an analyzer. It is also the cheapest way to confirm a defensive-copy prediction: if the IL has the defensive-copy signature, the analyzer was right.
Step 0 - is something already answering this?
- "Does my code have a defensive copy I can fix in the editor?" -> a
source-level defensive-copy analyzer (roslyn-analyzers) already flags the common cases live. Use this skill only to (a) confirm a flagged case, or (b) find the synthesized copies the analyzer documents as out of scope.
- "Is this copy actually costing me time / allocations?" ->
performance-testing
(boxing shows as Allocated under [MemoryDiagnoser]; a hot defensive copy shows in a trace).
- "Did the JIT keep the copy?" ->
framework-jit-optimization/
[DisassemblyDiagnoser]. The C# compiler may emit an IL copy that the JIT then elides, so IL presence is necessary but not sufficient for a runtime cost.
- Otherwise, read the IL (below).
Workflow
- Build Release with a portable PDB. Optimized IL is what ships; Debug IL has
extra copies and spills. The PDB's sequence points are what map IL offsets back to file:line. Make sure the build emits a portable PDB - embedded or portable in the project.
- Extract the method's IL. Pick a tool from the table below. Disassemble the
single method of interest, not the whole assembly.
- Match the copy patterns. Scan the method body for the copy opcodes and the
defensive-copy temp signature. The full catalog - every opcode, the ldobj/stloc/ldloca/call defensive sequence, box, cpobj, ldfld vs ldflda - is in [references/copy-opcodes.md](references/copy-opcodes.md).
- Map IL offset to source. Use the PDB sequence points (most disassemblers can
interleave source, e.g. ilspycmd -il with debug info, or read sequence points via System.Reflection.Metadata) to attribute each copy to a line - the same artifact-to-source drill the performance-testing skill does with filtrace.
- Report the type copied, the mechanism (defensive / box / by-value), and the
source line. Distinguish intended copies (a documented value transfer) from unintended ones; IL alone cannot, so use the source context.
Tool options
| Tool | Good for | Note | | ---- | -------- | ---- | | ilspycmd -il (ICSharpCode.ILSpyCmd) | One-method IL dump, scriptable | dotnet tool install -g ilspycmd; cross-platform | | ildasm | Quick Windows dump | Ships with the .NET SDK / VS; Windows-centric | | Mono.Cecil | Programmatic body walking, custom rules | Best when scripting a repeatable copy audit | | System.Reflection.Metadata (MetadataReader, MethodBodyBlock) | In-proc, no extra dependency, owns the PDB sequence-point mapping | Most code; the right base for an automated pass |
For a repeatable, automated audit, Mono.Cecil or System.Reflection.Metadata walking the method body and matching the opcode patterns from the catalog is the durable choice; ilspycmd is the fastest manual spot-check.
Constraints
- Needs a build and a PDB. Unlike an analyzer (source only), this requires
compiled output. No PDB means no source-line mapping - opcodes only.
- IL copy != runtime cost. The JIT may elide an emitted copy. Confirm cost at
the asm or runtime layer before claiming a perf impact.
- Generics share IL. A copy of
Tappears once in the shared body; the real
cost depends on the instantiation. Note the open generic, then reason per value-type substitution.
- Intent is lost in IL. A by-value copy that is a deliberate transfer looks
identical to an accidental one. Keep the source open to classify; this is the same "unintended vs intended" limit a defensive-copy analyzer's docs call out.
Cross-skill
roslyn-analyzers- the source-level, predictive side (defensive-copy rules).
This skill confirms its predictions and covers the synthesized copies it cannot see.
framework-jit-optimization- the next layer down (asm); whether the JIT kept the
copy, and what to do about it on .NET Framework.
performance-testing- whether the copy costs measurable time / allocation.scratch-buffer-strategy- many[NonCopyable]types are pooled buffers; this
skill audits whether one is being copied by value.
- A consuming repository wires these cross-references and its concrete diagnostic
IDs and project names in its overlay.
Disambiguation
"Find the copies" is ambiguous across layers. Route by artifact: predict from source, live -> roslyn-analyzers; read the compiler's emitted IL -> this skill; read the JIT's machine code -> framework-jit-optimization; measure the runtime cost -> performance-testing. This skill never runs the code and never measures time - it reads static bytecode.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: JeremyKuhne
- Source: JeremyKuhne/agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.