Check the inflate ceiling before the write, not after it - #102
JohnCampionJr wants to merge 1 commit into
Conversation
From Copilot's review on #92, against code that merged in #89 -- and it is right. The stream is created with capacity , so a write crossing that grows the backing array (MemoryStream doubles) and the check fired only once the allocation had happened. On a large declared image that is a hundred megabytes handed out in order to refuse a payload: the exact 'bounded after the fact' shape the guard exists to prevent, reintroduced by the guard itself. KittyTransmission.TryInflate had the same ordering and the same fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Folded into #92 instead — the finding came from a review comment there, it is two lines, and a separate PR is more review and merge overhead than the change is worth. The branch is deleted; the commit is on |
Perf comparison — this change, against its base3 run(s) of each side, alternating on one machine. Allocation is a count and is gated exactly. Time is a measurement, so its gate is derived from the spread this job just observed in itself rather than fixed in advance.
Each corpus is gated at assemblies measured
Perf comparison — cumulative, everything since 2.0.0-rc0023 run(s) of each side, alternating on one machine. Allocation is a count and is gated exactly. Time is a measurement, so its gate is derived from the spread this job just observed in itself rather than fixed in advance.
Each corpus is gated at assemblies measured
|
Follow-up to #89, from a Copilot comment left on #92 that pointed at code which had already merged. It is a real hole in the bound that PR shipped.
Inflatecreates itsMemoryStreamwith capacityexpected, then writes a read into it and afterwards asks whether the total exceeded the ceiling. A write that crosses the capacity makesMemoryStreamgrow its backing array — it doubles — so on a large declared image the check fires only once roughly a hundred megabytes has already been allocated in order to refuse the payload.That is precisely the "bounded after the fact" shape #89 existed to eliminate, reintroduced by the guard itself.
output.Length + read > expectedis asked before the write now, so the refusal costs nothing.KittyTransmission.TryInflatehad the same ordering and gets the same fix.Suite green: 1899. No perf run — this is an image-decode path, not the print path, and the change removes an allocation rather than adding work.
🤖 Generated with Claude Code