Skip to content

Data flow: Add hook for preventing lambda dispatch in source call contexts#21592

Open
hvitved wants to merge 2 commits intogithub:mainfrom
hvitved:dataflow/source-call-context-type-flow
Open

Data flow: Add hook for preventing lambda dispatch in source call contexts#21592
hvitved wants to merge 2 commits intogithub:mainfrom
hvitved:dataflow/source-call-context-type-flow

Conversation

@hvitved
Copy link
Contributor

@hvitved hvitved commented Mar 26, 2026

Consider the following example:

void Foo(Action<string> a)
{
    var x = Source();
    a(x);              // (1)
    a = s => Sink(s);  // (2)
    a(x);              // (3)
}

void Bar()
{
     Foo(s => Sink(s)); // (4)
}

Because of the call at (4), both (1) and (3) are calls that can reach a sink.

However, when we use the flow feature FeatureHasSourceCallContext (or FeatureEqualSourceSinkCallContext), we want to reject the call edge from (1) to (4).

We achieve this using the TypeFlow module, by assigning the parameter a a special type that is incompatible with all lambda types. This is currently only implemented for C#, so all other languages should be unaffected by this change.

Thanks to @aschackmull for pointing me in the right direction.

@hvitved hvitved force-pushed the dataflow/source-call-context-type-flow branch 2 times, most recently from 292fb0a to 1efb323 Compare March 26, 2026 19:34
@hvitved hvitved force-pushed the dataflow/source-call-context-type-flow branch from 1efb323 to aa52b10 Compare March 27, 2026 08:18
@hvitved hvitved added the no-change-note-required This PR does not need a change note label Mar 27, 2026
@hvitved hvitved marked this pull request as ready for review March 27, 2026 08:26
@hvitved hvitved requested review from a team as code owners March 27, 2026 08:26
@hvitved hvitved requested review from aschackmull and Copilot March 27, 2026 08:26
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a configurable hook in the shared dataflow library to prevent resolving lambda dispatch when using source call-context flow features (implemented for C# via a special “source context parameter” type), so call-context–sensitive analyses can reject spurious edges.

Changes:

  • Extend shared dataflow InputSig/TypeFlow plumbing with a hook for assigning a special parameter-node type in source call-context scenarios.
  • Implement the hook for C# by introducing a dedicated DataFlowType variant and compatibility behavior.
  • Add a C# model-generator regression test snippet to ensure the added call-site pattern doesn’t affect summary generation.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll Threads a new TypeFlowInput predicate and applies a special type for parameters in source call-context.
shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll Implements the new TypeFlowInput hook for forward analysis; defaults it to none() for reverse.
shared/dataflow/codeql/dataflow/DataFlow.qll Adds a new InputSig extension point with detailed documentation/example.
csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs Adds a small call-site intended to guard summary generation behavior.
csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll Introduces a C#-specific “source context parameter” dataflow type and compatibility handling.
csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplSpecific.qll Wires the new InputSig hook to return the C# special type.
Comments suppressed due to low confidence (1)

shared/dataflow/codeql/dataflow/DataFlow.qll:91

  • The example explanation is a little confusing because it refers to a “call edge from (3) to (2)”, but (2) is the assignment statement (not the lambda itself). Consider clarifying that (3) can still dispatch to the lambda assigned at (2), to avoid readers misinterpreting which edge is meant.
   * If a source call context flow feature is used, `a` can be assigned a special
   * type that is incompatible with the type of _any_ lambda expression, which will
   * prevent the call edge from (1) to (4). Note that the call edge from (3) to (2)
   * will still be valid.

}

pragma[nomagic]
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This predicate should also have added the compatibleTypesSourceContextParameterTypeLeft(t1, t2) case, I think.

* prevent the call edge from (1) to (4). Note that the call edge from (3) to (2)
* will still be valid.
*/
default DataFlowType getSourceContextParameterNodeType() { none() }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether this type ought to be parameterised on the parameter. Conceptually it's a subtype of whatever callback type the parameter has and there could be multiple mutually disjoint callback types. And if this type is introduced as a singleton then it could conceptually ruin that disjointness.

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

Labels

C# DataFlow Library no-change-note-required This PR does not need a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants