Skip to content

Commit ac44cb4

Browse files
authored
Merge branch 'master' into js/call-graph-exploration
2 parents 18188b6 + 1b88c97 commit ac44cb4

File tree

28 files changed

+727
-110
lines changed

28 files changed

+727
-110
lines changed

change-notes/1.25/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
## Changes to libraries
2121

2222
* A library `semmle.javascript.explore.CallGraph` has been added to help write queries for exploring the call graph.
23+
* Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module.

csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22
using System.Linq;
33
using System.Text;
44

@@ -169,7 +169,7 @@ void NextCommand()
169169
arguments.Append(" &&");
170170
}
171171

172-
public CommandBuilder RunCommand(string exe, string? argumentsOpt = null)
172+
public CommandBuilder RunCommand(string exe, string? argumentsOpt = null, bool quoteExe = true)
173173
{
174174
var (exe0, arg0) =
175175
escapingMode == EscapeMode.Process && exe.EndsWith(".exe", System.StringComparison.Ordinal)
@@ -183,7 +183,10 @@ public CommandBuilder RunCommand(string exe, string? argumentsOpt = null)
183183
}
184184
else
185185
{
186-
QuoteArgument(exe0);
186+
if (quoteExe)
187+
QuoteArgument(exe0);
188+
else
189+
Argument(exe0);
187190
}
188191
Argument(arg0);
189192
Argument(argumentsOpt);

csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@ public BuildScript Analyse(Autobuilder builder, bool auto)
5757
var command = new CommandBuilder(builder.Actions);
5858

5959
if (vsTools != null)
60+
{
6061
command.CallBatFile(vsTools.Path);
62+
// `vcvarsall.bat` sets a default Platform environment variable,
63+
// which may not be compatible with the supported platforms of the
64+
// given project/solution. Unsetting it means that the default platform
65+
// of the project/solution is used instead.
66+
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
67+
}
6168

6269
builder.MaybeIndex(command, MsBuild);
6370
command.QuoteArgument(projectOrSolution.FullPath);

javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,16 @@ private Node convertLabeledStatement(JsonObject node, SourceLocation loc) throws
15881588
}
15891589

15901590
private Node convertLiteralType(JsonObject node, SourceLocation loc) throws ParseError {
1591-
return convertChild(node, "literal");
1591+
Node literal = convertChild(node, "literal");
1592+
// Convert a negated literal to a negative number
1593+
if (literal instanceof UnaryExpression) {
1594+
UnaryExpression unary = (UnaryExpression) literal;
1595+
if (unary.getOperator().equals("-") && unary.getArgument() instanceof Literal) {
1596+
Literal arg = (Literal) unary.getArgument();
1597+
literal = new Literal(loc, arg.getTokenType(), "-" + arg.getValue());
1598+
}
1599+
}
1600+
return literal;
15921601
}
15931602

15941603
private Node convertMappedType(JsonObject node, SourceLocation loc) throws ParseError {

javascript/ql/src/javascript.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import semmle.javascript.Base64
1212
import semmle.javascript.CFG
1313
import semmle.javascript.Classes
1414
import semmle.javascript.Closure
15+
import semmle.javascript.Collections
1516
import semmle.javascript.Comments
1617
import semmle.javascript.Concepts
1718
import semmle.javascript.Constants

javascript/ql/src/semmle/javascript/Arrays.qll

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,55 @@ module ArrayTaintTracking {
9696
* Classes and predicates for modelling data-flow for arrays.
9797
*/
9898
private module ArrayDataFlow {
99+
private import DataFlow::PseudoProperties
100+
99101
/**
100-
* Gets a pseudo-field representing an element inside an array.
102+
* A step modelling the creation of an Array using the `Array.from(x)` method.
103+
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
101104
*/
102-
private string arrayElement() { result = "$arrayElement$" }
105+
private class ArrayFrom extends DataFlow::AdditionalFlowStep, DataFlow::CallNode {
106+
ArrayFrom() { this = DataFlow::globalVarRef("Array").getAMemberCall("from") }
107+
108+
override predicate loadStoreStep(
109+
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
110+
) {
111+
pred = this.getArgument(0) and
112+
succ = this and
113+
fromProp = arrayLikeElement() and
114+
toProp = arrayElement()
115+
}
116+
}
117+
118+
/**
119+
* A step modelling an array copy where the spread operator is used.
120+
* The result is essentially array concatenation.
121+
*
122+
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
123+
*/
124+
private class ArrayCopySpread extends DataFlow::AdditionalFlowStep {
125+
DataFlow::Node spreadArgument; // the spread argument containing the elements to be copied.
126+
DataFlow::Node base; // the object where the elements should be copied to.
127+
128+
ArrayCopySpread() {
129+
exists(DataFlow::MethodCallNode mcn | mcn = this |
130+
mcn.getMethodName() = ["push", "unshift"] and
131+
spreadArgument = mcn.getASpreadArgument() and
132+
base = mcn.getReceiver().getALocalSource()
133+
)
134+
or
135+
spreadArgument = this.(DataFlow::ArrayCreationNode).getASpreadArgument() and
136+
base = this
137+
}
138+
139+
override predicate loadStoreStep(
140+
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
141+
) {
142+
pred = spreadArgument and
143+
succ = base and
144+
fromProp = arrayLikeElement() and
145+
toProp = arrayElement()
146+
}
147+
}
103148

104149
/**
105150
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
@@ -110,10 +155,10 @@ private module ArrayDataFlow {
110155
this.getMethodName() = "unshift"
111156
}
112157

113-
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
158+
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
114159
prop = arrayElement() and
115-
(element = this.getAnArgument() or element = this.getASpreadArgument()) and
116-
obj = this.getReceiver().getALocalSource()
160+
element = this.getAnArgument() and
161+
obj.getAMethodCall() = this
117162
}
118163
}
119164

@@ -143,10 +188,10 @@ private module ArrayDataFlow {
143188
element = this
144189
}
145190

146-
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
191+
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
147192
prop = arrayElement() and
148193
element = this.(DataFlow::PropWrite).getRhs() and
149-
this = obj.(DataFlow::SourceNode).getAPropertyWrite()
194+
this = obj.getAPropertyWrite()
150195
}
151196
}
152197

@@ -189,7 +234,7 @@ private module ArrayDataFlow {
189234
element = getCallback(0).getParameter(0)
190235
}
191236

192-
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
237+
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
193238
this.getMethodName() = "map" and
194239
prop = arrayElement() and
195240
element = this.getCallback(0).getAReturn() and
@@ -209,7 +254,7 @@ private module ArrayDataFlow {
209254
private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::Node {
210255
ArrayCreationStep() { this instanceof DataFlow::ArrayCreationNode }
211256

212-
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
257+
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
213258
prop = arrayElement() and
214259
element = this.(DataFlow::ArrayCreationNode).getAnElement() and
215260
obj = this
@@ -223,10 +268,10 @@ private module ArrayDataFlow {
223268
private class ArraySpliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
224269
ArraySpliceStep() { this.getMethodName() = "splice" }
225270

226-
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
271+
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
227272
prop = arrayElement() and
228273
element = getArgument(2) and
229-
obj = this.getReceiver().getALocalSource()
274+
this = obj.getAMethodCall()
230275
}
231276
}
232277

@@ -260,4 +305,20 @@ private module ArrayDataFlow {
260305
succ = this
261306
}
262307
}
308+
309+
/**
310+
* A step for modelling `for of` iteration on arrays.
311+
*/
312+
private class ForOfStep extends DataFlow::AdditionalFlowStep, DataFlow::ValueNode {
313+
ForOfStmt forOf;
314+
DataFlow::Node element;
315+
316+
ForOfStep() { this.asExpr() = forOf.getIterationDomain() }
317+
318+
override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) {
319+
obj = this and
320+
e = DataFlow::lvalueNode(forOf.getLValue()) and
321+
prop = arrayElement()
322+
}
323+
}
263324
}

0 commit comments

Comments
 (0)