diff --git a/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index 306ec34d31d0..039c96a9a0bc 100644 --- a/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -9,5 +9,5 @@ import internal.CaptureModels from DataFlowSummaryTargetApi api, string flow -where flow = ContentSensitive::captureFlow(api) +where flow = ContentSensitive::captureFlow(api, _) select flow order by flow diff --git a/csharp/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql new file mode 100644 index 000000000000..6d7004fcc090 --- /dev/null +++ b/csharp/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql @@ -0,0 +1,13 @@ +/** + * @name Capture mixed neutral models. + * @description Finds neutral models to be used by other queries. + * @kind diagnostic + * @id cs/utils/modelgenerator/mixed-neutral-models + * @tags modelgenerator + */ + +import internal.CaptureModels + +from DataFlowSummaryTargetApi api, string noflow +where noflow = captureMixedNeutral(api) +select noflow order by noflow diff --git a/csharp/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql new file mode 100644 index 000000000000..4a0bf7c9e227 --- /dev/null +++ b/csharp/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql @@ -0,0 +1,13 @@ +/** + * @name Capture mixed summary models. + * @description Finds applicable summary models to be used by other queries. + * @kind diagnostic + * @id cs/utils/modelgenerator/mixed-summary-models + * @tags modelgenerator + */ + +import internal.CaptureModels + +from DataFlowSummaryTargetApi api, string flow +where flow = captureMixedFlow(api, _) +select flow order by flow diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll index 7c0aed91b6b8..fb2bfafbf258 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -131,7 +131,10 @@ module ModelGeneratorInput implements ModelGeneratorInputSig throw null; - public void M1() { + public void M1() + { var o = new object(); SetMySyntheticField(o); Sink(GetMySyntheticField()); } - public void M2() { + public void M2() + { var o = new object(); SetMyNestedSyntheticField(o); Sink(GetMyNestedSyntheticField()); } - public void M3() { + public void M3() + { var o = new object(); SetMyFieldOnSyntheticField(o); Sink(GetMyFieldOnSyntheticField()); @@ -329,4 +333,19 @@ public void M3() { static void Sink(object o) { } } + + // Test content data flow provenance. + public class L + { + public void M1() + { + var l = new Library(); + var o = new object(); + l.SetValue(o); + Sink(l.GetValue()); + } + + static void Sink(object o) { } + } + } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs_ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs_ index a6f0d8c99913..0f74a41d8814 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs_ +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs_ @@ -13,5 +13,9 @@ namespace My.Qltest public static object StepArgReturnGenerated(object x) => throw null; public static object StepArgReturnGeneratedIgnored(object x) => throw null; + + public void SetValue(object o) => throw null; + + public object GetValue() => throw null; } } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.dll b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.dll index ec85f11a1be7..4455e0b042e4 100644 Binary files a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.dll and b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.dll differ diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected index 0b80a70fbade..a7459ce8645b 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected @@ -30,6 +30,8 @@ models | 29 | Summary: My.Qltest; K; false; GetMyNestedSyntheticField; (); ; Argument[this].SyntheticField[My.Qltest.K.MySyntheticField1].SyntheticField[MySyntheticField1.MyNestedSyntheticField]; ReturnValue; value; manual | | 30 | Summary: My.Qltest; K; false; SetMyFieldOnSyntheticField; (System.Object); ; Argument[0]; Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]; value; manual | | 31 | Summary: My.Qltest; K; false; GetMyFieldOnSyntheticField; (); ; Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]; ReturnValue; value; manual | +| 32 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated | +| 33 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated | edges | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | | @@ -127,21 +129,26 @@ edges | ExternalFlow.cs:279:13:279:23 | [post] this access : J | ExternalFlow.cs:281:18:281:21 | this access : J | provenance | | | ExternalFlow.cs:279:22:279:22 | access to local variable j : Object | ExternalFlow.cs:279:13:279:23 | [post] this access : J | provenance | MaD:25 | | ExternalFlow.cs:281:18:281:21 | this access : J | ExternalFlow.cs:281:18:281:27 | access to property Prop1 | provenance | MaD:24 | -| ExternalFlow.cs:313:17:313:17 | access to local variable o : Object | ExternalFlow.cs:314:33:314:33 | access to local variable o : Object | provenance | | -| ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | ExternalFlow.cs:313:17:313:17 | access to local variable o : Object | provenance | | -| ExternalFlow.cs:314:13:314:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:315:18:315:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | | -| ExternalFlow.cs:314:33:314:33 | access to local variable o : Object | ExternalFlow.cs:314:13:314:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | MaD:26 | -| ExternalFlow.cs:315:18:315:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | provenance | MaD:27 | -| ExternalFlow.cs:319:17:319:17 | access to local variable o : Object | ExternalFlow.cs:320:39:320:39 | access to local variable o : Object | provenance | | -| ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | ExternalFlow.cs:319:17:319:17 | access to local variable o : Object | provenance | | -| ExternalFlow.cs:320:13:320:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:321:18:321:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | | -| ExternalFlow.cs:320:39:320:39 | access to local variable o : Object | ExternalFlow.cs:320:13:320:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | MaD:28 | -| ExternalFlow.cs:321:18:321:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | provenance | MaD:29 | -| ExternalFlow.cs:325:17:325:17 | access to local variable o : Object | ExternalFlow.cs:326:40:326:40 | access to local variable o : Object | provenance | | -| ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | ExternalFlow.cs:325:17:325:17 | access to local variable o : Object | provenance | | -| ExternalFlow.cs:326:13:326:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:327:18:327:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | | -| ExternalFlow.cs:326:40:326:40 | access to local variable o : Object | ExternalFlow.cs:326:13:326:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | MaD:30 | -| ExternalFlow.cs:327:18:327:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | provenance | MaD:31 | +| ExternalFlow.cs:315:17:315:17 | access to local variable o : Object | ExternalFlow.cs:316:33:316:33 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | ExternalFlow.cs:315:17:315:17 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:316:13:316:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:317:18:317:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | | +| ExternalFlow.cs:316:33:316:33 | access to local variable o : Object | ExternalFlow.cs:316:13:316:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | MaD:26 | +| ExternalFlow.cs:317:18:317:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | provenance | MaD:27 | +| ExternalFlow.cs:322:17:322:17 | access to local variable o : Object | ExternalFlow.cs:323:39:323:39 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | ExternalFlow.cs:322:17:322:17 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:323:13:323:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:324:18:324:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | | +| ExternalFlow.cs:323:39:323:39 | access to local variable o : Object | ExternalFlow.cs:323:13:323:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | MaD:28 | +| ExternalFlow.cs:324:18:324:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | provenance | MaD:29 | +| ExternalFlow.cs:329:17:329:17 | access to local variable o : Object | ExternalFlow.cs:330:40:330:40 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | ExternalFlow.cs:329:17:329:17 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:330:13:330:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:331:18:331:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | | +| ExternalFlow.cs:330:40:330:40 | access to local variable o : Object | ExternalFlow.cs:330:13:330:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | MaD:30 | +| ExternalFlow.cs:331:18:331:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | provenance | MaD:31 | +| ExternalFlow.cs:343:17:343:17 | access to local variable o : Object | ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | ExternalFlow.cs:343:17:343:17 | access to local variable o : Object | provenance | | +| ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | provenance | | +| ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | provenance | MaD:32 | +| ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | ExternalFlow.cs:345:18:345:29 | call to method GetValue | provenance | MaD:33 | nodes | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | @@ -261,24 +268,30 @@ nodes | ExternalFlow.cs:279:22:279:22 | access to local variable j : Object | semmle.label | access to local variable j : Object | | ExternalFlow.cs:281:18:281:21 | this access : J | semmle.label | this access : J | | ExternalFlow.cs:281:18:281:27 | access to property Prop1 | semmle.label | access to property Prop1 | -| ExternalFlow.cs:313:17:313:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:314:13:314:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | -| ExternalFlow.cs:314:33:314:33 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | semmle.label | call to method GetMySyntheticField | -| ExternalFlow.cs:315:18:315:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | -| ExternalFlow.cs:319:17:319:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:320:13:320:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | -| ExternalFlow.cs:320:39:320:39 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | semmle.label | call to method GetMyNestedSyntheticField | -| ExternalFlow.cs:321:18:321:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | -| ExternalFlow.cs:325:17:325:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:326:13:326:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | -| ExternalFlow.cs:326:40:326:40 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | semmle.label | call to method GetMyFieldOnSyntheticField | -| ExternalFlow.cs:327:18:327:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | +| ExternalFlow.cs:315:17:315:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:316:13:316:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | +| ExternalFlow.cs:316:33:316:33 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | semmle.label | call to method GetMySyntheticField | +| ExternalFlow.cs:317:18:317:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | +| ExternalFlow.cs:322:17:322:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:323:13:323:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | +| ExternalFlow.cs:323:39:323:39 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | semmle.label | call to method GetMyNestedSyntheticField | +| ExternalFlow.cs:324:18:324:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | +| ExternalFlow.cs:329:17:329:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:330:13:330:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | +| ExternalFlow.cs:330:40:330:40 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | semmle.label | call to method GetMyFieldOnSyntheticField | +| ExternalFlow.cs:331:18:331:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | +| ExternalFlow.cs:343:17:343:17 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | semmle.label | [post] access to local variable l : Library [synthetic X] : Object | +| ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | semmle.label | access to local variable l : Library [synthetic X] : Object | +| ExternalFlow.cs:345:18:345:29 | call to method GetValue | semmle.label | call to method GetValue | subpaths | ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map : T[] [element] : Object | invalidModelRow @@ -308,6 +321,7 @@ invalidModelRow | ExternalFlow.cs:240:18:240:18 | access to local variable o | ExternalFlow.cs:238:21:238:28 | object creation of type HC : HC | ExternalFlow.cs:240:18:240:18 | access to local variable o | $@ | ExternalFlow.cs:238:21:238:28 | object creation of type HC : HC | object creation of type HC : HC | | ExternalFlow.cs:258:18:258:18 | access to local variable b | ExternalFlow.cs:256:20:256:31 | object creation of type Object : Object | ExternalFlow.cs:258:18:258:18 | access to local variable b | $@ | ExternalFlow.cs:256:20:256:31 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:281:18:281:27 | access to property Prop1 | ExternalFlow.cs:278:21:278:32 | object creation of type Object : Object | ExternalFlow.cs:281:18:281:27 | access to property Prop1 | $@ | ExternalFlow.cs:278:21:278:32 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | $@ | ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | $@ | ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | $@ | ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | $@ | ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | $@ | ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | $@ | ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:345:18:345:29 | call to method GetValue | ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | ExternalFlow.cs:345:18:345:29 | call to method GetValue | $@ | ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml index f2cf9972a73d..a582a581cf12 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml @@ -43,6 +43,8 @@ extensions: - ["My.Qltest", "K", false, "GetMyNestedSyntheticField", "()", "", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField1].SyntheticField[MySyntheticField1.MyNestedSyntheticField]", "ReturnValue", "value", "manual"] - ["My.Qltest", "K", false, "SetMyFieldOnSyntheticField", "(System.Object)", "", "Argument[0]", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]", "value", "manual"] - ["My.Qltest", "K", false, "GetMyFieldOnSyntheticField", "()", "", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "Library", false, "SetValue", "(System.Object)", "", "Argument[0]", "Argument[this].SyntheticField[X]", "value", "dfc-generated"] + - ["My.Qltest", "Library", false, "GetValue", "()", "", "Argument[this].SyntheticField[X]", "ReturnValue", "value", "dfc-generated"] - addsTo: pack: codeql/csharp-all diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql index b2777d4bc346..bed1f3ec0944 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql +++ b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql @@ -3,7 +3,7 @@ import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { - string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c) } + string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c, _) } string getKind() { result = "contentbased-summary" } } diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs b/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs index 5a110fc02aac..d7256b1019c4 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs +++ b/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs @@ -13,21 +13,21 @@ public class BasicFlow private string tainted; // summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;df-generated + // contentbased-summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;dfc-generated public BasicFlow ReturnThis(object input) { return this; } // summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;value;dfc-generated public string ReturnParam0(string input0, object input1) { return input0; } // summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;taint;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;value;df-generated + // contentbased-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;value;dfc-generated public object ReturnParam1(string input0, object input1) { return input1; @@ -35,29 +35,29 @@ public object ReturnParam1(string input0, object input1) // summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;taint;df-generated // summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;taint;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;value;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;value;df-generated + // contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;value;dfc-generated + // contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;value;dfc-generated public object ReturnParamMultiple(object input0, object input1) { return (System.DateTime.Now.DayOfWeek == System.DayOfWeek.Monday) ? input0 : input1; } // summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;df-generated + // contentbased-summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;dfc-generated public string ReturnSubstring(string s) { return s.Substring(0, 1); } // summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this].SyntheticField[Models.BasicFlow.tainted];value;df-generated + // contentbased-summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this].SyntheticField[Models.BasicFlow.tainted];value;dfc-generated public void SetField(string s) { tainted = s; } // summary=Models;BasicFlow;false;ReturnField;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;BasicFlow;false;ReturnField;();;Argument[this].SyntheticField[Models.BasicFlow.tainted];ReturnValue;value;df-generated + // contentbased-summary=Models;BasicFlow;false;ReturnField;();;Argument[this].SyntheticField[Models.BasicFlow.tainted];ReturnValue;value;dfc-generated public string ReturnField() { return tainted; @@ -69,91 +69,91 @@ public class CollectionFlow private readonly string tainted; // summary=Models;CollectionFlow;false;CollectionFlow;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;CollectionFlow;(System.String);;Argument[0];Argument[this].SyntheticField[Models.CollectionFlow.tainted];value;df-generated + // contentbased-summary=Models;CollectionFlow;false;CollectionFlow;(System.String);;Argument[0];Argument[this].SyntheticField[Models.CollectionFlow.tainted];value;dfc-generated public CollectionFlow(string s) { tainted = s; } // summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;value;dfc-generated public object ReturnArrayElement(object[] input) { return input[0]; } // summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;value;dfc-generated public void AssignToArray(object data, object[] target) { target[0] = data; } // summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this];Argument[0].Element;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;dfc-generated public void AssignFieldToArray(object[] target) { target[0] = tainted; } // summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;value;dfc-generated public object ReturnListElement(List input) { return input[0]; } // summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List,System.Object);;Argument[1];Argument[0].Element;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List,System.Object);;Argument[1];Argument[0].Element;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List,System.Object);;Argument[1];Argument[0].Element;value;dfc-generated public void AddToList(List input, object data) { input.Add(data); } // summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List);;Argument[this];Argument[0].Element;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;dfc-generated public void AddFieldToList(List input) { input.Add(tainted); } // summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this].SyntheticField[Models.CollectionFlow.tainted];ReturnValue.Element;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this].SyntheticField[Models.CollectionFlow.tainted];ReturnValue.Element;value;dfc-generated public List ReturnFieldInAList() { return new List { tainted }; } // SPURIOUS-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0];ReturnValue;value;dfc-generated public string[] ReturnComplexTypeArray(string[] a) { return a; } // SPURIOUS-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0];ReturnValue;value;dfc-generated public List ReturnBulkTypeList(List a) { return a; } // SPURIOUS-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0];ReturnValue;value;dfc-generated public Dictionary ReturnComplexTypeDictionary(Dictionary a) { return a; } // SPURIOUS-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0];ReturnValue;value;dfc-generated public Array ReturnUntypedArray(Array a) { return a; } // SPURIOUS-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0];ReturnValue;value;dfc-generated public IList ReturnUntypedList(IList a) { return a; @@ -187,28 +187,28 @@ public class IEnumerableFlow private readonly string tainted; // summary=Models;IEnumerableFlow;false;IEnumerableFlow;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;IEnumerableFlow;false;IEnumerableFlow;(System.String);;Argument[0];Argument[this].SyntheticField[Models.IEnumerableFlow.tainted];value;df-generated + // contentbased-summary=Models;IEnumerableFlow;false;IEnumerableFlow;(System.String);;Argument[0];Argument[this].SyntheticField[Models.IEnumerableFlow.tainted];value;dfc-generated public IEnumerableFlow(string s) { tainted = s; } // SPURIOUS-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;value;dfc-generated public IEnumerable ReturnIEnumerable(IEnumerable input) { return input; } // summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;dfc-generated public object ReturnIEnumerableElement(IEnumerable input) { return input.First(); } // summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this].SyntheticField[Models.IEnumerableFlow.tainted];ReturnValue.Element;value;df-generated + // contentbased-summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this].SyntheticField[Models.IEnumerableFlow.tainted];ReturnValue.Element;value;dfc-generated public IEnumerable ReturnFieldInIEnumerable() { return new List { tainted }; @@ -220,49 +220,49 @@ public class GenericFlow private T tainted; // summary=Models;GenericFlow;false;SetGenericField;(T);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;GenericFlow;false;SetGenericField;(T);;Argument[0];Argument[this].SyntheticField[Models.GenericFlow`1.tainted];value;df-generated + // contentbased-summary=Models;GenericFlow;false;SetGenericField;(T);;Argument[0];Argument[this].SyntheticField[Models.GenericFlow`1.tainted];value;dfc-generated public void SetGenericField(T t) { tainted = t; } // summary=Models;GenericFlow;false;ReturnGenericField;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;GenericFlow;false;ReturnGenericField;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue;value;df-generated + // contentbased-summary=Models;GenericFlow;false;ReturnGenericField;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue;value;dfc-generated public T ReturnGenericField() { return tainted; } // summary=Models;GenericFlow;false;AddFieldToGenericList;(System.Collections.Generic.List);;Argument[this];Argument[0].Element;taint;df-generated - // contentbased-summary=Models;GenericFlow;false;AddFieldToGenericList;(System.Collections.Generic.List);;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];Argument[0].Element;value;df-generated + // contentbased-summary=Models;GenericFlow;false;AddFieldToGenericList;(System.Collections.Generic.List);;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];Argument[0].Element;value;dfc-generated public void AddFieldToGenericList(List input) { input.Add(tainted); } // summary=Models;GenericFlow;false;ReturnFieldInGenericList;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;GenericFlow;false;ReturnFieldInGenericList;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue.Element;value;df-generated + // contentbased-summary=Models;GenericFlow;false;ReturnFieldInGenericList;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue.Element;value;dfc-generated public List ReturnFieldInGenericList() { return new List { tainted }; } // summary=Models;GenericFlow;false;ReturnGenericParam;(S);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;GenericFlow;false;ReturnGenericParam;(S);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;GenericFlow;false;ReturnGenericParam;(S);;Argument[0];ReturnValue;value;dfc-generated public S ReturnGenericParam(S input) { return input; } // summary=Models;GenericFlow;false;ReturnGenericElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;GenericFlow;false;ReturnGenericElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=Models;GenericFlow;false;ReturnGenericElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;value;dfc-generated public S ReturnGenericElement(List input) { return input[0]; } // summary=Models;GenericFlow;false;AddToGenericList;(System.Collections.Generic.List,S);;Argument[1];Argument[0].Element;taint;df-generated - // contentbased-summary=Models;GenericFlow;false;AddToGenericList;(System.Collections.Generic.List,S);;Argument[1];Argument[0].Element;value;df-generated + // contentbased-summary=Models;GenericFlow;false;AddToGenericList;(System.Collections.Generic.List,S);;Argument[1];Argument[0].Element;value;dfc-generated public void AddToGenericList(List input, S data) { input.Add(data); @@ -272,7 +272,7 @@ public void AddToGenericList(List input, S data) public abstract class BaseClassFlow { // summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;dfc-generated public virtual object ReturnParam(object input) { return input; @@ -282,7 +282,7 @@ public virtual object ReturnParam(object input) public class DerivedClass1Flow : BaseClassFlow { // summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;taint;df-generated - // contentbased-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;value;df-generated + // contentbased-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;value;dfc-generated public string ReturnParam1(string input0, string input1) { return input1; @@ -292,14 +292,14 @@ public string ReturnParam1(string input0, string input1) public class DerivedClass2Flow : BaseClassFlow { // summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;dfc-generated public override object ReturnParam(object input) { return input; } // summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;value;dfc-generated public string ReturnParam0(string input0, int input1) { return input0; @@ -311,7 +311,7 @@ public class OperatorFlow public readonly object Field; // summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this].Field[Models.OperatorFlow.Field];value;df-generated + // contentbased-summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this].Field[Models.OperatorFlow.Field];value;dfc-generated public OperatorFlow(object o) { Field = o; @@ -319,7 +319,7 @@ public OperatorFlow(object o) // Flow Summary. // summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;value;dfc-generated public static OperatorFlow operator +(OperatorFlow a, OperatorFlow b) { return a; @@ -360,7 +360,7 @@ public override bool Equals(object obj) } // summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;value;dfc-generated public string Equals(string s) { return s; @@ -378,14 +378,14 @@ public class Properties private string tainted; // summary=Models;Properties;false;get_Prop1;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;Properties;false;get_Prop1;();;Argument[this].SyntheticField[Models.Properties.tainted];ReturnValue;value;df-generated + // contentbased-summary=Models;Properties;false;get_Prop1;();;Argument[this].SyntheticField[Models.Properties.tainted];ReturnValue;value;dfc-generated public string Prop1 { get { return tainted; } } // summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this].SyntheticField[Models.Properties.tainted];value;df-generated + // contentbased-summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this].SyntheticField[Models.Properties.tainted];value;dfc-generated public string Prop2 { set { tainted = value; } @@ -566,7 +566,7 @@ public abstract class BasePublic public class AImplBasePublic : BasePublic { // summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;value;dfc-generated public override string Id(string x) { return x; @@ -596,7 +596,7 @@ private abstract class C : IPublic2 public class BImpl : B { // summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;value;dfc-generated public override string Id(string x) { return x; @@ -606,7 +606,7 @@ public override string Id(string x) private class CImpl : C { // summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated + // contentbased-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;value;dfc-generated public override string Id(string x) { return x; @@ -628,16 +628,40 @@ public class DImpl : D private readonly string tainted; // summary=Models;Inheritance+DImpl;false;DImpl;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;Inheritance+DImpl;false;DImpl;(System.String);;Argument[0];Argument[this].SyntheticField[Models.Inheritance+DImpl.tainted];value;df-generated + // contentbased-summary=Models;Inheritance+DImpl;false;DImpl;(System.String);;Argument[0];Argument[this].SyntheticField[Models.Inheritance+DImpl.tainted];value;dfc-generated public DImpl(string s) { tainted = s; } // summary=Models;Inheritance+IPublic3;true;get_Prop;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;Inheritance+DImpl;true;get_Prop;();;Argument[this].SyntheticField[Models.Inheritance+DImpl.tainted];ReturnValue;value;df-generated + // contentbased-summary=Models;Inheritance+DImpl;true;get_Prop;();;Argument[this].SyntheticField[Models.Inheritance+DImpl.tainted];ReturnValue;value;dfc-generated public override string Prop { get { return tainted; } } } + + public abstract class BaseContent + { + public abstract object GetValue(); + + public abstract void SetValue(object o); + } + + private class Content1 : BaseContent + { + private object field; + + // summary=Models;Inheritance+BaseContent;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated + public override object GetValue() + { + return field; + } + + // summary=Models;Inheritance+BaseContent;true;SetValue;(System.Object);;Argument[0];Argument[this];taint;df-generated + public override void SetValue(object o) + { + field = o; + } + } } public class MemberFlow @@ -650,14 +674,14 @@ public class C } // summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0].Property[Models.MemberFlow+C.Prop];ReturnValue;value;df-generated + // contentbased-summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0].Property[Models.MemberFlow+C.Prop];ReturnValue;value;dfc-generated public string M1(C c) { return c.Prop; } // summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0].Field[Models.MemberFlow+C.Field];ReturnValue;value;df-generated + // contentbased-summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0].Field[Models.MemberFlow+C.Field];ReturnValue;value;dfc-generated public string M2(C c) { return c.Field; @@ -667,7 +691,7 @@ public string M2(C c) public class IDictionaryFlow { // summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary,System.Object);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary,System.Object);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair`2.Value];ReturnValue;value;df-generated + // contentbased-summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary,System.Object);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair`2.Value];ReturnValue;value;dfc-generated public object ReturnIDictionaryValue(IDictionary input, object key) { return input[key]; @@ -680,21 +704,21 @@ public class NestedFieldFlow public NestedFieldFlow FieldB; // summary=Models;NestedFieldFlow;false;Move;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;NestedFieldFlow;false;Move;();;Argument[this].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldB];value;df-generated + // contentbased-summary=Models;NestedFieldFlow;false;Move;();;Argument[this].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldB];value;dfc-generated public NestedFieldFlow Move() { return new NestedFieldFlow() { FieldB = this.FieldA }; } // summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this].Field[Models.NestedFieldFlow.FieldB].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;df-generated + // contentbased-summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this].Field[Models.NestedFieldFlow.FieldB].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;dfc-generated public NestedFieldFlow MoveNested() { return new NestedFieldFlow() { FieldA = FieldB.Move() }; } // summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this].Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;df-generated + // contentbased-summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this].Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;dfc-generated public NestedFieldFlow ReverseFields() { var x = new NestedFieldFlow() { FieldB = this.FieldA.FieldB }; @@ -715,28 +739,28 @@ public class SyntheticFields private string brokenChainEnd; // summary=Models;SyntheticFields;false;SyntheticFields;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;SyntheticFields;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields.value1];value;df-generated + // contentbased-summary=Models;SyntheticFields;false;SyntheticFields;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields.value1];value;dfc-generated public SyntheticFields(string v1) { value1 = v1; } // summary=Models;SyntheticFields;false;GetValue1;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;GetValue1;();;Argument[this].SyntheticField[Models.SyntheticFields.value1];ReturnValue;value;df-generated + // contentbased-summary=Models;SyntheticFields;false;GetValue1;();;Argument[this].SyntheticField[Models.SyntheticFields.value1];ReturnValue;value;dfc-generated public string GetValue1() { return value1; } // summary=Models;SyntheticFields;false;GetValue2;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;GetValue2;();;Argument[this].SyntheticField[Models.SyntheticFields.value2];ReturnValue;value;df-generated + // contentbased-summary=Models;SyntheticFields;false;GetValue2;();;Argument[this].SyntheticField[Models.SyntheticFields.value2];ReturnValue;value;dfc-generated public string GetValue2() { return value2; } // summary=Models;SyntheticFields;false;SetValue2;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;SetValue2;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields.value2];value;df-generated + // contentbased-summary=Models;SyntheticFields;false;SetValue2;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields.value2];value;dfc-generated public void SetValue2(string v2) { value2 = v2; @@ -750,21 +774,21 @@ public void SetValue3(string v3) } // summary=Models;SyntheticFields;false;SetChainBegin;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;SetChainBegin;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields.chainBegin];value;df-generated + // contentbased-summary=Models;SyntheticFields;false;SetChainBegin;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields.chainBegin];value;dfc-generated public void SetChainBegin(string v) { chainBegin = v; } // neutral=Models;SyntheticFields;CopyChainValue;();summary;df-generated - // contentbased-summary=Models;SyntheticFields;false;CopyChainValue;();;Argument[this].SyntheticField[Models.SyntheticFields.chainBegin];Argument[this].SyntheticField[Models.SyntheticFields.chainEnd];value;df-generated + // contentbased-summary=Models;SyntheticFields;false;CopyChainValue;();;Argument[this].SyntheticField[Models.SyntheticFields.chainBegin];Argument[this].SyntheticField[Models.SyntheticFields.chainEnd];value;dfc-generated public void CopyChainValue() { chainEnd = chainBegin; } // summary=Models;SyntheticFields;false;GetChainEnd;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;GetChainEnd;();;Argument[this].SyntheticField[Models.SyntheticFields.chainEnd];ReturnValue;value;df-generated + // contentbased-summary=Models;SyntheticFields;false;GetChainEnd;();;Argument[this].SyntheticField[Models.SyntheticFields.chainEnd];ReturnValue;value;dfc-generated public string GetChainEnd() { return chainEnd; @@ -789,14 +813,14 @@ public class InnerSyntheticFields private readonly string value; // summary=Models;SyntheticFields+InnerSyntheticFields;false;InnerSyntheticFields;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;SyntheticFields+InnerSyntheticFields;false;InnerSyntheticFields;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields+InnerSyntheticFields.value];value;df-generated + // contentbased-summary=Models;SyntheticFields+InnerSyntheticFields;false;InnerSyntheticFields;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticFields+InnerSyntheticFields.value];value;dfc-generated public InnerSyntheticFields(string v) { value = v; } // summary=Models;SyntheticFields+InnerSyntheticFields;false;GetValue;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;SyntheticFields+InnerSyntheticFields;false;GetValue;();;Argument[this].SyntheticField[Models.SyntheticFields+InnerSyntheticFields.value];ReturnValue;value;df-generated + // contentbased-summary=Models;SyntheticFields+InnerSyntheticFields;false;GetValue;();;Argument[this].SyntheticField[Models.SyntheticFields+InnerSyntheticFields.value];ReturnValue;value;dfc-generated public string GetValue() { return value; @@ -804,7 +828,7 @@ public string GetValue() } // summary=Models;SyntheticFields;false;MakeInner;(System.String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=Models;SyntheticFields;false;MakeInner;(System.String);;Argument[0];ReturnValue.SyntheticField[Models.SyntheticFields+InnerSyntheticFields.value];value;df-generated + // contentbased-summary=Models;SyntheticFields;false;MakeInner;(System.String);;Argument[0];ReturnValue.SyntheticField[Models.SyntheticFields+InnerSyntheticFields.value];value;dfc-generated public InnerSyntheticFields MakeInner(string v) { return new InnerSyntheticFields(v); @@ -818,14 +842,14 @@ public class SyntheticProperties private string Prop2 { get; set; } // summary=Models;SyntheticProperties;false;SyntheticProperties;(System.String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=Models;SyntheticProperties;false;SyntheticProperties;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticProperties.Prop1];value;df-generated + // contentbased-summary=Models;SyntheticProperties;false;SyntheticProperties;(System.String);;Argument[0];Argument[this].SyntheticField[Models.SyntheticProperties.Prop1];value;dfc-generated public SyntheticProperties(string v1) { Prop1 = v1; } // summary=Models;SyntheticProperties;false;GetProp1;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=Models;SyntheticProperties;false;GetProp1;();;Argument[this].SyntheticField[Models.SyntheticProperties.Prop1];ReturnValue;value;df-generated + // contentbased-summary=Models;SyntheticProperties;false;GetProp1;();;Argument[this].SyntheticField[Models.SyntheticProperties.Prop1];ReturnValue;value;dfc-generated public string GetProp1() { return Prop1; @@ -838,3 +862,102 @@ public void SetProp2(string v) Prop2 = v; } } + +public class SyntheticCollections +{ + private object[] array; + + // summary=Models;SyntheticCollections;false;SyntheticCollections;(System.Object[]);;Argument[0].Element;Argument[this];taint;df-generated + // contentbased-summary=Models;SyntheticCollections;false;SyntheticCollections;(System.Object[]);;Argument[0];Argument[this].SyntheticField[Models.SyntheticCollections.array];value;dfc-generated + public SyntheticCollections(object[] array) + { + this.array = array; + } + + // summary=Models;SyntheticCollections;false;GetElement;(System.Int32);;Argument[this];ReturnValue;taint;df-generated + // contentbased-summary=Models;SyntheticCollections;false;GetElement;(System.Int32);;Argument[this].SyntheticField[Models.SyntheticCollections.array].Element;ReturnValue;value;dfc-generated + public object GetElement(int index) + { + return array[index]; + } +} + +public class Fanout +{ + + public abstract class Base1 + { + public abstract string GetValue(); + } + + public abstract class Base2 : Base1 { } + + public class Impl1 : Base1 + { + public string Prop { get; set; } + + // summary=Models;Fanout+Base1;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated + // contentbased-summary=Models;Fanout+Impl1;true;GetValue;();;Argument[this].Property[Models.Fanout+Impl1.Prop];ReturnValue;value;dfc-generated + public override string GetValue() + { + return Prop; + } + } + + public class Impl2 : Base2 + { + public string Prop { get; set; } + + // summary=Models;Fanout+Base1;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated + // contentbased-summary=Models;Fanout+Impl2;true;GetValue;();;Argument[this].Property[Models.Fanout+Impl2.Prop];ReturnValue;value;dfc-generated + public override string GetValue() + { + return Prop; + } + } + + public class Impl3 : Base2 + { + public string Prop { get; set; } + + // summary=Models;Fanout+Base1;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated + // contentbased-summary=Models;Fanout+Impl3;true;GetValue;();;Argument[this].Property[Models.Fanout+Impl3.Prop];ReturnValue;value;dfc-generated + public override string GetValue() + { + return Prop; + } + } + + public class Impl4 : Base2 + { + public string Prop { get; set; } + + // summary=Models;Fanout+Base1;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated + // contentbased-summary=Models;Fanout+Impl4;true;GetValue;();;Argument[this].Property[Models.Fanout+Impl4.Prop];ReturnValue;value;dfc-generated + public override string GetValue() + { + return Prop; + } + } + + // summary=Models;Fanout;false;ConcatValueOnBase1;(System.String,Models.Fanout+Base1);;Argument[0];ReturnValue;taint;df-generated + // summary=Models;Fanout;false;ConcatValueOnBase1;(System.String,Models.Fanout+Base1);;Argument[1];ReturnValue;taint;df-generated + // No content based summaries are expected for this method on parameter `b1` + // as the fanout (number of content flows) exceeds the limit of 3. + // contentbased-summary=Models;Fanout;false;ConcatValueOnBase1;(System.String,Models.Fanout+Base1);;Argument[0];ReturnValue;taint;dfc-generated + public string ConcatValueOnBase1(string other, Base1 b1) + { + return other + b1.GetValue(); + } + + // summary=Models;Fanout;false;ConcatValueOnBase2;(System.String,Models.Fanout+Base2);;Argument[0];ReturnValue;taint;df-generated + // summary=Models;Fanout;false;ConcatValueOnBase2;(System.String,Models.Fanout+Base2);;Argument[1];ReturnValue;taint;df-generated + // contentbased-summary=Models;Fanout;false;ConcatValueOnBase2;(System.String,Models.Fanout+Base2);;Argument[0];ReturnValue;taint;dfc-generated + // contentbased-summary=Models;Fanout;false;ConcatValueOnBase2;(System.String,Models.Fanout+Base2);;Argument[1].Property[Models.Fanout+Impl2.Prop];ReturnValue;taint;dfc-generated + // contentbased-summary=Models;Fanout;false;ConcatValueOnBase2;(System.String,Models.Fanout+Base2);;Argument[1].Property[Models.Fanout+Impl3.Prop];ReturnValue;taint;dfc-generated + // contentbased-summary=Models;Fanout;false;ConcatValueOnBase2;(System.String,Models.Fanout+Base2);;Argument[1].Property[Models.Fanout+Impl4.Prop];ReturnValue;taint;dfc-generated + public string ConcatValueOnBase2(string other, Base2 b2) + { + return other + b2.GetValue(); + } +} diff --git a/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index ad3008e54a59..b1340e2c0d33 100644 --- a/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -9,5 +9,5 @@ import internal.CaptureModels from DataFlowSummaryTargetApi api, string flow -where flow = ContentSensitive::captureFlow(api) +where flow = ContentSensitive::captureFlow(api, _) select flow order by flow diff --git a/java/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql b/java/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql new file mode 100644 index 000000000000..6ad943137697 --- /dev/null +++ b/java/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql @@ -0,0 +1,13 @@ +/** + * @name Capture mixed neutral models. + * @description Finds neutral models to be used by other queries. + * @kind diagnostic + * @id java/utils/modelgenerator/mixed-neutral-models + * @tags modelgenerator + */ + +import internal.CaptureModels + +from DataFlowSummaryTargetApi api, string noflow +where noflow = captureMixedNeutral(api) +select noflow order by noflow diff --git a/java/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql new file mode 100644 index 000000000000..b6f6fc9ff3aa --- /dev/null +++ b/java/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql @@ -0,0 +1,13 @@ +/** + * @name Capture mixed summary models. + * @description Finds applicable summary models to be used by other queries. + * @kind diagnostic + * @id java/utils/modelgenerator/mixed-summary-models + * @tags modelgenerator + */ + +import internal.CaptureModels + +from DataFlowSummaryTargetApi api, string flow +where flow = captureMixedFlow(api, _) +select flow order by flow diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll index 6724527a1b17..6239b535c986 100644 --- a/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -110,7 +110,10 @@ module ModelGeneratorInput implements ModelGeneratorInputSig 100) { return two; @@ -30,31 +30,31 @@ public String returnMultipleParameters(String one, String two) { } // summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated - // contentbased-summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;df-generated + // contentbased-summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;dfc-generated public String returnArrayElement(String[] input) { return input[0]; } // summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated - // contentbased-summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;df-generated + // contentbased-summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;dfc-generated public String returnVarArgElement(String... input) { return input[0]; } // summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;value;dfc-generated public String returnCollectionElement(List input) { return input.get(0); } // summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;value;dfc-generated public String returnIteratorElement(Iterator input) { return input.next(); } // summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;taint;df-generated - // contentbased-summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;value;df-generated + // contentbased-summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;value;dfc-generated public String returnIterableElement(Iterable input) { return input.iterator().next(); } @@ -65,19 +65,19 @@ public Class mapType(Class input) { } // summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated - // contentbased-summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated + // contentbased-summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;dfc-generated public void writeChunked(byte[] data, OutputStream output) throws IOException { output.write(data, 0, data.length); } // summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated - // contentbased-summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated + // contentbased-summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;dfc-generated public void writeChunked(char[] data, OutputStream output) throws IOException { output.write(String.valueOf(data).getBytes(), 0, data.length); } // summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;taint;df-generated - // contentbased-summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;value;df-generated + // contentbased-summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;value;dfc-generated public void addTo(String data, List target) { target.add(data); } diff --git a/java/ql/test/utils/modelgenerator/dataflow/p/Pojo.java b/java/ql/test/utils/modelgenerator/dataflow/p/Pojo.java index 3e83c7150c1e..1c30f83bccfa 100644 --- a/java/ql/test/utils/modelgenerator/dataflow/p/Pojo.java +++ b/java/ql/test/utils/modelgenerator/dataflow/p/Pojo.java @@ -34,21 +34,21 @@ int length() { // summary=p;Pojo;false;Pojo;(Byte[],char[]);;Argument[0];Argument[this];taint;df-generated // summary=p;Pojo;false;Pojo;(Byte[],char[]);;Argument[1];Argument[this];taint;df-generated - // contentbased-summary=p;Pojo;false;Pojo;(Byte[],char[]);;Argument[0];Argument[this].SyntheticField[p.Pojo.byteObjectArray];value;df-generated - // contentbased-summary=p;Pojo;false;Pojo;(Byte[],char[]);;Argument[1];Argument[this].SyntheticField[p.Pojo.charArray];value;df-generated + // contentbased-summary=p;Pojo;false;Pojo;(Byte[],char[]);;Argument[0];Argument[this].SyntheticField[p.Pojo.byteObjectArray];value;dfc-generated + // contentbased-summary=p;Pojo;false;Pojo;(Byte[],char[]);;Argument[1];Argument[this].SyntheticField[p.Pojo.charArray];value;dfc-generated public Pojo(Byte[] byteObjectArray, char[] charArray) { this.byteObjectArray = byteObjectArray; this.charArray = charArray; } // summary=p;Pojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo;false;getValue;();;Argument[this].SyntheticField[p.Pojo.value];ReturnValue;value;df-generated + // contentbased-summary=p;Pojo;false;getValue;();;Argument[this].SyntheticField[p.Pojo.value];ReturnValue;value;dfc-generated public String getValue() { return value; } // summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo.value];value;df-generated + // contentbased-summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo.value];value;dfc-generated public void setValue(String value) { this.value = value; } @@ -75,19 +75,19 @@ public int[] getPrimitiveArray() { } // summary=p;Pojo;false;getCharArray;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo;false;getCharArray;();;Argument[this].SyntheticField[p.Pojo.charArray];ReturnValue;value;df-generated + // contentbased-summary=p;Pojo;false;getCharArray;();;Argument[this].SyntheticField[p.Pojo.charArray];ReturnValue;value;dfc-generated public char[] getCharArray() { return charArray; } // summary=p;Pojo;false;getByteArray;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo;false;getByteArray;();;Argument[this].Field[p.Pojo.byteArray];ReturnValue;value;df-generated + // contentbased-summary=p;Pojo;false;getByteArray;();;Argument[this].Field[p.Pojo.byteArray];ReturnValue;value;dfc-generated public byte[] getByteArray() { return byteArray; } // summary=p;Pojo;false;setByteArray;(byte[]);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=p;Pojo;false;setByteArray;(byte[]);;Argument[0];Argument[this].Field[p.Pojo.byteArray];value;df-generated + // contentbased-summary=p;Pojo;false;setByteArray;(byte[]);;Argument[0];Argument[this].Field[p.Pojo.byteArray];value;dfc-generated public void setByteArray(byte[] value) { byteArray = value; } @@ -114,7 +114,7 @@ public List getBoxedChars() { } // summary=p;Pojo;false;getBoxedBytes;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo;false;getBoxedBytes;();;Argument[this].SyntheticField[p.Pojo.byteObjectArray];ReturnValue;value;df-generated + // contentbased-summary=p;Pojo;false;getBoxedBytes;();;Argument[this].SyntheticField[p.Pojo.byteObjectArray];ReturnValue;value;dfc-generated public Byte[] getBoxedBytes() { return byteObjectArray; } @@ -130,25 +130,25 @@ public BigDecimal getBigDecimal() { } // summary=p;Pojo;false;fillIn;(List);;Argument[this];Argument[0].Element;taint;df-generated - // contentbased-summary=p;Pojo;false;fillIn;(List);;Argument[this].SyntheticField[p.Pojo.value];Argument[0].Element;value;df-generated + // contentbased-summary=p;Pojo;false;fillIn;(List);;Argument[this].SyntheticField[p.Pojo.value];Argument[0].Element;value;dfc-generated public void fillIn(List target) { target.add(value); } // summary=p;Pojo;false;setStringValue1;(String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=p;Pojo;false;setStringValue1;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo.stringValue1];value;df-generated + // contentbased-summary=p;Pojo;false;setStringValue1;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo.stringValue1];value;dfc-generated public void setStringValue1(String value) { this.stringValue1 = value; } // neutral=p;Pojo;copyStringValue;();summary;df-generated - // contentbased-summary=p;Pojo;false;copyStringValue;();;Argument[this].SyntheticField[p.Pojo.stringValue1];Argument[this].SyntheticField[p.Pojo.stringValue2];value;df-generated + // contentbased-summary=p;Pojo;false;copyStringValue;();;Argument[this].SyntheticField[p.Pojo.stringValue1];Argument[this].SyntheticField[p.Pojo.stringValue2];value;dfc-generated public void copyStringValue() { this.stringValue2 = this.stringValue1; } // summary=p;Pojo;false;getStringValue2;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo;false;getStringValue2;();;Argument[this].SyntheticField[p.Pojo.stringValue2];ReturnValue;value;df-generated + // contentbased-summary=p;Pojo;false;getStringValue2;();;Argument[this].SyntheticField[p.Pojo.stringValue2];ReturnValue;value;dfc-generated public String getStringValue2() { return this.stringValue2; } @@ -157,20 +157,20 @@ public class InnerPojo { private String value; // summary=p;Pojo$InnerPojo;true;InnerPojo;(String);;Argument[0];Argument[this];taint;df-generated - // contentbased-summary=p;Pojo$InnerPojo;true;InnerPojo;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo$InnerPojo.value];value;df-generated + // contentbased-summary=p;Pojo$InnerPojo;true;InnerPojo;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo$InnerPojo.value];value;dfc-generated public InnerPojo(String value) { this.value = value; } // summary=p;Pojo$InnerPojo;true;getValue;();;Argument[this];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo$InnerPojo;true;getValue;();;Argument[this].SyntheticField[p.Pojo$InnerPojo.value];ReturnValue;value;df-generated + // contentbased-summary=p;Pojo$InnerPojo;true;getValue;();;Argument[this].SyntheticField[p.Pojo$InnerPojo.value];ReturnValue;value;dfc-generated public String getValue() { return value; } } // summary=p;Pojo;false;makeInnerPojo;(String);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=p;Pojo;false;makeInnerPojo;(String);;Argument[0];ReturnValue.SyntheticField[p.Pojo$InnerPojo.value];value;df-generated + // contentbased-summary=p;Pojo;false;makeInnerPojo;(String);;Argument[0];ReturnValue.SyntheticField[p.Pojo$InnerPojo.value];value;dfc-generated public InnerPojo makeInnerPojo(String value) { return new InnerPojo(value); } diff --git a/java/ql/test/utils/modelgenerator/dataflow/p/PrivateFlowViaPublicInterface.java b/java/ql/test/utils/modelgenerator/dataflow/p/PrivateFlowViaPublicInterface.java index 8b9397fdb3ca..282d0b077b7e 100644 --- a/java/ql/test/utils/modelgenerator/dataflow/p/PrivateFlowViaPublicInterface.java +++ b/java/ql/test/utils/modelgenerator/dataflow/p/PrivateFlowViaPublicInterface.java @@ -29,9 +29,6 @@ public PrivateImplWithSink(File file) { } // summary=p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[this];ReturnValue;taint;df-generated - // This summary shouldn't be created because the method is private. - // This is most likely because the lifting logic hasn't been properly adapted. - // SPURIOUS-contentbased-summary=p;PrivateFlowViaPublicInterface$PrivateImplWithSink;false;openStream;();;Argument[this].SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];ReturnValue;taint;df-generated @Override public OutputStream openStream() throws IOException { return new FileOutputStream(file); @@ -54,7 +51,7 @@ public OutputStream openStreamNone() throws IOException { } // summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue;taint;df-generated - // contentbased-summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue.SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];value;df-generated + // contentbased-summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue.SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];value;dfc-generated public static SPI createAnSPI(File file) { return new PrivateImplWithSink(file); } diff --git a/java/ql/test/utils/modelgenerator/dataflow/p/SyntheticCollections.java b/java/ql/test/utils/modelgenerator/dataflow/p/SyntheticCollections.java new file mode 100644 index 000000000000..6dd351e12bfd --- /dev/null +++ b/java/ql/test/utils/modelgenerator/dataflow/p/SyntheticCollections.java @@ -0,0 +1,17 @@ +package p; + +public class SyntheticCollections { + private String[] array; + + // summary=p;SyntheticCollections;true;SyntheticCollections;(String[]);;Argument[0].ArrayElement;Argument[this];taint;df-generated + // contentbased-summary=p;SyntheticCollections;true;SyntheticCollections;(String[]);;Argument[0];Argument[this].SyntheticField[p.SyntheticCollections.array];value;dfc-generated + public SyntheticCollections(String[] array) { + this.array = array; + } + + // summary=p;SyntheticCollections;true;getElement;(Integer);;Argument[this];ReturnValue;taint;df-generated + // contentbased-summary=p;SyntheticCollections;true;getElement;(Integer);;Argument[this].SyntheticField[p.SyntheticCollections.array].ArrayElement;ReturnValue;value;dfc-generated + public String getElement(Integer index) { + return array[index]; + } +} diff --git a/misc/scripts/models-as-data/generate_flow_model.py b/misc/scripts/models-as-data/generate_flow_model.py index 4d4407252981..cfd524066cbf 100644 --- a/misc/scripts/models-as-data/generate_flow_model.py +++ b/misc/scripts/models-as-data/generate_flow_model.py @@ -33,7 +33,8 @@ def __init__ (self, language): self.generateSources = False self.generateSummaries = False self.generateNeutrals = False - self.generateContentSummaries = False + self.generateMixedSummaries = False + self.generateMixedNeutrals = False self.generateTypeBasedSummaries = False self.dryRun = False self.dirname = "modelgenerator" @@ -51,7 +52,8 @@ def printHelp(self): --with-sources --with-summaries --with-neutrals - --with-content-summaries (Experimental). May not be used in conjunction with --with-summaries + --with-mixed-summaries (Experimental). May not be used in conjunction with --with-summaries. + --with-mixed-neutrals (Experimental). Should only be used in conjunction with --with-mixed-summaries. --with-typebased-summaries (Experimental) If none of these flags are specified, all models are generated except for the type based models. @@ -83,7 +85,7 @@ def make(language): generator.printHelp() sys.exit(0) - if "--with-summaries" in sys.argv and "--with-content-summaries" in sys.argv: + if "--with-summaries" in sys.argv and "--with-mixed-summaries" in sys.argv: generator.printHelp() sys.exit(0) @@ -103,9 +105,13 @@ def make(language): sys.argv.remove("--with-neutrals") generator.generateNeutrals = True - if "--with-content-summaries" in sys.argv: - sys.argv.remove("--with-content-summaries") - generator.generateContentSummaries = True + if "--with-mixed-summaries" in sys.argv: + sys.argv.remove("--with-mixed-summaries") + generator.generateMixedSummaries = True + + if "--with-mixed-neutrals" in sys.argv: + sys.argv.remove("--with-mixed-neutrals") + generator.generateMixedNeutrals = True if "--with-typebased-summaries" in sys.argv: sys.argv.remove("--with-typebased-summaries") @@ -115,7 +121,13 @@ def make(language): sys.argv.remove("--dry-run") generator.dryRun = True - if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNeutrals and not generator.generateTypeBasedSummaries and not generator.generateContentSummaries: + if (not generator.generateSinks and + not generator.generateSources and + not generator.generateSummaries and + not generator.generateNeutrals and + not generator.generateTypeBasedSummaries and + not generator.generateMixedSummaries and + not generator.generateMixedNeutrals): generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNeutrals = True n = len(sys.argv) @@ -173,12 +185,17 @@ def makeContent(self): else: neutralAddsTo = { } - if self.generateContentSummaries: - contentSummaryAddsTo = self.getAddsTo("CaptureContentSummaryModels.ql", helpers.summaryModelPredicate) + if self.generateMixedSummaries: + mixedSummaryAddsTo = self.getAddsTo("CaptureMixedSummaryModels.ql", helpers.summaryModelPredicate) + else: + mixedSummaryAddsTo = { } + + if self.generateMixedNeutrals: + mixedNeutralAddsTo = self.getAddsTo("CaptureMixedNeutralModels.ql", helpers.neutralModelPredicate) else: - contentSummaryAddsTo = { } + mixedNeutralAddsTo = { } - return helpers.merge(summaryAddsTo, contentSummaryAddsTo, sinkAddsTo, sourceAddsTo, neutralAddsTo) + return helpers.merge(summaryAddsTo, mixedSummaryAddsTo, sinkAddsTo, sourceAddsTo, neutralAddsTo, mixedNeutralAddsTo) def makeTypeBasedContent(self): if self.generateTypeBasedSummaries: @@ -208,7 +225,12 @@ def run(self): print("Models as data extensions generated, but not written to file.") sys.exit(0) - if self.generateSinks or self.generateSources or self.generateSummaries or self.generateNeutrals: + if (self.generateSinks or + self.generateSources or + self.generateSummaries or + self.generateNeutrals or + self.generateMixedSummaries or + self.generatedMixedNeutrals): self.save(content, ".model.yml") if self.generateTypeBasedSummaries: diff --git a/shared/dataflow/codeql/dataflow/internal/ContentDataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/ContentDataFlowImpl.qll index b972fc533ce4..1eaa84505419 100644 --- a/shared/dataflow/codeql/dataflow/internal/ContentDataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/ContentDataFlowImpl.qll @@ -272,7 +272,10 @@ module MakeImplContentDataFlow Lang> { ) } - private ContentSet getAtIndex(int i) { + /** + * Gets the content set at index `i` in this access path, if any. + */ + ContentSet getAtIndex(int i) { i = 0 and result = this.getHead() or @@ -286,23 +289,6 @@ module MakeImplContentDataFlow Lang> { i >= 0 and result = TAccessPathCons(this.getAtIndex(i), this.reverse0(i - 1)) } - - /** - * Gets the length of this access path. - */ - private int length() { - result = 0 and this = TAccessPathNil() - or - result = 1 + this.getTail().length() - } - - /** - * Gets the reversed access path, if any. - * - * Note that not all access paths have a reverse as these are not - * included by default in the IPA type. - */ - AccessPath reverse() { result = this.reverse0(this.length() - 1) } } /** diff --git a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll index b0b8901e982e..4f6a88b6b28a 100644 --- a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll @@ -171,6 +171,7 @@ module Make< [ "ai", // AI (machine learning) "df", // Dataflow (model generator) + "dfc", // Content dataflow (model generator) "tb", // Type based (model generator) "hq", // Heuristic query ] diff --git a/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll b/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll index f668d80ef1fc..f56c1b8dfff0 100644 --- a/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll +++ b/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll @@ -30,11 +30,6 @@ signature module ModelGeneratorInputSig * A Callable. */ class Callable { - /** - * Gets the number of parameters of this callable. - */ - int getNumberOfParameters(); - /** * Gets a string representation of this callable. */ @@ -561,6 +556,16 @@ module MakeModelGenerator< private module PropagateContentFlow = ContentDataFlow::Global; + private module ContentModelPrintingInput implements Printing::ModelPrintingSig { + class SummaryApi = DataFlowSummaryTargetApi; + + class SourceOrSinkApi = SourceOrSinkTargetApi; + + string getProvenance() { result = "dfc-generated" } + } + + private module ContentModelPrinting = Printing::ModelPrinting; + private string getContentOutput(ReturnNodeExt node) { result = PrintReturnNodeExt::getOutput(node) } @@ -576,15 +581,7 @@ module MakeModelGenerator< } private string getContent(PropagateContentFlow::AccessPath ap, int i) { - exists(DataFlow::ContentSet head, PropagateContentFlow::AccessPath tail | - head = ap.getHead() and - tail = ap.getTail() - | - i = 0 and - result = "." + printContent(head) - or - i > 0 and result = getContent(tail, i - 1) - ) + result = "." + printContent(ap.getAtIndex(i)) } /** @@ -605,12 +602,7 @@ module MakeModelGenerator< * Holds if the access path `ap` contains a field or synthetic field access. */ private predicate mentionsField(PropagateContentFlow::AccessPath ap) { - exists(DataFlow::ContentSet head, PropagateContentFlow::AccessPath tail | - head = ap.getHead() and - tail = ap.getTail() - | - mentionsField(tail) or isField(head) - ) + isField(ap.getAtIndex(_)) } private predicate apiFlow( @@ -626,28 +618,35 @@ module MakeModelGenerator< /** * A class of APIs relevant for modeling using content flow. * The following heuristic is applied: - * Content flow is only relevant for an API, if - * #content flow <= 2 * #parameters + 3 - * If an API produces more content flow, it is likely that - * 1. Types are not sufficiently constrained leading to a combinatorial + * Content flow is only relevant for an API on a parameter, if + * #content flow from parameter <= 3 + * If an API produces more content flow on a parameter, it is likely that + * 1. Types are not sufficiently constrained on the parameter leading to a combinatorial * explosion in dispatch and thus in the generated summaries. * 2. It is a reasonable approximation to use the non-content based flow * detection instead, as reads and stores would use a significant * part of an objects internal state. */ private class ContentDataFlowSummaryTargetApi extends DataFlowSummaryTargetApi { + private DataFlow::ParameterNode parameter; + ContentDataFlowSummaryTargetApi() { count(string input, string output | exists( - DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads, - ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores + PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt, + PropagateContentFlow::AccessPath stores | - apiFlow(this, p, reads, returnNodeExt, stores, _) and - input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and + apiFlow(this, parameter, reads, returnNodeExt, stores, _) and + input = parameterNodeAsContentInput(parameter) + printReadAccessPath(reads) and output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) ) - ) <= 2 * this.getNumberOfParameters() + 3 + ) <= 3 } + + /** + * Gets a parameter node of `this` api, where there are less than 3 possible models, if any. + */ + DataFlow::ParameterNode getARelevantParameterNode() { result = parameter } } pragma[nomagic] @@ -658,20 +657,38 @@ module MakeModelGenerator< ) { PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and returnNodeExt.getEnclosingCallable() = api and - p.(NodeExtended).getEnclosingCallable() = api + p.(NodeExtended).getEnclosingCallable() = api and + p = api.getARelevantParameterNode() } /** * Holds if any of the content sets in `path` translates into a synthetic field. */ private predicate hasSyntheticContent(PropagateContentFlow::AccessPath path) { - exists(PropagateContentFlow::AccessPath tail, DataFlow::ContentSet head | - head = path.getHead() and - tail = path.getTail() - | - exists(getSyntheticName(head)) or - hasSyntheticContent(tail) - ) + exists(getSyntheticName(path.getAtIndex(_))) + } + + private string getHashAtIndex(PropagateContentFlow::AccessPath ap, int i) { + result = getSyntheticName(ap.getAtIndex(i)) + } + + private string getReversedHash(PropagateContentFlow::AccessPath ap) { + result = strictconcat(int i | | getHashAtIndex(ap, i), "." order by i desc) + } + + private string getHash(PropagateContentFlow::AccessPath ap) { + result = strictconcat(int i | | getHashAtIndex(ap, i), "." order by i) + } + + /** + * Gets all access paths that contain the synthetic fields + * from `ap` in reverse order (if `ap` contains at least one synthetic field). + * These are the possible candidates for synthetic path continuations. + */ + private PropagateContentFlow::AccessPath getSyntheticPathCandidate( + PropagateContentFlow::AccessPath ap + ) { + getHash(ap) = getReversedHash(result) } /** @@ -737,7 +754,7 @@ module MakeModelGenerator< exists(PropagateContentFlow::AccessPath mid, Type midType | hasSyntheticContent(mid) and step(t, read, midType, mid) and - reachesSynthExit(midType, mid.reverse()) + reachesSynthExit(midType, getSyntheticPathCandidate(mid)) ) } @@ -753,7 +770,7 @@ module MakeModelGenerator< exists(PropagateContentFlow::AccessPath mid, Type midType | hasSyntheticContent(mid) and step(midType, mid, t, store) and - synthEntryReaches(midType, mid.reverse()) + synthEntryReaches(midType, getSyntheticPathCandidate(mid)) ) } @@ -782,14 +799,15 @@ module MakeModelGenerator< Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store ) { - synthPathEntry(t1, read, t2, store) and reachesSynthExit(t2, store.reverse()) + synthPathEntry(t1, read, t2, store) and + reachesSynthExit(t2, getSyntheticPathCandidate(store)) or - exists(PropagateContentFlow::AccessPath store0 | store0.reverse() = read | + exists(PropagateContentFlow::AccessPath store0 | getSyntheticPathCandidate(store0) = read | synthEntryReaches(t1, store0) and synthPathExit(t1, read, t2, store) or synthEntryReaches(t1, store0) and step(t1, read, t2, store) and - reachesSynthExit(t2, store.reverse()) + reachesSynthExit(t2, getSyntheticPathCandidate(store)) ) } } @@ -828,26 +846,64 @@ module MakeModelGenerator< input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and input != output and - (if mentionsField(reads) or mentionsField(stores) then lift = false else lift = true) + ( + if mentionsField(reads) or mentionsField(stores) + then lift = false and api.isRelevant() + else lift = true + ) ) } /** * Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to - * the return value or a parameter). + * the return value or a parameter). `lift` is true, if the model should be lifted, otherwise false. * * Models are lifted to the best type in case the read and store access paths do not * contain a field or synthetic field access. */ - string captureFlow(ContentDataFlowSummaryTargetApi api) { - exists(string input, string output, boolean lift, boolean preservesValue | + string captureFlow(ContentDataFlowSummaryTargetApi api, boolean lift) { + exists(string input, string output, boolean preservesValue | captureFlow0(api, input, output, _, lift) and preservesValue = max(boolean p | captureFlow0(api, input, output, p, lift)) and - result = ModelPrinting::asModel(api, input, output, preservesValue, lift) + result = ContentModelPrinting::asModel(api, input, output, preservesValue, lift) ) } } + /** + * Gets the summary model(s) for `api`, if any. `lift` is true if the model is lifted + * otherwise false. + * The following heuristic is applied: + * 1. If content based flow yields at lease one summary for an API, then we use that. + * 2. If content based flow does not yield any summary for an API, then we try and + * generate flow summaries using the non-content based summary generator. + */ + string captureMixedFlow(DataFlowSummaryTargetApi api, boolean lift) { + result = ContentSensitive::captureFlow(api, lift) + or + not exists(ContentSensitive::captureFlow(api, lift)) and + result = captureFlow(api) and + lift = true + } + + /** + * Gets the neutral summary model for `api`, if any. + * A neutral summary model is generated, if we are not generating + * a mixed summary model that applies to `api`. + */ + string captureMixedNeutral(DataFlowSummaryTargetApi api) { + not exists(DataFlowSummaryTargetApi api0, boolean lift | + exists(captureMixedFlow(api0, lift)) and + ( + lift = false and api0 = api + or + lift = true and api0.lift() = api.lift() + ) + ) and + api.isRelevant() and + result = ModelPrinting::asNeutralSummaryModel(api) + } + /** * A dataflow configuration used for finding new sources. * The sources are the already known existing sources and the sinks are the API return nodes.