Skip to content

Commit d2b874f

Browse files
authored
Python: Use API graphs in PEP249 support
Because the replacement extension point now extends `API::Node`, I modified the `toString` method of the latter to have an empty body. The alternative would be to require everyone to provide a `toString` predicate for their extensions, but seeing as these will usually be pointing to already existing API graph nodes, this seems silly. (This may be the reason why the equivalent method in the JS libs has such an implementation.)
1 parent ab58cb3 commit d2b874f

File tree

8 files changed

+37
-125
lines changed

8 files changed

+37
-125
lines changed

python/ql/src/semmle/python/ApiGraphs.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ module API {
157157
/**
158158
* Gets a textual representation of this element.
159159
*/
160-
abstract string toString();
160+
string toString() { none() }
161161

162162
/**
163163
* Gets a path of the given `length` from the root to this node.

python/ql/src/semmle/python/frameworks/Django.qll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,11 @@ private module Django {
7878
/** Gets a reference to the `django.db` module. */
7979
DataFlow::Node db() { result = django_attr("db") }
8080

81-
class DjangoDb extends PEP249Module {
82-
DjangoDb() { this = db() }
81+
/**
82+
* `django.db` implements PEP249, providing ways to execute SQL statements against a database.
83+
*/
84+
private class DjangoDb extends PEP249ModuleApiNode {
85+
DjangoDb() { this = API::moduleImport("django").getMember("db") }
8386
}
8487

8588
/** Provides models for the `django.db` module. */

python/ql/src/semmle/python/frameworks/MySQLdb.qll

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private import python
99
private import semmle.python.dataflow.new.DataFlow
1010
private import semmle.python.dataflow.new.RemoteFlowSources
1111
private import semmle.python.Concepts
12+
private import semmle.python.ApiGraphs
1213
private import PEP249
1314

1415
/**
@@ -21,19 +22,8 @@ private module MySQLdb {
2122
// ---------------------------------------------------------------------------
2223
// MySQLdb
2324
// ---------------------------------------------------------------------------
24-
/** Gets a reference to the `MySQLdb` module. */
25-
private DataFlow::Node moduleMySQLdb(DataFlow::TypeTracker t) {
26-
t.start() and
27-
result = DataFlow::importNode("MySQLdb")
28-
or
29-
exists(DataFlow::TypeTracker t2 | result = moduleMySQLdb(t2).track(t2, t))
30-
}
31-
32-
/** Gets a reference to the `MySQLdb` module. */
33-
DataFlow::Node moduleMySQLdb() { result = moduleMySQLdb(DataFlow::TypeTracker::end()) }
34-
3525
/** MySQLdb implements PEP 249, providing ways to execute SQL statements against a database. */
36-
class MySQLdb extends PEP249Module {
37-
MySQLdb() { this = moduleMySQLdb() }
26+
class MySQLdb extends PEP249ModuleApiNode {
27+
MySQLdb() { this = API::moduleImport("MySQLdb") }
3828
}
3929
}

python/ql/src/semmle/python/frameworks/MysqlConnectorPython.qll

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private import python
99
private import semmle.python.dataflow.new.DataFlow
1010
private import semmle.python.dataflow.new.RemoteFlowSources
1111
private import semmle.python.Concepts
12+
private import semmle.python.ApiGraphs
1213
private import PEP249
1314

1415
/**
@@ -21,64 +22,14 @@ private module MysqlConnectorPython {
2122
// ---------------------------------------------------------------------------
2223
// mysql
2324
// ---------------------------------------------------------------------------
24-
/** Gets a reference to the `mysql` module. */
25-
private DataFlow::Node mysql(DataFlow::TypeTracker t) {
26-
t.start() and
27-
result = DataFlow::importNode("mysql")
28-
or
29-
exists(DataFlow::TypeTracker t2 | result = mysql(t2).track(t2, t))
30-
}
31-
32-
/** Gets a reference to the `mysql` module. */
33-
DataFlow::Node mysql() { result = mysql(DataFlow::TypeTracker::end()) }
34-
35-
/**
36-
* Gets a reference to the attribute `attr_name` of the `mysql` module.
37-
* WARNING: Only holds for a few predefined attributes.
38-
*/
39-
private DataFlow::Node mysql_attr(DataFlow::TypeTracker t, string attr_name) {
40-
attr_name in ["connector"] and
41-
(
42-
t.start() and
43-
result = DataFlow::importNode("mysql" + "." + attr_name)
44-
or
45-
t.startInAttr(attr_name) and
46-
result = mysql()
47-
)
48-
or
49-
// Due to bad performance when using normal setup with `mysql_attr(t2, attr_name).track(t2, t)`
50-
// we have inlined that code and forced a join
51-
exists(DataFlow::TypeTracker t2 |
52-
exists(DataFlow::StepSummary summary |
53-
mysql_attr_first_join(t2, attr_name, result, summary) and
54-
t = t2.append(summary)
55-
)
56-
)
57-
}
58-
59-
pragma[nomagic]
60-
private predicate mysql_attr_first_join(
61-
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary
62-
) {
63-
DataFlow::StepSummary::step(mysql_attr(t2, attr_name), res, summary)
64-
}
65-
66-
/**
67-
* Gets a reference to the attribute `attr_name` of the `mysql` module.
68-
* WARNING: Only holds for a few predefined attributes.
69-
*/
70-
private DataFlow::Node mysql_attr(string attr_name) {
71-
result = mysql_attr(DataFlow::TypeTracker::end(), attr_name)
72-
}
73-
7425
/** Provides models for the `mysql` module. */
7526
module mysql {
7627
/**
7728
* The mysql.connector module
7829
* See https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html
7930
*/
80-
class MysqlConnector extends PEP249Module {
81-
MysqlConnector() { this = mysql_attr("connector") }
31+
class MysqlConnector extends PEP249ModuleApiNode {
32+
MysqlConnector() { this = API::moduleImport("mysql").getMember("connector") }
8233
}
8334
}
8435
}

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@ private import python
77
private import semmle.python.dataflow.new.DataFlow
88
private import semmle.python.dataflow.new.RemoteFlowSources
99
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
1011

11-
/** A module implementing PEP 249. Extend this class for implementations. */
12-
abstract class PEP249Module extends DataFlow::Node { }
12+
/**
13+
* A module implementing PEP 249. Extend this class for implementations.
14+
*
15+
* DEPRECATED: Extend `PEP249ModuleApiNode` instead.
16+
*/
17+
abstract deprecated class PEP249Module extends DataFlow::Node { }
1318

14-
/** Gets a reference to a connect call. */
15-
private DataFlow::Node connect(DataFlow::TypeTracker t) {
16-
t.startInAttr("connect") and
17-
result instanceof PEP249Module
18-
or
19-
exists(DataFlow::TypeTracker t2 | result = connect(t2).track(t2, t))
20-
}
19+
/**
20+
* An abstract class encompassing API graph nodes that implement PEP 249.
21+
* Extend this class for implementations.
22+
*/
23+
abstract class PEP249ModuleApiNode extends API::Node { }
2124

2225
/** Gets a reference to a connect call. */
23-
DataFlow::Node connect() { result = connect(DataFlow::TypeTracker::end()) }
26+
DataFlow::Node connect() { result = any(PEP249ModuleApiNode a).getMember("connect").getAUse() }
2427

2528
/**
2629
* Provides models for the `db.Connection` class
@@ -43,10 +46,8 @@ module Connection {
4346
abstract class InstanceSource extends DataFlow::Node { }
4447

4548
/** A direct instantiation of `db.Connection`. */
46-
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
47-
override CallNode node;
48-
49-
ClassInstantiation() { node.getFunction() = connect().asCfgNode() }
49+
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
50+
ClassInstantiation() { this.getFunction() = connect() }
5051
}
5152

5253
/** Gets a reference to an instance of `db.Connection`. */
@@ -115,10 +116,8 @@ private DataFlow::Node execute(DataFlow::TypeTracker t) {
115116
DataFlow::Node execute() { result = execute(DataFlow::TypeTracker::end()) }
116117

117118
/** A call to the `execute` method on a cursor (or on a connection). */
118-
private class ExecuteCall extends SqlExecution::Range, DataFlow::CfgNode {
119-
override CallNode node;
120-
121-
ExecuteCall() { node.getFunction() = execute().asCfgNode() }
119+
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
120+
ExecuteCall() { this.getFunction() = execute() }
122121

123122
override DataFlow::Node getSql() {
124123
result.asCfgNode() in [node.getArg(0), node.getArgByName("sql")]

python/ql/src/semmle/python/frameworks/Psycopg2.qll

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private import python
99
private import semmle.python.dataflow.new.DataFlow
1010
private import semmle.python.dataflow.new.RemoteFlowSources
1111
private import semmle.python.Concepts
12+
private import semmle.python.ApiGraphs
1213
private import PEP249
1314

1415
/**
@@ -21,19 +22,8 @@ private module Psycopg2 {
2122
// ---------------------------------------------------------------------------
2223
// Psycopg
2324
// ---------------------------------------------------------------------------
24-
/** Gets a reference to the `psycopg2` module. */
25-
private DataFlow::Node psycopg2(DataFlow::TypeTracker t) {
26-
t.start() and
27-
result = DataFlow::importNode("psycopg2")
28-
or
29-
exists(DataFlow::TypeTracker t2 | result = psycopg2(t2).track(t2, t))
30-
}
31-
32-
/** Gets a reference to the `psycopg2` module. */
33-
DataFlow::Node psycopg2() { result = psycopg2(DataFlow::TypeTracker::end()) }
34-
3525
/** psycopg2 implements PEP 249, providing ways to execute SQL statements against a database. */
36-
class Psycopg2 extends PEP249Module {
37-
Psycopg2() { this = psycopg2() }
26+
class Psycopg2 extends PEP249ModuleApiNode {
27+
Psycopg2() { this = API::moduleImport("psycopg2") }
3828
}
3929
}

python/ql/src/semmle/python/frameworks/PyMySQL.qll

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,16 @@ private import python
77
private import semmle.python.dataflow.new.DataFlow
88
private import semmle.python.dataflow.new.RemoteFlowSources
99
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
1011
private import PEP249
1112

1213
/**
1314
* Provides models for the `PyMySQL` PyPI package.
1415
* See https://pypi.org/project/PyMySQL/
1516
*/
1617
private module PyMySQL {
17-
/** Gets a reference to the `pymysql` module. */
18-
private DataFlow::Node pymysql(DataFlow::TypeTracker t) {
19-
t.start() and
20-
result = DataFlow::importNode("pymysql")
21-
or
22-
exists(DataFlow::TypeTracker t2 | result = pymysql(t2).track(t2, t))
23-
}
24-
25-
/** Gets a reference to the `pymysql` module. */
26-
DataFlow::Node pymysql() { result = pymysql(DataFlow::TypeTracker::end()) }
27-
2818
/** PyMySQL implements PEP 249, providing ways to execute SQL statements against a database. */
29-
class PyMySQLPEP249 extends PEP249Module {
30-
PyMySQLPEP249() { this = pymysql() }
19+
class PyMySQLPEP249 extends PEP249ModuleApiNode {
20+
PyMySQLPEP249() { this = API::moduleImport("pymysql") }
3121
}
3222
}

python/ql/src/semmle/python/frameworks/Stdlib.qll

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,24 +1523,13 @@ private module Stdlib {
15231523
// ---------------------------------------------------------------------------
15241524
// sqlite3
15251525
// ---------------------------------------------------------------------------
1526-
/** Gets a reference to the `sqlite3` module. */
1527-
private DataFlow::Node sqlite3(DataFlow::TypeTracker t) {
1528-
t.start() and
1529-
result = DataFlow::importNode("sqlite3")
1530-
or
1531-
exists(DataFlow::TypeTracker t2 | result = sqlite3(t2).track(t2, t))
1532-
}
1533-
1534-
/** Gets a reference to the `sqlite3` module. */
1535-
DataFlow::Node sqlite3() { result = sqlite3(DataFlow::TypeTracker::end()) }
1536-
15371526
/**
15381527
* sqlite3 implements PEP 249, providing ways to execute SQL statements against a database.
15391528
*
15401529
* See https://devdocs.io/python~3.9/library/sqlite3
15411530
*/
1542-
class Sqlite3 extends PEP249Module {
1543-
Sqlite3() { this = sqlite3() }
1531+
class Sqlite3 extends PEP249ModuleApiNode {
1532+
Sqlite3() { this = API::moduleImport("sqlite3") }
15441533
}
15451534
}
15461535

0 commit comments

Comments
 (0)