Skip to content

Commit 03bc334

Browse files
committed
JS: More stuff
1 parent ae28fba commit 03bc334

File tree

3 files changed

+71
-59
lines changed

3 files changed

+71
-59
lines changed

javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSteps.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ private module CachedSteps {
339339
pred = DataFlow::valueNode(node1) and
340340
succ = getNodeFromNameResolutionNode(node2)
341341
)
342+
or
343+
exists(Import imprt, Module mod |
344+
imprt.getImportedModule() = mod and
345+
pred = DataFlow::valueNode(NameResolution::getModuleBulkExport(mod)) and
346+
succ = imprt.getImportedModuleNodeStrict()
347+
)
342348
}
343349

344350
pragma[inline]

javascript/ql/lib/semmle/javascript/internal/NameResolution.qll

Lines changed: 65 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ module NameResolution {
188188
private predicate commonStep(Node node1, Node node2) {
189189
commonStep1(node1, node2)
190190
or
191-
node2 = ValueFlow::exportsObjectRhs(node1)
191+
node2 = exportsObjectRhs(node1)
192192
}
193193

194194
/**
@@ -216,7 +216,8 @@ module NameResolution {
216216
exists(PropAccess access |
217217
node1 = access.getBase() and
218218
name = access.getPropertyName() and
219-
node2 = access
219+
node2 = access and
220+
access instanceof RValue
220221
)
221222
or
222223
exists(ObjectPattern pattern |
@@ -268,6 +269,66 @@ module NameResolution {
268269
)
269270
}
270271

272+
pragma[nomagic]
273+
private GlobalVarAccess globalAccess(Module mod, string name) {
274+
result.getName() = name and
275+
result.getTopLevel() = mod and
276+
name = ["exports", "module"] // manually restrict size of predicate
277+
}
278+
279+
/** Gets a reference to the CommonJS `module` object within the given module. */
280+
private Node moduleObjectRef(Module mod) {
281+
result = mod.getScope().getVariable("module").getAnAccess()
282+
or
283+
result = globalAccess(mod, "module")
284+
or
285+
commonStep1(moduleObjectRef(mod), result)
286+
}
287+
288+
/** Gets the right-hand side of an assignment to `module.exports` within the given module. */
289+
private Node exportsObjectRhs(Module mod) {
290+
exists(AssignExpr assign |
291+
assign.getLhs().(PropAccess).accesses(moduleObjectRef(mod), "exports") and
292+
result = assign.getRhs()
293+
)
294+
}
295+
296+
/** Gets a node that is bulk-exported from the given module. */
297+
Node getModuleBulkExport(ModuleLike mod) { result = exportsObjectRhs(mod) }
298+
299+
/** Gets a node that flows to `module.exports` within the given module. */
300+
private Node exportsObjectRhsPred(Module mod) { commonStep1*(result, exportsObjectRhs(mod)) }
301+
302+
/** Gets a node that is an alias for `module.exports` within the given module. */
303+
private Node exportsObjectAlias(Module mod) {
304+
result = mod.getScope().getVariable("exports").getAnAccess()
305+
or
306+
result = globalAccess(mod, "exports")
307+
or
308+
result.(ThisExpr).getBindingContainer() = mod and
309+
mod instanceof NodeModule
310+
or
311+
readStep(moduleObjectRef(mod), "exports", result)
312+
or
313+
result = exportsObjectRhsPred(mod)
314+
or
315+
commonStep(exportsObjectAlias(mod), result)
316+
}
317+
318+
/** Holds if `node` is stored into `module.exports.<name>` within the given module. */
319+
private predicate storeToExports(Node node, Module mod, string name) {
320+
exists(AssignExpr assign |
321+
node = assign.getRhs() and
322+
assign.getLhs().(PropAccess).accesses(exportsObjectAlias(mod), name)
323+
)
324+
or
325+
exists(Property prop |
326+
node = prop.getInit() and
327+
name = prop.getName() and
328+
prop.getObjectExpr() = exportsObjectAlias(mod)
329+
)
330+
}
331+
271332
private signature module TypeResolutionInputSig {
272333
/**
273334
* Holds if flow is permitted through the given variable.
@@ -399,58 +460,6 @@ module NameResolution {
399460
value = target.getAnAssignedExpr().(ObjectExpr).getPropertyByName(prop).getInit()
400461
}
401462

402-
pragma[nomagic]
403-
private GlobalVarAccess globalAccess(Module mod, string name) {
404-
result.getName() = name and
405-
result.getTopLevel() = mod and
406-
name = ["exports", "module"] // manually restrict size of predicate
407-
}
408-
409-
private Node moduleObjectRef(Module mod) {
410-
result = mod.getScope().getVariable("module").getAnAccess()
411-
or
412-
result = globalAccess(mod, "module")
413-
or
414-
commonStep1(moduleObjectRef(mod), result)
415-
}
416-
417-
Node exportsObjectRhs(Module mod) {
418-
exists(AssignExpr assign |
419-
assign.getLhs().(PropAccess).accesses(moduleObjectRef(mod), "exports") and
420-
result = assign.getRhs()
421-
)
422-
}
423-
424-
private Node exportsObjectRhsPred(Module mod) { commonStep1*(result, exportsObjectRhs(mod)) }
425-
426-
private Node exportsObjectAlias(Module mod) {
427-
result = mod.getScope().getVariable("exports").getAnAccess()
428-
or
429-
result = globalAccess(mod, "exports")
430-
or
431-
result.(ThisExpr).getBindingContainer() = mod and
432-
mod instanceof NodeModule
433-
or
434-
readStep(moduleObjectRef(mod), "exports", result)
435-
or
436-
result = exportsObjectRhsPred(mod)
437-
or
438-
commonStep(exportsObjectAlias(mod), result)
439-
}
440-
441-
private predicate storeToExports(Node node, Module mod, string name) {
442-
exists(AssignExpr assign |
443-
node = assign.getRhs() and
444-
assign.getLhs().(PropAccess).accesses(exportsObjectAlias(mod), name)
445-
)
446-
or
447-
exists(Property prop |
448-
node = prop.getInit() and
449-
name = prop.getName() and
450-
prop.getObjectExpr() = exportsObjectAlias(mod)
451-
)
452-
}
453-
454463
/** Steps that only apply for this configuration. */
455464
private predicate specificStep(Node node1, Node node2) {
456465
exists(LexicalName var | S::isRelevantVariable(var) |
@@ -519,6 +528,8 @@ module NameResolution {
519528
or
520529
defaultImportInteropStep(trackModule(mod), result) and
521530
not mod.(ES2015Module).hasBothNamedAndDefaultExports()
531+
or
532+
result = exportsObjectAlias(mod)
522533
}
523534

524535
predicate trackClassValue = ValueFlow::TrackNode<ClassDefinition>::track/1;

javascript/ql/test/library-tests/EndpointNaming/EndpointNaming.expected

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
testFailures
2-
| pack8/foo.js:1:1:1:12 | | Unexpected result: name=(pack8).Foo.Foo |
3-
| pack8/foo.js:1:14:1:34 | // $ na ... k8).Foo | Missing result: name=(pack8).Foo |
4-
| pack8/foo.js:4:26:4:28 | | Unexpected result: alias=(pack8).Foo.default==(pack8).Foo.Foo |
5-
| pack8/foo.js:4:31:4:73 | // $ al ... k8).Foo | Missing result: alias=(pack8).Foo.default==(pack8).Foo |
6-
| pack8/foo.js:5:27:5:65 | // $ al ... k8).Foo | Missing result: alias=(pack8).Foo.Foo==(pack8).Foo |
72
ambiguousPreferredPredecessor
83
| pack2/lib.js:1:1:3:1 | def moduleImport("pack2").getMember("exports").getMember("lib").getMember("LibClass").getInstance() |
94
| pack2/lib.js:8:22:8:34 | def moduleImport("pack2").getMember("exports").getMember("lib").getMember("LibClass").getMember("foo") |

0 commit comments

Comments
 (0)