More Module interop code

This commit is contained in:
Asger F
2024-03-04 15:46:55 +01:00
parent 5340a89107
commit 7ae28ceee0

View File

@@ -1,24 +1,32 @@
private import javascript
private import PreCallGraphStep as PCG
class ES2015InteropCall extends DataFlow::CallNode {
ES2015InteropCall() {
this.getCalleeName() = ["_interopRequireDefault", "_interopRequireWildcard"]
}
private Import getAnImport() {
/**
* Base class for calls whose first argument is an imported module.
*/
abstract private class ModuleInteropCall extends DataFlow::CallNode {
private Import getImport() {
this.getArgument(0).getALocalSource() = result.getImportedModuleNode()
}
Module getImportedModule() { result = this.getAnImport().getImportedModule() }
/** Gets the module that is passed as the first argument. */
Module getImportedModule() { result = this.getImport().getImportedModule() }
/** Holds if the imported module is an ES2015 module or a compiled version thereof. */
predicate isImportingESModule() {
this.getImportedModule() instanceof ES2015Module
or
exists(this.getImportedModule().getAnExportedValue("__esModule"))
}
}
DataFlow::SourceNode getImportedObject() {
/** A call that wraps the imported object in a `default` property, unless it is from an ES2015 module. */
private class InteropRequireCall extends ModuleInteropCall {
InteropRequireCall() {
this.getCalleeName() = ["_interopRequireDefault", "_interopRequireWildcard"]
}
DataFlow::SourceNode getImportedObjectRef() {
this.isImportingESModule() and
result = this
or
@@ -27,14 +35,42 @@ class ES2015InteropCall extends DataFlow::CallNode {
}
}
/**
* A call that read the `default` property if it exists, otherwise returns the object as-is.
*/
private class InteropDefaultCall extends ModuleInteropCall {
InteropDefaultCall() { this.getCalleeName() = "_interopDefault" }
DataFlow::Node getDefaultExport() {
result = this.getImportedModule().getAnExportedValue("default")
}
DataFlow::Node getImportedObjectSource() {
result = this.getDefaultExport()
or
not exists(this.getDefaultExport()) and
result = this.getArgument(0)
}
}
predicate interopModuleStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(ES2015InteropCall call |
exists(InteropRequireCall call |
pred = call.getArgument(0) and
succ = call.getImportedObject()
succ = call.getImportedObjectRef()
or
exists(string prop |
pred = call.getImportedModule().getAnExportedValue(prop) and
succ = call.getImportedObject().getAPropertyRead(prop)
succ = call.getImportedObjectRef().getAPropertyRead(prop)
)
)
or
exists(InteropDefaultCall call |
pred = call.getImportedObjectSource() and
succ = call
or
exists(string prop |
pred = call.getDefaultExport().getALocalSource().getAPropertyWrite(prop).getRhs() and
succ = call.getAPropertyRead(prop)
)
)
}