joern
joern copied to clipboard
[gosrc2cpg] Missing function calls inside if statement
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:
- 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)
}
}
- 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.
- 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)
}
}
- 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.