C#: Only allow source propgatation upwards in the call stack if the call path consists of unique call targets (to avoid unwanted virtual dispatch). This severely tightens the generation of extrapolated sources.

This commit is contained in:
Michael Nebel
2024-06-11 10:41:54 +02:00
parent 1c3ceacf04
commit 40204911bc
2 changed files with 24 additions and 0 deletions

View File

@@ -249,6 +249,7 @@ string captureSource(DataFlowTargetApi api) {
PropagateFromSource::flow(source, sink) and
ExternalFlow::sourceNode(source, kind) and
api = sink.getEnclosingCallable() and
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
result = ModelPrinting::asSourceModel(api, sink.getOutput(), kind)
)
}

View File

@@ -257,6 +257,29 @@ predicate apiSource(DataFlow::Node source) {
)
}
private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) {
exists(DataFlowCall call |
dc1 = call.getEnclosingCallable() and
dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0)
)
}
bindingset[dc1, dc2]
private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) =
fastTC(uniquelyCalls/2)(dc1, dc2)
/**
* Holds if it is not relevant to generate a source model for `api`, even
* if flow is detected from a node within `source` to a sink within `api`.
*/
bindingset[sourceEnclosing, api]
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, TargetApiSpecific api) {
not exists(DataFlowCallable dc1, DataFlowCallable dc2 | uniquelyCallsPlus(dc1, dc2) or dc1 = dc2 |
dc1.getUnderlyingCallable() = api and
dc2.getUnderlyingCallable() = sourceEnclosing
)
}
/**
* Gets the MaD input string representation of `source`.
*/