Skip to content

Commit b0c7a52

Browse files
committed
Discard predicates for elements with direct location links in dbscheme
1 parent 3015c12 commit b0c7a52

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

python/ql/lib/python.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import semmle.python.pointsto.CallGraph
3737
import semmle.python.objects.ObjectAPI
3838
import semmle.python.Unit
3939
import site
40+
private import semmle.python.Overlay
4041
// Removing this import perturbs the compilation process enough that the points-to analysis gets
4142
// compiled -- and cached -- differently depending on whether the data flow library is imported. By
4243
// importing it privately here, we ensure that the points-to analysis is compiled the same way.
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* Defines entity discard predicates for Python overlay analysis.
3+
*/
4+
overlay[local?]
5+
module;
6+
7+
import python
8+
9+
/**
10+
* A local predicate that always holds for the overlay variant and
11+
* never holds for the base variant. This is used to define local
12+
* predicates that behave differently for the base and overlay variant.
13+
*/
14+
overlay[local]
15+
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
16+
17+
/** Gets the raw file path for a locatable Python AST node. */
18+
overlay[local]
19+
private string getRawPathForLocatable(@py_location_parent el) {
20+
exists(@location loc | py_locations(loc, el) | result = getRawPathForLocation(loc))
21+
}
22+
23+
/** Gets the raw path for a location. */
24+
overlay[local]
25+
private string getRawPathForLocation(@location loc) {
26+
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
27+
or
28+
exists(@py_Module mod | locations_ast(loc, mod, _, _, _, _) | result = getRawPathForModule(mod))
29+
}
30+
31+
overlay[local]
32+
private string getRawPathForModule(@py_Module mod) {
33+
exists(@container fileOrFolder | py_module_path(mod, fileOrFolder) |
34+
result = getRawPathForContainer(fileOrFolder)
35+
)
36+
}
37+
38+
overlay[local]
39+
private string getRawPathForScope(@py_scope scope) {
40+
exists(@location loc | py_scope_location(loc, scope) | result = getRawPathForLocation(loc))
41+
or
42+
result = getRawPathForModule(scope.(@py_Module))
43+
}
44+
45+
overlay[local]
46+
private string getRawPathForContainer(@container fileOrFolder) {
47+
files(fileOrFolder, result) or folders(fileOrFolder, result)
48+
}
49+
50+
/**
51+
* Discard all locatable AST nodes (`@py_location_parent`) in modified files
52+
* since they use *-ids and hence cannot be referenced across TRAP files.
53+
*/
54+
overlay[discard_entity]
55+
private predicate discardLocatable(@py_location_parent el) {
56+
overlayChangedFiles(getRawPathForLocatable(el)) and
57+
not isOverlay()
58+
}
59+
60+
overlay[local]
61+
private predicate scopeExistsInBase(@py_scope scope) { not isOverlay() and exists(scope) }
62+
63+
overlay[local]
64+
private predicate scopeExistsInOverlay(@py_scope scope) { isOverlay() and exists(scope) }
65+
66+
/**
67+
* Discard scopes (classes, functions, modules) that were deleted in the overlay.
68+
*/
69+
overlay[discard_entity]
70+
private predicate discardScope(@py_scope scope) {
71+
overlayChangedFiles(getRawPathForScope(scope)) and
72+
scopeExistsInBase(scope) and
73+
not scopeExistsInOverlay(scope)
74+
}
75+
76+
overlay[local]
77+
private predicate containerExistsInBase(@container fileOrFolder) {
78+
not isOverlay() and exists(fileOrFolder)
79+
}
80+
81+
overlay[local]
82+
private predicate containerExistsInOverlay(@container fileOrFolder) {
83+
isOverlay() and exists(fileOrFolder)
84+
}
85+
86+
/**
87+
* Discard files and folders that were deleted in the overlay.
88+
*/
89+
overlay[discard_entity]
90+
private predicate discardContainer(@container fileOrFolder) {
91+
overlayChangedFiles(getRawPathForContainer(fileOrFolder)) and
92+
containerExistsInBase(fileOrFolder) and
93+
not containerExistsInOverlay(fileOrFolder)
94+
}
95+
96+
overlay[local]
97+
private predicate baseXmlLocatable(@xmllocatable l) {
98+
not isOverlay() and not files(l, _) and not xmlNs(l, _, _, _)
99+
}
100+
101+
overlay[local]
102+
private predicate overlayHasXmlLocatable() {
103+
isOverlay() and
104+
exists(@xmllocatable l | not files(l, _) and not xmlNs(l, _, _, _))
105+
}
106+
107+
overlay[discard_entity]
108+
private predicate discardBaseXmlLocatable(@xmllocatable el) {
109+
// The XML extractor is currently not incremental, so if
110+
// the overlay contains any XML locatables, the overlay should
111+
// contain a full extraction and all XML locatables from base
112+
// should be discarded.
113+
baseXmlLocatable(el) and overlayHasXmlLocatable()
114+
}
115+
116+
overlay[local]
117+
private predicate baseYamlLocatable(@yaml_locatable l) { not isOverlay() and exists(l) }
118+
119+
overlay[local]
120+
private predicate overlayHasYamlLocatable() {
121+
isOverlay() and
122+
exists(@yaml_locatable l)
123+
}
124+
125+
overlay[discard_entity]
126+
private predicate discardBaseYamlLocatable(@yaml_locatable el) {
127+
// The Yaml extractor is currently not incremental, so if
128+
// the overlay contains any Yaml locatables, the overlay should
129+
// contain a full extraction and all Yaml locatables from base
130+
// should be discarded.
131+
baseYamlLocatable(el) and overlayHasYamlLocatable()
132+
}

0 commit comments

Comments
 (0)