Skip to content

Commit e491b61

Browse files
committed
Python: move the contents of PEP249Impl to PEP249, which is possible now that the deprecations have been deleted
1 parent a7ba693 commit e491b61

File tree

2 files changed

+175
-196
lines changed

2 files changed

+175
-196
lines changed

python/ql/lib/semmle/python/frameworks/PEP249.qll

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,178 @@ private import semmle.python.dataflow.new.DataFlow
88
private import semmle.python.dataflow.new.RemoteFlowSources
99
private import semmle.python.Concepts
1010
private import semmle.python.ApiGraphs
11-
import semmle.python.frameworks.internal.PEP249Impl
11+
12+
/**
13+
* Provides classes modeling database interfaces following PEP 249.
14+
* See https://www.python.org/dev/peps/pep-0249/.
15+
*/
16+
module PEP249 {
17+
/**
18+
* An API graph node representing a module that implements PEP 249.
19+
*/
20+
abstract class PEP249ModuleApiNode extends API::Node {
21+
/** Gets a string representation of this element. */
22+
override string toString() { result = this.(API::Node).toString() }
23+
}
24+
25+
/** Gets a reference to the `connect` function of a module that implements PEP 249. */
26+
DataFlow::Node connect() {
27+
result = any(PEP249ModuleApiNode a).getMember("connect").getAValueReachableFromSource()
28+
}
29+
30+
/**
31+
* Provides models for database connections (following PEP 249).
32+
*
33+
* See https://www.python.org/dev/peps/pep-0249/#connection-objects.
34+
*/
35+
module Connection {
36+
/**
37+
* A source of database connections (following PEP 249), extend this class to model new instances.
38+
*
39+
* This can include instantiations of the class, return values from function
40+
* calls, or a special parameter that will be set when functions are called by external
41+
* libraries.
42+
*
43+
* Use the predicate `Connection::instance()` to get references to database connections (following PEP 249).
44+
*
45+
* Extend this class if the module implementing PEP 249 offers more direct ways to obtain
46+
* a connection than going through `connect`.
47+
*/
48+
abstract class InstanceSource extends DataFlow::Node { }
49+
50+
/** A call to the `connect` function of a module that implements PEP 249. */
51+
private class ConnectCall extends InstanceSource, DataFlow::CallCfgNode {
52+
ConnectCall() { this.getFunction() = connect() }
53+
}
54+
55+
/** Gets a reference to a database connection (following PEP 249). */
56+
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
57+
t.start() and
58+
result instanceof InstanceSource
59+
or
60+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
61+
}
62+
63+
/** Gets a reference to a database connection (following PEP 249). */
64+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
65+
}
66+
67+
/**
68+
* Provides models for database cursors (following PEP 249).
69+
*
70+
* These are returned by the `cursor` method on a database connection.
71+
* See https://www.python.org/dev/peps/pep-0249/#cursor.
72+
*/
73+
module Cursor {
74+
/**
75+
* A source of database cursors (following PEP 249), extend this class to model new instances.
76+
*
77+
* This can include instantiations of the class, return values from function
78+
* calls, or a special parameter that will be set when functions are called by external
79+
* libraries.
80+
*
81+
* Use the predicate `Cursor::instance()` to get references to database cursors (following PEP 249).
82+
*
83+
* Extend this class if the module implementing PEP 249 offers more direct ways to obtain
84+
* a connection than going through `connect`.
85+
*/
86+
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
87+
88+
/** Gets a reference to a database cursor. */
89+
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
90+
t.start() and
91+
result instanceof InstanceSource
92+
or
93+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
94+
}
95+
96+
/** Gets a reference to a database cursor. */
97+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
98+
99+
/** Gets a reference to the `cursor` method on a database connection. */
100+
private DataFlow::TypeTrackingNode methodRef(DataFlow::TypeTracker t) {
101+
t.startInAttr("cursor") and
102+
result = Connection::instance()
103+
or
104+
exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t))
105+
}
106+
107+
/** Gets a reference to the `cursor` method on a database connection. */
108+
DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
109+
110+
/** A call to the `cursor` method on a database connection */
111+
private class CursorCall extends InstanceSource, DataFlow::CallCfgNode {
112+
CursorCall() { this.getFunction() = methodRef() }
113+
}
114+
115+
/** Gets a reference to a result of calling the `cursor` method on a database connection. */
116+
private DataFlow::TypeTrackingNode methodResult(DataFlow::TypeTracker t) {
117+
t.start() and
118+
result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode()
119+
or
120+
exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
121+
}
122+
}
123+
124+
/**
125+
* Gets a reference to the `execute` method on a cursor (or on a connection).
126+
*
127+
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
128+
* recognize it as an alias for constructing a cursor and calling `execute` on it.
129+
*
130+
* See https://peps.python.org/pep-0249/#execute.
131+
*/
132+
private DataFlow::TypeTrackingNode execute(DataFlow::TypeTracker t) {
133+
t.startInAttr("execute") and
134+
result in [Cursor::instance(), Connection::instance()]
135+
or
136+
exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
137+
}
138+
139+
/**
140+
* Gets a reference to the `execute` method on a cursor (or on a connection).
141+
*
142+
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
143+
* recognize it as an alias for constructing a cursor and calling `execute` on it.
144+
*
145+
* See https://peps.python.org/pep-0249/#execute.
146+
*/
147+
DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) }
148+
149+
/**
150+
* A call to the `execute` method on a cursor or a connection.
151+
*
152+
* See https://peps.python.org/pep-0249/#execute
153+
*
154+
* Note: While `execute` method on a connection is not part of PEP249, if it is used, we
155+
* recognize it as an alias for constructing a cursor and calling `execute` on it.
156+
*/
157+
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
158+
ExecuteCall() { this.getFunction() = execute() }
159+
160+
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
161+
}
162+
163+
private DataFlow::TypeTrackingNode executemany(DataFlow::TypeTracker t) {
164+
t.startInAttr("executemany") and
165+
result in [Cursor::instance(), Connection::instance()]
166+
or
167+
exists(DataFlow::TypeTracker t2 | result = executemany(t2).track(t2, t))
168+
}
169+
170+
private DataFlow::Node executemany() { executemany(DataFlow::TypeTracker::end()).flowsTo(result) }
171+
172+
/**
173+
* A call to the `executemany` method on a cursor or a connection.
174+
*
175+
* See https://peps.python.org/pep-0249/#executemany
176+
*
177+
* Note: While `executemany` method on a connection is not part of PEP249, if it is used, we
178+
* recognize it as an alias for constructing a cursor and calling `executemany` on it.
179+
*/
180+
private class ExecutemanyCall extends SqlExecution::Range, DataFlow::CallCfgNode {
181+
ExecutemanyCall() { this.getFunction() = executemany() }
182+
183+
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
184+
}
185+
}

python/ql/lib/semmle/python/frameworks/internal/PEP249Impl.qll

Lines changed: 0 additions & 195 deletions
This file was deleted.

0 commit comments

Comments
 (0)