1515 * `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
1616 * - BarrierGuards:
1717 * `namespace; type; subtypes; name; signature; ext; input; acceptingValue; kind; provenance`
18+ * - Forwards:
19+ * `namespace; type; subtypes; name; signature; ext; start; constructor; output; provenance`
1820 *
1921 * The interpretation of a row is similar to API-graphs with a left-to-right
2022 * reading.
@@ -115,6 +117,7 @@ private import new.DataFlow
115117private import semmle.code.cpp.controlflow.IRGuards
116118private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as Nodes
117119private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
120+ private import semmle.code.cpp.ir.dataflow.internal.SsaImpl as SsaImpl
118121private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
119122private import internal.FlowSummaryImpl
120123private import internal.FlowSummaryImpl:: Public
@@ -160,6 +163,20 @@ predicate summaryModel(
160163 )
161164}
162165
166+ /**
167+ * Holds if a forward model exists for the given parameters.
168+ */
169+ predicate forwardsModel (
170+ string namespace , string type , boolean subtypes , string name , string signature , string ext ,
171+ string start , string constructor , string output , string provenance , string model
172+ ) {
173+ exists ( QlBuiltins:: ExtensionId madId |
174+ Extensions:: forwardsModel ( namespace , type , subtypes , name , signature , ext , start , constructor ,
175+ output , provenance , madId ) and
176+ model = "MaD:" + madId .toString ( )
177+ )
178+ }
179+
163180/** Provides a query predicate to check the data for validation errors. */
164181module ModelValidation {
165182 private string getInvalidModelInput ( ) {
@@ -186,6 +203,8 @@ module ModelValidation {
186203 sourceModel ( _, _, _, _, _, _, output , _, _, _) and pred = "source"
187204 or
188205 summaryModel ( _, _, _, _, _, _, _, output , _, _, _) and pred = "summary"
206+ or
207+ forwardsModel ( _, _, _, _, _, _, _, _, output , _, _) and pred = "forwards"
189208 |
190209 invalidSpecComponent ( output , part ) and
191210 not part = "" and
@@ -259,7 +278,8 @@ private predicate elementSpec(
259278 sinkModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _) or
260279 barrierModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _) or
261280 barrierGuardModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _) or
262- summaryModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _)
281+ summaryModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _) or
282+ forwardsModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _)
263283}
264284
265285/**
@@ -1054,6 +1074,103 @@ private module Cached {
10541074
10551075import Cached
10561076
1077+ /** Gets the constructor type selected by `constructorType` in a forwarding model. */
1078+ bindingset [ forwarder, type, name, constructorType]
1079+ private Type getForwardedConstructorType (
1080+ Function forwarder , string type , string name , string constructorType
1081+ ) {
1082+ exists ( string typeArguments , int index |
1083+ parseAngles ( type , _, typeArguments , "" ) and
1084+ constructorType = getAtIndex ( typeArguments , index ) and
1085+ result = forwarder .getDeclaringType ( ) .getTemplateArgument ( index )
1086+ )
1087+ or
1088+ exists ( string nameArguments , int index |
1089+ parseAngles ( name , _, nameArguments , "" ) and
1090+ constructorType = getAtIndex ( nameArguments , index ) and
1091+ result = forwarder .getTemplateArgument ( index )
1092+ )
1093+ }
1094+
1095+ /** Interprets a forwarding model, retaining its output and provenance. */
1096+ private predicate interpretForwardsModel (
1097+ Function forwarder , Constructor constructor , int start , string output , string provenance ,
1098+ string model
1099+ ) {
1100+ exists (
1101+ string namespace , string type , boolean subtypes , string name , string signature , string ext ,
1102+ string startString , string constructorType
1103+ |
1104+ forwardsModel ( namespace , type , subtypes , name , signature , ext , startString , constructorType ,
1105+ output , provenance , model ) and
1106+ forwarder = interpretElement ( namespace , type , subtypes , name , signature , ext ) and
1107+ start = startString .toInt ( )
1108+ |
1109+ // Either the row specifies forwarding to a type given by the type or
1110+ // function template, in which case we need to resolve that from the type
1111+ // or function name.
1112+ constructor .getDeclaringType ( ) =
1113+ getForwardedConstructorType ( forwarder , type , name , constructorType ) .getUnspecifiedType ( )
1114+ or
1115+ // Or the row specifies forwarding to a specific type.
1116+ classHasQualifiedName ( constructor .getDeclaringType ( ) , namespace , constructorType )
1117+ )
1118+ }
1119+
1120+ /** Holds if `forwarder` forwards its arguments starting at `start` to `constructor`. */
1121+ predicate forwards ( Function forwarder , Constructor constructor , int start ) {
1122+ interpretForwardsModel ( forwarder , constructor , start , _, _, _)
1123+ }
1124+
1125+ private int referenceIndirection ( Type unspecified ) {
1126+ if unspecified instanceof ReferenceType then result = 1 else result = 0
1127+ }
1128+
1129+ /**
1130+ * In order to support flow summaries for functions that perform "perfect
1131+ * forwarding" we interpret a call such as:
1132+ * ```cpp
1133+ * struct Foo { Foo(int) };
1134+ * std::vector<Foo> v;
1135+ * v.emplace_back(42);
1136+ * ```
1137+ * as:
1138+ * ```cpp
1139+ * v.emplace_back(42, &Foo);
1140+ * ```
1141+ * and add two summaries:
1142+ * (1) One flow from `42` to the first argument of a call to `Foo`
1143+ * (2) One flow from the return value of `Foo` to the `this` argument of the call
1144+ * to `emplace_back` (with a sequence of output `Content`s).
1145+ *
1146+ * These two summaries are automatically generated when a forwarding model
1147+ * for `emplace_back` exists.
1148+ */
1149+ private predicate interpretForwardingSummary (
1150+ Function forwarder , string input , string output , string provenance , string model
1151+ ) {
1152+ exists ( Constructor constructor , int start , string constructorOutput |
1153+ interpretForwardsModel ( forwarder , constructor , start , constructorOutput , provenance , model )
1154+ |
1155+ // Generate the (1) summary
1156+ exists ( int index , Parameter arg , Parameter p , int indirection |
1157+ arg = forwarder .getParameter ( start + index ) and
1158+ p = constructor .getParameter ( index ) and
1159+ indirection = [ 0 .. SsaImpl:: getMaxIndirectionsForPRType ( p .getUnspecifiedType ( ) ) ] and
1160+ input =
1161+ "Argument[" + repeatStars ( indirection + referenceIndirection ( arg .getUnspecifiedType ( ) ) ) +
1162+ ( start + index ) + "]" and
1163+ output =
1164+ "Argument[forward].Parameter[" +
1165+ repeatStars ( indirection + referenceIndirection ( p .getUnspecifiedType ( ) ) ) + index + "]"
1166+ )
1167+ or
1168+ // Generate the (2) summary
1169+ input = "Argument[forward].Parameter[-1]" and
1170+ output = constructorOutput
1171+ )
1172+ }
1173+
10571174/**
10581175 * Holds if `node` is specified as a source with the given kind in a MaD flow
10591176 * model.
@@ -1082,6 +1199,9 @@ private predicate interpretSummary(
10821199 model ) and
10831200 f = interpretElement ( namespace , type , subtypes , name , signature , ext )
10841201 )
1202+ or
1203+ interpretForwardingSummary ( f , input , output , provenance , model ) and
1204+ kind = "value"
10851205}
10861206
10871207// adapter class for converting Mad summaries to `SummarizedCallable`s
0 commit comments