Skip to content

Commit

Permalink
Fix: Create Sources from ClosureBindings over MethodRefs (#2343)
Browse files Browse the repository at this point in the history
The nodes and edges of `ClosureBinding` and `CAPTURE` hold the information containing which parent identifiers are associated with which child identifiers in children scopes.

* Added `DeclarationTraversal` to centralize the ability to use `CAPTURE` and `CLOSURE_BINDING` properties
* Leverage these properties instead of naively traversing child methods
  • Loading branch information
DavidBakerEffendi authored Mar 6, 2023
1 parent 5797650 commit 65f36d3
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package io.joern.dataflowengineoss.queryengine

import io.joern.x2cpg.Defines
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.generated.Operators
import io.shiftleft.codepropertygraph.generated.nodes._
import io.shiftleft.codepropertygraph.generated.{Operators, PropertyNames}
import io.shiftleft.semanticcpg.language._
import io.shiftleft.semanticcpg.language.operatorextension.allAssignmentTypes
import org.slf4j.LoggerFactory
Expand Down Expand Up @@ -63,7 +63,9 @@ class SourceToStartingPoints(src: StoredNode) extends RecursiveTask[List[CfgNode

private val cpg = Cpg(src.graph())

override def compute(): List[CfgNode] = {
override def compute(): List[CfgNode] = sourceToStartingPoints(src)

private def sourceToStartingPoints(src: StoredNode): List[CfgNode] = {
src match {
case methodReturn: MethodReturn =>
methodReturn.method.callIn.l
Expand All @@ -72,25 +74,25 @@ class SourceToStartingPoints(src: StoredNode) extends RecursiveTask[List[CfgNode
// is being passed to. Perhaps not the most sound as this doesn't handle re-assignment super well but it's
// difficult to check the control flow of when the method ref might use the value
val firstUsagesOfLHSIdentifiers =
lit.inAssignment.argument(1).isIdentifier.flatMap(identifiersFromChildScopes).l.distinctBy(_.method)
lit.inAssignment.argument(1).isIdentifier.refsTo.flatMap(identifiersFromCapturedScopes).l.distinctBy(_.method)
List(lit) ++ usages(
targetsToClassIdentifierPair(literalToInitializedMembers(lit))
) ++ firstUsagesOfLHSIdentifiers
case member: Member =>
usages(targetsToClassIdentifierPair(List(member)))
case x @ (_: Identifier | _: MethodParameterIn) =>
List(x).collectAll[CfgNode].toList ++ identifiersFromChildScopes(x.asInstanceOf[CfgNode])
case x: Declaration =>
List(x).collectAll[CfgNode].toList ++ identifiersFromCapturedScopes(x)
case x: Identifier =>
List(x).collectAll[CfgNode].toList ++ x.refsTo.collectAll[Local].flatMap(sourceToStartingPoints)
case x => List(x).collect { case y: CfgNode => y }
}
}

private def identifiersFromChildScopes(i: CfgNode): List[Identifier] = {
val name = i.property(PropertyNames.NAME, i.code)
i.method.ast.isMethodRef.referencedMethod.ast.isIdentifier
.nameExact(name)
private def identifiersFromCapturedScopes(i: Declaration): List[Identifier] =
i.capturedByMethodRef.referencedMethod.ast.isIdentifier
.nameExact(i.name)
.sortBy(x => (x.lineNumber, x.columnNumber))
.l
}

private def usages(pairs: List[(TypeDecl, AstNode)]): List[CfgNode] = {
pairs.flatMap { case (typeDecl, astNode) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import io.shiftleft.semanticcpg.language.nodemethods._
import io.shiftleft.semanticcpg.language.types.expressions.generalizations.{
AstNodeTraversal,
CfgNodeTraversal,
DeclarationTraversal,
ExpressionTraversal
}
import io.shiftleft.semanticcpg.language.types.expressions.{CallTraversal => OriginalCall, _}
Expand Down Expand Up @@ -271,4 +272,9 @@ trait LowPrioImplicits extends overflowdb.traversal.Implicits {
new AstNodeTraversal[A](Traversal.fromSingle(a))
implicit def iterOnceToAstNodeTraversal[A <: AstNode](a: IterableOnce[A]): AstNodeTraversal[A] =
new AstNodeTraversal[A](iterableToTraversal(a))

implicit def singleToDeclarationNodeTraversal[A <: Declaration](a: A): DeclarationTraversal[A] =
new DeclarationTraversal[A](Traversal.fromSingle(a))
implicit def iterOnceToDeclarationNodeTraversal[A <: Declaration](a: IterableOnce[A]): DeclarationTraversal[A] =
new DeclarationTraversal[A](iterableToTraversal(a))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.shiftleft.semanticcpg.language.types.expressions.generalizations

import io.shiftleft.codepropertygraph.generated.nodes.{ClosureBinding, Declaration, MethodRef}
import overflowdb.traversal.{Traversal, help, jIteratortoTraversal}

/** A declaration, such as a local or parameter.
*/
@help.Traversal(elementType = classOf[Declaration])
class DeclarationTraversal[NodeType <: Declaration](val traversal: Traversal[NodeType]) extends AnyVal {

/** The closure binding node referenced by this declaration
*/
def closureBinding: Traversal[ClosureBinding] = traversal.flatMap(_._refIn).collectAll[ClosureBinding]

/** Methods that capture this declaration
*/
def capturedByMethodRef: Traversal[MethodRef] = closureBinding.flatMap(_._captureIn).collectAll[MethodRef]

/** Types that capture this declaration
*/
def capturedByTypeRef: Traversal[MethodRef] = closureBinding.flatMap(_._captureIn).collectAll[MethodRef]

}

0 comments on commit 65f36d3

Please sign in to comment.