@@ -14,7 +14,7 @@ private import experimental.semmle.python.frameworks.Werkzeug
1414 * Provides models for the `flask` PyPI package.
1515 * See https://flask.palletsprojects.com/en/1.1.x/.
1616 */
17- private module Flask {
17+ private module Flask_Private {
1818 /** Gets a reference to the `flask` module. */
1919 private DataFlow:: Node flask ( DataFlow:: TypeTracker t ) {
2020 t .start ( ) and
@@ -42,69 +42,101 @@ private module Flask {
4242 /** Gets a reference to the `flask.request` object. */
4343 DataFlow:: Node request ( ) { result = request ( DataFlow:: TypeTracker:: end ( ) ) }
4444
45- /** Gets a reference to the `flask.Flask` class. */
46- private DataFlow:: Node classFlask ( DataFlow:: TypeTracker t ) {
47- t .start ( ) and
48- result = DataFlow:: importNode ( "flask.Flask" )
49- or
50- t .startInAttr ( "Flask" ) and
51- result = flask ( )
52- or
53- exists ( DataFlow:: TypeTracker t2 | result = classFlask ( t2 ) .track ( t2 , t ) )
54- }
55-
56- /** Gets a reference to the `flask.Flask` class. */
57- DataFlow:: Node classFlask ( ) { result = classFlask ( DataFlow:: TypeTracker:: end ( ) ) }
58-
59- /** Gets a reference to an instance of `flask.Flask` (a Flask application). */
60- private DataFlow:: Node app ( DataFlow:: TypeTracker t ) {
61- t .start ( ) and
62- result .asCfgNode ( ) .( CallNode ) .getFunction ( ) = flask:: classFlask ( ) .asCfgNode ( )
63- or
64- exists ( DataFlow:: TypeTracker t2 | result = app ( t2 ) .track ( t2 , t ) )
45+ /**
46+ * Provides models for the `flask.Flask` class
47+ *
48+ * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
49+ */
50+ module Flask {
51+ /** Gets a reference to the `flask.Flask` class. */
52+ private DataFlow:: Node classRef ( DataFlow:: TypeTracker t ) {
53+ t .start ( ) and
54+ result = DataFlow:: importNode ( "flask.Flask" )
55+ or
56+ t .startInAttr ( "Flask" ) and
57+ result = flask ( )
58+ or
59+ exists ( DataFlow:: TypeTracker t2 | result = classRef ( t2 ) .track ( t2 , t ) )
60+ }
61+
62+ /** Gets a reference to the `flask.Flask` class. */
63+ DataFlow:: Node classRef ( ) { result = classRef ( DataFlow:: TypeTracker:: end ( ) ) }
64+
65+ /**
66+ * A source of an instance of `flask.Flask`.
67+ *
68+ * This can include instantiation of the class, return value from function
69+ * calls, or a special parameter that will be set when functions are call by external
70+ * library.
71+ *
72+ * Use `Flask::instance()` predicate to get references to instances of `flask.Flask`.
73+ */
74+ abstract class InstanceSource extends DataFlow:: Node { }
75+
76+ /** A direct instantiation of `flask.Flask`. */
77+ private class ClassInstantiation extends InstanceSource , DataFlow:: CfgNode {
78+ override CallNode node ;
79+
80+ ClassInstantiation ( ) { node .getFunction ( ) = classRef ( ) .asCfgNode ( ) }
81+ }
82+
83+ /** Gets a reference to an instance of `flask.Flask` (a flask application). */
84+ private DataFlow:: Node instance ( DataFlow:: TypeTracker t ) {
85+ t .start ( ) and
86+ result instanceof InstanceSource
87+ or
88+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
89+ }
90+
91+ /** Gets a reference to an instance of `flask.Flask` (a flask application). */
92+ DataFlow:: Node instance ( ) { result = instance ( DataFlow:: TypeTracker:: end ( ) ) }
93+
94+ /**
95+ * Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application).
96+ * WARNING: Only holds for a few predefined attributes.
97+ */
98+ private DataFlow:: Node instance_attr ( DataFlow:: TypeTracker t , string attr_name ) {
99+ attr_name in [ "route" , "add_url_rule" ] and
100+ t .startInAttr ( attr_name ) and
101+ result = flask:: Flask:: instance ( )
102+ or
103+ // Due to bad performance when using normal setup with `instance_attr(t2, attr_name).track(t2, t)`
104+ // we have inlined that code and forced a join
105+ exists ( DataFlow:: TypeTracker t2 |
106+ exists ( DataFlow:: StepSummary summary |
107+ instance_attr_first_join ( t2 , attr_name , result , summary ) and
108+ t = t2 .append ( summary )
109+ )
110+ )
111+ }
112+
113+ pragma [ nomagic]
114+ private predicate instance_attr_first_join (
115+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res ,
116+ DataFlow:: StepSummary summary
117+ ) {
118+ DataFlow:: StepSummary:: step ( instance_attr ( t2 , attr_name ) , res , summary )
119+ }
120+
121+ /**
122+ * Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application).
123+ * WARNING: Only holds for a few predefined attributes.
124+ */
125+ private DataFlow:: Node instance_attr ( string attr_name ) {
126+ result = instance_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
127+ }
128+
129+ /** Gets a reference to the `route` method on an instance of `flask.Flask`. */
130+ DataFlow:: Node route ( ) { result = instance_attr ( "route" ) }
131+
132+ /** Gets a reference to the `add_url_rule` method on an instance of `flask.Flask`. */
133+ DataFlow:: Node add_url_rule ( ) { result = instance_attr ( "add_url_rule" ) }
65134 }
66-
67- /** Gets a reference to an instance of `flask.Flask` (a flask application). */
68- DataFlow:: Node app ( ) { result = app ( DataFlow:: TypeTracker:: end ( ) ) }
69135 }
70136
71137 // ---------------------------------------------------------------------------
72138 // routing modeling
73139 // ---------------------------------------------------------------------------
74- /**
75- * Gets a reference to the attribute `attr_name` of a flask application.
76- * WARNING: Only holds for a few predefined attributes.
77- */
78- private DataFlow:: Node app_attr ( DataFlow:: TypeTracker t , string attr_name ) {
79- attr_name in [ "route" , "add_url_rule" ] and
80- t .startInAttr ( attr_name ) and
81- result = flask:: app ( )
82- or
83- // Due to bad performance when using normal setup with `app_attr(t2, attr_name).track(t2, t)`
84- // we have inlined that code and forced a join
85- exists ( DataFlow:: TypeTracker t2 |
86- exists ( DataFlow:: StepSummary summary |
87- app_attr_first_join ( t2 , attr_name , result , summary ) and
88- t = t2 .append ( summary )
89- )
90- )
91- }
92-
93- pragma [ nomagic]
94- private predicate app_attr_first_join (
95- DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res , DataFlow:: StepSummary summary
96- ) {
97- DataFlow:: StepSummary:: step ( app_attr ( t2 , attr_name ) , res , summary )
98- }
99-
100- /**
101- * Gets a reference to the attribute `attr_name` of a flask application.
102- * WARNING: Only holds for a few predefined attributes.
103- */
104- private DataFlow:: Node app_attr ( string attr_name ) {
105- result = app_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
106- }
107-
108140 private string werkzeug_rule_re ( ) {
109141 // since flask uses werkzeug internally, we are using its routing rules from
110142 // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151
@@ -132,14 +164,14 @@ private module Flask {
132164 }
133165
134166 /**
135- * A call to ` flask.Flask.route `.
167+ * A call the `route` method on an instance of ` flask.Flask`.
136168 *
137169 * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.route
138170 */
139171 private class FlaskAppRouteCall extends FlaskRouteSetup , DataFlow:: CfgNode {
140172 override CallNode node ;
141173
142- FlaskAppRouteCall ( ) { node .getFunction ( ) = app_attr ( " route" ) .asCfgNode ( ) }
174+ FlaskAppRouteCall ( ) { node .getFunction ( ) = flask :: Flask :: route ( ) .asCfgNode ( ) }
143175
144176 override DataFlow:: Node getUrlPatternArg ( ) {
145177 result .asCfgNode ( ) in [ node .getArg ( 0 ) , node .getArgByName ( "rule" ) ]
@@ -149,14 +181,14 @@ private module Flask {
149181 }
150182
151183 /**
152- * A call to ` flask.Flask.add_url_rule `.
184+ * A call the `add_url_rule` method on an instance of ` flask.Flask`.
153185 *
154186 * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule
155187 */
156- private class FlaskAppAddUrlRule extends FlaskRouteSetup , DataFlow:: CfgNode {
188+ private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup , DataFlow:: CfgNode {
157189 override CallNode node ;
158190
159- FlaskAppAddUrlRule ( ) { node .getFunction ( ) = app_attr ( " add_url_rule" ) .asCfgNode ( ) }
191+ FlaskAppAddUrlRuleCall ( ) { node .getFunction ( ) = flask :: Flask :: add_url_rule ( ) .asCfgNode ( ) }
160192
161193 override DataFlow:: Node getUrlPatternArg ( ) {
162194 result .asCfgNode ( ) in [ node .getArg ( 0 ) , node .getArgByName ( "rule" ) ]
0 commit comments