Skip to content

Commit b601965

Browse files
committed
PS: Use named sets to model parameter and argument matching.
1 parent e4c702e commit b601965

File tree

2 files changed

+90
-20
lines changed

2 files changed

+90
-20
lines changed

powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,34 +170,75 @@ private module Cached {
170170

171171
cached
172172
newtype TArgumentPosition =
173-
TPositionalArgumentPosition(int pos) { exists(Cmd c | exists(c.getArgument(pos))) }
173+
TKeywordArgumentPosition(string name) { name = any(CmdParameter p).getName() } or
174+
TPositionalArgumentPosition(int pos, NamedSet ns) {
175+
exists(Cmd cmd |
176+
cmd = ns.getABindingCall() and
177+
exists(cmd.getArgument(pos))
178+
)
179+
}
174180

175181
cached
176-
newtype TParameterPosition = TPositionalParameterPosition(int pos) { none() /* TODO */ }
182+
newtype TParameterPosition =
183+
TKeywordParameter(string name) { name = any(CmdParameter p).getName() } or
184+
TPositionalParameter(int pos, NamedSet ns) {
185+
exists(Cmd cmd |
186+
cmd = ns.getABindingCall() and
187+
exists(cmd.getArgument(pos))
188+
)
189+
}
177190
}
178191

179192
import Cached
180193

181194
/** A parameter position. */
182195
class ParameterPosition extends TParameterPosition {
183-
/** Holds if this position represents a positional parameter at position `pos`. */
184-
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
196+
/**
197+
* Holds if this position represents a positional parameter at position `pos`
198+
* with function is called with exactly the named parameters from the set `ns`
199+
*/
200+
predicate isPositional(int pos, NamedSet ns) { this = TPositionalParameter(pos, ns) }
201+
202+
/** Holds if this parameter is a keyword parameter with `name`. */
203+
predicate isKeyword(string name) { this = TKeywordParameter(name) }
185204

186205
/** Gets a textual representation of this position. */
187-
string toString() { exists(int pos | this.isPositional(pos) and result = "position " + pos) }
206+
string toString() {
207+
exists(int pos, NamedSet ns |
208+
this.isPositional(pos, ns) and result = "pos(" + pos + ", " + ns.toString() + ")"
209+
)
210+
or
211+
exists(string name | this.isKeyword(name) and result = "kw(" + name + ")")
212+
}
188213
}
189214

190215
/** An argument position. */
191216
class ArgumentPosition extends TArgumentPosition {
192217
/** Holds if this position represents a positional argument at position `pos`. */
193-
predicate isPositional(int pos) { this = TPositionalArgumentPosition(pos) }
218+
predicate isPositional(int pos, NamedSet ns) { this = TPositionalArgumentPosition(pos, ns) }
219+
220+
predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) }
194221

195222
/** Gets a textual representation of this position. */
196-
string toString() { exists(int pos | this.isPositional(pos) and result = "position " + pos) }
223+
string toString() {
224+
exists(int pos, NamedSet ns |
225+
this.isPositional(pos, ns) and result = "pos(" + pos + ", " + ns.toString() + ")"
226+
)
227+
or
228+
exists(string name | this.isKeyword(name) and result = "kw(" + name + ")")
229+
}
197230
}
198231

199232
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
200233
pragma[nomagic]
201234
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
202-
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
235+
exists(string name |
236+
ppos.isKeyword(name) and
237+
apos.isKeyword(name)
238+
)
239+
or
240+
exists(int pos, NamedSet ns |
241+
ppos.isPositional(pos, ns) and
242+
apos.isPositional(pos, ns)
243+
)
203244
}

powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,6 @@ private module ParameterNodes {
294294
abstract Parameter getParameter();
295295

296296
abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition pos);
297-
298-
final predicate isSourceParameterOf(CfgScope c, ParameterPosition pos) {
299-
exists(DataFlowCallable callable |
300-
this.isParameterOf(callable, pos) and
301-
c = callable.asCfgScope()
302-
)
303-
}
304297
}
305298

306299
/**
@@ -315,8 +308,29 @@ private module ParameterNodes {
315308
override Parameter getParameter() { result = parameter }
316309

317310
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
318-
exists(CfgScope callable, int i |
319-
callable = c.asCfgScope() and pos.isPositional(i) and callable.getParameter(i) = parameter
311+
exists(CfgScope callable | callable = c.asCfgScope() |
312+
pos.isKeyword(parameter.getName())
313+
or
314+
// Given a function f with parameters x, y we map
315+
// x to the positions:
316+
// 1. keyword(x)
317+
// 2. position(0, {y})
318+
// 3. position(0, {})
319+
// Likewise, y is mapped to the positions:
320+
// 1. keyword(y)
321+
// 2. position(0, {x})
322+
// 3. position(1, {})
323+
// The interpretation of `position(i, S)` is the position of the i'th unnamed parameter when the
324+
// keywords in S are specified.
325+
exists(int i, int j, string name, NamedSet ns, Function f |
326+
pos.isPositional(j, ns) and
327+
parameter.getIndex() = i and
328+
f = parameter.getFunction() and
329+
f = ns.getAFunction() and
330+
name = parameter.getName() and
331+
not name = ns.getAName() and
332+
j = i - count(int k | k < i and f.getParameter(k).getName() = ns.getAName())
333+
)
320334
)
321335
}
322336

@@ -335,14 +349,29 @@ abstract class ArgumentNode extends Node {
335349
/** Holds if this argument occurs at the given position in the given call. */
336350
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
337351

338-
abstract predicate sourceArgumentOf(CfgNodes::StmtNodes::CmdCfgNode call, ArgumentPosition pos);
339-
340352
/** Gets the call in which this node is an argument. */
341353
final DataFlowCall getCall() { this.argumentOf(result, _) }
342354
}
343355

344356
module ArgumentNodes {
345-
// TODO
357+
class ExplicitArgumentNode extends ArgumentNode {
358+
CfgNodes::ExprNodes::ArgumentCfgNode arg;
359+
360+
ExplicitArgumentNode() { this.asExpr() = arg }
361+
362+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
363+
arg.getCmd() = call.asCall() and
364+
(
365+
pos.isKeyword(arg.getName())
366+
or
367+
exists(NamedSet ns, int i |
368+
i = arg.getPosition() and
369+
ns.getAnExactBindingCall() = call.asCall().getStmt() and
370+
pos.isPositional(i, ns)
371+
)
372+
)
373+
}
374+
}
346375
}
347376

348377
import ArgumentNodes

0 commit comments

Comments
 (0)