Repository navigation
Do not send a stale parameter name for an AddParams member the procedure does not declare - #135
Merged
Merged
Conversation
…tied The pool is filled with a sentinel name and returned without clearing before the command resolves its names. Stored procedure and text command, synchronous and asynchronous, unmatched-only and mixed members. They fail until the slot of an unmatched member is written. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ure does not declare The names a command sends are resolved into a string?[] rented from ArrayPool<string?>.Shared, which is process-wide. For a member of an AddParams object that matched none of the declared names, the loop moved on without writing its slot, and the later passes then read whatever name the previous renter had left there. The member was sent under that stale name, or two such members collided on it. A text command with @name markers took the same path. Write the slot (null: not sent) for every parameter before it is read. Regression tests dirty the shared pool without clearing it and run the command, for a stored procedure and a text command, synchronously and asynchronously, with unmatched-only and mixed members. IN1 audit of the other pool Rent sites found no other slot read before it is written. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix: an
AddParamsmember that the procedure (or the text) does not declare is no longer sent under a stale name left in the process-wideArrayPool<string?>.Resolving the names of an
AddParamsobject keeps the name each parameter ends up with in an array rented fromArrayPool<string?>.Shared. For a member that matched nothing, the first pass moved on without writing its slot, and the later passes read the slot anyway: whatever an earlier renter had left there was sent as the parameter name (or made two unmatched members collide). A text command with@namemarkers takes the same path.What changed
ExpressiveCommandBase.Apply: the slot of an unmatchedAddParamsmember is written (null: not sent) before it is read. One line. The clearing policy is unchanged (the used prefix is cleared on return).PooledNameSlotTests(7 tests): fill several arrays of the pool with a sentinel name and return them without clearing, betweenAddParamsand the terminal, then run the command:@namemarkers, unmatched member: sync and async (ExpressiveCommand,ExpressiveDbCommand);.Rent(site inSource/(13): only this one read a slot before it was written. The other twelve write every slot they read (or hand the array to a caller under a documented contract). No other change.Verification
Tests first, then the fix (two commits),
Tests/Open.Database.Extensions.Core.Tests, net10.0 and net11.0.dotnet test Tests/Open.Database.Extensions.Core.Tests -c Release --filter FullyQualifiedName~PooledNameSlotTests --nologo: Failed 7, Passed 0 on both targets (for exampleCollection: ["@stale"]where an empty list is expected).dotnet test Tests/Open.Database.Extensions.Core.Tests -c Release --nologo: net10.0 Passed 10200 of 10200; net11.0 Passed 10200 of 10200.dotnet test Tests/Open.Database.Extensions.Core.Tests -c Debug --nologo(soDebug.Assertfires): net10.0 Passed 10200 of 10200; net11.0 Passed 10199, Failed 1:SingleValueAllocationTests.ToArrayAndToListOfInt_AllocateNoMoreThanASelector(rows: 100)("3890 B per call through the terminal, 1936 B by hand"). That test passes when run on its own (--filter FullyQualifiedName~SingleValueAllocationTests, Debug, net11.0, 12 of 12) and does not touch name resolution. It was not run against the unmodified tree.Not done / decisions
MappedQuerySelectTests.TheAsyncProjection_AllocatesNothingPerRowfails intermittently on net11.0 Release (it did in this branch's full gate run: 10199 of 10200 passed). It was already known before this branch and is in code this change does not touch.object[]thatGetValuesleaves unwritten (documented on the publicGetValues(record, ..., pool)methods; the library reads only the field count).🤖 Generated with Claude Code