Skip to content

Commit ca9d327

Browse files
authored
Merge pull request #20915 from hvitved/content-flow-ap-limit
Shared: Improvements to content-sensitive model generation
2 parents 7fd4755 + 3ba256a commit ca9d327

File tree

5 files changed

+47
-18
lines changed

5 files changed

+47
-18
lines changed

csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
260260
)
261261
}
262262

263+
int contentAccessPathLimitInternal() { result = 2 }
264+
263265
bindingset[d]
264266
private string getFullyQualifiedName(Declaration d) {
265267
exists(string qualifier, string name |

java/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
218218
)
219219
}
220220

221+
int contentAccessPathLimitInternal() { result = 2 }
222+
221223
predicate isField(DataFlow::ContentSet c) {
222224
c instanceof DataFlowUtil::FieldContent or
223225
c instanceof DataFlowUtil::SyntheticFieldContent

rust/ql/test/utils-tests/modelgenerator/option.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,7 @@ impl<T> MyOption<T> {
299299
}
300300

301301
// summary=<test::option::MyOption>::insert;Argument[0];Argument[self].Reference.Field[test::option::MyOption::MySome(0)];value;dfc-generated
302-
// This summary is currently missing because of access path limit
303-
// summary-MISSING=<test::option::MyOption>::insert;Argument[0];ReturnValue.Reference;value;dfc-generated
302+
// summary=<test::option::MyOption>::insert;Argument[0];ReturnValue.Reference;value;dfc-generated
304303
// The content of `self` is overwritten so it does not flow to the return value.
305304
// SPURIOUS-summary=<test::option::MyOption>::insert;Argument[self].Reference.Field[test::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated
306305
pub fn insert(&mut self, value: T) -> &mut T {
@@ -311,8 +310,7 @@ impl<T> MyOption<T> {
311310
}
312311

313312
// summary=<test::option::MyOption>::get_or_insert;Argument[0];Argument[self].Reference.Field[test::option::MyOption::MySome(0)];value;dfc-generated
314-
// This summary is currently missing because of access path limit
315-
// summary-MISSING=<test::option::MyOption>::get_or_insert;Argument[0];ReturnValue.Reference;value;dfc-generated
313+
// summary=<test::option::MyOption>::get_or_insert;Argument[0];ReturnValue.Reference;value;dfc-generated
316314
// summary=<test::option::MyOption>::get_or_insert;Argument[self].Reference.Field[test::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated
317315
pub fn get_or_insert(&mut self, value: T) -> &mut T {
318316
self.get_or_insert_with(|| value)
@@ -328,7 +326,7 @@ impl<T> MyOption<T> {
328326

329327
// summary=<test::option::MyOption>::get_or_insert_with;Argument[self].Reference.Field[test::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated
330328
// summary=<test::option::MyOption>::get_or_insert_with;Argument[0].ReturnValue;Argument[self].Reference.Field[test::option::MyOption::MySome(0)];value;dfc-generated
331-
// SPURIOUS-summary=<test::option::MyOption>::get_or_insert_with;Argument[0];Argument[self].Reference.Field[test::option::MyOption::MySome(0)];value;dfc-generated
329+
// summary=<test::option::MyOption>::get_or_insert_with;Argument[0].ReturnValue;ReturnValue.Reference;value;dfc-generated
332330
pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
333331
where
334332
F: FnOnce() -> T,

shared/dataflow/codeql/dataflow/internal/ContentDataFlowImpl.qll

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ module MakeImplContentDataFlow<LocationSig Location, InputSig<Location> Lang> {
7575
/** Gets a limit on the number of reads out of sources and number of stores into sinks. */
7676
default int accessPathLimit() { result = Lang::accessPathLimit() }
7777

78+
/** Gets the access path limit used in the internal invocation of the standard data flow library. */
79+
default int accessPathLimitInternal() { result = Lang::accessPathLimit() }
80+
7881
/** Holds if `c` is relevant for reads out of sources or stores into sinks. */
7982
default predicate isRelevantContent(ContentSet c) { any() }
8083
}
@@ -110,7 +113,7 @@ module MakeImplContentDataFlow<LocationSig Location, InputSig<Location> Lang> {
110113

111114
FlowFeature getAFeature() { result = ContentConfig::getAFeature() }
112115

113-
predicate accessPathLimit = ContentConfig::accessPathLimit/0;
116+
predicate accessPathLimit = ContentConfig::accessPathLimitInternal/0;
114117

115118
// needed to record reads/stores inside summarized callables
116119
predicate includeHiddenNodes() { any() }
@@ -274,6 +277,16 @@ module MakeImplContentDataFlow<LocationSig Location, InputSig<Location> Lang> {
274277
)
275278
}
276279

280+
/**
281+
* Gets the length of this access path.
282+
*/
283+
int length() {
284+
this = TAccessPathNil() and
285+
result = 0
286+
or
287+
result = this.getTail().length() + 1
288+
}
289+
277290
/**
278291
* Gets the content set at index `i` in this access path, if any.
279292
*/

shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,16 @@ module MakeModelGeneratorFactory<
277277
*/
278278
predicate isAdditionalContentFlowStep(Lang::Node nodeFrom, Lang::Node nodeTo);
279279

280+
/**
281+
* Gets the access path limit for content flow analysis.
282+
*/
283+
default int contentAccessPathLimit() { result = 2 }
284+
285+
/**
286+
* Gets the internal access path limit for content flow analysis.
287+
*/
288+
default int contentAccessPathLimitInternal() { result = Lang::accessPathLimit() }
289+
280290
/**
281291
* Holds if the content set `c` is field like.
282292
*/
@@ -650,7 +660,10 @@ module MakeModelGeneratorFactory<
650660
exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t))
651661
}
652662

653-
int accessPathLimit() { result = 2 }
663+
predicate accessPathLimit = SummaryModelGeneratorInput::contentAccessPathLimit/0;
664+
665+
predicate accessPathLimitInternal =
666+
SummaryModelGeneratorInput::contentAccessPathLimitInternal/0;
654667

655668
predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) }
656669

@@ -703,14 +716,17 @@ module MakeModelGeneratorFactory<
703716
}
704717

705718
/**
706-
* Holds if the access path `ap` is not a parameter or returnvalue of a callback
707-
* stored in a field.
719+
* Holds if `ap` is valid for generating summary models.
720+
*
721+
* We currently don't include summaries that rely on parameters or return values
722+
* of callbacks stored in fields, as those are not supported by the data flow
723+
* library.
708724
*
709-
* That is, we currently don't include summaries that rely on parameters or return values
710-
* of callbacks stored in fields.
725+
* We also exclude access paths with contents not supported by `printContent`.
711726
*/
712727
private predicate validateAccessPath(PropagateContentFlow::AccessPath ap) {
713-
not (mentionsField(ap) and mentionsCallback(ap))
728+
not (mentionsField(ap) and mentionsCallback(ap)) and
729+
forall(int i | i in [0 .. ap.length() - 1] | exists(getContent(ap, i)))
714730
}
715731

716732
private predicate apiFlow(
@@ -720,7 +736,9 @@ module MakeModelGeneratorFactory<
720736
) {
721737
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
722738
getEnclosingCallable(returnNodeExt) = api and
723-
getEnclosingCallable(p) = api
739+
getEnclosingCallable(p) = api and
740+
validateAccessPath(reads) and
741+
validateAccessPath(stores)
724742
}
725743

726744
/**
@@ -763,9 +781,7 @@ module MakeModelGeneratorFactory<
763781
PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt,
764782
PropagateContentFlow::AccessPath stores, boolean preservesValue
765783
) {
766-
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
767-
getEnclosingCallable(returnNodeExt) = api and
768-
getEnclosingCallable(p) = api and
784+
apiFlow(api, p, reads, returnNodeExt, stores, preservesValue) and
769785
p = api.getARelevantParameterNode()
770786
}
771787

@@ -956,8 +972,6 @@ module MakeModelGeneratorFactory<
956972
input = parameterNodeAsExactInput(p) + printReadAccessPath(reads) and
957973
output = getExactOutput(returnNodeExt) + printStoreAccessPath(stores) and
958974
input != output and
959-
validateAccessPath(reads) and
960-
validateAccessPath(stores) and
961975
(
962976
if mentionsField(reads) or mentionsField(stores)
963977
then lift = false and api.isRelevant()

0 commit comments

Comments
 (0)