Skip to content

Commit 447f339

Browse files
authored
Merge pull request #5641 from tausbn/python-use-localsourcenode-in-typetrackers
Python: Use API graphs in PEP249 support
2 parents 92508be + a6bb9eb commit 447f339

File tree

8 files changed

+42
-123
lines changed

8 files changed

+42
-123
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
lgtm,codescanning
2+
* Modeling of libraries supporting PEP249 has been changed to use API graphs. When defining new
3+
models, the relevant extension point is now `PEP249ModuleApiNode` in the `PEP249` module, instead
4+
of `PEP249Module`. The latter class has now been deprecated.

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

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

358-
class DjangoDb extends PEP249Module {
359-
DjangoDb() { this = db() }
358+
/**
359+
* `django.db` implements PEP249, providing ways to execute SQL statements against a database.
360+
*/
361+
private class DjangoDb extends PEP249ModuleApiNode {
362+
DjangoDb() { this = API::moduleImport("django").getMember("db") }
360363
}
361364

362365
/** 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: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,26 @@ 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))
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 {
24+
/** Gets a string representation of this element. */
25+
override string toString() { result = this.(API::Node).toString() }
2026
}
2127

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

2531
/**
2632
* Provides models for the `db.Connection` class
@@ -43,10 +49,8 @@ module Connection {
4349
abstract class InstanceSource extends DataFlow::Node { }
4450

4551
/** 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() }
52+
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
53+
ClassInstantiation() { this.getFunction() = connect() }
5054
}
5155

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

117121
/** 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() }
122+
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
123+
ExecuteCall() { this.getFunction() = execute() }
122124

123125
override DataFlow::Node getSql() {
124126
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
@@ -856,24 +856,13 @@ private module Stdlib {
856856
// ---------------------------------------------------------------------------
857857
// sqlite3
858858
// ---------------------------------------------------------------------------
859-
/** Gets a reference to the `sqlite3` module. */
860-
private DataFlow::Node sqlite3(DataFlow::TypeTracker t) {
861-
t.start() and
862-
result = DataFlow::importNode("sqlite3")
863-
or
864-
exists(DataFlow::TypeTracker t2 | result = sqlite3(t2).track(t2, t))
865-
}
866-
867-
/** Gets a reference to the `sqlite3` module. */
868-
DataFlow::Node sqlite3() { result = sqlite3(DataFlow::TypeTracker::end()) }
869-
870859
/**
871860
* sqlite3 implements PEP 249, providing ways to execute SQL statements against a database.
872861
*
873862
* See https://devdocs.io/python~3.9/library/sqlite3
874863
*/
875-
class Sqlite3 extends PEP249Module {
876-
Sqlite3() { this = sqlite3() }
864+
class Sqlite3 extends PEP249ModuleApiNode {
865+
Sqlite3() { this = API::moduleImport("sqlite3") }
877866
}
878867
}
879868

0 commit comments

Comments
 (0)