joern icon indicating copy to clipboard operation
joern copied to clipboard

[gosrc2cpg] Missing function calls inside if statement

Open l1006986533 opened this issue 1 year ago • 0 comments

Describe the bug When I analyze a Go file with Joern, function calls inside an if statement are not correctly identified and listed.

To Reproduce Steps to reproduce the behavior:

  1. Create a go file
package main
import "fmt"

func myfunc() *string{
	var s string = "hello world"
	return &s
}

func main() {
	if s := myfunc(); s != nil {
    	fmt.Println(*s)
	}
}
  1. import and output all function calls by cpg.call.l
joern> importCode(inputPath="a.go", projectName="a-go")

Using generator for language: GOLANG: GoCpgGenerator
Creating project `a-go` for code at `a.go`
Project with name a-go already exists - overwriting
=======================================================================================================
Invoking CPG generator in a separate process. Note that the new process will consume additional memory.
If you are importing a large codebase (and/or running into memory issues), please try the following:
1) exit joern
2) invoke the frontend: /opt/joern/joern-cli/gosrc2cpg a.go -o /Users/xxx/xxx/workspace/a-go/cpg.bin.zip
3) start joern, import the cpg: `importCpg("path/to/cpg")`
=======================================================================================================

moving cpg.bin.zip to cpg.bin because it is already a database file
Creating working copy of CPG to be safe
Loading base CPG from: /Users/xxx/xxx/workspace/a-go/cpg.bin.tmp
Code successfully imported. You can now query it using `cpg`.
For an overview of all imported code, type `workspace`.
Adding default overlays to base CPG
The graph has been modified. You may want to use the `save` command to persist changes to disk.  All changes will also be saved collectively on exit
The graph has been modified. You may want to use the `save` command to persist changes to disk.  All changes will also be saved collectively on exit
val res0: io.shiftleft.codepropertygraph.generated.Cpg = Cpg[Graph[64 nodes]]
                                                                                                                                       
joern> cpg.call.l

val res1: List[io.shiftleft.codepropertygraph.generated.nodes.Call] = List(
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "s string = \"hello world\"",
    columnNumber = Some(value = 17),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 5),
    methodFullName = "<operator>.assignment",
    name = "<operator>.assignment",
    order = 2,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "string"
  ),
  Call(
    argumentIndex = 1,
    argumentName = None,
    code = "&s",
    columnNumber = Some(value = 9),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 6),
    methodFullName = "<operator>.addressOf",
    name = "<operator>.addressOf",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "*string"
  ),
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "s != nil",
    columnNumber = Some(value = 20),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 10),
    methodFullName = "<operator>.notEquals",
    name = "<operator>.notEquals",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "bool"
  ),
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "fmt.Println(*s)",
    columnNumber = Some(value = 6),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 11),
    methodFullName = "fmt.Println",
    name = "Println",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "fmt.Println()",
    typeFullName = "fmt.Println.<ReturnType>.<unknown>"
  ),
  Call(
    argumentIndex = 1,
    argumentName = None,
    code = "*s",
    columnNumber = Some(value = 18),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 11),
    methodFullName = "<operator>.indirection",
    name = "<operator>.indirection",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "ANY"
  )
)
             

Here we can see myfunc call is missing.

  1. change the source code and separate if statement into two parts
package main
import "fmt"

func myfunc() *string{
	var s string = "hello world"
	return &s
}

func main() {
	s := myfunc()
	if s != nil {
    	fmt.Println(*s)
	}
}
  1. re-import and list all function calls
joern> importCode(inputPath="a.go", projectName="a-go")

Using generator for language: GOLANG: GoCpgGenerator
Creating project `a-go` for code at `a.go`
Project with name a-go already exists - overwriting
closing/saving project `a-go`
=======================================================================================================
Invoking CPG generator in a separate process. Note that the new process will consume additional memory.
If you are importing a large codebase (and/or running into memory issues), please try the following:
1) exit joern
2) invoke the frontend: /opt/joern/joern-cli/gosrc2cpg a.go -o /Users/xxx/xxx/workspace/a-go/cpg.bin.zip
3) start joern, import the cpg: `importCpg("path/to/cpg")`
=======================================================================================================

moving cpg.bin.zip to cpg.bin because it is already a database file
Creating working copy of CPG to be safe
Loading base CPG from: /Users/xxx/xxx/a-go/cpg.bin.tmp
Code successfully imported. You can now query it using `cpg`.
For an overview of all imported code, type `workspace`.
Adding default overlays to base CPG
The graph has been modified. You may want to use the `save` command to persist changes to disk.  All changes will also be saved collectively on exit
The graph has been modified. You may want to use the `save` command to persist changes to disk.  All changes will also be saved collectively on exit
val res2: io.shiftleft.codepropertygraph.generated.Cpg = Cpg[Graph[68 nodes]]
                                                                                                                                       
joern> cpg.call.l

val res3: List[io.shiftleft.codepropertygraph.generated.nodes.Call] = List(
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "s string = \"hello world\"",
    columnNumber = Some(value = 17),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 5),
    methodFullName = "<operator>.assignment",
    name = "<operator>.assignment",
    order = 2,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "string"
  ),
  Call(
    argumentIndex = 1,
    argumentName = None,
    code = "&s",
    columnNumber = Some(value = 9),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 6),
    methodFullName = "<operator>.addressOf",
    name = "<operator>.addressOf",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "*string"
  ),
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "s := myfunc()",
    columnNumber = Some(value = 7),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 10),
    methodFullName = "<operator>.assignment",
    name = "<operator>.assignment",
    order = 2,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "*string"
  ),
  Call(
    argumentIndex = 2,
    argumentName = None,
    code = "myfunc()",
    columnNumber = Some(value = 7),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 10),
    methodFullName = "main.myfunc",
    name = "myfunc",
    order = 2,
    possibleTypes = IndexedSeq(),
    signature = "main.myfunc()*string",
    typeFullName = "*string"
  ),
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "s != nil",
    columnNumber = Some(value = 5),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 11),
    methodFullName = "<operator>.notEquals",
    name = "<operator>.notEquals",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "bool"
  ),
  Call(
    argumentIndex = -1,
    argumentName = None,
    code = "fmt.Println(*s)",
    columnNumber = Some(value = 6),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 12),
    methodFullName = "fmt.Println",
    name = "Println",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "fmt.Println()",
    typeFullName = "fmt.Println.<ReturnType>.<unknown>"
  ),
  Call(
    argumentIndex = 1,
    argumentName = None,
    code = "*s",
    columnNumber = Some(value = 18),
    dispatchType = "STATIC_DISPATCH",
    dynamicTypeHintFullName = IndexedSeq(),
    lineNumber = Some(value = 12),
    methodFullName = "<operator>.indirection",
    name = "<operator>.indirection",
    order = 1,
    possibleTypes = IndexedSeq(),
    signature = "",
    typeFullName = "*string"
  )
)

Here myfunc call is correctly listed as 4th.

Expected behavior myfunc function call should be listed in both situations.

Screenshots No screenshot.

Desktop (please complete the following information):

  • OS: MacOS Sonoma 14.5
  • Joern Version: 4.0.93
  • Java version: 21.0.4
> java --version
java 21.0.4 2024-07-16 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 21.0.4+8.1 (build 21.0.4+8-LTS-jvmci-23.1-b41)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21.0.4+8.1 (build 21.0.4+8-LTS-jvmci-23.1-b41, mixed mode, sharing)

Additional context No additional context.

l1006986533 avatar Oct 08 '24 13:10 l1006986533