Skip to content

Fix: SubqueryFilterChecker stack-empty crash#478

Open
snaumenko-st wants to merge 4 commits intomaster-servicetitanfrom
count-predicate
Open

Fix: SubqueryFilterChecker stack-empty crash#478
snaumenko-st wants to merge 4 commits intomaster-servicetitanfrom
count-predicate

Conversation

@snaumenko-st
Copy link
Copy Markdown

SubqueryFilterChecker.VisitBinary unconditionally called Pop() on its meaningfulLefts/meaningfulRights correlation stacks whenever it saw a "tuple[i] == null" comparison. If the checker visited a FilterProvider whose predicate started with a bare null-check before any correlation equality had pushed anything onto the stacks, Pop() threw InvalidOperationException("Stack empty.") during LINQ translation.

This shape surfaces naturally from:

  Query.All<T>()
    .GroupBy(p => p.Id)
    .Select(g => g.Count(x => x.Field == null))
    .ToArray();

where VisitAggregate takes the "use grouping AggregateProvider" optimization path and runs SubqueryFilterRemover over an origin data source whose top FilterProvider carries the bare "x.Field == null" predicate.

Guard Pop() with a Count==0 check and treat an empty-stack null-check as "not a subquery-correlation filter" (fall through to base.VisitFilter), which is the conservative, behavior-preserving choice.

Covered by a new e2e regression test in
Orm/Xtensive.Orm.Tests/Linq/SubqueryFilterCheckerTest.cs using an inline model; the test fails with "Stack empty." on the unfixed code and passes with the guard.

Made-with: Cursor

…cates

SubqueryFilterChecker.VisitBinary unconditionally called Pop() on its
meaningfulLefts/meaningfulRights correlation stacks whenever it saw a
"tuple[i] == null" comparison. If the checker visited a FilterProvider
whose predicate started with a bare null-check before any correlation
equality had pushed anything onto the stacks, Pop() threw
InvalidOperationException("Stack empty.") during LINQ translation.

This shape surfaces naturally from:

  Query.All<T>()
    .GroupBy(p => p.Id)
    .Select(g => g.Count(x => x.Field == null))
    .ToArray();

where VisitAggregate takes the "use grouping AggregateProvider"
optimization path and runs SubqueryFilterRemover over an origin data
source whose top FilterProvider carries the bare "x.Field == null"
predicate.

Guard Pop() with a Count==0 check and treat an empty-stack null-check
as "not a subquery-correlation filter" (fall through to
base.VisitFilter), which is the conservative, behavior-preserving
choice.

Covered by a new e2e regression test in
Orm/Xtensive.Orm.Tests/Linq/SubqueryFilterCheckerTest.cs using an
inline model; the test fails with "Stack empty." on the unfixed code
and passes with the guard.

Made-with: Cursor
Comment thread Orm/Xtensive.Orm/Orm/Linq/Rewriters/SubqueryFilterRemover.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants