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.
108110 * - "manual": The model has been written by hand.
109111 * This information is used in a heuristic for dataflow analysis to determine, if a
110112 * model or source code should be used for determining flow.
113+ *
114+ * The "Forwards" relation allows modeling of function that perform C++11-style "perfect
115+ * forwarding" where a function receives a number of arguments and forwards those arguments
116+ * to a constructor of another type. For example, the row:
117+ * `"std"; "vector<T>"; "True"; "emplace"; ""; ""; "1"; T; Argument[-1].Element; manual`
118+ * says that `std::vector<T>::emplace(arg0, arg1, ..., argn)` forwards arguments
119+ * `arg1, ..., argn` to a constructor for `T`, and the result of `T(arg1, ..., argn)`
120+ * flows to `Argument[-1].Element` (see information about the semantics of the `output`
121+ * column further above).
111122 */
112123
113124import cpp
114125private import new.DataFlow
115126private import semmle.code.cpp.controlflow.IRGuards
116127private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as Nodes
117128private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
129+ private import semmle.code.cpp.ir.dataflow.internal.SsaImpl as SsaImpl
118130private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
119131private import internal.FlowSummaryImpl
120132private import internal.FlowSummaryImpl:: Public
@@ -160,6 +172,20 @@ predicate summaryModel(
160172 )
161173}
162174
175+ /**
176+ * Holds if a forward model exists for the given parameters.
177+ */
178+ predicate forwardsModel (
179+ string namespace , string type , boolean subtypes , string name , string signature , string ext ,
180+ string start , string constructor , string output , string provenance , string model
181+ ) {
182+ exists ( QlBuiltins:: ExtensionId madId |
183+ Extensions:: forwardsModel ( namespace , type , subtypes , name , signature , ext , start , constructor ,
184+ output , provenance , madId ) and
185+ model = "MaD:" + madId .toString ( )
186+ )
187+ }
188+
163189/** Provides a query predicate to check the data for validation errors. */
164190module ModelValidation {
165191 private string getInvalidModelInput ( ) {
@@ -186,6 +212,8 @@ module ModelValidation {
186212 sourceModel ( _, _, _, _, _, _, output , _, _, _) and pred = "source"
187213 or
188214 summaryModel ( _, _, _, _, _, _, _, output , _, _, _) and pred = "summary"
215+ or
216+ forwardsModel ( _, _, _, _, _, _, _, _, output , _, _) and pred = "forwards"
189217 |
190218 invalidSpecComponent ( output , part ) and
191219 not part = "" and
@@ -259,7 +287,8 @@ private predicate elementSpec(
259287 sinkModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _) or
260288 barrierModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _) or
261289 barrierGuardModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _) or
262- summaryModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _)
290+ summaryModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _) or
291+ forwardsModel ( namespace , type , subtypes , name , signature , ext , _, _, _, _, _)
263292}
264293
265294/**
@@ -596,6 +625,14 @@ private string getAtIndex(string s, int i) {
596625 not ( s = "" and i = 0 )
597626}
598627
628+ /** Gets the number of comma-separated arguments in `s`. */
629+ bindingset [ s]
630+ private int getNumberOfArguments ( string s ) {
631+ s = "" and result = 0
632+ or
633+ s != "" and result = count ( s .indexOf ( "," ) ) + 1
634+ }
635+
599636/**
600637 * Normalizes `partiallyNormalizedSignature` by replacing the `remaining`
601638 * number of template arguments in `partiallyNormalizedSignature` with their
@@ -605,7 +642,7 @@ private string getSignatureWithoutClassTemplateNames(
605642 string partiallyNormalizedSignature , string typeArgs , string nameArgs , int remaining
606643) {
607644 elementSpecWithArguments0 ( _, _, _, partiallyNormalizedSignature , typeArgs , nameArgs ) and
608- remaining = count ( partiallyNormalizedSignature . indexOf ( "," ) ) + 1 and
645+ remaining = getNumberOfArguments ( typeArgs ) and
609646 result = partiallyNormalizedSignature
610647 or
611648 exists ( string mid |
@@ -619,7 +656,7 @@ private string getSignatureWithoutClassTemplateNames(
619656 )
620657 or
621658 // Make sure `remaining` is properly bound
622- remaining = [ 0 .. count ( partiallyNormalizedSignature . indexOf ( "," ) ) + 1 ] and
659+ remaining = [ 0 .. getNumberOfArguments ( typeArgs ) ] and
623660 not exists ( getAtIndex ( typeArgs , remaining ) ) and
624661 result = mid
625662 )
@@ -636,7 +673,7 @@ pragma[nomagic]
636673private string getSignatureWithoutFunctionTemplateNames (
637674 string partiallyNormalizedSignature , string typeArgs , string nameArgs , int remaining
638675) {
639- remaining = count ( partiallyNormalizedSignature . indexOf ( "," ) ) + 1 and
676+ remaining = getNumberOfArguments ( nameArgs ) and
640677 result =
641678 getSignatureWithoutClassTemplateNames ( partiallyNormalizedSignature , typeArgs , nameArgs , 0 )
642679 or
@@ -651,7 +688,7 @@ private string getSignatureWithoutFunctionTemplateNames(
651688 )
652689 or
653690 // Make sure `remaining` is properly bound
654- remaining = [ 0 .. count ( partiallyNormalizedSignature . indexOf ( "," ) ) + 1 ] and
691+ remaining = [ 0 .. getNumberOfArguments ( nameArgs ) ] and
655692 not exists ( getAtIndex ( nameArgs , remaining ) ) and
656693 result = mid
657694 )
@@ -1046,6 +1083,148 @@ private module Cached {
10461083
10471084import Cached
10481085
1086+ /** Gets the constructor type selected by `constructorType` in a forwarding model. */
1087+ private Type getForwardedConstructorType (
1088+ Function forwarder , string namespace , string type , boolean subtypes , string name ,
1089+ string signature , string ext , string constructorType
1090+ ) {
1091+ exists ( int index |
1092+ forwardsModel ( namespace , type , subtypes , name , signature , ext , _, constructorType , _, _, _) and
1093+ forwarder = interpretElement ( namespace , type , subtypes , name , signature , ext )
1094+ |
1095+ exists ( string typeArguments |
1096+ parseAngles ( type , _, typeArguments , "" ) and
1097+ constructorType = getAtIndex ( typeArguments , index ) and
1098+ result = forwarder .getDeclaringType ( ) .getTemplateArgument ( index )
1099+ )
1100+ or
1101+ exists ( string nameArguments |
1102+ parseAngles ( name , _, nameArguments , "" ) and
1103+ constructorType = getAtIndex ( nameArguments , index ) and
1104+ result = forwarder .getTemplateArgument ( index )
1105+ )
1106+ )
1107+ }
1108+
1109+ /** Interprets a forwarding model, retaining its constructed type, output, and provenance. */
1110+ private predicate interpretForwardsModelType (
1111+ Function forwarder , Type constructedType , int start , string output , string provenance ,
1112+ string model
1113+ ) {
1114+ exists (
1115+ string namespace , string type , boolean subtypes , string name , string signature , string ext ,
1116+ string startString , string constructorType
1117+ |
1118+ forwardsModel ( namespace , type , subtypes , name , signature , ext , startString , constructorType ,
1119+ output , provenance , model ) and
1120+ forwarder = interpretElement ( namespace , type , subtypes , name , signature , ext ) and
1121+ start = startString .toInt ( )
1122+ |
1123+ // Either the row specifies forwarding to a type given by the type or
1124+ // function template, in which case we need to resolve that from the type
1125+ // or function name.
1126+ constructedType =
1127+ getForwardedConstructorType ( forwarder , namespace , type , subtypes , name , signature , ext ,
1128+ constructorType ) .getUnspecifiedType ( )
1129+ or
1130+ // Or the row specifies forwarding to a specific type.
1131+ not exists (
1132+ getForwardedConstructorType ( forwarder , namespace , type , subtypes , name , signature , ext ,
1133+ constructorType )
1134+ ) and
1135+ classHasQualifiedName ( constructedType , namespace , constructorType )
1136+ )
1137+ }
1138+
1139+ /**
1140+ * Holds if `forwarder` may forward its arguments starting at `start` to `constructor`. The
1141+ * actual constructor being forwarded to depends on the types of arguments from `start`
1142+ * at calls to `forwarder`.
1143+ */
1144+ private predicate interpretForwardsModel (
1145+ Function forwarder , Constructor constructor , int start , string output , string provenance ,
1146+ string model
1147+ ) {
1148+ interpretForwardsModelType ( forwarder , constructor .getDeclaringType ( ) , start , output , provenance ,
1149+ model )
1150+ }
1151+
1152+ /** Holds if `forwarder` forwards its arguments starting at `start` to `constructor`. */
1153+ predicate forwards ( Function forwarder , Constructor constructor , int start ) {
1154+ interpretForwardsModel ( forwarder , constructor , start , _, _, _)
1155+ }
1156+
1157+ private int referenceIndirection ( Type unspecified ) {
1158+ if unspecified instanceof ReferenceType then result = 1 else result = 0
1159+ }
1160+
1161+ /** Gets `unspecified`, but with its outermost reference removed, if any. */
1162+ private Type stripReference ( Type unspecified ) {
1163+ result = unspecified .( ReferenceType ) .getBaseType ( ) .getUnspecifiedType ( )
1164+ or
1165+ not unspecified instanceof ReferenceType and
1166+ result = unspecified
1167+ }
1168+
1169+ /**
1170+ * In order to support flow summaries for functions that perform "perfect
1171+ * forwarding" we interpret a call such as:
1172+ * ```cpp
1173+ * struct Foo { Foo(int) };
1174+ * std::vector<Foo> v;
1175+ * v.emplace_back(42);
1176+ * ```
1177+ * as:
1178+ * ```cpp
1179+ * v.emplace_back(42, &Foo);
1180+ * ```
1181+ * and add two summaries:
1182+ * (1) One flow from `42` to the first argument of a call to `Foo`
1183+ * (2) One flow from the return value of `Foo` to the `this` argument of the call
1184+ * to `emplace_back` (with a sequence of output `Content`s).
1185+ *
1186+ * These two summaries are automatically generated when a forwarding model
1187+ * for `emplace_back` exists.
1188+ */
1189+ private predicate interpretForwardingSummary (
1190+ Function forwarder , string input , string output , string provenance , string model
1191+ ) {
1192+ exists ( Constructor constructor , int start , string constructorOutput |
1193+ interpretForwardsModel ( forwarder , constructor , start , constructorOutput , provenance , model )
1194+ |
1195+ // Generate the (1) summary
1196+ exists ( int index , Parameter arg , Parameter p , int indirection |
1197+ arg = forwarder .getParameter ( start + index ) and
1198+ p = constructor .getParameter ( index ) and
1199+ indirection = [ 0 .. SsaImpl:: getMaxIndirectionsForPRType ( p .getUnspecifiedType ( ) ) ] and
1200+ input =
1201+ "Argument[" + repeatStars ( indirection + referenceIndirection ( arg .getUnspecifiedType ( ) ) ) +
1202+ ( start + index ) + "]" and
1203+ output =
1204+ "Argument[forward].Parameter[" +
1205+ repeatStars ( indirection + referenceIndirection ( p .getUnspecifiedType ( ) ) ) + index + "]"
1206+ )
1207+ or
1208+ // Generate the (2) summary
1209+ input = "Argument[forward].Parameter[-1]" and
1210+ output = constructorOutput
1211+ )
1212+ or
1213+ // Scalar types have no constructor to synthesize. In this case, directly
1214+ // preserve the value of the single forwarded argument at the modeled output.
1215+ exists ( Type constructedType , int start , Parameter p , int indirection |
1216+ interpretForwardsModelType ( forwarder , constructedType , start , output , provenance , model ) and
1217+ not constructedType instanceof Class and
1218+ forwarder .getNumberOfParameters ( ) = start + 1 and
1219+ p = forwarder .getParameter ( start ) and
1220+ stripReference ( p .getUnspecifiedType ( ) ) = constructedType and
1221+ indirection = [ 0 .. SsaImpl:: getMaxIndirectionsForPRType ( constructedType ) ] and
1222+ input =
1223+ "Argument[" + repeatStars ( indirection + referenceIndirection ( p .getUnspecifiedType ( ) ) ) + start +
1224+ "]"
1225+ )
1226+ }
1227+
10491228/**
10501229 * Holds if `node` is specified as a source with the given kind in a MaD flow
10511230 * model.
@@ -1074,6 +1253,9 @@ private predicate interpretSummary(
10741253 model ) and
10751254 f = interpretElement ( namespace , type , subtypes , name , signature , ext )
10761255 )
1256+ or
1257+ interpretForwardingSummary ( f , input , output , provenance , model ) and
1258+ kind = "value"
10771259}
10781260
10791261// adapter class for converting Mad summaries to `SummarizedCallable`s
0 commit comments