Commit Graph
9611 Commits
Author SHA1 Message Date
Siegfried Pammer c29b0e8501 Merge pull request #4072 from icsharpcode/fix/3704-static-type-target
Fix #3704: keep the static type of a dynamic call target
2026-08-29 23:09:35 +02:00
Siegfried Pammer 8ab3f93f5e Fix #3704: keep the static type of a dynamic call target
A dynamic call site that names a type passes typeof(T) as its target. When
a later argument contains control flow, the compiler stores that typeof in
a temporary. ILInlining does not undo this: it inlines a store only into
the immediately following instruction, so an intervening statement leaves
the typeof behind, and the expression builder printed the temporary instead
of the type. Substituting the typeof back into the target slot is not an
option either, because a call there has side effects and blocks inlining of
the remaining arguments.

The type is therefore stored on the instruction. Object creation already
did this, but kept the field private, so the expression builder re-derived
the type from the target argument and failed on the spilled form. Member
invocation gets the same field. Both drop the target from Arguments, so the
dead-argument handling removes the store; ArgumentInfo keeps its entry for
the target, because the invocation symbol is built from it.

The type of an object creation is not nullable: the transform returns
before constructing the instruction when it cannot match the typeof, and
substitutes the unknown type otherwise. An unresolvable type therefore
reaches the expression builder as the unresolved type it is, and prints as
`?` like any other, rather than being indistinguishable from a missing one.

Those two are also the only binder method kinds that ever see
CSharpArgumentInfoFlags.IsStaticType. Every other way of naming a type as
the receiver binds statically and leaves only a conversion of the dynamic
operand behind.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 22:41:05 +02:00
Christoph Wille 7a08c6c57d Update NuGet packages; adapt to Dock.Serializer.SystemTextJson 12.1.0.6
Dock 12.1.0.6 removed the public JsonConverterFactoryList/JsonConverterList<T>
converters from Dock.Serializer.SystemTextJson that ILSpyDockJson used to
deserialize IList<T> into ObservableCollection<T>. Dock now does the same
substitution with an internal JsonTypeInfo modifier that swaps CreateObject
for IList<T> enumerables. ILSpyDockJson mirrors that technique in its own
modifier chain, which also removes the per-element JsonSerializer.Serialize
side effect the old converter had.

Also bumps Xaml.Behaviors.Avalonia, ProDataGrid, AwesomeAssertions, CliWrap,
NUnit3TestAdapter, and the decompiler minor version to 11.1.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-29 21:10:25 +02:00
Siegfried Pammer 2058b2e080 Merge pull request #4062 from icsharpcode/fix/3202-obfuscated-local-functions
Detect local functions renamed by obfuscators
2026-08-29 20:51:06 +02:00
Siegfried Pammer 2606bfd946 Merge pull request #4076 from icsharpcode/fix/sharptreeview-stranded-container
Scroll the tree by offset, so no container is left stranded
2026-08-29 20:48:56 +02:00
Siegfried Pammer 7bb731e25c Merge pull request #4074 from icsharpcode/fix/decompdiff-ref-packs
Bind each corpus assembly against its own reference-assembly pack
2026-08-29 20:28:20 +02:00
Siegfried Pammer f3d48a141e Merge pull request #4073 from icsharpcode/fix/context-menu-test-flake
Wait for the click target instead of counting frames
2026-08-29 20:27:58 +02:00
Siegfried Pammer 0f4bb196e6 Bind each corpus assembly against its own reference-assembly pack
decompdiff indexed the Microsoft.NETFramework.ReferenceAssemblies packs into
one flat name map shared by the whole corpus, and never indexed
Microsoft.NETCore.App.Ref at all. Ordering the packs by name let net45 claim
mscorlib and System.Runtime, so a net9.0 assembly resolved its BCL against
.NET Framework 4.5: Task, ValueTask and the async method builders came back
as UnknownType, AsyncAwaitDecompiler could not match a state machine, and
every async method decompiled as a raw MoveNext.

Both sides of a diff degraded identically, so comparisons stayed valid, but
the corpus stopped representing modern code. Over 28 nuget assemblies the
same run reports 338 //IL_ warnings instead of 18202, 237 leaked <> names
instead of 15654, and 116k fewer lines.

The pack is now chosen per assembly from its TargetFrameworkAttribute and
searched before anything else, matching how nugetfuzz already resolves them.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 19:43:59 +02:00
Siegfried Pammer 170aea4408 Wait for the click target instead of counting frames
Right_Clicking_A_Second_Row_Moves_The_Context_Highlight_To_It timed out on
the Windows CI agent waiting for the second context menu to open. A closed
popup's light-dismiss overlay keeps answering hit tests until the scene is
rendered again, and a press that lands on it raises no ContextRequested at
all, so the menu never opens. The test pumped a fixed four frames after
dismissing the first menu to get past that, which is a guess about how long
the overlay survives: enough on a fast machine, not on a loaded agent.

Hit testing the point is the same question the context-request handler asks,
so waiting for it to reach the row is the actual precondition for the click,
whatever number of frames that takes. The failure could not be reproduced
locally - removing the frames entirely still passes here - so this fixes the
documented mechanism rather than a reproduction, and a timeout now reports
which of the two conditions was not met.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 19:43:56 +02:00
Siegfried Pammer b279efd364 Merge pull request #4070 from icsharpcode/fix/unknown-type-erasure
Drop isReferenceType when erasing unknown types
2026-08-29 19:40:43 +02:00
Siegfried Pammer 997d2f2db3 Recognize a closure struct of a generic method or type
FindRefStructParameters dropped generic instantiations, so a parameter
typed 'ref <>c__DisplayClass0_0<T>' never reached RefStructTypes. Both
consumers therefore missed local functions whose declaring type or method
is generic: the signature test for an obfuscated local function, and
LocalFunctionNeedsAccessibilityChange, which left such a function internal
while its closure struct stayed private - the recompiled output then fails
with CS0051.

Cross-module signatures still drop out, because the generic type part of an
instantiation goes through GetTypeFromReference, which returns nil.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 19:19:21 +02:00
Siegfried Pammer 4bc51e6083 Drop isReferenceType when erasing unknown types
Whether an unresolvable type is a reference type is not a property of the
type but of the metadata that mentioned it: a signature spelling it
`valuetype T` yields false, a bare TypeRef yields null. UnknownType.Equals
compares the flag, so the two spellings of one missing type compared
unequal and EquivalentTypes reported false - the decompiler then emitted a
cast between a type and itself.

Erasing the flag in NormalizeTypeVisitor keeps the relaxation inside the
comparisons that ask for erasure, next to the nullability, modopt and tuple
erasure that are use-site spellings of the same kind. Dropping the term
from UnknownType.Equals instead was measured and rejected: Equals also keys
CSharpConversions' implicit-conversion cache, where merging the two
spellings lets whichever conversion is computed first answer for both,
adding 398 boxing casts across two real-world assemblies.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 18:17:51 +02:00
Daniel Grunwald d410645cb4 Merge pull request #4071 from icsharpcode/better-types-for-stack-slots
Improve types for variables generated from stack slots
2026-08-29 18:05:24 +02:00
Daniel Grunwald b360268d6d Adjust tests: the improved stack slot type caused variable names to improve. 2026-08-29 15:46:44 +02:00
Daniel Grunwald 5670bfc132 Stack slots holding value types previously nevertheless often had type object
This was due to StackType.O doing double-duty as `object` and `other`.
While ExpressionBuilder would often improve the type of such locals, the `object` nevertheless ended up used in a couple of places, e.g. via the `typeHint`. This could result in value types being boxed even though the original IL didn't contain any `box` instruction.

This is an attempt to use better types for stack slot variables created by ILReader. The idea is: there aren't many IL instructions that produce "other" value types, and `InferType()` already handles pretty much all of them, so we can use that to assign types to our stack slots.

It's a bit more tricky if the stack is pushed to on multiple branches that join together before the value is used: here the variable type must be suitable for both assignments. In this case, we go back to the previously-used stacktype.
2026-08-29 15:21:08 +02:00
Siegfried Pammer 3687c069ed Merge pull request #4063 from icsharpcode/fix/navigateto-short-form
Accept member IDs without a signature in --navigateto
2026-08-29 12:52:33 +02:00
Siegfried Pammer 8651329710 Scroll the tree by offset, so no container is left stranded
ListBox.ScrollIntoView realises a container for its target, arranges it at its
own desired width, parks it aside for a few layout passes and then drops the
reference. A container those passes do not adopt back into the realized range
stays a visible child of the panel that nothing arranges again: it keeps
painting its old item, at its old position and its own narrow width, over
whatever row now occupies that spot - the ghost row drawn across another.

Rows here are a uniform height, so the offset a row's index implies reaches the
same place without ever entering that path. ScrollIntoView is hidden on
SharpTreeView so the obvious call lands on the safe one; hiding is not
enforcement, since a call through an ItemsControl-typed reference still reaches
the base method, but no call site has such a reference.

Assisted-by: Claude:claude-opus-5:Claude Code
2026-08-29 12:10:44 +02:00
Siegfried Pammer ead3ee7e39 Decide --navigateto's selection from what the ID resolved to
An ID that resolves to no member left the tree on an empty selection with no
indication of what happened, because supplying --navigateto also suppresses the
single-assembly selection that opening a file otherwise makes. Only a target
that actually resolved should claim the selection; "none" still counts as
handled, since the VS add-in uses it to deliberately leave the tree empty.

The target arrives from a command line, so it goes through the omission-tolerant
search rather than exact resolution, and that can name several members. All of
them are selected. Landing on one would hide that there was a choice, and
falling back to the declaring type would bury the group in a large type's
decompilation - Enumerable.Where would decompile some two hundred members to
show four. The tree already multi-selects, so the overloads appear together at
the level the ID was pointing at.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 11:31:24 +02:00
Siegfried Pammer 9971c7e6df Find the member a hand-written documentation id was aiming at
Typing "M:System.Linq.Enumerable.Where" at a command line is a reasonable thing
to do, and it found nothing: resolution compares the whole id string, so a form
without the parameter list only ever matched a member that genuinely takes none.
Spelling the signature out is no answer, because it means knowing the overload
count before asking. The same goes for a generic arity - and the exact spelling,
Dictionary`2, does not even survive an unquoted bash prompt, where a backtick
starts command substitution.

None of that makes the short form legal. Measured against Roslyn: its own
DocumentationCommentId resolver accepts no abbreviation at all, and the compiler
never emits one - a cref is a different grammar, which the compiler binds and
rewrites into a full id, warning CS0419 and picking one member when the cref is
ambiguous. A prefixed cref is copied through unvalidated, so an id in a
documentation file can be anything a human typed.

So the id grammar stays exact and IdStringProvider stays with it, which is what
lets cref-following trust its answer. The tolerance belongs to the callers that
serve people typing, and lives in DocumentationIdSearch as a ladder that loosens
one thing at a time: the exact id, then the id without its parameter list, then
without generic arities. Stating a detail wrongly still finds nothing; only
leaving one out asks for any. A rung may match several members and all of them
are returned, because which to present is the caller's decision and hiding the
rest would hide that the id was ambiguous.

ilspycmd shows every member of the group, headed by a comment naming the
ambiguity, and accepts the shapes people actually type: no prefix, a shortened
namespace, and arity written the cref or C# way.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 11:31:24 +02:00
Siegfried Pammer 46d8f8c4f4 Merge pull request #4067 from icsharpcode/docs/code-review-guidelines
Add code review guidance and require Assisted-by on every agent commit
2026-08-29 09:29:28 +02:00
Daniel Grunwald aa00e3fb84 Merge pull request #4068 from icsharpcode/type-inference
Type inference for switch-expressions
2026-08-29 09:23:19 +02:00
Daniel Grunwald 5d9cdce94c We need to properly compare the C# type, not just the StackType, otherwise our implicit conversions might end up converting to the wrong type.
This also matters in the `1 => DateTime.Now, 2 => null` case -- BestCommonType infers `DateTime` here, but we need `DateTime?` instead. But both had `StackType.O` so this went wrong prior to this commit.
2026-08-28 21:15:15 +02:00
Daniel Grunwald b54a073efe Improvements to type inference:
* merge object/dynamic distinctions like we do with tuple element names. This fixes BestCommonType(object, dynamic).
 * add a test that `new[] { 1, null }` has the "best common type" = `int`. The conversion error from `null` to `int` only happens later, it's not related to the best common type computation.
2026-08-28 21:05:19 +02:00
Siegfried Pammer 2d9f852cd0 Merge pull request #4065 from icsharpcode/fix-3683
Insert casts in switch expression to ensure a best common type exists
2026-08-28 19:03:54 +02:00
Siegfried Pammer 89719860b9 Require the Assisted-by trailer on every agent-written commit
The previous wording described what an AI-assisted commit looks like
without saying the trailer is mandatory, which left it readable as a
convention for substantial changes only. The marker is what lets a
reader tell which work came from an agent, so it has to hold across all
of it -- an exemption for trivial commits makes the absence of the
trailer meaningless. The same reasoning closed a matching gap in how
agents comment on PRs, where a single disclaimer on a review body left
eleven inline comments unmarked.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-28 18:51:19 +02:00
Siegfried Pammer 6c261321d5 Add a code review guide and point CLAUDE.md at it
An agent review of PR #4065 posted twelve comments and eight had to be
withdrawn. Most were output of a decompdiff corpus sweep run against the
PR branch, which measures the whole decompiler rather than the diff, and
one called a cast a regression when it was the correct emission -- the
old form compiled only because C# target-types the switch expression.

The guide lives in .github/ rather than inline because most sessions
never review anything and should not carry it, and because it is as
useful to a human reviewer as to an agent. CLAUDE.md keeps only the two
rules that have to hold before you have decided you are reviewing at
all, plus the pointer.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-28 18:51:19 +02:00
Daniel Grunwald 1a784e2fa9 Fix throw switch-expr; by specifying the typeHint for throw. 2026-08-28 09:19:11 +02:00
Daniel Grunwald ca24b8f3af Fix #3683: insert casts in switch expression to ensure a best common type exists. 2026-08-27 23:14:42 +02:00
Siegfried Pammer 8997904b72 Merge pull request #4029 from icsharpcode/refactor/debug-steps-typed-il
Walk the whole decompiler pipeline in the Debug Steps pane
2026-08-27 10:51:03 +02:00
Siegfried Pammer 3160485f1f Keep the original name of an obfuscated local function
A Roslyn local function name is "<caller>g__name|x_y", where the trailing digits
are a synthetic disambiguator that SplitName has to strip before the scope-local
renumbering can run. An obfuscated name has no such suffix, so running it through
the same path renames "smethod_1" to "smethod_" -- a needless second mangling on
top of what the obfuscator already did.

#3202

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 10:25:26 +02:00
Siegfried Pammer e85d2ba00e Detect local functions renamed by obfuscators
Obfuscators strip the CompilerGeneratedAttribute and rewrite the
"<caller>g__name|x_y" name, which is all IsLocalFunctionMethod had to go on.
The method then stays an ordinary static method, its display struct escapes by
ref into a plain call, and TransformDisplayClassUsage correctly refuses to
scalar-replace it -- so the closure fields leak into the output as
"<>c__DisplayClass29_0_.iid" (issue #3202).

The one marker an obfuscator cannot remove is the signature: Roslyn emits
struct closures exclusively for local functions, and no hand-written C# can
name a "<>c__DisplayClass" type, so a by-ref parameter of one identifies the
method regardless of what it is called.

#3202

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 10:25:26 +02:00
Siegfried Pammer 3a8340ef60 Stop pointing the ILAst docs at a language that is not there
The ilspycmd dump and the contributor notes described themselves by reference to
the UI's ILAst language; the pane is what walks that pipeline now.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:46:46 +02:00
Siegfried Pammer ea28552655 Name the new file's author, and require the group depth
The file this branch adds takes the contributor's name rather than
AlphaSierraPapa, and three comments it added drop their en-GB spelling.

EndOpenGroups now requires its target depth: zero is the one value that closes
groups the caller does not own, which is the misattribution the depth argument
was added to prevent.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:46:46 +02:00
Siegfried Pammer 90d563b796 Walk the step tree with the helper the repo already has
Three copies of the same pre-order walk across two test files become
TreeTraversal.PreOrder, and the stepper fixture builds its decompiler through
the file-name constructor instead of assembling the type system by hand.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:46:03 +02:00
Siegfried Pammer 72ed28f903 Report the halted-ILAst write through a return value
The ref parameter was only there because a partial method could not return one.
An extended partial can, so the caller reads the answer where it uses it. The
implementation stays behind DEBUG, which now needs a Release counterpart: an
extended partial must have one in every configuration, and there the step limit
is never set, so it never writes.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:46:03 +02:00
Siegfried Pammer 1e95c82a52 Show each step's pipeline half, and filter without building the tree
Two things about the step tree's presentation. Nothing said which half of the
pipeline a step belonged to, so each one now names its phase from what it points
at - instructions for the IL half, syntax nodes for the C# half - and a group
opener with no anchor takes it from the first step underneath.

And the wrappers are built on demand because a recorded type runs to tens of
thousands of steps, but the filter walked them and so built every one on the
first keystroke. It now asks the recorded steps whether a subtree contains a
match, and only descends into wrappers that already exist or are on a revealed
path.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:45:49 +02:00
Siegfried Pammer b8d68d9143 Give the builder output a step of its own
The state the ExpressionBuilder and StatementBuilder leave behind was only
reachable as "state before the first AST transform" - an entry that names a
transform rather than the state, and that sits below every member's group in a
tree with one group per member. It is now a top-level step at the seam, where
the whole type is converted and nothing has transformed it yet.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:45:49 +02:00
Siegfried Pammer 44116503d9 Take the halted function from the stepper
Two extra pieces of state existed to reconstruct what the stepper already
records: which member a halt belongs to. The step the limit stopped on answers
it, except on a member's opening step, which is where the previous member's
state ends - and there the last step actually recorded answers it instead.

IL group openers gain an anchor so their position resolves. The member opener
deliberately keeps none: anchoring it to the member the pipeline is about to
start is exactly the misattribution the fallback exists to avoid.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:45:49 +02:00
Siegfried Pammer f24e7faa96 Carry step recording in the decompilation request
Whether a run records was read from the pane's own state at the moment the
decompiler was built, on a background task. A step index only means anything
against a run recorded the same way, so the full run and the step-limited replay
of one of its indices have to agree on it - and a view that can be attached or
detached between the two is the wrong place to ask.

The flag now travels in DecompilationOptions beside StepLimit and IsDebug, read
from the workspace on the UI thread when a run starts. Putting it on the tab
instead would miss the tabs opened after the pane, and the pane can be opened
before any tab exists at all.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:45:49 +02:00
Siegfried Pammer 1118f2c056 Let the pane's steps go when it closes
The recorded steps are pinned on the MEF-shared C# language, but the release
went through the pane's attached language, which is null whenever another
language is selected - open the pane on C#, switch to IL, close it, and the tree
stayed alive until the next full C# run. The language still raises StepperUpdated
at the end of every run, so a run that outlived the pane pinned its tree straight
back in. And opening the pane re-ran the decompile whatever the language,
discarding the view for a tree that only C# can produce.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:45:28 +02:00
Siegfried Pammer 0b4b2a3f08 Record the whole pipeline or none of it
Recording only gated the IL half, so a run with it off still numbered the C# AST
transforms into the shared stepper. That gave one pipeline two numbering scales,
and a step index is only meaningful against the scale it was recorded on: a tree
captured under one and replayed under the other selects a different step. It
also let the crashed-member attribution fire on a counter that had never moved -
a limit of zero matched at every throwing transform and rendered an unrelated
member's ILAst.

The flag now gates both halves, so steps exist exactly when recording is on, and
it lives on the pane instance rather than a static the background decompile read
across threads.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:45:28 +02:00
Siegfried Pammer a5bd230e14 Walk the whole decompiler pipeline in the Debug Steps pane
The pane used to split the pipeline across two languages: the ILAst language
stepped the IL transforms, the C# language stepped the AST transforms, and
nothing showed the seam between them, so a step index meant a different thing
depending on which language happened to be selected. Recording both halves into
one Stepper makes an index replayable across the whole pipeline; a limit that
lands in the IL phase has no C# to print, so the halted function is rendered as
ILAst instead.

Which function that is takes some care, because a member group's EndStep is the
next member's first step: a halt standing on a member's opening step belongs to
the member that just finished, a transform that throws where the limit was aimed
has to hand over the ILAst it half-transformed (what the ILAst language showed
as "ILAst after the crash"), and a step recorded on a helper function the
pipeline has not attached yet belongs to that function's own tree.

Retention stays opt-in twice over: the decompiler records IL steps only when
asked to, and the pane asks only while its view is on screen. Every kept step
pins the ILAst it captured, which for one type runs to tens of thousands of
nodes, so a closed pane would be paying for a tree nobody displays.

What is left of the ILAst language is its typed-IL dump, which runs no
transforms at all. That stays, as TypedILLanguage. IDebugStepProvider was down
to a single implementation and is removed.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-26 22:41:08 +02:00
Siegfried Pammer a980639f99 Pin the deconstruction shapes the transform has to keep matching
Twenty shapes that no fixture covered: nesting at depth three and at position
zero, inner discards on either side, property and no-conversion targets, and
deconstruction inside try, switch, if/else and while. All but one already
decompile correctly - they are checked in so a future change to
DeconstructionTransform cannot silently drop them.

The one that does not is left commented out with a pointer to #4059 rather than
as a red test: two back-to-back deconstructions share their out-slot
temporaries, and neither is recognized.

#4059

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-26 22:04:04 +02:00
Christoph Wille 27b45a4458 Fix #4054: Accept drops from sources that do not permit the Move effect
The assembly list answered DragOver with the Move effect only. OLE
intersects that answer with the effects the drag source permits, and
sources such as FileLocator Pro only permit Copy, so the negotiation
ended in None and the drop was refused although CF_HDROP was present
and the file path resolved fine. Explorer permits Move, which is why
drops from Explorer kept working. The WPF ILSpy offered Move, Copy and
Link and let the source pick; restore that.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-26 20:19:04 +02:00
Siegfried Pammer 5571b87074 Merge pull request #4051 from icsharpcode/docs/decompiler-engine-guardrails
Require spec references and design sign-off for engine changes
2026-08-26 08:29:51 +02:00
Siegfried Pammer 76ec7588e3 #2764: Add regression test for duplicate assembly references
A merging obfuscator can leave a module referencing two versions of the same
assembly. Loading both split every type they declare into two definitions that
compare unequal, so a signature naming such a type through one reference stopped
matching a base method naming it through the other, and a genuine override was
printed as virtual. ac0ef8a11 (#3253) dropped the lower-version duplicates, but
nothing covered that, and neither of the existing fixture kinds can carry the
three assemblies the situation needs.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-25 22:46:59 +02:00
Christoph Wille e930120ade Merge pull request #4047 from icsharpcode/fix/resources-file-length-validation
Bound every .resources length against the remaining stream before allocating
2026-08-25 18:03:58 +02:00
Christoph Wille 45470dfbed Merge pull request #4048 from icsharpcode/fix/bundle-entry-decompression-bound
Never size bundle entry decompression from the manifest's declared size
2026-08-25 18:03:28 +02:00
Christoph Wille 436a82a3f8 Merge pull request #4046 from icsharpcode/fix/lightjson-parser-depth-limit
Cap LightJson parser nesting depth to prevent stack overflow
2026-08-25 18:03:05 +02:00
Christoph Wille 629bed5677 Rename CheckLength to CheckLengthOrThrow
Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-25 13:53:19 +02:00