Skip to content

Commit 978200e

Browse files
committed
Python: Distinguish between Python 2 and 3
Also moves the filtering on `name` to before the big disjunction in `MkModuleImport`.
1 parent c7b2b71 commit 978200e

File tree

6 files changed

+41
-5
lines changed

6 files changed

+41
-5
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,15 @@ module API {
303303
MkRoot() or
304304
/** An abstract representative for imports of the module called `name`. */
305305
MkModuleImport(string name) {
306+
// Ignore the following module name for Python 2, as we alias `__builtin__` to `builtins` elsewhere
307+
(name != "__builtin__" or major_version() = 3) and
306308
(
307309
imports(_, name)
308310
or
309311
// When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes
310312
// `foo` and `foo.bar`:
311313
name = any(ImportExpr e | not e.isRelative()).getAnImportedModuleName()
312-
) and
313-
// Ignore the following module name, as we alias `__builtin__` to `builtins` elsewhere
314-
name != "__builtin__"
314+
)
315315
or
316316
// The `builtins` module should always be implicitly available
317317
name = "builtins"
@@ -414,6 +414,7 @@ module API {
414414
)
415415
or
416416
// Ensure the Python 2 `__builtin__` module gets the name of the Python 3 `builtins` module.
417+
major_version() = 2 and
417418
nd = MkModuleImport("builtins") and
418419
imports(ref, "__builtin__")
419420
or
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle-extractor-options: --lang=2 --max-import-depth=1
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def python2_style():
2+
from __builtin__ import open #$ use=moduleImport("builtins").getMember("open")
3+
open("hello.txt") #$ use=moduleImport("builtins").getMember("open").getReturn()

python/ql/test/experimental/dataflow/ApiGraphs-py2/use.expected

Whitespace-only changes.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import TestUtilities.InlineExpectationsTest
4+
import semmle.python.ApiGraphs
5+
6+
class ApiUseTest extends InlineExpectationsTest {
7+
ApiUseTest() { this = "ApiUseTest" }
8+
9+
override string getARelevantTag() { result = "use" }
10+
11+
private predicate relevant_node(API::Node a, DataFlow::Node n, Location l) {
12+
n = a.getAUse() and l = n.getLocation()
13+
}
14+
15+
override predicate hasActualResult(Location location, string element, string tag, string value) {
16+
exists(API::Node a, DataFlow::Node n | relevant_node(a, n, location) |
17+
tag = "use" and
18+
// Only report the longest path on this line:
19+
value =
20+
max(API::Node a2, Location l2 |
21+
relevant_node(a2, _, l2) and
22+
l2.getFile() = location.getFile() and
23+
l2.getStartLine() = location.getStartLine()
24+
|
25+
a2.getPath()
26+
) and
27+
element = n.toString()
28+
)
29+
}
30+
}

python/ql/test/experimental/dataflow/ApiGraphs/test.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,6 @@ def obscured_print():
136136
p("Can you see me?") #$ use=moduleImport("builtins").getMember("print").getReturn()
137137

138138
def python2_style():
139-
from __builtin__ import open #$ use=moduleImport("builtins").getMember("open")
140-
open("hello.txt") #$ use=moduleImport("builtins").getMember("open").getReturn()
139+
# In Python 3, `__builtin__` has no special meaning.
140+
from __builtin__ import open #$ use=moduleImport("__builtin__").getMember("open")
141+
open("hello.txt") #$ use=moduleImport("__builtin__").getMember("open").getReturn()

0 commit comments

Comments
 (0)