Skip to content

Selectivity functions: unchecked Const cast and leaked variable stats #54

Description

@demitri

This ticket is one of the findings my Claude/ChatGPT review found; the text below is written by Claude. If you'd prefer reports as PRs I'd be happy to resubmit. -- Demitri

Summary

The two selectivity-estimation callbacks assume the radius argument folds to a Const and cast to it unconditionally, and they never release the variable-statistics they acquire. This is planner-only (bad row estimates, a leaked stats-cache reference, and a possible bad read on an exotic query) — no data corruption. Found alongside #50.

Details

In both pgq3c_sel (q3c.c:127) and pgq3c_seljoin (q3c.c:173):

other = estimate_expression_value(root, vardata.var);
radDatum   = ((Const *) other)->constvalue;      /* q3c.c:129 / :175 */
isnull     = ((Const *) other)->constisnull;

estimate_expression_value returns a Const only when the expression can be folded; a non-foldable argument (e.g. an unresolved Param, or a non-constant radius) comes back as some other node type. Reading constvalue/constisnull off that node reinterprets unrelated fields — a garbage selectivity estimate, and potentially an invalid read.

Separately, examine_variable(...) acquires statistics into vardata, but neither function calls ReleaseVariableStats(&vardata) before returning, leaking the reference.

Suggested fix

Guard the cast with IsA(other, Const) and fall back to a sensible default selectivity otherwise; and always ReleaseVariableStats(&vardata) before returning (including on the early/isnull paths).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions