Skip to content

Commit aac10c1

Browse files
authored
Merge branch 'main' into patch-4
2 parents 20e23f8 + f6eabc2 commit aac10c1

File tree

125 files changed

+841
-476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+841
-476
lines changed

javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,13 +489,18 @@ public int run() throws IOException {
489489
diagnosticsToClose.forEach(DiagnosticWriter::close);
490490
}
491491

492-
if (!hasSeenCode()) {
492+
// Fail extraction if no relevant files were found.
493+
boolean seenRelevantFiles = EnvironmentVariables.isActionsExtractor()
494+
? seenFiles // assume all files are relevant for Actions extractor
495+
: hasSeenCode();
496+
if (!seenRelevantFiles) {
493497
if (seenFiles) {
494498
warn("Only found JavaScript or TypeScript files that were empty or contained syntax errors.");
495499
} else {
496500
warn("No JavaScript or TypeScript code found.");
497501
}
498-
// ensuring that the finalize steps detects that no code was seen.
502+
// Ensuring that the finalize steps detects that no code was seen.
503+
// This is necessary to ensure we don't produce an overlay-base database without externs.
499504
Path srcFolder = Paths.get(EnvironmentVariables.getWipDatabase(), "src");
500505
try {
501506
FileUtil8.recursiveDelete(srcFolder);

javascript/extractor/src/com/semmle/js/extractor/EnvironmentVariables.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ public class EnvironmentVariables {
1818
public static final String CODEQL_EXTRACTOR_JAVASCRIPT_WIP_DATABASE_ENV_VAR =
1919
"CODEQL_EXTRACTOR_JAVASCRIPT_WIP_DATABASE";
2020

21+
public static final String CODEQL_EXTRACTOR_ACTIONS_WIP_DATABASE_ENV_VAR =
22+
"CODEQL_EXTRACTOR_ACTIONS_WIP_DATABASE";
23+
2124
public static final String CODEQL_DIST_ENV_VAR = "CODEQL_DIST";
2225

2326
/**
@@ -94,4 +97,8 @@ public static String getCodeQLDist() {
9497
public static String getWipDatabase() {
9598
return Env.systemEnv().getNonEmpty(CODEQL_EXTRACTOR_JAVASCRIPT_WIP_DATABASE_ENV_VAR);
9699
}
100+
101+
public static boolean isActionsExtractor() {
102+
return Env.systemEnv().getNonEmpty(CODEQL_EXTRACTOR_ACTIONS_WIP_DATABASE_ENV_VAR) != null;
103+
}
97104
}

python/ql/examples/snippets/builtin_object.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
*/
99

1010
import python
11+
private import LegacyPointsTo
1112

12-
from Expr e, string name
13+
from ExprWithPointsTo e, string name
1314
where e.pointsTo(Value::named(name)) and not name.charAt(_) = "."
1415
select e

python/ql/examples/snippets/catch_exception.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
*/
99

1010
import python
11+
private import LegacyPointsTo
1112

1213
from ExceptStmt ex, ClassValue cls
1314
where
1415
cls.getName() = "MyExceptionClass" and
15-
ex.getType().pointsTo(cls)
16+
ex.getType().(ExprWithPointsTo).pointsTo(cls)
1617
select ex

python/ql/examples/snippets/conditional_expression.ql

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
*/
1010

1111
import python
12+
private import LegacyPointsTo
1213

1314
from IfExp e, ClassObject cls1, ClassObject cls2
1415
where
15-
e.getBody().refersTo(_, cls1, _) and
16-
e.getOrelse().refersTo(_, cls2, _) and
16+
e.getBody().(ExprWithPointsTo).refersTo(_, cls1, _) and
17+
e.getOrelse().(ExprWithPointsTo).refersTo(_, cls2, _) and
1718
cls1 != cls2
1819
select e

python/ql/examples/snippets/new_instance.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
*/
99

1010
import python
11+
private import LegacyPointsTo
1112

1213
from Call new, ClassValue cls
1314
where
1415
cls.getName() = "MyClass" and
15-
new.getFunc().pointsTo(cls)
16+
new.getFunc().(ExprWithPointsTo).pointsTo(cls)
1617
select new

python/ql/examples/snippets/print.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
*/
77

88
import python
9+
private import LegacyPointsTo
910

1011
from AstNode print
1112
where
1213
/* Python 2 without `from __future__ import print_function` */
1314
print instanceof Print
1415
or
1516
/* Python 3 or with `from __future__ import print_function` */
16-
print.(Call).getFunc().pointsTo(Value::named("print"))
17+
print.(Call).getFunc().(ExprWithPointsTo).pointsTo(Value::named("print"))
1718
select print

python/ql/examples/snippets/raise_exception.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
*/
99

1010
import python
11+
private import LegacyPointsTo
1112

1213
from Raise raise, ClassValue ex
1314
where
1415
ex.getName() = "AnException" and
15-
raise.getException().pointsTo(ex.getASuperType())
16+
raise.getException().(ExprWithPointsTo).pointsTo(ex.getASuperType())
1617
select raise, "Don't raise instances of 'AnException'"

python/ql/examples/snippets/store_none.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
*/
1111

1212
import python
13+
private import LegacyPointsTo
1314

1415
from SubscriptNode store
1516
where
1617
store.isStore() and
17-
store.getIndex().pointsTo(Value::named("None"))
18+
store.getIndex().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("None"))
1819
select store

python/ql/lib/LegacyPointsTo.qll

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/**
2+
* DEPRECATED: Using the methods in this module may lead to a degradation of performance. Use at
3+
* your own peril.
4+
*
5+
* This module contains legacy points-to predicates and methods for various classes in the
6+
* points-to analysis.
7+
*
8+
* Existing code that depends on, say, points-to predicates on `ControlFlowNode` should be modified
9+
* to use `ControlFlowNodeWithPointsTo` instead. In particular, if inside a method call chain such
10+
* as
11+
*
12+
* `someCallNode.getFunction().pointsTo(...)`
13+
*
14+
* an explicit cast should be added as follows
15+
*
16+
* `someCallNode.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(...)`
17+
*
18+
* Similarly, if a bound variable has type `ControlFlowNode`, and a points-to method is called on
19+
* it, the type should be changed to `ControlFlowNodeWithPointsTo`.
20+
*/
21+
22+
private import python
23+
private import semmle.python.pointsto.PointsTo
24+
private import semmle.python.objects.Modules
25+
26+
/**
27+
* An extension of `ControlFlowNode` that provides points-to predicates.
28+
*/
29+
class ControlFlowNodeWithPointsTo extends ControlFlowNode {
30+
/** Gets the value that this ControlFlowNode points-to. */
31+
predicate pointsTo(Value value) { this.pointsTo(_, value, _) }
32+
33+
/** Gets the value that this ControlFlowNode points-to. */
34+
Value pointsTo() { this.pointsTo(_, result, _) }
35+
36+
/** Gets a value that this ControlFlowNode may points-to. */
37+
Value inferredValue() { this.pointsTo(_, result, _) }
38+
39+
/** Gets the value and origin that this ControlFlowNode points-to. */
40+
predicate pointsTo(Value value, ControlFlowNode origin) { this.pointsTo(_, value, origin) }
41+
42+
/** Gets the value and origin that this ControlFlowNode points-to, given the context. */
43+
predicate pointsTo(Context context, Value value, ControlFlowNode origin) {
44+
PointsTo::pointsTo(this, context, value, origin)
45+
}
46+
47+
/**
48+
* Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to
49+
* analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly
50+
* precise, but may not provide information for a significant number of flow-nodes.
51+
* If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead.
52+
*/
53+
pragma[nomagic]
54+
predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) {
55+
this.refersTo(_, obj, cls, origin)
56+
}
57+
58+
/** Gets what this expression might "refer-to" in the given `context`. */
59+
pragma[nomagic]
60+
predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) {
61+
not obj = unknownValue() and
62+
not cls = theUnknownType() and
63+
PointsTo::points_to(this, context, obj, cls, origin)
64+
}
65+
66+
/**
67+
* Whether this flow node might "refer-to" to `value` which is from `origin`
68+
* Unlike `this.refersTo(value, _, origin)` this predicate includes results
69+
* where the class cannot be inferred.
70+
*/
71+
pragma[nomagic]
72+
predicate refersTo(Object obj, ControlFlowNode origin) {
73+
not obj = unknownValue() and
74+
PointsTo::points_to(this, _, obj, _, origin)
75+
}
76+
77+
/** Equivalent to `this.refersTo(value, _)` */
78+
predicate refersTo(Object obj) { this.refersTo(obj, _) }
79+
80+
/**
81+
* Check whether this control-flow node has complete points-to information.
82+
* This would mean that the analysis managed to infer an over approximation
83+
* of possible values at runtime.
84+
*/
85+
predicate hasCompletePointsToSet() {
86+
// If the tracking failed, then `this` will be its own "origin". In that
87+
// case, we want to exclude nodes for which there is also a different
88+
// origin, as that would indicate that some paths failed and some did not.
89+
this.refersTo(_, _, this) and
90+
not exists(ControlFlowNode other | other != this and this.refersTo(_, _, other))
91+
or
92+
// If `this` is a use of a variable, then we must have complete points-to
93+
// for that variable.
94+
exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v))
95+
}
96+
}
97+
98+
/**
99+
* Check whether a SSA variable has complete points-to information.
100+
* This would mean that the analysis managed to infer an overapproximation
101+
* of possible values at runtime.
102+
*/
103+
private predicate varHasCompletePointsToSet(SsaVariable var) {
104+
// Global variables may be modified non-locally or concurrently.
105+
not var.getVariable() instanceof GlobalVariable and
106+
(
107+
// If we have complete points-to information on the definition of
108+
// this variable, then the variable has complete information.
109+
var.getDefinition()
110+
.(DefinitionNode)
111+
.getValue()
112+
.(ControlFlowNodeWithPointsTo)
113+
.hasCompletePointsToSet()
114+
or
115+
// If this variable is a phi output, then we have complete
116+
// points-to information about it if all phi inputs had complete
117+
// information.
118+
forex(SsaVariable phiInput | phiInput = var.getAPhiInput() |
119+
varHasCompletePointsToSet(phiInput)
120+
)
121+
)
122+
}
123+
124+
/**
125+
* An extension of `Expr` that provides points-to predicates.
126+
*/
127+
class ExprWithPointsTo extends Expr {
128+
/**
129+
* NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead.
130+
* Gets what this expression might "refer-to". Performs a combination of localized (intra-procedural) points-to
131+
* analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly
132+
* precise, but may not provide information for a significant number of flow-nodes.
133+
* If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead.
134+
* NOTE: For complex dataflow, involving multiple stages of points-to analysis, it may be more precise to use
135+
* `ControlFlowNode.refersTo(...)` instead.
136+
*/
137+
predicate refersTo(Object obj, ClassObject cls, AstNode origin) {
138+
this.refersTo(_, obj, cls, origin)
139+
}
140+
141+
/**
142+
* NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead.
143+
* Gets what this expression might "refer-to" in the given `context`.
144+
*/
145+
predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) {
146+
this.getAFlowNode()
147+
.(ControlFlowNodeWithPointsTo)
148+
.refersTo(context, obj, cls, origin.getAFlowNode())
149+
}
150+
151+
/**
152+
* NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead.
153+
* Holds if this expression might "refer-to" to `value` which is from `origin`
154+
* Unlike `this.refersTo(value, _, origin)`, this predicate includes results
155+
* where the class cannot be inferred.
156+
*/
157+
pragma[nomagic]
158+
predicate refersTo(Object obj, AstNode origin) {
159+
this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode())
160+
}
161+
162+
/**
163+
* NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead.
164+
* Equivalent to `this.refersTo(value, _)`
165+
*/
166+
predicate refersTo(Object obj) { this.refersTo(obj, _) }
167+
168+
/**
169+
* Holds if this expression might "point-to" to `value` which is from `origin`
170+
* in the given `context`.
171+
*/
172+
predicate pointsTo(Context context, Value value, AstNode origin) {
173+
this.getAFlowNode()
174+
.(ControlFlowNodeWithPointsTo)
175+
.pointsTo(context, value, origin.getAFlowNode())
176+
}
177+
178+
/**
179+
* Holds if this expression might "point-to" to `value` which is from `origin`.
180+
*/
181+
predicate pointsTo(Value value, AstNode origin) {
182+
this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode())
183+
}
184+
185+
/**
186+
* Holds if this expression might "point-to" to `value`.
187+
*/
188+
predicate pointsTo(Value value) { this.pointsTo(value, _) }
189+
190+
/** Gets a value that this expression might "point-to". */
191+
Value pointsTo() { this.pointsTo(result) }
192+
193+
override string getAQlClass() { none() }
194+
}
195+
196+
/**
197+
* An extension of `Module` that provides points-to related methods.
198+
*/
199+
class ModuleWithPointsTo extends Module {
200+
/** Gets a name exported by this module, that is the names that will be added to a namespace by 'from this-module import *' */
201+
string getAnExport() {
202+
py_exports(this, result)
203+
or
204+
exists(ModuleObjectInternal mod | mod.getSource() = this.getEntryNode() |
205+
mod.(ModuleValue).exports(result)
206+
)
207+
}
208+
209+
override string getAQlClass() { none() }
210+
}

0 commit comments

Comments
 (0)