Repository: ShiftLeftSecurity/codepropertygraph (language: python)

Issue:
Duplicate REACHING_DEF edges
REACHING_DEF edges between RETURN nodes and their corresponding CALL nodes exist twice.


Discussion / hints:
Can you provide a sample code snippet on which this happened? Not sure what you mean exactly.
```
int foo() {
  return bar();
}
```

The CALL to `bar()` has ID `1000105L`:
```
  Call(
    id -> 1000105L,
    code -> "bar()",
    name -> "bar",
    order -> 1,
    methodInstFullName -> None,
    methodFullName -> "bar",
    argumentIndex -> 1,
    dispatchType -> "STATIC_DISPATCH",
    signature -> "TODO assignment signature",
    typeFullName -> "ANY",
    dynamicTypeHintFullName -> List(),
    lineNumber -> Some(2),
    columnNumber -> Some(9),
    resolved -> None,
    depthFirstOrder -> None,
    internalFlags -> None
  )
  ```
I'm using an ID to make sure that there is only a single node in the traversal.

Then run `run.ossdataflow` and:
```
joern> cpg.call.id(1000105L).outE(EdgeTypes.REACHING_DEF).inV.l 
res8: List[Node] = List(
  Return(
    id -> 1000104L,
    lineNumber -> Some(2),
    columnNumber -> Some(2),
    order -> 1,
    argumentIndex -> 1,
    code -> "return bar();",
    depthFirstOrder -> None,
    internalFlags -> None
  ),
  Return(
    id -> 1000104L,
    lineNumber -> Some(2),
    columnNumber -> Some(2),
    order -> 1,
    argumentIndex -> 1,
    code -> "return bar();",
    depthFirstOrder -> None,
    internalFlags -> None
  )
)
```

The edge is attached twice to the nodes involved:
```
joern> cpg.call.id(1000105L).outE(EdgeTypes.REACHING_DEF).l 
res9: List[Edge] = List(
  io.shiftleft.codepropertygraph.generated.edges.ReachingDef@7e66ecb3,
  io.shiftleft.codepropertygraph.generated.edges.ReachingDef@7e66ecb3
)

joern> cpg.all.id(1000104L).inE(EdgeTypes.REACHING_DEF).l 
res10: List[Edge] = List(
  io.shiftleft.codepropertygraph.generated.edges.ReachingDef@7e66ecb3,
  io.shiftleft.codepropertygraph.generated.edges.ReachingDef@7e66ecb3
)
```
Ok, thanks, looking...

Fix patch:
diff --git a/dataflowengineoss/src/main/scala/io/shiftleft/dataflowengineoss/passes/reachingdef/ReachingDefPass.scala b/dataflowengineoss/src/main/scala/io/shiftleft/dataflowengineoss/passes/reachingdef/ReachingDefPass.scala
index 43992f762..bd60de429 100755
--- a/dataflowengineoss/src/main/scala/io/shiftleft/dataflowengineoss/passes/reachingdef/ReachingDefPass.scala
+++ b/dataflowengineoss/src/main/scala/io/shiftleft/dataflowengineoss/passes/reachingdef/ReachingDefPass.scala
@@ -70,7 +70,7 @@ class ReachingDefPass(cpg: Cpg) extends ParallelCpgPass[nodes.Method](cpg) {
           usageAnalyzer.usedIncomingDefs(ret).foreach {
             case (use, inElements) =>
               addEdge(use, ret, use.asInstanceOf[nodes.CfgNode].code)
-              inElements.foreach { inElement =>
+              inElements.filter(x => x.node != use).foreach { inElement =>
                 addEdge(inElement.node, ret, nodeToEdgeLabel(inElement.node))
               }
               if (inElements.isEmpty) {


Test patch:
diff --git a/fuzzyc2cpg-tests/src/test/scala/io/shiftleft/fuzzyc2cpg/querying/CDataFlowTests.scala b/fuzzyc2cpg-tests/src/test/scala/io/shiftleft/fuzzyc2cpg/querying/CDataFlowTests.scala
index 807a47d4d..d339343f3 100644
--- a/fuzzyc2cpg-tests/src/test/scala/io/shiftleft/fuzzyc2cpg/querying/CDataFlowTests.scala
+++ b/fuzzyc2cpg-tests/src/test/scala/io/shiftleft/fuzzyc2cpg/querying/CDataFlowTests.scala
@@ -1,5 +1,6 @@
 package io.shiftleft.fuzzyc2cpg.querying
 
+import io.shiftleft.codepropertygraph.generated.EdgeTypes
 import io.shiftleft.fuzzyc2cpg.testfixtures.DataFlowCodeToCpgSuite
 import io.shiftleft.semanticcpg.language._
 import overflowdb.traversal.Traversal
@@ -920,3 +921,21 @@ class CDataFlowTests29 extends DataFlowCodeToCpgSuite {
     flows.size shouldBe 0
   }
 }
+
+class CDataFlowTests31 extends DataFlowCodeToCpgSuite {
+  override val code =
+    """
+      |int foo() {
+      | return bar();
+      |}
+      |
+      |""".stripMargin
+
+  "Test 31: should not create edges from call to ret twice" in {
+    implicit val s: Semantics = semantics
+    cpg
+      .call("bar")
+      .outE(EdgeTypes.REACHING_DEF)
+      .count(_.inNode() == cpg.ret.head) shouldBe 1
+  }
+}