From 8a737a8420850854215afdaf9f87d994bfc4157e Mon Sep 17 00:00:00 2001 From: MaxMilshin Date: Sun, 9 Jun 2024 17:47:34 +0300 Subject: [PATCH] enhance checking for unresolved variables --- ...kt => ArgumentParameterMatchingChecker.kt} | 2 +- ...gAnalyser.kt => ImplicitCastingChecker.kt} | 2 +- ...rsAnalyser.kt => MissingMembersChecker.kt} | 2 +- ...lyser.kt => UndeclaredVariablesChecker.kt} | 87 +- .../jacodb/panda/dynamic/parser/IRParser.kt | 17 +- .../analysis/PrimaryStaticAnalysisTest.kt | 47 +- .../codeqlSamples/unresolvedVariable2.json | 1007 +++++++++++++++++ .../codeqlSamples/unresolvedVariable2.ts | 21 + .../codeqlSamples/unresolvedVariable3.json | 956 ++++++++++++++++ .../codeqlSamples/unresolvedVariable3.ts | 17 + 10 files changed, 2128 insertions(+), 30 deletions(-) rename jacodb-panda-analysis/src/main/kotlin/panda/primary/{ArgumentParameterMatchingAnalyser.kt => ArgumentParameterMatchingChecker.kt} (98%) rename jacodb-panda-analysis/src/main/kotlin/panda/primary/{ImplicitCastingAnalyser.kt => ImplicitCastingChecker.kt} (98%) rename jacodb-panda-analysis/src/main/kotlin/panda/primary/{MissingMembersAnalyser.kt => MissingMembersChecker.kt} (98%) rename jacodb-panda-analysis/src/main/kotlin/panda/primary/{UndeclaredVariablesAnalyser.kt => UndeclaredVariablesChecker.kt} (54%) create mode 100644 jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.json create mode 100644 jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.ts create mode 100644 jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.json create mode 100644 jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.ts diff --git a/jacodb-panda-analysis/src/main/kotlin/panda/primary/ArgumentParameterMatchingAnalyser.kt b/jacodb-panda-analysis/src/main/kotlin/panda/primary/ArgumentParameterMatchingChecker.kt similarity index 98% rename from jacodb-panda-analysis/src/main/kotlin/panda/primary/ArgumentParameterMatchingAnalyser.kt rename to jacodb-panda-analysis/src/main/kotlin/panda/primary/ArgumentParameterMatchingChecker.kt index b59e86233..bf5d2bf82 100644 --- a/jacodb-panda-analysis/src/main/kotlin/panda/primary/ArgumentParameterMatchingAnalyser.kt +++ b/jacodb-panda-analysis/src/main/kotlin/panda/primary/ArgumentParameterMatchingChecker.kt @@ -20,7 +20,7 @@ import org.jacodb.panda.dynamic.api.* private val logger = mu.KotlinLogging.logger {} -class ArgumentParameterMatchingAnalyser(val project: PandaProject) { +class ArgumentParameterMatchingChecker(val project: PandaProject) { val graph = PandaApplicationGraphImpl(project) fun analyseOneCase(startMethods: List): List> { diff --git a/jacodb-panda-analysis/src/main/kotlin/panda/primary/ImplicitCastingAnalyser.kt b/jacodb-panda-analysis/src/main/kotlin/panda/primary/ImplicitCastingChecker.kt similarity index 98% rename from jacodb-panda-analysis/src/main/kotlin/panda/primary/ImplicitCastingAnalyser.kt rename to jacodb-panda-analysis/src/main/kotlin/panda/primary/ImplicitCastingChecker.kt index 24aa19825..e47cae098 100644 --- a/jacodb-panda-analysis/src/main/kotlin/panda/primary/ImplicitCastingAnalyser.kt +++ b/jacodb-panda-analysis/src/main/kotlin/panda/primary/ImplicitCastingChecker.kt @@ -25,7 +25,7 @@ enum class ImplicitCastAnalysisMode { POSSIBILITY_CHECK } -class ImplicitCastingAnalyser(val project: PandaProject) { +class ImplicitCastingChecker(val project: PandaProject) { val graph = PandaApplicationGraphImpl(project) fun analyseOneCase( diff --git a/jacodb-panda-analysis/src/main/kotlin/panda/primary/MissingMembersAnalyser.kt b/jacodb-panda-analysis/src/main/kotlin/panda/primary/MissingMembersChecker.kt similarity index 98% rename from jacodb-panda-analysis/src/main/kotlin/panda/primary/MissingMembersAnalyser.kt rename to jacodb-panda-analysis/src/main/kotlin/panda/primary/MissingMembersChecker.kt index 28fde1c1d..f20185e20 100644 --- a/jacodb-panda-analysis/src/main/kotlin/panda/primary/MissingMembersAnalyser.kt +++ b/jacodb-panda-analysis/src/main/kotlin/panda/primary/MissingMembersChecker.kt @@ -20,7 +20,7 @@ import org.jacodb.panda.dynamic.api.* private val logger = mu.KotlinLogging.logger {} -class MissingMembersAnalyser(val project: PandaProject) { +class MissingMembersChecker(val project: PandaProject) { val graph = PandaApplicationGraphImpl(project) companion object { diff --git a/jacodb-panda-analysis/src/main/kotlin/panda/primary/UndeclaredVariablesAnalyser.kt b/jacodb-panda-analysis/src/main/kotlin/panda/primary/UndeclaredVariablesChecker.kt similarity index 54% rename from jacodb-panda-analysis/src/main/kotlin/panda/primary/UndeclaredVariablesAnalyser.kt rename to jacodb-panda-analysis/src/main/kotlin/panda/primary/UndeclaredVariablesChecker.kt index b400c34a0..964cd42e9 100644 --- a/jacodb-panda-analysis/src/main/kotlin/panda/primary/UndeclaredVariablesAnalyser.kt +++ b/jacodb-panda-analysis/src/main/kotlin/panda/primary/UndeclaredVariablesChecker.kt @@ -20,7 +20,18 @@ import org.jacodb.panda.dynamic.api.* private val logger = mu.KotlinLogging.logger {} -class UndeclaredVariablesAnalyser(val project: PandaProject) { +enum class VarAccess { + READ, WRITE +} + +class UndeclaredVariablesCheckerError( + val varName: String, + val inst: PandaInst, + val varAccess: VarAccess, + val isConstant: Lazy +) + +class UndeclaredVariablesChecker(val project: PandaProject) { val graph = PandaApplicationGraphImpl(project) private val orderedInstructions = mutableListOf() @@ -55,13 +66,14 @@ class UndeclaredVariablesAnalyser(val project: PandaProject) { orderedInstructions.reverse() } - // TODO(): expand for writing (trysttoglobalbyname) and constants (stconsttoglobalbyname) - fun analyse(): List> { + fun analyse(): List { topologicalSort(graph) val instToGlobalVars = mutableMapOf>() - val unresolvedVariables = mutableListOf>() + val isVarConstantMap = mutableMapOf() + + val unresolvedVariables = mutableListOf() for (inst in orderedInstructions) { var predecessorInstructions = mutableListOf() @@ -78,24 +90,79 @@ class UndeclaredVariablesAnalyser(val project: PandaProject) { instToGlobalVars[inst]!!.intersect(instToGlobalVars[predecessorInst]!!) } if (inst is PandaAssignInst && inst.varName != null) { - instToGlobalVars[inst]!!.add(inst.varName!!) + val varName = inst.varName!! + val name = when { + varName.startsWith("constant.") -> { + val slicedName = varName.substring(9) + isVarConstantMap[slicedName] = true + slicedName + } + else -> varName + } + instToGlobalVars[inst]!!.add(name) } - // adhoc check for tryldglobalname, TODO(): check trysttoglobalname (for both will be cooler after better global variable processing) + + // TODO("refactor after better global variable processing in IR") + // check for tryldglobalname val probablyUndefinedVarNames = inst.recursiveOperands.mapNotNull { op -> if (op is PandaLoadedValue && op.instance is PandaStringConstant) { - ((op.instance) as PandaStringConstant).value + Pair( + ((op.instance) as PandaStringConstant).value, + VarAccess.READ + ) } else null + }.toMutableList() + + // check for trystglobalbyname + if (inst is PandaAssignInst && inst.lhv is PandaLoadedValue) { + val lhvInstance = (inst.lhv as PandaLoadedValue).instance + if (lhvInstance is PandaStringConstant) { + probablyUndefinedVarNames.add( + Pair( + lhvInstance.value, + VarAccess.WRITE + ) + ) + } } val stdVarNames = listOf("console") // TODO(): need more smart filter - probablyUndefinedVarNames.forEach { varName -> + probablyUndefinedVarNames.forEach { varInfo -> + val varName = varInfo.first + val varAccess = varInfo.second if (varName !in stdVarNames && varName !in instToGlobalVars[inst]!!) { - unresolvedVariables.add(Pair(varName, inst)) - logger.info { "unresolved variable $varName in $inst with location: (method:${inst.location.method}, index: ${inst.location.index})" } + unresolvedVariables.add( + UndeclaredVariablesCheckerError( + varName = varName, + inst = inst, + varAccess = varAccess, + isConstant = lazy { + isVarConstantMap.getOrDefault(varName, false) + } + ) + ) } } } + val varAccessToStr: (VarAccess) -> String = { varAccess -> + when(varAccess) { + VarAccess.WRITE -> "Write" + VarAccess.READ -> "Read" + } + } + + val isVarConstantToString: (Boolean) -> String = { isVarConstant -> + when(isVarConstant) { + true -> "constant" + false -> "regular" + } + } + + unresolvedVariables.forEach { err -> + logger.info { "${varAccessToStr(err.varAccess)} access to undeclared ${isVarConstantToString(err.isConstant.value)} variable ${err.varName} in ${err.inst} (location: ${err.inst.location})" } + } + return unresolvedVariables } } \ No newline at end of file diff --git a/jacodb-panda-dynamic/src/main/kotlin/org/jacodb/panda/dynamic/parser/IRParser.kt b/jacodb-panda-dynamic/src/main/kotlin/org/jacodb/panda/dynamic/parser/IRParser.kt index d68d66261..ea0f39503 100644 --- a/jacodb-panda-dynamic/src/main/kotlin/org/jacodb/panda/dynamic/parser/IRParser.kt +++ b/jacodb-panda-dynamic/src/main/kotlin/org/jacodb/panda/dynamic/parser/IRParser.kt @@ -983,6 +983,14 @@ class IRParser( } val localVar = inputs[0] method.nameToLocalVarId[variableName] = localVar + // tmp + if (inputs[0] is PandaConstant) { + val lv = PandaLocalVar(method.currentLocalVarId++, PandaAnyType) + val assignment = PandaAssignInst(locationFromOp(this), lv, inputs[0], varName = "constant.${stringData!!}") + method.pushInst(assignment) + program!!.setLocalAssignment(method.signature, lv, assignment) + env.setLocalVar(stringData!!, lv) + } } "Intrinsic.callthis0" -> { @@ -1125,9 +1133,12 @@ class IRParser( } "Intrinsic.trystglobalbyname" -> { - val lv = env.getLocalVar(stringData!!) - ?: error("Can't load local var from environment for literal \"$stringData\"") - method.pushInst(PandaAssignInst(locationFromOp(this), lv, inputs[0])) + val name = stringData!! +// val lv = env.getLocalVar(name) +// ?: error("Can't load local var from environment for literal \"$stringData\"") + val assignee = env.getLocalVar(name) + ?: PandaLoadedValue(PandaStringConstant(name)) + method.pushInst(PandaAssignInst(locationFromOp(this), assignee, inputs[0])) } else -> checkIgnoredInstructions(this) diff --git a/jacodb-panda-dynamic/src/test/kotlin/analysis/PrimaryStaticAnalysisTest.kt b/jacodb-panda-dynamic/src/test/kotlin/analysis/PrimaryStaticAnalysisTest.kt index 2e17c1ef9..8057aefae 100644 --- a/jacodb-panda-dynamic/src/test/kotlin/analysis/PrimaryStaticAnalysisTest.kt +++ b/jacodb-panda-dynamic/src/test/kotlin/analysis/PrimaryStaticAnalysisTest.kt @@ -16,6 +16,7 @@ package analysis +import org.jacodb.panda.dynamic.api.PandaProject import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test @@ -23,12 +24,16 @@ import panda.primary.* import parser.loadIr class PrimaryStaticAnalysisTest { + private fun getProjectByProgramName(programName: String): PandaProject { + val parser = loadIr("/samples/${programName}.json") + return parser.getProject() + } + @Nested inner class ArgumentParameterCorrespondenceTest { private val programName = "codeqlSamples/parametersArgumentsMismatch" - private val parser = loadIr("/samples/${programName}.json") - private val project = parser.getProject() - private val analyser = ArgumentParameterMatchingAnalyser(project) + private val project = getProjectByProgramName(programName) + private val analyser = ArgumentParameterMatchingChecker(project) @Test fun `test for mismatch detection in regular function call`() { @@ -74,24 +79,39 @@ class PrimaryStaticAnalysisTest { @Nested inner class UnresolvedVariableTest { - private val programName = "codeqlSamples/unresolvedVariable" - private val parser = loadIr("/samples/${programName}.json") - private val project = parser.getProject() - private val analyser = UndeclaredVariablesAnalyser(project) + private fun getAnalyserByProgramName(programName: String): UndeclaredVariablesChecker { + val project = getProjectByProgramName(programName) + val analyser = UndeclaredVariablesChecker(project) + return analyser + } @Test fun `counterexample - program that read some unresolved variables`() { + val analyser = getAnalyserByProgramName("codeqlSamples/unresolvedVariable") val unresolvedVariables = analyser.analyse() assert(unresolvedVariables.size == 4) } + + @Test + fun `counterexample - program that also write into unresolved variables`() { + val analyser = getAnalyserByProgramName("codeqlSamples/unresolvedVariable2") + val unresolvedVariables = analyser.analyse() + assert(unresolvedVariables.size == 3) + } + + @Test + fun `counterexample - program that read undeclared const variables`() { + val analyser = getAnalyserByProgramName("codeqlSamples/unresolvedVariable3") + val unresolvedVariables = analyser.analyse() + assert(unresolvedVariables.size == 3) + } } @Nested inner class ImplicitCastingTest { private val programName = "codeqlSamples/implicitCasting" - private val parser = loadIr("/samples/${programName}.json") - private val project = parser.getProject() - private val analyser = ImplicitCastingAnalyser(project) + private val project = getProjectByProgramName(programName) + private val analyser = ImplicitCastingChecker(project) @Test fun `test implicit casting observation in binary expressions with primitive literals`() { @@ -132,10 +152,9 @@ class PrimaryStaticAnalysisTest { @Nested inner class MissingMembersTest { - private fun getAnalyserByProgramName(programName: String): MissingMembersAnalyser { - val parser = loadIr("/samples/${programName}.json") - val project = parser.getProject() - val analyser = MissingMembersAnalyser(project) + private fun getAnalyserByProgramName(programName: String): MissingMembersChecker { + val project = getProjectByProgramName(programName) + val analyser = MissingMembersChecker(project) return analyser } diff --git a/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.json b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.json new file mode 100644 index 000000000..2e04b7009 --- /dev/null +++ b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.json @@ -0,0 +1,1007 @@ +{ + "classes": [ + { + "name": "GLOBAL", + "properties": [ + { + "method": { + "accessFlags": 264, + "basicBlocks": [ + { + "id": 1, + "insts": [ + { + "id": "v0", + "index": 0, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v1", + "index": 1, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v2", + "index": 2, + "opcode": "Parameter", + "type": "any" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "successors": [ + 0 + ] + }, + { + "id": 0, + "insts": [ + { + "id": "v3", + "opcode": "SaveState", + "type": "void", + "users": [ + "v4" + ] + }, + { + "id": "v4", + "inputs": [ + "v3" + ], + "opcode": "LoadString", + "string": "bar function call", + "stringOffset": 206, + "type": "ref", + "users": [ + "v5" + ] + }, + { + "id": "v5", + "inputs": [ + "v4" + ], + "opcode": "CastValueToAnyType", + "type": "any", + "users": [ + "v6" + ] + }, + { + "id": "v7", + "opcode": "SaveState", + "type": "void", + "users": [ + "v6" + ] + }, + { + "id": "v6", + "imms": [ + 0, + 225 + ], + "inputs": [ + "v5", + "v7" + ], + "intrinsic_id": "Intrinsic.trystglobalbyname", + "opcode": "Intrinsic", + "string_data": "c", + "type": "void" + }, + { + "id": "v9", + "opcode": "SaveState", + "type": "void", + "users": [ + "v8" + ] + }, + { + "id": "v8", + "imms": [ + 1, + 228 + ], + "inputs": [ + "v9" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "console", + "type": "any", + "users": [ + "v14", + "v10" + ] + }, + { + "id": "v11", + "opcode": "SaveState", + "type": "void", + "users": [ + "v10" + ] + }, + { + "id": "v10", + "imms": [ + 2, + 245 + ], + "inputs": [ + "v8", + "v11" + ], + "intrinsic_id": "Intrinsic.ldobjbyname", + "opcode": "Intrinsic", + "string_data": "log", + "type": "any", + "users": [ + "v14" + ] + }, + { + "id": "v13", + "opcode": "SaveState", + "type": "void", + "users": [ + "v12" + ] + }, + { + "id": "v12", + "imms": [ + 4, + 225 + ], + "inputs": [ + "v13" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "c", + "type": "any", + "users": [ + "v14" + ] + }, + { + "id": "v15", + "opcode": "SaveState", + "type": "void", + "users": [ + "v14" + ] + }, + { + "id": "v14", + "imms": [ + 5 + ], + "inputs": [ + "v8", + "v12", + "v10", + "v15" + ], + "intrinsic_id": "Intrinsic.callthis1", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v17", + "opcode": "SaveState", + "type": "void", + "users": [ + "v16" + ] + }, + { + "id": "v16", + "inputs": [ + "v17" + ], + "intrinsic_id": "Intrinsic.ldundefined", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v19", + "opcode": "SaveState", + "type": "void", + "users": [ + "v18" + ] + }, + { + "id": "v18", + "inputs": [ + "v19" + ], + "intrinsic_id": "Intrinsic.returnundefined", + "opcode": "Intrinsic", + "type": "void" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 1 + ], + "successors": [ + 2 + ] + }, + { + "id": 2, + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 0 + ] + } + ], + "name": "bar", + "returnType": "any", + "signature": ".bar" + }, + "name": "bar" + }, + { + "method": { + "accessFlags": 264, + "basicBlocks": [ + { + "id": 1, + "insts": [ + { + "id": "v0", + "index": 0, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v1", + "index": 1, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v2", + "index": 2, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v3", + "index": 3, + "opcode": "Parameter", + "type": "any", + "users": [ + "v5" + ] + }, + { + "id": "v4", + "index": 4, + "opcode": "Parameter", + "type": "any", + "users": [ + "v5" + ] + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "successors": [ + 0 + ] + }, + { + "id": 0, + "insts": [ + { + "id": "v6", + "opcode": "SaveState", + "type": "void", + "users": [ + "v5" + ] + }, + { + "id": "v5", + "imms": [ + 0 + ], + "inputs": [ + "v3", + "v4", + "v6" + ], + "intrinsic_id": "Intrinsic.add2", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v9" + ] + }, + { + "id": "v8", + "opcode": "SaveState", + "type": "void", + "users": [ + "v7" + ] + }, + { + "id": "v7", + "imms": [ + 1, + 237 + ], + "inputs": [ + "v8" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "d", + "type": "any", + "users": [ + "v9" + ] + }, + { + "id": "v10", + "opcode": "SaveState", + "type": "void", + "users": [ + "v9" + ] + }, + { + "id": "v9", + "imms": [ + 2 + ], + "inputs": [ + "v5", + "v7", + "v10" + ], + "intrinsic_id": "Intrinsic.add2", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v11" + ] + }, + { + "id": "v12", + "opcode": "SaveState", + "type": "void", + "users": [ + "v11" + ] + }, + { + "id": "v11", + "imms": [ + 3, + 225 + ], + "inputs": [ + "v9", + "v12" + ], + "intrinsic_id": "Intrinsic.trystglobalbyname", + "opcode": "Intrinsic", + "string_data": "c", + "type": "void" + }, + { + "id": "v14", + "opcode": "SaveState", + "type": "void", + "users": [ + "v13" + ] + }, + { + "id": "v13", + "imms": [ + 4, + 228 + ], + "inputs": [ + "v14" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "console", + "type": "any", + "users": [ + "v19", + "v15" + ] + }, + { + "id": "v16", + "opcode": "SaveState", + "type": "void", + "users": [ + "v15" + ] + }, + { + "id": "v15", + "imms": [ + 5, + 245 + ], + "inputs": [ + "v13", + "v16" + ], + "intrinsic_id": "Intrinsic.ldobjbyname", + "opcode": "Intrinsic", + "string_data": "log", + "type": "any", + "users": [ + "v19" + ] + }, + { + "id": "v18", + "opcode": "SaveState", + "type": "void", + "users": [ + "v17" + ] + }, + { + "id": "v17", + "imms": [ + 7, + 225 + ], + "inputs": [ + "v18" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "c", + "type": "any", + "users": [ + "v19" + ] + }, + { + "id": "v20", + "opcode": "SaveState", + "type": "void", + "users": [ + "v19" + ] + }, + { + "id": "v19", + "imms": [ + 8 + ], + "inputs": [ + "v13", + "v17", + "v15", + "v20" + ], + "intrinsic_id": "Intrinsic.callthis1", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v22", + "opcode": "SaveState", + "type": "void", + "users": [ + "v21" + ] + }, + { + "id": "v21", + "inputs": [ + "v22" + ], + "intrinsic_id": "Intrinsic.ldundefined", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v24", + "opcode": "SaveState", + "type": "void", + "users": [ + "v23" + ] + }, + { + "id": "v23", + "inputs": [ + "v24" + ], + "intrinsic_id": "Intrinsic.returnundefined", + "opcode": "Intrinsic", + "type": "void" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 1 + ], + "successors": [ + 2 + ] + }, + { + "id": 2, + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 0 + ] + } + ], + "name": "foo", + "returnType": "any", + "signature": ".foo" + }, + "name": "foo" + }, + { + "method": { + "accessFlags": 264, + "basicBlocks": [ + { + "id": 1, + "insts": [ + { + "id": "v0", + "index": 0, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v1", + "index": 1, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v2", + "index": 2, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v15", + "opcode": "Constant", + "type": "i32", + "users": [ + "v30", + "v17" + ], + "value": 2 + }, + { + "id": "v16", + "opcode": "Constant", + "type": "i32", + "users": [ + "v30", + "v17" + ], + "value": 3 + }, + { + "id": "v19", + "opcode": "Constant", + "type": "i32", + "users": [ + "v22", + "v20" + ], + "value": 5 + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "successors": [ + 0 + ] + }, + { + "id": 0, + "insts": [ + { + "id": "v4", + "opcode": "SaveState", + "type": "void", + "users": [ + "v3" + ] + }, + { + "id": "v3", + "imms": [ + 2 + ], + "inputs": [ + "v4" + ], + "intrinsic_id": "Intrinsic.newlexenv", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v6", + "opcode": "SaveState", + "type": "void", + "users": [ + "v5" + ] + }, + { + "functionName": ".bar", + "id": "v5", + "imms": [ + 0, + 362, + 0 + ], + "inputs": [ + "v6" + ], + "intrinsic_id": "Intrinsic.definefunc", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v7" + ] + }, + { + "id": "v8", + "opcode": "SaveState", + "type": "void", + "users": [ + "v7" + ] + }, + { + "id": "v7", + "imms": [ + 1, + 201 + ], + "inputs": [ + "v5", + "v8" + ], + "intrinsic_id": "Intrinsic.stglobalvar", + "opcode": "Intrinsic", + "string_data": "bar", + "type": "void" + }, + { + "id": "v10", + "opcode": "SaveState", + "type": "void", + "users": [ + "v9" + ] + }, + { + "functionName": ".foo", + "id": "v9", + "imms": [ + 2, + 390, + 2 + ], + "inputs": [ + "v10" + ], + "intrinsic_id": "Intrinsic.definefunc", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v11" + ] + }, + { + "id": "v12", + "opcode": "SaveState", + "type": "void", + "users": [ + "v11" + ] + }, + { + "id": "v11", + "imms": [ + 3, + 240 + ], + "inputs": [ + "v9", + "v12" + ], + "intrinsic_id": "Intrinsic.stglobalvar", + "opcode": "Intrinsic", + "string_data": "foo", + "type": "void" + }, + { + "id": "v14", + "opcode": "SaveState", + "type": "void", + "users": [ + "v13" + ] + }, + { + "id": "v13", + "imms": [ + 4, + 240 + ], + "inputs": [ + "v14" + ], + "intrinsic_id": "Intrinsic.ldglobalvar", + "opcode": "Intrinsic", + "string_data": "foo", + "type": "any", + "users": [ + "v17" + ] + }, + { + "id": "v18", + "opcode": "SaveState", + "type": "void", + "users": [ + "v17" + ] + }, + { + "id": "v17", + "imms": [ + 5 + ], + "inputs": [ + "v15", + "v16", + "v13", + "v18" + ], + "intrinsic_id": "Intrinsic.callargs2", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v21", + "opcode": "SaveState", + "type": "void", + "users": [ + "v20" + ] + }, + { + "id": "v20", + "imms": [ + 7, + 225 + ], + "inputs": [ + "v19", + "v21" + ], + "intrinsic_id": "Intrinsic.sttoglobalrecord", + "opcode": "Intrinsic", + "string_data": "c", + "type": "void" + }, + { + "id": "v23", + "opcode": "SaveState", + "type": "void", + "users": [ + "v22" + ] + }, + { + "id": "v22", + "imms": [ + 8, + 237 + ], + "inputs": [ + "v19", + "v23" + ], + "intrinsic_id": "Intrinsic.sttoglobalrecord", + "opcode": "Intrinsic", + "string_data": "d", + "type": "void" + }, + { + "id": "v25", + "opcode": "SaveState", + "type": "void", + "users": [ + "v24" + ] + }, + { + "id": "v24", + "imms": [ + 9, + 201 + ], + "inputs": [ + "v25" + ], + "intrinsic_id": "Intrinsic.ldglobalvar", + "opcode": "Intrinsic", + "string_data": "bar", + "type": "any", + "users": [ + "v26" + ] + }, + { + "id": "v27", + "opcode": "SaveState", + "type": "void", + "users": [ + "v26" + ] + }, + { + "id": "v26", + "imms": [ + 10 + ], + "inputs": [ + "v24", + "v27" + ], + "intrinsic_id": "Intrinsic.callarg0", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v29", + "opcode": "SaveState", + "type": "void", + "users": [ + "v28" + ] + }, + { + "id": "v28", + "imms": [ + 12, + 240 + ], + "inputs": [ + "v29" + ], + "intrinsic_id": "Intrinsic.ldglobalvar", + "opcode": "Intrinsic", + "string_data": "foo", + "type": "any", + "users": [ + "v30" + ] + }, + { + "id": "v31", + "opcode": "SaveState", + "type": "void", + "users": [ + "v30" + ] + }, + { + "id": "v30", + "imms": [ + 13 + ], + "inputs": [ + "v15", + "v16", + "v28", + "v31" + ], + "intrinsic_id": "Intrinsic.callargs2", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v33", + "opcode": "SaveState", + "type": "void", + "users": [ + "v32" + ] + }, + { + "id": "v32", + "inputs": [ + "v33" + ], + "intrinsic_id": "Intrinsic.ldundefined", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v35", + "opcode": "SaveState", + "type": "void", + "users": [ + "v34" + ] + }, + { + "id": "v34", + "inputs": [ + "v35" + ], + "intrinsic_id": "Intrinsic.returnundefined", + "opcode": "Intrinsic", + "type": "void" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 1 + ], + "successors": [ + 2 + ] + }, + { + "id": 2, + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 0 + ] + } + ], + "name": "func_main_0", + "returnType": "any", + "signature": ".func_main_0" + }, + "name": "func_main_0" + } + ] + } + ] +} \ No newline at end of file diff --git a/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.ts b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.ts new file mode 100644 index 000000000..515319613 --- /dev/null +++ b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable2.ts @@ -0,0 +1,21 @@ +function foo(a, b) { + c = a + b + d + console.log(c) +} + +function bar() { + c = "bar function call" + console.log(c) +} + +// in this call variables c, d are unresolved +foo(2, 3) + +let c = 5 +let d = 5 + +// in this call variable c is already defined +bar() + +// in this call variables c, d already defined +foo(2, 3) diff --git a/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.json b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.json new file mode 100644 index 000000000..ecc48ce7e --- /dev/null +++ b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.json @@ -0,0 +1,956 @@ +{ + "classes": [ + { + "name": "GLOBAL", + "properties": [ + { + "method": { + "accessFlags": 264, + "basicBlocks": [ + { + "id": 1, + "insts": [ + { + "id": "v0", + "index": 0, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v1", + "index": 1, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v2", + "index": 2, + "opcode": "Parameter", + "type": "any" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "successors": [ + 0 + ] + }, + { + "id": 0, + "insts": [ + { + "id": "v4", + "opcode": "SaveState", + "type": "void", + "users": [ + "v3" + ] + }, + { + "id": "v3", + "imms": [ + 0, + 218 + ], + "inputs": [ + "v4" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "console", + "type": "any", + "users": [ + "v9", + "v5" + ] + }, + { + "id": "v6", + "opcode": "SaveState", + "type": "void", + "users": [ + "v5" + ] + }, + { + "id": "v5", + "imms": [ + 1, + 240 + ], + "inputs": [ + "v3", + "v6" + ], + "intrinsic_id": "Intrinsic.ldobjbyname", + "opcode": "Intrinsic", + "string_data": "log", + "type": "any", + "users": [ + "v9" + ] + }, + { + "id": "v8", + "opcode": "SaveState", + "type": "void", + "users": [ + "v7" + ] + }, + { + "id": "v7", + "imms": [ + 3, + 227 + ], + "inputs": [ + "v8" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "d", + "type": "any", + "users": [ + "v9" + ] + }, + { + "id": "v10", + "opcode": "SaveState", + "type": "void", + "users": [ + "v9" + ] + }, + { + "id": "v9", + "imms": [ + 4 + ], + "inputs": [ + "v3", + "v7", + "v5", + "v10" + ], + "intrinsic_id": "Intrinsic.callthis1", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v12", + "opcode": "SaveState", + "type": "void", + "users": [ + "v11" + ] + }, + { + "id": "v11", + "inputs": [ + "v12" + ], + "intrinsic_id": "Intrinsic.ldundefined", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v14", + "opcode": "SaveState", + "type": "void", + "users": [ + "v13" + ] + }, + { + "id": "v13", + "inputs": [ + "v14" + ], + "intrinsic_id": "Intrinsic.returnundefined", + "opcode": "Intrinsic", + "type": "void" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 1 + ], + "successors": [ + 2 + ] + }, + { + "id": 2, + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 0 + ] + } + ], + "name": "bar", + "returnType": "any", + "signature": ".bar" + }, + "name": "bar" + }, + { + "method": { + "accessFlags": 264, + "basicBlocks": [ + { + "id": 1, + "insts": [ + { + "id": "v0", + "index": 0, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v1", + "index": 1, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v2", + "index": 2, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v3", + "index": 3, + "opcode": "Parameter", + "type": "any", + "users": [ + "v5" + ] + }, + { + "id": "v4", + "index": 4, + "opcode": "Parameter", + "type": "any", + "users": [ + "v5" + ] + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "successors": [ + 0 + ] + }, + { + "id": 0, + "insts": [ + { + "id": "v6", + "opcode": "SaveState", + "type": "void", + "users": [ + "v5" + ] + }, + { + "id": "v5", + "imms": [ + 0 + ], + "inputs": [ + "v3", + "v4", + "v6" + ], + "intrinsic_id": "Intrinsic.add2", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v9" + ] + }, + { + "id": "v8", + "opcode": "SaveState", + "type": "void", + "users": [ + "v7" + ] + }, + { + "id": "v7", + "imms": [ + 1, + 227 + ], + "inputs": [ + "v8" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "d", + "type": "any", + "users": [ + "v9" + ] + }, + { + "id": "v10", + "opcode": "SaveState", + "type": "void", + "users": [ + "v9" + ] + }, + { + "id": "v9", + "imms": [ + 2 + ], + "inputs": [ + "v5", + "v7", + "v10" + ], + "intrinsic_id": "Intrinsic.add2", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v11" + ] + }, + { + "id": "v12", + "opcode": "SaveState", + "type": "void", + "users": [ + "v11" + ] + }, + { + "id": "v11", + "imms": [ + 3, + 210 + ], + "inputs": [ + "v9", + "v12" + ], + "intrinsic_id": "Intrinsic.trystglobalbyname", + "opcode": "Intrinsic", + "string_data": "c", + "type": "void" + }, + { + "id": "v14", + "opcode": "SaveState", + "type": "void", + "users": [ + "v13" + ] + }, + { + "id": "v13", + "imms": [ + 4, + 218 + ], + "inputs": [ + "v14" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "console", + "type": "any", + "users": [ + "v19", + "v15" + ] + }, + { + "id": "v16", + "opcode": "SaveState", + "type": "void", + "users": [ + "v15" + ] + }, + { + "id": "v15", + "imms": [ + 5, + 240 + ], + "inputs": [ + "v13", + "v16" + ], + "intrinsic_id": "Intrinsic.ldobjbyname", + "opcode": "Intrinsic", + "string_data": "log", + "type": "any", + "users": [ + "v19" + ] + }, + { + "id": "v18", + "opcode": "SaveState", + "type": "void", + "users": [ + "v17" + ] + }, + { + "id": "v17", + "imms": [ + 7, + 210 + ], + "inputs": [ + "v18" + ], + "intrinsic_id": "Intrinsic.tryldglobalbyname", + "opcode": "Intrinsic", + "string_data": "c", + "type": "any", + "users": [ + "v19" + ] + }, + { + "id": "v20", + "opcode": "SaveState", + "type": "void", + "users": [ + "v19" + ] + }, + { + "id": "v19", + "imms": [ + 8 + ], + "inputs": [ + "v13", + "v17", + "v15", + "v20" + ], + "intrinsic_id": "Intrinsic.callthis1", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v22", + "opcode": "SaveState", + "type": "void", + "users": [ + "v21" + ] + }, + { + "id": "v21", + "inputs": [ + "v22" + ], + "intrinsic_id": "Intrinsic.ldundefined", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v24", + "opcode": "SaveState", + "type": "void", + "users": [ + "v23" + ] + }, + { + "id": "v23", + "inputs": [ + "v24" + ], + "intrinsic_id": "Intrinsic.returnundefined", + "opcode": "Intrinsic", + "type": "void" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 1 + ], + "successors": [ + 2 + ] + }, + { + "id": 2, + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 0 + ] + } + ], + "name": "foo", + "returnType": "any", + "signature": ".foo" + }, + "name": "foo" + }, + { + "method": { + "accessFlags": 264, + "basicBlocks": [ + { + "id": 1, + "insts": [ + { + "id": "v0", + "index": 0, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v1", + "index": 1, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v2", + "index": 2, + "opcode": "Parameter", + "type": "any" + }, + { + "id": "v15", + "opcode": "Constant", + "type": "i32", + "users": [ + "v17" + ], + "value": 2 + }, + { + "id": "v16", + "opcode": "Constant", + "type": "i32", + "users": [ + "v17" + ], + "value": 3 + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "successors": [ + 0 + ] + }, + { + "id": 0, + "insts": [ + { + "id": "v4", + "opcode": "SaveState", + "type": "void", + "users": [ + "v3" + ] + }, + { + "id": "v3", + "imms": [ + 2 + ], + "inputs": [ + "v4" + ], + "intrinsic_id": "Intrinsic.newlexenv", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v6", + "opcode": "SaveState", + "type": "void", + "users": [ + "v5" + ] + }, + { + "functionName": ".bar", + "id": "v5", + "imms": [ + 0, + 357, + 0 + ], + "inputs": [ + "v6" + ], + "intrinsic_id": "Intrinsic.definefunc", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v7" + ] + }, + { + "id": "v8", + "opcode": "SaveState", + "type": "void", + "users": [ + "v7" + ] + }, + { + "id": "v7", + "imms": [ + 1, + 205 + ], + "inputs": [ + "v5", + "v8" + ], + "intrinsic_id": "Intrinsic.stglobalvar", + "opcode": "Intrinsic", + "string_data": "bar", + "type": "void" + }, + { + "id": "v10", + "opcode": "SaveState", + "type": "void", + "users": [ + "v9" + ] + }, + { + "functionName": ".foo", + "id": "v9", + "imms": [ + 2, + 385, + 2 + ], + "inputs": [ + "v10" + ], + "intrinsic_id": "Intrinsic.definefunc", + "opcode": "Intrinsic", + "type": "any", + "users": [ + "v11" + ] + }, + { + "id": "v12", + "opcode": "SaveState", + "type": "void", + "users": [ + "v11" + ] + }, + { + "id": "v11", + "imms": [ + 3, + 235 + ], + "inputs": [ + "v9", + "v12" + ], + "intrinsic_id": "Intrinsic.stglobalvar", + "opcode": "Intrinsic", + "string_data": "foo", + "type": "void" + }, + { + "id": "v14", + "opcode": "SaveState", + "type": "void", + "users": [ + "v13" + ] + }, + { + "id": "v13", + "imms": [ + 4, + 235 + ], + "inputs": [ + "v14" + ], + "intrinsic_id": "Intrinsic.ldglobalvar", + "opcode": "Intrinsic", + "string_data": "foo", + "type": "any", + "users": [ + "v17" + ] + }, + { + "id": "v18", + "opcode": "SaveState", + "type": "void", + "users": [ + "v17" + ] + }, + { + "id": "v17", + "imms": [ + 5 + ], + "inputs": [ + "v15", + "v16", + "v13", + "v18" + ], + "intrinsic_id": "Intrinsic.callargs2", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v19", + "opcode": "SaveState", + "type": "void", + "users": [ + "v20" + ] + }, + { + "id": "v20", + "inputs": [ + "v19" + ], + "opcode": "LoadString", + "string": "ccc", + "stringOffset": 213, + "type": "ref", + "users": [ + "v21" + ] + }, + { + "id": "v21", + "inputs": [ + "v20" + ], + "opcode": "CastValueToAnyType", + "type": "any", + "users": [ + "v22" + ] + }, + { + "id": "v23", + "opcode": "SaveState", + "type": "void", + "users": [ + "v22" + ] + }, + { + "id": "v22", + "imms": [ + 7, + 210 + ], + "inputs": [ + "v21", + "v23" + ], + "intrinsic_id": "Intrinsic.stconsttoglobalrecord", + "opcode": "Intrinsic", + "string_data": "c", + "type": "void" + }, + { + "id": "v24", + "opcode": "SaveState", + "type": "void", + "users": [ + "v25" + ] + }, + { + "id": "v25", + "inputs": [ + "v24" + ], + "opcode": "LoadString", + "string": "ddd", + "stringOffset": 230, + "type": "ref", + "users": [ + "v26" + ] + }, + { + "id": "v26", + "inputs": [ + "v25" + ], + "opcode": "CastValueToAnyType", + "type": "any", + "users": [ + "v27" + ] + }, + { + "id": "v28", + "opcode": "SaveState", + "type": "void", + "users": [ + "v27" + ] + }, + { + "id": "v27", + "imms": [ + 8, + 227 + ], + "inputs": [ + "v26", + "v28" + ], + "intrinsic_id": "Intrinsic.stconsttoglobalrecord", + "opcode": "Intrinsic", + "string_data": "d", + "type": "void" + }, + { + "id": "v30", + "opcode": "SaveState", + "type": "void", + "users": [ + "v29" + ] + }, + { + "id": "v29", + "imms": [ + 9, + 205 + ], + "inputs": [ + "v30" + ], + "intrinsic_id": "Intrinsic.ldglobalvar", + "opcode": "Intrinsic", + "string_data": "bar", + "type": "any", + "users": [ + "v31" + ] + }, + { + "id": "v32", + "opcode": "SaveState", + "type": "void", + "users": [ + "v31" + ] + }, + { + "id": "v31", + "imms": [ + 10 + ], + "inputs": [ + "v29", + "v32" + ], + "intrinsic_id": "Intrinsic.callarg0", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v34", + "opcode": "SaveState", + "type": "void", + "users": [ + "v33" + ] + }, + { + "id": "v33", + "inputs": [ + "v34" + ], + "intrinsic_id": "Intrinsic.ldundefined", + "opcode": "Intrinsic", + "type": "any" + }, + { + "id": "v36", + "opcode": "SaveState", + "type": "void", + "users": [ + "v35" + ] + }, + { + "id": "v35", + "inputs": [ + "v36" + ], + "intrinsic_id": "Intrinsic.returnundefined", + "opcode": "Intrinsic", + "type": "void" + } + ], + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 1 + ], + "successors": [ + 2 + ] + }, + { + "id": 2, + "isCatchBegin": false, + "isTryBegin": false, + "isTryEnd": false, + "predecessors": [ + 0 + ] + } + ], + "name": "func_main_0", + "returnType": "any", + "signature": ".func_main_0" + }, + "name": "func_main_0" + } + ] + } + ] +} \ No newline at end of file diff --git a/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.ts b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.ts new file mode 100644 index 000000000..40c164a3b --- /dev/null +++ b/jacodb-panda-dynamic/src/test/resources/samples/codeqlSamples/unresolvedVariable3.ts @@ -0,0 +1,17 @@ +function foo(a, b) { + c = a + b + d + console.log(c) +} + +function bar() { + console.log(d) +} + +// in this call variables c, d are unresolved +foo(2, 3) + +const c = "ccc" +const d = "ddd" + +// in this call variable d is already defined +bar() \ No newline at end of file